您的位置:首页 > 其它

PE学习(六)第六章 栈与重定位表 实例栈溢出、模拟加载器加载DLL、遍历重定位表

2015-03-24 21:21 429 查看
第六章 栈与重定位表

16bit OS 存在长调用 lcall push cs,ip 相应的iret pop ip, cs 而call/ret only focus ip register

32bit OS 因为32寄存器可以访问4G空间,可以长短调用被忽略,只关注eip

实模式:段地址+程序偏移地址 SS::SP= SS<<16+SP

保护模式:段选择子+程序偏移地址 原来的段寄存器称为段选择子,指向是 GDT/LDT(全局描述符表/局部描述符表)

call 0xXXXXXXXX ;//push 后面的返回地址 再 jump 0xXXXXXXXX

push ebp

mov ebp,esp ;//这两句是masm32中伪关键字proc,和C中的函数一样,翻译为汇编时自动会加上这两行还有leave

...

leave 等价 mov esp,ebp pop ebp

上面这3行是 编译器为proc做的

ret ;//pop eip

//当只有一个要访问.text段中的数据时,需要设置段属性

C:\testmasm\example\666>ml /coff HelloWorld1.asm /link -subsystem:windows -section:.text,ERW

window加载器发现IMAGE_OPTIONAL_HEADER32.ImageBase被占用时,会根据重定位表修改所有的重定位信息







//栈溢出导致部分代码未执行
.386
.model flat,stdcall
option casemap:none

include    windows.inc
include    user32.inc
includelib user32.lib
include    kernel32.inc
includelib kernel32.lib

;数据段
.data
szTextHelloWord     db  'HelloWorld',0
szTextOverData		 db  'Test overwrite ret address to simulate stack overflow!',0
szShellCode				db	'oneArg',0

;代码段
.code
_overWrite proc _lpSrc
;_lpSrc,retAddress,ebp
pushad
mov [ebp+4],offset someAddress
popad
ret
_overWrite endp

start:
invoke _overWrite,addr szShellCode
invoke MessageBox,NULL,offset szTextHelloWord,NULL,MB_OK
someAddress:
invoke MessageBox,NULL,offset szTextOverData,NULL,MB_OK
invoke ExitProcess,NULL
end start


//no_exist_import_realloc_data.asm
;------------------------
; 无导入表、无数据段、无重定位信息的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

;代码段
.code

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  ?

;------------------------------------
; 根据kernel32.dll中的一个地址获取它的基地址
;------------------------------------
_getKernelBase  proc _dwKernelRetAddress
local @dwRet

pushad

mov @dwRet,0

mov edi,_dwKernelRetAddress
and edi,0ffff0000h  ;查找指令所在页的边界,以1000h对齐

.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]
push eax
call @F   ; 免去重定位
@@:
pop ebx
sub ebx,offset @B

pop eax
;获取kernel32.dll的基地址
invoke _getKernelBase,eax
mov [ebx+offset hKernel32Base],eax

;从基地址出发搜索GetProcAddress函数的首址
mov eax,offset szGetProcAddr
add eax,ebx

mov edi,offset hKernel32Base
mov ecx,[ebx+edi]

invoke _getApi,ecx,eax
mov [ebx+offset lpGetProcAddr],eax

;为函数引用赋值 GetProcAddress
mov [ebx+offset _getProcAddress],eax

;使用GetProcAddress函数的首址
;传入两个参数调用GetProcAddress函数,获得LoadLibraryA的首址
mov eax,offset szLoadLib
add eax,ebx

mov edi,offset hKernel32Base
mov ecx,[ebx+edi]

mov edx,offset _getProcAddress
add edx,ebx

;模仿调用 invoke GetProcAddress,hKernel32Base,addr szLoadLib
push eax
push ecx
call dword ptr [edx]

mov [ebx+offset _loadLibrary],eax

;使用LoadLibrary获取user32.dll的基地址

mov eax,offset user32_DLL
add eax,ebx

mov edi,offset _loadLibrary
mov edx,[ebx+edi]

push eax
call edx   ; invoke LoadLibraryA,addr _loadLibrary

mov [ebx+offset hUser32Base],eax

;使用GetProcAddress函数的首址,获得函数MessageBoxA的首址
mov eax,offset szMessageBox
add eax,ebx

mov edi,offset hUser32Base
mov ecx,[ebx+edi]

mov edx,offset _getProcAddress
add edx,ebx

;模仿调用 invoke GetProcAddress,hUser32Base,addr szMessageBox
push eax
push ecx
call dword ptr [edx]
mov [ebx+offset _messageBox],eax

;调用函数MessageBoxA
mov eax,offset szText
add eax,ebx

mov edx,offset _messageBox
add edx,ebx

;模仿调用 invoke MessageBoxA,NULL,addr szText,NULL,MB_OK
push MB_OK
push NULL
push eax
push NULL
call dword ptr [edx]

ret
end start


//遍历重定位表
;--------------------
; 获取PE文件的重定位信息
;--------------------
_getRelocInfo proc  _lpFile,_lpPeHead,_dwSize
local @szBuffer[1024]:byte
local @szSectionName[16]:byte

pushad
mov esi,_lpPeHead
assume esi:ptr IMAGE_NT_HEADERS
mov eax,[esi].OptionalHeader.DataDirectory[8*5].VirtualAddress
.if !eax
invoke _appendInfo,addr szMsgReloc4
jmp _ret
.endif
push eax
invoke _RVAToOffset,_lpFile,eax
add eax,_lpFile
mov esi,eax
pop eax
invoke _getRVASectionName,_lpFile,eax
invoke wsprintf,addr @szBuffer,addr szMsgReloc1,eax
invoke _appendInfo,addr @szBuffer
assume esi:ptr IMAGE_BASE_RELOCATION
;循环处理每个重定位块
.while [esi].VirtualAddress
cld			;//set DF=0 向高地址步增
lodsd   ;eax=[esi].VirtualAddress
mov ebx,eax
lodsd   ;eax=[esi].SizeofBlock
sub eax,sizeof IMAGE_BASE_RELOCATION  ;块总长度-两个dd
shr eax,1                             ;然后除以2,得到重定位项数量
;除以2是因为重定位项是word
push eax
invoke wsprintf,addr @szBuffer,addr szMsgReloc2,ebx,eax
invoke _appendInfo,addr @szBuffer
pop ecx                               ;重定位项数量
xor edi,edi
.repeat
push ecx
lodsw
mov cx,ax
and cx,0f000h    ;得到高四位
.if cx==03000h   ;重定位地址指向的双字的32位都需要休正
and ax,0fffh
movzx eax,ax
add eax,ebx    ;得到修正以前的偏移,该偏移加上装入时的基址就是绝对地址
.else            ;该重定位项无意义,仅用来作为对齐
mov eax,-1
.endif
invoke wsprintf,addr @szBuffer,addr szMsgReloc3,eax
inc edi
.if edi==8       ;每显示8个项目换行
invoke lstrcat,addr @szBuffer,addr szCrLf
xor edi,edi
.endif
invoke _appendInfo,addr @szBuffer
pop ecx
.untilcxz
.if edi
invoke _appendInfo,addr szCrLf
.endif
.endw
_ret:
assume esi:nothing
popad
ret
_getRelocInfo endp
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: