首页
社区
课程
招聘
[求助]给dll文件打补丁的堆栈平衡问题[已解决]
发表于: 2007-10-9 20:53 7373

[求助]给dll文件打补丁的堆栈平衡问题[已解决]

2007-10-9 20:53
7373
我自己写了个程序A.exe,运行时调用b.dll,现在我希望用补丁的方法调用我写的另一个dll文件,C.dll,于是在下面b.dll的代码空间

10009B47  |> \8BC6          mov eax,esi
10009B49  |.  5E            pop esi
10009B4A  \.  C3            retn
10009B4B      8B4424 08     mov eax,dword ptr ss:[esp+8]    //从这里开始补丁代码 修改为: call 1000F100     (1000F100是程序的空白地址)
10009B4F      56            push esi
10009B50  |.  85C0          test eax,eax
10009B52  |.  8BF1          mov esi,ecx
10009B54  |.  75 08         jnz short Regula_1.10009B5E
10009B56  |.  E8 13470000   call Regula_1.1000E26E
10009B5B  |.  8B40 10       mov eax,dword ptr ds:[eax+10]
10009B5E  |>  85F6          test esi,esi
10009B60  |.  75 04         jnz short Regula_1.10009B66
10009B62  |.  33C9          xor ecx,ecx
10009B64  |.  EB 03         jmp short Regula_1.10009B69
10009B66  |>  8B4E 1C       mov ecx,dword ptr ds:[esi+1C]
10009B69  |>  FF7424 10     push dword ptr ss:[esp+10]               ; /Style
10009B6D  |.  50            push eax                                 ; |Title
10009B6E  |.  FF7424 10     push dword ptr ss:[esp+10]               ; |Text
10009B72  |.  51            push ecx                                 ; |hOwner
10009B73  |.  FF15 84020110 call dword ptr ds:[<&USER32.MessageBoxA>>; \MessageBoxA
10009B79  |.  5E            pop esi
10009B7A  \.  C2 0C00       retn 0C

补丁处代码
1000F100      50            push eax
1000F101      53            push ebx
1000F102      51            push ecx
1000F103      52            push edx
1000F104      55            push ebp
1000F105      56            push esi
1000F106      57            push edi

1000F107  |.  E8 10000000   call Regula_1.1000F11C   //使用LoadLiabraryA和GetProcAddress调用我自己的dll

1000F10C      5F            pop edi
1000F10D      5E            pop esi
1000F10E      5D            pop ebp
1000F10F      5A            pop edx
1000F110      59            pop ecx
1000F111      5B            pop ebx
1000F112      58            pop eax
1000F113  |.  8B4424 08     mov eax,dword ptr ss:[esp+8]
1000F117  |.  56            push esi
1000F118  |.  83C4 04       add esp,4    //恢复esp
1000F11B  \.  C3            retn             //成功返回到10009B50

执行1000F107处的CALL,利用LoadLiabraryA和GetProcAddress成功加载了c.dll并调用了里面的函数,并且顺利返回到1000F10C,但发现执行代码mov eax,dword ptr ss:[esp+8]时eax的值不对了,应该改为mov eax,dword ptr ss:[esp+0C]才是正确的.堆栈肯定出了问题,但为什么可以正常返回呢?

返回后执行10009B73处函数MessageBoxA时又出错了,而且在10009B7A处返回到了不正确的地址,程序出错了.

请问错在哪里?

不知我有没有把问题表达清楚,请路过的大侠前辈们指点一下,堆栈出错在哪里?

附 1000F107  |.  E8 10000000   call Regula_1.1000F11C  代码
如下:
1000F11C  /$  E8 3F000000   call Regula_1.1000F160
1000F121  |.  05 3F4F0000   add eax,4F3F
1000F126  |.  E8 39000000   call Regula_1.1000F164
1000F12B  |.  8BF8          mov edi,eax
1000F12D  |.  85C0          test eax,eax
1000F12F  |.  74 0F         je short Regula_1.1000F142
1000F131  |.  E8 2A000000   call Regula_1.1000F160
1000F136  |.  05 3A4F0000   add eax,4F3A
1000F13B  |.  E8 32000000   call Regula_1.1000F172
1000F140  |>  FFD0          call eax
1000F142  \.  C3            retn
................

1000F160  /$  8B0424        mov eax,dword ptr ss:[esp]
1000F163  \.  C3            retn
1000F164  /$  50            push eax
1000F165  |.  E8 F6FFFFFF   call Regula_1.1000F160
1000F16A  |.  05 22100000   add eax,1022
1000F16F  |.  FF10          call dword ptr ds:[eax]       ;  kernel32.LoadLibraryA
1000F171  \.  C3            retn
1000F172  /$  50            push eax
1000F173  |.  57            push edi
1000F174  |.  E8 E7FFFFFF   call Regula_1.1000F160
1000F179  |.  05 43100000   add eax,1043
1000F17E  |.  FF10          call dword ptr ds:[eax]       ;  kernel32.GetProcAddress
1000F180  \.  C3            retn

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 0
支持
分享
最新回复 (9)
雪    币: 212
活跃值: (91)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
思路不清晰,这样很容易出错的,应该
10009B4B      8B4424 08     mov eax,dword ptr ss:[esp+8]    //从这里开始补丁代码 修改为: jmp 1000F100     
然后
1000F100      50            push eax
1000F101      53            push ebx
1000F102      51            push ecx
1000F103      52            push edx
1000F104      55            push ebp
1000F105      56            push esi
1000F106      57            push edi

1000F107  |.  E8 10000000   call Regula_1.1000F11C   //使用LoadLiabraryA和GetProcAddress调用我自己的dll

1000F10C      5F            pop edi
1000F10D      5E            pop esi
1000F10E      5D            pop ebp
1000F10F      5A            pop edx
1000F110      59            pop ecx
1000F111      5B            pop ebx
1000F112      58            pop eax
1000F113  |.  8B4424 08     mov eax,dword ptr ss:[esp+8]
1000F117  |.  56            push esi
1000F118  |.                  jmp 10009B50
这样就不容易搞错了,你错的应该是
1000F113  |.  8B4424 08     mov eax,dword ptr ss:[esp+8]
1000F117  |.  56            push esi
这两句了,这两句在retn之前当然会出错了。
2007-10-9 22:21
0
雪    币: 3758
活跃值: (3337)
能力值: ( LV15,RANK:500 )
在线值:
发帖
回帖
粉丝
3
你call的时候, 会将返回地址入栈, 在没有返回前, 平衡的情况, 堆栈自然和call句前差4.
2007-10-10 01:18
0
雪    币: 256
活跃值: (753)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
4
[QUOTE=jxx_gt;368852]思路不清晰,这样很容易出错的,应该
10009B4B      8B4424 08     mov eax,dword ptr ss:[esp+8]    //从这里开始补丁代码 修改为: jmp 1000F100     
然后
1000F100      50            pus...[/QUOTE]

首先感谢你!这种做法是可以的,但

1000F113  |.  8B4424 08     mov eax,dword ptr ss:[esp+8]
1000F117  |.  56             push esi
1000F118  |.  83C4 04       add esp,4    //恢复esp

由于修改的地方是:
mov eax,dword ptr ss:[esp+8]
push esi

但我在后面用add esp,4恢复了esp呀,这种做法我在.exe试过好几个,基本都是对的,但在dll中为何恢复了栈指针还不行呢? 我想知道道理是什么?而不仅仅是方法呀.
2007-10-10 08:35
0
雪    币: 256
活跃值: (753)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
5
如果用call方式,应该修改哪里?
2007-10-10 09:05
0
雪    币: 212
活跃值: (91)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
[QUOTE=wyqzm;368919]首先感谢你!这种做法是可以的,但

1000F113  |.  8B4424 08     mov eax,dword ptr ss:[esp+8]
1000F117  |.  56             push esi
1000F118  |.  83C4 04       add e...[/QUOTE]
其实你只要比较一下原程序和你修改程序执行到10009B50时的堆栈内容就知道错在哪里了。
首先mov eax,dword ptr ss:[esp+8]这一句应该改为mov eax,dword ptr ss:[esp+c],这样eax里的值才没修改之前的程序一样,第二在执行到1000F118时堆栈如下:(比如esp=10002000)
10002000:esi的值(push esi执行之后结果)
10002004:509B0010(返回地址)
10002008:00000000
而未修改的原程序堆栈如下:
10002004:esi的值((原程序push esi执行之后结果)
10002008:00000000
这样原程序和你修改后的程序esi入栈后并不在同一个位置,后面用到esi的值不出错才怪!如果你非要这样用你的法子的话,你就在返回之前push esi之后将[esp]和[esp+4]里的值互换,然后不要add esp,4,直接retn就行了(你不觉得这样太罗嗦了么)。
2007-10-10 18:25
0
雪    币: 256
活跃值: (753)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
7
[QUOTE=jxx_gt;369127]其实你只要比较一下原程序和你修改程序执行到10009B50时的堆栈内容就知道错在哪里了。
首先mov eax,dword ptr ss:[esp+8]这一句应该改为mov eax,dword ptr ss:[esp+c],这样eax里的值才没修改之前的程序一样,第二在执行到1000F118时堆栈如...[/QUOTE]

谢谢,经过调试,我已经明白了,就原来代码不用多少修改,如下:

10009B4B   /E9 31560000    jmp Regula_1.1000F181  //原来的call 1000F100

1000F181    E8 7AFFFFFF     call Regula_1.1000F100   //放一个CALL在这里让它自己平衡吧,安全一点
1000F186    8B4424 08       mov eax,dword ptr ss:[esp+8]   //补回原来的代码
1000F18A    56              push esi
1000F18B  ^ E9 C0A9FFFF     jmp Regula_1.10009B50   //跳到原来的地方继续执行

下面:
1000F100    50              push eax  //还不如直接写成pushad
1000F101    53              push ebx
1000F102    51              push ecx
1000F103    52              push edx
1000F104    55              push ebp
1000F105    56              push esi
1000F106    57              push edi
1000F107    E8 10000000     call Regula_1.1000F11C
1000F10C    5F              pop edi
1000F10D    5E              pop esi
1000F10E    5D              pop ebp
1000F10F    5A              pop edx
1000F110    59              pop ecx
1000F111    5B              pop ebx
1000F112    58              pop eax           //这里可以直接写成popad,上面的各位弹出就没有必要了.
1000F113    C3              retn           //寄存器恢复后直接返回,在CALL外面补回代码比较安全,呵呵,这是要注意的.虽然是小问题,但也是经验呀,怪自己平时跟踪工作做得太少了.
2007-10-10 19:12
0
雪    币: 212
活跃值: (91)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
最好还加上pushfd和popfd,如下:
pushfd
pushad
call xxxxxxxx
popad
popfd
2007-10-10 23:23
0
雪    币: 256
活跃值: (753)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
9
嗯,不错,这样就更保险一点啦,呵呵,再次感谢呀
2007-10-11 08:33
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
good!!
2007-10-11 10:41
0
游客
登录 | 注册 方可回帖
返回
//