;look up address of function from DLL export table
;rcx=DLL name string, rdx=function name string
;DLL name must be in .lookup_api_uppercase
;r15=address of LoadLibraryA (optional, needed if export is forwarded)
;returns address in rax
;returns 0 if DLL not loaded or exported function not found in DLL
;lookup_api func
lookup_api:
Sub rsp, 28H ;set up stack frame in case we call loadlibrary
Call get_offset
Add rdx, r14
Add rcx, r14
.lookup_api_start
Push 60H
Pop rax
DB 65H, 4CH, 8BH, 00H ;Mov r8, Gs:[rax] peb
Mov r8, [r8 + 18H] ;peb loader data
Lea r12, [r8 + 10H] ;InLoadOrderModuleList (list head) - save for later
Mov r8, [r12] ;follow _LIST_ENTRY->Flink to first item in list
Cld
.lookup_api_for_each_dll ;r8 points to current _ldr_data_table_entry
Mov rdi, [r8 + 60H] ;UNICODE_STRING at 58h, actual string buffer at 60h
Mov rsi, rcx ;pointer to dll we're looking for
.lookup_api_compare_dll
Lodsb ;load character of our dll name string
Test Al, Al ;check for null terminator
Jz >.lookup_api_found_dll ;if at the end of our string and all matched so far, found it
Mov Ah, [rdi] ;get character of current dll
Cmp Ah, 61H ;lowercase 'a'
Jl >.lookup_api_uppercase
Sub Ah, 20H ;convert to uppercase
.lookup_api_uppercase
Cmp Ah, Al
Jne >.lookup_api_wrong_dll ;found a character mismatch - try next dll
Inc rdi ;skip to next unicode character
Inc rdi
Jmp .lookup_api_compare_dll ;continue string comparison
.lookup_api_wrong_dll
Mov r8, [r8] ;move to next _list_entry (following Flink pointer)
Cmp r8, r12 ;see if we're back at the list head (circular list)
Jne .lookup_api_for_each_dll
Xor rax, rax ;DLL not found
Jmp >>.lookup_api_done
.lookup_api_found_dll
Mov rbx, [r8 + 30H] ;get dll base addr - points to DOS "MZ" header
Mov r9d, [rbx + 3CH] ;get DOS header e_lfanew field for offset to "PE" header
Add r9, rbx ;add to base - now r9 points to _image_nt_headers64
Add r9, 88H ;18h to optional header + 70h to data directories
;r9 now points to _image_data_directory[0] array entry
;which is the export directory
Mov r13d, [r9] ;get virtual address of export directory
Test r13, r13 ;if zero, module does not have export table
Jnz >.lookup_api_has_exports
Xor rax, rax ;no exports - function will not be found in dll
Jmp >>.lookup_api_done
.lookup_api_has_exports
Lea r8, [rbx + r13] ;add dll base to get actual memory address
;r8 points to _image_export_directory structure (see winnt.h)
Mov r14d, [r9 + 4] ;get size of export directory
Add r14, r13 ;add base rva of export directory
;r13 and r14 now contain range of export directory
;will be used later to check if export is forwarded
Mov Ecx, [r8 + 18H] ;NumberOfNames
Mov r10d, [r8 + 20H] ;AddressOfNames (array of RVAs)
Add r10, rbx ;add dll base
Dec Ecx ;point to last element in array (searching backwards)
.lookup_api_for_each_func
Lea r9, [r10 + 4 * rcx] ;get current index in names array
Mov Edi, [r9] ;get RVA of name
Add rdi, rbx ;add base
Mov rsi, rdx ;pointer to function we're looking for
.lookup_api_compare_func
Cmpsb
Jne >.lookup_api_wrong_func ;function name doesn't match
Mov Al, [rsi] ;current character of our function
Test Al, Al ;check for null terminator
Jnz >.lookup_api_have_not_found
Mov Al, [rdi]
Test Al, Al
Jz >.lookup_api_found_func ;if at the end of our string and all matched so far, found it
.lookup_api_have_not_found
Jmp .lookup_api_compare_func ;continue string comparison
.lookup_api_wrong_func
Loop .lookup_api_for_each_func ;try next function in array
Xor rax, rax ;function not found in export table
Jmp >>.lookup_api_done
.lookup_api_found_func ;ecx is array index where function name found
;r8 points to _image_export_directory structure
Mov r9d, [r8 + 24H] ;AddressOfNameOrdinals (rva)
Add r9, rbx ;add dll base address
Mov Cx, [r9 + 2 * rcx] ;get ordinal value from array of words
Mov r9d, [r8 + 1CH] ;AddressOfFunctions (rva)
Add r9, rbx ;add dll base address
Mov Eax, [r9 + rcx * 4] ;Get RVA of function using index
Cmp rax, r13 ;see if func rva falls within range of export dir
Jl >.lookup_api_not_forwarded
Cmp rax, r14 ;if r13 <= func < r14 then forwarded
Jae >.lookup_api_not_forwarded
;forwarded function address points to a string of the form <DLL name>.<function>
;note: dll name will be in .lookup_api_uppercase
;extract the DLL name and add ".DLL"
Lea rsi, [rax + rbx] ;add base address to rva to get forwarded function name
Lea rdi, [rsp + 30H] ;using register storage space on stack as a work area
Mov r12, rdi ;save pointer to beginning of string
.lookup_api_copy_dll_name
Movsb
Cmp B[rsi], 2EH ;check for '.' (period) character
Jne .lookup_api_copy_dll_name
Movsb ;also copy period
Mov D[rdi], 004C4C44H ;add "DLL" extension and null terminator
Mov rcx, r12 ;r12 points to "<DLL name>.DLL" string on stack
Call r15 ;call LoadLibraryA with target dll
Mov rcx, r12 ;target dll name
Mov rdx, rsi ;target function name
Jmp .lookup_api_start ;start over with new parameters
.lookup_api_not_forwarded
Add rax, rbx ;add base addr to rva to get function address
.lookup_api_done
Add rsp, 28H ;clean up stack
Ret
lookup_api_end:
;lookup_api endp