Skip to content

Instantly share code, notes, and snippets.

@davide99
Created April 12, 2021 16:35
Show Gist options
  • Save davide99/967e313952c08ea33ccfc113a7040c2e to your computer and use it in GitHub Desktop.
Save davide99/967e313952c08ea33ccfc113a7040c2e to your computer and use it in GitHub Desktop.
;------------------------------------------------
; Minimal Hello World with no linked libraries
;
; Author: Davide Pisanò
;------------------------------------------------
.386
.model flat, stdcall
option casemap:none
assume fs:nothing
.DATA
HelloWorldString db "Hello world", 0
Kernel32Dll dw "K", "E", "R", "N", "E", "L", "3", "2", ".", "D", "L", "L", 0
Kernel32DllLen equ 26
LoadLibraryAName db "LoadLibraryA", 0
LoadLibraryANameLen equ 13
GetProcAddressName db "GetProcAddress", 0
GetProcAddressNameLen equ 15
User32Dll db "USER32.DLL", 0
MessageBoxAName db "MessageBoxA", 0
.CODE
memcmp PROC ptr1:DWORD, ptr2:DWORD, len:DWORD
push ESI
push EDI
push ECX
mov ESI, ptr1 ; ESI = ptr1
mov EDI, ptr2 ; EDI = ptr2
mov ECX, len ; ECX = len
cld ; Clear direction flag: increasing addresses
cmp ECX, ECX ; if len==0 don't compare anything
repe cmpsb ; compare bytes at DS:ESI and ES:EDI while ZF==1
setne AL ; set AL if ZF=0
movzx EAX, AL
pop ECX
pop EDI
pop ESI
ret
memcmp ENDP
findProcAddressByName PROC OrdinalPos:DWORD, OrdinalTableRVA:DWORD, AddressTableRVA:DWORD, DllBase:DWORD
push ECX
push EBX
mov EBX, DllBase
mov ECX, OrdinalTableRVA
shl OrdinalPos, 1 ; OrdinalPos * 2
add ECX, OrdinalPos ; ECX = Ordinal function RVA
mov AX, [EBX + ECX] ; EBX = DLLBase, AX = ordinal function
movzx EAX, AX
shl EAX, 2 ; EAX * 4
add EAX, AddressTableRVA
mov EAX, [EBX + EAX] ; EAX = function RVA
add EAX, EBX ; EAX = function pointer
pop EBX
pop ECX
ret
findProcAddressByName ENDP
MainEntry proc
LOCAL ExportedFunctions: DWORD
LOCAL ExportTableRVA: DWORD
LOCAL AddressTableRVA: DWORD
LOCAl OrdinalTableRVA: DWORD
LOCAL LoadLibraryA: DWORD
LOCAL GetProcAddress: DWORD
;
; Find kernel32.dll base address
;
mov EBX, [FS:30h] ; Get the PEB pointer from TEB (or TIB)
mov EBX, [EBX + 0Ch] ; Get the Ldr pointer from PEB
mov EBX, [EBX + 14h] ; Get the InMemoryOrderModuleList pointer from Ldr (pointer to first element)
findKernel32:
push Kernel32DllLen ; Length of KERNEL32.DLL
push [EBX + 40] ; Pointer to BaseDllName
push offset Kernel32Dll ; Pointer to Kernel32Dll
call memcmp
cmp EAX, 0
je foundKernel32
mov EBX, [EBX] ; Go to next entry
jmp findKernel32
foundKernel32:
mov EBX, [EBX + 16] ; EBX = kernel32.dll base address
;
; Check the PE signature
; Status:
; - EBX = DLLBase
;
mov EAX, [EBX + 3Ch] ; *(EBX+3Ch) = PE RVA, we dereference it in EAX
add EAX, EBX ; EAX points to {'P', 'E', '\0', '\0'} reversed = 0x00004550
mov ECX, EAX ; Save PE pointer for later
mov EAX, [EAX] ; dereference the pointer
cmp EAX, 00004550h
jne exit
;
; Find the export table RVA
; Status:
; - EBX = DLLBase
; - ECX = pointer to PE signature
;
mov EAX, [ECX + 78h] ; ECX + 78h points to the export table RVA, EAX contains the ExportTableRVA
mov ExportTableRVA, EAX
;
; Find the number of exported functions
; Status:
; - EAX = pointer to export table RVA
; - EBX = DLLBase
;
mov ECX, [EBX + EAX + 14h] ; 14 = offset
mov ExportedFunctions, ECX
;
; Find the address table RVA
; Status:
; - EAX = pointer to export table RVA
; - EBX = DLLBase
;
mov ECX, [EBX + EAX + 1Ch] ; 1C = offset
mov AddressTableRVA, ECX
;
; Find the name pointer table RVA
; Status:
; - EAX = pointer to export table RVA
; - EBX = DLLBase
;
mov ECX, [EBX + EAX + 20h] ; 20 = offset
mov ESI, ECX ; Save Name pointer table RVA for later
;
; Find the ordinal table RVA
; Status:
; - EAX = pointer to export table RVA
; - EBX = DLLBase
;
mov ECX, [EBX + EAX + 24h] ; 24 = offset
mov OrdinalTableRVA, ECX
;
; Find LoadLibraryA and GetProcAddress
; Registers that cannot be used:
; - EBX = DLLBase
;
mov LoadLibraryA, 0
mov GetProcAddress, 0
mov ECX, 0
findFuncLoop:
cmp ECX, ExportedFunctions
je findFuncLoopEnd
mov EAX, LoadLibraryA
and EAX, GetProcAddress
cmp EAX, 0
jnz findFuncLoopEnd ; found both functions?
mov EDX, [EBX + ESI] ; EDX = RVA of the function name, ESI = Name pointer table RVA
add EDX, EBX ; EDX = Pointer to function name "string"
push LoadLibraryANameLen ; 3rd argument
push offset LoadLibraryAName ; 2nd argument
push EDX ; 1st argument
call memcmp
cmp EAX, 0 ; found?
je foundLoadLibraryAPos
push GetProcAddressNameLen
push offset GetProcAddressName
push EDX
call memcmp
cmp EAX, 0 ; found?
je foundGetProcAddressNamePos
findFuncLoopTail:
inc ECX
add ESI, 4 ; move pointer to next function name
jmp findFuncLoop
foundLoadLibraryAPos:
mov LoadLibraryA, ECX ; initially save the position
jmp findFuncLoopTail
foundGetProcAddressNamePos:
mov GetProcAddress, ECX ; initially save the position
jmp findFuncLoopTail
findFuncLoopEnd:
mov EAX, LoadLibraryA
and EAX, GetProcAddress
cmp EAX, 0 ; We can't find the functions
je exit
push EBX ; DLLBase
push AddressTableRVA
push OrdinalTableRVA
push LoadLibraryA
call findProcAddressByName
mov LoadLibraryA, EAX ; override the position with the actual pointer
push EBX ; DLLBase
push AddressTableRVA
push OrdinalTableRVA
push GetProcAddress
call findProcAddressByName
mov GetProcAddress, EAX ; override the position with the actual pointer
push offset User32Dll
call LoadLibraryA
push offset MessageBoxAName
push EAX
call GetProcAddress
push 0
push offset HelloWorldString
push offset HelloWorldString
push 0
call EAX
exit:
ret
MainEntry endp
END
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment