【文章标题】: 一个名为CKGM1a的CrackMe算法分析
【文章作者】: Root
【作者邮箱】: cppcoffee@gmail.com
【软件名称】: CKGM1a
【下载地址】: 附件
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
闲话一则: 由于在2010年末裸辞了,比较有多余的时间来充电了(其实鸭梨也挺大的).每天都会看下订阅的RSS,看到http://crackmes.de/更新了,随手就下载了一个CrackMe来分析.
未加壳,嘿嘿.以下是分析过程:
-------------------------->8------------------------------------------------------------
00401682 /. 55 PUSH EBP ; 对话框回调函数入口
00401683 |. 89E5 MOV EBP,ESP
00401685 |. 83EC 28 SUB ESP,0x28
00401688 |. 895D F4 MOV DWORD PTR SS:[EBP-0xC],EBX
0040168B |. 8975 F8 MOV DWORD PTR SS:[EBP-0x8],ESI
0040168E |. 897D FC MOV DWORD PTR SS:[EBP-0x4],EDI
00401691 |. 8B7D 08 MOV EDI,DWORD PTR SS:[EBP+0x8] ; hWnd
00401694 |. 8B45 0C MOV EAX,DWORD PTR SS:[EBP+0xC] ; uMsg
00401697 |. 8B55 10 MOV EDX,DWORD PTR SS:[EBP+0x10] ; wParam
0040169A |. 3D 11010000 CMP EAX,0x111 ; MSG == WM_COMMAND
0040169F |. 0F84 EF000000 JE CKGM1a.00401794 ; 是WM_COMMAND消息则跳
..........................................................................; 中间省略一堆代码
00401794 |> 83FA 01 CMP EDX,0x1 ; wParam == IDOK
00401797 |. 74 0E JE SHORT CKGM1a.004017A7 ; 跳转到Check Serial按钮点击
00401799 |. 83FA 02 CMP EDX,0x2 ; wParam == IDCANCEL
0040179C |. 0F84 25010000 JE CKGM1a.004018C7 ; 跳转到结束对话框语句
004017A2 |. E9 3A010000 JMP CKGM1a.004018E1
004017A7 |> C74424 04 ED0>MOV DWORD PTR SS:[ESP+0x4],0x3ED ; |Check Serial按钮点击处理
004017AF |. 893C24 MOV DWORD PTR SS:[ESP],EDI ; |
004017B2 |. E8 99080000 CALL <JMP.&USER32.GetDlgItem> ; \获取Serial Edit窗口句柄
004017B7 |. 83EC 08 SUB ESP,0x8
004017BA |. 8945 F0 MOV DWORD PTR SS:[EBP-0x10],EAX ; |
004017BD |. 890424 MOV DWORD PTR SS:[ESP],EAX ; |
004017C0 |. E8 9B080000 CALL <JMP.&USER32.GetWindowTextLengthA> ; \获取输入的序列号长度
004017C5 |. 83EC 04 SUB ESP,0x4
004017C8 |. 85C0 TEST EAX,EAX ; |输入的序列号长度是否0
004017CA |. 75 2D JNZ SHORT CKGM1a.004017F9 ; |序列号长度不为0则跳
004017CC |. C74424 0C 100>MOV DWORD PTR SS:[ESP+0xC],0x10 ; |
004017D4 |. C74424 08 794>MOV DWORD PTR SS:[ESP+0x8],CKGM1a.00404079 ; |ASCII "Error"
004017DC |. C74424 04 804>MOV DWORD PTR SS:[ESP+0x4],CKGM1a.00404080 ; |ASCII "Please enter your serial number."
004017E4 |. 893C24 MOV DWORD PTR SS:[ESP],EDI ; |
004017E7 |. E8 84080000 CALL <JMP.&USER32.MessageBoxA> ; \MessageBoxA
004017EC |. 83EC 10 SUB ESP,0x10
004017EF |. B8 FFFFFFFF MOV EAX,-0x1
004017F4 |. E9 ED000000 JMP CKGM1a.004018E6
004017F9 |> 83F8 63 CMP EAX,0x63 ; |序列号长度与100比较
004017FC |. 7E 2D JLE SHORT CKGM1a.0040182B ; |小于等于100则跳
004017FE |. C74424 0C 100>MOV DWORD PTR SS:[ESP+0xC],0x10 ; |
00401806 |. C74424 08 794>MOV DWORD PTR SS:[ESP+0x8],CKGM1a.00404079 ; |ASCII "Error"
0040180E |. C74424 04 A14>MOV DWORD PTR SS:[ESP+0x4],CKGM1a.004040A1 ; |ASCII "Serial is too long..."
00401816 |. 893C24 MOV DWORD PTR SS:[ESP],EDI ; |
00401819 |. E8 52080000 CALL <JMP.&USER32.MessageBoxA> ; \MessageBoxA
0040181E |. 83EC 10 SUB ESP,0x10
00401821 |. B8 FFFFFFFF MOV EAX,-0x1
00401826 |. E9 BB000000 JMP CKGM1a.004018E6
0040182B |> 8D70 01 LEA ESI,DWORD PTR DS:[EAX+0x1] ; |||ESI = 序列号长度增加1,以存放'0'结尾的字符串
0040182E |. 893424 MOV DWORD PTR SS:[ESP],ESI ; |||
00401831 |. E8 6A070000 CALL <JMP.&msvcrt.malloc> ; ||\分配指定的长度
00401836 |. 89C3 MOV EBX,EAX ; ||
00401838 |. 897424 08 MOV DWORD PTR SS:[ESP+0x8],ESI ; ||
0040183C |. C74424 04 000>MOV DWORD PTR SS:[ESP+0x4],0x0 ; ||
00401844 |. 890424 MOV DWORD PTR SS:[ESP],EAX ; ||
00401847 |. E8 44070000 CALL <JMP.&msvcrt.memset> ; |\将分配的内存全部置0
0040184C |. C74424 08 640>MOV DWORD PTR SS:[ESP+0x8],0x64 ; |
00401854 |. 895C24 04 MOV DWORD PTR SS:[ESP+0x4],EBX ; |
00401858 |. 8B45 F0 MOV EAX,DWORD PTR SS:[EBP-0x10] ; |
0040185B |. 890424 MOV DWORD PTR SS:[ESP],EAX ; |
0040185E |. E8 1D080000 CALL <JMP.&USER32.GetWindowTextA> ; \获取序列号长度,存放到刚才分配的内存空间中
00401863 |. 83EC 0C SUB ESP,0xC
00401866 |. 891C24 MOV DWORD PTR SS:[ESP],EBX ; 将序列号内存地址存入堆栈
00401869 |. E8 C4FAFFFF CALL <CKGM1a.IsValidSerial> ; 是否有效的序列号(见下面分析)
0040186E |. 83F8 FF CMP EAX,-0x1 ; |根据返回值判断是否有效的序列号
00401871 |. 75 2A JNZ SHORT CKGM1a.0040189D ; |
00401873 |. C74424 0C 100>MOV DWORD PTR SS:[ESP+0xC],0x10 ; |无效序列号弹窗
0040187B |. C74424 08 794>MOV DWORD PTR SS:[ESP+0x8],CKGM1a.00404079 ; |ASCII "Error"
00401883 |. C74424 04 B74>MOV DWORD PTR SS:[ESP+0x4],CKGM1a.004040B7 ; |ASCII "Invalid serial number."
0040188B |. 893C24 MOV DWORD PTR SS:[ESP],EDI ; |
0040188E |. E8 DD070000 CALL <JMP.&USER32.MessageBoxA> ; \MessageBoxA
00401893 |. 83EC 10 SUB ESP,0x10
00401896 |. B8 FFFFFFFF MOV EAX,-0x1
0040189B |. EB 49 JMP SHORT CKGM1a.004018E6
0040189D |> C74424 0C 300>MOV DWORD PTR SS:[ESP+0xC],0x30 ; |正确序列号弹窗
004018A5 |. C74424 08 CE4>MOV DWORD PTR SS:[ESP+0x8],CKGM1a.004040CE ; |ASCII "Congratulation!"
004018AD |. C74424 04 E04>MOV DWORD PTR SS:[ESP+0x4],CKGM1a.004040E0 ; |ASCII "You have found a valid serial!"
004018B5 |. 893C24 MOV DWORD PTR SS:[ESP],EDI ; |
004018B8 |. E8 B3070000 CALL <JMP.&USER32.MessageBoxA> ; \MessageBoxA
004018BD |. 83EC 10 SUB ESP,0x10
004018C0 |. B8 FFFFFFFF MOV EAX,-0x1
004018C5 |. EB 1F JMP SHORT CKGM1a.004018E6
004018C7 |> C74424 04 000>MOV DWORD PTR SS:[ESP+0x4],0x0 ; |IDCANCEL按钮处理(Quit)
004018CF |. 893C24 MOV DWORD PTR SS:[ESP],EDI ; |hDlgWnd
004018D2 |. E8 B9070000 CALL <JMP.&USER32.EndDialog> ; \EndDialog
004018D7 |. 83EC 08 SUB ESP,0x8
004018DA |. B8 00000000 MOV EAX,0x0 ; return 0
004018DF |. EB 05 JMP SHORT CKGM1a.004018E6
004018E1 |> B8 00000000 MOV EAX,0x0
004018E6 |> 8B5D F4 MOV EBX,DWORD PTR SS:[EBP-0xC]
004018E9 |. 8B75 F8 MOV ESI,DWORD PTR SS:[EBP-0x8]
004018EC |. 8B7D FC MOV EDI,DWORD PTR SS:[EBP-0x4]
004018EF |. 89EC MOV ESP,EBP
004018F1 |. 5D POP EBP
004018F2 \. C2 1000 RETN 0x10
-------------------------->8------------------------------------------------------------
; IsValidSerial 函数(是否有效的序列号)
<CKGM1a.I>/$ 55 PUSH EBP ; 序列号是否有效,函数入口点
00401333 |. 89E5 MOV EBP,ESP
00401335 |. 57 PUSH EDI
00401336 |. 56 PUSH ESI
00401337 |. 53 PUSH EBX
00401338 |. 83EC 7C SUB ESP,0x7C
0040133B |. 8B5D 08 MOV EBX,DWORD PTR SS:[EBP+0x8] ; |EBX = 输入的序列号
0040133E |. 66:C745 D8 00>MOV WORD PTR SS:[EBP-0x28],0x0 ; |
00401344 |. C645 DA 00 MOV BYTE PTR SS:[EBP-0x26],0x0 ; |
00401348 |. 8D7D A8 LEA EDI,DWORD PTR SS:[EBP-0x58] ; |SS:[EBP-0x58] = 输入的序列号
0040134B |. FC CLD ; |
0040134C |. B9 08000000 MOV ECX,0x8 ; |
00401351 |. B8 00000000 MOV EAX,0x0 ; |
00401356 |. F3:AB REP STOS DWORD PTR ES:[EDI] ; |清空SS:[EBP-0x58]的内容
00401358 |. C607 00 MOV BYTE PTR DS:[EDI],0x0 ; |
0040135B |. 89DF MOV EDI,EBX ; |EDI = 输入的序列号
0040135D |. B9 FFFFFFFF MOV ECX,-0x1 ; |
00401362 |. F2:AE REPNE SCAS BYTE PTR ES:[EDI] ; |计算输入序列号的长度
00401364 |. BA FFFFFFFF MOV EDX,-0x1 ; |
00401369 |. 83F9 D3 CMP ECX,-0x2D ; |输入序列号长度是否是45个
0040136C |. 0F85 0C020000 JNZ CKGM1a.0040157E ; |如果不是44个字符,则结束
00401372 |. 8D55 A8 LEA EDX,DWORD PTR SS:[EBP-0x58] ; |
00401375 |. 8D45 C0 LEA EAX,DWORD PTR SS:[EBP-0x40] ; |
00401378 |. 894424 18 MOV DWORD PTR SS:[ESP+0x18],EAX ; |存放第五组序列号的缓冲区(长度8)
0040137C |. 8D45 B8 LEA EAX,DWORD PTR SS:[EBP-0x48] ; |
0040137F |. 894424 14 MOV DWORD PTR SS:[ESP+0x14],EAX ; |存放第四组序列号的缓冲区(长度8)
00401383 |. 8D45 B0 LEA EAX,DWORD PTR SS:[EBP-0x50] ; |
00401386 |. 894424 10 MOV DWORD PTR SS:[ESP+0x10],EAX ; |存放第三组序列号的缓冲区(长度8)
0040138A |. 895424 0C MOV DWORD PTR SS:[ESP+0xC],EDX ; |存放第二组序列号的缓冲区(长度8)
0040138E |. 8D45 D8 LEA EAX,DWORD PTR SS:[EBP-0x28] ; |
00401391 |. 894424 08 MOV DWORD PTR SS:[ESP+0x8],EAX ; |存放第一组序列号的缓冲区(长度4)
00401395 |. C74424 04 004>MOV DWORD PTR SS:[ESP+0x4],CKGM1a.004040>; |ASCII "CKGM1%2s-%8s-%8s-%8s-%8s"
0040139D |. 891C24 MOV DWORD PTR SS:[ESP],EBX ; |
004013A0 |. E8 0B0C0000 CALL <JMP.&msvcrt.sscanf> ; \进行sscanf格式化
004013A5 |. BA FFFFFFFF MOV EDX,-0x1
004013AA |. 83F8 05 CMP EAX,0x5 ; 格式化是否完成
004013AD |. 0F85 CB010000 JNZ CKGM1a.0040157E ; 没有完成则Over
004013B3 |. C74424 04 A43>MOV DWORD PTR SS:[ESP+0x4],CKGM1a.004032>; 特征码字符串1: ACEGIKMOQSUWY(参数2)
004013BB |. 0FBE45 D8 MOVSX EAX,BYTE PTR SS:[EBP-0x28] ; 第一组序列号的第一个字符
004013BF |. 890424 MOV DWORD PTR SS:[ESP],EAX
004013C2 |. E8 8F020000 CALL <CKGM1a.IsCharacter> ; 字符是否在特征码中
{
; IsCharacter函数
<CKGM1a.I>/$ 55 PUSH EBP ; 函数功能: 字符是否在特征码中
00401657 |. 89E5 MOV EBP,ESP
00401659 |. 53 PUSH EBX
0040165A |. 8B45 0C MOV EAX,DWORD PTR SS:[EBP+0xC] ; 特征码字符串地址
0040165D |. 0FB64D 08 MOVZX ECX,BYTE PTR SS:[EBP+0x8] ; 所请求的字符
00401661 |. BB FFFFFFFF MOV EBX,-0x1 ; EBX: 存放返回值
00401666 |. BA 00000000 MOV EDX,0x0 ; 置计数器0
0040166B |> 380C02 /CMP BYTE PTR DS:[EDX+EAX],CL ; 字符与特征码进行比较
0040166E |. 75 07 |JNZ SHORT CKGM1a.00401677 ; 不相等则跳
00401670 |. BB 00000000 |MOV EBX,0x0 ; 置有效的返回值
00401675 |. EB 06 |JMP SHORT CKGM1a.0040167D
00401677 |> 42 |INC EDX ; 计数器增1(下一个特征码的位置)
00401678 |. 83FA 0C |CMP EDX,0xC ; 结束条件(特征码是否循环结束)
0040167B |.^ 7E EE \JLE SHORT CKGM1a.0040166B
0040167D |> 89D8 MOV EAX,EBX ; 将保存的返回值给EAX
0040167F |. 5B POP EBX
00401680 |. 5D POP EBP
00401681 \. C3 RETN
}
004013C7 |. BA FFFFFFFF MOV EDX,-0x1
004013CC |. 83F8 FF CMP EAX,-0x1
004013CF |. 0F84 A9010000 JE CKGM1a.0040157E ; 不在特征码中则Over
004013D5 |. C74424 04 B23>MOV DWORD PTR SS:[ESP+0x4],CKGM1a.004032>; 特征码字符串2: BDFHYLNPRTVXZ
004013DD |. 0FBE45 D9 MOVSX EAX,BYTE PTR SS:[EBP-0x27] ; 第一组序列号的第二个字符
004013E1 |. 890424 MOV DWORD PTR SS:[ESP],EAX
004013E4 |. E8 6D020000 CALL <CKGM1a.IsCharacter> ; 字符是否在特征码中(具体实现见上面的函数)
004013E9 |. BA FFFFFFFF MOV EDX,-0x1
004013EE |. 83F8 FF CMP EAX,-0x1
004013F1 |. 0F84 87010000 JE CKGM1a.0040157E ; 不在特征码中则Over
004013F7 |. /EB 1E JMP SHORT CKGM1a.00401417
004013F9 |> |BA FFFFFFFF MOV EDX,-0x1
004013FE |. |E9 7B010000 JMP CKGM1a.0040157E
00401403 |> |BA FFFFFFFF MOV EDX,-0x1
00401408 |. |E9 71010000 JMP CKGM1a.0040157E
0040140D |> |BA FFFFFFFF MOV EDX,-0x1
00401412 |. |E9 67010000 JMP CKGM1a.0040157E
00401417 |> \C74424 04 A43>MOV DWORD PTR SS:[ESP+0x4],CKGM1a.004032>; 特征码字符串1: ACEGIKMOQSUWY
0040141F |. 0FBE45 D8 MOVSX EAX,BYTE PTR SS:[EBP-0x28] ; 第一组序列号的第一个字符
00401423 |. 890424 MOV DWORD PTR SS:[ESP],EAX
00401426 |. E8 0F020000 CALL <CKGM1a.GetCharacterPos> ; 获取字符在特征码中的位置
{
; GetCharacterPos函数
<CKGM1a.G>/$ 55 PUSH EBP ; 函数功能: 获取字符在特征码中的位置
0040163B |. 89E5 MOV EBP,ESP
0040163D |. 8B4D 0C MOV ECX,DWORD PTR SS:[EBP+0xC] ; 特征码参数地址
00401640 |. 0FB655 08 MOVZX EDX,BYTE PTR SS:[EBP+0x8] ; 要查找的字符
00401644 |. B8 00000000 MOV EAX,0x0 ; 置计数器
00401649 |> 381408 /CMP BYTE PTR DS:[EAX+ECX],DL ; 字符与指定特征码进行比较
0040164C |. 74 06 |JE SHORT CKGM1a.00401654 ; 相等则跳
0040164E |. 40 |INC EAX ; 增加计数器
0040164F |. 83F8 0C |CMP EAX,0xC ; 结束条件
00401652 |.^ 7E F5 \JLE SHORT CKGM1a.00401649
00401654 |> 5D POP EBP
00401655 \. C3 RETN
}
0040142B |. 89C2 MOV EDX,EAX ; EDX = 字符在特征码的位置
0040142D |. BF 00000000 MOV EDI,0x0 ; 计数器 i = 0
00401432 |> 0FB682 A43240>/MOVZX EAX,BYTE PTR DS:[EDX+0x4032A4] ; EAX = 当前位置的特征码
00401439 |. 8887 18504000 |MOV BYTE PTR DS:[EDI+0x405018],AL ; 保存特征码数组1
0040143F |. 42 |INC EDX ; 位置增加1
00401440 |. 83FA 0D |CMP EDX,0xD ; 确定位置不超出范围
00401443 |. 0F95C0 |SETNE AL ; 根据Z标志位设置al的值
00401446 |. 0FB6C0 |MOVZX EAX,AL
00401449 |. F7D8 |NEG EAX ; 对EAX取反
0040144B |. 21C2 |AND EDX,EAX
0040144D |. 47 |INC EDI ; i++
0040144E |. 83FF 0C |CMP EDI,0xC ; i与12进行比较
00401451 |.^ 7E DF \JLE SHORT CKGM1a.00401432
00401453 |. C74424 04 B23>MOV DWORD PTR SS:[ESP+0x4],CKGM1a.004032>; 特征码2: BDFHYLNPRTVXZ
0040145B |. 0FBE45 D9 MOVSX EAX,BYTE PTR SS:[EBP-0x27] ; 第一组注册码第二个字符
0040145F |. 890424 MOV DWORD PTR SS:[ESP],EAX
00401462 |. E8 D3010000 CALL <CKGM1a.GetCharacterPos> ; 获取字符在特征码的位置(具体实现见上面的函数)
00401467 |. 89C2 MOV EDX,EAX
00401469 |. BF 00000000 MOV EDI,0x0 ; i = 0
0040146E |> 0FB682 B23240>/MOVZX EAX,BYTE PTR DS:[EDX+0x4032B2] ; EAX = 当前位置的特征码
00401475 |. 8887 26504000 |MOV BYTE PTR DS:[EDI+0x405026],AL ; 保存到特征码数组2
0040147B |. 42 |INC EDX ; 位置增加1
0040147C |. 83FA 0D |CMP EDX,0xD ; 确定位置不超出范围
0040147F |. 0F95C0 |SETNE AL ; 根据Z标志位设置al值
00401482 |. 0FB6C0 |MOVZX EAX,AL
00401485 |. F7D8 |NEG EAX ; 对EAX取反
00401487 |. 21C2 |AND EDX,EAX
00401489 |. 47 |INC EDI ; i++
0040148A |. 83FF 0C |CMP EDI,0xC ; i与12进行比较
0040148D |.^ 7E DF \JLE SHORT CKGM1a.0040146E
0040148F |. 8D7D A8 LEA EDI,DWORD PTR SS:[EBP-0x58] ; EDI = 第2,3,4,5组序列号起始地址
00401492 |. FC CLD
00401493 |. B9 FFFFFFFF MOV ECX,-0x1
00401498 |. B0 00 MOV AL,0x0
0040149A |. F2:AE REPNE SCAS BYTE PTR ES:[EDI]
0040149C |. F7D1 NOT ECX
0040149E |. 8D59 FF LEA EBX,DWORD PTR DS:[ECX-0x1] ; 以上代码是计算2,3,4,5组序列号的字符长度
004014A1 |. BF 00000000 MOV EDI,0x0 ; i = 0
004014A6 |. 39DF CMP EDI,EBX ; 长度是否为0
004014A8 |. 7D 42 JGE SHORT CKGM1a.004014EC ; 跳转到长度为0的处理
004014AA |> /F7C7 01000000 /TEST EDI,0x1 ; i整除2是否为0
004014B0 |. |74 17 |JE SHORT CKGM1a.004014C9 ; 结果为0则跳
004014B2 |. |C74424 04 265>|MOV DWORD PTR SS:[ESP+0x4],CKGM1a.00405>; ASCII "ZBDFHYLNPRTVX"
004014BA |. |0FBE442F A8 |MOVSX EAX,BYTE PTR DS:[EDI+EBP-0x58] ; EDI指定的序列号字符位置
004014BF |. |890424 |MOV DWORD PTR SS:[ESP],EAX
004014C2 |. |E8 8F010000 |CALL <CKGM1a.IsCharacter> ; 字符是否在序列号中
004014C7 |. |EB 15 |JMP SHORT CKGM1a.004014DE
004014C9 |> |C74424 04 185>|MOV DWORD PTR SS:[ESP+0x4],CKGM1a.00405>; ASCII "YACEGIKMOQSUW"
004014D1 |. |0FBE442F A8 |MOVSX EAX,BYTE PTR DS:[EDI+EBP-0x58] ; EDI指定的序列号字符位置
004014D6 |. |890424 |MOV DWORD PTR SS:[ESP],EAX
004014D9 |. |E8 78010000 |CALL <CKGM1a.IsCharacter> ; 序列号的字符是否在特征码中
004014DE |> |83F8 FF |CMP EAX,-0x1
004014E1 |.^|0F84 12FFFFFF |JE CKGM1a.004013F9 ; 不再特征码中则Over
004014E7 |. |47 |INC EDI ; i++
004014E8 |. |39DF |CMP EDI,EBX ; 序列号长度与i进行比较(保证不超出范围)
004014EA |.^\7C BE \JL SHORT CKGM1a.004014AA
004014EC |> C745 A4 FFFFF>MOV DWORD PTR SS:[EBP-0x5C],-0x1 ; 用来保存位置1变量,初始化操作
004014F3 |. C745 A0 FFFFF>MOV DWORD PTR SS:[EBP-0x60],-0x1 ; 用来保存位置2变量,初始化操作
004014FA |. BF 00000000 MOV EDI,0x0 ; 重置循环次数
004014FF |> /0FBE447D A8 /MOVSX EAX,BYTE PTR SS:[EBP+EDI*2-0x58] ; EAX = EDI指定的序列号组合位置字符
00401504 |. |0FBE5C7D A9 |MOVSX EBX,BYTE PTR SS:[EBP+EDI*2-0x57] ; EBX = EDI指定的序列号组合位置的后一个字符
00401509 |. C74424 04 185>|MOV DWORD PTR SS:[ESP+0x4],CKGM1a.00405018 ; 重组后的特征码1
00401511 |. 890424 |MOV DWORD PTR SS:[ESP],EAX
00401514 |. E8 21010000 |CALL <CKGM1a.GetCharacterPos> ; 得到字符在特征码中的位置
00401519 |. 89C6 |MOV ESI,EAX ; 保存到ESI中
0040151B |. C74424 04 265>|MOV DWORD PTR SS:[ESP+0x4],CKGM1a.00405026 ; 重组后的特征码2
00401523 |. |891C24 |MOV DWORD PTR SS:[ESP],EBX
00401526 |. |E8 0F010000 |CALL <CKGM1a.GetCharacterPos> ; 得到字符在特征码的位置
0040152B |. |89C3 |MOV EBX,EAX ; 保存到EBX中
0040152D |. C74424 08 003>|MOV DWORD PTR SS:[ESP+0x8],CKGM1a.00403000 ; 注意这个地址
-------------------------->8------------------------------------------------------------
去这个地址看看 db 403000:
00403000 01 00 00 00 01 00 00 00 01 00 00 00 01 00 00 00 ............
00403010 01 00 00 00 00 00 00 00 01 00 00 00 01 00 00 00 .............
00403020 01 00 00 00 01 00 00 00 01 00 00 00 01 00 00 00 ............
00403030 01 00 00 00 01 00 00 00 01 00 00 00 00 00 00 00 .............
00403040 00 00 00 00 01 00 00 00 01 00 00 00 01 00 00 00 .............
00403050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00403060 01 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 .............
00403070 01 00 00 00 01 00 00 00 01 00 00 00 00 00 00 00 .............
00403080 01 00 00 00 01 00 00 00 01 00 00 00 01 00 00 00 ............
00403090 01 00 00 00 01 00 00 00 01 00 00 00 01 00 00 00 ............
004030A0 01 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 ..............
004030B0 01 00 00 00 01 00 00 00 01 00 00 00 00 00 00 00 .............
004030C0 01 00 00 00 01 00 00 00 01 00 00 00 01 00 00 00 ............
004030D0 01 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 ..............
004030E0 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 ..............
004030F0 00 00 00 00 01 00 00 00 01 00 00 00 01 00 00 00 .............
00403100 01 00 00 00 01 00 00 00 01 00 00 00 01 00 00 00 ............
00403110 01 00 00 00 01 00 00 00 01 00 00 00 01 00 00 00 ............
00403120 00 00 00 00 00 00 00 00 01 00 00 00 01 00 00 00 ..............
00403130 00 00 00 00 00 00 00 00 01 00 00 00 01 00 00 00 ..............
00403140 01 00 00 00 01 00 00 00 01 00 00 00 01 00 00 00 ............
00403150 01 00 00 00 01 00 00 00 01 00 00 00 01 00 00 00 ............
00403160 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ...............
00403170 01 00 00 00 00 00 00 00 01 00 00 00 01 00 00 00 .............
00403180 01 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 ..............
00403190 00 00 00 00 01 00 00 00 01 00 00 00 01 00 00 00 .............
004031A0 01 00 00 00 01 00 00 00 01 00 00 00 01 00 00 00 ............
004031B0 00 00 00 00 00 00 00 00 01 00 00 00 01 00 00 00 ..............
004031C0 01 00 00 00 01 00 00 00 01 00 00 00 00 00 00 00 .............
004031D0 01 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 .............
004031E0 01 00 00 00 01 00 00 00 01 00 00 00 01 00 00 00 ............
004031F0 01 00 00 00 00 00 00 00 01 00 00 00 01 00 00 00 .............
00403200 01 00 00 00 01 00 00 00 01 00 00 00 00 00 00 00 .............
00403210 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ...............
00403220 01 00 00 00 01 00 00 00 01 00 00 00 01 00 00 00 ............
00403230 01 00 00 00 01 00 00 00 01 00 00 00 01 00 00 00 ............
00403240 01 00 00 00 01 00 00 00 01 00 00 00 01 00 00 00 ............
00403250 01 00 00 00 01 00 00 00 01 00 00 00 01 00 00 00 ............
00403260 00 00 00 00 01 00 00 00 01 00 00 00 00 00 00 00 ..............
00403270 01 00 00 00 01 00 00 00 01 00 00 00 01 00 00 00 ............
00403280 01 00 00 00 01 00 00 00 01 00 00 00 00 00 00 00 .............
00403290 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 ...............
004032A0 01 00 00 00 ...
Alt+M打开内存映射窗口,看下地址的信息:
Memory map, 条目 15
地址=00403000
大小=00001000 (4096.)
属主=CKGM1a 00400000
区段=.data
包含=数据
类型=Imag 01001002
访问=R
初始访问=RWE
根据上面的数据,得知403000是一个常量数组的地址.
处理后的数据(4字节长度):
1111101111111110011100001101111011111111100111101111110010100111111111110011001111111111100010111100011111110011111011011111101111101000111111111111111101101111111000011
目前还不知道它是干什么的,只能继续看代码:
-------------------------->8------------------------------------------------------------
00401535 |. 894424 04 |MOV DWORD PTR SS:[ESP+0x4],EAX ; EAX = 特征码位置1
00401539 |. 893424 |MOV DWORD PTR SS:[ESP],ESI ; ESI = 特征码位置2
0040153C |. E8 D9000000 |CALL <CKGM1a.IsValidPosValue> ; 是否有效的位置
{
; IsValidPosValue函数
<CKGM1a.I>/$ 55 PUSH EBP ; IsValidPosValue函数入口点
0040161B |. 89E5 MOV EBP,ESP
0040161D |. 8B45 0C MOV EAX,DWORD PTR SS:[EBP+0xC]
00401620 |. 8D1440 LEA EDX,DWORD PTR DS:[EAX+EAX*2] ; nCount = nPos2 + nPos2 * 2
00401623 |. 8D1490 LEA EDX,DWORD PTR DS:[EAX+EDX*4] ; nCount = nPos2 + nCount * 4
00401626 |. 0355 08 ADD EDX,DWORD PTR SS:[EBP+0x8] ; nCount += nPos1
00401629 |. 8B45 10 MOV EAX,DWORD PTR SS:[EBP+0x10]
0040162C |. 833C90 01 CMP DWORD PTR DS:[EAX+EDX*4],0x1 ; pdwPosArray[nCount] == 1 ??
00401630 |. 0F94C0 SETE AL ; 相等则置1
00401633 |. 0FB6C0 MOVZX EAX,AL ; 扩展到EAX
00401636 |. 48 DEC EAX ; 将结果减1
00401637 |. 5D POP EBP
00401638 \. C3 RETN
}
额,分析得知原来是进行特征码位置计算后的值在全局数组中的数据是否为1
00401541 |. 83F8 FF |CMP EAX,-0x1
00401544 |.^ 0F84 B9FEFFFF |JE CKGM1a.00401403 ; 无效的位置值,则Over
0040154A |. 895C24 0C |MOV DWORD PTR SS:[ESP+0xC],EBX ; 第二个字符的特征码位置
0040154E |. 897424 08 |MOV DWORD PTR SS:[ESP+0x8],ESI ; 第一个字符的特征码位置
00401552 |. 8B45 A0 |MOV EAX,DWORD PTR SS:[EBP-0x60] ; 用来保存位置的变量2
00401555 |. 894424 04 |MOV DWORD PTR SS:[ESP+0x4],EAX
00401559 |. 8B45 A4 |MOV EAX,DWORD PTR SS:[EBP-0x5C] ; 用来保存位置的变量1
0040155C |. 890424 |MOV DWORD PTR SS:[ESP],EAX
0040155F |. E8 24000000 |CALL <CKGM1a.IsValidCalcValue> ; 计算值是否有效
{
; IsValidCalcValue 用来计算值是否有效
<CKGM1a.I>/$ 55 PUSH EBP ; 用来计算值是否有效的入口点
00401589 |. 89E5 MOV EBP,ESP
0040158B |. 83EC 0C SUB ESP,0xC
0040158E |. 891C24 MOV DWORD PTR SS:[ESP],EBX
00401591 |. 897424 04 MOV DWORD PTR SS:[ESP+0x4],ESI
00401595 |. 897C24 08 MOV DWORD PTR SS:[ESP+0x8],EDI ; 以上是保存寄存器的操作(用于堆栈使用)
00401599 |. 8B5D 08 MOV EBX,DWORD PTR SS:[EBP+0x8] ; 参数1 --- 保存位置1的值
0040159C |. 8B7D 0C MOV EDI,DWORD PTR SS:[EBP+0xC] ; 参数2 --- 保存位置2的值
0040159F |. 8B75 10 MOV ESI,DWORD PTR SS:[EBP+0x10] ; 参数3 --- 位置1的值
004015A2 |. 83FB FF CMP EBX,-0x1 ; nSavePos1 == -1
004015A5 |. 0F94C2 SETE DL ; 如果nSavePos1的值是-1,置dl为1
004015A8 |. 85F6 TEST ESI,ESI ; nPos1 > 0
004015AA |. 0F9FC0 SETG AL ; nPos1大于0,则值al为1
004015AD |. B9 FFFFFFFF MOV ECX,-0x1
004015B2 |. 84D0 TEST AL,DL ; 两个结果必须有效
004015B4 |. 75 52 JNZ SHORT CKGM1a.00401608 ; 无效则Over
004015B6 |. 83FB 0C CMP EBX,0xC
004015B9 |. 74 4D JE SHORT CKGM1a.00401608 ; nSavePos1如果等于12,则Over
004015BB |. 89D8 MOV EAX,EBX
004015BD |. F7D0 NOT EAX ; ~nSavePos1 取反操作
004015BF |. C1E8 1F SHR EAX,0x1F ; nSavePos1 >> 31
004015C2 |. 89FA MOV EDX,EDI
004015C4 |. F7D2 NOT EDX ; ~nSavePos2 取反操作
004015C6 |. C1EA 1F SHR EDX,0x1F ; nSavePos2 >> 31
004015C9 |. 20D0 AND AL,DL ; nSavePos1 & nSavePos2
004015CB |. B9 00000000 MOV ECX,0x0
004015D0 |. 84C0 TEST AL,AL ; 两个值相与的结果是否为0
004015D2 |. 74 34 JE SHORT CKGM1a.00401608 ; 如果两个值的高位不为1,则Over
004015D4 |. 39F3 CMP EBX,ESI ; nSavePos2与nPos1比较
004015D6 |. 75 14 JNZ SHORT CKGM1a.004015EC ; 跳转到不等的处理位置
004015D8 |. 8B45 14 MOV EAX,DWORD PTR SS:[EBP+0x14]
004015DB |. 48 DEC EAX ; nPos2 - 1
004015DC |. 39F8 CMP EAX,EDI ; nPos2 - 1的结果与nSavePos2进行比较
004015DE |. 74 28 JE SHORT CKGM1a.00401608 ; 相等则Over
004015E0 |. 39F3 CMP EBX,ESI ; nSavePos1与nPos1比较
004015E2 |. 75 08 JNZ SHORT CKGM1a.004015EC ; 不等,则跳
004015E4 |. 8B45 14 MOV EAX,DWORD PTR SS:[EBP+0x14] ; EAX = nPos2
004015E7 |. 40 INC EAX ; nPos2 + 1
004015E8 |. 39F8 CMP EAX,EDI ; nPos2+1后的结果与nSavePos2进行比较
004015EA |. 74 1C JE SHORT CKGM1a.00401608 ; 相等则Over
004015EC |> 8D46 FF LEA EAX,DWORD PTR DS:[ESI-0x1] ; EAX = nPos1 - 1
004015EF |. 39D8 CMP EAX,EBX ; nPos1-1的结果与nSavePos1进行比较
004015F1 |. 0F94C2 SETE DL ; 相等则置DL为1
004015F4 |. 3B7D 14 CMP EDI,DWORD PTR SS:[EBP+0x14] ; nSavePos2与nPos2进行比较
004015F7 |. 0F94C0 SETE AL ; 相等则置al为1
004015FA |. B9 00000000 MOV ECX,0x0 ; ECX = 临时返回值
004015FF |. 84D0 TEST AL,DL ; 两结果进行与操作
00401601 |. 75 05 JNZ SHORT CKGM1a.00401608
00401603 |. B9 FFFFFFFF MOV ECX,-0x1
00401608 |> 89C8 MOV EAX,ECX ; EAX = 临时的返回值
0040160A |. 8B1C24 MOV EBX,DWORD PTR SS:[ESP] ; 以下操作是平衡堆栈前,寄存器的还原操作
0040160D |. 8B7424 04 MOV ESI,DWORD PTR SS:[ESP+0x4]
00401611 |. 8B7C24 08 MOV EDI,DWORD PTR SS:[ESP+0x8]
00401615 |. 89EC MOV ESP,EBP
00401617 |. 5D POP EBP
00401618 \. C3 RETN
}
00401564 |. 83F8 FF |CMP EAX,-0x1 ; 返回值是否有效
00401567 |.^ 0F84 A0FEFFFF |JE CKGM1a.0040140D ; 无效则Over
0040156D |. 8975 A4 |MOV DWORD PTR SS:[EBP-0x5C],ESI ; 保存位置1
00401570 |. 895D A0 |MOV DWORD PTR SS:[EBP-0x60],EBX ; 保存位置2
00401573 |. 47 |INC EDI ; 增加循环次数计数
00401574 |. 83FF 0F |CMP EDI,0xF ; 循环必须高于15次
00401577 |.^ 7E 86 \JLE SHORT CKGM1a.004014FF
00401579 |. BA 00000000 MOV EDX,0x0 ; EDX存放序列号正确的标志位
0040157E |> 89D0 MOV EAX,EDX ; EDX做返回值
00401580 |. 83C4 7C ADD ESP,0x7C
00401583 |. 5B POP EBX
00401584 |. 5E POP ESI
00401585 |. 5F POP EDI
00401586 |. 5D POP EBP
00401587 \. C3 RETN
-------------------------->8------------------------------------------------------------
到此,注册算法已经分析完毕了.
由于鄙人功力不够,注册机还没能力写出来.楼下哪位兄台能帮个忙,写出注册机,万分感谢.
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!
2011年02月11日 19:01:47
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课