主函数在start的第一个参数里面。去除如下花指令
一个rc4加密,密钥在第一个生成盒函数的参数里。第二个函数是加密函数,动调密钥会被修改。
在第二个函数的call处下断点动调就可以看到加密函数,进入加密函数后发现花指令,和上面一样的nop掉后可以发现魔改RC4。
我们输入一串字符进行动调,在主函数的unk_5C6CC0中下硬件断点。后面会断在如下位置,这里就是比较的位置。去除这里的花指令后就可以看到逻辑,密文就是上面这些。所有数据都已经拿到,记得把密文转一下端序(见python脚本),最后还有一个异或0x23。
密文:25cd54af511c58d3a84b4f56ec835dd4f6474a6fe073b0a5a8c317815e2bf4f671ea2fffa8639957
密钥:921C2B1FBAFBA2FF07697D77188C
a = [0x0D3581C51AF54CD25,0x0D45D83EC564F4BA8,0x0A5B073E06F4A47F6,0x0F6F42B5E8117C3A8,0x579963A8FF2FEA71]
b=""
for i in a:
b += i.to_bytes(8,'little').hex()
print(f"{b}",end='')
方法2,不去花指令的动调获取,需要汇编基础,当作汇编和动调练习了。
首先我们寻找输入输入数据的位置,可以单步进入函数看从什么位置开始读取数据,当然这很麻烦,万不得已还是别了吧。接下来我们用更简单一点的方法进行定位,首先我们调试直接运行到输入数据的时候,程序会等待我们的输入,这时我们用ida的trace来寻找输入函数。按下图打开栈追踪,
进行函数追踪
这个时候程序会断在一个位置,一般这个位置就是输入数据的前一个位置,在断下的位置(EIP)下断点(总之下的断点要把程序停在附近,不能让程序结束),单步运行到程序等待输入,然后输入数据。用Call stack可以看函数调用的顺序,寻找出主函数和加密函数,不过暂时用不到。
其实我们也可以发现①就是一个读取函数,我们的程序断在了断点处,并且我们往上分析就可以看到我们输入的数据,这个时候我们就可以下一个硬件断点在输入的数据上,继续动调,下断点的时候建议多下几个,最少头尾两个,这样更好分析。我们接下来运行程序,分析汇编。
我们运行下去就会发现我们会在一个函数里面循环,分析一下,好像是把我们的输入转存到rbx-1里面去了,我们进入,继续给数据下硬件断点。
我们可以发现这个变量是有名字的,我们对这个变量进行引用查看,就会到一个函数如下图,这个函数里面有一个%s。上面是我们输入的数据,下面有个%s,想都不用想,下一个call就是输入函数scanf,所以这里大概就是主函数了。
如下图,继续看引用可以看到上面有一个别的变量好像存储了一些数据,感觉是密文,先记下来。我们可以看到我们的输入数据被加载到了rdi中,然后call了一个r8函数(猜不出来也没问题,可以继续用硬件断点分析),估计这个函数就是处理数据的函数。我们给call下一个断点,继续运行程序。发现下一步直接到了call这里,继续运行。
如下图,我们会进入一个函数循环中,这就是加密主逻辑了,看到&255你能想到什么?没错,就是RC4。单步分析这个循环,我们还可以发现RC4的表,以及还有一个异或0x23。在最后我们在返回处下一个断点单步运行,发现返回的位置就是Call r8的位置,那么这就是RC4加密函数。我们可以知道,RC4前面的一个函数一般就是用密钥生成盒,而且正好在我们call r8的上面刚还有一个call r8,而且上面刚好也加载了一个变量,没错,这就是我们之前记下的密钥。
继续往下运行,我们到了一个比较函数,上面有一大串的数据,我们加密后的密文也在cmp处进行比较,右侧就是密文。至此,分析结束,我们开始解密。结束了吗?还没有,我们拿到的密钥被反调试修改了,我们要在没有调试的情况下获取密钥,就在我们记下的那个变量里。这样就可以正确解密了,解密参照方法1.