首页
社区
课程
招聘
[原创]riijj Crackme (1) 的详解
发表于: 2004-11-26 11:57 218558

[原创]riijj Crackme (1) 的详解

2004-11-26 11:57
218558

【破文标题】riijj Crackme (1) 的详解


【对  象】初入门的新手


【下载地址】

http://bbs.pediy.com/upload/files/1084801702.zip


【破解工具】OD


【保护方式】序号


【任  务】找出序号


【破文作者】riijj


【组  织】没有


【破解声明】我的破解很菜,写这篇东西是给刚入门的兄弟可以顺利完成这个 crackme,找到一点信心


【备  注】老手勿看,别浪费你的时间


【电  邮】je6543@yahoo.com


【破解过程】



[PART. 1 第一部分]



对于刚接触破解的新手来说,这个 crackme 是一只没有杀伤力的小兔。



一般破文都是注重处理 antidebug 和序号检查这些精要的部份,可是这个 crackme 实在是太简单,所以


会详尽一点,把新手不懂的地方也说一下



1.  检查壳 (check for protector)



在开始之前,我们都会用 peid 或 Fi 这些工具检查一下壳,如果程序是有加壳的,当然是先脱壳。


(关于脱壳,这里不多说了)



打开 peid ,把 exe 拉进去



peid 显示 Microsoft Visual C++ 6.0



这表示没有加壳,这是以 vc6 编写的原程序。  (注: 有些程序加壳后,会故意修改,装成没有加壳的样子,所以我们不可以


尽信查壳工具)



2. 用 OD 加载



我们可以用的调试工具很多,静态调试的有 IDA , wdasm893 (现在比较少人用),动态调试我们可以用 OD (olly debug)


,或是用 softice 对系统设下断点来破。 我们这里介绍 OD ,如果你喜欢其它工具也是可以的,原理是差不多。



加载后,看到



00401368 >/$ 55             PUSH EBP        <------- 我们在这里


00401369  |. 8BEC           MOV EBP,ESP


0040136B  |. 6A FF          PUSH -1


0040136D  |. 68 E8404000    PUSH ncrackme.004040E8


00401372  |. 68 9C1E4000    PUSH ncrackme.00401E9C                   ;  SE handler installation


00401377  |. 64:A1 00000000 MOV EAX,DWORD PTR FS:[0]


0040137D  |. 50             PUSH EAX


0040137E  |. 64:8925 000000>MOV DWORD PTR FS:[0],ESP


00401385  |. 83EC 58        SUB ESP,58


00401388  |. 53             PUSH EBX



这样的一大堆,便是程序开始的地方。一般程序的入口点都是 40xxxx 这样的,如果程序加了壳,入口点会不同。


程序的入口点,是可以由作者自行设定的,没有特别规定



在程序开始段常见的 API :  KERNEL32.GetVersion, GetCommandLineA, GetStartupInfoA



我们在这片密麻麻的字海里,是很难找到我们要破解的地方,我们第一步是要找出检查序号的部份。程序多数会用 GetWindowTextA,


GetDlgItemTextA 这类 API 来得到文字方块里的字符串。此外,当我们输入错误序号的时候,程序会弹出一个失败信息,这个信息由


MessageBoxA 所提供。假若我们要分析算法,便需要在 GetWindowTextA 下断,一步一步跟踪。现在我们想从内存中找出序号,比较


快速的方法是在 MessageBoxA 下断。



在 OD 上方的 Plugins ,选 Commandline ,这里可以像 softice 一样输入命令行



设下一个断点 :  



bp MessageBoxA



输入这行后,当程序使用 MessageBoxA ,程序便会断下



现在,我们把程序正常运行 (按 F9),输入一个名字,我在里输入了 riijj ,在序号那行输入了  AAAABBBBCCCC



按下 "Register" ,这时候程序遇到断点,停在以下地方



77E16544 > 55               PUSH EBP   <---停在这里


77E16545   8BEC             MOV EBP,ESP


77E16547   51               PUSH ECX


77E16548   833D 1893E477 00 CMP DWORD PTR DS:[77E49318],0


77E1654F   0F85 EA220100    JNZ USER32.77E2883F


77E16555   6A 00            PUSH 0


77E16557   FF75 14          PUSH DWORD PTR SS:[EBP+14]


77E1655A   FF75 10          PUSH DWORD PTR SS:[EBP+10]


77E1655D   FF75 0C          PUSH DWORD PTR SS:[EBP+C]


77E16560   FF75 08          PUSH DWORD PTR SS:[EBP+8]


77E16563   E8 04000000      CALL USER32.MessageBoxExA


77E16568   C9               LEAVE


77E16569   C2 1000          RETN 10


77E1656C > 55               PUSH EBP



看看 OD 的上方,写着 "CPU - main thread, module USER32" ,这说明了我们身处 user32.dll 的领空里,这是系统的程序


部份,我们是不会修改这里的。



(注 : 如果你把文字窗口向上卷的时候,发现 OD 的编码出现不正常现象 (例如刚刚那行 77E16544 的上方变成了 ??? ) ,


这可能是 OD 的对位出错)



我们要返回 crackme 的领空里,有几个方法



1. 不停接 F8 ,一步一步地执行直至程序遇上 retn ,这是返回指令,它会带我们回去


2. 按 Ctrl + F9 ,这样 OD 会不停执行,直至遇到 retn 停下


3. 按一下返回的 retn ,再按 F4 ,程序会执行到光标所在的地方


4. 打开 OD 的 call stack window,看看我们从那里飞来,便设一个断点在那地方,之后 F9 运行



我们按一下 F2 清除断点,再按一下 77E16569 (retn) 那行,按 F4 执行到那里,再按一下 F7 进入 retn。



00401050   . 817C24 08 1101>CMP DWORD PTR SS:[ESP+8],111


00401058   . 75 74          JNZ SHORT ncrackme.004010CE


0040105A   . 8B4424 0C      MOV EAX,DWORD PTR SS:[ESP+C]


0040105E   . 66:3D EA03     CMP AX,3EA


00401062   . 75 42          JNZ SHORT ncrackme.004010A6


00401064   . E8 C7010000    CALL ncrackme.00401230


00401069   . 85C0           TEST EAX,EAX


0040106B   . 6A 00          PUSH 0                                   ; /Style = MB_OK|MB_APPLMODAL


0040106D   . 68 80504000    PUSH ncrackme.00405080                   ; |Title = "ncrackme"


00401072   . 75 1B          JNZ SHORT ncrackme.0040108F              ; |


00401074   . A1 B8564000    MOV EAX,DWORD PTR DS:[4056B8]            ; |


00401079   . 68 64504000    PUSH ncrackme.00405064                   ; |Text = "Registration successful."


0040107E   . 50             PUSH EAX                                 ; |hOwner => 001C0218 ('Newbie smallsize crackme -



v1',class='myWindowClass')


0040107F   . FF15 C0404000  CALL DWORD PTR DS:[<&USER32.MessageBoxA>>; \MessageBoxA


00401085   . E8 A6020000    CALL ncrackme.00401330


0040108A   . 33C0           XOR EAX,EAX


0040108C   . C2 1000        RETN 10


0040108F   > 8B0D B8564000  MOV ECX,DWORD PTR DS:[4056B8]            ; |


00401095   . 68 50504000    PUSH ncrackme.00405050                   ; |Text = "Registration fail."


0040109A   . 51             PUSH ECX                                 ; |hOwner => 001C0218 ('Newbie smallsize crackme -



v1',class='myWindowClass')


0040109B   . FF15 C0404000  CALL DWORD PTR DS:[<&USER32.MessageBoxA>>; \MessageBoxA


004010A1   . 33C0           XOR EAX,EAX                        <--------------- 我们停在这里


004010A3   . C2 1000        RETN 10


004010A6   > 66:3D EB03     CMP AX,3EB


004010AA   . 75 22          JNZ SHORT ncrackme.004010CE


004010AC   . A1 C0564000    MOV EAX,DWORD PTR DS:[4056C0]


004010B1   . 85C0           TEST EAX,EAX


004010B3   . 74 19          JE SHORT ncrackme.004010CE



我们看见了这里是 MessageBox 跳出的程序,这里是成功信息和失败信息的地方。 (读者可能已经大叫,只要把跳往失败信息的跳转修改


一下,便可以成功爆破) 。这是对的,假如我们要爆破它,只要把 00401072 的 JNZ (jump if not zero),修改成 JZ 便可以。



那么,假若我们不想修改软件,而是找出正确的序号,那又怎办呢 ? 我们需要往那个 jump 的上面看看。在 00401069 这里有一个 TEST


,这就是进行比较的指令,它的结果用在其后的 jnz 上。



这句 TEST EAX,EAX 是检查 EAX 是否等于 0 的典型语句,假如 EAX 不等于 0,JNZ 便会跳。我们就是不想它跳,所以我们要找出让 EAX


等于 0 的条件。在 TEST 的上方是 CALL ncrackme.00401230,这个 CALL 的返回值就是 EAX 的值。



我们按右键选 Go to,在 expression 输入 00401230 这个位置



我们来到了检查序号的地方,一看之下便感到这里是一堆很麻烦的运算。今次我们的目的是检出一个给


自己用的序号,我们有没有方法可以从算法中看出序号呢 ?



[PART. 2 第二部分]



按 F7 单步跟踪,细心观察它在干甚么



00401230  /$ 8B0D BC564000  MOV ECX,DWORD PTR DS:[4056BC]


00401236  |. 83EC 30        SUB ESP,30                        // 在 stack 划出空间,作为变量


00401239  |. 8D4424 00      LEA EAX,DWORD PTR SS:[ESP]


0040123D  |. 53             PUSH EBX


0040123E  |. 56             PUSH ESI


0040123F  |. 8B35 94404000  MOV ESI,DWORD PTR DS:[<&USER32.GetDlgIte>;  USER32.GetDlgItemTextA


00401245  |. 6A 10          PUSH 10                                  ; /Count = 10 (16.)


00401247  |. 50             PUSH EAX                                 ; |Buffer                   //  <---- 注意这里,


00401248  |. 68 E8030000    PUSH 3E8                                 ; |ControlID = 3E8 (1000.)  //  可以看出存放字符串的地方


0040124D  |. 51             PUSH ECX                                 ; |hWnd => NULL            


0040124E  |. 33DB           XOR EBX,EBX                              ; |


00401250  |. FFD6           CALL ESI                                 ; \GetDlgItemTextA


00401252  |. 83F8 03        CMP EAX,3                         // 找到注册名字,如果字名的长度不小于 3,便跳,否则便完结


00401255  |. 73 0B          JNB SHORT ncrackme.00401262


00401257  |. 5E             POP ESI


00401258  |. B8 01000000    MOV EAX,1


0040125D  |. 5B             POP EBX


0040125E  |. 83C4 30        ADD ESP,30


00401261  |. C3             RETN                              // 如果来了这里,便完结了


00401262  |> A1 BC564000    MOV EAX,DWORD PTR DS:[4056BC]     // 从 JNB 来了这里


00401267  |. 8D5424 28      LEA EDX,DWORD PTR SS:[ESP+28]


0040126B  |. 6A 10          PUSH 10


0040126D  |. 52             PUSH EDX                          // <----- 注意这里,可以看出存放序号字符串的地方


0040126E  |. 68 E9030000    PUSH 3E9


00401273  |. 50             PUSH EAX


00401274  |. FFD6           CALL ESI                          // 再用 GetDlgItemTextA ,得到序号


00401276  |. 0FBE4424 08    MOVSX EAX,BYTE PTR SS:[ESP+8]     // 把名字的第一个位,放入 EAX


0040127B  |. 0FBE4C24 09    MOVSX ECX,BYTE PTR SS:[ESP+9]     // 把名字的第二个位,放入 ECX


00401280  |. 99             CDQ                               // 把 EAX 扩展,成为 EDX:EAX 的 QWORD(64 位长)


00401281  |. F7F9           IDIV ECX                          // 把 EDX:EAX 除以 ECX,余数放在 EDX


00401283  |. 8BCA           MOV ECX,EDX                       


00401285  |. 83C8 FF        OR EAX,FFFFFFFF                   // EAX = 0xffffffff


00401288  |. 0FBE5424 0A    MOVSX EDX,BYTE PTR SS:[ESP+A]     // 把名字的第一个位,放入 EDX


0040128D  |. 0FAFCA         IMUL ECX,EDX                      // 把刚才的余数乘以 EDX


00401290  |. 41             INC ECX                           // ECX 增加 1


00401291  |. 33D2           XOR EDX,EDX                       // EDX = 0


00401293  |. F7F1           DIV ECX                           // 以 0xffffffff 除以 ECX



以 C 语言表达,想象成



EAX 的值:  0xFFFFFFFF / (1+(buffer[0] % buffer[1] * buffer[2])



数值相等于 4546e6




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

收藏
免费 7
支持
分享
最新回复 (267)
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
很细
很适合像我一般的菜菜们
支持一下先
2004-11-26 12:18
0
雪    币: 898
活跃值: (4044)
能力值: ( LV9,RANK:3410 )
在线值:
发帖
回帖
粉丝
3
自写自解不容易
支持
2004-11-26 12:39
0
雪    币: 205
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
感谢 收藏..
2004-11-26 13:36
0
雪    币: 201
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
收藏起来……
2004-11-26 16:11
0
雪    币: 323
活跃值: (589)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
6
学习!!
2004-11-26 17:45
0
雪    币: 253
活跃值: (250)
能力值: ( LV9,RANK:210 )
在线值:
发帖
回帖
粉丝
7
双手互搏?
2004-11-26 18:52
0
雪    币: 206
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
请问楼主:要返回 crackme 的领空,除了上面提到的4种外,可不可已这样来:中断后,OD右下角
0012FC98   004010A1  /CALL 到 MessageBoxA 来自 ncrackme.0040109B
0012FC9C   0017052C  |hOwner = 0017052C ('Newbie smallsize crackme - v1',class='myWindowClass')
0012FCA0   00405050  |Text = "Registration fail."
0012FCA4   00405080  |Title = "ncrackme"
0012FCA8   00000000  \Style = MB_OK|MB_APPLMODAL

在第一行右击,选“在反汇编中跟随”
2004-11-26 19:41
0
雪    币: 102419
活跃值: (201669)
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
9
支持!!!
2004-11-26 21:06
0
雪    币: 61
活跃值: (160)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
10
写的不错啊
2004-11-26 21:27
0
雪    币: 1540
活跃值: (2807)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
继续努力,把注册机也给写出来吧
2004-11-26 21:31
0
雪    币: 2319
活跃值: (565)
能力值: (RANK:300 )
在线值:
发帖
回帖
粉丝
12
最初由 hcjsj 发布
请问楼主:要返回 crackme 的领空,除了上面提到的4种外,可不可已这样来:中断后,OD右下角
0012FC98 004010A1 /CALL 到 MessageBoxA 来自 ncrackme.0040109B
0012FC9C 0017052C |hOwner = 0017052C ('Newbie smallsize crackme - v1',class='myWindowClass')
0012FCA0 00405050 |Text = "Registration fail."
0012FCA4 00405080 |Title = "ncrackme"
........


可以 !

stack 中存放了返回位置,在返回位置上,按 “follow in disassembler” ,或是按 Enter
2004-11-26 22:06
0
雪    币: 2319
活跃值: (565)
能力值: (RANK:300 )
在线值:
发帖
回帖
粉丝
13
最初由 moon 发布
双手互搏?


:D :D
2004-11-26 22:18
0
雪    币: 206
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
继续请教:
    OD中断后,是不是一定不在设断的领空?
2004-11-27 21:41
0
雪    币: 2319
活跃值: (565)
能力值: (RANK:300 )
在线值:
发帖
回帖
粉丝
15
最初由 hcjsj 发布
继续请教:
OD中断后,是不是一定不在设断的领空?


用 OD 的 command line 设断点,断点会设在 API 的第一行,所以中断时我们身处 API 领空,如果我们用 F2 人手设断点在我们的程序里,当然是断在设了断点的那一行   :D
2004-11-27 22:42
0
雪    币: 212
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
刚好能看懂,呵呵。
2004-11-27 23:42
0
雪    币: 206
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
最初由 riijj 发布


用 OD 的 command line 设断点,断点会设在 API 的第一行,所以中断时我们身处 API 领空,如果我们用 F2 人手设断点在我们的程序里,当然是断在设了断点的那一行 :D


多谢指点!!!
2004-11-28 11:05
0
雪    币: 216
活跃值: (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
我太菜了~~刚开始学破解,汇编还真看呢!!看的不是很懂~~只会爆破 我的OD是中文的~~
在 OD 上方的 Plugins ,选 Commandline
Plugins的中文什么意思呀!!词霸都翻译不通!Commadline呢?
2004-11-30 17:33
0
雪    币: 2319
活跃值: (565)
能力值: (RANK:300 )
在线值:
发帖
回帖
粉丝
19
最初由 布丁 发布
我太菜了~~刚开始学破解,汇编还真看呢!!看的不是很懂~~只会爆破 我的OD是中文的~~
在 OD 上方的 Plugins ,选 Commandline
Plugins的中文什么意思呀!!词霸都翻译不通!Commadline呢?


Plugin 是插件,在 OD 上方第 4 粒按钮
Command line 是命令列,给你输入 OD 指令的地方

汇编可以慢慢学,查看 intel 或汇编书的注解
我的汇编也不好   :o
2004-11-30 18:52
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
请问何处可以下载OD
2004-11-30 19:12
0
雪    币: 2319
活跃值: (565)
能力值: (RANK:300 )
在线值:
发帖
回帖
粉丝
21
建议你到这里看看

0edK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6%4N6#2)9J5k6i4m8W2k6r3W2&6i4K6u0W2j5$3!0E0

到工具那一页
2004-11-30 19:36
0
雪    币: 308
活跃值: (367)
能力值: ( LV12,RANK:370 )
在线值:
发帖
回帖
粉丝
22
真是难得,希望楼主能多写些这样的破文,让象我这样的菜鸟学习,辛苦了
2004-11-30 21:34
0
雪    币: 216
活跃值: (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
谢谢了~~如果我下载了叉件要怎么装进去呀
2004-12-1 15:04
0
雪    币: 216
活跃值: (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24
我说呢~~我的叉件运行库的地址弄错了~~我把它直正了~~就有了第4个按纽:D 呵呵
2004-12-1 15:25
0
雪    币: 216
活跃值: (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
为什么我用bp MessageBoxA中断后,按ctrl+f9运行到retn,然后f4,f7 跟进就来到这里的004010A1。
004010A1    .  33C0              xor eax,eax
004010A3    .  C2 1000           retn 10
004010A6    >  66:3D EB03        cmp ax,3EB
004010AA    .  75 22             jnz short ncrackme.004010CE
004010AC    .  A1 C0564000       mov eax,dword ptr ds:[4056C0]
004010B1    .  85C0              test eax,eax
004010B3    .  74 19             je short ncrackme.004010CE
004010B5    .  8B15 B8564000     mov edx,dword ptr ds:[4056B8]

然后按f8就由004010A3的retn跳到了
77D3647D    /0F85 885B0100       jnz USER32.77D4C00B
77D36483    |6A 00               push 0
77D36485    |FF7424 14           push dword ptr ss:[esp+14]
77D36489    |FF7424 14           push dword ptr ss:[esp+14]
77D3648D    |FF7424 14           push dword ptr ss:[esp+14]
77D36491    |FF7424 14           push dword ptr ss:[esp+14]
77D36495    |E8 03000000         call USER32.MessageBoxExA
77D3649A    |C2 1000             retn 10
77D3649D U> |55                  push ebp
77D3649E    |8BEC                mov ebp,esp
77D364A0    |6A FF               push -1

好象是又回到了user32.dll的领域!!
2004-12-2 20:08
0
游客
登录 | 注册 方可回帖
返回