这道题主要是要发现算法里的坑。
拿到程序发现是VB的程序,使用VB Decompiler进行反编译,发现算法非常清晰,如下图所示。
这是一个二元方程组,global_84和global_92是输入内容的左边八位和右边八位,并且两者都大于0,global_84大于global_92。这两个数是方程组的两个未知数。global_76,global104和global100都是已知的,其他全局变量都为0。令global84=a,global92=b,global76=c,global104=N1,global100=N2。可以将VB Decompiler反编译得出的方程组简化如下。
通过matlab进行计算,发现求出来的值都是复数,也就是说不存在实数解,踩坑了。看来反编译出来的代码应该有问题,看VB Decompiler中反汇编的p-code,发现和反编译的代码可以正确对应,所以问题不在这,这时就得看看是不是在将p-code字节反汇编成p-code时出现了问题。
程序无法用OD打开,不过可以使用OD附加程序分析。我们从反编译的代码中可以发现他使用了Left和Right函数去获取输入的左边八位和右边八位。因此可以直接对这两个函数下断。找到这些函数有个捷径,我们可以在VB虚拟机的入口上方发现一些jmp指令,从这些指令可以直接找到Left函数的地址,下断即可。
由于这个程序主要是进行方程的求解,因此VB虚拟机运行的过程十分清晰。在VB虚拟机中,esi存放p-code的eip,我们在VB虚拟机中单步调试时,可以观察esi寄存器的变化,然后和VB Decompiler反汇编出的p-code的地址对应起来,以确定当前的p-code指令对应的是什么操作。比如如下图所示。
当前esi寄存器的值是4083fa,说明当前p-code的eip是4083fa。VB虚拟机会将4083fa中的p-code字节码传递给al,并作为虚表的偏移去找下一个要执行位置。从VB Decompiler中可以看到4083fa位置的p-code指令是MulR8,也就是乘法,那么VB虚拟机通过p-code字节码找到虚表偏移后进入的地方就是来执行乘法这样一个操作。这个地方就是上图jmp指令跳转到的地方,进入后可以发现确实是执行乘法。
如此一来就可以根据p-code和对应的操作去确定是哪个地方出现问题,由于程序中多是加减乘除次方这样的计算,对应的操作都是浮点运算操作,可以很清晰地跟踪它的计算流程。
前面的流程都没有问题,直到p-code到达408427时,从VB Decompiler反汇编的p-code中可以得出这是个AddR8指令。但是我们发现该位置的指令字节码是0xAF。
在前面的跟踪,我们发现AddR8指令字节码是0xAB,这里0xAF被VB Decompiler认为是AddR8指令,可见VB Decompiler反汇编p-code时出了问题,跟进jmp可以发现这其实是个SubR4指令,是个减法,而VB Decompiler认为他是加法。(根据爱琴海的设计文章,可以知道在程序中对这些指令进行了修改,由于我是用OD附加调试,调试是在反调试内容之后进行的,侥幸绕过了这个坑)
继续跟踪可以发现流程还有其他几个地方存在这个问题,出现的位置就是在方程组第一个方程中a^4,b^4,c^4前的符号,这里应该是减号,所以第一个方程应该是
0.5*(-a^4-b^4-c^4+2*a^2*b^2+2*b^2*c^2+2*a^2*c^2)^0.5/(a+b+c)=N1
那么方程组就是
(PS:第二个式子是海伦公式,N2是三角形外接圆半径,冥冥之中感觉这个方程应该是求解三角形三边之类的。。)
使用matlab计算,可以得出a=1587167000,b=1043855616。由于a是左边八位,b是右边八位,输入要求十六进制,因此最终答案为5e9a3f183e37f900。
[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界