【CrackMe】160道CrackMe--001 Acid burn 做完这160个练习题,90%的软件你就能搞定了

160道题目网盘链接

链接:https://pan.baidu.com/s/15bqvffOLM6V5bff98DkT6w
提取码:3hc6

据说做完这160个练习题,90%的软件你都能搞定了,我也不清楚哈,也是才开始练习。
今天写的是第一道题,比较简单,但因为是第一次做,也是有点磕磕绊绊,所以过程会写的很详细,加深理解。
【CrackMe】160道CrackMe--001 Acid burn 做完这160个练习题,90%的软件你就能搞定了
这道题属于Name\Serial类型的题,即根据你输入的Name可以理解为账号,进行一些运算,然后得到Serial可以理解为注册序列号,然后和自己输入的Serial进行比较,相同则成功,如果写注册机的话就需要在程序获取Name的时候分析它的算法过程。

两种验证方式

先打开CrackMe熟悉下功能,我们发现该程序有两种验证方式

直接验证你输入的序列号跟在程序中的原本保存的序列号序列号
【CrackMe】160道CrackMe--001 Acid burn 做完这160个练习题,90%的软件你就能搞定了

自己输入Name,根据输入的Name经过运算生成的序列号和输入的序列号比较,相同则成功。
【CrackMe】160道CrackMe--001 Acid burn 做完这160个练习题,90%的软件你就能搞定了

第一种Serial

拖进OD,运行程序,很明显这个错误弹窗是一个MessageBox的弹窗,直接Ctrl+G搜索MessageBoxA,这种老程序一般使用的是单字节版本也就是MessageBoxA

【CrackMe】160道CrackMe--001 Acid burn 做完这160个练习题,90%的软件你就能搞定了

在此处下断点,随便输入一个数123456尝试一下,发现程序在此断下,我们开始单步走一下看看有什么有用信息,不可能性不大,这只是个标准的MessageBox,也没有重写。

【CrackMe】160道CrackMe--001 Acid burn 做完这160个练习题,90%的软件你就能搞定了

果然没有发现什么有用的东西,走出MessageBox看看是谁调用了它

【CrackMe】160道CrackMe--001 Acid burn 做完这160个练习题,90%的软件你就能搞定了

跳出MessageBox任然没有发现什么有价值的信息,但当我们往下翻堆栈的时候,发现在调用我们当前位置的函数的函数的函数已将我们输入的“123456”取出来并当作参数压入栈中了

【CrackMe】160道CrackMe--001 Acid burn 做完这160个练习题,90%的软件你就能搞定了
箭头指向的堆栈所代表的函数才是真正调用这个错误信息框的函数
【CrackMe】160道CrackMe--001 Acid burn 做完这160个练习题,90%的软件你就能搞定了

现在我们就明确目标了,找出已将我们输入123456取出的函数的位置,即这个真正调用我们这个消息框的函数,因为既然取出了我们的输入,那么大概率就要进行验证了,不断单步走,走到该函数为止。

【CrackMe】160道CrackMe--001 Acid burn 做完这160个练习题,90%的软件你就能搞定了
并且这时候我们发现,还出现了不同于错误提示消息的字符,并且还有一个大跳转。
【CrackMe】160道CrackMe--001 Acid burn 做完这160个练习题,90%的软件你就能搞定了
那么这个大跳转上面的这个CALL很有可能就是判断输入的Serial是否正确的函数了

0042F4EA  |.  E8 81ACFFFF   call    0042A170

我们直接往上翻,拉到这个函数开始扩展栈空间即函数开始的位置,在这个位置上下断点

【CrackMe】160道CrackMe--001 Acid burn 做完这160个练习题,90%的软件你就能搞定了

F9运行程序,在此输入123456,发现程序在此断下我们开始逐行分析
发现运行到如下指令取得用户输入
CALL 0041AA58
【CrackMe】160道CrackMe--001 Acid burn 做完这160个练习题,90%的软件你就能搞定了

调试到之前所说的猜测是判断用户输入的CALL函数前我们发现这是个Fastcall规范的函数即通过寄存器传递参数
通过寄存器EAX和EDX传递了两个参数一个是我们输入的"123456" 还有一个是"Hello Dude!"
这个Hello Dude!很有可能就是Serial
【CrackMe】160道CrackMe--001 Acid burn 做完这160个练习题,90%的软件你就能搞定了
我们进入到函数内部看一下,可以看到该CMP就是比较用户输入是否等于"Hello Dude!“的。
【CrackMe】160道CrackMe--001 Acid burn 做完这160个练习题,90%的软件你就能搞定了
再结合上面的分析我们可以肯定Serial就是"Hello Dude!”。等于则提示God Job dude! 不等于则提示Try Again!
【CrackMe】160道CrackMe--001 Acid burn 做完这160个练习题,90%的软件你就能搞定了

验证是否成功

【CrackMe】160道CrackMe--001 Acid burn 做完这160个练习题,90%的软件你就能搞定了

第二种Name/Serial

这次我们要编写注册机
也是在MessageBoxA函数下断点,输入Name输入123456,Serial输入789 ,进行尝试

【CrackMe】160道CrackMe--001 Acid burn 做完这160个练习题,90%的软件你就能搞定了
同样的走出MessageBox查看是谁调用了他
【CrackMe】160道CrackMe--001 Acid burn 做完这160个练习题,90%的软件你就能搞定了
还是将堆栈往下翻一下,我们又发现我们输入的123456和789以及被取出了还有一些字符串也在堆栈中,
【CrackMe】160道CrackMe--001 Acid burn 做完这160个练习题,90%的软件你就能搞定了
同样的,不断步过到达该函数,又看到了我们熟悉的字段
【CrackMe】160道CrackMe--001 Acid burn 做完这160个练习题,90%的软件你就能搞定了
老样子在该函数开始处下断点,F9运行开始分析
【CrackMe】160道CrackMe--001 Acid burn 做完这160个练习题,90%的软件你就能搞定了
发现也是通过CALL 0041A58取用户输入Name
【CrackMe】160道CrackMe--001 Acid burn 做完这160个练习题,90%的软件你就能搞定了
不断往下走,这有个判断是否大于等于四位的条件
【CrackMe】160道CrackMe--001 Acid burn 做完这160个练习题,90%的软件你就能搞定了
开始取用户输入的序列号
【CrackMe】160道CrackMe--001 Acid burn 做完这160个练习题,90%的软件你就能搞定了

又来到了熟悉的比较函数,这里发现之前发现的CW-XXXX的字符串就是程序根据用户输入的Name进行运算后生成的序列号
【CrackMe】160道CrackMe--001 Acid burn 做完这160个练习题,90%的软件你就能搞定了
进入该函数查看,发现果然如此
【CrackMe】160道CrackMe--001 Acid burn 做完这160个练习题,90%的软件你就能搞定了
我们这里直接修改下ZF标志位让其相等验证所说是否正确
【CrackMe】160道CrackMe--001 Acid burn 做完这160个练习题,90%的软件你就能搞定了
发现修改后果然提示正确
【CrackMe】160道CrackMe--001 Acid burn 做完这160个练习题,90%的软件你就能搞定了

开始编写注册机

经过多次试验发现注册码规律为CW-XXXX-CRACKED是有 “CW-“前缀和”-CRACKED后缀”,因此我们只需要判断中间的XXXX是怎么来的就行了
重新加载一下

0042FA57  |.  83F8 04       cmp     eax, 4                           ;  判断用户输入是否大于或等于四位
0042FA5A  |.  7D 1D         jge     short 0042FA79
0042FA5C  |.  6A 00         push    0
0042FA5E  |.  B9 74FB4200   mov     ecx, 0042FB74                    ;  ASCII "Try Again!"
0042FA63  |.  BA 80FB4200   mov     edx, 0042FB80                    ;  ASCII "Sorry , The serial is incorect !"
0042FA68  |.  A1 480A4300   mov     eax, dword ptr [430A48]
0042FA6D  |.  8B00          mov     eax, dword ptr [eax]
0042FA6F  |.  E8 FCA6FFFF   call    0042A170
0042FA74      E9 BE000000   jmp     0042FB37
0042FA79  |>  8D55 F0       lea     edx, [local.4]
0042FA7C  |.  8B83 DC010000 mov     eax, dword ptr [ebx+1DC]
0042FA82  |.  E8 D1AFFEFF   call    0041AA58
0042FA87  |.  8B45 F0       mov     eax, [local.4]                   ;  EAX=11223344
0042FA8A  |.  0FB600        movzx   eax, byte ptr [eax]              ;  取11223344第一个字节 ASCII '1'=0x31 EAX=0X31
0042FA8D  |.  F72D 50174300 imul    dword ptr [431750]               ;  有符号乘法 [431750]=0x29
0042FA93  |.  A3 50174300   mov     dword ptr [431750], eax          ;  EAX=0X31*0X29=0X7D9
0042FA98  |.  A1 50174300   mov     eax, dword ptr [431750]          ;  再把结果取出来
0042FA9D  |.  0105 50174300 add     dword ptr [431750], eax          ;  再相加 [431750]=0X7D9+0X7D9=0XFB2
0042FAA3  |.  8D45 FC       lea     eax, [local.1]
0042FAA6  |.  BA ACFB4200   mov     edx, 0042FBAC                    ;  ASCII "CW" 前缀
0042FAAB  |.  E8 583CFDFF   call    00403708
0042FAB0  |.  8D45 F8       lea     eax, [local.2]
0042FAB3  |.  BA B8FB4200   mov     edx, 0042FBB8                    ;  ASCII "CRACKED"
0042FAB8  |.  E8 4B3CFDFF   call    00403708
0042FABD  |.  FF75 FC       push    [local.1]
0042FAC0  |.  68 C8FB4200   push    0042FBC8
0042FAC5  |.  8D55 E8       lea     edx, [local.6]
0042FAC8  |.  A1 50174300   mov     eax, dword ptr [431750]
0042FACD  |.  E8 466CFDFF   call    00406718                         ;  生成注册码 将EAX的值转化为十进制并且将其转化为字符串
0042FAD2  |.  FF75 E8       push    [local.6]                        ;  4018


该CALL将计算完毕的[431750]中的值转化为十进制,并且以字符串的形式储存

0042FACD  |.  E8 466CFDFF   call    00406718       

【CrackMe】160道CrackMe--001 Acid burn 做完这160个练习题,90%的软件你就能搞定了

算法
1.判断用户输入Name是否大于等于四位数
2.去用户输入Name的第一个字符,将其乘与0x29
3.将相乘的结果再乘以2
4.将所得到的十六进制数字转化为十进制,再将其转化为字符串
5.拼接前缀和后缀

#include <cstdio>
#include <string>

#include <iostream>
using namespace std;
int main()
{
    cout << "请输入Name" << endl;
    int cName;
    string nameStr;
    cin >> nameStr;
    if (nameStr.length()<4)
    {
        cout << "请输入长度大于4的序列号" <<endl;
        return 0;
    }
    cName = nameStr[0];//只取第一个字符
    if (cName > 0x21) // 只处理可见字符
    {
        cName *= 0x29; // 乘法
        cName *= 2; // 自增一倍
        printf("Serial: CW-%4d-CRACKED\r\n", cName);
    }
    else {
        printf("input error!\r\n");
    }
    return 0;
}
上一篇:LeetCode-160-相交链表


下一篇:力扣:160. 相交链表