新手破解练习Crackme160之143 - tc.9
-
解锁
IDR反编译查看解锁码的事件可得, 解锁码为: "CrackMe [id:9] by tC... ." (不包括双引号), 最后还得多输入任意一位才会成功 -
用户名注册码
也是IDR直接看事件源码
Unit1::TForm1.Register1Click
00444754 push ebp
00444755 mov ebp,esp
00444757 push 0
00444759 push 0
0044475B push 0
0044475D push ebx
0044475E push esi
0044475F push edi
00444760 mov esi,eax
00444762 xor eax,eax
00444764 push ebp
00444765 push 4448C3
0044476A push dword ptr fs:[eax]
0044476D mov dword ptr fs:[eax],esp
00444770 lea edx,[ebp-8]
00444773 mov eax,dword ptr [esi+2CC]; TForm1.Edit3:TEdit
00444779 call TControl.GetText
0044477E mov edx,dword ptr [ebp-8]
00444781 mov eax,446868; gvar_00446868:AnsiString
00444786 call @LStrAsg
0044478B lea edx,[ebp-8]
0044478E mov eax,dword ptr [esi+2C8]; TForm1.Edit2:TEdit
00444794 call TControl.GetText
00444799 mov eax,dword ptr [ebp-8]
0044479C call @LStrLen
004447A1 cmp eax,5 ;;;;; 5位以上
>004447A4 jl 004448A5
004447AA xor eax,eax
004447AC mov [00446894],eax; gvar_00446894
004447B1 xor eax,eax
004447B3 mov [00446898],eax; gvar_00446898
004447B8 lea edx,[ebp-8]
004447BB mov eax,dword ptr [esi+2C8]; TForm1.Edit2:TEdit
004447C1 call TControl.GetText
004447C6 mov eax,dword ptr [ebp-8]
004447C9 call @LStrLen
004447CE mov [00446854],eax; gvar_00446854:Longint ;;;;;;长度存起来
004447D3 lea edx,[ebp-8]
004447D6 mov eax,dword ptr [esi+2C8]; TForm1.Edit2:TEdit
004447DC call TControl.GetText
004447E1 mov eax,dword ptr [ebp-8]
004447E4 call @LStrLen
004447E9 mov edi,eax
004447EB test edi,edi
>004447ED jle 00444848
004447EF mov dword ptr [ebp-4],1 ;;;;;;;;;;;算法开始
004447F6 mov ebx,446870; gvar_00446870:Integer
004447FB lea edx,[ebp-8]
004447FE mov eax,dword ptr [esi+2C8]; TForm1.Edit2:TEdit
00444804 call TControl.GetText
00444809 mov eax,dword ptr [ebp-8]
0044480C mov edx,dword ptr [ebp-4]
0044480F mov al,byte ptr [eax+edx-1]
00444813 xor al,3
00444815 mov byte ptr [ebx],al
00444817 xor eax,eax
00444819 mov al,byte ptr [ebx]
0044481B mov edx,dword ptr ds:[446894]; gvar_00446894 ;;;;;;这几行需要读内存值,所以需要OD跟踪
00444821 add edx,edx
00444823 add eax,edx
00444825 mov [00446894],eax; gvar_00446894
0044482A mov al,[00446870]; gvar_00446870:Integer
0044482F imul byte ptr ds:[446854]; gvar_00446854:Longint
00444835 add byte ptr [ebx],al
00444837 xor eax,eax
00444839 mov al,byte ptr [ebx]
0044483B add dword ptr ds:[446898],eax; gvar_00446898
00444841 inc dword ptr [ebp-4]
00444844 inc ebx
00444845 dec edi
<00444846 jne 004447FB
00444848 call 00444460
0044484D call 00444670 ;;;;;;;;;;;;算法结束
00444852 mov eax,[00446850]; gvar_00446850
00444857 cmp eax,dword ptr ds:[446854]; gvar_00446854:Longint ;;;;;;对比
>0044485D jne 004448A5
0044485F lea edx,[ebp-8]
00444862 mov eax,dword ptr [esi+2C8]; TForm1.Edit2:TEdit
00444868 call TControl.GetText
0044486D mov ecx,dword ptr [ebp-8]
00444870 lea eax,[ebp-0C]
00444873 mov edx,4448DC; 'Registered to: '
00444878 call @LStrCat3
0044487D mov edx,dword ptr [ebp-0C]
00444880 mov eax,dword ptr [esi+2F0]; TForm1.StatusBar1:TStatusBar
00444886 call TStatusBar.SetSimpleText
0044488B xor edx,edx
0044488D mov eax,dword ptr [esi+2C8]; TForm1.Edit2:TEdit
00444893 mov ecx,dword ptr [eax]
00444895 call dword ptr [ecx+60]; TControl.SetEnabled
00444898 xor edx,edx
0044489A mov eax,dword ptr [esi+2CC]; TForm1.Edit3:TEdit
004448A0 mov ecx,dword ptr [eax]
004448A2 call dword ptr [ecx+60]; TControl.SetEnabled
004448A5 xor eax,eax
004448A7 pop edx
004448A8 pop ecx
004448A9 pop ecx
004448AA mov dword ptr fs:[eax],edx
004448AD push 4448CA
004448B2 lea eax,[ebp-0C]
004448B5 call @LStrClr
004448BA lea eax,[ebp-8]
004448BD call @LStrClr
004448C2 ret
<004448C3 jmp @HandleFinally
<004448C8 jmp 004448B2
004448CA pop edi
004448CB pop esi
004448CC pop ebx
004448CD mov esp,ebp
004448CF pop ebp
004448D0 ret
中间算法有一堆的计算, 需要很认真的一步步跟进去, 跟套娃一样, 一层套一层, 中间虚虚实实, 有些是没用的, 分析步骤如下:
1). 004447FB ~ 00444846 循环用户名得到一个5位的字符串(内存00446870处) 和 2个数值([00446894] 和 [00446898])
2). 004444848 这个子方法中, 00444497 ~ 004444B 修正上面的5位串并计算到到新的1个数值([00446890]), 004444E5 ~ 0044450B 计算得到新的1个数值([0044689C]),
3). 0044484D 这个子方法中, 00444691 ~ 004446FE 这13次循环组装了8个字符串(应该有其中5个是重复的地址)不知道干嘛用的, 没整明白,第1个数和第4个数分别拼上65A 和 H3, 中间两个数也作了些运算, 组装结果类似于: 127565A-3023-815-FFFFD847H3, 组装好后都存在了内存中032F7D8附近, 组装完, 又进入一个子方法(00444700), F7进入, 00444575 ~ 004445FF 循环8次判断 前面组装的串是否等于输入的注册码[edi], 循环到第6次时, 程序进到另一分支(这才是真正组装正确注册码串的地方), 004445C2这里就是正确串组装好后的地方, 此处即可追码拿到正确的注册码, 与输入串对比成功后(004445CC), 将用户名的长度[00446854]赋值给[00446850] (004445D3处), 然后继续无效循环, 结束后, 再来5次无效循环, 这些循环每个都像真正的算法, 让你必须认认真真的单步跟踪, 好心累, 到这里这个子方法就结束了
4). 一路F8返回到主方法00444852处, 对比[00446854]与[00446850]这两个内存值是否相等(可见得上一步第6次循环的关键性), 相等则提示注册成功, 否则就没任何提示结束~
算法分析完了, 下面是注册机代码:
#include <stdio.h>
#include <string.h>
int main() {
char user[21] = {0}; //用户名
unsigned char str[21] = {0}; //计算所得临时串
printf("用户名: "); scanf("%s", user);
int len = strlen(user);
if(len < 5){
printf("用户名5位以上");
return 0;
}
int s1 = 0, s2 = 0, s3 = 0;
unsigned int s4 = 0;
unsigned char al = 0, bl = 0;
for(int i=0; i<len; i++) {
al = user[i];
al ^= 3;
str[i] = al;
s1 = al + s1 * 2;
al = str[0] * len;
str[i] += al;
s2 += str[i];
}
for(int i=0; i<len; i++){ //00444848 call 0044460
str[i] += i + 1 + 4;
s3 = str[i] + s3 * 2;
}
s4 = s1 + s2 - s3 * (len - 2);
printf("注册码: %X-%d-%d-%X\n", s3, s1, s2, s4);
getchar();getchar();
return 0;
}
运行示例:
用户名: abcde
注册码: 1275-3036-970-FFFFD847
1~160每个破解过程,在吾爱破解论坛都有高手破解过了,也有整理好现成的, 我这边主要就是自己动手操作的过程,与他们的不太一样
附上高手们的连接: 点击前往查看
使用的工具连接(工具有点多有点大,可以先下OD,其它的后面慢慢下) 点击前往下载
新人入门教程"玩玩破解,写给新人看" 点击前往查看
我就是从这里开始的,对我这样的小白感觉超级友好~
下面是我的OD的界面布局,我觉得这4个是最常用的界面,其它的我基本上没用到~


浙公网安备 33010602011771号