下面是旧的 WP 要把那个 Alpha 去掉
直接复制粘贴反汇编程序
大概把流程逆过来实现了,但还是不对。。
容我分析一下程序先:
程序入口
_main()
函数初始化全局变量,包括 magic a;
这个 magic a 是一个伪装的包装异常处理函数的结构体
这是 magic 的构造函数吧
可以看到程序是用 VEH 处理异常,并注册了 _scanf()
这个处理异常的函数
这是 _scanf()
函数,它在系统抛出错误之后当调试器不处理之后他就来处理错误,可以看到程序判断了发生错误的位置和相应修改内存的代码
第一个位置 loc_40172E
反汇编后在这里:
可知在进入循环的时候可能会报错,但是报错的原因还不知道
好了现在知道了,这里有一个物理断点存在,一开始就在 magic 里设置了
初始化线程的寄存器,DR0-DR3 为设置断点的地址,DR7 保存了断点是否启用、断点类型和长度等信息。
看看 DR7 存 405 意味着什么
0x405 == 0b0100 0000 0101
也就是 L0 = 1 L1 = 1 其他为 0,也就是开启了 DR0 和 1 的硬件断点,可是明明前面只有开了一个 Dr0, Dr1 有没有指定地址呢?
好吧,问题不在这,没设置就是没设置
问题在于
Rip += 49i64
通过让 IP 移动来达到异常产生后跳过一部分代码的功能,通过对 DX 跟踪找到最终要跳转的地址 40175F
也就是这里:
所以说循环变成了这样:
第二个位置 loc_4017C2
可以很清楚的知道这里用 int 3 打了一个软中断,会把这个识别成断点。
因为调试器的原理就是运用异常的处理机制来运作的,所以这个 int 3 会引发异常也是肯定的,如果不是在调试状态下的话,程序一定会进入 _snanf()
里面,并进行对 cipher 的修改
总之 主函数的其他函数基本都没有什么问题,就是这个 base64 () 内有玄机,运用中断的异常和赋值操作的异常来调用一些一般不会起作用的后门函数来起到迷惑的作用
所以基于这种逻辑,可以通过逆向来把异常修复的函数显式的调用之后再把整个过程从 cipher 逆过来反推到 flag