; /************************************************************* ; * Ukazkovy shellcode, urceny ke clanku na soom.cz. ; * ; * LoadLibraryA(), MessageBox(), ExitProcess() ; * - Vyhleda kernel v pameti ; * - Zobrazi zpravu Ahoj ; * ; * ; * ; * Zkompilovani: ; * - ml /c /coff /Cp shellcode03.asm ; * - link /subsystem:windows /section:.text,w shellcode03.obj ; * ; * babcca [at] seznam.cz ; * ; * ; \************************************************************* .386 .model flat, stdcall option casemap :none .code db "Zacatek kodu:", 0, 0 start: ; ############################################################ ; ## Tendle kod je nutne zlo, ## ; ## mozna se da zmensit, ## ; ## ale bohuzel jsem lepsi reseni nenalezl :). ## ; ## ## ; ## - Hledame zacatek knihovny kernel32.dll, pote hledame ## ; ## adresu funkce GetProcAddress, po skonceni mame v ## ; ## zasobniku ulozenu adresu funkce a kernelu. ## ; ## ## ; ############################################################ ; - Zacatek useku, ktery hleda kernel ; => xor eax, eax ; - Nuluj eax ; mov eax, dword ptr fs:[eax+30h] ; - Toto nejde prelozit, da se nahradit: db 64h, 8Bh, 40h, 30h test eax, eax ; - Proved bitovy soucin js hledej_kernel_9x ; - Skoc pokud je nastaven prinak SF (jedna se o system windows 9x) push esi ; - uloz esi mov eax, dword ptr ds:[eax+0Ch] ; - Do eax uloz dvojslovo na adrese: data_segmen : eax + 12 mov esi, dword ptr ds:[eax+01Ch] ; - Do esi uloz dvojslovo na adrese: data_segmen : eax + 28 lods dword ptr ds:[esi] ; - Nahraj do registru eax adresu DS:ESI (zvis/sniz esi o 4)? mov eax, dword ptr ds:[eax+8h] ; - Do eax uloz dvojslovo na adrese: data_segmen : eax + 8 pop esi ; - Obnov esi jmp hledej_zacatek_dll ; - Uz jsme nasli adresu kernelu, hledej_kernel_9x: ; - Heldej kernel na systemu 9x mov eax, dword ptr ds:[eax+34h] ; - Do eax uloz dvojslovo na adrese: data_segmen : eax + 52 add eax, 7Ch ; - K eax pricti 124 mov eax, dword ptr ds:[eax+3Ch] ; - Do eax uloz dvojslovo na adrese: data_segmen : eax + 60 ; <= ; - Tady konci usek hledani kernelu, v eax je adresa kernelu hledej_zacatek_dll: ; - Pro jistotu kontrola cmp word ptr [eax], 5A4Dh ; - Porovnej 2 znaky s MZ (hlavicka dll) je mam_zacatek_dll ; - Pokud je shoda, mame presnou adresu dec eax ; - Pokud ne sniz eax o jedna (=> Pokus se najit presnejsi adresu) jmp hledej_zacatek_dll ; - Pokracuj v hledani mam_zacatek_dll: ; - Mame presnou adresu push eax ; - Uloz adresu (handle) na zasobnik, pro dalsi pouziti jmp getprocaddress ; - Ziskej retezec GetProcAddress MamGetProcAddress: pop edx ; - Uloz ukazatel do edx xor ebx, ebx ; - Nuluj ebx mov byte ptr [edx+14], bl ; - Dosad NULL do retezce mov ebx, eax ; - Zkopiruj adresu kernelu do ebx mov esi, dword ptr [ebx+3Ch] ; - Offset na PE add esi, ebx ; - K tomuto ofsetu pricti adresu kernelu mov esi, dword ptr [esi+78h] ; - Export Table Address add esi, ebx ; - K tomuto ofsetu pricti adresu kernelu mov ecx, dword ptr [esi+14h] ; - Do ecx uloz pocet exportovanych funkci knihovnou mov edi, dword ptr [esi+20h] ; - Do edi uloz adresu kde je offset na seznam nazvu funkci add edi, ebx ; - K teto adrese pricti adresu kernelu xor ebp, ebp ; - Nuluj ebp, zde si budeme ukladat indexi funkci push esi ; - Schovame Export Table, jelikoz se bude menit ; Ziskame index funkce v knihovne smycka_hledejadresu: ; - Do (Smicka) push edi ; - Ulozime si edi, ecx na zasobnik push ecx ; mov edi, dword ptr [edi] ; - Najdeme si offset na nazev dane fce add edi, ebx ; - Ziskame adresu z ofsetu mov esi, edx ; - Nas string GetProcAddress xor ecx, ecx ; - Nuluj ecx, kvuli NULL znaku mov cl, 0Eh ; - Do 8 bitoveho cl (z ecx) uloz delku retezce (14) repz cmpsb ; - Porovname (ecx = delka retezce) je getprocaddr_nalezeno ; - Pokud souhlasi pokracujeme dal pop ecx ; - Pokud ne, vratime ecx = zbyvajici pocet funkci pop edi ; - Obnovime edi = adresa na offsety s nazvy funkci add edi, 4h ; - Pricteme delku ofsetu, takze se edi odkazuje na dalsi funkci inc ebp ; - Zvisime ebp (indexy funkci) a zkousime dalsi loop smycka_hledejadresu ; - Until (ecx <> 0) ; - Hledame dalsi (pocet kroku v ecx ktery je nastaven na pocet exportovanych fci) getprocaddr_nalezeno: pop ecx ; - Vratime ze zasobniku 3 ulozene hodnoty pop edi pop esi mov ecx, ebp ; - Presuneme index do ecx shl ecx, 1 ; - Vynasobime dvema mov eax, dword ptr [esi+24h] ; - Najdeme adresu na tabulku s dalsimi offsety add eax, ebx ; - K adrese pricteme adresu kernelu add eax, ecx ; - K eax pricteme index a ziskame adresu na index teto fce v jine tabulce :) xor ecx, ecx ; - Nuluj ecx, ecx mov cx, word ptr [eax] ; - Do cx nacteme slovo z teto adresy cimz ziskame dany index shl ecx, 2h ; - Vynasobime 4ma mov eax, dword ptr [esi+1Ch] ; - Najdeme offset tabulky adres funkci add eax, ebx ; - Z offsetu ziskame adresu add eax, ecx ; - Pricteme index a ziskali sme konecnou adresu na ktere je offset fce mov eax, dword ptr [eax] ; - Nacteme offset dane fce add eax, ebx ; - Konecne mame vyslednou adresu push eax ; - Ulozime adresu na zasobnik ; ############################################################ ; ## Tady nam to zlo konci, odtud ## ; ## je uz jen nas vlastni kod. ## ; ## ## ; ## - Na vrcholu zasobniku je adresa GetProcAddres, pod ## ; ## ni je adresa kernelu. V eax mame adresu fce. ## ; ## ## ; ############################################################ ; - Tady zacina vlastni telo naseho shellcodu ; EBX => Kernel (Nepotrebne, mame v zasobniku) ; EAX => GetProcAddress (Nepotrebne, mame v zasobniku) ; ESP => Ukazatel na vrchol zasobniku ; ; +0 _________________ ; | GetProcAddress | \ ; |_________________| \ ; +4 _________________ > Zasobnik ; | Kernel32.dll | / ; |_________________| / jmp load ; - Ziskej ukazatel na retezec mam_load: xor ecx, ecx ; - Nuluj ecx, pro dosazeni NULL pop edx ; - Vem ukazatel mov byte ptr [edx+0Ch], cl ; - Pridej NULL push edx ; - Uloz na zasobnik push dword ptr [esp+08h] ; - Kernel se nam posunul o dalsi 4 bajty nahoru, tedy puvodni 4 + 4*1 = 8 ; Adresa kernelu je zaroven i handle call dword ptr [esp+08h] ; - Fce se posunula o 8 bajtu (dva parametry), tedy 0 + 4*2 = 8 ; V eax adresa LoadLibraryA jmp usr ; - Ziskej offset retezce mam_usr: xor ecx, ecx ; - Nuluj ecx, pro dosazeni NULL pop edx ; - Vem offset mov byte ptr [edx+0Ah], cl ; - Pridej NULL push edx ; - Uloz offset retezce User32.dll call eax ; - Zavolej LoadLibraryA(nazev_knihovny) jmp msg ; - Ziskej offset retezce mam_msg: xor ecx, ecx ; - Nuluj ecx, pro dosazeni NULL pop edx ; - Vem offset mov byte ptr [edx+0Bh], cl ; - Pridej NULL push edx ; - Uloz offset na string MessageBoxA push eax ; - Uloz handle knihovny User32.dll call dword ptr [esp+08h] ; - Zavolej GetProcAddress(handle, nazev_fce) ; V eax adresa funkce MessageBoxA jmp txt ; - Ziskej offset retezce mam_txt: xor ecx, ecx ; - Nuluj ecx, pro dosazeni NULL pop edx ; - Vem offset mov byte ptr [edx+04h], cl ; - Pridej NULL push ecx ; - Uloz 4. parametr na zasobnik (0 = MB_OK) push edx ; - Uloz 3. parametr na zasobnik (Nadpis) push edx ; - Uloz 2. parametr na zasobnik (Text zpravy) push ecx ; - Uloz 1. parametr na zasobnik (0 = Handle plochy) call eax ; - Zavolej MessageBoxA(handle, text, nadpis, typ) ; V eax ulozena navratova hodnota fce (0 - OK, <> 0 - Error) jmp exit mam_exit: xor ecx, ecx ; - Nuluj ecx, pro dosazeni NULL pop edx ; - Vem offset mov byte ptr [edx+0Bh], cl ; - Pridej NULL push edx ; - Uloz na zasobnik push dword ptr [esp+08h] ; - Kernel se nam posunul o dalsi 4 bajty nahoru, tedy puvodni 4 + 4*1 = 8 ; Adresa kernelu je zaroven i handle call dword ptr [esp+08h] ; - Fce se posunula o 8 bajtu (dva parametry), tedy 0 + 4*2 = 8 ; V eax adrresa ExitProcess xor ecx, ecx ; - Nuluj ecx push ecx ; - Uloz 0 na zasobnik (exit_code) call eax ; - Zavolej ExitProcess(exit_code) => konec :) load: call mam_load db "LoadLibraryAN" usr: call mam_usr db "user32.dllN" msg: call mam_msg db "MessageBoxAN" txt: call mam_txt db "AhojN" exit: call mam_exit db "ExitProcessN" getprocaddress: ; - Potreba pri hledani kernelu call MamGetProcAddress db "GetProcAddressN" db "<-Konec kodu!",0,0 end start