如何既执行if模块,由执行else模块

从上下了一个程序unixc.rar,在readme.txt中,作者说:
该程序模拟UNIX中save与resume函数,并介绍在VC中如何使用汇编进行机器级的操作.
主函数很简单首先引入两个外部函数,
extern"C"表示按传统C命名习惯.函数save将程序指针保存在(*s)中并返回0,为什么有
 if(save(&sp)){...}
if后的语句看起来永远都不会被执行,但是运行结果表明它被执行了.这个问题同UNIX中处理机调度函数(switc
h)的那个if语句(第一句)一样.
程序执行完save(&sp)后得到因为条件为假而执行else语句,却在判断之前将程序指针保存在sp中了.
else语句中的resume(&sp),该函数很狡猾将堆栈中的返回地址改变了,改到了sp所指出,即将程序指针改到了执
行条件判断前.resume返回1,条件满足,执行if语句.
save函数堆栈:
eip ebp+8
s ebp+4
ebp ebp+0
resume函数堆栈与save的相同.

新建一个win32的工程,将unixc.cpp和unix.obj加入过程即可.
unix.obj是用masm6.11生成的:ml /c /coff unix.asm,生成coff格式的obj而不是omf格式.

本文主要通过反汇编来说明,如何通过保存返回地址使得即执行程序的if模块还执行
程序的else模块。

--- E:/程序_规范/UnixC/UnixC.cpp  ----------------------------------------------

1:

2:    #include<stdio.h>

3:    extern "C" int save(long * s);

4:    extern "C" int resume(long * s);

5:    void main()

6:    {

00401030   push        ebp 

 

保存栈底指针

ESP = 0012FF80

EBP = 0012FFC0

0012FF80  C0 FF 12  ...  堆栈内为ebp的值

 

00401031   mov         ebp,esp  //把当前的栈顶当作栈底

 

ESP = 0012FF80

EBP = 0012FF80

 

00401033   sub         esp,44h  //预留44h的栈空间

 

ESP = 0012FF3C   栈顶指向

EBP = 0012FF80   此时的栈底

 

00401036   push        ebx //把要用到的寄存器值进栈

 

ESP = 0012FF38

EBP = 0012FF80

012FF39  F0 FD 7F  .  //ebx

0012FF3C  02 00 00  ...

 

00401037   push        esi

00401038   push        edi

ESP = 0012FF30

EBP = 0012FF80

0012FF30  00 00 00  ... edi

0012FF33  00 00 00  ...  esi

0012FF36  00 00 00  ... 

0012FF39  F0 FD 7F  .

0012FF3C  02 00 00  ...

 

00401039   lea         edi,[ebp-44h] 

 

EDI = 0012FF3C

 

0040103C   mov         ecx,11h  //计数器 11h*4=44h

00401041   mov         eax,0CCCCCCCCh

00401046   rep stos    dword ptr [edi] //将这44个字节全部初始化为cc  int 3

7:        long    spp;

0012FF7C  CC CC CC  .

&sp = 0x0012ff7c

 

8:        printf("Both the code in the if and the code in the else will be exe!!!/n");

00401048   push        offset string "Both the code in the if and the "... (00422050)

0040104D   call        printf (004010c0)

00401052   add         esp,4

9:        if(save(&spp))

00401055   lea         eax,[ebp-4]

 

//spp的地址付给eax

eax = 0x0012ff7c

 

00401058   push        eax

 

ESP = 0012FF2C

EBP = 0012FF80

012FF2C  7C FF 12  |..  //eax入栈

0012FF2F  00 00 00  ...

0012FF32  00 00 00  ...

0012FF35  00 00 00  ...

0012FF38  00 F0 FD  .

0012FF3B  7F CC CC  .

0012FF3E  CC CC CC  .

 

00401059   call        @ILT+5(_main+176080) (0040100a)

ESP = 0012FF28

EBP = 0012FF80

012FF26  12 00 5E  ..^   子程序返回时,下一条要执行的语句的地址

0012FF29  10 40 00  .@.

0012FF2C  7C FF 12  |..

0012FF2F  00 00 00  ...

0012FF32  00 00 00  ...

 

0040105E   add         esp,4 将调用_save时的参数弹出栈

ESP = 0012FF30

EBP = 0012FF80

 

00401061   test        eax,eax

//返回至为零,因为我们置eax为零

00401063   je          main+44h (00401074)

10:       {

11:           printf("return form the if/n");

00401065   push        offset string "return form the if/n" (00422038)

0040106A   call        printf (004010c0)

0040106F   add         esp,4

12:           return;

00401072   jmp         main+5Dh (0040108d)

13:       }

14:       else

15:       {

16:           printf("return form the else/n");

00401074   push        offset string "return form the else/n" (0042201c)

00401079   call        printf (004010c0)

0040107E   add         esp,4

17:           resume(&spp);

00401081   lea         ecx,[ebp-4]

spp的地址付给ecx,作为函数调用的参数

ECX = 0012FF7C

 

00401084   push        ecx

入栈

ESP = 0012FF2C

EBP = 0012FF80

0012FF2C  7C FF 12  |.. spp的地址

0012FF2F  00 00 00  ...

 

00401085   call        @ILT+0(_main+176098) (00401005)

0040108A   add         esp,4

18:       }

19:       return;

20:   }

0040108D   pop         edi

0040108E   pop         esi

0040108F   pop         ebx

00401090   add         esp,44h

00401093   cmp         ebp,esp

00401095   call        __chkesp (00401140)

0040109A   mov         esp,ebp

0040109C   pop         ebp

0040109D   ret

 

 

子函数_save

_save:

ESP = 0012FF28

EBP = 0012FF80

012FF26  12 00 5E  ..^  _save返回时,下一条要执行的语句的地址

0012FF29  10 40 00  .@.

0012FF2C  7C FF 12  |..

0012FF2F  00 00 00  ...

0012FF32  00 00 00  ...

0042B000   push        ebp

ESP = 0012FF24

 EBP = 0012FF80

0012FF24  80 FF 12  €.. ebp

0012FF27  00 5E 10  .^. _save返回时,下一条要执行的语句的地址

0012FF2A  40 00 7C  @.|

0012FF2D  FF 12 00  ...

0012FF30  00 00 00  ...

 

0042B001   mov         ebp,esp

ESP = 0012FF24

EBP = 0012FF24

 

0042B003   mov         esi,dword ptr [ebp+8]

ESI = 0012FF7C     spp的地址给esi

 

0042B006   mov         eax,dword ptr [ebp+4]

EAX = 0040105E    _save返回时,下一条要执行的语句的地址eax

 

0042B009   mov         dword ptr [esi],eax

 

spp的内存地址中保留_save返回时下一条要执行的语句的地址 0040105e

012FF7C  5E 10 40  ^.@

0012FF7F  00 C0 FF  ...

 

0042B00B   pop         ebp

ESP = 0012FF28   ESP= ESP+4

EBP = 0012FF80

012FF28  5E 10 40  ^.@返回时下一条要执行的语句的地址

0012FF2B  00 7C FF  .|.

0012FF2E  12 00 00  ...

0012FF31  00 00 00  ...

 

0042B00C   mov         eax,0  //郅返回结果为0

0042B011   ret 回主函数

子函数_resume

_resume:

0042B012   push        ebp

0042B013   mov         ebp,esp

ESP = 0012FF24

EBP = 0012FF24

012FF24  80 FF 12  €..

0012FF27  00 8A 10  ...  //函数调用返回后,下一条要执行的语句的地址0040108a

0012FF2A  40 00 7C  @.|

0012FF2D  FF 12 00  ...

这时,我么要注意,ebp+4就是函数调用返回后,下一条要执行的语句的地址0040108a

我们想把函数的返回地址改变,改为执行_save后的第一条指令,还指令的地址放在ebp+8

0042B015   mov         esi,dword ptr [ebp+8]

取出_save后的第一条地址存放的地址为spp的地址 0012ff7c

0042B018   mov         eax,dword ptr [esi]

esi中的值给eax eax =0x0040105e 这就是改为执行_save后的第一条指令,而不是按正常执行_resume后的第一条指令

0042B01A   mov         dword ptr [ebp+4],eax

修改_resume函数返回后执行的第一条指令的地址

 

012FF24  80 FF 12  €..

012FF27  00 5E 10  .^. //函数调用返回后,下一条要执行的语句的地址由0040108a改为0040105e

0012FF2A  40 00 7C  @.|

0012FF2D  FF 12 00  ...

 

0042B01D   pop         ebp

0042B01E   mov         eax,1

//付值为1,返回,但程序会跳转到_save后的第一条指令,这样else if 都执行了

0042B023   ret

总的来说,就是通过一个变量来保存返回断点的下一条指令的地址,然后用该地址
替换程序正常返回地址,从而达到目的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值