前言
这是160个CreakMe系列的第003个CM,难度:☆;(涉及浮点数运算)
这次这个浮点数直接进入我的知识盲区了,临时搜搜查查,算是大概弄懂了这个程序的序列号。
本次分析使用到的环境和工具如下:
- 操作系统:Windows 10 2004(物理机)
- 工具:x32dbg
- IDE:Visual Studio 2019
软件分析
跟上一个CM一样,是用户名+序列号的验证
那么这次的分析目标也是:实现验证的破解,以及分析出来序列号的算法
分析目标1:暴力破解
这个的暴力破解跟上一个一样,查找字符串,然后把跳转给修改了
je改成了jne或者nop即可
分析目标2:注册机
之前分析了一大堆没分析出来,看了大佬们的题解,仿佛懂了什么,现在重新来分析
VB反汇编常见函数功能:https://www.cnblogs.com/bbdxf/p/3780187.html
因为这个程序和上一个很相似,至少算得第一个数字的过程是一样的,所以我们从导入函数计算字符串长度的那个call开始往下分析
刚开始这一块跟上一个程序是一样的,获取字符串长度,长度*一个数+首字母ascii值,然后十六进制转十进制
用户名abc,那第一个数字算出来是266761
我前面犯的一个错,要知道这些函数只是实现一些功能,而加密的逻辑不在这些函数里面,不用往里面分析
然后往下步过,注意观察x32dbg右边提示的数字,如果出现了刚刚我们算的第一个数字,那就要注意了:
往下走一会,就遇到了一个要把这个数字入栈调用函数的地方,这里入栈了的一个是我们第一个数字,另一个是一个地址
通过查阅资料,vb程序反汇编函数__vbaR8str的功能是: 将一个字符串转为双精度单精度浮点型(8个字节)的数值形式
一路步过下去,一共看见过3个数字:266763,800287,800302,而这个800302就是正确的序列号,所以在此推测,这里面经过了三次运算,最后得到了正确的值,然后去分析这几个数字出现的地方吧:
这一块代码的主要内容是:
将266761转换成浮点型,存储在st(0)里,然后进行一个判断,这里判断是不跳转,所以浮点数10.0/5.0=2.0,也堆到st里,然后st1和st0相加,变成266763了,然后又转换成了字符串
接着往下看:
第二段运算呢是,先把字符串变成浮点数,然后乘2.125,再减去2.0,得到800287
至于浮点数在内存中是怎么表示的,可以用这个网站来计算一下:
http://lostphp.com/hexconvert/
第三段计算
跟前两段差不多,这次是+15.0
这里是双精度浮点型,注意是双精度,用转换器要选择双精度的,不然算不出来!
http://www.binaryconvert.com/result_double.html?decimal=045049053
用这个转换器就行
到此计算已经完成了,序列号的生成已经很清楚了
算法是
((字符串长度*15B38+首字母ASCII码值)+2.0) * 3.0 - 2.0 + 15.0
我们手动算一个来验算一下:
用户名:abcd
序列号为:
4 * 0x15B38 + 0x61 = 0x56D41
0x56D41 = 355649
(355649.0 +2.0)*3.0 = 1066953.0
1066953.0 - 2.0 + 15.0 = 1066966
验证一下:
编写注册机
#include<stdio.h>
#include<windows.h>
int main() {
// 获取用户名
char username[MAXBYTE] = { 0 };
printf("请输入用户名:"); scanf_s("%s",username,MAXBYTE);
//计算序列号
char szbuffer[MAXBYTE] = { 0 };
int nSeries = (strlen(username) * 0x15B38 + username[0] + 2) * 3 + 13;
printf("序列号是:%d\r\n",nSeries);
system("pause");
return 0;
}
效果演示:
总结
这次的实践让我认识到了我对浮点数一无所知,要去补一下基础知识了
这次我学习到新的分析思路:不要钻到某个调用里,看主要的逻辑,看函数的功能,借助往上的资料来了解反汇编函数是干嘛的,遇到问题多看看大家是怎么做的,能让人学到新思路,不要一门心思自己钻研,要多去看看别人的分享!