zoukankan      html  css  js  c++  java
  • 关于seh的那些事二(易语言的try..except模块化封装)

        之前我们已经说过了seh的一些事情,包括如何用seh构建易语言的try..except,这个是之前的代码

    .版本 2

    .子程序 子程序_模拟try

    ' _asm{
    ' pushad
    ' call my

    ' my:
    ' pop eax ;自定位
    ' lea ecx, dword [eax-6+safe]
    ' push ecx
    ' lea ecx,dword [eax-6+handle]
    ' push ecx
    ' push dword  [fs:0]
    ' mov  dword  [fs:0], esp

    ' xor eax,eax   ;这里随便写被保护的代码
    ' mov [eax],eax

    ' jmp safe

    ' handle:
    ' pushad

    ' mov edi,[ebp+10h]
    ' mov eax,[ebp+0ch]

    ' push dword [eax+8h]
    ' pop dword [edi+0B8h]

    ' popad
    ' mov eax,0
    ' ret 10h

    ' safe:
    ' mov esp, dword  [fs:0]
    ' pop dword  [fs:0]
    ' add esp,08h
    ' popad
    ' }

          这个代码是易语言内联汇编构造的try..except模型,但是我们看到了,如果要用这个模型,写要被保护的代码,必须用内联汇编代码.这样很不方便,我们学易语言,就是为了简单.在try..except模型保护下的代码还必须用汇编,那么显然,这个模型是还不够完善的,今天我们就来完善这个模型,让这个try..except模型能保护易语言的原生态代码.

          下面我还是给出易语言代码,然后再讲解一下.

    .版本 2
    .支持库 spec

    .子程序 子程序_模拟try
    .参数 参数一
    .参数 参数二
    .参数 参数三
    .局部变量 局_变量一, 整数型

    参数一 = 1
    参数二 = 2
    参数三 = 3

    ' _asm{
    ' pushad
    ' call my

    ' my:
    ' pop eax ;自定位
    ' lea ecx, dword [eax-6+safe]
    ' push ecx
    ' lea ecx,dword [eax-6+handle]
    ' push ecx
    ' push dword  [fs:0]
    ' mov  dword  [fs:0], esp


    ' jmp bottom

    ' handle:
    ' pushad

    ' mov edi,[ebp+10h]
    ' mov eax,[ebp+0ch]

    ' push dword [eax+8h]
    ' pop dword [edi+0B8h]

    ' popad
    ' mov eax,0
    ' ret 10h

    ' safe:
    ' mov esp, dword  [fs:0]
    ' pop dword  [fs:0]
    ' add esp,08h
    ' popad
    ' mov esp,ebp
    ' pop ebp
    ' ret 0ch

    ' bottom:
    ' }

    调试输出 (“参数一是” + 到文本 (参数一))
    调试输出 (“参数二是” + 到文本 (参数二))
    调试输出 (“参数三是” + 到文本 (参数三))
    局_变量一 = 局_变量一 + 4
    调试输出 (“局_变量一是” + 到文本 (局_变量一))
    写到内存 (4, 0, 1)

    大部分跟昨天一样,只有少量代码做了一些改变,我们重点说下改变的位置.

    昨天在' jmp bottom的位置,我们是内联汇编写入的需要保护的代码,昨天在这个位置我们内联汇编构造了一个异常,今天,我们就不直接内联汇编写异常代码了,直接跳到内联汇编的尾部,我们在内联汇编尾部写易语言原生态代码,这样jmp bottom 就跳到了原生态代码处,我们就保护了原生态代码.

    另一个位置在safe标号位置,我们在内联代码处增加了三行代码

    ' mov esp,ebp
    ' pop ebp
    ' ret 0ch

    这里模拟的就是易语言的函数尾

    为什么要模拟易语言的函数尾呢,这里我们假设,如果易语言原生态代码出现异常,比如今天我们就用写到内存(4,0,1)构造了一个异常,那么抛出异常来到了safe安全位置,safe安全位置首先卸载seh,然后平衡堆栈,如果不模拟易语言函数尾,那么他下面继续走,会执行什么?当然是会执行下面的代码.也就是继续执行原生态代码这一段

    调试输出 (“参数一是” + 到文本 (参数一))
    调试输出 (“参数二是” + 到文本 (参数二))
    调试输出 (“参数三是” + 到文本 (参数三))
    局_变量一 = 局_变量一 + 4
    调试输出 (“局_变量一是” + 到文本 (局_变量一))
    写到内存 (4, 0, 1)

    那么很显然,写到内存(4,0,1)又是这个异常,这次不好运了,我们连seh都卸了,就会弹出错误,所以我们要执行到safe安全位置后,平衡堆栈,然后模拟易语言函数的尾部,返回,不再执行下面代码.这里要重点说明下,易语言函数的调用约定是stdcall调用方式.也就是函数尾部自己平衡堆栈,我这里写了个简单的测试程序

    .版本 2

    .子程序 A

    B (1)
    ' _asm{
    ' mov eax,eax
    ' mov eax,eax
    ' mov eax,eax
    ' mov eax,eax
    ' mov eax,eax
    ' }


    .子程序 B, 整数型, , 参看B的调用约定
    .参数 C

    返回 (C)

    反汇编工具查看了下

    00AD04D6 - 55                         - push ebp
    00AD04D7 - 8b ec                      - mov ebp,esp
    00AD04D9 - 68 01 00 00 00             - push 00000001 参数=1
    00AD04DE - e8 0e 00 00 00             - call 00ad04f1     B程序CALL
    00AD04E3 - 89 c0                      - mov eax,eax
    00AD04E5 - 89 c0                      - mov eax,eax
    00AD04E7 - 89 c0                      - mov eax,eax
    00AD04E9 - 89 c0                      - mov eax,eax
    00AD04EB - 89 c0                      - mov eax,eax
    00AD04ED - 8b e5                      - mov esp,ebp
    00AD04EF - 5d                         - pop ebp
    00AD04F0 - c3                         - ret
    00AD04F1 - 55                         - push ebp
    00AD04F2 - 8b ec                      - mov ebp,esp
    00AD04F4 - 8b 45 08                   - mov eax,[ebp+08]
    00AD04F7 - e9 00 00 00 00             - jmp 00ad04fc
    00AD04FC - 8b e5                      - mov esp,ebp
    00AD04FE - 5d                         - pop ebp
    00AD04FF - c2 04 00                   - ret 0004     自己平衡了堆栈

    这里证明了 确实易语言函数的调用约定确实是stdcall方式,所以我们模拟易语言函数尾就要自己平衡堆栈,我们模拟程序是三个参数,所以自己平衡堆栈是ret 0ch,如果大家用这个try..except模型保护代码,一定要注意被保护函数的参数个数.

    下面有同学要问了,假如我的被保护的原生态易代码,没有异常,也就是顺利执行,那么他的流程大概是这样的:

    ' _asm{
    ' pushad
    ' call my

    ' my:
    ' pop eax ;自定位
    ' lea ecx, dword [eax-6+safe]
    ' push ecx
    ' lea ecx,dword [eax-6+handle]
    ' push ecx
    ' push dword  [fs:0]
    ' mov  dword  [fs:0], esp


    ' jmp bottom

    bottom:

    调试输出 (“参数一是” + 到文本 (参数一))
    调试输出 (“参数二是” + 到文本 (参数二))
    调试输出 (“参数三是” + 到文本 (参数三))
    局_变量一 = 局_变量一 + 4
    调试输出 (“局_变量一是” + 到文本 (局_变量一))

    你昨天都说过,注册seh,用了三个push,如果发生异常,被异常处理函数处理,来到安全位置,用pop和add esp,08平衡了堆栈,但是现在你的原生态易语言代码是安全的,那你怎么平衡堆栈?

    我的回答是,用易语言自己的函数尾平衡堆栈.下面我来详细说明下,为什么可以用易语言自己的函数尾平衡堆栈:

    易语言函数头是

    push ebp

    mov ebp,esp

    这个是易语言的函数头,通过函数头进入函数后,保存了调用函数方的ebp,然后esp=ebp,也就是经过函数头以后,[ebp]等于上一个ebp,[ebp+4]等于返回地址[ebp+08h]等于参数一,如果还有局部变量的话,比如,如果有个一个局部变量,就是sub,esp 4.有二个局部变量,就是sub,esp 8,经过易语言函数头初始化以后,才进入到自己写代码中,所以在易语言函数里,是用ebp寻址,寻参的话是[ebp+8]开始,寻局部变量是[ebp-4]开始,所以用ebp不能被破坏,esp在经过函数头以后,做的别的事情是不会破坏堆栈的,只要在返回的时候,把esp地址找回来就行了,这里我要说的是,一定要经过易语言函数头后,esp才能做点别的事情.

    那么我们看下易语言函数尾:一般是这样二句

    mov esp,ebp

    pop ebp

    这里mov esp,ebp把ebp=esp,对应的是之前函数头的mov ebp,esp,终于,拿了我的给我还回来,吃了我的给我吐出来了.

    然后现在[esp]=调用函数方的ebp值,[esp+4]=等于返回地址

    下一个pop ebp

    把调用函数方的ebp值放入ebp,然后现在[esp]等于返回地址了.

         这样就完美的走完了整个调用过程,长路漫漫,他的使命终于完成了,不管他是完美的走过,还是出现了那么小丁点的错误,但总归,找到了来时的路.我们表示祝贺已及最真挚的慰问.

       

    源代码:http://files.cnblogs.com/qq32175822/2.rar

  • 相关阅读:
    Java 开发环境配置
    kettle脚本定时任务不执行
    python 列表之队列
    tensorflow训练过程中内存溢出
    关于 numpy.array和list之间的转换
    vscode 小笔记
    【python2/3坑】从gensim的Word2Vec.load()的中文vector模型输出时显示unicode码
    WingIDE用法笔记
    numpy.ndarray类型的数组元素输出时,保留小数点后4位
    tensorboard 用法
  • 原文地址:https://www.cnblogs.com/qq32175822/p/3499478.html
Copyright © 2011-2022 走看看