移梵塔

本文详细解析了Delphi环境下递归函数的反编译过程及单步运行机制,通过具体实例展示了参数传递、堆栈操作及递归调用的内部细节。

  var
    x,y,z:char;
    N,k:integer;

procedure sub(n:integer;a,c,b:char);
begin
  if n=0 then Exit;
  sub(n-1,a,b,c);
  Inc(k);
  Writeln(k,':from',a,'->',c);
 //sub(n-1,b,c,a);
  end;

begin
  { TODO -oUser -cConsole Main : Insert code here }
write('n=');
readln(n);
  k:=0;
  x:='A';y:='B';Z:='C';
  sub(n,x,y,z);
  readln
end.

 

简单分析如下代码

目的:了解DELPHI递归反编译单步运行分析

 sub(n,x,y,z);

4个参数

n存于ESI

X 分别用第一参数表示

Y 第二参数

Z 第三参数

反现个规律:
第三参数压堆栈 第二参数存ECX 第一参数存EDX 递归的计数N-1存于EAX中

假调N=2情况分析

 

SUB(N,x,y,z)  PA:

SUB(N,A,C,B)

SUB(N-1,A,B,C)---》

=============                                 

        =========    SUB(N-1,A,C,B)

                                SUB(N-1-1,A,B,C)

                                                                         SUB(N-1-1,A,C,B)

                                                                        SUB(N-1-1-1,A,B,C)

Project1.dpr.48: k:=0;
004084A9 33C0             xor eax,eax
004084AB A398A74000       mov [k],eax


Project1.dpr.49: x:='A';y:='B';Z:='C';
004084B0 B041             mov al,$41    //A 
084B2 B242             mov dl,$42   //B                           //存第一
084B4 B143             mov cl,$43   //40A143=C          //存第二 起始ECX EDX相反参数初始 eaz存记数

       N     X      Y         Z

--   ESI eax  eDX    ECX 初始时  ESI=N  EAX=A EDX=B  ECX=C

 

运行时:

第三参数压堆栈 第二参数存ECX 第一参数存EDX 递归的计数N-1存于EAX中

Z压堆栈 Y压ECX  X压 EDX N 压EAX

 2       n      x      y      z    

esi    eaX  edx ecx    堆栈  堆栈保存不动    参数下划一级    为CALL准备参数

 


Project1.dpr.50: sub(n,x,y,z);   //PA

///下面开始为CALL准备参数sub(n,x,y,z);  

004084B6 51               push ecx                //保存第三参数压堆栈 C 

004084B7 8BCE             mov ecx,esi         //esi=N=2假设N=2 
004084B9 91               xchg eax,ecx       //EAX=2 ecx=A
004084BA 87CA             xchg edx,ecx     //ecx=B 值 EDX=A

 

             n           X=A          Y=B   

ESI      EAX         EdX           EcX      堆栈   存放第三参数ECX做周转实现

调用CALL前的准备:第三参数压堆栈 第二参数存ECX 第一参数存EDX 递归的计数N存于EAX中

 

 

004084BC E8AFFEFFFF       call sub

[

Project1.dpr.36: begin
00408370 55               push ebp
00408371 8BEC             mov ebp,esp  //保存当前EBP值到
00408373 51               push ecx    //第三参数压推栈ECX值是B 是SUB(A,B,C)之前调用的SUB(A,C,B)C中值是B第三
00408374 53               push ebx  //保存EBX原值
00408375 884DFF           mov [ebp-$01],cl  [EBP-$01]=B c1值是=$B //这里奇怪多了个B作用
00408378 8BDA             mov ebx,edx  EBX='a'

 

 


Project1.dpr.37: if n=0 then Exit;
0040837A 85C0             test eax,eax  //比较N值是否为0 是0结束函数
0040837C 7452             jz +$52  
Project1.dpr.38: sub(n-1,a,b,c);         //
0040837E 8A55FF           mov dl,[ebp-$01]
00408381 52               push edx
00408382 48               dec eax
00408383 8A4D08           mov cl,[ebp+$08]
00408386 8BD3             mov edx,ebx
00408388 E8E3FFFFFF       call sub
Project1.dpr.39: Inc(k);
0040838D FF0598A74000     inc dword ptr [k]
Project1.dpr.40: Writeln(k,':from',a,'->',c);
00408393 A104934000       mov eax,[$00409304]
00408398 8B1598A74000     mov edx,[k]
0040839E E8C9AAFFFF       call @Write0Long
004083A3 BAE0834000       mov edx,$004083e0
004083A8 E82BBDFFFF       call @Write0LString
004083AD 8BD3             mov edx,ebx
004083AF E83CAAFFFF       call @Write0Char
004083B4 BAF0834000       mov edx,$004083f0
004083B9 E81ABDFFFF       call @Write0LString
004083BE 8A55FF           mov dl,[ebp-$01]
004083C1 E82AAAFFFF       call @Write0Char
004083C6 E8D1AAFFFF       call @WriteLn
004083CB E85CA2FFFF       call @_IOTest
Project1.dpr.42: end;
004083D0 5B               pop ebx
004083D1 59               pop ecx

 

 

 

 

 

 

 

 

 

]

 

 

 

 

 


Project1.dpr.52: end.
004084C1 A170934000       mov eax,[$00409370]
004084C6 E88DA6FFFF       call @ReadLn
004084CB E85CA1FFFF       call @_IOTest
Project1.dpr.52: end.
004084D0 5E               pop esi
004084D1 E816B7FFFF       call @Halt0
004084D6 0000             add [eax],al
004084D8 FF               db $ff
004084D9 FF               db $ff
004084DA FF               db $ff
004084DB FF02             inc dword ptr [edx]
004084DD 0000             add [eax],al
004084DF 006E3D           add [esi+$3d],ch
004084E2 0000             add [eax],al
004084E4 0000             add [eax],al
004084E6 0000             add [eax],al
004084E8 0000             add [eax],al
004084EA 0000             add [eax],al
004084EC 0000             add [eax],al
004084EE 0000             add [eax],al
004084F0 0000             add [eax],al

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

////////////////////////////////////////////////

 

 

Project1.dpr.48: k:=0;         
004084A9 33C0             xor eax,eax
004084AB A398A74000       mov [k],eax
Project1.dpr.49: x:='A';y:='B';Z:='C';
004084B0 B041             mov al,$41  //EAX 65 A
004084B2 B242             mov dl,$42  //eDx 66 B
004084B4 B143             mov cl,$43  //ecx  67 C  这里不同前两个寄存器存的是值 C1存的是地址(存放C的地址0040A143)
Project1.dpr.50: sub(n,x,y,z);                       此时ESP=13FFAC=K
004084B6 51               push ecx          C压入堆     (ESP)K-4 =13FFA8=0040A143=C //当前栈顶
004084B7 8BCE             mov ecx,esi   //ESI存放的是N的值 假设是3 放入ECX         
004084B9 91               xchg eax,ecx 交换        EAX=3 ECX=$41 

004084BA 87CA             xchg edx,ecx            ECX=$42  EDX=$41  N放入EAX  

004084BC E8AFFEFFFF    call sub   //调用SUB (esp)K-8=13FFA4  值是:004084C1是SUB CALL的下一条指令地址:堆栈存返回地址
Project1.dpr.52: end.
004084C1 A170934000       mov eax,[$00409370]
004084C6 E88DA6FFFF       call @ReadLn
004084CB E85CA1FFFF       call @_IOTest
Project1.dpr.52: end.
004084D0 5E               pop esi
004084D1 E816B7FFFF       call @Halt0
004084D6 0000             add [eax],al
004084D8 FF               db $ff
004084D9 FF               db $ff
004084DA FF               db $ff
004084DB FF02             inc dword ptr [edx]
004084DD 0000             add [eax],al
004084DF 006E3D           add [esi+$3d],ch
004084E2 0000             add [eax],al
004084E4 0000             add [eax],al
004084E6 0000             add [eax],al
004084E8 0000             add [eax],al
004084EA 0000             add [eax],al
004084EC 0000             add [eax],al
004084EE 0000             add [eax],al
004084F0 0000             add [eax],al

 

 

调用SUB

Project1.dpr.36: begin                               
00408370 55               push ebp         

 PUSH执行前  K=ESP=0013FFA4= 004084C1 ESP+4=0013FFA8=C EAX=N=3 ECX42 EDX41 ESI=N 

执行后   (esp)K-4=0013ffa0=EBP=0013FFC0   //保存EBP   

 

00408371 8BEC             mov ebp,esp    ebp=ESP=0013ffa0=K-4
00408373 51               push ecx

 

执行后:ESP=K-8=0013FF9C=$42  EBP=0013FFA0=K-4


00408374 53               push ebx                                                   //

执行后:esp=k-c=0013FF98 ==$41     EBP=0013FFA0=K-4


00408375 884DFF           mov [ebp-$01],cl [EBP-$01]=0013FFA0-$01=0013ff9c=$42


ebp-$0100408378 8BDA             mov ebx,edx==41                                     //
Project1.dpr.37: if n=0 then Exit;
0040837A 85C0             test eax,eax
0040837C 7452             jz +$52
Project1.dpr.38: sub(n-1,a,b,c);
0040837E 8A55FF           mov dl,[ebp-$01]
00408381 52               push edx
00408382 48               dec eax
00408383 8A4D08           mov cl,[ebp+$08]
00408386 8BD3             mov edx,ebx
00408388 E8E3FFFFFF       call sub
Project1.dpr.39: Inc(k);
0040838D FF0598A74000     inc dword ptr [k]
Project1.dpr.40: Writeln(k,':from',a,'->',c);
00408393 A104934000       mov eax,[$00409304]
00408398 8B1598A74000     mov edx,[k]
0040839E E8C9AAFFFF       call @Write0Long
004083A3 BAE0834000       mov edx,$004083e0
004083A8 E82BBDFFFF       call @Write0LString
004083AD 8BD3             mov edx,ebx
004083AF E83CAAFFFF       call @Write0Char
004083B4 BAF0834000       mov edx,$004083f0
004083B9 E81ABDFFFF       call @Write0LString
004083BE 8A55FF           mov dl,[ebp-$01]
004083C1 E82AAAFFFF       call @Write0Char
004083C6 E8D1AAFFFF       call @WriteLn
004083CB E85CA2FFFF       call @_IOTest
Project1.dpr.42: end;
004083D0 5B               pop ebx
004083D1 59               pop ecx

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值