第六章 栈与重定位表
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,stdcalloption casemap:noneinclude    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,ebppushadmov [ebp+4],offset someAddresspopadret
_overWrite endpstart:invoke _overWrite,addr szShellCodeinvoke MessageBox,NULL,offset szTextHelloWord,NULL,MB_OK
someAddress:invoke MessageBox,NULL,offset szTextOverData,NULL,MB_OKinvoke ExitProcess,NULL
end start
//no_exist_import_realloc_data.asm
;------------------------
; 无导入表、无数据段、无重定位信息的HelloWorld
; 戚利
; 2010.6.27
;------------------------.386.model flat,stdcalloption casemap:noneinclude    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;代码段.codeszText         db  'HelloWorldPE',0
szGetProcAddr  db  'GetProcAddress',0
szLoadLib      db  'LoadLibraryA',0
szMessageBox   db  'MessageBoxA',0user32_DLL     db  'user32.dll',0,0;定义函数
_getProcAddress _ApiGetProcAddress  ?
_loadLibrary    _ApiLoadLib         ?
_messageBox     _ApiMessageBoxA     ?hKernel32Base   dd  ?
hUser32Base     dd  ?
lpGetProcAddr   dd  ?
lpLoadLib       dd  ?;------------------------------------
; 根据kernel32.dll中的一个地址获取它的基地址
;------------------------------------
_getKernelBase  proc _dwKernelRetAddresslocal @dwRetpushadmov @dwRet,0mov edi,_dwKernelRetAddressand edi,0ffff0000h  ;查找指令所在页的边界,以1000h对齐.repeat;找到kernel32.dll的dos头.if word ptr [edi]==IMAGE_DOS_SIGNATURE  mov esi,ediadd esi,[esi+003ch];找到kernel32.dll的PE头标识.if word ptr [esi]==IMAGE_NT_SIGNATURE mov @dwRet,edi.break.endif.endifsub edi,010000h.break .if edi<070000000h.until FALSEpopadmov eax,@dwRetret
_getKernelBase  endp   ;-------------------------------
; 获取指定字符串的API函数的调用地址
; 入口参数:_hModule为动态链接库的基址
;           _lpApi为API函数名的首址
; 出口参数:eax为函数在虚拟地址空间中的真实地址
;-------------------------------
_getApi proc _hModule,_lpApilocal @retlocal @dwLenpushadmov @ret,0;计算API字符串的长度,含最后的零mov edi,_lpApimov ecx,-1xor al,alcldrepnz scasbmov ecx,edisub ecx,_lpApimov @dwLen,ecx;从pe文件头的数据目录获取导出表地址mov esi,_hModuleadd esi,[esi+3ch]assume esi:ptr IMAGE_NT_HEADERSmov esi,[esi].OptionalHeader.DataDirectory.VirtualAddressadd esi,_hModuleassume esi:ptr IMAGE_EXPORT_DIRECTORY;查找符合名称的导出函数名mov ebx,[esi].AddressOfNamesadd ebx,_hModulexor edx,edx.repeatpush esimov edi,[ebx]add edi,_hModulemov esi,_lpApimov ecx,@dwLenrepz cmpsb.if ZERO?pop esijmp @F.endifpop esiadd ebx,4inc edx.until edx>=[esi].NumberOfNamesjmp _ret
@@:;通过API名称索引获取序号索引再获取地址索引sub ebx,[esi].AddressOfNamessub ebx,_hModuleshr ebx,1add ebx,[esi].AddressOfNameOrdinalsadd ebx,_hModulemovzx eax,word ptr [ebx]shl eax,2add eax,[esi].AddressOfFunctionsadd eax,_hModule;从地址表得到导出函数的地址mov eax,[eax]add eax,_hModulemov @ret,eax_ret:assume esi:nothingpopadmov eax,@retret
_getApi endpstart:;取当前函数的堆栈栈顶值mov eax,dword ptr [esp]push eaxcall @F   ; 免去重定位
@@:pop ebxsub ebx,offset @Bpop eax;获取kernel32.dll的基地址invoke _getKernelBase,eaxmov [ebx+offset hKernel32Base],eax;从基地址出发搜索GetProcAddress函数的首址mov eax,offset szGetProcAddradd eax,ebxmov edi,offset hKernel32Basemov ecx,[ebx+edi]invoke _getApi,ecx,eaxmov [ebx+offset lpGetProcAddr],eax;为函数引用赋值 GetProcAddressmov [ebx+offset _getProcAddress],eax   ;使用GetProcAddress函数的首址;传入两个参数调用GetProcAddress函数,获得LoadLibraryA的首址mov eax,offset szLoadLibadd eax,ebxmov edi,offset hKernel32Basemov ecx,[ebx+edi]mov edx,offset _getProcAddressadd edx,ebx;模仿调用 invoke GetProcAddress,hKernel32Base,addr szLoadLibpush eaxpush ecxcall dword ptr [edx]   mov [ebx+offset _loadLibrary],eax;使用LoadLibrary获取user32.dll的基地址mov eax,offset user32_DLLadd eax,ebxmov edi,offset _loadLibrarymov edx,[ebx+edi]push eaxcall edx   ; invoke LoadLibraryA,addr _loadLibrarymov [ebx+offset hUser32Base],eax;使用GetProcAddress函数的首址,获得函数MessageBoxA的首址mov eax,offset szMessageBoxadd eax,ebxmov edi,offset hUser32Basemov ecx,[ebx+edi]mov edx,offset _getProcAddressadd edx,ebx;模仿调用 invoke GetProcAddress,hUser32Base,addr szMessageBoxpush eaxpush ecxcall dword ptr [edx]   mov [ebx+offset _messageBox],eax;调用函数MessageBoxAmov eax,offset szTextadd eax,ebxmov edx,offset _messageBoxadd edx,ebx;模仿调用 invoke MessageBoxA,NULL,addr szText,NULL,MB_OK    push MB_OKpush NULLpush eaxpush NULLcall dword ptr [edx]   retend start
//遍历重定位表
;--------------------
; 获取PE文件的重定位信息
;--------------------
_getRelocInfo proc  _lpFile,_lpPeHead,_dwSizelocal @szBuffer[1024]:bytelocal @szSectionName[16]:bytepushadmov esi,_lpPeHeadassume esi:ptr IMAGE_NT_HEADERSmov eax,[esi].OptionalHeader.DataDirectory[8*5].VirtualAddress.if !eaxinvoke _appendInfo,addr szMsgReloc4jmp _ret.endifpush eaxinvoke _RVAToOffset,_lpFile,eaxadd eax,_lpFilemov esi,eaxpop eaxinvoke _getRVASectionName,_lpFile,eaxinvoke wsprintf,addr @szBuffer,addr szMsgReloc1,eaxinvoke _appendInfo,addr @szBufferassume esi:ptr IMAGE_BASE_RELOCATION;循环处理每个重定位块.while [esi].VirtualAddresscld         ;//set DF=0 向高地址步增lodsd   ;eax=[esi].VirtualAddressmov ebx,eaxlodsd   ;eax=[esi].SizeofBlocksub eax,sizeof IMAGE_BASE_RELOCATION  ;块总长度-两个ddshr eax,1                             ;然后除以2,得到重定位项数量;除以2是因为重定位项是wordpush eaxinvoke wsprintf,addr @szBuffer,addr szMsgReloc2,ebx,eaxinvoke _appendInfo,addr @szBufferpop ecx                               ;重定位项数量xor edi,edi.repeatpush ecxlodswmov cx,axand cx,0f000h    ;得到高四位.if cx==03000h   ;重定位地址指向的双字的32位都需要休正and ax,0fffhmovzx eax,axadd eax,ebx    ;得到修正以前的偏移,该偏移加上装入时的基址就是绝对地址.else            ;该重定位项无意义,仅用来作为对齐mov eax,-1.endifinvoke wsprintf,addr @szBuffer,addr szMsgReloc3,eaxinc edi.if edi==8       ;每显示8个项目换行invoke lstrcat,addr @szBuffer,addr szCrLfxor edi,edi.endifinvoke _appendInfo,addr @szBufferpop ecx.untilcxz.if ediinvoke _appendInfo,addr szCrLf.endif.endw
_ret:assume esi:nothingpopadret
_getRelocInfo endp

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

  1. 【OS学习笔记】十 实模式:实现一个程序加载器-程序加载器如何将用户程序加载到内存并执行

    上一篇文章学习了以下内容: 用一种不同的分段方法,从另一个不同的的角度理解处理器的分段内存访问机制 使用循环和条件转移指令来优化主引导扇区代码 点击链接查看上一篇文章:点击链接查看 对于主引导扇区部分 ...

  2. Unix原理与应用学习笔记----第六章 文件的基本属性2

    Unix原理与应用学习笔记----第六章 文件的基本属性2 改变文件权限命令:chmod 提示:文件或目录创建后,就被赋予一组默认的权限.所有的用户都有读,只有文件的所有者才有写. 相对权限设置 Ch ...

  3. 《Go语言圣经》学习笔记 第六章 方法

    <Go语言圣经>学习笔记 第六章 方法 目录 方法声明 基于指针对象的方法 通过嵌入结构体来扩展类型 方法值和方法表达式 示例:Bit数组 封装 注:学习<Go语言圣经>笔记, ...

  4. 中根遍历二叉查找树所得序列一定是有序序列_学习数据结构--第六章:查找(查找)

    第六章:查找 1.查找的基本概念 查找:在数据集合中寻找满足某种条件的数据元素的过程. 查找的结果 查找成功和查找失败 查找表:用于查找的数据集合,由同一种数据类型(或记录)的组成,可以是一个数组或链 ...

  5. 《疯狂Java讲义》学习笔记 第六章 面向对象(下)

    <疯狂Java讲义>学习笔记 第六章 面向对象(下) 6.1包装类 基本数据类型 包装类 byte Byte short Short int Integer long Long char ...

  6. 《SysML精粹》学习记录--第六章

    <SysML精粹>学习记录 第六章:活动图 活动图简介 活动图外框 活动图的关键元素   动作   对象节点   边   动作详述   控制节点 活动分区 小结 第六章:活动图 活动图简介 ...

  7. PMBOK(第六版) 学习笔记 ——《第一章 引论》

    系列文章目录 PMBOK(第六版) 学习笔记 --<第一章 引论> PMBOK(第六版) 学习笔记 --<第二章 项目运行环境> PMBOK(第六版) 学习笔记 --<第 ...

  8. 学习数据结构--第六章:查找(查找)

    第六章:查找 1.查找的基本概念 查找:在数据集合中寻找满足某种条件的数据元素的过程. 查找的结果 查找成功和查找失败 查找表:用于查找的数据集合,由同一种数据类型(或记录)的组成,可以是一个数组或链 ...

  9. Java基础学习——第十六章 Java8新特性

    Java基础学习--第十六章 Java8 新特性 Java8(JDK8.0)较 JDK7.0 有很多变化或者说是优化,比如 interface 里可以有静态方法和默认方法,并且可以有方法体,这一点就颠 ...

最新文章

  1. 我在不炎熱也不抑鬱的秋天,依然不抽煙
  2. java原生类型没有封装_Java基本数据类型与封装类型详解(int和Integer区别)
  3. Lispbox的简单配置
  4. python画折线图代码-Python折线图的分析过程和画图的方法
  5. 关于用jQuery实现的checkbox全选和反选功能
  6. Netty之线程模型
  7. 关于CCSpriteSheet报错问题
  8. Greenplum 行存、列存,堆表、AO表的原理和选择
  9. PAT甲题题解-1077. Kuchiguse (20)-找相同后缀
  10. python安装目录结构_1.5 python安装目录介绍《Python基础开发入门到精通》
  11. linux 离线安装node.js,Linux上离线安装node.js、Newman、newman-reporter-html
  12. 反编译获取任何微信小程序源码(完)
  13. 计算机课程设计心得,课程设计心得体会 -心得
  14. android adb点击坐标,Android 利用adb命令 使App自动点击屏幕指定位置
  15. (八)理解迭代思维(80)
  16. mysql的week函数与JAVA计算周的差别问题
  17. 计算机毕业设计SSM大众点评管理系统【附源码数据库】
  18. python错误解决TypeError: () must be callable
  19. 关于质量和效能的思考
  20. Word中插入Visio留空太大怎么办

热门文章

  1. Interview:算法岗位面试—上海某公司算法岗位(偏图像算法,互联网科技行业)技术面试考点之区块链的TPS等问题
  2. AI:《A Simple Tool to Start Making Decisions with the Help of AI—借助人工智能开始决策的简单工具》翻译与解读
  3. Python之tkinter:动态演示调用python库的tkinter带你进入GUI世界(Canvas)
  4. 4.2 Tensorflow笔记:池化函数
  5. 洛谷P2698 [USACO12MAR]花盆Flowerpot
  6. CentOS7修改默认运行级别
  7. seaJS简介和完整实例
  8. Python基础(14)_python模块之configparser模块、suprocess
  9. Interview with BOA
  10. Android 下拉刷新