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被占用时,会根据重定位表修改所有的重定位信息
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
相关文章推荐
- 从内存资源中加载DLL 模拟PE加载器
- 从内存资源中加载DLL 模拟PE加载器
- 动态加载dll,并创建类和实例
- C#动态加载DLL(反射学习(二))
- 加载DLL文件并调用DLL函数实例
- 用16进制编辑器写Dll文件---学习PE必看的资料之一
- 实例学习如何在ASP中调用DLL
- PE文件和COFF文件格式分析——导出表的应用——通过导出表隐性加载DLL
- Pe研究之:从内存中加载Pe文件(代码重定位,进程隐藏,代码注入)
- SharePoint学习笔记002:未能加载文件或程序集'Microsoft.SharePoint.Sandbox.dll
- 【翻译】WF从入门到精通(第六章):加载和卸载实例
- WF从入门到精通(第六章):加载和卸载实例
- C++Builder学习笔记5.1(连接数据库,读写配置文件,加载DLL)
- WF从入门到精通(第六章):加载和卸载实例 (转)
- 【翻译作品】JavaScript DOM学习第六章:表单实例
- Pe研究之:从内存中加载Pe文件(代码重定位,进程隐藏,代码注入)
- [导入]【翻译】WF从入门到精通(第六章):加载和卸载实例
- SilverLight学习笔记--Silverligh之动态加载程序集(.DLL)
- 一种保护应用程序的方法 模拟Windows PE加载器,从内存资源中加载DLL
- 模拟Windows PE加载器,从内存资源中加载DLL