Dynamic loading technology
Dynamic loading technology allows programmers from complex import table structure, constructed in the space program similar to calling the import table function mechanism is introduced.
Before understanding that knowledge is best to understand the windows virtual memory management, as detailed in my blog
Dynamic library technology
DLL static call
Also known as implicit invocation. Call a dynamic link library function is usually taken is: the addition of ".lib" library file produced when generating dynamic link library and ".inc" file contains the project application, when you want to use the DLL function , direct use of the function name. For example, adding user32.lib user32.inc call the MessageBox function, you can see examples of my another blog ;
DLL Dynamic Invocation
Also known as an explicit call. Load and unload DLL to achieve the purpose of calling DLL functions through the API function. Function and dynamic library calls related mainly includes:
- LoadLibrary (or the MFC AfxLoadLibrary), loaded dynamic link library
- GetProcAddress, acquire VA (virtual memory address) to introduce the function, the symbolic name or identification number to a DLL internal address
- FreeLibrary (or the MFC AfxFreeLibrary), the release of dynamic link library
Export function start address
Program to introduce dynamic link library ultimate goal is to call the dynamic link library function of the code, so to get the key derivation function starting address is dynamic link library dynamic loading technology.
Assuming now that user32.dll is dynamically loaded into memory at 0x77DF0000, then the entry is the address VA MessageBoxA:
0x77DF000 + 0x00026544 = 0x7E16544
If the VA after a function in the process of determining the space, the easiest way is to take the call by call it hard-coded
push xx ;显示往栈里压入该函数的参数,个数由调用的函数决定
......
mov eax,77E16544;
call eax
Loading techniques using dynamic programming in
Three steps:
1. Get the base address of kernel32.dll
2. Get the address of the function GetProcAddress (LoadLibrary function and obtain the address by this function)
3. using the acquired function address in the program code
1. Find the base address of kernel32.dll
.386
.model flat,stdcall
option casemap:none
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
;数据段
.data
szText db 'kernel32.dll在本程序地址空间的基地址为:%08x',0dh,0ah,0
kernel32Base dd ?
szBuffer db 256 dup(0)
;代码段
.code
_getKernelBase proc _dwKernelRetAddress
local @dwRet
pushad
mov @dwRet,0
mov edi,_dwKernelRetAddress
and edi,0ffff0000h ;查找指令所在页的边界,以1000h对齐
.repeat
.if word ptr [edi]==IMAGE_DOS_SIGNATURE ;找到kernel32.dll的dos头
mov esi,edi
add esi,[esi+003ch]
.if word ptr [esi]==IMAGE_NT_SIGNATURE ;找到kernel32.dll的PE头标识
mov @dwRet,edi
.break
.endif
.endif
sub edi,010000h
.break .if edi<070000000h
.until FALSE
popad
mov eax,@dwRet
ret
_getKernelBase endp
start:
mov eax,dword ptr [esp]
invoke _getKernelBase,eax
invoke wsprintf,addr szBuffer,addr szText,eax
invoke MessageBox,NULL,addr szBuffer,NULL,MB_OK
ret
end start
2. Get GetProcAddress address
By _getApi, until the base address of a dynamic link library, and knowing the calling function name, address can be obtained by calling the function
;------------------------------------------------
; 从内存中模块的导出表中获取某个 API 的入口地址
;------------------------------------------------
_getApi proc _hModule,_lpszApi
local @dwReturn,@dwStringLen
pushad
mov @dwReturn,0
call @F
@@:
pop ebx
sub ebx,offset @B
;创建用于错误处理的SEH结构
assume fs:nothing
push ebp
lea eax,[ebx+offset _ret]
push eax
lea eax,[ebx+offset _SEHHandler]
push eax
push fs:[0]
mov fs:[0],esp
;计算API字符串的长度(注意带尾部的0)
mov edi,_lpszApi
mov ecx,-1
xor al,al
cld
repnz scasb
mov ecx,edi
sub ecx,_lpszApi
mov @dwStringLen,ecx
;从DLL文件头的数据目录中获取导出表的位置
mov esi,_hModule
add esi,[esi+3ch]
assume esi:ptr IMAGE_NT_HEADERS
mov esi,[esi].OptionalHeader.DataDirectory.VirtualAddress
add esi,_hModule
assume esi:ptr IMAGE_EXPORT_DIRECTORY
mov ebx,[esi].AddressOfNames
add ebx,_hModule
xor edx,edx
.repeat
push esi
mov edi,[ebx]
add edi,_hModule
mov esi,_lpszApi
mov ecx,@dwStringLen
repz cmpsb
.if ZERO?
pop esi
jmp @F
.endif
pop esi
add ebx,4
inc edx
.until edx>=[esi].NumberOfNames
jmp _ret
@@:
;API名称索引->序号索引->地址索引
sub ebx,[esi].AddressOfNames
sub ebx,_hModule
shr ebx,1
add ebx,[esi].AddressOfNameOrdinals
add ebx,_hModule
movzx eax,word ptr [ebx]
shl eax,2
add eax,[esi].AddressOfFunctions
add eax,_hModule
;从地址表得到导出函数地址
mov eax,[eax]
add eax,_hModule
mov @dwReturn,eax
_ret:
pop fs:[0]
add esp,0ch
assume esi:nothing
popad
mov eax,@dwReturn
ret
_getApi endp
start:
invoke _getApi,hDllKernel32,addr szGetProcAddress ;获取GetProcAddress函数的内存地址
mov _GetProcAddress,eax
...
ret
end start
3. Use the programming function address acquired in the code
;声明函数
_QLMessageBoxA typedef proto :dword,:dword,:dword,:dword
;声明函数引用
_ApiMessageBoxA typedef ptr _QLMessageBoxA
...
;定义函数
_messageBox _ApiMessageBoxA ?
...;动态获取_messageBox的地址
;调用函数
invoke _messageBox,NULL,offset szText,NULL,MB_OK