
BlackLotus-Z2A-Challenge, Nothing to see here 4 now , please move along
BlackLotus-Z2A-Challenge, Rien à voir ici pour l'instant, veuillez passer votre chemin
Commençons par le commencement

Pour des raisons esthétiques uniquement, j'emprunterai (volerai) honteusement :)) de @darthmaulware(Ryan “DM” Smith) la solution les règles de détection yara juste pour faire pro. Va voir son twitter, c'est une personne super cool ! PS. Ryan, ne m'en veux pas d'avoir volé ça :))) et merci pour ton soutien sur Discord :)
Regarde aussi son travail :)
https://gitlab.com/malre-rcs/zero2automated/-/blob/main/solutions/bi_weekly_challenge/BlackLotus_20230321/BlackLotus_HTTP_Downloader.ipynb``` rule Blacklotus_HTTP_Downloader { meta: description = "Rule to detect Blacklotus HTTP Downloader" author = "Darth Maulware" sha256 = "d68f668b4240f9518e4f80499d93d8c5a1eddece0771658c33ae916cc54f5a66"
strings:
$opcode1 = {48 89 4C 24 08 48 89 54 24 10 4C}
$opcode2 = {89 44 24 18 4C 89 4C 24 20 48 83}
$opcode3 = {EC 28 B9 31 62 D7 2E 90 90 E8 ??}
$opcode4 = {?? ?? ?? 48 83 C4 28 48 8B 4C 24}
$opcode5 = {08 48 8B 54 24 10 4C 8B 44 24 18}
$opcode6 = {4C 8B 4C 24 20 4C 8B D1 90 90}
condition:
(uint16(0) == 0x5a4d and filesize < 500KB and all of them)
}
Aussi pour des raisons esthétiques, je vais aussi voler ceci parce que ça a l'air cool :) encore désolé ryan, ne te fâche pas contre moi s'il te plaît :)```
C:\\Users\\REM\\Desktop>capa.exe -f pe -r capa-rules-5.0.0 d68f668b4240f9518e4f80499d93d8c5a1eddece0771658c33ae916cc54f5a66.exe
matching: 100%|████████| 124/124 [00:02<00:00, 46.96 functions/s, skipped 1 library functions (0%)]
+------------------------+------------------------------------------------------------------------------------+
| ATT&CK Tactic | ATT&CK Technique |
|------------------------+------------------------------------------------------------------------------------|
| DEFENSE EVASION | Obfuscated Files or Information T1027 |
| DISCOVERY | Process Discovery T1057 |
| EXECUTION | Shared Modules T1129 |
+------------------------+------------------------------------------------------------------------------------+
+-----------------------------+-------------------------------------------------------------------------------+
| MBC Objective | MBC Behavior |
|-----------------------------+-------------------------------------------------------------------------------|
| ANTI-BEHAVIORAL ANALYSIS | Debugger Detection::Process Environment Block BeingDebugged [B0001.035] |
| | Debugger Detection::Process Environment Block NtGlobalFlag [B0001.036] |
| CRYPTOGRAPHY | Encrypt Data::RC4 [C0027.009] |
| | Generate Pseudo-random Sequence::RC4 PRGA [C0021.004] |
| DATA | Encode Data::XOR [C0026.002] |
| DEFENSE EVASION | Obfuscated Files or Information::Encoding-Standard Algorithm [E1027.m02] |
+-----------------------------+-------------------------------------------------------------------------------+
+------------------------------------------------------+------------------------------------------------------+
| CAPABILITY | NAMESPACE |
|------------------------------------------------------+------------------------------------------------------|
| execute syscall instruction (35 matches) | anti-analysis |
| check for PEB BeingDebugged flag (2 matches) | anti-analysis/anti-debugging/debugger-detection |
| check for PEB NtGlobalFlag flag | anti-analysis/anti-debugging/debugger-detection |
| encode data using XOR (2 matches) | data-manipulation/encoding/xor |
| encrypt data using RC4 PRGA (2 matches) | data-manipulation/encryption/rc4 |
| get process heap flags | host-interaction/process |
| get ntdll base address (3 matches) | linking/runtime-linking |
| parse PE header (2 matches) | load-code/pe |
| resolve function by parsing PE exports (2 matches) | load-code/pe |
+------------------------------------------------------+------------------------------------------------------+
tbh si j'étais toi, je ne ferais pas entièrement confiance à capa (du moins dans ce cas précis) parce qu'ici ça dit que l'échantillon utilise RC4 alors qu'en réalité il utilise AES, mais bref, comme mentionné, c'est strictement pour l'esthétique :)
Avant de commencer, tu vas rencontrer tout au long de ce rapport beaucoup de

Ignore ça, s'il te plaît, car IDA n'arrive pas à désassembler correctement ça en assembleur, c'est

Et ça fait planter le débogueur ? Pourquoi ?
Parce qu'il essaie d'écrire à l'adresse 0, ce qui dans le folklore hacker est connu comme écrire à une adresse de pointeur nul, quelque chose qui était largement exploité pour obtenir l'exécution de code (CE), et cela a évidemment été mitigé.
Et avec la mitigation actuelle, si tu essaies d'écrire à 0, ça fera planter le processus, dans notre cas le malware & par conséquent le débogueur.
Maintenant, si on ouvre ça dans IDA

J'ai renommé chaque fonction pour indiquer une certaine logique qu'elle effectue, commençons par la première fonction, do_syscall()

On remarque immédiatement l'utilisation de syscalls, ce qui est une méthode connue pour rendre la vie d'un analyste plus difficile lors de l'analyse dynamique.
Pour ceux qui ne sont pas familiers avec les syscalls sous Windows, voici une vidéo sympa réalisée par oalabs (https://www.youtube.com/watch?v=Uba3SQH2jNE). Regarde-la parce que je l'ai fait aussi et ça m'a beaucoup aidé à comprendre ce qui se passe dans cette fonction.
Si on inspecte le "pseudo-code" résolu par IDA, on voit que ça ressemble à ça

Si on inspecte statiquement solve_hash, ça ressemble à ça


D'un point de vue pseudo-code, ça ressemble à ça

Veuillez te référer à solve_hash.py pour voir mon "émulation" de ça au cas où tu voudrais voir un bout d'automatisation et découvrir ce que les syscalls résolvent par un algorithme de hachage. Mais quoi qu'il en soit, ça fait partie d'un projet appelé SysWhispers2 ou du moins c'est ce que je suppose que les auteurs du malware ont utilisé comme inspiration. Quoi qu'il en soit, veuillez te référer à la vidéo d'oalabs mentionnée plus haut pour une meilleure compréhension.
Quoi qu'il en soit, la fonction anti_debug est facilement contournable et bien connue (https://anti-debug.checkpoint.com/techniques/debug-flags.html#manual-checks-ntglobalflag). La façon de la contourner est d'avoir ScyllaHide installé et NtGlobalFlag coché (ce qui devrait être activé par défaut si tu utilises x86dbg). Quoi qu'il en soit, voici ce que tu es censé vérifier

Et voici à quoi ressemble la "pseudo-fonction" anti-debug

Plutôt simple si tu veux mon avis
Ensuite, nous avons la fonction check_inmemory_ldr qui ressemble à ça


Maintenant, pour le but de l'analyse de la fonction, si on demande gentiment à x86dbg, on peut voir que si on exécute jusqu'à l'instruction syscall, x86dbg sera assez gentil pour nous retourner le syscall qu'il est sur le point d'exécuter. Dans notre cas

Maintenant, en se basant sur le contexte actuel, on peut supposer que NtSetInformationThread sera utilisé comme une sorte de technique anti-analyse. Effectivement, si on fait une recherche rapide sur Google, on tombe sur ça https://ntquery.wordpress.com/tag/ntqueryinformationthread/
Heureusement, c'est facilement contournable, il suffit de patcher avec nop+ret :)
=============================================================================
En suivant l'ordre d'exécution, après cette fonction, la suivante est

Encore une fois, si on inspecte ce qu'elle fait

Elle vérifie simplement un flag dans le TEB pour voir si le processus actuel (l'exe dans notre cas) est débogué. Encore une fois, c'est facilement contournable car c'est une méthode connue (https://anti-debug.checkpoint.com/techniques/debug-flags.html#manual-checks-peb-beingdebugged-flag). De la même manière que nous avons utilisé ScyllaHide, cette fois tu dois avoir coché

ce qui devrait être activé par défaut
=============================================================================
Maintenant custom_hash2_and_aplib_possible qui ressemble à ça

Et d'un point de vue graphe

Veuillez te référer à decompress_aplib.py pour voir l'"émulation" de cette fonction.
En explorant get_ntdll_and_unhook2, ça ressemble à ça


D'un point de vue graphe, ça ressemble à ça

Pas mal du tout :))
En remontant un peu, nous avons aplib_decompress, maintenant ça ressemble à ça

D'un point de vue analyse de code statique, ça ressemble à ça




Mhmm un peu gros, rien de bien méchant les amis, c'est faisable :)
Si tu utilises le script d'émulation aplib_decompress.py, tu devrais obtenir quelque chose comme ça

Cool, une chose que je n'avais pas remarquée dans les autres blogs/analyses, si on regarde à nouveau le pseudo-code d'IDA pour ntdll_and_unhook2

tu verras un memcpy intéressant
À un moment donné, quand je faisais l'analyse dynamique, j'ai remarqué qu'une autre DLL était chargée, qui était une autre version de ntdll

si on regarde dans le débogueur, ça ressemble à ça

Je n'ai pas pu détecter ce qui était hooké/patched, mais si quelqu'un le sait, veuillez faire une pull request et modifier ce document. Aussi, dans mes tentatives pour trouver ce qui est hooké, j'ai essayé de faire un bindiff entre les deux ntdll et malheureusement je n'ai rien trouvé, mais c'est peut-être parce que je faisais déjà un diff sur une DLL système qui était infectée, donc pas une exécution propre, donc peut-être que c'est pour ça ¯_(ツ)_/¯

=============================================================================
En continuant le processus d'analyse, parmi les fonctions inexpliquées, nous avons some_hasing et ntquertyinformationprocess_anti_debug, celles-ci n'ont pas été expliquées. check_if_being_debug_through_teb et anti_debug ont déjà été expliquées heureusement car elles étaient utilisées dans la/les fonction(s) précédente(s), donc veuillez lire les sections précédentes si tu veux réviser les connaissances à leur sujet. Je voudrais commencer par ntquertyinformationprocess_anti_debug et ensuite finir avec some_hasing.
En l'inspectant, on voit la même fonction appelée 3 fois.

Et d'un point de vue assembleur


Pour plus de commodité, je l'ai déjà nommée, ce qui est ntquertyinformationprocess_ProcessDebugPort. D'où je savais que les fonctions appelées étaient ntquertyinformationprocess_ProcessDebugPort ? En les inspectant, on révèle un appel de fonction déjà vu / des algorithmes connus

Qu'en est-il des commentaires faits dans IDA ? Eh bien, si tu cherches ntqueryinformationprocess sur Google, on tombe sur une bonne ressource sur l'anti-débogage (https://anti-debug.checkpoint.com/techniques/debug-flags.html). Si on suit, on peut voir qu'il explique qu'en fonction de certaines valeurs passées comme paramètres à cette fonction, elle peut être utilisée comme méthode anti-débogage.
Par exemple, pour le premier appel, on peut voir les arguments de pile suivants dans le débogueur

Si on va maintenant vérifier la page MSDN pour ntqueryinformationprocess

Le même processus se répète pour les deux syscalls suivants

où 0x1e est spécifique pour la méthode anti-débogage ProcessDebugObjectHandle (https://www.apriorit.com/dev-blog/367-anti-reverse-engineering-protection-techniques-to-use-before-releasing-software)
et enfin ProcessDebugFlags

Alors, comment les contourner ?! Prends une pilule de chill, frérot, car ScyllaHide a du répondant

Comme tu peux le voir

Donc on est en sécurité ! Pas tout à fait, alors que ScyllaHide nous couvre pour les 2 premiers syscalls, pour le dernier syscall, on doit le faire manuellement ! et wtf je fais ? Eh bien, solution simple ! on retourne de cette fonction, donc de toute la fonction ntquertyinformationprocess_anti_debug et on met eax à 0. Donc dans des circonstances normales, ça ressemble à ça

Et avec notre "aide", ça ressemble à ça et on laisse l'exécution se poursuivre en toute sécurité :)

=============================================================================
Maintenant some_hasing, tu connais déjà la routine

Et maintenant le pseudo-code

On remarque une chose étrange ici. Le pseudo-code d'IDA échoue ici... parce que si on suit le graphe après call_syscall, il y a plus d'instructions à désassembler. Alors qu'est-ce qu'on fait ici maintenant ? Eh bien, on va se fier au débogueur pour analyser dynamiquement ce code...
Donc on voit que le syscall qu'il effectue est

Maintenant, si on regarde ntquerydefaultlocale, Google montre que c'est une API non documentée qui prend 2 arguments (http://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FLocale%2FNtQueryDefaultLocale.html). Cool, donc qu'est-ce que ça fait ? Ça retourne l'identifiant de locale actuel. Cool, alors wtf est un identifiant de locale ? D'après MSDN (https://learn.microsoft.com/en-us/windows/win32/intl/locale-identifiers), une valeur 32 bits qui se compose d'un identifiant de langue et d'un identifiant d'ordre de tri. Pour faire court, quelle langue tu parles sur ce PC :)
Ensuite, ça vérifie si l'API n'a pas échoué et si ce n'est pas le cas, ça prend la valeur retournée par ntquerydefaultlocale, soustrait 0x419, compare avec 0x26 (probablement une constante) comme on peut le voir dans l'image ci-dessous.

Si ce n'est pas inférieur ou égal à 0x26, ça le compare avec 0x818 sinon ça fait la même comparaison avec 0x819 comme on le voit clairement

Alors, qu'est-ce qui se passe ici ? et pourquoi ces constantes spécifiques. Eh bien, je vais aller droit au but. En cherchant différentes constantes, je suis tombé sur cet article (https://www.cnblogs.com/DirWang/p/17281690.html#autoid-8-0-0), un chercheur qui a déjà analysé BlackLotus mieux que je ne pourrais le faire. Et comme quelqu'un l'a dit un jour : "On ne peut pas tricher dans l'analyse de malware, on peut juste se faciliter la tâche". Donc ce que le chercheur a dit, c'est que fondamentalement cette fonction vérifie des constantes spécifiques qui identifient la langue parlée sur l'ordinateur. Dans son article, il fournit un lien vers ceci (https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/MS-LCID/[MS-LCID].pdf) qui est comme un document standard de Microsoft avec chaque identifiant de langue.
Maintenant, en utilisant notre logique hax00r l33t, on peut déduire que probablement 0x26 est un offset utilisé, donc comme les identifiants de langue suivants 0x26 après 0x419, qui sont

Si on inspecte aussi ce document, on peut voir que 0x818 correspond à

et 0x819 à

Et on sait d'après des "investigations" précédentes / rapports en ligne que ce malware ne s'exécutait pas sur certains PC de certaines régions du monde, donc on peut conclure que cette fonction vérifie dans quelle région se trouve la machine infectée.
=============================================================================
Crazy ham00brg33r jusqu'à maintenant, frérot, quelle est la prochaine ? On sert la fonction some_more_syscall. D'accord ! Alors qu'est-ce que t'as là ack ! La voici

On en veut plus ! Bien sûr mon pote !



Hmmmm

Donc vérifie si un débogueur noyau est présent (https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntexapi/system_information_class.htm) (0x23), checky checky !
Alors quoi ack ! On a pcr (pile et combinaisons party)

=============================================================================
Maintenant, si on inspecte la fonction iterate_over_modules(), elle ressemble à ça

D'un point de vue "pseudo-code", ça ressemble à

D'un point de vue autonome, l'assembleur et le pseudo-code d'IDA semblent correspondre, alors quelle est la logique de cette fonction ? Eh bien, assez simple, elle itère sur les modules en mémoire (les DLL) et vérifie par rapport à une liste de hachages :) v4[0] = 0x1E7EACEF; v4[1] = 0x4468A620; v4[2] = 0x68536B95; v4[3] = 0x73EBBB53; v4[4] = 0xDA165168; v4[5] = 0xB24D33A7; v4[6] = 0xB1E2CEC6; v4[7] = 0x5136992; v4[8] = 0x98C500D9; v4[9] = 0x3E0169B6;
Et si aucune DLL en mémoire n'a le même hachage, on retourne 0, sinon 1 et on fait planter le débogueur. Et donc, une telle conclusion, on peut dire que c'est une autre méthode anti-analyse. Correct, mais qu'en est-il de chaque valeur de hachage ? Eh bien, je vais encore tricher (comme quelqu'un l'a dit un jour, on ne peut pas tricher dans l'analyse de malware, seulement se faciliter la vie :) ). Le chercheur asiatique mentionné plus haut a eu la gentillesse de nous fournir une liste de valeurs à partir desquelles les valeurs ont été dérivées
sbiedll.dll dbghelp.dll api_log.dll dir_watch.dll pstorec.dll vmcheck.dll wpespy.dll cmdvrt64.dll avghookx.dll snxhk.dll
Maintenant, pour voir dynamiquement si des valeurs correspondent à l'une des DLL mentionnées

Et effectivement, ça correspond :)
Mais comment suis-je arrivé à la conclusion que l'algorithme vérifie ces valeurs ? Eh bien, quand j'ai émulé un morceau de ce malware, j'ai dû réimplémenter iterate_over_module_name_and_hash (dans le fichier solve_hash_syscalls.py ) et dans cette fonction, nous avons

où x (l'argument passé) dans ce cas est v2 qui est un tableau (un pointeur) de valeurs qui s'incrémente (là où il pointe dans le tableau) tant qu'il ne correspond à aucune valeur de la liste mentionnée ci-dessus. Sacré pavé :P
Cool ! Ensuite
=============================================================================
iterate_over_modules2 à peu près la même histoire ici

Et pseudo-code

À peu près la même histoire, seulement des hachages différents :)
v5[0] = 0x7D73878E; v5[1] = 0xEF36424B; v5[2] = 0xAF64BC2B; v5[3] = 0x1DBBC879; v5[4] = 0xAE6D1D56; v5[5] = 0x7B3242F2; v5[6] = 0x14D922B9; v5[7] = 0x4C92DF53;
qui correspondent à
sample.exe bot.exe sandbox.exe malware.exe test.exe klavme.exe myapp.exe testapp.exe
=============================================================================
iterate_over_modules3 même histoire ici

Et pseudo-code

même histoire, hachages différents :)v4[0] = 0x42D12D59; v4[1] = 0xEC5D7AA; v4[2] = 0x861E460F; v4[3] = 0x84BCC8DB; v4[4] = 0x6474D72B; v4[5] = 0xB8B9C504; v4[6] = 0x69A0620E; v4[7] = 0x6017EE43; v4[8] = 0xE93BE2E0; v4[9] = 0x149EFC55; v4[10] = 0xE3FA84A4; v4[11] = 0x7CFDD7AF; v4[12] = 0x5B098C67; v4[13] = 0x2F1FB18E; v4[14] = 0xFE8F2B18;
qui correspondent à
prl_cc.exe prl_tools.exe qemu-ga.exe vmtoolsd.exe vmwaretray.exe vmwareuser.exe VGAuthService.exe vmacthlp.exe vboxservice.exe vboxtray.exe VMSrvc.exe VMUSrvc.exe xenservice.exe
=============================================================================
Anti_debug_measure_1 j'ai fini par le renommer en anti_debug_measure2_RtlAddVectoredExceptionHandler_int3. Pourquoi ? Vous allez voir dans une minute. Donc ça ressemble à ça

Et d'un point de vue pseudo-code, ça ressemble à ça

Alors qu'est-ce que c'est que ce f ? Eh bien, il crée essentiellement un gestionnaire d'exceptions pour __debugbreak(int 3) qui exécutera du code chaque fois que int3 est déclenché. J'ai fini par chercher plus et je suis tombé sur ceci
(https://blog.lexfo.fr/dridex-malware.html) qui est une ressource sympa qui nous indique qu'il s'agit simplement d'un mécanisme anti-débogage, et dans notre cas, nous exécutons simplement cette fonction, nous ignorons sub_13F2820D0 qui est déclenché chaque fois que nous exécutons int3 et nous patchons eax à 0 :) donc en mémoire, l'exécution ressemble à ça :)
Avant le patch

Après le patch

Après cela, vous quittez la fonction et éditez également rax/eax à 0 pour sauter le jne qui ferait planter le débogueur

=============================================================================
Anti_debug_measure_2 que j'ai ensuite renommé en anti_debug_measure2_RtlAddVectoredExceptionHandler_int2


Encore une fois, rien de nouveau sous le soleil, même chose, juste le hook d'un autre int/syscall, cette fois int2, même astuce pour contourner : utiliser le patching dynamique de la valeur de retour pour le contourner :)
Si vous cherchez anti analysis 2dh sur Google, beaucoup de choses apparaîtront, alors oui, vous pouvez l'utiliser comme référence pour en apprendre plus, je n'ai pas passé beaucoup de temps là-dessus :)
Pour celui-ci, même si vous essayez de passer par-dessus, cela finira par ret comme ici

et pour contourner cela, exécutez simplement jusqu'au return et vous êtes bon :)
=============================================================================
Voici maintenant anti_debug_measure_heap que j'ai ensuite renommé iterate_over_current_process_and_check_again_hases

Et une fonctionnalité sympa de cette fonction est qu'elle utilise ntquerysysteminformation à l'intérieur de iterate_over_current_process_and_hash_check pour lister tous les processus en cours. Voici à quoi ressemble iterate_over_current_process_and_hash_check


Cool, mais comment diable suis-je arrivé à la conclusion que iterate_over_current_process_and_hash_check fait ce que son nom suggère ? Eh bien, d'abord c'est l'appel à ntquerysysteminformation, qui si vous cherchez sur Google, vous verrez qu'il est utilisé pour obtenir une liste des processus en cours, et ensuite j'ai simplement fait une supposition éclairée basée sur l'extrait de code suivant LODWORD(v4) = RtlAllocateHeap(NtCurrentPeb()->ProcessHeap, 8u, v10); v3 = v4; v5 = ntquerysysteminformation(); v6 = v3; .... memcpy(v9, v6[8], *(v6 + 28)); v9[*(v6 + 28) >> 1] = 0; if ( some_hash_0x1003F(v9) == a1 ) qu'il copierait la liste des processus, itérerait sur chacun et comparerait chaque hash du tableau précédent avec le processus en cours. Encore une fois, félicitations au blog de recherche asiatique car je ne sais pas comment diable il a obtenu le nom réel des valeurs du tableau v4. Veuillez vous référer à iterate_over_modules.py au cas où vous voudriez voir comment j'ai émulé cela.
Ps. si vous déboguez dynamiquement cette fonction, vous finirez par tomber sur int 2d à nouveau, et la solution est la même que mentionnée ci-dessus, seulement vous exécutez jusqu'au return 0xf fois, ce qui parcourt le hev et après cela, si vous voulez être sûr de revenir de iterate_over_current_process_and_check_again_hases, placez simplement un br à la fin de cette fonction et vous êtes en sécurité :)
============================================================================= anti_debug_measure_heap



Donc oui, nous avons de la chance que ce ne soit pas si gros, et qui plus est, nous avons déjà implémenté demangle_strings. Maintenant, j'ai réimplémenté cela pour des tableaux plus grands, veuillez aller voir anti_debug_measure.py .
cela vérifie essentiellement contre``` \Registry\Machine\SOFTWARE\Microsoft\Virtual Machine\Guest\Parameters \Registry\Machine\SYSTEM\ControlSet001\Services\vioscsi \Registry\Machine\SYSTEM\ControlSet001\Services\VirtIO-FS Service \Registry\Machine\SYSTEM\ControlSet001\Services\VirtioSerial \Registry\Machine\SYSTEM\ControlSet001\Services\BALLOON \Registry\Machine\SYSTEM\ControlSet001\Services\BalloonService \Registry\Machine\SYSTEM\ControlSet001\Services\netkvm \Registry\Machine\SOFTWARE\VMware, Inc.\VMware Tools \Registry\Machine\HARDWARE\ACPI\DSDT\VBOX__ \Registry\Machine\HARDWARE\ACPI\FADT\VBOX__ \Registry\Machine\HARDWARE\ACPI\RSDT\VBOX__ \Registry\Machine\SOFTWARE\Oracle\VirtualBox Guest Additions \Registry\Machine\SYSTEM\ControlSet001\Services\VBoxGuest \Registry\Machine\SYSTEM\ControlSet001\Services\VBoxMouse \Registry\Machine\SYSTEM\ControlSet001\Services\VBoxService \Registry\Machine\SYSTEM\ControlSet001\Services\VBoxSF \Registry\Machine\SYSTEM\ControlSet001\Services\VBoxVideo
Now get_oem_key







D'abord, il démêle la chaîne en```
\Registry\Machine\HARDWARE\DEVICEMAP\Scsi\Scsi Port 0\Scsi Bus 0\Target Id 0\Logical Unit Id 0
\Registry\Machine\SYSTEM\ControlSet001\Control\SystemInformation
\Registry\Machine\HARDWARE\Description\System
Identifier
SystemManufacturer
SystemBiosVersion
VMWARE
QEMU
VBOX
Et puis interroge
\Registry\Machine\HARDWARE\DEVICEMAP\Scsi\Scsi Port 0\Scsi Bus 0\Target Id 0\Logical Unit Id 0
\Registry\Machine\SYSTEM\ControlSet001\Control\SystemInformation
\Registry\Machine\HARDWARE\Description\System
et vérifie leurs valeurs par rapport à qemu, vbox, VMWARE comme on peut le voir dans l'extrait IDA et la fenêtre x86 :)


Comme on peut le voir dans le premier extrait, il vérifie vmware par rapport aux valeurs qui étaient stockées dans ma VM au moment de l'analyse :)
Pas grave, il suffit d'exécuter cette fonction jusqu'au ret et de changer eax lorsqu'il retourne à 0 :) pour contourner cette méthode d'anti-analyse :)
=============================================================================
maintenant get_oem_from_firmware





Maintenant, quelque chose d'intéressant : on voit que cette fonction commence par sub_13F267288() qui a 0x52534D42 passé en paramètre. Si vous cherchez cette valeur sur Google, vous tomberez sur beaucoup de questions intéressantes sur différents forums, eg(https://ru.stackoverflow.com/questions/778618/c-%D0%9A%D0%B0%D0%BA-%D0%B4%D0%BE%D1%81%D1%82%D0%B0%D1%82%D1%8C-%D0%B8%D0%BD%D1%84%D0%BE%D1%80%D0%BC%D0%B0%D1%86%D0%B8%D1%8E-%D0%BE%D0%B1-%D1%83%D1%81%D1%82%D1%80%D0%BE%D0%B9%D1%81%D1%82%D0%B2%D0%B0%D1%85-%D0%BA%D0%BE%D0%BC%D0%BF%D1%8C%D1%8E%D1%82%D0%B5%D1%80%D0%B0-%D0%BD%D0%B5-%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D1%83%D1%8F-wmi) (https://msdn-whiteknight.github.io/answers/html/tools/html/ru.stackoverflow.com/posts/780170.html) (https://www.maldun.com/analysis/YXNkZmRzZmFkc2Y2NDEwNjlkc2Zhc2RmYXNkZg==/) ou ceci(https://github.com/digitalocean/go-smbios/blob/master/smbios/stream_windows.go) mais le plus intéressant, après avoir lu cela et cherché RSMB, vous tomberez peut-être sur ce lien https://evasions.checkpoint.com/techniques/firmware-tables.html qui nous explique qu'il s'agit d'une méthode d'anti-analyse :) Cool, alors qu'est-ce que ça fait ?
D'abord, il vide la table du firmware SMBIOS, puis démangle une chaîne dont la première est qemu, puis appelle sub_13F2655E0 avec comme paramètres la chaîne démantelée et la table du firmware. D'après l'analyse statique


Précisément, if ( v4 != v5) je suis arrivé à la conclusion qu'il s'agit d'une implémentation de strcmp approximative, il vérifie ce qui se trouve dans la table du firmware avec la chaîne démantelée. Comme on peut le voir dans le débogueur
r8 est un pointeur vers la table du firmware et plus intéressant, on peut voir que blah blah quelque chose... virtualbox est le nom trouvé dans la table du firmware et rcx est qemu, donc on peut affirmer sans risque qu'il s'agit d'une implémentation de strcmp. Et comme on peut le voir, on est safe :) pour cette vérification

Maintenant, ce processus se répète pour les chaînes VirtualBox, vbox, VBOX, VMWare :) En général, la solution pour contourner cette vérification de fonction est de l'exécuter jusqu'au ret, patcher eax et continuer l'analyse :)
============================================================================
Cool, maintenant check_oem_key ()






Alors qu'est-ce que ça fait ? Eh bien, même astuce que précédemment expliquée mais cette fois avec la table ACPI. Qu'est-ce que j'entends par là ? Il vaut mieux lire ces 14 diapositives(https://dc4420.org/slides/2015-11-24/acpi_vm_detect.pdf) qui l'expliquent mieux, mais même astuce bon marché :)) cette fois contre BOCHS, BXPC, VMWARE


============================================================================
Je veux commencer par la fonction anti_debug_processor_Timing() et ensuite finir avec check_for_flags(). Alors

Voilà à quoi ça ressemble. Alors qu'est-ce que ça fait ? Il lit la valeur actuelle du timestamp du processeur, puis prend le nom du processeur (dans notre cas GenuineIntel), puis soustrait le timestamp récupéré du nom du processeur et vérifie simplement si le résultat est supérieur à 19999.
Après rdtsc

après cpuid

Comme on peut le voir, la chaîne est divisée en 3 registres

Et dans notre cas, on voit qu'on "échoue" à cette vérification et on met eax à 1

Solution pour cette anti-vérification : simplement retourner de la fonction et patcher eax à 0 :)
============================================================================
Maintenant entry_to_peb()







D'un point de vue pseudo-code



Donc, jusqu'au if check, il n'y a rien de nouveau, on a déjà vu ce type d'algorithme. Alors quoi ? Eh bien, si vous allez voir le write-up déjà référencé de la recherche asiatique, vous verrez qu'il dit qu'il vérifie si la version de Windows est plus grande que win7/server 2008 r2. Mais comment est-il arrivé à cette idée ? Eh bien, si on lit http://waleedassar.blogspot.com/2012/08/major-minorsubsystemversion.html il dit

aussi si vous lisez ceci :)
et appliquez ce qui est dit ici, à savoir que if est automatiquement casté vers la structure KUSER_SHARED_DATA, mais ici mon IDA avait un bug pendant l'analyse, donc c'est comme ça :)
Afin de ne pas vous ennuyer avec la même répétition du même algorithme à peu près, voici les chaînes finales récupérées et démantelées de la fonction :) C'était un processus épuisant car cela a été fait avec un débogueur :) J'étais trop paresseux pour émuler cela.``` user32.dll advapi32.dll Rpcrt4.dll bcrypt.dll ole32.dll Cabinet.dll
CreateWindowExW
ShutdownBlockReasonCreate
ShutdownBlockReasonDestroy
DestroyWindow
CloseHandle
CreateProcessW
InitializeProcThreadAttributeList
UpdateProcThreadAttribute
LoadAppInitDlls
Sleep
GetExitCodeProcess
MoveFileExW
OpenSCManagerW
OpenServiceW
QueryServiceStatus
StartServiceW
CloseServiceHandle
GetUserNameW
ConvertSidToStringSidW
LookupAccountNameW
CreateWellKnownSid
LookupPrivilegeValueW
ConvertStringSecurityDescriptorToSecurityDescriptorW
RpcStringBindingComposeW
RpcBindingFromStringBindingW
RpcStringFreeW
RpcBindingSetOption
RpcBindingSetAuthInfoExW
RpcBindingFree
NdrClientCall2
NdrClientCall3
BCryptOpenAlgorithmProvider
BCryptSetProperty
BCryptGenerateSymmetricKey
BCryptDecrypt
BCryptDestroyKey
BCryptCloseAlgorithmProvider
BCryptGetProperty
BCryptGenRandom
CoCreateInstance
CoInitializeEx
CoUninitialize
CoInitializeSecurity
CoSetProxyBlanket
if >win7/server 2008 r2
{
CreateDecompressor
CloseDecompressor
Decompress
}
Et voilà, cela marque la fin de la première moitié du défi d'analyse BlackLotus.
============================================================================
Pour la seconde moitié
Perspective assembleur

Perspective pseudo-code

Nous commencerons la dissection par la fonction some_hash()
============================================================================
Perspective graphique

Perspective assembleur



Perspective pseudo-code
