小菜对 SomkeFX 的 KeygenMe v1.0 的简单算法分析过程
本帖最后由 cxj98 于 2014-3-9 21:05 编辑本小菜初学算法分析,所以到处网上搜索一些简单的 KeygenMe。功夫不负有心人,终于在某 CrackMe 网站找到一款比较适合初学者入门的算法分析软件。
下面本小菜就开始这个 KeygenMe 的分析计算过程。
主程序载入OD后,然后F9直接跑起来,习惯性地输入用户名:cxj98,假码:1234567890,点击 Unlock 按扭,弹出错误提示:
---------------------------
Invalid Serial
---------------------------
Insert Coin Try Again!
---------------------------
OK
---------------------------
有错误提示框,好办,下 bp MessageboxA 断点,重新点击 Unlock 按扭。
程序果断中断下来,断在
76DFFD1E >8BFF MOV EDI, EDI ; smokefx.004589F8
76DFFD20 55 PUSH EBP
76DFFD21 8BEC MOV EBP, ESP
76DFFD23 6A 00 PUSH 0x0
76DFFD25 FF75 14 PUSH DWORD PTR SS:
76DFFD28 FF75 10 PUSH DWORD PTR SS:
76DFFD2B FF75 0C PUSH DWORD PTR SS:
76DFFD2E FF75 08 PUSH DWORD PTR SS:
76DFFD31 E8 A0FFFFFF CALL user32.MessageBoxExA
76DFFD36 5D POP EBP
右下角堆栈中右键菜单里选择反汇编窗口中跟随,
0018FAF4 004545BF/CALL 到 MessageBoxA 来自 smokefx.004545BA
0018FAF8 000E1C24|hOwner = 000E1C24 ('SmokeFX',class='TApplication')
0018FAFC 01C89A7C|Text = "Insert Coin Try Again!"
0018FB00 004589F8|Title = "Invalid Serial"
0018FB04 00000030\Style = MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL
0018FB08 0018FB80指向下一个 SEH 记录的指针
0018FB0C 00454629SE处理程序
0018FB10 0018FB74
来到
004545B0|.53 PUSH EBX ; /Style
004545B1|.57 PUSH EDI ; |Title
004545B2|.56 PUSH ESI ; |Text
004545B3|.8B45 FC MOV EAX, DWORD PTR SS: ; |
004545B6|.8B40 30 MOV EAX, DWORD PTR DS: ; |
004545B9|.50 PUSH EAX ; |hOwner
004545BA|.E8 C91FFBFF CALL <JMP.&user32.MessageBoxA> ; \MessageBoxA
往上找段首:
004544D4/[ DISCUZ_CODE_88 ]nbsp; 55 PUSH EBP ;// 段首
004544D5|.8BEC MOV EBP, ESP
004544D7|.83C4 AC ADD ESP, -0x54
004544DA|.53 PUSH EBX
发现多处调用:
本地调用来自 004546D1, 0045878D, 00458868, 004588EB, 00458938, 00458982
不管是正确提示,错误提示,注册码长度不对提示,都会调到到这里,习惯性地按下 Ctrl + K, 打开 查看调用树,如下:
Call tree
调用来自 函数过程 调用 注释
smokefx.004546D1 smokefx.004544D4 > smokefx.00402278 ???
smokefx.0045878D > smokefx.004026DC
smokefx.00458868 > smokefx.004027C0
smokefx.004588EB > smokefx.00402818
smokefx.00458938 > smokefx.00403AC8 Leaf
smokefx.00458982 > smokefx.00403AF0 ???
> smokefx.00403C60 Leaf
> smokefx.00403CBC Leaf
> smokefx.00403CEC
> smokefx.00403D78
> smokefx.00403E50
> smokefx.00403E5C
> smokefx.00405464 ???
> smokefx.00405BAC
> smokefx.00405BB8 Leaf
> smokefx.00405BC0
> smokefx.00405C04
smokefx.0044B168 Leaf
smokefx.0044B170 Leaf
smokefx.0044B24C ???
smokefx.0044B300
smokefx.004533E8 Leaf
> kernel32.TlsGetValue ???
> kernel32.WriteFile ???
> kernel32.TlsSetValue ???
> kernel32.LocalAlloc ???
> kernel32.FreeLibrary ???
> kernel32.GetStdHandle ???
> user32.IsWindow ???
user32.GetWindowRect ???
user32.SetWindowPos ???
> user32.EnableWindow ???
user32.SetActiveWindow ???
user32.GetActiveWindow ???
user32.MessageBoxA ???
未知目标
右键菜单中,选择 在每个调用上设置断点,然后继续 F9 跑起来,再次点击 Unlock 按扭,看看到底先在哪个调用上断下来。
经过分析,发现果断断在了如下位置:
004588F5|> \6A 30 PUSH 0x30 ;// 注册失败提示处
004588F7|.8D4D D4 LEA ECX, DWORD PTR SS:
004588FA|.A1 E0A14500 MOV EAX, DWORD PTR DS:
004588FF|.8B00 MOV EAX, DWORD PTR DS:
00458901|.8B80 FC020000 MOV EAX, DWORD PTR DS:
00458907|.8B80 18020000 MOV EAX, DWORD PTR DS:
0045890D|.BA 05000000 MOV EDX, 0x5
00458912|.8B18 MOV EBX, DWORD PTR DS:
00458914|.FF53 0C CALL NEAR DWORD PTR DS:
00458917|.8B45 D4 MOV EAX, DWORD PTR SS:
0045891A|.8D55 D8 LEA EDX, DWORD PTR SS:
0045891D|.E8 FEF9FFFF CALL smokefx.00458320
00458922|.8B45 D8 MOV EAX, DWORD PTR SS: ;// 注册码不正确,请重试!
00458925|.E8 FEB9FAFF CALL smokefx.00404328
0045892A|.8BD0 MOV EDX, EAX
0045892C|.B9 F8894500 MOV ECX, smokefx.004589F8
00458931|.A1 C4A04500 MOV EAX, DWORD PTR DS:
00458936|.8B00 MOV EAX, DWORD PTR DS:
00458938|.E8 97BBFFFF CALL smokefx.004544D4 ;// 经过运行,发现果断在此处断了下来。
往上找段首,然后疯狂按 F8 一路分析下去:
004587CC/.55 PUSH EBP ;// 段首
004587CD|.8BEC MOV EBP, ESP
004587CF|.B9 06000000 MOV ECX, 0x6
004587D4|>6A 00 /PUSH 0x0
004587D6|.6A 00 |PUSH 0x0
004587D8|.49 |DEC ECX
004587D9|.^ 75 F9 \JNZ SHORT smokefx.004587D4
004587DB|.51 PUSH ECX
004587DC|.53 PUSH EBX
004587DD|.8BD8 MOV EBX, EAX
004587DF|.33C0 XOR EAX, EAX
004587E1|.55 PUSH EBP
004587E2|.68 D4894500 PUSH smokefx.004589D4
004587E7|.64:FF30 PUSH DWORD PTR FS:
004587EA|.64:8920 MOV DWORD PTR FS:, ESP
004587ED|.8D55 FC LEA EDX, DWORD PTR SS:
004587F0|.8B83 14030000 MOV EAX, DWORD PTR DS:
004587F6|.E8 CDBEFDFF CALL smokefx.004346C8
004587FB|.837D FC 00 CMP DWORD PTR SS:, 0x0 ;// 用户名输入了木有?
004587FF|.0F84 3A010000 JE smokefx.0045893F ;// 木有的话,跳到提示你要输入用户名处,否则工作继续。
00458805|.8D55 F8 LEA EDX, DWORD PTR SS:
00458808|.8B83 14030000 MOV EAX, DWORD PTR DS:
0045880E|.E8 B5BEFDFF CALL smokefx.004346C8
00458813|.8B45 F8 MOV EAX, DWORD PTR SS:
00458816|.E8 0DBBFAFF CALL smokefx.00404328
0045881B|.E8 ECFBFAFF CALL smokefx.0040840C
00458820|.83F8 04 CMP EAX, 0x4 ;// 用户名长度是否大于4位数?
00458823|.73 4D JNB SHORT smokefx.00458872 ;// 如果大于4位就跳,否则执行下面的出错提示
00458825|.6A 10 PUSH 0x10
00458827|.8D4D F0 LEA ECX, DWORD PTR SS:
0045882A|.A1 E0A14500 MOV EAX, DWORD PTR DS:
0045882F|.8B00 MOV EAX, DWORD PTR DS:
00458831|.8B80 FC020000 MOV EAX, DWORD PTR DS:
00458837|.8B80 18020000 MOV EAX, DWORD PTR DS:
0045883D|.BA 04000000 MOV EDX, 0x4
00458842|.8B18 MOV EBX, DWORD PTR DS:
00458844|.FF53 0C CALL NEAR DWORD PTR DS:
00458847|.8B45 F0 MOV EAX, DWORD PTR SS:
0045884A|.8D55 F4 LEA EDX, DWORD PTR SS:
0045884D|.E8 CEFAFFFF CALL smokefx.00458320
00458852|.8B45 F4 MOV EAX, DWORD PTR SS: ;// 出错:用户名字符数必须大于4位数
00458855|.E8 CEBAFAFF CALL smokefx.00404328
0045885A|.8BD0 MOV EDX, EAX
0045885C|.B9 E0894500 MOV ECX, smokefx.004589E0 ;ASCII 53,"mokeFX ERROR"
00458861|.A1 C4A04500 MOV EAX, DWORD PTR DS:
00458866|.8B00 MOV EAX, DWORD PTR DS:
00458868|.E8 67BCFFFF CALL smokefx.004544D4 ;// 调用 出错提示框
0045886D|.E9 15010000 JMP smokefx.00458987
00458872|>8D55 EC LEA EDX, DWORD PTR SS: ;// 用户名如果大于4位数,则从这里继续往下执行。
00458875|.8B83 18030000 MOV EAX, DWORD PTR DS:
0045887B|.E8 48BEFDFF CALL smokefx.004346C8
00458880|.8B45 EC MOV EAX, DWORD PTR SS: ;// 获取 假码给 EAX
00458883|.50 PUSH EAX
00458884|.8D55 E4 LEA EDX, DWORD PTR SS:
00458887|.8B83 14030000 MOV EAX, DWORD PTR DS:
0045888D|.E8 36BEFDFF CALL smokefx.004346C8
00458892|.8B45 E4 MOV EAX, DWORD PTR SS: ;// 获取 用户名给 EAX
00458895|.8D55 E8 LEA EDX, DWORD PTR SS:
00458898|.E8 4BFBFFFF CALL smokefx.004583E8 ;// 核心算法,必须 F7 进入瞅瞅。
F8 走到核心算法,按 F7 进去瞅瞅吧!然后又是从算法的段首开始,一路疯狂地按 F8 继续分析下去:
004583E8/[ DISCUZ_CODE_93 ]nbsp; 55 PUSH EBP ;// F7 进入后,这里就是算法的段首
004583E9|.8BEC MOV EBP, ESP
004583EB|.33C9 XOR ECX, ECX
004583ED|.51 PUSH ECX
004583EE|.51 PUSH ECX
004583EF|.51 PUSH ECX
004583F0|.51 PUSH ECX
004583F1|.51 PUSH ECX
004583F2|.53 PUSH EBX
004583F3|.56 PUSH ESI
004583F4|.8BF2 MOV ESI, EDX
004583F6|.8945 FC MOV DWORD PTR SS:, EAX
004583F9|.8B45 FC MOV EAX, DWORD PTR SS:
004583FC|.E8 17BFFAFF CALL smokefx.00404318
00458401|.33C0 XOR EAX, EAX ;// EAX 与 EAX 异或,相同值为 0
00458403|.55 PUSH EBP
00458404|.68 85844500 PUSH smokefx.00458485
00458409|.64:FF30 PUSH DWORD PTR FS:
0045840C|.64:8920 MOV DWORD PTR FS:, ESP
0045840F|.8B45 FC MOV EAX, DWORD PTR SS: ;// 用户名给 EAX
00458412|.E8 11BFFAFF CALL smokefx.00404328
00458417|.E8 F0FFFAFF CALL smokefx.0040840C
0045841C|.8BD8 MOV EBX, EAX ;// 用户名长度给 EBX
0045841E|.8D55 F8 LEA EDX, DWORD PTR SS:
00458421|.8BC3 MOV EAX, EBX ;// 用户名长度又给 EAX
00458423|.E8 B4F9FAFF CALL smokefx.00407DDC
00458428|.FF75 F8 PUSH DWORD PTR SS: ;// 长度值 (即:cxj98 = 5)
0045842B|.8D55 F4 LEA EDX, DWORD PTR SS:
0045842E|.69C3 9A020000 IMUL EAX, EBX, 0x29A ;// EAX= EBX * 666 (EBX 为用户名长度)
00458434|.E8 A3F9FAFF CALL smokefx.00407DDC
00458439|.FF75 F4 PUSH DWORD PTR SS: ;// 计算出值 (用户名 cxj98 为5位数, 5 * 666 = 3330)
0045843C|.8D55 F0 LEA EDX, DWORD PTR SS:
0045843F|.69C3 FA000000 IMUL EAX, EBX, 0xFA ;// EAX = EBX * 250 (EBX 为用户名长度)
00458445|.E8 92F9FAFF CALL smokefx.00407DDC
0045844A|.FF75 F0 PUSH DWORD PTR SS: ;// 计算出值 (用户名 cxj98 为5位数, 5 * 250 = 1250)
0045844D|.8D55 EC LEA EDX, DWORD PTR SS:
00458450|.69C3 10270000 IMUL EAX, EBX, 0x2710 ;// EAX= EBX * 10000 (EBX 为用户名长度)
00458456|.E8 81F9FAFF CALL smokefx.00407DDC
0045845B|.FF75 EC PUSH DWORD PTR SS: ;// 计算出值 (用户名 cxj98 为5位数, 5 * 10000 = 50000)
0045845E|.8BC6 MOV EAX, ESI
00458460|.BA 04000000 MOV EDX, 0x4
00458465|.E8 7EBDFAFF CALL smokefx.004041E8
0045846A|.33C0 XOR EAX, EAX
0045846C|.5A POP EDX
0045846D|.59 POP ECX
0045846E|.59 POP ECX
0045846F|.64:8910 MOV DWORD PTR FS:, EDX
00458472|.68 8C844500 PUSH smokefx.0045848C
00458477|>8D45 EC LEA EAX, DWORD PTR SS:
0045847A|.BA 05000000 MOV EDX, 0x5
0045847F|.E8 08BAFAFF CALL smokefx.00403E8C ;// 注册码循环比较 call, 这里可以 F7 进入瞅瞅
00458484\.C3 RETN
00458485 .^ E9 E2B3FAFF JMP smokefx.0040386C
0045848A .^ EB EB JMP SHORT smokefx.00458477
0045848C .5E POP ESI
0045848D .5B POP EBX
0045848E .8BE5 MOV ESP, EBP
00458490 .5D POP EBP
00458491 .C3 RETN
F8走到上面这里,也就走出了整个核心算法,来到下面的地址,还是继续疯狂按 F8 一路分析下去:
0045889D|.8B55 E8 MOV EDX, DWORD PTR SS: ;// 弹出真码,(即:53330125050000),此处可内存注册机
004588A0|.58 POP EAX ;// EAX 弹出假码 (即:1234567890)
004588A1|.E8 CEB9FAFF CALL smokefx.00404274 ;// 真假码比较 call,此处无须 F7 进入瞅瞅,可以略过,当然有兴趣的也可以进去一观到底。
004588A6|.75 4D JNZ SHORT smokefx.004588F5 ;// 如果真假码不匹配,则跳向 注册码错误 提示处!
004588A8|.6A 40 PUSH 0x40 ;// 注册成功提示处
004588AA|.8D4D DC LEA ECX, DWORD PTR SS:
004588AD|.A1 E0A14500 MOV EAX, DWORD PTR DS:
004588B2|.8B00 MOV EAX, DWORD PTR DS:
004588B4|.8B80 FC020000 MOV EAX, DWORD PTR DS:
004588BA|.8B80 18020000 MOV EAX, DWORD PTR DS:
004588C0|.BA 06000000 MOV EDX, 0x6
004588C5|.8B18 MOV EBX, DWORD PTR DS:
004588C7|.FF53 0C CALL NEAR DWORD PTR DS:
004588CA|.8B45 DC MOV EAX, DWORD PTR SS:
004588CD|.8D55 E0 LEA EDX, DWORD PTR SS:
004588D0|.E8 4BFAFFFF CALL smokefx.00458320
004588D5|.8B45 E0 MOV EAX, DWORD PTR SS: ;// 恭喜你成功计算出注册码。
004588D8|.E8 4BBAFAFF CALL smokefx.00404328
004588DD|.8BD0 MOV EDX, EAX
004588DF|.B9 F0894500 MOV ECX, smokefx.004589F0
004588E4|.A1 C4A04500 MOV EAX, DWORD PTR DS:
004588E9|.8B00 MOV EAX, DWORD PTR DS:
004588EB|.E8 E4BBFFFF CALL smokefx.004544D4
004588F0|.E9 92000000 JMP smokefx.00458987
004588F5|>6A 30 PUSH 0x30 ;// 注册失败提示处
004588F7|.8D4D D4 LEA ECX, DWORD PTR SS:
004588FA|.A1 E0A14500 MOV EAX, DWORD PTR DS:
004588FF|.8B00 MOV EAX, DWORD PTR DS:
00458901|.8B80 FC020000 MOV EAX, DWORD PTR DS:
00458907|.8B80 18020000 MOV EAX, DWORD PTR DS:
0045890D|.BA 05000000 MOV EDX, 0x5
00458912|.8B18 MOV EBX, DWORD PTR DS:
00458914|.FF53 0C CALL NEAR DWORD PTR DS:
00458917|.8B45 D4 MOV EAX, DWORD PTR SS:
0045891A|.8D55 D8 LEA EDX, DWORD PTR SS:
0045891D|.E8 FEF9FFFF CALL smokefx.00458320
00458922|.8B45 D8 MOV EAX, DWORD PTR SS: ;// 注册码不正确,请重试!
00458925|.E8 FEB9FAFF CALL smokefx.00404328
0045892A|.8BD0 MOV EDX, EAX
0045892C|.B9 F8894500 MOV ECX, smokefx.004589F8
00458931|.A1 C4A04500 MOV EAX, DWORD PTR DS:
00458936|.8B00 MOV EAX, DWORD PTR DS:
00458938|.E8 97BBFFFF CALL smokefx.004544D4 ;// 经过运行,发现果断在此处断了下来。
0045893D|.EB 48 JMP SHORT smokefx.00458987
0045893F|>6A 20 PUSH 0x20
00458941|.8D4D CC LEA ECX, DWORD PTR SS:
00458944|.A1 E0A14500 MOV EAX, DWORD PTR DS:
00458949|.8B00 MOV EAX, DWORD PTR DS:
0045894B|.8B80 FC020000 MOV EAX, DWORD PTR DS:
00458951|.8B80 18020000 MOV EAX, DWORD PTR DS:
00458957|.BA 03000000 MOV EDX, 0x3
0045895C|.8B18 MOV EBX, DWORD PTR DS:
0045895E|.FF53 0C CALL NEAR DWORD PTR DS:
00458961|.8B45 CC MOV EAX, DWORD PTR SS:
00458964|.8D55 D0 LEA EDX, DWORD PTR SS:
00458967|.E8 B4F9FFFF CALL smokefx.00458320
0045896C|.8B45 D0 MOV EAX, DWORD PTR SS:
0045896F|.E8 B4B9FAFF CALL smokefx.00404328
00458974|.8BD0 MOV EDX, EAX
00458976|.B9 F0894500 MOV ECX, smokefx.004589F0
0045897B|.A1 C4A04500 MOV EAX, DWORD PTR DS:
00458980|.8B00 MOV EAX, DWORD PTR DS:
00458982|.E8 4DBBFFFF CALL smokefx.004544D4
00458987|>33C0 XOR EAX, EAX
00458989|.5A POP EDX
0045898A|.59 POP ECX
0045898B|.59 POP ECX
0045898C|.64:8910 MOV DWORD PTR FS:, EDX
0045898F|.68 DB894500 PUSH smokefx.004589DB
00458994|>8D45 CC LEA EAX, DWORD PTR SS:
00458997|.BA 06000000 MOV EDX, 0x6
0045899C|.E8 EBB4FAFF CALL smokefx.00403E8C
004589A1|.8D45 E4 LEA EAX, DWORD PTR SS:
004589A4|.E8 BFB4FAFF CALL smokefx.00403E68
004589A9|.8D45 E8 LEA EAX, DWORD PTR SS:
004589AC|.E8 B7B4FAFF CALL smokefx.00403E68
004589B1|.8D45 EC LEA EAX, DWORD PTR SS:
004589B4|.E8 AFB4FAFF CALL smokefx.00403E68
004589B9|.8D45 F0 LEA EAX, DWORD PTR SS:
004589BC|.BA 02000000 MOV EDX, 0x2
004589C1|.E8 C6B4FAFF CALL smokefx.00403E8C
004589C6|.8D45 F8 LEA EAX, DWORD PTR SS:
004589C9|.BA 02000000 MOV EDX, 0x2
004589CE|.E8 B9B4FAFF CALL smokefx.00403E8C
004589D3\.C3 RETN
至此,整个算法分析完成,所以对算法有了一个大概的了解。
下面我们就来总结一下这个 KeygenMe 的算法:
注册码 = 用户名长度 & 用户名长度 * 666 & 用户名长度 * 250 & 用户名长度 * 10000
即: sn = lenth(UserName) & Lenth(UserName) * 666 & Lenth(UserName) * 250 & Lenth(UserName) * 10000
因为 cxj98 = 5 位数,
所以 5 & 5 * 666 & 5 * 250 & 5 * 10000 = 5 3330 1250 50000
因此计算出来的注册码为:53330125050000
将计算出来的注册码输入进去,再次点击 Unlock 按扭,果断弹出:
---------------------------
SmokeFX
---------------------------
Congratulations you beat the code :) regards, Wayne Modz
---------------------------
OK
---------------------------
完毕收工。
本文由 cxj98 原创发表,如果要转载,请保留完整的破文内容等信息,谢谢。
KeygenMe 本地下载:
第一次离大牛这么近 牛
都分析算法了 大牛啊,又看到你了。在那都能看到你犀利的身影啊。 膜拜的。收我为徒吧。。{:lol:}{:lol:}{:lol:}{:lol:}{:lol:} cxj98是个大牛呀,吾爱常见。 都往算法方向了,这个非常耗费时间的。 这样可以更好的学习下,谢谢老师。
第一次离大牛这么近 不错,不错,支持下 来学习一下了,支持大牛
页:
[1]
2