最近在读《python 灰帽子》一书,按照书上代码照抄一边,运行结果却是预期的效果,前三章的练习通过网上搜索修改后可以正常运行。第四章的第一个示例代码printf_random的结果也和书上不一致(可能是因为书上系统环境是32位,我的是64位吧)。错误结果如下图:
网上查了一下,找到这篇文章:
http://www.docin.com/p-680357401.html。
里面通过在回调方法
printf_randomizer
方法中调用dbg.dump_context()
方法查看context内容。发现
parameter_addr = dbg.context.Esp + 0x8 处 0x8 改为 0x4
。可以取到堆(heap)上的字符串“Loop iteration 4!”
, 然后截取字符串替换字符串的方式实现了预期结果。但是文章最后也提到了这种方式最后修改的并不是存放counter的那块内存中的值,只是修改了最后输出语句中两个字节的值。
另外还发现另一篇文章http://blog.csdn.net/u012763794/article/details/52174275。
里面提到发现调用的轨迹:
call python27.PyOS_snprintf ----> msvcr90._vsnprintf --> msvcr90.printf
而参数入栈在_vsnprintf 就已经搞定了,到后面的printf直接压字符串入栈就可以了,应该msvcrt也是一样的。
所以在printf打断点时就只能修改字符串了,想要修改counter,需要在_vsnprintf调用之前加断点,在尝试msvcr90._vsnprintf 和 msvcr90.printf失败后,最终作者python27.PyOS_snprintf成功了,但是作者文章中写的比较模糊,最后成功的代码也没贴出来,我试了几次也没成功。
在查看dump_context时发现EDI里放的好像就是counter里的值!
然后通过修改context.Edi最终也成功出来结果。
但是也存在回调函数调用两次的情况,和文章的情况不一样的地方是他输出的是一个固定的常量地址(难道是counter的地址?),而我的输出的是counter的原始值。
最后贴出代码: