
BlackLotus-Z2A-Challenge, Niente da vedere qui per ora , per favore passa oltre
BlackLotus-Z2A-Challenge, non c'è niente da vedere per ora, per favore proseguite
Prima di tutto

Per scopi puramente estetici, prenderò in prestito (ruberò) :)) senza vergogna le regole di rilevamento yara dalla soluzione di @darthmaulware(Ryan “DM” Smith) solo per farlo sembrare professionale. Vai a dare un'occhiata al suo Twitter, è una persona fighissima! P.S. Ryan, per favore non ti arrabbiare perché l'ho rubato :))) e grazie per il supporto su Discord :)
Date un'occhiata anche al suo lavoro :)
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)
}
Anche per ragioni estetiche rubo anche questo perché è figo :) di nuovo scusa Ryan, per favore non arrabbiarti con me :)```
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 se fossi in te non mi fiderei al 100% di capa (almeno in questo caso specifico) perché qui dice che il campione usa rc4 mentre in realtà usa aes, ma vabbè, come già detto questo è strettamente per estetica :)
Prima di iniziare, incontrerai durante questo report un sacco di

Per favore ignora questo perché ida non riesce a disassemblare correttamente in assembly; questo è

E questo crasha il debugger? Perché?
perché cerca di scrivere all'indirizzo 0, cosa che nel folklore hacker è nota come scrittura a un puntatore nullo, che era qualcosa di ampiamente sfruttato per ottenere CE (esecuzione di codice), ed è stato ovviamente mitigato.
E quindi con la mitigazione attuale, se provi a scrivere a 0, il processo crasha - nel nostro caso il malware - e di conseguenza anche il debugger.
Ora, se apriamo questo in ida

Ho rinominato ogni funzione per indicare una certa logica che svolge; iniziamo con la prima funzione, do_syscall()

Notiamo subito l'uso delle syscall, che è un metodo noto per rendere la vita più dura a un analista nell'analisi dinamica.
Per chi non ha familiarità con le syscall in Windows, ecco un bel video fatto da oalabs(https://www.youtube.com/watch?v=Uba3SQH2jNE). Per favore guardatelo perché l'ho fatto anch'io e mi ha aiutato molto a capire cosa succede in questa funzione.
Se ispezioniamo il "pseudo-codice" generato da ida, vediamo che appare così.

Se ispezioniamo staticamente solve_hash, appare così.


Da una prospettiva pseudo, appare così.

Per favore fate riferimento a solve_hash.py per vedere la mia "emulazione" di questo, nel caso vogliate vedere un pezzo di automazione e scoprire come le syscall vengono risolte tramite l'algoritmo di lookup basato su hash. Ma comunque, questo fa parte di un progetto chiamato SysWhispers2, o almeno è ciò che presumo gli autori del malware abbiano usato come ispirazione. Ad ogni modo, fate riferimento al video di oalabs qui sopra per una migliore comprensione.
Comunque, la funzione anti_debug è facilmente bypassabile e ben nota(https://anti-debug.checkpoint.com/techniques/debug-flags.html#manual-checks-ntglobalflag). Il modo per bypassarla è avere scyllahide installato e l'opzione NtGlobalFlag spuntata(che dovresti avere attiva di default se usi x86dbg). Ad ogni modo, ecco cosa dovresti controllare:

E così appare la "pseudo-funzione" anti-debug:

Abbastanza semplice, se me lo chiedi.
Poi abbiamo la funzione check_inmemory_ldr, che appare così:


Ora, ai fini dell'analisi della funzione, se chiediamo gentilmente a x86dbg, possiamo vedere che se eseguiamo fino all'istruzione syscall, x86dbg sarà così gentile da restituirci la syscall che sta per eseguire. Nel nostro caso:

Ora, in base al contesto attuale, possiamo presumere che Ntsetinformationthread venga usata come una sorta di trucco anti-analisi. Sicuramente, se facciamo una rapida ricerca su Google, troviamo questo: https://ntquery.wordpress.com/tag/ntqueryinformationthread/
Fortunatamente è facilmente bypassabile, basta patcharlo con nop+ret :)
=============================================================================
Seguendo l'ordine di esecuzione, dopo questa prossima funzione c'è

Ancora una volta, se ispezioniamo per vedere cosa fa

Controlla semplicemente un flag nel TEB per vedere se il processo corrente (l'exe nel nostro caso) è sotto debug. Anche questo è facilmente bypassabile, essendo un metodo noto(https://anti-debug.checkpoint.com/techniques/debug-flags.html#manual-checks-peb-beingdebugged-flag), nello stesso modo in cui abbiamo usato scyllahide; questa volta devi avere spuntata

che dovrebbe essere attiva di default
=============================================================================
Ora, custom_hash2_and_aplib_possible, che appare così:

E da una prospettiva a grafo:

Per favore fate riferimento a decompress_aplib.py per vedere l'"emulazione" di questa funzione.
Esplorando get_ntdll_and_unhook2, appare così:


Da una vista a grafo appare così:

Non male :))
Facendo un passo indietro, abbiamo aplib_decompress, che ora appare così:

Da un'analisi statica del codice appare così:




Mhmm, un po' grande, ma niente di cui preoccuparsi, ragazzi, è fattibile :)
Se usi lo script di emulazione aplib_decompress.py, dovresti ottenere qualcosa del genere:

Una cosa figa che non ho notato in altri blog/analisi era questa: se diamo un'altra occhiata al pseudo-codice di ida per ntdll_and_unhook2

vedrai un memcpy interessante.
A un certo punto, mentre facevo l'analisi dinamica, ho notato un'altra dll caricata, che era un'altra versione di ntdll:

se guardiamo nel debugger, appare così:

Non sono riuscito a rilevare cosa fosse stato hookato/patchato, ma se qualcuno lo sa, per favore faccia una pull request e modifichi questo documento. Inoltre, nei miei tentativi di scoprire cosa viene hookato, ho provato a fare un bindiff tra le due ntdll e sfortunatamente non ho trovato nulla, ma potrebbe essere perché stavo già facendo il diff sulla dll di sistema che era infetta, quindi non era un'esecuzione pulita, quindi forse è per questo ¯_(ツ)_/¯

=============================================================================
Proseguendo con il processo di analisi, tra le funzioni non spiegate abbiamo some_hasing e ntquertyinformationprocess_anti_debug, che non sono state ancora spiegate. check_if_being_debug_through_teb e anti_debug sono già state spiegate, fortunatamente, perché sono state usate nella/e funzione/funzioni precedente/i, quindi per favore rileggete le sezioni precedenti se volete rivedere le conoscenze su di esse. Vorrei iniziare prima con ntquertyinformationprocess_anti_debug e poi finire con some_hasing.
Ispezionandola, vediamo la stessa funzione chiamata 3 volte.

E da un punto di vista assembly:


Per comodità l'ho già nominata, cioè ntquertyinformationprocess_ProcessDebugPort. Da dove ho saputo che le funzioni chiamate erano ntquertyinformationprocess_ProcessDebugPort? Ispezionandole, si rivelano una chiamata di funzione già vista / algoritmi a noi noti:

E i commenti fatti in ida? Beh, se cerchi ntqueryinformationprocess su Google, troviamo una buona risorsa sull'anti-debug(https://anti-debug.checkpoint.com/techniques/debug-flags.html). Se la seguiamo, possiamo vedere che ci spiega che, in base a certi valori passati come parametri a questa funzione, può essere usata come metodo anti-debug.
Per esempio, per la prima chiamata possiamo vedere i seguenti argomenti di stack nel debugger:

Se ora andiamo a controllare la pagina MSDN per ntqueryinformationprocess:

Lo stesso processo si ripete per le due syscall successive:

dove 0x1e è specifico per il metodo anti-debug ProcessDebugObjectHandle(https://www.apriorit.com/dev-blog/367-anti-reverse-engineering-protection-techniques-to-use-before-releasing-software)
e infine ProcessDebugFlags

Quindi come li bypassiamo?! Calmati, fam, perché ScyllaHide ha le spalle coperte

Come puoi vedere

Quindi siamo al sicuro! Non proprio: mentre ScyllaHide ci copre le spalle per le prime 2 syscall, per l'ultima syscall dobbiamo farlo manualmente! E che diavolo faccio??? Beh, soluzione semplice! Ritorniamo da questa funzione, cioè dall'intera ntquertyinformationprocess_anti_debug, e impostiamo eax a 0. Quindi in circostanze normali appare così:

E con il nostro "aiuto" appare così e lasciamo proseguire l'esecuzione in sicurezza :)

=============================================================================
Ora, some_hasing: ormai conoscete la procedura.

E ora il pseudo-codice:

Notiamo una cosa strana qui. Il pseudo-codice di ida fallisce qui... perché se seguiamo il grafo dopo call_syscall ci sono altre istruzioni da disassemblare. Quindi cosa facciamo qui? Beh, faremo affidamento sul debugger per analizzare dinamicamente questo codice...
Quindi vediamo che la syscall che esegue è:

Ora, se cerchiamo ntquerydefaultlocale, Google mostra che è un'API non documentata che accetta 2 argomenti(http://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FLocale%2FNtQueryDefaultLocale.html). Figo, quindi cosa fa? Restituisce l'identificatore di locale corrente. Figo, e allora che diavolo è un identificatore di locale? Da MSDN (https://learn.microsoft.com/en-us/windows/win32/intl/locale-identifiers): un valore a 32 bit composto da un identificatore di lingua e un identificatore di ordinamento. In sintesi, che lingua parli su quel PC :)
Successivamente controlla se l'API non ha fallito e, se non è fallita, prende il valore restituito da ntquerydefaultlocale, sottrae 0x419 e lo confronta con 0x26 (probabilmente una costante), come puoi vedere nell'immagine qui sotto.

Se non è minore o uguale a 0x26, lo confronta con 0x818, altrimenti fa lo stesso confronto con 0x819, come puoi vedere chiaramente.

Quindi che diavolo sta succedendo qui? E perché queste costanti specifiche? Beh, vado dritto al punto. Mentre cercavo diverse costanti, mi sono imbattuto in questo articolo(https://www.cnblogs.com/DirWang/p/17281690.html#autoid-8-0-0), di un ricercatore che ha già analizzato blacklotus meglio di quanto potrei fare io. E come disse qualcuno una volta: "Non puoi imbrogliare nell'analisi di malware, puoi solo rendere il tuo lavoro più facile". Quindi quello che ha detto il ricercatore è che fondamentalmente questa funzione controlla costanti specifiche che identificano quale lingua è parlata sul computer. Nel suo articolo fornisce un link a questo(https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/MS-LCID/[MS-LCID].pdf) che è come un documento standard Microsoft con tutti gli identificatori di lingua.
Ora, usando la nostra logica hax00r l33t, possiamo dedurre che probabilmente 0x26 è una specie di offset usato, quindi tipo qualsiasi identificatore di lingua successivo a 0x419 entro 0x26, che sono:

Se ispezioniamo anche quel documento, possiamo vedere che 0x818 corrisponde a:

e 0x819 a:

E sappiamo da precedenti "indagini"/report online che questo malware non girava su certi PC di certe regioni del mondo, quindi possiamo concludere che questa funzione controlla su quale regione si trova la macchina infetta.
=============================================================================
Che hamburger pazzesco finora, fam, e adesso? Serviamo la funzione some_more_syscall. Va bene! Allora cosa hai lì, ack! Eccola:

Ne vogliamo ancora! Certo, dawg!



Hmmmm

Quindi controlla se kerneldebugger è presente(https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntexapi/system_information_class.htm)(0x23), controlliamo, controlliamo!
E quindi, ack! Abbiamo pcr (festa di pile e combinazioni)

=============================================================================
Ora, se ispezioniamo la funzione iterate_over_modules(), appare così:

Da una prospettiva "pseudo-codice" appare così:

Dal punto di vista autonomo, sembra che l'assembly e il pseudo-codice di ida corrispondano; quindi qual è la logica di questa funzione? Beh, abbastanza semplice: itera sui moduli in memoria (dll) e verifica una lista di hash :) 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;
E se nessuna dll in memoria risulta avere lo stesso hash, restituiamo 0, altrimenti 1 e facciamo crashare il debugger. Quindi, con questa conclusione, possiamo dire che è un altro metodo anti-analisi. Corretto, ma riguardo a ciascuno dei valori di hash? Beh, imbroglierò di nuovo (come disse qualcuno una volta, non puoi imbrogliare nell'analisi di malware, solo rendere la tua vita più facile :) ). Il ricercatore asiatico summenzionato è stato così gentile da fornirci una lista di valori da cui sono stati derivati i valori:
sbiedll.dll dbghelp.dll api_log.dll dir_watch.dll pstorec.dll vmcheck.dll wpespy.dll cmdvrt64.dll avghookx.dll snxhk.dll
Ora, per vedere dinamicamente se alcuni valori corrispondono a una delle dll menzionate:

E certo che corrispondono :)
Ma come sono arrivato alla conclusione che l'algoritmo verifica questi valori? Beh, quando ho emulato un pezzo di questo malware, ho dovuto reimplementare iterate_over_module_name_and_hash (nel file solve_hash_syscalls.py) e in questa funzione abbiamo:

dove x (argomento passato) in questo caso è v2, che è un array (un puntatore) di valori che viene incrementato (dove punta nell'array) finché non corrisponde a nessuno dei valori già menzionati sopra. Accidenti, è un bel boccone :P
Figo! Prossimo
=============================================================================
iterate_over_modules2, più o meno stessa storia qui:

E pseudo-codice:

Più o meno stessa storia, solo hash diversi :)
v5[0] = 0x7D73878E; v5[1] = 0xEF36424B; v5[2] = 0xAF64BC2B; v5[3] = 0x1DBBC879; v5[4] = 0xAE6D1D56; v5[5] = 0x7B3242F2; v5[6] = 0x14D922B9; v5[7] = 0x4C92DF53;
che corrispondono a:
sample.exe bot.exe sandbox.exe malware.exe test.exe klavme.exe myapp.exe testapp.exe
=============================================================================
iterate_over_modules3, stessa storia qui:

E pseudo-codice:

stessa storia, hash diversi :)
=============================================================================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;
che corrispondono a
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: ho finito per rinominarlo in anti_debug_measure2_RtlAddVectoredExceptionHandler_int3. Perché? Lo vedrete tra un minuto. Quindi appare così

E da una prospettiva di pseudo-codice appare così

Allora che diavolo è questo? Beh, fondamentalmente crea un gestore di eccezioni per __debugbreak(int 3) che eseguirà codice ogni volta che viene sollevata una int3. Ho finito per cercare altro e mi sono imbattuto in questo
(https://blog.lexfo.fr/dridex-malware.html) che è una bella risorsa che ci fa capire che questo è semplicemente un meccanismo anti-debug, e nel nostro caso ci basta eseguire questa funzione e ignorare sub_13F2820D0 che
viene attivato ogni volta che eseguiamo int3 e patchiamo eax a 0 :) quindi in memoria l'esecuzione appare così :)
Prima della patch

Dopo la patch

Dopodiché esci dalla funzione e modifichi anche rax/eax a 0 in modo da saltare il jne che farebbe crashare il debugger

=============================================================================
Anti_debug_measure_2 che in seguito ho cambiato in anti_debug_measure2_RtlAddVectoredExceptionHandler_int2


Di nuovo, niente di nuovo sotto il sole: stessa cosa, solo che aggancia un altro int/syscall, questa volta int2. Stesso trucco per bypassarlo: usare il patching dinamico del valore di ritorno per superarlo :)
Se cerchi su Google "anti analysis 2dh" apparirà un sacco di roba, quindi sì, puoi usarla come riferimento per saperne di più. Non ci ho passato molto tempo :)
Per questo, anche se provi a fare step over, finirai comunque alla ret come qui

e per bypassarlo basta eseguire fino al return e sei a posto :)
=============================================================================
Quindi ora arriva anti_debug measure heap, che in seguito ho rinominato in iterate_over_current_process_and_check_again_hases

E una caratteristica interessante di questa funzione è che usa ntquerysysteminformation all'interno di iterate_over_current_process_and_hash_check per elencare tutti i processi in esecuzione. Ecco come appare iterate_over_current_process_and_hash_check


Fico, ma come diavolo sono arrivato alla conclusione che iterate_over_current_process_and_hash_check fa ciò che il nome suggerisce? Beh, prima di tutto c'è la chiamata a ntquerysysteminformation, che se cerchi su Google vedrai che viene usata per ottenere la lista dei processi in esecuzione, e poi ho semplicemente fatto un'ipotesi basata sul seguente snippet di codice 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 ) e cioè che copiasse la lista dei processi, iterasse su ciascuno e confrontasse ogni hash dell'array precedente con qualunque processo fosse in esecuzione. Di nuovo, complimenti al blog di ricerca dell'asiatico, perché non so come diavolo abbia fatto a ottenere il nome effettivo dei valori dell'array v4. Fare riferimento a iterate_over_modules.py nel caso vogliate vedere come ho emulato tutto questo.
Ps. se esegui il debug dinamico di questa funzione, finirai di nuovo su int 2d, e la soluzione è la stessa menzionata sopra, solo che in pratica esegui fino al return 0xf volte, il che sostanzialmente attraversa l'hev e dopo, se vuoi essere sicuro di arrivare al return da iterate_over_current_process_and_check_again_hases, metti un breakpoint alla fine di questa funzione e sei al sicuro :)
============================================================================= anti_debug_measure_heap



Quindi sì, siamo fortunati che non sia così grande, e inoltre abbiamo già implementato demangle_strings. Ora l'ho reimplementato per array più grandi: andate a vedere anti_debug_measure.py .
questo fondamentalmente confronta con``` \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
Ora get_oem_key







Prima esegue il demangling della stringa in```
\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
E poi interroga
\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
e confronta i loro valori con qemu, vbox, VMWARE, come si può vedere nello snippet di IDA e nella finestra x86 :)


Come si può vedere nel primo snippet, controlla vmware rispetto ai valori memorizzati nella mia VM al momento dell'analisi :)
Niente di che: basta eseguire questa funzione fino a ret e cambiare eax quando ritorna a 0 :) per bypassare questo metodo anti-analisi :)
=============================================================================
ora get_oem_from_firmware





Ora qualcosa di interessante: vediamo che questa funzione inizia con sub_13F267288() a cui viene passato 0x52534D42 come parametro. Se cerchi questo valore su Google, troverai molte domande interessanti su vari forum, ad esempio (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==/) oppure questo (https://github.com/digitalocean/go-smbios/blob/master/smbios/stream_windows.go), ma la cosa più interessante è che dopo aver letto questo e aver cercato RSMB potresti imbatterti in questo https://evasions.checkpoint.com/techniques/firmware-tables.html che ci spiega che questo è un metodo anti-analisi :) Figo, quindi che cazzo fa?
Prima effettua il dump della tabella firmware SMBIOS, poi demangla una stringa, la prima stringa è qemu, e quindi chiama sub_13F2655E0 con come parametri la stringa demanglata e la tabella firmware. Dall'analisi statica


precisamente, per via di if ( v4 != v5), sono giunto alla conclusione che questa è una specie di implementazione di strcmp: controlla ciò che c'è nella tabella firmware con la stringa demanglata. Come si può vedere nel debugger
r8 è un puntatore alla tabella firmware e, cosa più interessante, possiamo vedere che blah blah qualcosa... virtualbox è il nome trovato nella tabella firmware, mentre rcx è qemu, quindi possiamo tranquillamente dire che è una specie di implementazione di strcmp. E sicuramente, come si può vedere, siamo al sicuro :) per questo controllo

Ora questo processo si ripete per le stringhe VirtualBox, vbox, VBOX, VMware :) In generale, la soluzione per bypassare il controllo di questa funzione è eseguirla fino a ret, applicare una patch a eax e continuare l'analisi :)
============================================================================
Bene, ora check_oem_key()






Quindi che cazzo fa? Beh, stesso trucco spiegato in precedenza, ma questa volta con la tabella ACPI. Cosa intendo? Beh, meglio leggere queste 14 slide (https://dc4420.org/slides/2015-11-24/acpi_vm_detect.pdf), la spiegano meglio, ma è lo stesso trucco economico :)) questa volta contro BOCHS, BXPC, VMWARE


============================================================================
Voglio iniziare con la funzione anti_debug_processor_Timing() e poi finire con check_for_flags(). Quindi

Ecco come appare. Quindi che cazzo fa? Legge il valore corrente del time-stamp del processore, poi prende il nome del processore (nel nostro caso GenuineIntel), poi sottrae il time-stamp ottenuto dal nome del processore e infine controlla semplicemente se il risultato è maggiore di 19999.
Dopo rdtsc

dopo cpuid

Come si può vedere, la stringa è divisa su 3 registri

E nel nostro caso vediamo che "falliamo" questo controllo e impostiamo eax a 1

La soluzione a questo anti-controllo è semplicemente tornare dalla funzione e applicare una patch a eax impostandolo a 0 :)
============================================================================
Ora entry_to_peb()







Da una prospettiva di pseudo-codice



Quindi, fino al controllo if non c'è niente di nuovo: abbiamo già visto questo tipo di algoritmo, quindi che succede? Beh, se vai al write-up già citato della ricerca asiatica, vedrai che dice che controlla se la versione di Windows è più recente di Win7/Server 2008 R2. Ma come gli è venuta quest'idea? Beh, se leggiamo http://waleedassar.blogspot.com/2012/08/major-minorsubsystemversion.html dice

inoltre, se leggete anche questo :)
e applicate ciò che dice qui, cioè che viene automaticamente castato alla struttura KUSER_SHARED_DATA, ma qui la mia IDA era buggata durante l'analisi, quindi è quel che è :)
Per non annoiarvi con la stessa ripetizione di più o meno lo stesso algoritmo, ecco le stringhe finali recuperate e demanglate delle funzioni :) È stato un processo estenuante, visto che è stato fatto con un debugger :) ero troppo pigro per emularlo.``` 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
}
E con questo si segna la fine della prima metà della sfida di analisi blacklotus.
============================================================================
Per la seconda metà
Prospettiva assembly

Prospettiva pseudo-codice

Inizieremo la dissezione con la funzione some_hash()
============================================================================
Prospettiva grafico

Prospettiva assembly



Prospettiva pseudo-codice
