【吾爱破解精华帖】一个crackme的分析
|
(出处: 吾爱破解论坛) 拿到crackme用PEID的深度扫描发现是aspack2.x的壳,用Abstersiver把壳脱掉。运行脱壳后的程序,随便输入几组用户名和注册码,发现并没有任何提示信息。由此可以推测只有输入正确的name和serial程序才会给出提示信息。用OD加载起来程序,大概浏览一下代码,找到两处调用MessageBox的地方,很容易判断上面那个MessageBox是和验证注册码相关的。因为它上面有一个跳转,那个跳转是要跳转到返回的,所以这个跳转很关键,而决定要不要跳转的判断条件是eax的值,而eax的值是call 00401509的返回值。所以00401509这个call很关键,我们在这个地址处下一个断点重点分析一下。
下面就是00401509这个CALL的详细分析。Ctrl+F2重新启动被调试程序,F9让程序运行起来,我先输入一组name和serial,name是nvluoyan,serial是whaththefuck ,点击程序的check按钮,发现程序被断在了00401509。
总结一下就是获取用户输入的name并对name的长度进行判断。
总结一下就是对name的长度进行运算,确保name的长度必须在一个范围之内,即0x0190<=((0x02bc-5*(0x30-0x48/Lname))*0x6b)-0xcf6c<=0x2300解一下这个不等式。这个不等式我之后直接用16进制计算,发现得不到正确的结果,不知道为什么。
我们输入的nvluoyan是8位,正好在[3,9]之间。 对name的长度验证之后就进行了对serial的处理了。处理serial的函数需要三个参数,第一个是hwnd,和算法没关系,第二个是name的长度Lname,第三个是用户输入的用户名name
然后进入00401305这个call的内部来看看。
没什么重要的信息,就是一些字符串初始化操作,字符串的作用都在注释中写清楚了,就不多做解释了。
然后获取用户输入的Serial,把Serial存放到UserSerial中。
获取用户输入的Serial的第一个字符,用0x11cf对Serial的第一个字符取余,检测结果是不是0x17,如果是则继续流程,否则返回。可见这个crackme对Serial的第一个字符是有要求的,我们可以写一个小程序来输出一下,很简单的遍历输出即可。
输出结果是:
所以用户输入的Serial的第一个字符必须是$ * 6 8 ? H Q T l ~ 这10个中的其中一个。为了让流程继续下去,我们修改一下输入的Serial,从whatthefuck变为6hatthefuck
然后是取得用户的name,并把name中的每个字符按顺序加起来,最后的结果保存在sum中。00401305这个CALL有两个重要的参数一个是用户输入的name,一个是name的长度Lname,在这里用到了!
这部分就是就是关键了,详细的在注释中都说明了。
然后对SerialFirst数组格式化,就是在最前面加一个大写字母T,把结果存放到SerialFormatFirst数组中。
然后是对SerialFirst数组的第二次格式化,结果存放到SerialFormatSecond[256]中。
然后就是一个重要的call了,这个call有三个参数,其中两个是根据name生成并格式化过的Serial和它的长度,另外一个是用户输入的Serial。
程序并没有直接比较SerialFormatSecond和UserSerial中的每个字符,而是取得SerialFormatSecond中的每个字符,经过一定运算得到一个字符,如果这个字符和UserSerial中相应的某个字符比较是否相等,所以注册机就很好写了。值得注意的一点是,有一个代码是idiv ecx,是对0xA取余。取余这个操作很有意思,它的结果总是小于自己,对0x0A取余,那么结果一定小于0x0A,想一想为什么要对0x0A取余呢?因为它的结果一定是在0到0x0x0A-1这个范围里面,再加上0x30,那么这个范围就变成了0x30~0x3A-1,对应的ASCII码就是数字0到数字9,这样就保证用户的注册码只能包含数字来了。注册机源码本来想用python写的,可是对于位操作不太熟悉,所以就用C语言写了一个。 [C] 纯文本查看 复制代码
(5.2 KB, 下载次数: 25) |

浙公网安备 33010602011771号