kernel32.dll默认很早加载进去,其中有函数用于加载进程,否则进程创建不出。
获取kernel32.dll的基地址:
1.使用vs cmd自带的dumpbin工具:dumpbin /headers kernel32.dll
还有PEinfo,onlydbg
XP OS下ntdll.dll,kernel32.dll不会被重定位。
2.从进程地址空间开始搜索
寻找PE特征字符串,分析导出表,查找GetProcAddress"特征函数“,再对齐即可。
3.从SEH框架开始查找
OS默认的结构化异常处理程度指向kernel32._except_handler3函数。
4.从PEB开始查找
5.直接从main函数入口时esp指向地址为kernel.dll中的一个值
//通过main函数入口里esp指向的返回地址为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
;------------------------
; 获取kernel32.dll的基址
; 从PEB结构中搜索kernel32.dll的基地址
; 戚利
; 2010.6.27
;------------------------
.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',0
szOut db '%08x',0dh,0ah,0
szBuffer db 256 dup(0)
;代码段
.code
start:
assume fs:nothing
mov eax,fs:[30h] ;获取PEB所在地址
mov eax,[eax+0ch] ;获取PEB_LDR_DATA 结构指针
mov esi,[eax+1ch] ;获取InInitializationOrderModuleList 链表头
;第一个LDR_MODULE节点InInitializationOrderModuleList成员的指针
lodsd ;获取双向链表当前节点后继的指针
mov eax,[eax+8] ;获取kernel32.dll的基地址
;输出模块基地址
invoke wsprintf,addr szBuffer,addr szText,eax
invoke MessageBox,NULL,addr szBuffer,NULL,MB_OK
ret
end start
;------------------------
; 获取kernel32.dll的基址
; 从SEH框架空间中搜索kernel32.dll的基地址
; 戚利
; 2010.6.27
;------------------------
.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',0
szOut db '%08x',0dh,0ah,0
szBuffer db 256 dup(0)
;代码段
.code
start:
assume fs:nothing
mov eax,fs:[0]
inc eax ; 如果eax=0FFFFFFFFh,则设置为0
loc1:
dec eax
mov esi,eax ;ESI指向EXCEPTION_REGISTRATION
mov eax,[eax] ;eax=EXCEPTION_REGISTRATION.prev
inc eax ;如果eax=0FFFFFFFFh,则设置为0
jne loc1
lodsd ;跳过0FFFFFFFFh
lodsd ;获取kernel32._except_handler地址
xor ax,ax ;按照10000h对齐,舍入
jmp loc3
loc2:
sub eax,10000h
loc3:
cmp dword ptr [eax],905A4Dh
jne loc2
;输出模块基地址
invoke wsprintf,addr szBuffer,addr szText,eax
invoke MessageBox,NULL,addr szBuffer,NULL,MB_OK
ret
end start
;------------------------
; 获取kernel32.dll的基址
; 从进程地址空间搜索kernel32.dll的基地址
; 戚利
; 2010.6.27
;------------------------
.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',0
szOut db '%08x',0dh,0ah,0
szBuffer db 256 dup(0)
;代码段
.code
start:
call loc0
db 'GetProcAddress',0 ;特征函数名
loc0:
pop edx ;edx中存放了特征函数名所在地址
push edx
mov ebx,7ffe0000h ;从高地址开始
loc1:
cmp dword ptr [ebx],905A4Dh
JE loc2 ;判断是否为MS DOS头标志
loc5:
sub ebx,00010000h
pushad ;保护寄存器1
invoke IsBadReadPtr,ebx,2
.if eax
popad ;恢复寄存器1
jmp loc5
.endif
popad ;恢复寄存器1
jmp loc1
loc2: ;遍历导出表
mov esi,dword ptr [ebx+3ch]
add esi,ebx ;ESI指向PE头
mov esi,dword ptr [esi+78h]
nop
.if esi==0
jmp loc5
.endif
add esi,ebx ;ESI指向数据目录中的导出表
mov edi,dword ptr [esi+20h] ;指向导出表的AddressOfNames
add edi,ebx ;EDI为AddressOfNames数组起始位置
mov ecx,dword ptr [esi+18h] ;指向导出表的NumberOfNames
push esi
xor eax,eax
loc3:
push edi
push ecx
mov edi,dword ptr [edi]
add edi,ebx ;edi指向了第一个函数的字符串名起始
mov esi,edx ;esi指向了特征函数名起始
xor ecx,ecx
mov cl,0eh ;特征函数名的长度
repe cmpsb
pop ecx
pop edi
je loc4 ;找到特征函数,转移
add edi,4 ;edi移动到下一个函数名所在地址
inc eax ;eax为计数
loop loc3
jmp loc5
loc4:
;特征函数匹配成功,输出模块基地址
invoke wsprintf,addr szBuffer,addr szText,ebx
invoke MessageBox,NULL,addr szBuffer,NULL,MB_OK
ret
end start
;------------------------
; 无导入表的HelloWorld
; 戚利
; 2010.6.27
;------------------------
.386
.model flat,stdcall
option casemap:none
include windows.inc
;声明函数
_QLGetProcAddress typedef proto :dword,:dword
;声明函数引用
_ApiGetProcAddress typedef ptr _QLGetProcAddress
_QLLoadLib typedef proto :dword
_ApiLoadLib typedef ptr _QLLoadLib
_QLMessageBoxA typedef proto :dword,:dword,:dword,:dword
_ApiMessageBoxA typedef ptr _QLMessageBoxA
;数据段
.data
szText db 'HelloWorldPE',0
szGetProcAddr db 'GetProcAddress',0
szLoadLib db 'LoadLibraryA',0
szMessageBox db 'MessageBoxA',0
user32_DLL db 'user32.dll',0,0
;定义函数
_getProcAddress _ApiGetProcAddress ?
_loadLibrary _ApiLoadLib ?
_messageBox _ApiMessageBoxA ?
hKernel32Base dd ?
hUser32Base dd ?
lpGetProcAddr dd ?
lpLoadLib dd ?
;代码段
.code
;------------------------------------
; 根据kernel32.dll中的一个地址获取它的基地址
;------------------------------------
_getKernelBase proc _dwKernelRetAddress
local @dwRet
pushad
mov @dwRet,0
;查找指令所在页的边界,以1000h对齐
mov edi,_dwKernelRetAddress
and edi,0ffff0000h
.repeat
;找到kernel32.dll的dos头
.if word ptr [edi]==IMAGE_DOS_SIGNATURE
mov esi,edi
add esi,[esi+003ch]
;找到kernel32.dll的PE头标识
.if word ptr [esi]==IMAGE_NT_SIGNATURE
mov @dwRet,edi
.break
.endif
.endif
sub edi,010000h
.break .if edi<070000000h
.until FALSE
popad
mov eax,@dwRet
ret
_getKernelBase endp
;-------------------------------
; 获取指定字符串的API函数的调用地址
; 入口参数:_hModule为动态链接库的基址
; _lpApi为API函数名的首址
; 出口参数:eax为函数在虚拟地址空间中的真实地址
;-------------------------------
_getApi proc _hModule,_lpApi
local @ret
local @dwLen
pushad
mov @ret,0
;计算API字符串的长度,含最后的零
mov edi,_lpApi
mov ecx,-1
xor al,al
cld
repnz scasb
mov ecx,edi
sub ecx,_lpApi
mov @dwLen,ecx
;从pe文件头的数据目录获取导出表地址
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,_lpApi
mov ecx,@dwLen
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 @ret,eax
_ret:
assume esi:nothing
popad
mov eax,@ret
ret
_getApi endp
start:
;取当前函数的堆栈栈顶值
mov eax,dword ptr [esp]
;获取kernel32.dll的基地址
invoke _getKernelBase,eax
mov hKernel32Base,eax
;从基地址出发搜索GetProcAddress函数的首址
invoke _getApi,hKernel32Base,addr szGetProcAddr
mov lpGetProcAddr,eax
mov _getProcAddress,eax ;为函数引用赋值 GetProcAddress
;使用GetProcAddress函数的首址
;传入两个参数调用GetProcAddress函数
;获得LoadLibraryA的首址
invoke _getProcAddress,hKernel32Base,addr szLoadLib
mov _loadLibrary,eax
;使用LoadLibrary获取user32.dll的基地址
invoke _loadLibrary,addr user32_DLL
mov hUser32Base,eax
;使用GetProcAddress函数的首址,获得函数MessageBoxA的首址
invoke _getProcAddress,hUser32Base,addr szMessageBox
mov _messageBox,eax ;调用函数MessageBoxA
invoke _messageBox,NULL,offset szText,NULL,MB_OK
ret
end start