首页
社区
课程
招聘
郁闷中,拿个以为比较简单的小Crackme想出出气,谁知道还是一样郁闷
发表于: 2006-7-9 16:43 7556

郁闷中,拿个以为比较简单的小Crackme想出出气,谁知道还是一样郁闷

2006-7-9 16:43
7556

下载地址:http://www.crackmes.de/users/indomit/indokgm1

使用工具:OllyDbg

  一个用Delphi写的控制台程序,试注册,找提示字符串,然后用OD载入,
根据提示字符串定位到如下代码处:

//////////////  以下是代码  //////////////

00408695   .  E8 D6A4FFFF   call    00402B70                         ;  ReadLn
0040869A   .  A1 70934000   mov     eax, [409370]
0040869F   .  E8 38A5FFFF   call    00402BDC
004086A4   .  E8 839FFFFF   call    0040262C
004086A9   .  A1 98A74000   mov     eax, [40A798]
004086AE   .  E8 01B8FFFF   call    00403EB4                         ;  求长度
004086B3   .  8BD8          mov     ebx, eax
004086B5   .  83FB 04       cmp     ebx, 4                           ;  用户名必须输入4――16个字符
004086B8   .  7C 05         jl      short 004086BF
004086BA   .  83FB 10       cmp     ebx, 10
004086BD   .  7E 19         jle     short 004086D8
004086BF   >  A1 04934000   mov     eax, [409304]
004086C4   .  BA 00894000   mov     edx, 00408900                    ;  ASCII 0A,"<--! Plz, "
004086C9   .  E8 12BAFFFF   call    004040E0
004086CE   .  E8 21A7FFFF   call    00402DF4
004086D3   .  E8 549FFFFF   call    0040262C
004086D8   >  83FB 04       cmp     ebx, 4
004086DB   .^ 7C 95         jl      short 00408672
004086DD   .  83FB 10       cmp     ebx, 10
004086E0   .^ 7F 90         jg      short 00408672
004086E2   .  A1 04934000   mov     eax, [409304]
004086E7   .  BA 2C894000   mov     edx, 0040892C                    ;  ASCII 0A,"--> Serial"
004086EC   .  E8 EFB9FFFF   call    004040E0
004086F1   .  E8 E2A2FFFF   call    004029D8
004086F6   .  E8 319FFFFF   call    0040262C
004086FB   .  BA 9CA74000   mov     edx, 0040A79C
00408700   .  A1 70934000   mov     eax, [409370]
00408705   .  E8 66A4FFFF   call    00402B70
0040870A   .  A1 70934000   mov     eax, [409370]
0040870F   .  E8 C8A4FFFF   call    00402BDC
00408714   .  E8 139FFFFF   call    0040262C
00408719   .  A1 9CA74000   mov     eax, [40A79C]
0040871E   .  E8 91B7FFFF   call    00403EB4
00408723   .  83F8 10       cmp     eax, 10                          ;  序列号必须是16个字符
00408726   .  74 0A         je      short 00408732
00408728   .  E8 77FDFFFF   call    004084A4
0040872D   .  E9 39010000   jmp     0040886B
00408732   >  B8 01000000   mov     eax, 1                           ;  计数器
00408737   .  BE A4A74000   mov     esi, 0040A7A4
0040873C   >  8B15 9CA74000 mov     edx, [40A79C]                    ;  序列号首地址
00408742   .  8A5402 FF     mov     dl, [edx+eax-1]                  ;  依次取序列号各字符
00408746   .  8BCA          mov     ecx, edx
00408748   .  80C1 BF       add     cl, 0BF
0040874B   .  80E9 06       sub     cl, 6
0040874E   .  73 04         jnb     short 00408754                   ;  cl>5则跳(相当于原dl<'A'或dl>'F')
00408750   .  8816          mov     [esi], dl
00408752   .  EB 18         jmp     short 0040876C                   ;  dl>='A'或dl<='F'
00408754   >  8BCA          mov     ecx, edx
00408756   .  80C1 D0       add     cl, 0D0
00408759   .  80E9 0A       sub     cl, 0A
0040875C   .  73 04         jnb     short 00408762                   ;  cl>9则跳(相当于原dl<'0'或dl>'9')
0040875E   .  8816          mov     [esi], dl
00408760   .  EB 0A         jmp     short 0040876C
00408762   >  E8 3DFDFFFF   call    004084A4                         ;  显示错误信息并终止
00408767   .  E9 FF000000   jmp     0040886B
0040876C   >  40            inc     eax
0040876D   .  46            inc     esi
0040876E   .  83F8 11       cmp     eax, 11                          ;  这一循环是检测序列号是否仅由16进制字符组成
00408771   .^ 75 C9         jnz     short 0040873C
00408773   .  50            push    eax
00408774   .  53            push    ebx
00408775   .  51            push    ecx
00408776   .  52            push    edx
00408777   .  31C0          xor     eax, eax
00408779   .  31DB          xor     ebx, ebx
0040877B   .  31C9          xor     ecx, ecx
0040877D   .  31D2          xor     edx, edx
0040877F   .  8B0D 98A74000 mov     ecx, [40A798]                    ;  用户名指针
00408785   >  0FB619        movzx   ebx, byte ptr [ecx]
00408788   .  31D3          xor     ebx, edx
0040878A   .  01D8          add     eax, ebx
0040878C   .  C1C0 07       rol     eax, 7
0040878F   .  89DA          mov     edx, ebx
00408791   .  41            inc     ecx
00408792   .  8039 00       cmp     byte ptr [ecx], 0                ;  是否已到达串尾
00408795   .^ 75 EE         jnz     short 00408785
00408797   .  31C9          xor     ecx, ecx
00408799   >  31D8          xor     eax, ebx
0040879B   .  C1C3 10       rol     ebx, 10
0040879E   .  01D3          add     ebx, edx
004087A0   .  31D8          xor     eax, ebx
004087A2   .  C1C0 03       rol     eax, 3
004087A5   .  31D0          xor     eax, edx
004087A7   .  C1C2 08       rol     edx, 8
004087AA   .  01DA          add     edx, ebx
004087AC   .  31D0          xor     eax, edx
004087AE   .  C1C0 05       rol     eax, 5
004087B1   .  41            inc     ecx
004087B2   .  83F9 0A       cmp     ecx, 0A
004087B5   .^ 75 E2         jnz     short 00408799
004087B7   .  A3 A0A74000   mov     [40A7A0], eax                    ;  这里计算出值A1
004087BC   .  5A            pop     edx
004087BD   .  59            pop     ecx
004087BE   .  5B            pop     ebx
004087BF   .  58            pop     eax
004087C0   .  B8 01000000   mov     eax, 1
004087C5   .  BA A4A74000   mov     edx, 0040A7A4
004087CA   >  33C9          xor     ecx, ecx
004087CC   .  8A0A          mov     cl, [edx]                        ;  edx=输入序列号的指针
004087CE   .  310D BCA74000 xor     [40A7BC], ecx
004087D4   .  83F8 10       cmp     eax, 10
004087D7   .  74 07         je      short 004087E0
004087D9   .  C125 BCA74000>shl     dword ptr [40A7BC], 2
004087E0   >  40            inc     eax
004087E1   .  42            inc     edx
004087E2   .  83F8 11       cmp     eax, 11
004087E5   .^ 75 E3         jnz     short 004087CA
004087E7   .  A1 BCA74000   mov     eax, [40A7BC]
004087EC   .  C1E8 0C       shr     eax, 0C
004087EF   .  C1E0 0C       shl     eax, 0C                          ;  等价于and eax, 0FFFFF000h
004087F2   .  8B15 A0A74000 mov     edx, [40A7A0]
004087F8   .  C1EA 14       shr     edx, 14
004087FB   .  03C2          add     eax, edx
004087FD   .  8B15 A0A74000 mov     edx, [40A7A0]
00408803   .  C1E2 14       shl     edx, 14
00408806   .  C1EA 14       shr     edx, 14                          ;  等价于and edx, 0FFFh
00408809   .  33C2          xor     eax, edx
0040880B   .  8B15 A0A74000 mov     edx, [40A7A0]
00408811   .  C1E2 0C       shl     edx, 0C
00408814   .  C1EA 18       shr     edx, 18
00408817   .  33C2          xor     eax, edx
00408819   .  A3 BCA74000   mov     [40A7BC], eax                    ;  这里计算出A2
0040881E   .  A1 BCA74000   mov     eax, [40A7BC]
00408823   .  3B05 A0A74000 cmp     eax, [40A7A0]
00408829   .  75 07         jnz     short 00408832
0040882B   .  E8 B0FCFFFF   call    004084E0                         ;  检测到爆破?
00408830   .  EB 39         jmp     short 0040886B
00408832   >  E8 CDFBFFFF   call    00408404
00408837   .  84C0          test    al, al                           ;  al != 0为成功标志
00408839   .  74 07         je      short 00408842
0040883B   .  C605 B4A74000>mov     byte ptr [40A7B4], 1
00408842   >  803D B4A74000>cmp     byte ptr [40A7B4], 0
00408849   .  74 1B         je      short 00408866                   ;  关键跳转(跳为失败)
0040884B   .  A1 04934000   mov     eax, [409304]
00408850   .  BA 44894000   mov     edx, 00408944                    ;  ASCII LF,"<-- You did it! Now write a small tutorial! -->",LF,"<-- And not forget about keygen ;) -->",LF

//////////////  以上是代码  //////////////

从关键跳转的地方回溯到408832处的call 408404,跟进去一看:

//////////////  以下是代码  //////////////

//这里略去一段代码
00408420  |.  E8 53FFFFFF   call    00408378
00408425  |.  84C0          test    al, al
00408427  |.  74 40         je      short 00408469
00408429  |.  8D45 FC       lea     eax, [ebp-4]
0040842C  |.  50            push    eax                              ; /Arg1
0040842D  |.  A1 A0A74000   mov     eax, [40A7A0]                    ; |
00408432  |.  8945 EC       mov     [ebp-14], eax                    ; |
00408435  |.  C645 F0 00    mov     byte ptr [ebp-10], 0             ; |
00408439  |.  A1 BCA74000   mov     eax, [40A7BC]                    ; |
0040843E  |.  8945 F4       mov     [ebp-C], eax                     ; |
00408441  |.  C645 F8 00    mov     byte ptr [ebp-8], 0              ; |
00408445  |.  8D55 EC       lea     edx, [ebp-14]                    ; |
00408448  |.  B9 01000000   mov     ecx, 1                           ; |
0040844D  |.  B8 98844000   mov     eax, 00408498                    ; |ASCII "%.8x%.8x"
00408452  |.  E8 71DCFFFF   call    004060C8                         ; \indoKGM1.004060C8
00408457  |.  8B45 FC       mov     eax, [ebp-4]
0040845A  |.  8B15 B8A74000 mov     edx, [40A7B8]
00408460  |.  E8 27BBFFFF   call    00403F8C                         ;  比较字符串,相等标志ZF=0
00408465  |.  74 02         je      short 00408469                   ;  这里跳表示注册成功
00408467  |.  33DB          xor     ebx, ebx

//////////////  以上是代码  //////////////

这个地方有明码比较,既然都出现"%.8x%.8x"之类字样,那肯定是调用象
wsprintf一类的函数了,看一下它的参数及输出,可以知道它是把[40A7A0]和
[40A7BC]处的16进制数值转换成字符串,然后再与输入的序列号比较,相等则
成功,不等则失败。于是得出结论:序列号应该是16字符,并且只能由16进制
字符(大写字母)组成。(其实在主程序中已有相关检测)至于真码的值则存
放在[40A7A0]及[40A7BC]两个双字中。

  接下来回到主程序中,看[40A7A0]及[40A7BC]两个双字的值是怎么算出来
的。前者的计算倒没什么问题,从40877F到4087B5这段代码根据用户名计算出
一个数值放到[40A7A0]中。如果把这段代码称为F1函数,这就是说:

          dword ptr [40A7A0] = F1(用户名)

但[40A7BC]的计算就大有文章了,先把输入的序列号第一个字符的ASCII码放
到[40A7BC]中,然后重复执行“左移2位后与下一个字符的ASCII码异或”动作
15次,最后再把低12位改成根据已计算好的[40A7A0]算出来的一个数值。如果
把这段代码称为F2函数,那么正确的序列号应该满足:

     序列号 = (F1(用户名), F2(序列号))

也就是说正确的序列号必须在某种变换之下能还原到自身,但是只给你这个要
求,不提供任何的具体算法,你能马上构造一个正确的序列号吗?是为这个方
程式的恼人之处。但事已至此,也只能尝试着探索一条从已知的信息计算出未
知序列号的途径:

   假设用户名为PEDIY

   按前述算法计算出F1("PEDIY")=3973076F

   于是,序列号的前8字符应该是这个值,也就是说,可以:

   假设序列号为3973076FIJKLMNPQ

   这里的IJKLMNPQ都是16进制数字,因而其ASCII码应该在30――39,
 以及40――46之间。

   注意到“左移两位与下一个ASCII码异或”这个操作的特点:由于
 ASCII码至多7位,因而在每一次操作中,在[40A7BC]的高24位中的数
 值都只是简单地被左移,而数码本身不会被改变。

   通过“左移两位与下一个ASCII码异或”的重复操作,到处理完
 "3973076F"这一部分时,[40A7BC]数值为3EC3**,其中3EC3这部分已
 不会再改变。后面还有7次左移,共左移14位,"3EC3"的3及E的高2位
 被移出,变成"B0**",于是I=B,J=0

   序列号现在已经解出到3973076FB0KLMNPQ的程度

   这样可以计算到当处理完"3973076FB0"这部分时,[40A7BC]的值
 为3EC3F**,最后3以及E的高2位被移出后转化为"B0F**",于是K=F

   序列号现在已经解出到3973076FB0FLMNPQ的程度

   这样可以计算到当处理完"3973076FB0F"这部分时,[40A7BC]的值
 为FB0FC**,最后F被移出转化为"B0FC**",于是L=C
   
   序列号现在已经解出到3973076FB0FCMNPQ的程度

   这样可以计算到当处理完"3973076FB0FC"这部分时,[40A7BC]的值
 为3EC3F36C,最后3及E的高2位被移出转化为"B0FC**"。注意,这里C后
 面的两个二进制位是11,也就是原来的3。因此,C后面紧接的16进制数
 字不会小于C,因而它的ASCII码以4开头,用这个4去跟[40A7BC]的16进
 “十”位数字6异或得到的是2,这样就可以预计下一个字符处理完的时
 候,上述3后面两个二进制位是00,也就是说,下一个数字应该是
 1100B,也就是"C",于是M=C  
   
   由于最后把后面有把[40A7BC]的低12位改成与[40A7A0]的高12位相
 同,再依次与[40A7A0]的低12位及中8位异或,也就是说:

   NPQ=([40A7A0]的高12位^中8位^低12位)=397^30^76F=4C8

   序列号为3973076FB0FCC4C8

  由此可见,由F1(用户名)可以得出序列号的前8字符,由前8字符可
以计算出第9、10以及倒数三个字符,由前10个字符可以计算第11字符,
由前11字符可以计算出第12字符,由前12字符求解第13个字符就有些连猜
带蒙的成分了。这个算法可以具体编程实现,但实在是太拖泥带水了,鄙
人偷懒,不想搞了……

附F1函数的C实现

long int f1(char *szUserName)
{
        long int loc_a = 0,
                 loc_b = 0,
                     loc_c = 0;
       
        int      loc_i = 0;

        while(loc_b = (long int)szUserName[loc_i])
        {
                loc_b = loc_b ^ loc_c;
                loc_a = loc_a + loc_b;
                loc_a = (loc_a << 7) | (loc_a >> (32 - 7));
                loc_c = loc_b;
                loc_i = loc_i + 1;
        }
       
        loc_i = 0;
       
        while(loc_i < 10)
        {
                loc_a = loc_a ^ loc_b;
                loc_b = (loc_b << 10) | (loc_b >> (32 - 10));
                loc_b = loc_b + loc_c;
                loc_a = loc_a ^ loc_b;
                loc_a = (loc_a << 3) | (loc_a >> (32 - 3));
                loc_a = loc_a ^ loc_c;
                loc_c = (loc_c << 8) | (loc_c >> (32 - 8));
        loc_c = loc_c + loc_b;
        loc_a = loc_a ^ loc_c;
        loc_a = (loc_a << 5) | (loc_a >> (32 - 5));
                loc_i = loc_i + 1;
        }

        return loc_a;
}


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

收藏
免费 7
支持
分享
最新回复 (6)
雪    币: 249
活跃值: (10)
能力值: ( LV12,RANK:250 )
在线值:
发帖
回帖
粉丝
2
2006-7-9
先占个位置,trying to crack it

初看上去似乎是个比较麻烦的crack me需要研究一下

2006-7-10

昨天花了一些时间没有跟踪出来,这个位置白占了。(初入贵道,第一次调试delphi 的 RTL)

为什么pascal 写的 console显示一行文本都要3个CALL
那几个call是作者自己写的还是编译后调用RLT库的?
2006-7-9 17:18
0
雪    币: 370
活跃值: (78)
能力值: ( LV9,RANK:970 )
在线值:
发帖
回帖
粉丝
3
上传一份到本地。
上传的附件:
2006-7-10 11:17
0
雪    币: 433
活跃值: (176)
能力值: ( LV13,RANK:1250 )
在线值:
发帖
回帖
粉丝
4
整理了一下思路,由用户名计算序列号的思路大体应该这样来说:

首先准备一个16字符的模板用于存放生成的序列号:

****************

从用户名根据F1函数计算出前8个字符

假设RSTUVXYZ=F1(用户名)
(这里RSTUVXYZ都是16进数字,字母用大写形式,下同)

再计算NPQ = RST xor UV xor XYZ
则序列号的形式应该是
RSTUVXYZ*****NPQ
到了这里,先将一个双字变量(记为小写a好了)清零后放入字符R的ASCII码,然后:
a = a shl 2
a = a xor S的ASCII码
a = a shl 2
a = a xor T的ASCII码
……
如此下去一直做到
a = a xor Z的ASCII码
a = a shl 2
这时令a1 = a
a1 = a1 shl 14
这时的a1的前两个16进位(若记为IJ)就是序列号的9和10两个字符
则序列号为RSTUVXYZIJ***NPQ
接着
a = a xor I的ASCII码
a = a shl 2
a = a xor J的ASCII码
a = a shl 2
这时令a1 = a
a1 = a1 shl 18
a1的最高16进位(若记为K)就是序列号的第11个字符
序列号为RSTUVXYZIJK**NPQ
接着a = a xor K的ASCII码
a = a shl 2
再令a1 = a
a1 = a1 shl 20
a1的最高16进位(若记为L)是序列号的第12个字符
序列号为RSTUVXYZIJKL*NPQ
接着a = a xor L的ASCII码
a = a shl 2
假设序列号的第13个字符在'0'到'9'之间,那么它的ASCII码的高16进位应该是3
于是令a1 = a
a1 = a1 xor 30h
a1 = a1 shr 6
a1 = a1 and 0Fh
如果最后得到的a1确实在0到9之间,这个结果就是可以接受的,而序列号的第13个字符就是该数字
否则重新假设假设序列号的第13个字符在'A'到'F'之间,它的ASCII码的高16进位是4,
令a1 = a
a1 = a1 xor 40h
a1 = a1 shr 6
a1 = a1 and 0Fh
这时a1必在0Ah到0Fh之间(这是可以证明的),序列号的第13个字符就是该数字
若把此数字记为M
序列号为RSTUVXYZIJKLMNPQ
2006-7-10 18:00
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
sdy
5
<<---[ KeygenMe #1 - by indomit ]--->>>

--> Name: ANSON

--> Serial: 8DA7797F7DC2A1D2

<-- You did it! Now write a small tutorial! -->
<-- And not forget about keygen ;) -->

Hit <Enter> to exit
2006-7-10 22:17
0
雪    币: 201
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
哎!我还不能下载.权限太低
2006-7-10 23:21
0
雪    币: 215
活跃值: (25)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
7
为什么不能下啊
2009-5-18 13:31
0
游客
登录 | 注册 方可回帖
返回
//