15788888 发表于 2024-11-23 20:22

新手学破解记录贴【160个CrackMe】之004

本人刚刚入门汇编逆向破解分析,本帖将记录我对160个CrackMe程序中的第004程序的分析过程。在学习的过程中,我会边学边记录。如果有不正确之处,还请各位指正。


因为003程序我这里并不能正常运行 所以直接跳过003来分析一下004程序。

程序查壳是无壳的 Delphi语言编写的 。输入假码之后没有任何错误提示   只知道如果破解成功 下面的图片框会显示一幅图片。



首先还是查找字符串 看一下有没有什么有用的字符提示


字符串这里找到了一个注册成功 上面0x0045803B地址是关键跳转 会跳过注册成功的代码 我们把它nop掉,然后输入完用户名和密码点击图片框 就会直接爆破成功



已经爆破成功了 继续来研究一下他的注册码算法, 现在这个代码的头部下一个断点 然后来看一下汇编代码。
下图这串汇编代码 相当于 就把用户名的长度加0x5 得出来的十进制数值在和 用户名 和ebx寄存器值进行拼接,和下面的关键比较完全没有关系啊!!!
cmp dword ptr ds:,85      这行代码就是 esi+30的地址数值 如果等于0x85就注册成功,上面的汇编代码完全没有改变esi+30C里面的数值啊!!


关键点在于esi+30C的数值等于0x85 才可以,是哪里访问的esi+30C这个位置呢我们下一个硬件访问断点在重新注册试一下看。



下完这个断点之后我们发现 只要在注册码的文本框输入一个新的字符 就会断下来。




断下来之后我们发现了一个 字符串 “黑头Sun Bird15dseloffc-012-OKa123456789” 我测试了一下是正确的注册码 (经过测试发发现 输入完激活码需要双击才能注册成功 爆破的时候只需要单击就可以)
除了这个正确的激活码我们还发现了 有一个跳转 如果不成立就会给刚才注册的关键比较esi+0x30C的位置赋值,但是赋的值是0x3E 并不是0x85 (跟上面的双击有关 作者留的一个小坑 一会说)

现在已经知道了正确的注册码了 我们向上看 分析一下汇编代码。

第一部分 这部分代码实现了注册码的生成方式 首先 取用户名长度 然后加上0x5 得出来一个数值转成十进制 然后 进行拼接: 黑头Sun Bird&用户名长度&dseloffc-012-OK&用户名
拼接后的值为 黑头Sun Bird15dseloffc-012-OKa123456789这个也就是正确的注册码。


00457C43 | 51                        | push ecx                        |
00457C44 | B9 05000000               | mov ecx,5                         |
00457C49 | 6A 00                     | push 0                            |
00457C4B | 6A 00                     | push 0                            |
00457C4D | 49                        | dec ecx                           |
00457C4E | 75 F9                     | jne ckme.457C49                   | 循环5次push 0
00457C50 | 51                        | push ecx                        |
00457C51 | 874D FC                   | xchg dword ptr ss:,ecx   | :"13a1234567890"
00457C54 | 53                        | push ebx                        | ebx:&"鵀B"
00457C55 | 56                        | push esi                        |
00457C56 | 8BD8                      | mov ebx,eax                     | ebx:&"鵀B"
00457C58 | 33C0                      | xor eax,eax                     |
00457C5A | 55                        | push ebp                        |
00457C5B | 68 3D7E4500               | push ckme.457E3D                  |
00457C60 | 64:FF30                   | push dword ptr fs:         |
00457C63 | 64:8920                   | mov dword ptr fs:,esp      |
00457C66 | 8BB3 F8020000             | mov esi,dword ptr ds:    | 用户名长度
00457C6C | 83C6 05                   | add esi,5                         | 用户名长度+0x5
00457C6F | FFB3 10030000             | push dword ptr ds:       | :"黑头Sun Bird"
00457C75 | 8D55 F8                   | lea edx,dword ptr ss:      | :"15"
00457C78 | 8BC6                      | mov eax,esi                     |
00457C7A | E8 85FEFAFF               | call ckme.407B04                  | 用户名长度加0x5之后转成10进制字符
00457C7F | FF75 F8                   | push dword ptr ss:         | :"15"
00457C82 | FFB3 14030000             | push dword ptr ds:       | :"dseloffc-012-OK"
00457C88 | 8D55 F4                   | lea edx,dword ptr ss:      | :"a123456789"
00457C8B | 8B83 D4020000             | mov eax,dword ptr ds:    | :&"鵀B"
00457C91 | E8 B2B6FCFF               | call ckme.423348                  |
00457C96 | FF75 F4                   | push dword ptr ss:         | :"a123456789"
00457C99 | 8D83 18030000             | lea eax,dword ptr ds:    | :"黑头Sun Bird15dseloffc-012-OKa123456789"
00457C9F | BA 04000000               | mov edx,4                         |
00457CA4 | E8 93BFFAFF               | call ckme.403C3C                  | 拼接字符串 黑头Sun Bird&用户名长度&dseloffc-012-OK&用户名


第二部分:跟之前分析的基本一样 只不过是把用户名的长度加0x3 得出来的十进制数值在和 用户名 和esi寄存器值进行拼接循环19次,之前的和这部分汇编代码好像没什么作用。
00457CC9 | 8D55 EC                   | lea edx,dword ptr ss:   | :"a123456789"
00457CCC | 8B83 D4020000             | mov eax,dword ptr ds:    | :&"鵀B"
00457CD2 | E8 71B6FCFF               | call ckme.423348                  |
00457CD7 | 8B45 EC                   | mov eax,dword ptr ss:   | :"a123456789"
00457CDA | E8 9DBEFAFF               | call ckme.403B7C                  |
00457CDF | 83C0 03                   | add eax,3                         |
00457CE2 | 8D55 F0                   | lea edx,dword ptr ss:   | :"13"
00457CE5 | E8 1AFEFAFF               | call ckme.407B04                  |
00457CEA | FF75 F0                   | push dword ptr ss:      | :"13"
00457CED | 8D55 E8                   | lea edx,dword ptr ss:   | :"a123456789"
00457CF0 | 8B83 D4020000             | mov eax,dword ptr ds:    | :&"鵀B"
00457CF6 | E8 4DB6FCFF               | call ckme.423348                  |
00457CFB | FF75 E8                   | push dword ptr ss:      | :"a123456789"
00457CFE | 8D55 E4                   | lea edx,dword ptr ss:   |
00457D01 | 8BC6                      | mov eax,esi                     |
00457D03 | E8 FCFDFAFF               | call ckme.407B04                  |
00457D08 | FF75 E4                   | push dword ptr ss:      |
00457D0B | 8D45 FC                   | lea eax,dword ptr ss:      | :"13a1234567890"
00457D0E | BA 03000000               | mov edx,3                         |
00457D13 | E8 24BFFAFF               | call ckme.403C3C                  |
00457D18 | 46                        | inc esi                           |
00457D19 | 83FE 13                   | cmp esi,13                        |
00457D1C | 75 AB                     | jne ckme.457CC9                   | 循环19次

第三部分: 这部分代码主要就是看输入的激活码和生成的一致不一致,如果一致就会把 注册成功的关键地址esi+30C赋值0x3E。


00457D1E | 8D55 E0                   | lea edx,dword ptr ss:   |
00457D21 | 8B83 D8020000             | mov eax,dword ptr ds:    | :&"鵀B"
00457D27 | E8 1CB6FCFF               | call ckme.423348                  |
00457D2C | 8B45 E0                   | mov eax,dword ptr ss:   |
00457D2F | 8B93 18030000             | mov edx,dword ptr ds:    | :"黑头Sun Bird15dseloffc-012-OKa123456789"
00457D35 | E8 52BFFAFF               | call ckme.403C8C                  | 生成的激活码和输入的进行对比 然后决定下面的跳转是否赋值0x3E
00457D3A | 75 0A                     | jne ckme.457D46                   |
00457D3C | C783 0C030000 3E000000    | mov dword ptr ds:,3E   | 如果跳转不成立给注册成功关键对比的内存地址赋值3E
00457D46 | 8B83 0C030000             | mov eax,dword ptr ds:    |

通过上面这些代码有存在一个问题 就是激活码都已经一致了不应该赋值0x85注册才能成功吗 为什么赋值0x3E呢 这样赋值即便激活码输入对了那注册不还是不成功吗?
确实是这样的,这个也就是作者留的一个小小的坑,之前有说过 如果直接爆破 在图片框单击一下就可以注册成功, 如果输入正确的激活码那要双击才能成功,那由此就可以推断出来
点击图片框只会进行一个 ebx+0x30C 是否等于0x85的判断 相等就注册成功否则就不成功 所以直接爆破 把这个判断nop掉就会直接成功,如果要输入活码要双击才能成功 那就是在双击的时候 会触发一个把ebx+0x30C的值改变成0x85的一个动作,
既然要改变成0x85 那肯定在双击的时候还会访问这个内存地址,我们接着下一个硬件访问断点 然后输入正确的激活码双击看一下。


双击后断在了这个位置 结果很明显了, 如果 这个 ebx+0x30C = 0x3E 那就赋值0x85。



总结:注册码算法就是   “黑头Sun Bird”+用户名长度+ 0x5+“dseloffc-012-OK”+用户名   ,只要在文本输入框按下字符 就会检测一次激活码 如果激活码正确就会直接给esi+0x30c地址赋值0x3E 双击图片框后会 判断esi+0x30c地址的值是否为0x3E 如果是 在赋值0x85 这个时候在点击图片框 会判断这个地址的值是否是0x85 如果是那就注册成功。




注册机编写:
#include <iostream>
#include <string>
using namespace std;


int main()
{
    //获取输入字符串
    string str;
    cout << "请输入账号:" << endl;
    cin >> str;
    int len = str.length();
    int num = len + 0x5 ;

    string key = "黑头Sun Bird"+ to_string(num)+"dseloffc-012-OK"+ str;
    cout<< "您的注册key:" << key << endl;
    return 0;
}

zhang0201 发表于 2024-11-24 00:38

感谢分享

chx1126 发表于 2024-11-24 01:22

感谢分享思路

abandoncs 发表于 2024-11-24 03:10

思路是对的;www

asmprofan 发表于 2024-11-24 05:30

一起开启学习之路。

qing124A 发表于 2024-11-24 08:03

谢谢分享
页: [1]
查看完整版本: 新手学破解记录贴【160个CrackMe】之004