欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

[原创] CTF2017 第11题 ToBeBetter CrackMe 详细破解过程

[原创] CTF2017 第11题 ToBeBetter CrackMe 详细破解过程

序言:
   本题使用了父子进程守护、壳、SMC、反调试、DES算法、多个坑等设计,难度不低,可惜多解,现仅提交140组答案,
   破解此题需要攻击者具备解壳或动态调试能力、跟踪父子进程、熟谙DES算法细节和直觉(否则栽在坑里了)。
一、侦壳、PE格式,试运行了解作品(套路),未知壳,作品有窗口还有错误提示(容易找到合适的断点位置)
二、解壳:
// 破解本题无需真的脱掉壳,只需要找到OEP,利用OD脚本进行自动断在OEP并Patch代码即可。
// OD载入,停在这里:

0044742E >  E8 ECFBFFFF     CALL 11-ToBeB.0044701F

00447433    C3              RETN

// 跟入CALL 44701F,省略一系列解码过程,破解此题不需要关心这些,只需要找到OEP

0044739E    8B85 E0FEFFFF   MOV EAX,DWORD PTR SS:[EBP-0x120]

004473A4    8BE5            MOV ESP,EBP

004473A6    5D              POP EBP

004473A7    59              POP ECX

004473A8    FFE0            JMP EAX                                  ; 飞向光明顶,此处设断

004473AA    83BD ECFEFFFF 0>CMP DWORD PTR SS:[EBP-0x114],0x0

// 来到OEP

00418356    E8 574C0000     CALL 11-ToBeB.0041CFB2                   ; OEP

0041835B  ^ E9 7FFEFFFF     JMP 11-ToBeB.004181DF

00418360    8B5424 0C       MOV EDX,DWORD PTR SS:[ESP+0xC]

00418364    8B4C24 04       MOV ECX,DWORD PTR SS:[ESP+0x4]

// 可以写个OD脚本,自动断OEP

BPHWS 418356,"x"

RUN

BPHWC 418356


三、分析子进程的坑
// OD加载运行后,只出来一个带窗口进程,与正常运行的双进程不同,说明这是个坑
// 是坑也得分析不是?bp GetDlgItemTextW

0012F4F8   004017A9  /CALL 到 GetDlgItemTextW 来自 11-ToBeB.004017A3

0012F4FC   001701AC  |hWnd = 001701AC ('CrackMe',class='#32770')

0012F500   000003E9  |ControlID = 3E9 (1001.)

0012F504   0012F510  |Buffer = 0012F510

0012F508   000001FE  \Count = 1FE (510.)

// 返回程序

004017A3    FF15 90A14200   CALL DWORD PTR DS:[0x42A190]                            ; 获得输入

004017A9    C745 08 0000000>MOV DWORD PTR SS:[EBP+0x8],0x0

004017B0    33D2            XOR EDX,EDX

004017B2    B8 108B1E45     MOV EAX,0x451E8B10

004017B7    8B0D 087A4300   MOV ECX,DWORD PTR DS:[0x437A08]

004017BD    F7F1            DIV ECX                                                 ; 父进程对次处NOP

004017BF    8945 08         MOV DWORD PTR SS:[EBP+0x8],EAX

004017C2    FF75 08         PUSH DWORD PTR SS:[EBP+0x8]

004017C5    8D85 00FAFFFF   LEA EAX,DWORD PTR SS:[EBP-0x600]

004017CB    50              PUSH EAX

004017CC    E8 6F020000     CALL 11-ToBeB.00401A40                                  ; 算法流程(带坑)

004017D1    83C4 08         ADD ESP,0x8

004017D4    C785 00FCFFFF D>MOV DWORD PTR SS:[EBP-0x400],0x793A63D0

004017DE    85C0            TEST EAX,EAX

004017E0    8D85 04FCFFFF   LEA EAX,DWORD PTR SS:[EBP-0x3FC]

004017E6    68 FA010000     PUSH 0x1FA

004017EB    6A 00           PUSH 0x0

004017ED    50              PUSH EAX

004017EE    74 58           JE X11-ToBeB.00401848                                   ; 不能跳

004017F0    E8 6B6B0100     CALL 11-ToBeB.00418360

004017F5    68 F6010000     PUSH 0x1F6

004017FA    8D85 08FEFFFF   LEA EAX,DWORD PTR SS:[EBP-0x1F8]

00401800    C785 00FEFFFF E>MOV DWORD PTR SS:[EBP-0x200],0x518C6CE8

0040180A    6A 00           PUSH 0x0

0040180C    50              PUSH EAX

0040180D    C785 04FEFFFF 1>MOV DWORD PTR SS:[EBP-0x1FC],0x529F6210

00401817    E8 446B0100     CALL 11-ToBeB.00418360

0040181C    83C4 18         ADD ESP,0x18

0040181F    8D85 00FCFFFF   LEA EAX,DWORD PTR SS:[EBP-0x400]

00401825    6A 00           PUSH 0x0

00401827    50              PUSH EAX

00401828    8D85 00FEFFFF   LEA EAX,DWORD PTR SS:[EBP-0x200]

0040182E    50              PUSH EAX

0040182F    56              PUSH ESI

00401830    FF15 8CA14200   CALL DWORD PTR DS:[0x42A18C]                            ; 注册成功

00401836    6A 02           PUSH 0x2

00401838    56              PUSH ESI

00401839    FF15 88A14200   CALL DWORD PTR DS:[0x42A188]                            ; user32.EndDialog

0040183F    33C0            XOR EAX,EAX

00401841    5E              POP ESI

00401842    8BE5            MOV ESP,EBP

00401844    5D              POP EBP

00401845    C2 1000         RETN 0x10

00401848    E8 136B0100     CALL 11-ToBeB.00418360

0040184D    68 F6010000     PUSH 0x1F6

00401852    8D85 08FEFFFF   LEA EAX,DWORD PTR SS:[EBP-0x1F8]

00401858    C785 00FEFFFF E>MOV DWORD PTR SS:[EBP-0x200],0x518C6CE8

00401862    6A 00           PUSH 0x0

00401864    50              PUSH EAX

00401865    C785 04FEFFFF 3>MOV DWORD PTR SS:[EBP-0x1FC],0x8D255931

0040186F    E8 EC6A0100     CALL 11-ToBeB.00418360

00401874    83C4 18         ADD ESP,0x18

00401877    8D85 00FCFFFF   LEA EAX,DWORD PTR SS:[EBP-0x400]

0040187D    6A 00           PUSH 0x0

0040187F    50              PUSH EAX

00401880    8D85 00FEFFFF   LEA EAX,DWORD PTR SS:[EBP-0x200]

00401886    50              PUSH EAX

00401887    56              PUSH ESI

00401888    FF15 8CA14200   CALL DWORD PTR DS:[0x42A18C]                            ; 注册失败

0040188E    33C0            XOR EAX,EAX

00401890    5E              POP ESI

00401891    8BE5            MOV ESP,EBP

00401893    5D              POP EBP

00401894    C2 1000         RETN 0x10

00401897    66:83F8 02      CMP AX,0x2

0040189B    75 0B           JNZ X11-ToBeB.004018A8

0040189D    6A 02           PUSH 0x2

0040189F    FF75 08         PUSH DWORD PTR SS:[EBP+0x8]

004018A2    FF15 88A14200   CALL DWORD PTR DS:[0x42A188]                            ; user32.EndDialog

004018A8    33C0            XOR EAX,EAX

004018AA    8BE5            MOV ESP,EBP

004018AC    5D              POP EBP

004018AD    C2 1000         RETN 0x10

// CALL 401A40 为子进程算法,跟进

00401A40    55              PUSH EBP

00401A41    8BEC            MOV EBP,ESP

00401A43    83EC 0C         SUB ESP,0xC                                             ; 父进程对此处进行流程修改

00401A46    53              PUSH EBX

00401A47    56              PUSH ESI

00401A48    57              PUSH EDI

00401A49    8B7D 08         MOV EDI,DWORD PTR SS:[EBP+0x8]

00401A4C    33D2            XOR EDX,EDX

00401A4E    33F6            XOR ESI,ESI

00401A50    8955 F8         MOV DWORD PTR SS:[EBP-0x8],EDX

00401A53    8975 FC         MOV DWORD PTR SS:[EBP-0x4],ESI

00401A56    33C9            XOR ECX,ECX

00401A58    8D5F 02         LEA EBX,DWORD PTR DS:[EDI+0x2]

00401A5B    EB 03           JMP X11-ToBeB.00401A60

00401A5D    8D49 00         LEA ECX,DWORD PTR DS:[ECX]

00401A60    66:8B07         MOV AX,WORD PTR DS:[EDI]

00401A63    83C7 02         ADD EDI,0x2

00401A66    66:85C0         TEST AX,AX

00401A69  ^ 75 F5           JNZ X11-ToBeB.00401A60

00401A6B    2BFB            SUB EDI,EBX

00401A6D    D1FF            SAR EDI,1

00401A6F    83FF 14         CMP EDI,0x14                                            ; 虚假的 < 20位

00401A72    7C 09           JL X11-ToBeB.00401A7D

00401A74    5F              POP EDI

00401A75    5E              POP ESI

00401A76    33C0            XOR EAX,EAX

00401A78    5B              POP EBX

00401A79    8BE5            MOV ESP,EBP

00401A7B    5D              POP EBP

00401A7C    C3              RETN

// 异或累加 == 0x127514D 就是个很直白的坑

00401AE2    8D42 61         LEA EAX,DWORD PTR DS:[EDX+0x61]

00401AE5    8B55 F8         MOV EDX,DWORD PTR SS:[EBP-0x8]

00401AE8    98              CWDE

00401AE9    33F0            XOR ESI,EAX                                             ; 异或

00401AEB    03D6            ADD EDX,ESI                                             ; 累加

00401AED    8B75 FC         MOV ESI,DWORD PTR SS:[EBP-0x4]

00401AF0    8955 F8         MOV DWORD PTR SS:[EBP-0x8],EDX

00401AF3    3BDF            CMP EBX,EDI

00401AF5  ^ 7C 99           JL X11-ToBeB.00401A90

00401AF7    33C0            XOR EAX,EAX

00401AF9    81FA 4D512701   CMP EDX,0x127514D                                       ; 异或累加值 == 0x127514D

00401AFF    5F              POP EDI                                                 ; 测试了几组长度离答案差太多,肯定是坑

// 此时想到父进程必然有小动作
// 找到加载窗口的位置(父进程不显示窗口,所以在相关位置必有选择)

00401691  |.  8BEC          MOV EBP,ESP

00401693  |.  83EC 70       SUB ESP,0x70

00401696  |.  803D 509B4300>CMP BYTE PTR DS:[0x439B50],0x0

0040169D  |.  0F84 88000000 JE dumped_.0040172B

004016A3  |.  E8 08FFFFFF   CALL dumped_.004015B0

004016A8  |.  803D 519B4300>CMP BYTE PTR DS:[0x439B51],0x0

004016AF  |.  74 1C         JE Xdumped_.004016CD                                      ;  父进程子进程选择分支

004016B1  |.  6A 00         PUSH 0x0                                                  ; /lParam = NULL

004016B3  |.  68 40174000   PUSH dumped_.00401740                                     ; |DlgProc = dumped_.00401740

004016B8  |.  6A 00         PUSH 0x0                                                  ; |hOwner = NULL

004016BA  |.  6A 67         PUSH 0x67                                                 ; |pTemplate = 0x67

004016BC  |.  FF75 08       PUSH DWORD PTR SS:[EBP+0x8]                               ; |hInst

004016BF  |.  FF15 94A14200 CALL DWORD PTR DS:[<&user32.DialogBoxParamW>]             ; \DialogBoxParamW

004016C5  |.  33C0          XOR EAX,EAX

004016C7  |.  8BE5          MOV ESP,EBP

004016C9  |.  5D            POP EBP

004016CA  |.  C2 1000       RETN 0x10

004016CD  |>  8D4D 90       LEA ECX,DWORD PTR SS:[EBP-0x70]

004016D0  |.  E8 0BF10000   CALL dumped_.004107E0

004016D5  |.  E8 C6FEFFFF   CALL dumped_.004015A0

004016DA  |.  8D4D EC       LEA ECX,DWORD PTR SS:[EBP-0x14]

//置父子进程标志位的地方

0040145D    A2 519B4300     MOV BYTE PTR DS:[0x439B51],AL


四、分析父进程小动作
// 正常运行之后,OD附加父进程,对CODE段下访问断点,断到

04115B0    56              PUSH ESI

004115B1    8BF1            MOV ESI,ECX

004115B3    8B46 20         MOV EAX,DWORD PTR DS:[ESI+0x20]

004115B6    85C0            TEST EAX,EAX

004115B8    74 07           JE Xdumped_.004115C1

004115BA    50              PUSH EAX

004115BB    FF15 7CA04200   CALL DWORD PTR DS:[<&kernel32.SetEvent>]                  ; kernel32.SetEvent

004115C1    8B46 24         MOV EAX,DWORD PTR DS:[ESI+0x24]

004115C4    85C0            TEST EAX,EAX

004115C6    74 07           JE Xdumped_.004115CF

004115C8    50              PUSH EAX

004115C9    FF15 78A04200   CALL DWORD PTR DS:[<&kernel32.DebugActiveProcessStop>]    ; kernel32.DebugActiveProcessStop

004115CF    8B46 1C         MOV EAX,DWORD PTR DS:[ESI+0x1C]

004115D2    83F8 FF         CMP EAX,-0x1

004115D5    74 3E           JE Xdumped_.00411615

004115D7    57              PUSH EDI

004115D8    8B3D 80A04200   MOV EDI,DWORD PTR DS:[<&kernel32.WaitForSingleObject>]    ; kernel32.WaitForSingleObject

004115DE    6A 00           PUSH 0x0

004115E0    50              PUSH EAX

004115E1    FFD7            CALL EDI

004115E3    3D 02010000     CMP EAX,0x102

004115E8    75 1A           JNZ Xdumped_.00411604

004115EA    53              PUSH EBX

004115EB    8B1D 88A04200   MOV EBX,DWORD PTR DS:[<&kernel32.Sleep>]                  ; kernel32.Sleep

004115F1    6A 64           /PUSH 0x64

004115F3    FFD3            |CALL EBX

004115F5    6A 00           |PUSH 0x0

004115F7    FF76 1C         |PUSH DWORD PTR DS:[ESI+0x1C]

004115FA    FFD7            |CALL EDI

004115FC    3D 02010000     |CMP EAX,0x102

00411601  ^ 74 EE           \JE Xdumped_.004115F1

00411603    5B              POP EBX

00411604    FF76 1C         PUSH DWORD PTR DS:[ESI+0x1C]

00411607    FF15 2CA04200   CALL DWORD PTR DS:[<&kernel32.CloseHandle>]               ; kernel32.CloseHandle

0041160D    C746 1C FFFFFFF>MOV DWORD PTR DS:[ESI+0x1C],-0x1

00411614    5F              POP EDI

00411615    8B46 20         MOV EAX,DWORD PTR DS:[ESI+0x20]

00411618    85C0            TEST EAX,EAX

0041161A    74 0E           JE Xdumped_.0041162A

0041161C    50              PUSH EAX

0041161D    FF15 2CA04200   CALL DWORD PTR DS:[<&kernel32.CloseHandle>]               ; kernel32.CloseHandle

00411623    C746 20 0000000>MOV DWORD PTR DS:[ESI+0x20],0x0

0041162A    C746 54 0000000>MOV DWORD PTR DS:[ESI+0x54],0x0

00411631    5E              POP ESI

00411632    C3              RETN

// 父进程再设断点

00410AA2    8B1D 74A04200   MOV EBX,DWORD PTR DS:[0x42A074]          ; kernel32.WaitForDebugEvent

00410AA8    6A FF           PUSH -0x1

00410AAA    8D45 8C         LEA EAX,DWORD PTR SS:[EBP-0x74]

00410AAD    50              PUSH EAX

00410AAE    FFD3            CALL EBX

00410AB0    85C0            TEST EAX,EAX                             ; 断点这里

00410AB2    74 3C           JE X11-ToBeB.00410AF0

00410AB4    8D45 8C         LEA EAX,DWORD PTR SS:[EBP-0x74]

00410AB7    50              PUSH EAX

00410AB8    8B47 18         MOV EAX,DWORD PTR DS:[EDI+0x18]

00410ABB    57              PUSH EDI

00410ABC    6A 00           PUSH 0x0

00410ABE    FFD0            CALL EAX

00410AC0    8D45 8C         LEA EAX,DWORD PTR SS:[EBP-0x74]

00410AC3    50              PUSH EAX

00410AC4    57              PUSH EDI

00410AC5    FF75 8C         PUSH DWORD PTR SS:[EBP-0x74]

00410AC8    E8 93010000     CALL 11-ToBeB.00410C60

00410ACD    8945 EC         MOV DWORD PTR SS:[EBP-0x14],EAX

00410AD0    8D45 8C         LEA EAX,DWORD PTR SS:[EBP-0x74]

00410AD3    50              PUSH EAX

00410AD4    8B47 18         MOV EAX,DWORD PTR DS:[EDI+0x18]

00410AD7    57              PUSH EDI

00410AD8    6A 01           PUSH 0x1

00410ADA    FFD0            CALL EAX                                 ; 修改子进程2处

00410ADC    83C4 24         ADD ESP,0x24

00410ADF    FF75 EC         PUSH DWORD PTR SS:[EBP-0x14]

00410AE2    FF75 94         PUSH DWORD PTR SS:[EBP-0x6C]

00410AE5    FF75 90         PUSH DWORD PTR SS:[EBP-0x70]

00410AE8    FF15 70A04200   CALL DWORD PTR DS:[0x42A070]             ; kernel32.ContinueDebugEvent

// 410ADA CALL EAX 有小动作,跟进

00402000    50              PUSH EAX

00402001    6A 02           PUSH 0x2

00402003    8D45 08         LEA EAX,DWORD PTR SS:[EBP+0x8]

00402006    66:C745 08 9090 MOV WORD PTR SS:[EBP+0x8],0x9090

0040200C    50              PUSH EAX

0040200D    FF76 18         PUSH DWORD PTR DS:[ESI+0x18]

00402010    52              PUSH EDX

00402011    FFD3            CALL EBX                                 ; WriteProcessMemory

// 堆栈

015BFCD4   00000154

015BFCD8   004017BD  11-ToBeB.004017BD

015BFCDC   015BFE5C

015BFCE0   00000002

015BFCE4   015BFE44

015BFCE8   76EFD000  kernel32.GetLastError

// 将子进程 4017BD 位置用 9090 NOP掉

// 改前

004017BD    F7F1            DIV ECX

// 改后

004017BD    90              NOP                                                     ; 父进程对次处NOP

004017BE    90              NOP

// 还有小动作

00402080    50              PUSH EAX

00402081    6A 05           PUSH 0x5

00402083    8D45 F0         LEA EAX,DWORD PTR SS:[EBP-0x10]

00402086    50              PUSH EAX

00402087    8B02            MOV EAX,DWORD PTR DS:[EDX]

00402089    8B00            MOV EAX,DWORD PTR DS:[EAX]

0040208B    05 37373737     ADD EAX,0x37373737

00402090    35 4EE5B3C8     XOR EAX,0xC8B3E54E

00402095    83C0 03         ADD EAX,0x3

00402098    50              PUSH EAX

00402099    57              PUSH EDI

0040209A    FFD3            CALL EBX                                 ; WriteProcessMemory

// 堆栈

015BFCD8   00401A43  11-ToBeB.00401A43

015BFCDC   015BFE44

015BFCE0   00000005

015BFCE4   015BFE5C

015BFCE8   76EFD000  kernel32.GetLastError

015BFCEC   0012FECC

// [15BFE44] = E9 BB 08 00 00
// 将子进程 401A43 位置用 E9 BB 08 00 00 修改

// 改前:

00401A43    83EC 0C         SUB ESP,0xC

00401A46    53              PUSH EBX

00401A47    56              PUSH ESI

// 改后:

00401A43   /E9 BB080000     JMP 11-ToBeB.00402303

// 至此,已经分析清楚父进程对子进程的两处代码修改,后续调试我们就脱离父进程
// OD脚本模拟父进程自动patch代码

BPHWS 418356,"x"

RUN

BPHWC 418356

MOV [4017BD],#9090#

MOV [401A43],#E9BB080000#


五、分析第一段算法
// 重新再来(代码已经patch)

004017A3    FF15 90A14200   CALL DWORD PTR DS:[0x42A190]                            ; 获得输入

004017A9    C745 08 0000000>MOV DWORD PTR SS:[EBP+0x8],0x0

004017B0    33D2            XOR EDX,EDX

004017B2    B8 108B1E45     MOV EAX,0x451E8B10

004017B7    8B0D 087A4300   MOV ECX,DWORD PTR DS:[0x437A08]

004017BD    90              NOP                                                     ; 父进程对次处NOP

004017BE    90              NOP

004017BF    8945 08         MOV DWORD PTR SS:[EBP+0x8],EAX

004017C2    FF75 08         PUSH DWORD PTR SS:[EBP+0x8]

004017C5    8D85 00FAFFFF   LEA EAX,DWORD PTR SS:[EBP-0x600]

004017CB    50              PUSH EAX

004017CC    E8 6F020000     CALL 11-ToBeB.00401A40                                  ; 算法流程(带坑)

00401A40    55              PUSH EBP

00401A41    8BEC            MOV EBP,ESP

00401A43    E9 BB080000     JMP 11-ToBeB.00402303                                   ; 父进程对此处进行流程修改

// 跟踪改变后的流程,动态申请内存0x5000字节,用于存放待解密数据

00402657    6A 40           PUSH 0x40

00402659    68 00100000     PUSH 0x1000

0040265E    68 00500000     PUSH 0x5000

00402663    6A 00           PUSH 0x0

00402665    FFD7            CALL EDI                                                ; ZwAllocateVirtualMemory

00402667    8945 F4         MOV DWORD PTR SS:[EBP-0xC],EAX

// 用于读取自身0x5000字节待解密数据

004029B7    6A 00           PUSH 0x0

004029B9    8D45 80         LEA EAX,DWORD PTR SS:[EBP-0x80]

004029BC    50              PUSH EAX

004029BD    68 00500000     PUSH 0x5000

004029C2    FF75 F4         PUSH DWORD PTR SS:[EBP-0xC]

004029C5    FF75 D0         PUSH DWORD PTR SS:[EBP-0x30]

004029C8    FFD7            CALL EDI                                                ; ZwReadFile

004029CA    8B75 80         MOV ESI,DWORD PTR SS:[EBP-0x80]

// 获取输入并转换格式十六进制

004029D5    8B5D 08         MOV EBX,DWORD PTR SS:[EBP+0x8]           ; input

004029D8    8D55 F8         LEA EDX,DWORD PTR SS:[EBP-0x8]

004029DB    8BCB            MOV ECX,EBX

004029DD    C745 F8 0000000>MOV DWORD PTR SS:[EBP-0x8],0x0

004029E4    E8 D7F1FFFF     CALL 11-ToBeB.00401BC0                   ; 检查格式,转16进制

004029E9    85C0            TEST EAX,EAX

004029EB    0F84 49010000   JE 11-ToBeB.00402B3A                     ; 不能跳

004029F1    8D4B 10         LEA ECX,DWORD PTR DS:[EBX+0x10]

004029F4    C645 F3 00      MOV BYTE PTR SS:[EBP-0xD],0x0

004029F8    8D55 F3         LEA EDX,DWORD PTR SS:[EBP-0xD]

004029FB    E8 10F1FFFF     CALL 11-ToBeB.00401B10                   ; 检查格式,转16进制

00401BC0    56              PUSH ESI                                 ; 转十六进制

00401BC1    57              PUSH EDI

00401BC2    8BF9            MOV EDI,ECX

00401BC4    C702 00000000   MOV DWORD PTR DS:[EDX],0x0

00401BCA    33F6            XOR ESI,ESI

00401BCC    8D6424 00       LEA ESP,DWORD PTR SS:[ESP]

00401BD0    0FB70477        MOVZX EAX,WORD PTR DS:[EDI+ESI*2]        ; input

00401BD4    83F8 30         CMP EAX,0x30

00401BD7    72 05           JB X11-ToBeB.00401BDE

00401BD9    83F8 39         CMP EAX,0x39

00401BDC    76 0A           JBE X11-ToBeB.00401BE8

00401BDE    83F8 41         CMP EAX,0x41

00401BE1    72 3E           JB X11-ToBeB.00401C21

00401BE3    83F8 5A         CMP EAX,0x5A

00401BE6    77 39           JA X11-ToBeB.00401C21                    ; 要求输入 0 - 9 或 A - Z

00401BE8    8B0A            MOV ECX,DWORD PTR DS:[EDX]               ; 取变量,初值0

00401BEA    C1E1 04         SHL ECX,0x4                              ; *16 -- > 进位,转十六进制

00401BED    890A            MOV DWORD PTR DS:[EDX],ECX               ; 结果存回变量

00401BEF    83F8 30         CMP EAX,0x30

00401BF2    72 0A           JB X11-ToBeB.00401BFE

00401BF4    83F8 39         CMP EAX,0x39

00401BF7    77 05           JA X11-ToBeB.00401BFE

00401BF9    83E8 30         SUB EAX,0x30                             ; -0x30 数字

00401BFC    EB 11           JMP X11-ToBeB.00401C0F

00401BFE    83F8 41         CMP EAX,0x41

00401C01    72 0A           JB X11-ToBeB.00401C0D

00401C03    83F8 5A         CMP EAX,0x5A

00401C06    77 05           JA X11-ToBeB.00401C0D

00401C08    83E8 37         SUB EAX,0x37                             ; -0x37 大写字母

00401C0B    EB 02           JMP X11-ToBeB.00401C0F

00401C0D    33C0            XOR EAX,EAX

00401C0F    03C1            ADD EAX,ECX                              ; 加到累加变量

00401C11    46              INC ESI

00401C12    8902            MOV DWORD PTR DS:[EDX],EAX

00401C14    83FE 08         CMP ESI,0x8

00401C17  ^ 7C B7           JL X11-ToBeB.00401BD0

00401C19    5F              POP EDI                                  ; 01389DBE

00401C1A    B8 01000000     MOV EAX,0x1

00401C1F    5E              POP ESI

00401C20    C3              RETN

// 第一段算法暴露(SMC)

00402A12    0FB645 F3       MOVZX EAX,BYTE PTR SS:[EBP-0xD]          ; 第9、10位

00402A16    8B7D F8         MOV EDI,DWORD PTR SS:[EBP-0x8]           ; 第1-8位

00402A19    8B5D F4         MOV EBX,DWORD PTR SS:[EBP-0xC]

00402A1C    69F0 01010101   IMUL ESI,EAX,0x1010101                   ; ESI = EAX 第9、10位 * 0x1010101

00402A22    8B0493          MOV EAX,DWORD PTR DS:[EBX+EDX*4]         ; 表数组,准备解密

00402A25    8D0C3A          LEA ECX,DWORD PTR DS:[EDX+EDI]           ; 初值第1-8位,后面就是对其累加1

00402A28    03C6            ADD EAX,ESI                              ; 表数组 + (第9、10位 * 0x1010101)

00402A2A    33C8            XOR ECX,EAX                              ; 第1-8位 xor (表 + (第9、10位 * 0x1010101))

00402A2C    890C93          MOV DWORD PTR DS:[EBX+EDX*4],ECX         ; 异或结果存回地址

00402A2F    42              INC EDX                                  ; 计数器+1

00402A30    8B45 80         MOV EAX,DWORD PTR SS:[EBP-0x80]          ; 0x5000

00402A33    C1E8 02         SHR EAX,0x2                              ; /4 (>>2)

00402A36    3BD0            CMP EDX,EAX                              ; 5120次

00402A38  ^ 72 E8           JB X11-ToBeB.00402A22

if ( v68 & 0xFFFFFFFC )

  {

   v71 = v168;

   v72 = v167;

   v73 = 0x1010101 * v166;

   do

     {

      *(_DWORD *)(v72 + 4 * v70) = (v73 + *(_DWORD *)(v72 + 4 * v70)) ^ (v70 + v71);

        ++v70;

     }

   while ( v70 < v135 >> 2 );

     v69 = a1;

  }

// 异或解密后比较

00402A50    8A81 B0404300   MOV AL,BYTE PTR DS:[ECX+0x4340B0]                       ; 解密后数据必须与 [4340B0] 相同

00402A56    3A8411 B0404300 CMP AL,BYTE PTR DS:[ECX+EDX+0x4340B0]                   ; 比较异或解密后的数据是否正确

00402A5D    0F85 D7000000   JNZ 11-ToBeB.00402B3A

00402A63    41              INC ECX

00402A64    83F9 60         CMP ECX,0x60                                            ; 0x60字节

00402A67  ^ 72 E7           JB X11-ToBeB.00402A50
// 待解密代码:(后面省略一堆)

004F0000  83F08EA7

004F0004  3F0FBA29

004F0008  E747E97C

004F000C  93D03647

004F0010  EC72CD2C

004F0014  93C0BA2E

004F0018  90A578A3

004F001C  2A40BA2F

004F0020  DB3FF233

004F0024  9031FB09

004F0028  D1477258

004F002C  905E3DAC

004F0030  AB817C35

004F0034  6BD43434

004F0038  C49E84E4

004F003C  83B426AF

004F0040  51C0BA3A

004F0044  280080B8

004F0048  93BE3FF3

004F004C  8E36BA3B

004F0050  E9C0BA3C

004F0054  93C0BA29

004F0058  93C0B2C5

004F005C  1680CD3F

004F0060  92D0D6BC

// 解密后必须为:(后面省略一堆)

004340B0  1070EC81

004340B4  55530000

004340B8  BC8B5756

004340BC  00108424

004340C0  BBF63300

004340C4  00000001

004340C8  0725C68B

004340CC  79800000

004340D0  C8834805

004340D4  07B140F8

004340D8  C68BC82A

004340DC  07E28399

004340E0  F8C1C203

004340E4  38148A03

004340E8  D322FAD2

004340EC  10349488

004340F0  46000002

004340F4  7C40FE83

004340F8  0002BDCF

004340FC  05BA0000

00434100  BE000000

00434104  00000014

00434108  000008B9

0043410C  8DC03300

// 据此写Python穷举第一段注册码(穷举第9、10位,组合很少,秒出)

code_x = [0x83F08EA7,0x3F0FBA29]

code_m = [0x1070EC81,0x55530000]

for sn_9_10 in range(0x00,0x100):

    #注册码第9、10位只有这几百种

    y = code_m[0] ^ ((code_x[0] + sn_9_10 * 0x1010101) & 0xffffffff)

    y = y + 1

    if code_m[1] ^ y == ((code_x[1] + sn_9_10 * 0x1010101) & 0xffffffff):

        print ('找到 sn_9_10: %x' % sn_9_10)

        print ('找到 sn_1_8: %x' % (y-1))

// 找到 sn_9_10: E1,找到 sn_1_8: 75A29C09,因此第一段注册码(sn_1-10):“75A29C09E1”


六、分析第二段算法
// 上述解密后的动态申请的内存作为函数运行(DES+奇数位取反

00402ABE    C745 84 3139393>MOV DWORD PTR SS:[EBP-0x7C],0x33393931

00402AC5    50              PUSH EAX

00402AC6    8BC2            MOV EAX,EDX

00402AC8    C745 88 3039303>MOV DWORD PTR SS:[EBP-0x78],0x37303930

00402ACF    50              PUSH EAX                                                ; 除前10位之外的其他注册码

00402AD0    8D45 84         LEA EAX,DWORD PTR SS:[EBP-0x7C]

00402AD3    56              PUSH ESI

00402AD4    50              PUSH EAX                                                ; DES 密钥 "19930907"

00402AD5    F3:             PREFIX REP:                                             ; 多余的前缀

00402AD6    0F7F85 DCFEFFFF MOVQ QWORD PTR SS:[EBP-0x124],MM0

00402ADD    FFD7            CALL EDI                                                ; 调用刚才解密的代码,DES+奇数位取反

// 接下来跟进 CALL EDI,痛苦就此开始,第一眼判断可能位DES算法,使用工具计算结果不符,无奈跟进去分析,巨复杂
// 初步判断作者可能对DES的几个表做了调整,因此我花费了时间自己码了DES代码,对每一个DES步骤、表格进行检查(这工作量你懂得)
// 结果......DES解密过程没有问题,与标准的相同!!!真正的手脚在于DES末尾IP-1逆置换、交换左右32bit结束后,作者竟然将bit的奇数位取反!!!
// DES 解密末尾的坑:

003B2494   /79 05               JNS X003B249B                                        ; 非负数跳走

003B2496   |4A                  DEC EDX

003B2497   |83CA FE             OR EDX,0xFFFFFFFE

003B249A   |42                  INC EDX                                              ; 即bit奇数位取反,偶数位不变

003B249B   \75 11               JNZ X003B24AE                                        ; 下标偶数不跳,下标奇数跳

003B249D    389C34 10020000     CMP BYTE PTR SS:[ESP+ESI+0x210],BL                   ; 比较当前bit是否为1

003B24A4    0F95C1              SETNE CL                                             ; 为1时,CL=0;为0时,CL=1

003B24A7    888C34 10020000     MOV BYTE PTR SS:[ESP+ESI+0x210],CL                   ; 为1时就替换为0,为0时就替换为1,即取反

003B24AE    46                  INC ESI                                              ; 指向下一位

003B24AF    83FE 40             CMP ESI,0x40

003B24B2  ^ 7C D8               JL X003B248C

// 所以破解算法思路变成了将解密结果先bit奇数位取反,然后用“19930907”密钥进行DES加密,结果就是注册码的第二段
// CALL EDI 必须返回“!HelloHaniella!” 字符串

00402AF2    8A10            MOV DL,BYTE PTR DS:[EAX]

00402AF4    3A11            CMP DL,BYTE PTR DS:[ECX]

00402AF6    75 30           JNZ X11-ToBeB.00402B28                                  ; 比较"!HelloHaniella!"

00402AF8    84D2            TEST DL,DL

00402AFA    74 12           JE X11-ToBeB.00402B0E                                   ; 末尾0x00结束符

00402AFC    8A50 01         MOV DL,BYTE PTR DS:[EAX+0x1]

00402AFF    3A51 01         CMP DL,BYTE PTR DS:[ECX+0x1]                            ; 比较"!HelloHaniella!"

00402B02    75 24           JNZ X11-ToBeB.00402B28

00402B04    83C0 02         ADD EAX,0x2

00402B07    83C1 02         ADD ECX,0x2

00402B0A    84D2            TEST DL,DL                                              ; 末尾0x00结束符

00402B0C  ^ 75 E4           JNZ X11-ToBeB.00402AF2

// 比如,要使 CALL EDI 返回:

21 48 65 6C 6C 6F 48 61 6E 69 65 6C 6C 61 21 00  !HelloHaniella!

--> 0x2148656C6C6F48616E69656C6C612100

// 二进制

0 0 1 0 0 0 0 1 0 1 0 0 1 0 0 0

0 1 1 0 0 1 0 1 0 1 1 0 1 1 0 0

0 1 1 0 1 1 0 0 0 1 1 0 1 1 1 1

0 1 0 0 1 0 0 0 0 1 1 0 0 0 0 1

0 1 1 0 1 1 1 0 0 1 1 0 1 0 0 1

0 1 1 0 0 1 0 1 0 1 1 0 1 1 0 0

0 1 1 0 1 1 0 0 0 1 1 0 0 0 0 1

0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0

// --> 奇数位取反(下标偶数位)

1 0 0 0 1 0 1 1 1 1 1 0 0 0 1 0

1 1 0 0 1 1 1 1 1 1 0 0 0 1 1 0

1 1 0 0 0 1 1 0 1 1 0 0 0 1 0 1

1 1 1 0 0 0 1 0 1 1 0 0 1 0 1 1

1 1 0 0 0 1 0 0 1 1 0 0 0 0 1 1

1 1 0 0 1 1 1 1 1 1 0 0 0 1 1 0

1 1 0 0 0 1 1 0 1 1 0 0 1 0 1 1

1 0 0 0 1 0 1 1 1 0 1 0 1 0 1 0

// 转回十六进制和字符串

--> 0x8BE2CFC6C6C5E2CBC4C3CFC6C6CB8BAA

--> 字符串:“['掀婆馑拿掀扑Z辍?/pre>

// 以“19930907”为密钥加密“['掀婆馑拿掀扑Z辍钡玫健?0217C048420956C15DA309FF2B69170”



// 与第一段注册码连接:75A29C09E180217C048420956C15DA309FF2B69170

// 这就是正确注册码!


七、分析算法多解
由于作者没有对输入的字符串长度做明确要求,而是对DES+奇数位取反结果的字符串做比较,且以0x00作为比较终止符,终止符之后的数据忽略,因此存在无数解。前42位保持“75A29C09E180217C048420956C15DA309FF2B69170”不变,在后面添加任意符合DES解密规则的字符都可以,提交了包含140组答案的附件。
八、总结
一个设计理念跟我的(第三题)接近的作品,防护手段太显眼,算法存在太多解,可惜了一个好作品。

上传的附件 11-ToBeBetterCrackMe.rar
CM11_a_lot_keys.txt

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功