接上回,还剩几条跳转的指令还没分析到,这些指令将在本篇中完成。

先来看看call/jmp [ebp-0x4]这条指令。这是在当前函数_except_handler4栈的局部变量,因此需要查看反汇编代码:

0:000> uf ntdll!ExecuteHandler2
ntdll!ExecuteHandler2:
7c923282 55              push    ebp
7c923283 8bec            mov     ebp,esp
7c923285 ff750c          push    dword ptr [ebp+0Ch]
7c923288 52              push    edx
7c923289 64ff3500000000  push    dword ptr fs:[0]
7c923290 64892500000000  mov     dword ptr fs:[0],esp
7c923297 ff7514          push    dword ptr [ebp+14h]
7c92329a ff7510          push    dword ptr [ebp+10h]
7c92329d ff750c          push    dword ptr [ebp+0Ch]
7c9232a0 ff7508          push    dword ptr [ebp+8]
7c9232a3 8b4d18          mov     ecx,dword ptr [ebp+18h]
7c9232a6 ffd1            call    ecx ;调用异常处理程序_except_handler

先前提到,由于栈溢出,异常处理结构已经被覆盖,因此执行call ecx时并不会去执行_except_handler而是执行call/jmp [ebp+N]指令。由于这条指令并没有操作ebp,因此ebp的值依然是ntdll!ExecuteHandler2的函数栈桢。[ebp-4]就顺理成章的变成了ntdll!ExecuteHandler2中的第一个入栈局部变量。而第一个入栈的局部变量正是[ebp+0xc]。这个值是什么?正好和另一个call/jmp [ebp+N]相同----call/jmp [ebp+0x0c]。

上面提到了[ebp+0xc],现在我们来看下call/jmp [ebp+0x0c]这个指令。这个指令分析起来比较简单ebp+0x0c传入函数的第二个参数的地址(广义Esp定理:[ebp+0]:orig ebp;[ebp+4]:retAddr;[ebp+8]:arg1;[ebp+0xc]:arg2).被调用的函数不用说就是异常处理函数_except_handler4了,那么,是谁调用并传参数给它的?

0:000> kb
ChildEBP RetAddr  Args to Child
0012f9b4 7c9232a8 0012faa0 0012fe80(<-参数2) 0012fab4 offset!_except_handler4
0012f9d8 7c92327a 0012faa0 0012fe80 0012fab4 ntdll!ExecuteHandler2+0x26
0012fa88 7c92e46a 00000000 0012fab4 0012faa0 ntdll!ExecuteHandler+0x240:000> dd 0012fe80 L2 ;第二个参数的地址值为0x12fe80
0012fe80  0012ffa8 00411078 ;12fe80包含了一个异常处理节点
0:000> ln 00411078
(00411078)   offset!ILT+115(__except_handler4)   |  (0041107d)   offset!ILT+120(__lock)
Exact matches:

从堆栈回溯结果来看Arg2是ntdll!ExecuteHandler2调用_except_handler4时传入的;而_except_handler4接口的第二个参数正是PEXCEPTION_REGISTRATION结构。这样异常处理时还是会跳转到被溢出后的栈中,进而执行shellcode。

再看第4条指令call [ebp-0x18]又指向哪?同样,当前ebp指向的是ntdll!ExecuteHandler2的栈桢,[ebp-0x18]还是ntdll!ExecuteHandler2中的局部变量。

0:000> ?? @ebp-0x18
unsigned int 0x12f9c0
0:000> dd 0x12f9c0 L1
0012f9c0  0012fe80 ;同样是当前异常处理节点在栈中的地址ntdll!ExecuteHandler2:
7c92329d ff750c          push    dword ptr [ebp+0Ch] <----这条指令执行后,正好形成局部变量[ebp-0x18]。而这条指令压入的正是前面分析过的[ebp+0xc]
7c9232a0 ff7508          push    dword ptr [ebp+8]
7c9232a3 8b4d18          mov     ecx,dword ptr [ebp+18h]
7c9232a6 ffd1            call    ecx

最后两条指令,偏移实在是太远了:[ebp+0x24]/[ebp+0x30]一种冲出地球的感觉...

[ebp+0x0c]是函数ntdll!ExecuteHandler2的第二个参数,[ebp+0x24]比[ebp+0x0c]更早入栈,这十有八九和ntdll!ExecuteHandler2的调用者有关了,查看函数调用栈:

0:000> kb
ChildEBP RetAddr  Args to Child
0012f9b4 7c9232a8 0012faa0 0012fe80 0012fab4 offset!_except_handler4
0012f9d8 7c92327a 0012faa0 0012fe80 0012fab4 ntdll!ExecuteHandler2+0x26
0012fa88 7c92e46a 00000000 0012fab4 0012faa0 ntdll!ExecuteHandler+0x24

ntdll!ExecuteHandler2的调用者是ntdll!ExecuteHandler,反汇编代码,可以看到[ebp+0x24]的由来:

0:000> uf ExecuteHandler
ntdll!ExecuteHandler:
7c923256 53              push    ebx  <----------------压栈后形成[ebp+0x24]
7c923257 56              push    esi
7c923258 57              push    edi
7c923259 33c0            xor     eax,eax
7c92325b 33db            xor     ebx,ebx
7c92325d 33f6            xor     esi,esi
7c92325f 33ff            xor     edi,edi
7c923261 ff742420        push    dword ptr [esp+20h]
7c923265 ff742420        push    dword ptr [esp+20h]
7c923269 ff742420        push    dword ptr [esp+20h]
7c92326d ff742420        push    dword ptr [esp+20h] <---------这条指令形成[ebp+0x0c],从这倒着数上去就能找到[ebp+0x24]的由来,那就是函数的第一条指令
7c923271 ff742420        push    dword ptr [esp+20h]
7c923275 e808000000      call    ntdll!ExecuteHandler2 (7c923282)

push ebx和异常处理的关系比较隐晦。张银奎的<软件调试>P723写到过ntdll!RtlpExecuteHandlerForException在调用ExecuteHandler前会将合适的值存放到ebx中然后再跳转到ExecuteHandler中执行。

ntdll!RtlpExecuteHandlerForException:
7c923247 babc32927c      mov     edx,offset ntdll!ExecuteHandler2+0x3a (7c9232bc)
7c92324c eb08            jmp     ntdll!ExecuteHandler (7c923256)0:000> ?? @ebp+0x24
unsigned int 0x12f9fc
0:000> dd 0x12f9fc L2
0012f9fc  0012fe80 7c94a9ef

ntdll!RtlpExecuteHandlerForException其实也不算什么函数,仅仅是做了个跳转,不会对栈造成影响。但是ebx中的值为什么会是当前异常处理结构呢?这又和ntdll!RtlpExecuteHandlerForException的调用者ntdll!RtlDispatchException有关。

ntdll!RtlDispatchException+0xa0:
7c94a9de ff7304          push    dword ptr [ebx+4]
7c94a9e1 8d45ec          lea     eax,[ebp-14h]
7c94a9e4 50              push    eax
7c94a9e5 ff750c          push    dword ptr [ebp+0Ch]
7c94a9e8 53              push    ebx
7c94a9e9 56              push    esi
7c94a9ea e85888fdff      call    ntdll!RtlpExecuteHandlerForException

<软件调试>P718上给出了调用RtlpExecuteHandlerForException的接口形式:
RtlpExecuteHandlerForException(pExcptRec,pRegistration,pContext,&DispatcherContext,pRegistration->Handler);
结合接口形式和反汇编代码可以知道ebx中存储的值是pRegistration---异常处理节点;当进入到ntdll!RtlpExecuteHandlerForException后,ebx的值不变,还是pRegistration,因此[ebp+0x24]处存放的也是异常处理节点。

    知道了[ebp+0x24]的来历,再来反推[ebp+0x30]的来历就显得相对简单很多:进入ntdll!RtlpExecuteHandlerForException后的第一次push ebx与进行异常处理调用call  _except_handler4之间差[0x24],在这个偏差上再反推找到3次压栈操作即为[ebp+0x30],凑巧这发生在ntdll!RtlDispatchException函数调用RtlpExecuteHandlerForException之际
ntdll!RtlDispatchException+0xa0:
7c94a9e8 53              push    ebx ;第一次压栈 [ebp+0x30]
7c94a9e9 56              push    esi ;第二次压栈 [ebp+0x2c]
7c94a9ea e85888fdff      call    ntdll!RtlpExecuteHandlerForException ;函数调用 又一次压栈 [ebp+0x28]--->进入RtlpExecuteHandlerForException,执行push ebx; 
    终于把所有指令分析结束 阿门

Oday安全 11.6利用加载模块之外的地址绕过SafeSEH一节注记---jmp [ebp+N] (下)相关推荐

  1. Oday安全 11.6利用加载模块之外的地址绕过SafeSEH一节注记---jmp [ebp+N] (上)

    看到这一章我又抓狂了:作者提及从进程空间类型为Map的映射文件中寻找如下指令地址: call/jmp dword ptr[esp+0x8] call/jmp dword ptr[esp+0x14] c ...

  2. Oday安全 11.5利用未启用SafeSEH模块绕过SafeSEH一节注记

    Oday安全一书的内容越往后越深奥,不得不做些注记备忘. 1.书P297 插图11.5.6写道__except函数地址根据EBP-4的值得出.这是目前为止,书中写的最含糊的地方,需要展开讨论一下.参考 ...

  3. 模块化加载_webpack模块化原理-异步加载模块

    在上篇文章中,我们介绍了 webpack 同步加载模块的原理.这篇文章,我们来介绍一下 webpack 异步加载模块. 异步加载模块 还是先做一些准备工作. 首先定义一个依赖模块:math.js,ma ...

  4. [driver]linux内核动态加载模块

    问题: 1. 把编译好的模块放到板子/lib/modules对应文件夹下,并且执行了depmod -a, 比如pl2303.ko, 那么下一次插入pl2303的串口线,是否可以识别,也就是自动加载pl ...

  5. [转载] 在IPython中重新加载模块 importlib

    参考链接: 在Python中重新加载模块 起因: 我们在学习 python 的时候,经常性的会用到 Ipython,进行函数的测试,但是我们会经常性的遇到调试函数,反复的修改函数,所以需要重新载入函数 ...

  6. nodejs探秘:require加载模块的原理及代码实现

    最近因为项目需要使用nodejs,因此不得不对其进行学习研究.一番深入后发现,nodejs除了好用,作为后台效率非常高之外,它自身的设计堪称精妙.我们都知道学习的一种有效方式就是看牛逼人物是怎么打造牛 ...

  7. JVM SandBox源码解析(一):启动时初始化、启动时加载模块、ModuleHttpServlet进行Http路由

    前言 上篇JVM SandBox实现原理详解文章中,主要解析了JVM SandBox的核心实现原理,并且对SandBoxClassLoader和ModuleClassLoader做了源码解析,也解释了 ...

  8. thinkphp pathinfo nginx 无法加载模块:Index

    thinkphp 报了 无法加载模块:Index 错误位置 FILE: /var/multrix/wxactivity_archive/ThinkPHP/Library/Think/Dispatche ...

  9. go加载python_人生苦短我用python(02)动态加载模块-Go语言中文社区

    文章内容为原创,欢迎转载请注明出处 作者: EflyPro->晦明禅师 文章来源:公众号"睿江云计算" 继第一期[人生苦短我用Python系列专栏]发布后,深受广大睿普迷的一 ...

最新文章

  1. linux怎样优化桌面,简单优化设置Ubuntu 18.04系统的GNOME桌面
  2. mysql dump sql文件_用mysqldump导出sql文件的问题。
  3. tkinter笔记:画布canvas
  4. halcon知识:图标对象如何存盘和读入
  5. 647. Palindromic Substrings 回文子串
  6. java 原理图_Java中比较重要的原理图(三大框架、、、、)
  7. tomcat的根路径设置
  8. 268. 缺失数字 golang
  9. muduo网络库源码阅读Step by Step
  10. python中numpy矩阵运算操作大全(非常全)!
  11. vue中怎么点击修改文字_杭州展馆设计中说明牌和说明文字怎么样才能使用最大化?...
  12. NLP人机对话与落地案例分享
  13. vlan绑定_【实操】多VLAN间通信
  14. javascript计算两个时间差
  15. python爬取豆瓣T250电影及保存excel(易上手)
  16. 浅析图片懒加载(三种实现方法与两种优化方式)
  17. 面板PSM+DID如何做匹配?
  18. Java中文繁简体转换工具
  19. Unity3D 模型大小,面数,贴图大小,骨骼数量规范(一)
  20. 文件上传下载遇到的异常

热门文章

  1. H323——H239演示功能
  2. 基于 VPX 总线的工件台运动控制系统研究与开发-以光刻运动台为例(一)
  3. 面试题:说下局部最优和全局最优的区别
  4. mybatis黑马:一级缓存和二级缓存
  5. HTML进阶--如何使用Sublime Text来创建网页 -------16岁的小前端
  6. 群晖内网穿透(实战)
  7. Spring实战读书笔记 高级装配(1)
  8. 一看就懂!renren-fast 快速开发框架使用以及开发文档
  9. (转)Servlet3.0下@WebFilter注解配置Filter
  10. 超详细的张飞硬件第五部读书笔记01