首页
社区
课程
招聘
CRACKME破解分析(简单的逆推练习)
发表于: 2006-10-4 13:11 11637

CRACKME破解分析(简单的逆推练习)

2006-10-4 13:11
11637

【破文标题】CRACKME破解分析
【破文作者】逍遥风
【破解工具】OD, 计算器
【破解平台】WINXP
【破解声明】菜鸟偶得一点心得,与大家分享
----------------------------------------------------------------------

ACG'S CRACKME
简单的CRACKME练习.主要练习逆推出注册码

这个CRACKME的主要验证过程是

F(注册名)+G(注册码) = 定值.

用OD载入这个CRACKME,根据字符串提示信息很容易找到关键代码

来到关键代码处

0040124C   .  6A 28         PUSH 28                            ; /Count = 28 (40.)
0040124E   .  68 06214000   PUSH crcme1.00402106               ; |Buffer = crcme1.00402106
00401253   .  68 E9030000   PUSH 3E9                           ; |ControlID = 3E9 (1001.)
00401258   .  FF75 08       PUSH DWORD PTR SS:[EBP+8]          ; |hWnd
0040125B   .  E8 10020000   CALL <JMP.&USER32.GetDlgItemTextA> ; \GetDlgItemTextA
00401260   .  83F8 05       CMP EAX,5                          ;  注册名位数与5比较
00401263   .  0F82 BD000000 JB crcme1.00401326                 ;  小于5位就跳向失败

注册名位数不得小于5位

00401269   .  6A 28         PUSH 28                            ; /Count = 28 (40.)
0040126B   .  68 2E214000   PUSH crcme1.0040212E               ; |Buffer = crcme1.0040212E
00401270   .  68 EA030000   PUSH 3EA                           ; |ControlID = 3EA (1002.)
00401275   .  FF75 08       PUSH DWORD PTR SS:[EBP+8]          ; |hWnd
00401278   .  E8 F3010000   CALL <JMP.&USER32.GetDlgItemTextA> ; \GetDlgItemTextA
0040127D   .  BF 06214000   MOV EDI,crcme1.00402106            ;  取输入的注册码
00401282   .  33DB          XOR EBX,EBX                        ;  EBX清零
00401284   .  33C0          XOR EAX,EAX                        ;  EAX清零
00401286   >  8A1F          MOV BL,BYTE PTR DS:[EDI]           ;  取注册名每一位的ASCII码
00401288   .  80FB 20       CMP BL,20                          ;  格式验证
0040128B   .  0F82 95000000 JB crcme1.00401326
00401291   .  03C3          ADD EAX,EBX                        ;  注册名每一位的 ASCII码累加
00401293   .  47            INC EDI                            ;  每计算一次EDI中的值加1
00401294   .  803F 00       CMP BYTE PTR DS:[EDI],0            ;  累加完了吗
00401297   .^ 75 ED         JNZ SHORT crcme1.00401286          ;  循环计算

将注册名的每一位进行累加计算
例如:
注册名lovetc, 对应的累加结果就是28D

00401299   .  C1C0 03       ROL EAX,3                          ;  累加的结果设为A,ROL(A,3)得到B
0040129C   .  35 A5150500   XOR EAX,515A5                      ;  XOR(B,0x515A5),得到的结果设为C

到这里对注册名的计算就完成了.

对注册名的计算步骤是:

1)将注册名的每一位进行累加
2)ROL(累加结果,3),得到B
3) 将B与定值0x515A5进行XOR运算,得到最后结果C

004012A1   .  50            PUSH EAX
004012A2   .  33C0          XOR EAX,EAX
004012A4   .  33DB          XOR EBX,EBX
004012A6   .  33FF          XOR EDI,EDI                        ;  个寄存器清零
004012A8   .  BE 2E214000   MOV ESI,crcme1.0040212E            ;  使ESI等于输入的注册码
004012AD   >  B8 0A000000   MOV EAX,0A                         ;  令EAX等于定值0xA
作者:逍遥风
004012B2   .  8A1E          MOV BL,BYTE PTR DS:[ESI]           ;  取注册码的每一位进行转换
004012B4   .  85DB          TEST EBX,EBX
004012B6   .  74 15         JE SHORT crcme1.004012CD
004012B8   .  80FB 30       CMP BL,30                          ;  格式验证
004012BB   .  72 69         JB SHORT crcme1.00401326
004012BD   .  80FB 39       CMP BL,39                          ;  格式验证
004012C0   .  7F 64         JG SHORT crcme1.00401326
004012C2   .  83EB 30       SUB EBX,30
004012C5   .  0FAFF8        IMUL EDI,EAX
004012C8   .  03FB          ADD EDI,EBX
004012CA   .  46            INC ESI
004012CB   .^ EB E0         JMP SHORT crcme1.004012AD          ;  循环计算

在注意这里,这个循环的作用是将输入的注册码转换成对应的16进制形式

004012CD   >  81F7 CA870000 XOR EDI,87CA                       ;  XOR(注册码的16进制,0x87CA),得到的结果设为D
004012D3   .  8BDF          MOV EBX,EDI

以上代码是对输入的注册码进行的计算.

主要步骤是将注册码的16进制与定值0x87CA)进行XOR运算

004012D5   .  58            POP EAX
004012D6   .  03C3          ADD EAX,EBX                        ;  将注册名和注册码的计算结果相加,得到的和设为E

将注册名的计算结果与注册码的计算结果相加

004012D8   .  35 E7970700   XOR EAX,797E7                      ;  XOR(E,0x797E7)
004012DD   .  85C0          TEST EAX,EAX                       ;  检验是否等于零

从这里可以得知,最后的计算结果必须等于0x797E7
就是说:
F (注册名) + G (注册码) = 定值0x797E7

004012DF   .  75 45         JNZ SHORT crcme1.00401326          ;  不等于零就跳向失败
004012E1   .  6A 00         PUSH 0                             ; /Style = MB_OK|MB_APPLMODAL
004012E3   .  68 1B204000   PUSH crcme1.0040201B               ; |-=acg=- t h e   b e s t -=acg=-
004012E8   .  68 77204000   PUSH crcme1.00402077               ; |Text = "Yeah You Did It!!!
Czyli nareszczie ci si?uda筹
Teraz mo垮sz przy彻czy?si?do ACG"
004012ED   .  FF75 08       PUSH DWORD PTR SS:[EBP+8]          ; |hOwner
004012F0   .  E8 5D010000   CALL <JMP.&USER32.MessageBoxA>     ; \MessageBoxA

----------------------------------------------------------------------
算法总结:
由于注册信息必须满足
F(注册名) + G(注册码) = 定值
所以要进行逆推.已知定值等于0x797E7

很容易得出:G(注册码) = 定值0x797E7 - F(注册名)

根据分析的结论,以注册名lovetc为例,
F(注册名) = 0x501CD
所以: G(注册码) = 定值0x797E7 - F(注册名) = 0x797E7 -  0x501CD = 0x296EA

因为
G(注册码) = XOR(注册码的16进制,0x87CA),

所以:注册码的16进制就等于XOR(0x296EA,0x87CA)
即::注册码的16进制 = XOR(0x296EA,0x87CA)  = 211D0

所以注册码就应该等于135632

注册名:lovetc
注册码:135632

----------------------------------------------------------------------
【版权声明】本文只为交流,转载请保留作者及文章完整


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

上传的附件:
收藏
免费 7
支持
分享
最新回复 (13)
雪    币: 263
活跃值: (10)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
2
完全不懂,看都不会看。。。。。。 不过要支持一下
2006-10-4 15:27
0
雪    币: 256
活跃值: (10)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
3
又见到逍遥风出手了!!!!
对照注释,简单的跟了一遍
感觉讲的思路清晰,
只不过算法可能略为简单一些,
但是很适合我这样的菜鸟学习,
提出的逆向的算法,其实就是
解线性方程.逍遥风给出的就是
一种思想.
2006-10-5 10:46
0
雪    币: 174
活跃值: (10)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
4
好,逍兄弟的crackme越来越详细了,国庆了,也不休息。支持一下。
2006-10-5 13:04
0
雪    币: 177
活跃值: (40)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
5
跟了一下,用perl写了个注册机,不过算法确实简单了些

#!/usr/local/bin/perl

chomp($_=<>);

@ascii_array = unpack("C*", $_);
(@ascii_array >= 5) or die "Please enter at least 5 characters\n";

foreach $asc (@ascii_array) {
    $user += $asc;
}
$user = ($user * 8) ^ 0x515a5;

$inv = (0x797e7 - $user) ^ 0x87ca;
print "key:$inv\n";
2006-10-5 22:48
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
很详细阿
不过很适合我这个新手了
2006-10-9 13:23
0
雪    币: 309
活跃值: (15)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
7
哈哈~~
这个偶喜欢~~
逍遥兄,你在哪里找的啊??
给偶介绍下~~~
2006-10-11 20:09
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
能看懂,,但不是不懂下断点,,找不到关嫔代码...
2006-10-13 10:57
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9

function intStrToHex(str:string):integer;
var
  i,sum:Integer;

begin
sum:=0;
for i:=1 to length(str) do
sum:=sum+ord(str[i]);
result :=(497639- ((sum shl 3) xor 333221 )) xor 34762
//result:=IntToHex(sum,2);
end;

edit2.Text:=IntToStr( intStrToHex(edit1.Text));
2006-10-13 12:37
0
雪    币: 209
活跃值: (40)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
该crackme一开始还有个验证keyfile的操作, 比较隐蔽,只有验证成功才有提示
00401000 >/$  6A 00         push    0                                ; /hTemplateFile = NULL
00401002  |.  68 80000000   push    80                               ; |Attributes = NORMAL
00401007  |.  6A 03         push    3                                ; |Mode = OPEN_EXISTING
00401009  |.  6A 00         push    0                                ; |pSecurity = NULL
0040100B  |.  6A 00         push    0                                ; |ShareMode = 0
0040100D  |.  68 00000080   push    80000000                         ; |Access = GENERIC_READ
00401012  |.  68 6B234000   push    0040236B                         ; |FileName = "ACG.key"
00401017  |.  E8 84040000   call    <jmp.&KERNEL32.CreateFileA>      ; \CreateFileA
0040101C  |.  83F8 FF       cmp     eax, -1                          ;  由上可知keyfile名叫"ACG.key"
0040101F  |.  0F84 59010000 je      0040117E
00401025  |.  A3 73234000   mov     [402373], eax
0040102A  |.  6A 00         push    0                                ; /pFileSizeHigh = NULL
0040102C  |.  FF35 73234000 push    dword ptr [402373]               ; |hFile = NULL
00401032  |.  E8 51040000   call    <jmp.&KERNEL32.GetFileSize>      ; \GetFileSize
00401037  |.  83F8 0C       cmp     eax, 0C                          ;  keyfile文件长0C个字节
0040103A  |.  0F85 3E010000 jnz     0040117E
00401040  |.  6A 0C         push    0C                               ; /MemSize = C (12.)
00401042  |.  6A 00         push    0                                ; |Flags = GMEM_FIXED
00401044  |.  E8 39040000   call    <jmp.&KERNEL32.GlobalAlloc>      ; \GlobalAlloc
00401049  |.  A3 7B234000   mov     [40237B], eax
0040104E  |.  6A 00         push    0                                ; /pOverlapped = NULL
00401050  |.  68 77234000   push    00402377                         ; |pBytesRead = crcme1.00402377
00401055  |.  6A 0C         push    0C                               ; |BytesToRead = C (12.)
00401057  |.  FF35 7B234000 push    dword ptr [40237B]               ; |Buffer = NULL
0040105D  |.  FF35 73234000 push    dword ptr [402373]               ; |hFile = NULL
00401063  |.  E8 14040000   call    <jmp.&KERNEL32.ReadFile>         ; \ReadFile

00401068  |.  8B3D 7B234000 mov     edi, [40237B]
edi指向从ACG.key文件读取的字符串指针的首地址
0040106E  |.  33DB          xor     ebx, ebx
00401070  |.  8A1F          mov     bl, [edi]
取该字符串的字符,bl当前指向的是第一个字符
00401072  |.  80F3 1B       xor     bl, 1B
00401075  |.  C1C3 02       rol     ebx, 2
00401078  |.  81F3 68010000 xor     ebx, 168
0040107E  |.  85DB          test    ebx, ebx
00401080  |.  0F85 F8000000 jnz     0040117E                         ;  跳就验证keyfile失败

00401080  |.  0F85 F8000000 jnz     0040117E                         ;  跳就验证keyfile失败
jnz就失败,可见
0040107E  |.  85DB          test    ebx, ebx
的值必须为0,所以
00401078  |.  81F3 68010000 xor     ebx, 168
就可以推导出此时ebx值为168,只有168 xor 168 = 0,继续向上逆推
00401075  |.  C1C3 02       rol     ebx, 2
ebx << 2 = 168H,所以ebx = 168H >> 2 =168H /4 = 5A,请不要忘记这里的数字都是16进制的
00401072  |.  80F3 1B       xor     bl, 1B
bl xor 1B = 5A => bl  = 5A xor 1B => bl = 41H,41H对应的ASCII码是字母'A',所以keyfile的第一个字符为'A',同理可以推导出其它字符,最后得到keyfile的内容为"ACG The Best",哈王婆卖瓜呐,保存为ACG.key,重新运行程序,哈,看到提示了吧“Key File OK teraz tylko Name/Serial!”
2006-10-14 03:00
0
雪    币: 709
活跃值: (2420)
能力值: ( LV12,RANK:1010 )
在线值:
发帖
回帖
粉丝
11
写出来真的不错啊...
看了很感触.
2006-10-19 21:56
0
雪    币: 235
活跃值: (12)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
12
用汇编写了一个注册机,因为没有上传权限,所以把代码放上来了!
.386
.Model Flat, StdCall
Option Casemap :None

Include windows.inc
Include user32.inc
Include kernel32.inc
IncludeLib user32.lib
IncludeLib kernel32.lib

IDD_DIALOG     equ          101
IDC_EDIT1      equ          1000
IDC_EDIT2      equ          1001
IDC_STATIC     equ           -1
.DATA?
   hInstance        dd                      ?
        username           db  20 dup (?)
        xuliehao    db  20 dup (?)
.CODE
_ProcDlgMain        proc        uses ebx edi esi hWnd,wMsg,wParam,lParam

                mov        eax,wMsg
                .if        eax == WM_CLOSE
                        invoke        EndDialog,hWnd,NULL
                .elseif        eax == WM_COMMAND
                        mov        eax,wParam
                        .if        ax == IDOK
                                invoke   GetDlgItemText,hWnd,IDC_EDIT2,addr xuliehao,sizeof xuliehao
                     mov esi,offset xuliehao
                     mov edi,offset username
                     mov ebx,eax
                     sal eax,1
                     mov edx,eax
                     mov ecx,ebx
                  a:
                     mov al,BYTE ptr [esi]
                     sub al,dl
                     mov BYTE ptr [edi],al
                     inc esi
                                                        inc edi
                                                        loop a
                                                        mov esi,offset xuliehao
                                                        mov edi,offset username
                                                        mov ecx,ebx
                                                        sar ebx,1
                                                        mov dl,BYTE ptr [esi+ebx]
                                                        mov bl,dl
                                                        sub bl,'A'
                                                b:
                                                        xor BYTE ptr [edi],bl
                                                        xor BYTE ptr [edi],dl
                                                        mov al,BYTE ptr [esi]
                                                        xor BYTE ptr [edi],al
                                                        inc esi
                                                        inc edi
                                                        loop b
                                invoke        SetDlgItemText,hWnd,IDC_EDIT1,addr username
                        .endif
                .else
                        mov        eax,FALSE
                        ret
                .endif
                mov        eax,TRUE
                ret

_ProcDlgMain        endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
start:
                invoke        GetModuleHandle,NULL
                mov        hInstance,eax
                invoke        DialogBoxParam,hInstance,IDD_DIALOG,NULL,offset _ProcDlgMain,NULL
                invoke        ExitProcess,NULL
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                end        start
2006-10-20 18:59
0
雪    币: 405
活跃值: (10)
能力值: ( LV9,RANK:1130 )
在线值:
发帖
回帖
粉丝
13
易语言注册机代码:

.版本 2

name = 编辑框1.内容
len = 取文本长度 (编辑框1.内容)

.计次循环首 (len, i)
    sum = sum + 取代码 (name, i)
    eax = 左移 (sum, 3)
    eax = 位异或 (eax, 333221)
    eax = 497639 - eax
.计次循环尾 ()
snzuizhong = 位异或 (eax, 34762)
编辑框2.内容 = 到文本 (snzuizhong)
2006-10-22 14:39
0
雪    币: 224
活跃值: (10)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
14
哇噻噻……

高人真是太多了呀………………

谢谢楼主了撒~

学习……

2006-11-7 17:09
0
游客
登录 | 注册 方可回帖
返回
//