- UID
- 3808
- 精华
- 积分
- 1480
- 威望
- 点
- 宅币
- 个
- 贡献
- 次
- 宅之契约
- 份
- 最后登录
- 1970-1-1
- 在线时间
- 小时
|
今天中午睡午觉的时候日常在床上玩会手机,.我开始看QQ浏览器的新闻,忽然我看到QQ浏览器有给我推送一篇关于C/C++的面试题,我当时点进去看完后感觉没有多大意义,就退出来了。
但是中午醒来准备上课,上课的过程中我才发现原来那个东西比上课有意思,所以我就又开始回想那个推送的面试题。
注意:以下操作是在win10,VS2013(win32 Debug模式)和IDA中完成的。
题目大概是这样的:如何填写pass函数中的内容,使main函数中的第二个printf打印234,代码如下:
- #include <stdio.h>
- void pass()
- {
-
-
- }
- int main(void)
- {
- int a = 123;
- printf("%d\n",a);
- pass();
- printf("%d\n",a);
- return 0;
- }
复制代码
我一开始想不出来这个怎么通过C语言来用子函数控制主函数中的作用域的变量。
这个就很恼火了。那么就来汇编吧,我是空想想不出来,于是在课本上半沿写了写函数开头都有的反汇编,发现自己只知道大概思路,但是具体的每一步居然写不出来。
只有回到宿舍来用电脑看看了。
这个程序中主函数中的变量a所对应的汇编中的地址为ebp-8,大家可以用vs2013或者IDA自己反汇编看看。小弟在这里贴一下题目中main函数在IDA中的反汇编:
- _main proc near ; CODE XREF: _main_0↑j
- .text:004113C0
- .text:004113C0 var_CC = byte ptr -0CCh
- [b][u].text:004113C0 a = dword ptr -8[/u][/b]
- .text:004113C0
- .text:004113C0 push ebp
- .text:004113C1 mov ebp, esp
- .text:004113C3 sub esp, 0CCh
- .text:004113C9 push ebx
- .text:004113CA push esi
- .text:004113CB push edi
- .text:004113CC lea edi, [ebp+var_CC]
- .text:004113D2 mov ecx, 33h
- .text:004113D7 mov eax, 0CCCCCCCCh
- .text:004113DC rep stosd
- [u][b].text:004113DE mov [ebp+a], 7Bh[/b][/u]
- .text:004113E5 mov esi, esp
- .text:004113E7 mov eax, [ebp+a]
- .text:004113EA push eax
- .text:004113EB push offset Format ; "%d\n"
- .text:004113F0 call ds:__imp__printf
- .text:004113F6 add esp, 8
- .text:004113F9 cmp esi, esp
- .text:004113FB call j___RTC_CheckEsp
- .text:00411400 call j__pass
- .text:00411405 mov esi, esp
- .text:00411407 mov eax, [ebp+a]
- .text:0041140A push eax
- .text:0041140B push offset Format ; "%d\n"
- .text:00411410 call ds:__imp__printf
- .text:00411416 add esp, 8
- .text:00411419 cmp esi, esp
- .text:0041141B call j___RTC_CheckEsp
- .text:00411420 xor eax, eax
- .text:00411422 pop edi
- .text:00411423 pop esi
- .text:00411424 pop ebx
- .text:00411425 add esp, 0CCh
- .text:0041142B cmp ebp, esp
- .text:0041142D call j___RTC_CheckEsp
- .text:00411432 mov esp, ebp
- .text:00411434 pop ebp
- .text:00411435 retn
- .text:00411435 _main endp
复制代码
可以很清晰的看出来文中加粗和加下划线中main函数中变量a所对应的地址在反汇编中是ebp-8
好的,那我就想我在pass函数中通过ebp的偏移,找到main函数中的ebp的位置,然后修改地址ebp-8的所对应的值来达到修改main函数中a的值可能会成功(我也不知道,只有试了才知道)。
一开始我想通过pop edi, pop esi, pop ebx, pop ebp来获取ebp的值,但是发现那样根本行不通,通过栈的偏移来找ebp的值也不行(程序会有逻辑错误)。我想我得换个法子了。
于是我通过打印pass中的ebp和main中的ebp来寻找他们的关系,我就把上面的程序稍微修改了一下:
- #include <stdio.h>
- void pass()
- {
- int i = 1; //设置变量,用来存储pass中的ebp的值
- _asm
- {
- lea eax,[ebp]
- mov [i],eax
- }
- printf("pass中的ebp:%d\n", i);
- }
- int main(void)
- {
- int a = 123;
- printf("%d\n", a);
- int b = 0; //设置变量,用来存储main中ebp的值
-
- _asm
- {
- lea eax,[ebp]
- mov [b],eax
- }
- printf("main中的ebp:%d\n", b);
- pass();
- printf("%d\n", a);
- return 0;
- }
复制代码
运行结果如下:
- 第一次运行结果:
- 123
- main中的ebp:5241420
- pass中的ebp:5241184
- 123
- 请按任意键继续. . .
- 第二次运行结果:
- 123
- main中的ebp:13892528
- pass中的ebp:13892292
- 123
- 请按任意键继续. . .
- 第三次运行结果:
- 123
- main中的ebp:15726676
- pass中的ebp:15726440
- 123
- 请按任意键继续. . .
复制代码
我们可以发现,通过多次的运行,在这个程序中,main中的ebp和pass中的ebp总是相差一个常数,那就是236。好了,我想我找到答案了,我们在pass中给ebp加上236就是main中的ebp,然后给ebp-8就是main中变量a的地址,通过修改ebp-8所对应的值来达到修改main中变量a的值。
最终程序如下:
- #include <stdio.h>
- void pass()
- {
- int i = 1;
- _asm
- {
- mov dword ptr [ebp+228],234 //通过ebp+236是main中ebp的位置,然后ebp+236-8是main中变量a的地址。
- }
- }
- int main(void)
- {
- int a = 123;
- printf("%d\n", a);
- int b;
- pass();
- printf("%d\n", a);
- return 0;
- }
复制代码
运行结果为:
可以看到最后的这个程序还是有两点不足:
1.程序最后的时候main函数中必须要有一个int b;(初不初始化都行,但是必须要有,否则要崩溃,但是这么做就不符合题目的本意了)
2.tangptr说不喜欢C/C++来内嵌汇编来写,但是小弟不知道能不能不内嵌汇编,用C语言的方式完成这道题目?
小弟知识浅薄,望各位大佬多多指正,不必留情。 |
|