我写第二题吧,第一题暂时不写了,今天刚刚加入的群,多谢美丽の破船放我进去了.呵呵.这里我写下我做第二题的思路吧.
首先用IDA载入.很快就把结构分析出来了.核心代码就这两个SUB程序.:
text:00401020 _main proc near ; CODE XREF: start+AFp
.text:00401020 call sub_401000
.text:00401020
.text:00401025 push 0
.text:00401027 push offset s_MD ; "m=%d\n"
.text:0040102C call sub_401057
.text:0040102C
.text:00401031 add esp, 8
.text:00401034 retn
.text:00401034
.text:00401034 _main endp
上面是main函数,从上面看在00401020地方先CALL了个子程序.也就是test函数了.在IDA里直接双击进入test函数显示如下:
这个是test函数
sub_401000 proc near ; CODE XREF: _mainp
.text:00401000
.text:00401000 var_4 = dword ptr -4
.text:00401000
.text:00401000 push ecx
.text:00401001 lea eax, [esp+4+var_4]
.text:00401005 mov [esp+4+var_4], 0 ; 401000给局部变量分配空间
.text:00401005 ; 再是按址赋值为0
.text:0040100D push eax ; &t压栈
.text:0040100E push offset s_D ; "%d"
.text:00401013 call _scanf
.text:00401013
.text:00401018 add esp, 0Ch ; 平衡堆栈
.text:0040101B retn
.text:0040101B
.text:0040101B sub_401000 endp
这里我把该函数的每句说明一下.
首先是push ecx是用来给局部变量开辟空间的.此时栈顶就成了esp-4
然后再用lea传地址,用mov把0赋给建立的局部变量.这样堆栈顶的内容就成了0.这里完成了局部变量的初始化工作.
然后是push eax,注意经过这一步后,堆栈变成了esp-8并且栈顶的值为局部变量的有效地址.然后是push offset s_D
call _scanf
这两步完成的是输入操作.注意在scanf和printf函数是需要自行平衡堆栈的,所以在其后紧跟一句
add esp, 0Ch
注意了,因为在push eax 后又有了一句push offset s_D 所以平衡堆栈就得是add esp, 0Ch 了.然后是retn子函数的返回.
在子函数返回后,此时的堆栈栈顶回复到了调用它之前的状态,在理论上来说在该栈顶以上的部分数据没用了,不过这些数据却还是可以调用的.注意我在上面说了.在子函数中的push eax这一句里是esp-8的地方保存的局部变量的有效地址.那么OK在返回了主函数后,只要我们把局部变量的有效地址传给主函数里的一个变量,然后调用printf不就可以达到输入输出相等了吗?
不知道上面我的表述是否大家能明白.如果不明白的建议自己写两个子函数然后跟踪下堆栈.这样就能明白
push ebp
mov ebp,esp
的意思了.好了闲话不多说,这里开始正式干活.用OD载入第二题.我们用IDA里已看到了.MAIN函数的开始地址是00401020.那么我们就直接ctrl+g输入地址直接到达我们主函数
看到如下:
00401020 /$ E8 DBFFFFFF call 00401000
00401025 6A 00 push 0
00401027 68 34804000 push 00408034 ; ASCII "m=%d",LF
0040102C |. E8 26000000 call 00401057
00401031 |. 83C4 08 add esp, 8
00401034 \. C3 retn
00401035 90 nop
00401036 90 nop
00401037 90 nop
00401038 90 nop
00401039 90 nop
0040103A 90 nop
0040103B 90 nop
0040103C 90 nop
0040103D 90 nop
前面的几行是不是跟我们在IDA里看到的很像呢?那么就开始行动吧.我们知道
00401025 6A 00 push 0
就是传入给输出函数的值.那么如果我们把它改成test函数里的局部变量.这不就达到了题目的要求了嘛?所以呢我们就需要把局部变量的值给它传过去.我们观察到在401035到103D有着一大堆的空地方.那么我们就有效的利用起它.直接在
00401025 6A 00 push 0
上按回车进行汇编.
改成
jmp short 00401035
然后到00401035
的地方用如下:
push dword ptr [esp-8]
OK现在我们输入的数已经压栈了.那么就继续跳回原来的地址继续执行.所以在后面加下面这句:
jmp short 00401027
这样就实现了我们的目的了,试验运行下成功.然后就是复制修改部分到文件了.此题顺利完成.
完整的修改代码如下(注意红色部分):
00401020 /$ E8 DBFFFFFF call 00401000
00401025 |. EB 0E jmp short 00401035
00401027 |> 68 34804000 push 00408034 ; ASCII "m=%d",LF
0040102C |. E8 26000000 call 00401057
00401031 |. 83C4 08 add esp, 8
00401034 |. C3 retn
00401035 |> FF7424 F8 push dword ptr [esp-8]
00401039 \.^ EB EC jmp short 00401027
0040103B 90 nop
可能有些人在看了上面的后会有以下的疑问:
1.为什么不直接修改00401025处为push dword ptr [esp-8],而是要跳到一个空区呢?
解答:大家注意输入这段后OD里的变化为:
00401035 |> \FF7424 F8 push dword ptr [esp-8]
而
00401025 6A 00 push 0
这里可以看到它的机器码长度明显大于原来的.所以这也是我为什么不直接在00401025 修改而要
跳到一个空白区进行操作的原因.
2.是否可以把[esp-8]的值传给某一个寄存器然后用push某一个寄存器呢?
解答:这是可以的.不过因为要考虑到要保持各寄存器的值的问题,在用寄存器保存值时记得事先要把原有的值压入堆栈,完成后还要记得保持平衡,因为要考虑比较多的东西,我这里就不那么麻烦,直接把值压入堆栈了.
最后把我修改后的发上来,算是交作业了.不知道是否能算我过关啊^^
第二题交作业.rar