windycandy 发表于 2006-3-5 18:43:23

一个crackme的算法分析(适合初学者)

【破文标题】一个crackme的算法分析
【破文作者】windycandy
【破解工具】OD,Peid0.94
【破解平台】Windows xp
【软件名称】crackme
【软件大小】12K
【保护方式】name & SN
【破解声明】我是一只小菜鸟,偶得一点心得,愿与大家分享
------------------------------------------------------------------------
1.前言

最近学习CCDebuger前辈的<OllyDBG 入门系列>,使我等菜鸟受益匪浅,今有所成,又巧遇一crackme,可用前辈的
<消息断点及 RUN 跟踪>方法破之,遂将过程写出来,与跟我一样的菜鸟共勉,同时激励前辈在有时间情况下写出
更多的教程,以供我们观摩学习.

2.破解过程

先运行程序看看情况,点HELP随便输入name:windycandy,serial:87654321.按OK,出现错误提示框.好了,现在拿
工具开始行动.

Peid 查壳无壳,为MASM32 / TASM32 编写的程序.

OD载入,停在入口:

00401000 C>/$6A 00         push 0                              ; /(初始化 cpu 选择状态)
00401002   |.E8 FF040000   call <jmp.&KERNEL32.GetModuleHandle>; \GetModuleHandleA
00401007   |.A3 CA204000   mov dword ptr ds:,eax
0040100C   |.6A 00         push 0                              ; /Title = NULL
0040100E   |.68 F4204000   push CRACKME.004020F4               ; |no need to disasm the code!
00401013   |.E8 A6040000   call <jmp.&USER32.FindWindowA>      ; \FindWindowA
00401018   |.0BC0          or eax,eax
0040101A   |.74 01         je short CRACKME.0040101D

用字符串插件能找到有效字符"great work, mate!\nnow try the next crackme!"及"no luck there, mate!"分别
双击都能来到反汇编窗口,但是向上找都没有找到能跳过错误提示框的关键跳,这下好象有点意思了.这样找关键算法
的call好象也比较困难,改用<消息断点及 RUN 跟踪>方法则轻松破之.

OD重新载入,F9运行,到注册界面输入"windycandy"及"8765432100",不按"OK"
在OD菜单找"查看"下的"窗口"或直接按"M"(有时按"窗口"或"M"看不到内容,这时可以轮换按"M"或"窗口")
出现以下窗口

句柄         标题               父级       WinProc    ID      ? 样式       ExtStyle   线程       ClsProc    Class
00020684                            Topmost                        0CC00000   00000100   主          10005F60   ATL:10055250
00040682       Register             Topmost                        14C800C4   00010101   主          77D1C6C4   #32770
K0002064E      Serial               00040682            0000FFFF   50020000   00000004   主          77D1CC6C   Static
K00020652      Name               00040682            0000FFFF   50020000   00000004   主          77D1CC6C   Static
K00020654      Cancel               00040682            000003EB   50010000   00000004   主          77D30515   Button
K00020664      OK                   00040682            000003EA   50010000   00000004   主          77D30515   Button
K00020666                           00040682            000003E9   50010080   00000204   主          77D28530   Edit
K00030668                           00040682            000003E8   50010080   00000204   主          77D28530   Edit
E00090650      Default IME          00040682                         8C000000            主          77D63CE2   IME
NE0008066C   M                  00090650                         8C000000            主          FFFF037D   MSCTFIME UI
00060644       Hammer of Thor       Topmost                        8C000000            主          77D15C55   Mjolnir
E00040642      THOR MAIN WINDOW   00060644                         8C400000   00000188   主          10037BCB   CiceroUIWndFrame
NK0002063E   CiceroUIWndFrame   00040642                         8C000000   00080008   主          10037BCB   CiceroUIWndFrame
NIK0002062E    PadListView          0002063E                         56000000   00000200   主          10028210   PadListView
NIIE000206A2                        0002062E            00000020   50000002            主          FFFF02C1   SysHeader32
NIE0002063C    CiceroUIWndFrame   0002063E                         8C800000   00000008   主          10037BCB   CiceroUIWndFrame
NK00020640   CiceroUIWndFrame   00040642                         8C800000   00000008   主          10037BCB   CiceroUIWndFrame
NE00020698   PadListView          00040642                         56000000   00000200   主          10028210   PadListView
NNE00020658                         00020698            00000020   40000002            主          FFFF02C1   SysHeader32
00090648       CrackMe v1.0         Topmost               00070781   1CCF0000   00000100   主          00401128   No need to disasm the code!

找到按钮"OK"
单击右键------->"在Classproc上设消息断点"---------> 选"202 WM_LBUTTONUP"--------> 点"确定"

再在"调试"菜单下"打开或清除RUN跟踪",开始RUN跟踪
确保在反汇编窗口下
单击右键---------> RUN跟踪------------->添加全部函数例程的入口
返回到crackme窗口,按"OK"
条件中断在
77D30515 [>55            push ebp--------中断在这里
77D30516   8BEC            mov ebp,esp
77D30518   8B4D 08         mov ecx,dword ptr ss:
77D3051B   56            push esi
77D3051C   E8 0335FEFF   call USER32.77D13A24
77D30521   8BF0            mov esi,eax
77D30523   85F6            test esi,esi
77D30525   74 38         je short USER32.77D3055F
77D30527   8B55 0C         mov edx,dword ptr ss:
77D3052A   3B15 C8C0D677   cmp edx,dword ptr ds:
77D30530   77 1E         ja short USER32.77D30550
77D30532   33C0            xor eax,eax

按Alt+M

内存映射,项目 23
地址=00401000
大小=00001000 (4096.)
宿主=CRACKME00400000
区段=CODE
包含=code
类型=Imag 01001002
访问=R
初始访问=RWE

在crackme, code 段下F2断点,F9运行,中断在00401253

00401253   /.C8 000000   enter 0,0-------断在这里
00401257   |.53            push ebx
00401258   |.56            push esi
00401259   |.57            push edi
0040125A   |.817D 0C 10010>cmp dword ptr ss:,110
00401261   |.74 34         je short CRACKME.00401297
00401263   |.817D 0C 11010>cmp dword ptr ss:,111
0040126A   |.74 35         je short CRACKME.004012A1
0040126C   |.837D 0C 10    cmp dword ptr ss:,10
00401270   |.0F84 81000000 je CRACKME.004012F7
00401276   |.817D 0C 01020>cmp dword ptr ss:,201
0040127D   |.74 0C         je short CRACKME.0040128B
0040127F   |.B8 00000000   mov eax,0
00401284   |>5F            pop edi
00401285   |.5E            pop esi

向下翻,看到

004012B5   |.6A 0B         |push 0B                            ; /Count = B (11.)
004012B7   |.68 8E214000   |push CRACKME.0040218E            ; |Buffer = CRACKME.0040218E
004012BC   |.68 E8030000   |push 3E8                           ; |ControlID = 3E8 (1000.)
004012C1   |.FF75 08       |push dword ptr ss:          ; |hWnd
004012C4   |.E8 07020000   |call <jmp.&USER32.GetDlgItemTextA> ; \GetDlgItemTextA--------------这个,我们喜欢
004012C9   |.83F8 01       |cmp eax,1
004012CC   |.C745 10 EB030>|mov dword ptr ss:,3EB
004012D3   |.^ 72 CC         \jb short CRACKME.004012A1
004012D5   |.6A 0B         push 0B                           ; /Count = B (11.)
004012D7   |.68 7E214000   push CRACKME.0040217E               ; |Buffer = CRACKME.0040217E
004012DC   |.68 E9030000   push 3E9                            ; |ControlID = 3E9 (1001.)
004012E1   |.FF75 08       push dword ptr ss:         ; |hWnd
004012E4   |.E8 E7010000   call <jmp.&USER32.GetDlgItemTextA>; \GetDlgItemTextA--------------这个,我们喜欢
004012E9   |.B8 01000000   mov eax,1
004012EE   |.EB 07         jmp short CRACKME.004012F7

于是在4012B5,F2下断,删除其他断点, Ctrl+F2重新载入,F9运行,输入name和serail,点确定中断在4012B5
F8一路来到
00401223    .83F8 00       cmp eax,0
00401226    .^ 74 BE         je short CRACKME.004011E6
00401228    .68 8E214000   push CRACKME.0040218E               ;ASCII "windycandy"姓名入栈
0040122D    .E8 4C010000   call CRACKME.0040137E -----------------对name进行算法运算,F7跟进
00401232    .50            push eax
00401233    .68 7E214000   push CRACKME.0040217E               ;ASCII "8765432100"
00401238    .E8 9B010000   call CRACKME.004013D8
0040123D    .83C4 04       add esp,4
00401240    .58            pop eax
00401241    .3BC3          cmp eax,ebx
00401243    .74 07         je short CRACKME.0040124C
00401245    .E8 18010000   call CRACKME.00401362
0040124A    .^ EB 9A         jmp short CRACKME.004011E6
0040124C    >E8 FC000000   call CRACKME.0040134D
00401251    .^ EB 93         jmp short CRACKME.004011E6

进入40122D来到
0040137E   /$8B7424 04   mov esi,dword ptr ss:------------输入的name放入esi
00401382   |.56            push esi
00401383   |>8A06          /mov al,byte ptr ds:---------------取name的字符进行逐个判断
00401385   |.84C0          |test al,al
00401387   |.74 13         |je short CRACKME.0040139C---------------所有字符判断结束则跳走
00401389   |.3C 41         |cmp al,41               ----------------是否是字母"A"以上的字符
0040138B   |.72 1F         |jb short CRACKME.004013AC---------------不是,over
0040138D   |.3C 5A         |cmp al,5A
0040138F   |.73 03         |jnb short CRACKME.00401394---------------与字母"Z"比较,不小于则进行处理
00401391   |.46            |inc esi                  ------------------下一个字符
00401392   |.^ EB EF         |jmp short CRACKME.00401383
00401394   |>E8 39000000   |call CRACKME.004013D2------------------------字符转换,关键call,F7跟进
00401399   |.46            |inc esi                            ;CRACKME.0040218E
0040139A   |.^ EB E7         \jmp short CRACKME.00401383

F7进入401394
004013D2   /$2C 20         sub al,20---------------------------------------将name中的小写字母换成大写字母
004013D4   |.8806          mov byte ptr ds:,al
004013D6   \.C3            retn-----------------------------------------------返回

字符转换完后,返回到这里继续以下处理

0040139C   |> \5E            pop esi             ---------------------------换算结果入esi
0040139D   |.E8 20000000   call CRACKME.004013C2--------------------------算法call,F7跟进
004013A2   |.81F7 78560000 xor edi,5678
004013A8   |.8BC7          mov eax,edi

F7进入40139D

004013C2   /$33FF          xor edi,edi-----------------清零,准备运算
004013C4   |.33DB          xor ebx,ebx-----------------清零,准备运算
004013C6   |>8A1E          /mov bl,byte ptr ds:---逐一取esi的字符
004013C8   |.84DB          |test bl,bl            
004013CA   |.74 05         |je short CRACKME.004013D1--esi内的字符处理完则跳走
004013CC   |.03FB          |add edi,ebx------------------累加,结果放入edi
004013CE   |.46            |inc esi-------------------下一位字符
004013CF   |.^ EB F5         \jmp short CRACKME.004013C6
004013D1   \>C3            retn----------------------------返回

返回到这里
004013A2   |.81F7 78560000 xor edi,5678---------------运算结果与"5678"异域运算
004013A8   |.8BC7          mov eax,edi-----------------运算结果送入eax
004013AA   |.EB 15         jmp short CRACKME.004013C1---跳到4013C1,返回

返回这里
00401232    .50            push eax--------------------返回这里
00401233    .68 7E214000   push CRACKME.0040217E               ;ASCII "8765432100"假码入栈
00401238    .E8 9B010000   call CRACKME.004013D8------------------算法call,F7跟进
0040123D    .83C4 04       add esp,4
00401240    .58            pop eax
00401241    .3BC3          cmp eax,ebx
00401243    .74 07         je short CRACKME.0040124C
00401245    .E8 18010000   call CRACKME.00401362
0040124A    .^ EB 9A         jmp short CRACKME.004011E6
0040124C    >E8 FC000000   call CRACKME.0040134D
00401251    .^ EB 93         jmp short CRACKME.004011E6

F7进入
004013D8   /$33C0          xor eax,eax-----------------清零,准备运算
004013DA   |.33FF          xor edi,edi-----------------清零,准备运算
004013DC   |.33DB          xor ebx,ebx-----------------清零,准备运算
004013DE   |.8B7424 04   mov esi,dword ptr ss:----假码送入esi
004013E2   |>B0 0A         /mov al,0A
004013E4   |.8A1E          |mov bl,byte ptr ds:----逐一取假码进行运算
004013E6   |.84DB          |test bl,bl
004013E8   |.74 0B         |je short CRACKME.004013F5---处理完则跳走
004013EA   |.80EB 30       |sub bl,30-------------------减30
004013ED   |.0FAFF8      |imul edi,eax-----------------edi=edi*eax
004013F0   |.03FB          |add edi,ebx------------------edi=eid+ebx
004013F2   |.46            |inc esi----------------------下一位
004013F3   |.^ EB ED         \jmp short CRACKME.004013E2
004013F5   |>81F7 34120000 xor edi,1234--------------------运算结果与1234异域
004013FB   |.8BDF          mov ebx,edi----------------------运算结果送入edx
004013FD   \.C3            retn-----------------------------返回

返回这里
0040123D    .83C4 04       add esp,4------返回这里
00401240    .58            pop eax
00401241    .3BC3          cmp eax,ebx-----------------------name的算法运算结果与serial的算法运算结果比较
00401243    .74 07         je short CRACKME.0040124C---------------关键跳,爆破点
00401245    .E8 18010000   call CRACKME.00401362--------------------不等则OVER
0040124A    .^ EB 9A         jmp short CRACKME.004011E6
0040124C    >E8 FC000000   call CRACKME.0040134D--------------------相等"congraduatin!"
00401251    .^ EB 93         jmp short CRACKME.004011E6


破解总结:
这个crackme的注册属于F'(name)=F'(serial)的类型,其算法为:
①输入的name必须全部是字母,在name的字母中如果有小写字母则需要将该小写字母换成大写
字母,本身是大写字母的不用转换,然后将name(都是大写字母)的各字符串的ARSII值累加,累
加结果与"5678"进行异域运算,得出F'(name);
②取输入假码的每位ARSCII值(B),作如下运算(A为常数):
y<=B-30
Z<=Z*A
Z<=Z+Y
算完一位再取下一位.
最后将累加结果(Z)与"1234"作异域运算,得出F'(serial)

如果F'(name)=F'(serial)则注册成功.

注册机,我不会写,只能算出自己的注册码,有时间再学写写注册机.

name=windycandy
serial=B102或serial=18102

推算过程:
windycany

│转换为大写

WINDYCANDY

│name的算法、累加处理

2FA

│xor 5678

5482----F'(name)

│xor 1234

46B6

│除以常数“A”------------余数“2”,2+30=32-----ARSII表中为字符“2”------注册码倒数第一位

712

│除以常数“A”------------余数“0”,0+30=30-----ARSII表中为字符“0”------注册码倒数第二位

B5

│除以常数“A”------------余数“1”,1+30=31-----ARSII表中为字符“1”------注册码倒数第三位

12---------(如果只算到这里余数“12”,12+30=42---ARSII表中为字符“B”------注册码倒数第四位)----得出serial=B102

│除以常数“A”------------余数“8”,8+30=38-----ARSII表中为字符“8”------注册码倒数第四位

1--------------------------余数“1”,1+30=31-----ARSII表中为字符“1”------注册码倒数第五位----得出serial=18102


最后,如果使用字符串插件找到"no luck there, mate!",双击来到反汇编窗口
00401362   /$6A 00         push 0                              ; /BeepType = MB_OK
00401364   |.E8 AD000000   call <jmp.&USER32.MessageBeep>      ; \MessageBeep
00401369   |.6A 30         push 30                           ; /Style = MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL
0040136B   |.68 60214000   push CRACKME.00402160               ; |no luck!
00401370   |.68 69214000   push CRACKME.00402169               ; |no luck there, mate!--------------到这里
00401375   |.FF75 08       push dword ptr ss:         ; |hOwner
00401378   |.E8 BD000000   call <jmp.&USER32.MessageBoxA>      ; \MessageBoxA
0040137D   \.C3            retn

到这里后,注意401362及40137D,可以猜测这是某个CALL调用的子程序,于是使用Ctrl+F查找"call 401362"也能找到关键点
00401241    .3BC3          cmp eax,ebx
00401243    .74 07         je short CRACKME.0040124C
00401245    .E8 18010000   call CRACKME.00401362------------找到这里
0040124A    .^ EB 9A         jmp short CRACKME.004011E6
0040124C    >E8 FC000000   call CRACKME.0040134D
00401251    .^ EB 93         jmp short CRACKME.004011E6
以下分析相同.


------------------------------------------------------------------------
【版权声明】本文仅属于技术交流,如有转载请注明出处.

[ 本帖最后由 windycandy 于 2006-3-19 01:30 编辑 ]

飘云 发表于 2006-3-5 18:49:11

建议将CrackMe贴出来,给大家学习!

写注册机时,对算法求逆就可以了,呵呵!

冷血书生 发表于 2006-3-5 20:19:04

其实只要在这里下断就OK:

00401223    .83F8 00       cmp eax,0

往下的两个CALL 就是算法CALL了!很容易看出来!

对于这个练习,好像有点麻烦了!呵呵!

不过对于学习,我是非常支持的!!

先计算出用户名的算法,再计算注册码,是非常容易的!呵呵!

NAME: lengxue
CODE: 18004

vivian 发表于 2006-3-6 09:03:36

强啊,适合我等新手

byh9999 发表于 2006-3-6 09:43:31

好文章哪!! 顶起来!!!

lzc627 发表于 2006-3-6 18:04:09

辛苦了,支持一下
页: [1]
查看完整版本: 一个crackme的算法分析(适合初学者)