依旧使用的是traceme,相关内容请参考https://blog.51cto.com/181647568/2421560

通过反复的研究traceme的汇编代码,我通过观察赋值的值来推测某些命令的作用。

image.png

我在指令的右边标注了那些代码都是干什么的,直到最后一行的call命令,这个call命令是接下来跳转的部分了,下图中的je也是我们最一开始爆破nop掉的那个那个命令,所以无论正确的序列号是怎么出来的,已经就在call TraceMe.00401340中了。

image.png

点击call的行按住回车可以跳转到这个方法中,为了方便我在这里加了断点,以后我可以通过F9键来快速的跳到这一步。

image.png

根据查看赋值我很快的发现了上图结尾几行为一个循环部分。

image.png

循环结束后,程序又做了一个取序列号的操作,并且在下方进行了一次对比(lstrcmpA方法)。因为根据前面的一篇博客(https://blog.51cto.com/181647568/2421560)我已经能够取到正确的验证码了,所以在这个地方我分别输入了正确的和错误的验证码,查看情况。结果表明这个程序在运行完成后会有一个寄存器(EAX)保留着一个值,序列号码错误为0正确为1。

而这个test就是控制je命令的。

那么这样我可以确认,序列号就是在那个循环中算出来的。

image.png

我可以看到一个0x7的我一开始以为是循环七次,然后我看着循环反复的重复着,mov部分,我可以清楚地看到蓝色部分的赋值,

image.png

上图是第一次循环的结果,我可以认出这个字符是我输入的用户名的第四位,为了验证是否和我想的一致,我修改了好几次用户名,每次都是第四位。而且被转换成数字了,我猜测是ascii码,在表格上一对应,确实是ASCII码,不过是16进制的。

而mov粉红色的一部分是十六进制的C,我没搞清楚是什么意思。

然后接下来的操作包含了imul,add,inc三个操作符,我特意百度了一下imul是乘法相当于edx=edx*ebx,数值是前面的用户名第四位的ASCII码和C的积。同理add就是esi=esi+edx,这个esi只在这句话里出现,而edx正好是前面乘法的结果,所以每次循环的积都会被累加到esi中。

inc ecx则是指ecx=ecx+1这个很像是计数器,所以ecx,eax都是计数器,它们都对应着一个cmp。

最后的那个cmp用ecx和edi,根据我的调试,edi永远是用户名的长度,而且这个判断是控制循环的,这个循环从4开始循环到用户名长度的那个数。

在每次循环中我反复的观察两个MOV命令,蓝色部分比较明显,永远是用户名的第N位的ASCII码,从4开始。粉红色部分就比较奇怪了,第一个是C,第二次是A第三次是13,都是16位的数字,毫无规律可循。于是我只能去理解[eax+0x405030]是什么意思了,首先eax一定指的是寄存器eax,eax的值会由一句inc eax每次都加1,而在循环第一句会判断这个eax是否会大于7,如果大于7会执行xor eax,eax,这个操作会把eax清零。(而在一开始我把这个7给理解错了,我以为这个控制循环次数的,循环从4开始,到用户名长度结束,如果用户名长度很长的话,也只会运行七次。但是后来我输入了一个较长的用户名,运行七次后并没有退出程序。)

0x405030明显是一个内存地址,我右键“数据窗口中跟随”然后查到这个内存地址

image.png

对应的ASCII码是乱码,我一开始没有理解,不过在几次循环后我发了规律,oc oa 13 09这些数字和粉红色参数的值是对应的,我立即就猜出了第四次循环的蓝色值和粉红色的值。第四次循环的结果确定了,当时还没能理解eax和这个内存地址的关系。我就用了一个比较长的用户名不停的测试,粉红色部分一直到最后的08之后并没有到D0而是回到了0C。于是我就能理解了,这是八个数字开始循环的。于是整个循环的命令差不多就能模拟出了。

从用户名的第四个字符开始取ASCII码乘以C,第五个字符的ASCII码乘以A,一次类推,第十二个字符又开始乘以C。直到最后一个字符。这些乘积都加起来,转换成十进制就是序列号。


算码器用易语言写是这样的,其他的语言写起来应该更加简单。不过我就不举例了。

.版本 2

.支持库 spec


.子程序 子程序1

.局部变量 用户名, 文本型

.局部变量 序列号, 整数型

.局部变量 用户名长度, 整数型

.局部变量 计数器, 整数型

.局部变量 第二个数, 整数型, , "0"

.局部变量 sum, 整数型


用户名 = “traceme”

用户名长度 = 取文本长度 (用户名)

第二个数 = { 12, 10, 19, 9, 12, 11, 10, 8 }


计数器 = 1

.判断循环首 (计数器 + 3 ≤ 用户名长度)

    sum = sum + 取代码 (取文本中间 (用户名, 计数器 + 3, 1), ) × 第二个数 [计数器 % 8]

    计数器 = 计数器 + 1

    ' 暂停 ()

.判断循环尾 ()

调试输出 (sum)