昨天在网上看到一个BT的面试题,代码如下:问题是运行这个程序屏幕上为什么会出现一个 :) ,就是一个冒号加一个右括号。
注:环境VC6 SP6 + vista sp2
我囧,当然是先跑起来看一下,debug下确实在屏幕上打印出来一个 :) ,再看看程序,它把c2的地址强制转换为了一个函数指针,它想干嘛?!然后下面还调用了这个函数,居然没crash,看来是c2里面的数值有点特殊,可能是构造的指令码,懒得分析了,直接把debug下编出来的文件放OD里面看一下,跑到函数调用的地方,如图:
三个红框的部分是两次调用pf和一次调用printf的位置,前面给c1和c2分配了空间,调用pf实际上直接就是运行EBP-C处的代码也就是指令执行到栈上去了,牛×,第一个call跟进去,如下图:
那个指令00B8 00004000 C3实际上就是c1和c2的值,可以转换成十六进制看一下,RETN返回之后,EAX中的值是00400000,很神奇的一个数字啊,为什么神奇,因为EXE文件加载到内存中的时候基址就是Ox00400000,所以实际上,这个时候EAX指向的是pe文件的第一个字节。
PE文件的第一个字节是啥?打开来看下:4D,传说中的MZ。再看第一个图片的代码,函数返回后把EAX加1,然后取指向的值,返回0x5A,接着这个值减去0x31,再存入ECX,计算出来是十进制41,查下ascii表http://apps.hi.baidu.com/share/detail/703688,果然是对应的右括号,第二个冒号也可以同样分析出来,汗。机器码前,了无秘密。
还有一个问题是,如果我编成release来跑的,直接crash,还是OD看一下是啥问题:
我囧,怎么这两个变量c1和c2没了……直接去执行堆栈指针指向地址的堆栈上的东东,不crash才怪了。那就给编译器使个障眼法,让它不优化掉这两个变量吧。杯具的代码。
【END】
联系客服