【破文标题】一个crackme的算法分析
【破文作者】windycandy
【破解工具】OD,Peid0.94
【破解平台】Windows xp
【软件名称】crackme
【软件大小】12K
【原版下载】http://bbs.chinapyg.cn/viewthread.php?tid=3951&extra=page%3D1
【保护方式】name & SN
【破解声明】我是一只小菜鸟,偶得一点心得,愿与大家分享
------------------------------------------------------------------------
1.前言
最近学习CCDebuger前辈的<OllyDBG 入门系列>,使我等菜鸟受益匪浅,今有所成,又巧遇一crackme,可用前辈的
<消息断点及 RUN 跟踪>方法破之,遂将过程写出来,与跟我一样的菜鸟共勉,同时激励前辈在有时间情况下写出
更多的教程,以供我们观摩学习.
2.破解过程
先运行程序看看情况,点HELP随便输入name:windycandy,serial:87654321.按OK,出现错误提示框.好了,现在拿
工具开始行动.
Peid 查壳无壳,为MASM32 / TASM32 [Overlay]编写的程序.
OD载入,停在入口:
00401000 C>/$ 6A 00 push 0 ; /(初始化 cpu 选择状态)
00401002 |. E8 FF040000 call <jmp.&KERNEL32.GetModuleHandle>; \GetModuleHandleA
00401007 |. A3 CA204000 mov dword ptr ds:[4020CA],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:[ebp+8]
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:[ebp+C]
77D3052A 3B15 C8C0D677 cmp edx,dword ptr ds:[77D6C0C8]
77D30530 77 1E ja short USER32.77D30550
77D30532 33C0 xor eax,eax
按Alt+M
内存映射,项目 23
地址=00401000
大小=00001000 (4096.)
宿主=CRACKME 00400000
区段=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:[ebp+C],110
00401261 |. 74 34 je short CRACKME.00401297
00401263 |. 817D 0C 11010>cmp dword ptr ss:[ebp+C],111
0040126A |. 74 35 je short CRACKME.004012A1
0040126C |. 837D 0C 10 cmp dword ptr ss:[ebp+C],10
00401270 |. 0F84 81000000 je CRACKME.004012F7
00401276 |. 817D 0C 01020>cmp dword ptr ss:[ebp+C],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:[ebp+8] ; |hWnd
004012C4 |. E8 07020000 |call <jmp.&USER32.GetDlgItemTextA> ; \GetDlgItemTextA--------------这个,我们喜欢
004012C9 |. 83F8 01 |cmp eax,1
004012CC |. C745 10 EB030>|mov dword ptr ss:[ebp+10],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:[ebp+8] ; |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:[esp+4]------------输入的name放入esi
00401382 |. 56 push esi
00401383 |> 8A06 /mov al,byte ptr ds:[esi]---------------取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:[esi],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]---逐一取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:[esp+4]----假码送入esi
004013E2 |> B0 0A /mov al,0A
004013E4 |. 8A1E |mov bl,byte ptr ds:[esi]----逐一取假码进行运算
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:[ebp+8] ; |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
以下分析相同.
------------------------------------------------------------------------
【版权声明】本文仅属于技术交流,如有转载请注明出处.
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
上传的附件: