首页
社区
课程
招聘
[原创]****CHM 注册流程及算法分析(MD5+AES-256+ZLIB),附AES库
发表于: 2006-11-29 09:54 25453

[原创]****CHM 注册流程及算法分析(MD5+AES-256+ZLIB),附AES库

2006-11-29 09:54
25453

【破文标题】**CHM 3.50 注册流程及算法分析
【破文作者】Ptero
【破解工具】FI,OllyDbg,Dede,IDA,MD5工具,AES库,ZLib库
【注册方式】序列号+KeyFile
【保护方式】花指令,自校检,进程检测,API断点检测
【加壳方式】UPX v0.94-1.90
【加密算法】MD5+AES-256(Rijndael)+ZLib
【软件限制】功能限制
【破解难度】难
【破解声明】初学Crack,只是感兴趣,没有其它目的。失误之处敬请诸位大侠赐教!

----------------------------------------------------

【破解分析】

    最近要做一个chm文件,就找到了这个软件。正好这几天有空,就拿它开刀啦!
初次接触加密算法保护的软件,就碰上了这么一个家伙,耗掉了我N个晚上……

关于AES:网上有很多了,我就不多说了。附件里有一个Delphi的AES库。
关于ZLib:这是Zip文件采用的算法,开源。有关资料可以去这里找:http://www.zlib.net

下面开始闯关:

++++++++++++++++++++++++++++++++++++++++ 第1关:脱壳 ++++++++++++++++++++++++++++++++++++++++

用FI查壳:UPX v0.94-1.90。简单脱掉,不多说了。
加这么弱的壳,不是菜鸟,就是对自己的注册算法很有信心。呵呵,我们看看是哪一种吧……

++++++++++++++++++++++++++++++++++++++++ 第2关:自校检 ++++++++++++++++++++++++++++++++++++++++

脱壳后运行程序会提示错误信息,然后程序崩溃。
走捷径:按照askformore给出的方法(http://bbs.pediy.com/showthread.php?threadid=7382),搜索cmp dword [ebp-0A],0(共2个)然后把后面的条件跳转改成nop,顺利过关。

++++++++++++++++++++++++++++++++++++++++ 第3关:检测敌意进程 ++++++++++++++++++++++++++++++++++++++++

程序检测敌意进程共3种方法:

1. FindWindow

这是黑名单:

Class:OWL_Window        ; 没见过这个
Class:TIdaWindow        ; IDA
Class:OLLYDBG                ; OllyDbg
Title:TRW2000                ; TRW2000
Class:TDeDeMainform        ; Dede
Class:FileMonClass        ; FileMon
Class:RegMonClass        ; RegMon
Class:SnackerClass        ; 没见过这个
Title:OLLYDBG                ; OllyDbg
Title:WinHex                ; WinHex
Title:ProcDump32 (C) 1998, 1999, 2000 G-RoM, Lorian & Stone        ; ProcDump32
Title:URSoft W32Dasm Ver 8.93 Program Disassembler/Debugger        ; W32Dasm
Title:NuMega SoftICE Symbol Loader        ; SoftICE
Title:TRW2000 for Windows 9x                ; TRW2000
Class:aqpqpxt|{szgx        ; 没见过这个
Title:DarK 3.50.04 (c) 1999-2003 by DaFixer/TMG        ; Dede

解决方法:

把这里:

0055536B    E8 3CF1FFFF    call fixed.005544AC
00555370    EB 04          jmp short fixed.00555376

全部nop掉,就可以了。

2. EnumWindows

这是黑名单:

ExeSpy
wxr95
Regmon
File Monitor
RegMonEx
Window Detective
DebugView
ResSpy
Advanced Registry Tracer
regsnap
MEMSPY
Memory Doctor
ProcDump32
Memory Editor
FrogsICE
SMU Winspector
Memory Dumper
MemoryMonitor
Regmon        ; 检测了2次。作者很怕这个吗?
DeDe
OpenTrap
Registry Monitor
InCtrl

解决方法:

把这里:

00407C9C  - FF25 2CD77500  jmp near [<&user32.#223>]        ; user32.EnumWindows

改为:

00407C9C    C2 0800        ret 8
00407C9F    90             nop
00407CA0    90             nop
00407CA1    90             nop

3. EnumThreadWindows

这里我没有跟踪就直接修补了,不知道它检测的是哪些程序。

解决方法:

把这里:

00407C94  - FF25 30D77500  jmp near [<&user32.#220>]        ; user32.EnumThreadWindows

改为:

00407C94    C2 0C00        ret 0C
00407C97    90             nop
00407C98    90             nop
00407C99    90             nop

修改完毕,把修改过的文件重命名为fixed.exe,顺利过关。

++++++++++++++++++++++++++++++++++++++++ 第4关:检测API int3断点 ++++++++++++++++++++++++++++++++++++++++

有若干个函数是用来检测int3断点的。
被检测的API如下:

MessageBoxA
GetWindowTextA
CreateFileA
DialogBoxParamA
GetModuleHandleA
GetWindowA
GetDlgItemTextA
CompareFileTimeA
GetLocalTimeA
GetSystemTimeA
GetTimeZoneInformationA

然而,作者检测的是程序中跳到API的地方的断点,所以还是可以直接在API入口出下断点的,而且并没有检测操作注册表的函数。难道是作者在放水吗?

不管怎么说,这一关形同虚设,直接pass。

++++++++++++++++++++++++++++++++++++++++ 第5关:验证注册码 ++++++++++++++++++++++++++++++++++++++++

用FI查看:Borland Delphi。所以要用Dede分析。
还有,IDA 5.0的流程图功能不错,大大提高了效率,所以也用IDA分析。
最后,用OD加载,忽略所有异常。

在0052DBAD处下断点,输入用户名、注册码,断下:

获得用户名长度:

0052DBAD    8B45 F8        mov eax, [ebp-8]
0052DBB0    E8 DF73EDFF    call fixed.00404F94        ; System.@LStrLen(String):Integer;
0052DBB5    83F8 02        cmp eax, 2        ; 如果用户名长度<2,就Game Over啦
0052DBB8    7D 08          jge short fixed.0052DBC2
0052DBBA    8D45 F8        lea eax, [ebp-8]
0052DBBD    E8 F670EDFF    call fixed.00404CB8        ; System.@LStrClr(void;void);
0052DBC2    EB 04          jmp short fixed.0052DBC8

获得注册码长度:

0052DBC8    8B45 F4        mov eax, [ebp-C]
0052DBCB    E8 C473EDFF    call fixed.00404F94        ; System.@LStrLen(String):Integer;
0052DBD0    83F8 13        cmp eax, 13        ; 如果注册码长度<19,就Game Over啦
0052DBD3    7D 08          jge short fixed.0052DBDD
0052DBD5    8D45 F4        lea eax, [ebp-C]
0052DBD8    E8 DB70EDFF    call fixed.00404CB8        ; System.@LStrClr(void;void);
0052DBDD    EB 04          jmp short fixed.0052DBE3

可以看到用户名长度要大于等于2,注册码长度要大于等于19才行。

检验注册码中是否包含字符'-':

004FF49D    8D45 EC        lea eax, [ebp-14]
004FF4A0    8B15 28CC5500  mov edx, [55CC28]
004FF4A6    8A52 01        mov dl, [edx+1]        ; '-'
004FF4A9    E8 F259F0FF    call fixed.00404EA0        ; System.@LStrFromChar(String;String;Char);
004FF4AE    8B45 EC        mov eax, [ebp-14]
004FF4B1    8B55 FC        mov edx, [ebp-4]
004FF4B4    E8 1F5EF0FF    call fixed.004052D8        ; System.@LStrPos;
004FF4B9    85C0           test eax, eax        ; 如果注册码中不含'-',就Game Over啦
004FF4BB    75 0D          jnz short fixed.004FF4CA
004FF4BD    EB 06          jmp short fixed.004FF4C5

这里计算注册码前2位的MD5值:

004CFAA3    8D55 FC        lea edx, [ebp-4]
004CFAA6    8B45 F8        mov eax, [ebp-8]        ; 注册码的前2位
004CFAA9    E8 FEA5FFFF    call fixed.004CA0AC        ; 计算MD5值

如果一路F7跟进的话可以在这里看到MD5的特征码:

004C9D08    C700 01234567  mov dword ptr [eax], 67452301
004C9D0E    C740 04 89ABCD>mov dword ptr [eax+4], EFCDAB89
004C9D15    C740 08 FEDCBA>mov dword ptr [eax+8], 98BADCFE
004C9D1C    C740 0C 765432>mov dword ptr [eax+C], 10325476

循环6次,比较2个MD5值:

004CFAB4    BE 06000000    mov esi, 6
004CFAB9    BF 98785500    mov edi, fixed.00557898
004CFABE    EB 06          jmp short fixed.004CFAC6

004CFAC6    8B17           mov edx, [edi]        ; 内存中的某个MD5值
004CFAC8    8B45 FC        mov eax, [ebp-4]        ; 注册码前2位的MD5值
004CFACB    E8 B09BF3FF    call fixed.00409680        ; SysUtils.SameText(AnsiString;AnsiString):Boolean;
004CFAD0    8BD8           mov ebx, eax
004CFAD2    EB 04          jmp short fixed.004CFAD8

004CFAD8    84DB           test bl, bl
004CFADA    75 06          jnz short fixed.004CFAE2        ; 如果与6个值都不相等,就Game Over啦
004CFADC    83C7 04        add edi, 4
004CFADF    4E             dec esi
004CFAE0   ^75 DC          jnz short fixed.004CFABE

内存中的6个MD5值和明文分别是:

        MD5值                                明文
"3e850aae9e730e9fee413f5219abd997"        "QE"
"42983b05e2f2cc22822e30beb7bdd668"        "CO"
"3fd6b696867d70225deda7868308679b"        "EC"
"c562607189d77eb9dfb707464c1e7b0b"        "LT"
"ae41a6d38b78679b4675941ff0c0c92d"        "ET"
"b2e68ec1fa49da52ca5b0f436e032dd6"        "LD"

也就是说,注册码的前2位必须要等于上面6者之一。

如果是"QE""EC""ET"的情况,在这里可以看到相应的注册类型:

004FF66F    8B45 F8        mov eax, [ebp-8]        ; "Single User License"
004FF672    E8 1D59F0FF    call fixed.00404F94

如果是"CO""LT""LD"的情况,则在这里:

取注册码的3-6位(0-9或A-F)并转为16进制:

004FF56A    8B45 F8        mov eax, [ebp-8]        ; 注册码的3-6位
004FF56D    E8 CEFDFFFF    call fixed.004FF340        ; 转为16进制(大写)
004FF572    8BF0           mov esi, eax
004FF574    83F6 4F        xor esi, 4F        ; 与4Fh异或
004FF577    EB 04          jmp short fixed.004FF57D

004FF57D    83FE 01        cmp esi, 1
004FF580    75 20          jnz short fixed.004FF5A2
004FF582    EB 04          jmp short fixed.004FF588        ; 等于1就跳到"Single User License"

不等于就跳到这里:

004FF5A2    EB 06          jmp short fixed.004FF5AA

004FF5AA    8D55 F8        lea edx, [ebp-8]
004FF5AD    8BC6           mov eax, esi
004FF5AF    E8 C0A7F0FF    call fixed.00409D74        ; SysUtils.IntToStr(Integer):AnsiString;overload;
004FF5B4    EB 04          jmp short fixed.004FF5BA

004FF5BA    8D55 E0        lea edx, [ebp-20]
004FF5BD    A1 28CB5500    mov eax, [55CB28]
004FF5C2    E8 1578F0FF    call fixed.00406DDC        ; 取加密字符串
004FF5C7    8B45 E0        mov eax, [ebp-20]
004FF5CA    8D55 E4        lea edx, [ebp-1C]
004FF5CD    E8 CEFAFFFF    call fixed.004FF0A0        ; 解密
004FF5D2    8B55 E4        mov edx, [ebp-1C]        ; " User Licences"
004FF5D5    8D45 F8        lea eax, [ebp-8]
004FF5D8    E8 BF59F0FF    call fixed.00404F9C        ; System.@LStrCat;

到这里就明白了:这是多用户许可,注册码3-6位异或4Fh为许可证数量!

到这里,注册码的验证工作就算完毕了。什么?居然与用户名没有关系?是的。这是KeyFile的注册方式啊!这里只是万里长征的第一步呢!
下面就要存放注册信息了:

加密用户名:

0052DC23    8D95 70FDFFFF  lea edx, [ebp-290]
0052DC29    8B45 F8        mov eax, [ebp-8]        ; 用户名
0052DC2C    E8 F786F0FF    call fixed.00436328        ; 将用户名的每一位加密

加密注册码:

0052DC60    8D95 6CFDFFFF  lea edx, [ebp-294]
0052DC66    8B45 F4        mov eax, [ebp-C]        ; 注册码
0052DC69    E8 BA86F0FF    call fixed.00436328        ; 将注册码的每一位加密

加密注册类型:

0052DC9F    8D95 68FDFFFF  lea edx, [ebp-298]
0052DCA5    8B45 F0        mov eax, [ebp-10]        ; 注册类型
0052DCA8    E8 7B86F0FF    call fixed.00436328        ; 将注册信息的每一位加密

获取日期时间:

0052DCDC    E8 F3E3EDFF    call fixed.0040C0D4        ; SysUtils.Date:TDateTime;

下面是一个Call

0052DD20    E8 2710FAFF    call fixed.004CED4C

如果F7跟进的话,就能看到程序把以上4项数据放在注册表
"HKCR\CLSID\{2757D5E0-7A80-11D8-A102-00E0C6843FFA}\ProgInfo"下的"ProgData"里。

好,如果能到达这里,就顺利过关啦。

++++++++++++++++++++++++++++++++++++++++ 第6关:计算KeyFile文件名 ++++++++++++++++++++++++++++++++++++++++

因为程序把注册信心都存放在注册表里,所以就下注册表函数的断点。
在RegQueryValueExA处下条件断点:[esp+8]=="ProgData"&&[esp+14]!=0
中断2次后取消断点。看堆栈中的"Buffer",在其指向的内存上设内存访问断点,F9运行。
中断在这里:

00404F1E    8A0A           mov cl, [edx]
00404F20    42             inc edx
00404F21  ^ E9 82FEFFFF    jmp fixed.00404DA8

取消内存断点,Ctrl+F9返回:

0054F332    8B45 F8        mov eax, [ebp-8]
0054F335    50             push eax
0054F336    8D45 F4        lea eax, [ebp-C]
0054F339    8B55 FC        mov edx, [ebp-4]
0054F33C    81C2 C8050000  add edx, 5C8        ; edx指向加密后的注册信息
0054F342    E8 D55BEBFF    call fixed.00404F1C        ; System.@LStrFromString(String;String;ShortString;ShortString);
0054F347    8B45 F4        mov eax, [ebp-C]
0054F34A    5A             pop edx
0054F34B    E8 7003FBFF    call fixed.004FF6C0        ; 这就是关键Call
0054F350    84C0           test al, al        ; 经典的cmp/test+jz/jnz指令
0054F352    0F85 AD000000  jnz fixed.0054F405        ; 这里就是爆破点,改成jmp就是注册版啦!

F7跟进这个Call,来到这里:

计算KeyFile文件名:

004FF74B    8D55 E4        lea edx, [ebp-1C]
004FF74E    8B45 F8        mov eax, [ebp-8]        ; 加密后的注册码
004FF751    E8 CA6CF3FF    call fixed.00436420        ; 解密
004FF756    8B45 E4        mov eax, [ebp-1C]        ; 注册码
004FF759    50             push eax
004FF75A    8D55 E0        lea edx, [ebp-20]
004FF75D    8B45 FC        mov eax, [ebp-4]        ; 加密后的用户名
004FF760    E8 BB6CF3FF    call fixed.00436420        ; 解密
004FF765    8B45 E0        mov eax, [ebp-20]        ; 用户名
004FF768    8D4D F0        lea ecx, [ebp-10]
004FF76B    5A             pop edx
004FF76C    E8 139CFDFF    call fixed.004D9384        ; 根据用户名和注册码的一部分计算出KeyFile文件名,具体过程见下文
04FF771    33C0           xor eax, eax
004FF773    5A             pop edx
004FF774    59             pop ecx
004FF775    59             pop ecx
004FF776    64:8910        mov fs:[eax], edx
004FF779    EB 31          jmp short fixed.004FF7AC

检验文件是否存在:

004FF7AC    8D55 DC        lea edx, [ebp-24]        ; KeyFile文件名
004FF7AF    8B45 F0        mov eax, [ebp-10]
004FF7B2    E8 FD9FF0FF    call fixed.004097B4        ; SysUtils.Trim(AnsiString):AnsiString;overload;
004FF7B7    837D DC 00     cmp dword ptr [ebp-24], 0
004FF7BB    74 0C          je short fixed.004FF7C9
004FF7BD    8B45 F0        mov eax, [ebp-10]
004FF7C0    E8 27ACF0FF    call fixed.0040A3EC        ; SysUtils.FileExists(AnsiString):Boolean;
004FF7C5    84C0           test al, al
004FF7C7    75 18          jnz short fixed.004FF7E1        ; 如果文件不存在,就Game Over啦

如果KeyFile存在就跳到这里:

004FF7E1    EB 04          jmp short fixed.004FF7E7

004FF7E7    8D45 D8        lea eax, [ebp-28]
004FF7EA    50             push eax
004FF7EB    8D55 D4        lea edx, [ebp-2C]
004FF7EE    8B45 F8        mov eax, [ebp-8]        ; 加密后的注册码
004FF7F1    E8 2A6CF3FF    call fixed.00436420        ; 解密
004FF7F6    8B45 D4        mov eax, [ebp-2C]        ; 注册码
004FF7F9    50             push eax
004FF7FA    8D55 D0        lea edx, [ebp-30]
004FF7FD    8B45 FC        mov eax, [ebp-4]        ; 加密后的用户名
004FF800    E8 1B6CF3FF    call fixed.00436420        ; 解密
004FF805    8B45 D0        mov eax, [ebp-30]        ; 用户名
004FF808    8B4D F0        mov ecx, [ebp-10]        ; KeyFile文件名
004FF80B    5A             pop edx
004FF80C    E8 879FFDFF    call fixed.004D9798        ; 这里进入7、8、9三关,KeyFile解密
004FF811    8B45 D8        mov eax, [ebp-28]        ; KeyFile解密后的字串
004FF814    E8 3BA1FDFF    call fixed.004D9954        ; 进入最后一关第10关!

好啦,到这里就可以进下一关啦!

下面是这关用到的一些函数:

根据用户名和注册码的一部分计算出KeyFile文件名:

---------------------------------------- 004D9384 ----------------------------------------

004D9384    55             push ebp

…………
…………
…………

004D93FF    8B45 F8        mov eax, [ebp-8]        ; 注册码
004D9402    E8 4566FFFF    call fixed.004CFA4C        ; 比较注册码的前2位是否合法
004D9407    84C0           test al, al
004D9409    75 0B          jnz short fixed.004D9416

注册码前2位合法就跳到这里:

004D9416    EB 04          jmp short fixed.004D941C

取注册码的倒数第13-10位:

004D941C    33C0           xor eax, eax
004D941E    55             push ebp
004D941F    68 55944D00    push fixed.004D9455
004D9424    64:FF30        push dword ptr fs:[eax]
004D9427    64:8920        mov fs:[eax], esp
004D942A    8D45 F0        lea eax, [ebp-10]
004D942D    50             push eax
004D942E    8B45 F8        mov eax, [ebp-8]        ; 注册码
004D9431    E8 5EBBF2FF    call fixed.00404F94        ; System.@LStrLen(String):Integer;
004D9436    8BD0           mov edx, eax
004D9438    83EA 03        sub edx, 3
004D943B    83EA 09        sub edx, 9
004D943E    B9 04000000    mov ecx, 4
004D9443    8B45 F8        mov eax, [ebp-8]        ; 注册码
004D9446    E8 A9BDF2FF    call fixed.004051F4        ; System.@LStrCopy
004D944B    33C0           xor eax, eax
004D944D    5A             pop edx
004D944E    59             pop ecx
004D944F    59             pop ecx
004D9450    64:8910        mov fs:[eax], edx
004D9453    EB 20          jmp short fixed.004D9475

004D9475    EB 06          jmp short fixed.004D947D

循环,异或用户名的每一位并相加:

004D947D    8B45 FC        mov eax, [ebp-4]        ; 用户名
004D9480    E8 0FBBF2FF    call fixed.00404F94        ; System.@LStrLen(String):Integer;
004D9485    85C0           test eax, eax
004D9487    7E 21          jle short fixed.004D94AA
004D9489    BA 01000000    mov edx, 1
004D948E    EB 04          jmp short fixed.004D9494

004D9494    8B4D FC        mov ecx, [ebp-4]
004D9497    8A4C11 FF      mov cl, [ecx+edx-1]        ; 取用户名的每一位
004D949B    80F1 5C        xor cl, 5C        ; 异或5Ch
004D949E    81E1 FF000000  and ecx, 0FF
004D94A4    03D9           add ebx, ecx        ; 累加
004D94A6    42             inc edx
004D94A7    48             dec eax
004D94A8  ^ 75 E4          jnz short fixed.004D948E

004D94B0    33C0           xor eax, eax
004D94B2    55             push ebp
004D94B3    68 EA944D00    push fixed.004D94EA
004D94B8    64:FF30        push dword ptr fs:[eax]
004D94BB    64:8920        mov fs:[eax], esp
004D94BE    33D2           xor edx, edx
004D94C0    8B45 F0        mov eax, [ebp-10]
004D94C3    E8 540AF3FF    call fixed.00409F1C        ; SysUtils.StrToIntDef(AnsiString;Integer):Integer;
004D94C8    83F3 2F        xor ebx, 2F        ; 将用户名的累加和异或2Fh
004D94CB    03C3           add eax, ebx        ; 再加上注册码的倒数13-10位
004D94CD    8D55 E8        lea edx, [ebp-18]
004D94D0    E8 9F08F3FF    call fixed.00409D74        ; SysUtils.IntToStr(Integer):AnsiString;overload;
004D94D5    8B55 E8        mov edx, [ebp-18]
004D94D8    8D45 F0        lea eax, [ebp-10]
004D94DB    E8 70B8F2FF    call fixed.00404D50        ; System.@LStrLAsg(void;void;void;void);
004D94E0    33C0           xor eax, eax
004D94E2    5A             pop edx
004D94E3    59             pop ecx
004D94E4    59             pop ecx
004D94E5    64:8910        mov fs:[eax], edx
004D94E8    EB 20          jmp short fixed.004D950A

004D950A    EB 06          jmp short fixed.004D9512

004D9512    33C0           xor eax, eax
004D9514    55             push ebp
004D9515    68 64954D00    push fixed.004D9564
004D951A    64:FF30        push dword ptr fs:[eax]
004D951D    64:8920        mov fs:[eax], esp
004D9520    EB 04          jmp short fixed.004D9526

004D9526    8D55 E0        lea edx, [ebp-20]
004D9529    8B45 F8        mov eax, [ebp-8]        ; 注册码
004D952C    E8 DF65FFFF    call fixed.004CFB10
004D9531    FF75 E0        push dword ptr [ebp-20]        ".dll"
004D9534    FF75 FC        push dword ptr [ebp-4]        用户名
004D9537    FF75 F0        push dword ptr [ebp-10]        注册码倒数13-10位和用户名计算结果
004D953A    FF75 F8        push dword ptr [ebp-8]        注册码
004D953D    FF75 F0        push dword ptr [ebp-10]        注册码倒数13-10位和用户名计算结果
004D9540    8D45 E4        lea eax, [ebp-1C]
004D9543    BA 05000000    mov edx, 5
004D9548    E8 07BBF2FF    call fixed.00405054        ; System.@LStrCatN;
004D954D    8B45 E4        mov eax, [ebp-1C]        ; 长字符串1=上面5个字符串相连
004D9550    8D4D EC        lea ecx, [ebp-14]
004D9553    33D2           xor edx, edx
004D9555    E8 EE6AFFFF    call fixed.004D0048        ; 计算出一个Hash值,F7跟进可看到算法
004D955A    33C0           xor eax, eax
004D955C    5A             pop edx
004D955D    59             pop ecx
004D955E    59             pop ecx
004D955F    64:8910        mov fs:[eax], edx
004D9562    EB 1D          jmp short fixed.004D9581

004D9581    EB 04          jmp short fixed.004D9587

004D9587    8B45 EC        mov eax, [ebp-14]        ; 计算出的Hash值
004D958A    E8 05BAF2FF    call fixed.00404F94
004D958F    83F8 08        cmp eax, 8
004D9592    7C 1A          jl short fixed.004D95AE        ; System.@LStrLen(String):Integer;
004D9594    EB 06          jmp short fixed.004D959C

004D959C    8B45 F4        mov eax, [ebp-C]
004D959F    50             push eax
004D95A0    8B4D EC        mov ecx, [ebp-14]        ; Hash值
004D95A3    8B55 F0        mov edx, [ebp-10]        ; 注册码倒数13-10位和用户名计算结果
004D95A6    8B45 F8        mov eax, [ebp-8]        ; 注册码
004D95A9    E8 32FDFFFF    call fixed.004D92E0        ; 计算KeyFile文件名,F7跟进可看到算法

以下就返回了……

--------------------------------------------------------------------------------

根据用户名和注册码计算Hash值:

---------------------------------------- 004D0048 ----------------------------------------

004D0048    55             push ebp

…………
…………
…………

004D009A    8D55 F4        lea edx, [ebp-C]
004D009D    A1 C4C65500    mov eax, [55C6C4]
004D00A2    E8 356DF3FF    call fixed.00406DDC        ; 取字符串
004D00A7    8B4D F4        mov ecx, [ebp-C]        ; "AbVytyNzU3NEpiqG0txQBxhLTMQiwbSCmAwZ0mBgKgOGGw6GM2RkFNdy1Q=="
004D00AA    8D45 F8        lea eax, [ebp-8]
004D00AD    8B55 FC        mov edx, [ebp-4]        ; 用户名和注册码一部分的混合
004D00B0    E8 2B4FF3FF    call fixed.00404FE0        ; System.@LStrCat3;
004D00B5    8B45 F8        mov eax, [ebp-8]        ; 上面2个字符串相连
004D00B8    8BD6           mov edx, esi
004D00BA    E8 C1FEFFFF    call fixed.004CFF80        ; 计算Hash值,F7跟进可看到算法

以下就返回了……

--------------------------------------------------------------------------------

这里是真正计算Hash的Call

---------------------------------------- 004CFF80 ----------------------------------------

004CFF80    55             push ebp

…………
…………
…………

循环取每一位,计算出一个Hash值:

004CFFBD    BE 01000000    mov esi, 1
004CFFC2    8B45 FC        mov eax, [ebp-4]
004CFFC5    8A4430 FF      mov al, [eax+esi-1]        ; 取出字符串的每一位
004CFFC9    83CA FF        or edx, FFFFFFFF
004CFFCC    E8 77FEFFFF    call fixed.004CFE48        ; 查表替换,F7跟进可看到算法
004CFFD1    03F8           add edi, eax        ; 将结果累加
004CFFD3    46             inc esi
004CFFD4    4B             dec ebx
004CFFD5  ^ 75 EB          jnz short fixed.004CFFC2

004CFFD7    8BC7           mov eax, edi
004CFFD9    E8 86FEFFFF    call fixed.004CFE64        ; 求反
004CFFDE    8BF8           mov edi, eax
004CFFE0    8B55 F8        mov edx, [ebp-8]
004CFFE3    8BC7           mov eax, edi        ; 计算出的Hash值
004CFFE5    E8 2AFFFFFF    call fixed.004CFF14        ; 转换成Ascii

以下就返回了……

--------------------------------------------------------------------------------

计算Hash过程中的查表替换:

---------------------------------------- 004CFE48 ----------------------------------------

004CFE48    32C2           xor al, dl        ; 求反
004CFE4A    25 FF000000    and eax, 0FF
004CFE4F    8B0485 F478550>mov eax, [eax*4+5578F4]        ; 查表
004CFE56    C1EA 08        shr edx, 8
004CFE59    81E2 FFFFFF00  and edx, 0FFFFFF
004CFE5F    33C2           xor eax, edx        ; 再与0FFFFFFh异或
004CFE61    C3             ret

这就是那张巨大的表:

005578F4  00 00 00 00 96 30 07 77 2C 61 0E EE BA 51 09 99  ....?w,a詈Q.
00557904  19 C4 6D 07 8F F4 6A 70 35 A5 63 E9 A3 95 64 9E  捻?jp5ャ椋?
00557914  32 88 DB 0E A4 B8 DC 79 1E E9 D5 E0 88 D9 D2 97  2?じ荠檎?僖
00557924  2B 4C B6 09 BD 7C B1 7E 07 2D B8 E7 91 1D BF 90  +L?近炳-哥??
00557934  64 10 B7 1D F2 20 B0 6A 48 71 B9 F3 DE 41 BE 84  d??瓣Hq贵蘖?
00557944  7D D4 DA 1A EB E4 DD 6D 51 B5 D4 F4 C7 85 D3 83  }在脘蓓Q翟羟?
00557954  56 98 6C 13 C0 A8 6B 64 7A F9 62 FD EC C9 65 8A  V?括kdz??慑
00557964  4F 5C 01 14 D9 6C 06 63 63 3D 0F FA F5 0D 08 8D  O\凫cc=?.
00557974  C8 20 6E 3B 5E 10 69 4C E4 41 60 D5 72 71 67 A2  ?n;^iL淞`镇qg
00557984  D1 E4 03 3C 47 D4 04 4B FD 85 0D D2 6B B5 0A A5  唁<G?K?.译?
00557994  FA A8 B5 35 6C 98 B2 42 D6 C9 BB DB 40 F9 BC AC  ??l?B稚慧@?
005579A4  E3 6C D8 32 75 5C DF 45 CF 0D D6 DC 59 3D D1 AB  沆?u\吲?周Y=勋
005579B4  AC 30 D9 26 3A 00 DE 51 80 51 D7 C8 16 61 D0 BF  ??:.扪?兹a锌
005579C4  B5 F4 B4 21 23 C4 B3 56 99 95 BA CF 0F A5 BD B8  掉?#某V?合ソ
005579D4  9E B8 02 28 08 88 05 5F B2 D9 0C C6 24 E9 0B B1  ?(?_操.??
005579E4  87 7C 6F 2F 11 4C 68 58 AB 1D 61 C1 3D 2D 66 B6  ?o/LhX?a?-f
005579F4  90 41 DC 76 06 71 DB 01 BC 20 D2 98 2A 10 D5 EF  ?荟q???*诊
00557A04  89 85 B1 71 1F B5 B6 06 A5 E4 BF 9F 33 D4 B8 E8  ?瘪刀ヤ?3愿
00557A14  A2 C9 07 78 34 F9 00 0F 8E A8 09 96 18 98 0E E1  ⑸x4??.??
00557A24  BB 0D 6A 7F 2D 3D 6D 08 97 6C 64 91 01 5C 63 E6  ?j-=m?d?\c
00557A34  F4 51 6B 6B 62 61 6C 1C D8 30 65 85 4E 00 62 F2  粞kkbal?e?.b
00557A44  ED 95 06 6C 7B A5 01 1B C1 F4 08 82 57 C4 0F F5  ?l{?留??
00557A54  C6 D9 B0 65 50 E9 B7 12 EA B8 BE 8B 7C 88 B9 FC  瀑板P榉旮?|?
00557A64  DF 1D DD 62 49 2D DA 15 F3 7C D3 8C 65 4C D4 FB  ?葩I-?簏?eL喳
00557A74  58 61 B2 4D CE 51 B5 3A 74 00 BC A3 E2 30 BB D4  Xa餐窝?t.迹?辉
00557A84  41 A5 DF 4A D7 95 D8 3D 6D C4 D1 A4 FB F4 D6 D3  AミJ??m难?糁
00557A94  6A E9 69 43 FC D9 6E 34 46 88 67 AD D0 B8 60 DA  j殚C?n4F??膏
00557AA4  73 2D 04 44 E5 1D 03 33 5F 4C 0A AA C9 7C 0D DD  s-D?3_L.?|.
00557AB4  3C 71 05 50 AA 41 02 27 10 10 0B BE 86 20 0C C9  <qP?'? .
00557AC4  25 B5 68 57 B3 85 6F 20 09 D4 66 B9 9F E4 61 CE  %佃W?o .枣?溽
00557AD4  0E F9 DE 5E 98 C9 D9 29 22 98 D0 B0 B4 A8 D7 C7  ?^??"?按ㄗ
00557AE4  17 3D B3 59 81 0D B4 2E 3B 5C BD B7 AD 6C BA C0  =迟??;\椒?豪
00557AF4  20 83 B8 ED B6 B3 BF 9A 0C E2 B6 03 9A D2 B1 74   ?矶晨?舛?濒
00557B04  39 47 D5 EA AF 77 D2 9D 15 26 DB 04 83 16 DC 73  9G贞??&??荏
00557B14  12 0B 63 E3 84 3B 64 94 3E 6A 6D 0D A8 5A 6A 7A  c?;d?jm.ㄚjz
00557B24  0B CF 0E E4 9D FF 09 93 27 AE 00 0A B1 9E 07 7D  ?????.?}
00557B34  44 93 0F F0 D2 A3 08 87 68 F2 01 1E FE C2 06 69  D?鹨????i
00557B44  5D 57 62 F7 CB 67 65 80 71 36 6C 19 E7 06 6B 6E  ]Wb魉ge?6l?kn
00557B54  76 1B D4 FE E0 2B D3 89 5A 7A DA 10 CC 4A DD 67  v轧??Zz?淌葭
00557B64  6F DF B9 F9 F9 EF BE 8E 43 BE B7 17 D5 8E B0 60  o吖?锞?痉?班
00557B74  E8 A3 D6 D6 7E 93 D1 A1 C4 C2 D8 38 52 F2 DF 4F  瑁种~?∧仑8R蜻O
00557B84  F1 67 BB D1 67 57 BC A6 DD 06 B5 3F 4B 36 B2 48  耒谎gW鸡??K6踩
00557B94  DA 2B 0D D8 4C 1B 0A AF F6 4A 03 36 60 7A 04 41  ?.靥.?J6`zA
00557BA4  C3 EF 60 DF 55 DF 67 A8 EF 8E 6E 31 79 BE 69 46  蔑`哒哏??1y鹃F
00557BB4  8C B3 61 CB 1A 83 66 BC A0 D2 6F 25 36 E2 68 52  ?a??歼绎%6忤R
00557BC4  95 77 0C CC 03 47 0B BB B9 16 02 22 2F 26 05 55  ?.?G还"/&U
00557BD4  BE 3B BA C5 28 0B BD B2 92 5A B4 2B 04 6A B3 5C  ?号(讲??j耻
00557BE4  A7 FF D7 C2 31 CF D0 B5 8B 9E D9 2C 1D AE DE 5B  ?茁1闲??,?[
00557BF4  B0 C2 64 9B 26 F2 63 EC 9C A3 6A 75 0A 93 6D 02  奥d?蜚?ju.?
00557C04  A9 06 09 9C 3F 36 0E EB 85 67 07 72 13 57 00 05  ?.?6?grW.
00557C14  82 4A BF 95 14 7A B8 E2 AE 2B B1 7B 38 1B B6 0C  ??z糕?丙8?
00557C24  9B 8E D2 92 0D BE D5 E5 B7 EF DC 7C 21 DF DB 0B  ??.菊宸镘|!咣
00557C34  D4 D2 D3 86 42 E2 D4 F1 F8 B3 DD 68 6E 83 DA 1F  砸?B庠聒齿hn?
00557C44  CD 16 BE 81 5B 26 B9 F6 E1 77 B0 6F 77 47 B7 18  ??[&滚狩帮wG?
00557C54  E6 5A 08 88 70 6A 0F FF CA 3B 06 66 5C 0B 01 11  孚?j?f\
00557C64  FF 9E 65 8F 69 AE 62 F8 D3 FF 6B 61 45 CF 6C 16  ?e????aE响
00557C74  78 E2 0A A0 EE D2 0D D7 54 83 04 4E C2 B3 03 39  x?_?自?N鲁9
00557C84  61 26 67 A7 F7 16 60 D0 4D 47 69 49 DB 77 6E 3E  a&g?`型GiI埙n>
00557C94  4A 6A D1 AE DC 5A D6 D9 66 0B DF 40 F0 3B D8 37  Jj旬苴仲f呃??
00557CA4  53 AE BC A9 C5 9E BB DE 7F CF B2 47 E9 FF B5 30  S?┡??喜G??
00557CB4  1C F2 BD BD 8A C2 BA CA 30 93 B3 53 A6 A3 B4 24  蚪?潞??SΓ?
00557CC4  05 36 D0 BA 93 06 D7 CD 29 57 DE 54 BF 67 D9 23  6泻?淄)W拊跨?
00557CD4  2E 7A 66 B3 B8 4A 61 C4 02 1B 68 5D 94 2B 6F 2A  .zf掣Ja?h]?o*
00557CE4  37 BE 0B B4 A1 8E 0C C3 1B DF 05 5A 8D EF 02 2D  7?础???Z?-

--------------------------------------------------------------------------------

根据Hash值和用户名、注册码计算KeyFile文件名:

---------------------------------------- 004D92E0 ----------------------------------------

004D92E0    55             push ebp

…………
…………
…………

004D930A    8D55 F4        lea edx, [ebp-C]
004D930D    8BC3           mov eax, ebx        ; 注册码
004D930F    E8 D468FFFF    call fixed.004CFBE8
004D9314    FF75 F4        push dword ptr [ebp-C]        ; "CHM"
004D9317    56             push esi        ; 注册码倒数13-9位和用户名计算结果
004D9318    57             push edi        ; Hash值
004D9319    8D55 F0        lea edx, [ebp-10]
004D931C    8BC3           mov eax, ebx        ; 注册码
004D931E    E8 ED67FFFF    call fixed.004CFB10
004D9323    FF75 F0        push dword ptr [ebp-10]        ; ".dll"
004D9326    8D45 F8        lea eax, [ebp-8]
004D9329    BA 04000000    mov edx, 4
004D932E    E8 21BDF2FF    call fixed.00405054        ; System.@LStrCatN;
004D9333    8B45 F8        mov eax, [ebp-8]        ; "CHM"+注册码倒数13-9位和用户名计算结果+Hash值+".dll"
004D9336    8D55 FC        lea edx, [ebp-4]
004D9339    E8 4E02F3FF    call fixed.0040958C        ; 转换为小写
004D933E    8B45 FC        mov eax, [ebp-4]        ; 这就是KeyFile文件名了

以下就返回了……

--------------------------------------------------------------------------------

++++++++++++++++++++++++++++++++++++++++ 第7关:计算AES-256初始密钥 ++++++++++++++++++++++++++++++++++++++++

呼……第6关还真是长啊!终于闯到第7关了!
进入第7关后一路F8往下,来到这里:

004D9839    8D45 E4        lea eax, [ebp-1C]
004D983C    E8 F7FEFFFF    call fixed.004D9738        ; 获得程序文件名
004D9841    8B4D E4        mov ecx, [ebp-1C]        ; "FIXED.exe"
004D9844    8D45 E8        lea eax, [ebp-18]
004D9847    8B55 FC        mov edx, [ebp-4]        ; 注册码
004D984A    E8 91B7F2FF    call fixed.00404FE0        ; System.@LStrCat3;
004D984F    8B45 E8        mov eax, [ebp-18]        ; 注册码+文件名(大写)
004D9852    8D4D EC        lea ecx, [ebp-14]
004D9855    33D2           xor edx, edx
004D9857    E8 9468FFFF    call fixed.004D00F0        ; 计算出一个MD5值,具体算法如下

计算MD5值的Call

---------------------------------------- 004D00F0 ----------------------------------------

004D00F0    55             push ebp

…………
…………
…………

004D0144    8D55 F4        lea edx, [ebp-C]
004D0147    A1 5CC65500    mov eax, [55C65C]
004D014C    E8 8B6CF3FF    call fixed.00406DDC        ; 取字符串
004D0151    8B4D F4        mov ecx, [ebp-C]        ; "bZxvRs2puRGpimSWzVBwwLTExBEHS1CJDJFawAZRwKFs4NCZRoxQX5N1W+RvRs2p5oimqGRL3ApwwA0bg0OZRsgor8nq"
004D0154    8D45 F8        lea eax, [ebp-8]
004D0157    8B55 FC        mov edx, [ebp-4]        ; 字符串
004D015A    E8 814EF3FF    call fixed.00404FE0        ; System.@LStrCat3;
004D015F    8B45 F8        mov eax, [ebp-8]
004D0162    8BD6           mov edx, esi
004D0164    E8 439FFFFF    call fixed.004CA0AC        ; 计算MD5值

以下就返回了……

--------------------------------------------------------------------------------

原来是把注册码加上文件名,再加上一个很长的字符串,一起计算MD5值。
MD5算出,过关!

++++++++++++++++++++++++++++++++++++++++ 第8关:AES-256解密 ++++++++++++++++++++++++++++++++++++++++

第8关的关键代码在这里:

004D2601    5A             pop edx        ; KeyFile文件大小
004D2602    2BD0           sub edx, eax        ; KeyFile文件大小-4为解密长度
004D2604    8D4D D4        lea ecx, [ebp-2C]        ; MD5值作为初始密钥
004D2607    8BC3           mov eax, ebx        ; KeyFile作为待解密字串
004D2609    E8 92FBFFFF    call fixed.004D21A0        ; 用AES-256解密,F7跟进可看到算法

解密后来到这里:

004D263B    52             push edx
004D263C    50             push eax        ; KeyFile的前4字节作为解密字串长度
004D263D    8B45 FC        mov eax, [ebp-4]
004D2640    E8 4BC3F4FF    call fixed.0041E990        ; 获得解密后的字串
004D2645    EB 04          jmp short fixed.004D264B

004D264B    8B45 F4        mov eax, [ebp-C]
004D264E    99             cdq
004D264F    52             push edx
004D2650    50             push eax
004D2651    8B45 FC        mov eax, [ebp-4]
004D2654    E8 D3C2F4FF    call fixed.0041E92C        ; 设置解密字串长度
004D2659    5F             pop edi
004D265A    5E             pop esi
004D265B    5B             pop ebx
004D265C    8BE5           mov esp, ebp
004D265E    5D             pop ebp
004D265F    C3             ret

这样KeyFile的格式就清楚了:前4个字节是明文长度,后面的部分是密文。
把密文还原成明文,就过关啦!

下面是AES-256解密的函数:

---------------------------------------- 004D21A0 ----------------------------------------

004D21A0    55             push ebp
004D21A1    8BEC           mov ebp, esp
004D21A3    81C4 00FFFFFF  add esp, -100
004D21A9    53             push ebx
004D21AA    56             push esi
004D21AB    8BF2           mov esi, edx
004D21AD    8BD8           mov ebx, eax
004D21AF    8D95 00FFFFFF  lea edx, [ebp-100]
004D21B5    8BC1           mov eax, ecx        ; MD5值
004D21B7    E8 30E5FFFF    call fixed.004D06EC        ; 生成解密密钥,F7跟进可看到算法
004D21BC    8B45 08        mov eax, [ebp+8]
004D21BF    50             push eax
004D21C0    8D8D 00FFFFFF  lea ecx, [ebp-100]        ; 解密密钥
004D21C6    8BD6           mov edx, esi        ; 需要解密的长度
004D21C8    8BC3           mov eax, ebx
004D21CA    E8 09000000    call fixed.004D21D8        ; 将密文解密
004D21CF    5E             pop esi
004D21D0    5B             pop ebx
004D21D1    8BE5           mov esp, ebp
004D21D3    5D             pop ebp
004D21D4    C2 0400        ret 4

--------------------------------------------------------------------------------

这里是生成解密密钥的过程:

---------------------------------------- 004D06EC ----------------------------------------

004D06EC    53             push ebx
004D06ED    8BDA           mov ebx, edx
004D06EF    8BD3           mov edx, ebx        ; MD5值
004D06F1    E8 52FBFFFF    call fixed.004D0248        ; KeySchedule,产生加密子密钥,F7跟进可看到算法
004D06F6    8BC3           mov eax, ebx        ; MD5值
004D06F8    E8 03FDFFFF    call fixed.004D0400        ; 根据加密子密钥生成解密子密钥
004D06FD    5B             pop ebx
004D06FE    C3             ret

--------------------------------------------------------------------------------

生成加密密钥:

---------------------------------------- 004D0248 ----------------------------------------

004D0248    53             push ebx
004D0249    56             push esi
004D024A    57             push edi
004D024B    83C4 F4        add esp, -0C

复制MD5值:

004D024E    8B08           mov ecx, [eax]
004D0250    890A           mov [edx], ecx
004D0252    8D48 04        lea ecx, [eax+4]
004D0255    8B09           mov ecx, [ecx]
004D0257    894A 04        mov [edx+4], ecx
004D025A    8D48 08        lea ecx, [eax+8]
004D025D    8B09           mov ecx, [ecx]
004D025F    894A 08        mov [edx+8], ecx
004D0262    8D48 0C        lea ecx, [eax+C]
004D0265    8B09           mov ecx, [ecx]
004D0267    894A 0C        mov [edx+C], ecx
004D026A    8D48 10        lea ecx, [eax+10]
004D026D    8B09           mov ecx, [ecx]
004D026F    894A 10        mov [edx+10], ecx
004D0272    8D48 14        lea ecx, [eax+14]
004D0275    8B09           mov ecx, [ecx]
004D0277    894A 14        mov [edx+14], ecx
004D027A    8D48 18        lea ecx, [eax+18]
004D027D    8B09           mov ecx, [ecx]
004D027F    894A 18        mov [edx+18], ecx
004D0282    83C0 1C        add eax, 1C
004D0285    8B00           mov eax, [eax]
004D0287    8942 1C        mov [edx+1C], eax
004D028A    33C0           xor eax, eax
004D028C    C70424 0100000>mov dword ptr [esp], 1        ; 循环计数器

循环,计算每一轮的子密钥:

004D0293    8B4C82 1C      mov ecx, [edx+eax*4+1C]        ; MD5值的28-32位作为初始密钥的第8列
004D0297    8BF9           mov edi, ecx
004D0299    C1E7 18        shl edi, 18        ;\
004D029C    C1E9 08        shr ecx, 8        ;-循环右移8位,RotWord
004D029F    0BF9           or edi, ecx        ;/
004D02A1    8BCF           mov ecx, edi
004D02A3    81E1 FF000000  and ecx, 0FF
004D02A9    8B0C8D 7C7D550>mov ecx, [ecx*4+557D7C]        ;查S-Box替换,SubBytes,这段代码是按字节方式算的,所以要4次
004D02B0    894C24 04      mov [esp+4], ecx
004D02B4    8BCF           mov ecx, edi
004D02B6    C1E9 08        shr ecx, 8
004D02B9    81E1 FF000000  and ecx, 0FF
004D02BF    8B0C8D 7C7D550>mov ecx, [ecx*4+557D7C]
004D02C6    8BDF           mov ebx, edi
004D02C8    C1EB 10        shr ebx, 10
004D02CB    81E3 FF000000  and ebx, 0FF
004D02D1    8B349D 7C7D550>mov esi, [ebx*4+557D7C]
004D02D8    8BDF           mov ebx, edi
004D02DA    C1EB 18        shr ebx, 18
004D02DD    81E3 FF000000  and ebx, 0FF
004D02E3    8B1C9D 7C7D550>mov ebx, [ebx*4+557D7C]
004D02EA    895C24 08      mov [esp+8], ebx
004D02EE    8BD9           mov ebx, ecx
004D02F0    C1E3 08        shl ebx, 8
004D02F3    C1E9 18        shr ecx, 18
004D02F6    0BD9           or ebx, ecx
004D02F8    335C24 04      xor ebx, [esp+4]
004D02FC    8BCE           mov ecx, esi
004D02FE    C1E1 10        shl ecx, 10
004D0301    C1EE 10        shr esi, 10
004D0304    0BCE           or ecx, esi
004D0306    33D9           xor ebx, ecx
004D0308    8B4C24 08      mov ecx, [esp+8]
004D030C    C1E1 18        shl ecx, 18
004D030F    8B7424 08      mov esi, [esp+8]
004D0313    C1EE 08        shr esi, 8
004D0316    0BCE           or ecx, esi
004D0318    33D9           xor ebx, ecx
004D031A    331C82         xor ebx, [edx+eax*4]        ; MD5值的前4位作为初始密钥的第1列,与W(i-4)异或
004D031D    8B0C24         mov ecx, [esp]
004D0320    331C8D 007D550>xor ebx, [ecx*4+557D00]        ; 与Rcon(i)异或,得到下一轮子密钥的第1列
004D0327    895C82 20      mov [edx+eax*4+20], ebx
004D032B    FF0424         inc dword ptr [esp]        ; 循环计数器+1
004D032E    8B4C82 04      mov ecx, [edx+eax*4+4]        ; MD5值的5-8位作为初始密钥的第2列
004D0332    334C82 20      xor ecx, [edx+eax*4+20]        ; W(i)与W(i-4)异或,得到密钥的下一列
004D0336    894C82 24      mov [edx+eax*4+24], ecx
004D033A    8B5C82 08      mov ebx, [edx+eax*4+8]        ; MD5值的9-12位作为初始密钥的第3列
004D033E    33D9           xor ebx, ecx        ; W(i)与W(i-4)异或,得到密钥的下一列
004D0340    895C82 28      mov [edx+eax*4+28], ebx
004D0344    8B7C82 0C      mov edi, [edx+eax*4+C]        ; MD5值的13-16位作为初始密钥的第4列
004D0348    33FB           xor edi, ebx        ; W(i)与W(i-4)异或,得到密钥的下一列
004D034A    897C82 2C      mov [edx+eax*4+2C], edi
004D034E    33C9           xor ecx, ecx
004D0350    8A4C82 2C      mov cl, [edx+eax*4+2C]
004D0354    8B0C8D 7C7D550>mov ecx, [ecx*4+557D7C]        ; SubBytes
004D035B    894C24 04      mov [esp+4], ecx
004D035F    8BCF           mov ecx, edi
004D0361    C1E9 08        shr ecx, 8
004D0364    81E1 FF000000  and ecx, 0FF
004D036A    8B0C8D 7C7D550>mov ecx, [ecx*4+557D7C]
004D0371    8BDF           mov ebx, edi
004D0373    C1EB 10        shr ebx, 10
004D0376    81E3 FF000000  and ebx, 0FF
004D037C    8B349D 7C7D550>mov esi, [ebx*4+557D7C]
004D0383    8BDF           mov ebx, edi
004D0385    C1EB 18        shr ebx, 18
004D0388    81E3 FF000000  and ebx, 0FF
004D038E    8B1C9D 7C7D550>mov ebx, [ebx*4+557D7C]
004D0395    895C24 08      mov [esp+8], ebx
004D0399    8BD9           mov ebx, ecx
004D039B    C1E3 08        shl ebx, 8
004D039E    C1E9 18        shr ecx, 18
004D03A1    0BD9           or ebx, ecx
004D03A3    335C24 04      xor ebx, [esp+4]
004D03A7    8BCE           mov ecx, esi
004D03A9    C1E1 10        shl ecx, 10
004D03AC    C1EE 10        shr esi, 10
004D03AF    0BCE           or ecx, esi
004D03B1    33D9           xor ebx, ecx
004D03B3    8B4C24 08      mov ecx, [esp+8]
004D03B7    C1E1 18        shl ecx, 18
004D03BA    8B7424 08      mov esi, [esp+8]
004D03BE    C1EE 08        shr esi, 8
004D03C1    0BCE           or ecx, esi
004D03C3    33D9           xor ebx, ecx
004D03C5    335C82 10      xor ebx, [edx+eax*4+10]        ; MD5值的17-20位作为初始密钥的第5列
004D03C9    895C82 30      mov [edx+eax*4+30], ebx        ; W(i)与W(i-4)异或,得到密钥的下一列
004D03CD    8B4C82 14      mov ecx, [edx+eax*4+14]        ; MD5值的21-24位作为初始密钥的第6列
004D03D1    334C82 30      xor ecx, [edx+eax*4+30]        ; W(i)与W(i-4)异或,得到密钥的下一列
004D03D5    894C82 34      mov [edx+eax*4+34], ecx
004D03D9    8B5C82 18      mov ebx, [edx+eax*4+18]        ; MD5值的25-28位作为初始密钥的第7列
004D03DD    33D9           xor ebx, ecx        ; W(i)与W(i-4)异或,得到密钥的下一列
004D03DF    895C82 38      mov [edx+eax*4+38], ebx
004D03E3    8B4C82 1C      mov ecx, [edx+eax*4+1C]        ; MD5值的28-32位作为初始密钥的第8列
004D03E7    33CB           xor ecx, ebx        ; W(i)与W(i-4)异或,得到密钥的下一列
004D03E9    894C82 3C      mov [edx+eax*4+3C], ecx
004D03ED    83C0 08        add eax, 8
004D03F0    83F8 34        cmp eax, 34
004D03F3  ^ 0F8C 9AFEFFFF  jl fixed.004D0293        ; 共计算7轮,得到14个子密钥
004D03F9    83C4 0C        add esp, 0C
004D03FC    5F             pop edi
004D03FD    5E             pop esi
004D03FE    5B             pop ebx
004D03FF    C3             ret

--------------------------------------------------------------------------------

在这里,作者调用了一个AES的库,很不幸地,或者说很幸运地,这个库被我用Google找到了。有了这个库,上面这段代码跟踪起来就比较轻松了。
下面是部分源码:

这是004D21A0这个Call,AES-256解密:

procedure DecryptAESStreamECB(Source: TStream; Count: cardinal;
  const Key: TAESKey256; Dest: TStream);
var
  ExpandedKey: TAESExpandedKey256;
begin
  ExpandAESKeyForDecryption(Key, ExpandedKey);
  DecryptAESStreamECB(Source, Count, ExpandedKey, Dest);
end;

这是004D06EC这个Call,生成解密密钥:

procedure ExpandAESKeyForDecryption(const Key: TAESKey256; var ExpandedKey: TAESExpandedKey256);
begin
  ExpandAESKeyForEncryption(Key, ExpandedKey);
  ExpandAESKeyForDecryption(ExpandedKey);
end;

我把这个库放到附件里了,有兴趣的朋友可以看看。

++++++++++++++++++++++++++++++++++++++++ 第9关:ZLib 解压 ++++++++++++++++++++++++++++++++++++++++

用注册码+文件名+某字符串的MD5值做密钥,用AES-256算法将KeyFile解密出来以后,来到这里:

004D98B5    8D55 F4        lea edx, [ebp-C]
004D98B8    8B45 F0        mov eax, [ebp-10]        ; AES-256解密后字串
004D98BB    E8 EC91FFFF    call fixed.004D2AAC        ; 用ZLib解压
004D98C0    EB 06          jmp short fixed.004D98C8

ZLib是开源的,而且Delphi自带了ZLib库,有兴趣的可以F7跟进看看算法。
解压后来到这里:

004D98FB    8B45 F4        mov eax, [ebp-C]        ; ZLib解压后字串
004D98FE    E8 91B6F2FF    call fixed.00404F94        ; System.@LStrLen(String):Integer;
004D9903    85C0           test eax, eax
004D9905    74 1F          je short fixed.004D9926
004D9907    8B45 F4        mov eax, [ebp-C]        ; ZLib解压后字串
004D990A    E8 85B6F2FF    call fixed.00404F94        ; System.@LStrLen(String):Integer;
004D990F    83F8 64        cmp eax, 64
004D9912    7C 12          jl short fixed.004D9926        ; 长度<100就Game Over啦
004D9914    EB 06          jmp short fixed.004D991C

呵呵,ZLib解压出来的东东还不能少于100字节呢。

过了这里,就过关啦!
可以Ctrl+F9返回啦!
让我们进入最后一关,挑战最终Boss!

++++++++++++++++++++++++++++++++++++++++ 第10关:MD5 校检 ++++++++++++++++++++++++++++++++++++++++

从这里开始,就是第10关啦:

---------------------------------------- 004D9954 ----------------------------------------

004D9954    55             push ebp
004D9955    8BEC           mov ebp, esp
004D9957    33C9           xor ecx, ecx
004D9959    51             push ecx
004D995A    51             push ecx
004D995B    51             push ecx
004D995C    51             push ecx
004D995D    51             push ecx
004D995E    53             push ebx
004D995F    56             push esi
004D9960    57             push edi
004D9961    8945 FC        mov [ebp-4], eax
004D9964    8B45 FC        mov eax, [ebp-4]
004D9967    E8 18B8F2FF    call fixed.00405184        ; System.@LStrAddRef(void;void):Pointer;
004D996C    33C0           xor eax, eax
004D996E    55             push ebp
004D996F    68 AC9A4D00    push fixed.004D9AAC
004D9974    64:FF30        push dword ptr fs:[eax]
004D9977    64:8920        mov fs:[eax], esp
004D997A    EB 04          jmp short fixed.004D9980

004D9980    C645 FB 00     mov byte ptr [ebp-5], 0        ; 注册标志位清0
004D9984    EB 04          jmp short fixed.004D998A

004D998A    8B45 FC        mov eax, [ebp-4]        ; KeyFile解密后的字串
004D998D    E8 02B6F2FF    call fixed.00404F94        ; System.@LStrLen(String):Integer;
004D9992    85C0           test eax, eax
004D9994    75 0D          jnz short fixed.004D99A3

004D99A3    33C0           xor eax, eax
004D99A5    55             push ebp
004D99A6    68 E0994D00    push fixed.004D99E0
004D99AB    64:FF30        push dword ptr fs:[eax]
004D99AE    64:8920        mov fs:[eax], esp
004D99B1    EB 04          jmp short fixed.004D99B7

取字符串的最后32字节:

004D99B7    8D45 F4        lea eax, [ebp-C]
004D99BA    50             push eax
004D99BB    8B45 FC        mov eax, [ebp-4]        ; KeyFile解密后的字串
004D99BE    E8 D1B5F2FF    call fixed.00404F94        ; System.@LStrLen(String):Integer;
004D99C3    8BD0           mov edx, eax
004D99C5    83EA 20        sub edx, 20
004D99C8    42             inc edx
004D99C9    B9 20000000    mov ecx, 20
004D99CE    8B45 FC        mov eax, [ebp-4]        ; 字符串
004D99D1    E8 1EB8F2FF    call fixed.004051F4        ; System.@LStrCopy
004D99D6    33C0           xor eax, eax
004D99D8    5A             pop edx
004D99D9    59             pop ecx
004D99DA    59             pop ecx
004D99DB    64:8910        mov fs:[eax], edx
004D99DE    EB 26          jmp short fixed.004D9A06

004D9A06    33C0           xor eax, eax
004D9A08    55             push ebp
004D9A09    68 519A4D00    push fixed.004D9A51
004D9A0E    64:FF30        push dword ptr fs:[eax]
004D9A11    64:8920        mov fs:[eax], esp
004D9A14    EB 06          jmp short fixed.004D9A1C

取字符串的其余字节:

004D9A1C    8D45 EC        lea eax, [ebp-14]
004D9A1F    50             push eax
004D9A20    8B45 FC        mov eax, [ebp-4]        ; 字符串
004D9A23    E8 6CB5F2FF    call fixed.00404F94        ; System.@LStrLen(String):Integer;
004D9A28    8BC8           mov ecx, eax
004D9A2A    83E9 20        sub ecx, 20
004D9A2D    BA 01000000    mov edx, 1
004D9A32    8B45 FC        mov eax, [ebp-4]        ; 字符串
004D9A35    E8 BAB7F2FF    call fixed.004051F4        ; System.@LStrCopy;
004D9A3A    8B45 EC        mov eax, [ebp-14]
004D9A3D    8D4D F0        lea ecx, [ebp-10]
004D9A40    33D2           xor edx, edx
004D9A42    E8 A966FFFF    call fixed.004D00F0        ; 加上某字符串,取MD5,这个Call在第7关计算AES-256密钥时见过
004D9A47    33C0           xor eax, eax
004D9A49    5A             pop edx
004D9A4A    59             pop ecx
004D9A4B    59             pop ecx
004D9A4C    64:8910        mov fs:[eax], edx
004D9A4F    EB 23          jmp short fixed.004D9A74

004D9A47    33C0           xor eax, eax
004D9A49    5A             pop edx
004D9A4A    59             pop ecx
004D9A4B    59             pop ecx
004D9A4C    64:8910        mov fs:[eax], edx
004D9A4F    EB 23          jmp short fixed.004D9A74

004D9A74    EB 04          jmp short fixed.004D9A7A

004D9A7A    8B45 F0        mov eax, [ebp-10]        ; 计算出的MD5值
004D9A7D    8B55 F4        mov edx, [ebp-C]        ; 注册码后32位
004D9A80    E8 5BB6F2FF    call fixed.004050E0        ; System.@LStrCmp;
004D9A85    0F9445 FB      sete [ebp-5]        ;设置注册标志位

原来是这样:ZLib解压出来的不小于100字节的东东,后32字节作为校检码,如果和前面字节的MD5相等,就注册成功啦!

到这里,历尽艰难险阻,终于通关啦!!!

--------------------------------------------------------------------------------
【总结】

    KeyFile的文件名用了自定义的算法,其余都用了标准算法,尤其是用MD5值做密钥,用了高强度的AES-256算法。

写到这里已经很累了,不想做注册机了。

下面举一个例子,作为注册流程和算法总结:

用户名:Ptero
注册码:COFFB00000-00000000
程序名:EasyCHM.EXE
KeyFile文件名:chm2259abbf22f.dll
KeyFile内容:
00000000h: 2C 00 00 00 08 CD EA 55 F3 C0 8E 1B 4F AA 26 04 ; ,....完U罄?O?.
00000010h: 72 FC 23 E7 68 6F DD 7D DD DC EF 48 86 4E 70 1E ; r?玷o蔟蒈锶?p.
00000020h: 62 BC 9E 40 C0 1A 4C 5A EE 80 DB A8 F4 61 98 C8 ; b?@?LZ?郇翎?
00000030h: 65 68 53 B6                                     ; ehS

算法:

1. 用MD5的方法验证注册码前2位:"QE""EC""ET"为个人用户,"CO""LT""LD"为企业用户
2. 如果是企业用户,则取注册码前4位"FFB0"异或4Fh=FFFFh(65535)为许可证数量
3. 用第6关的算法算出KeyFile文件名"chm2259abbf22f.dll"
4. 注册码+程序名(大写)+特定字符串:"COFFB00000-00000000EASYCHM.EXEbZxvRs2puRGpimSWzVBwwLTExBEHS1CJDJFawAZRwKFs4NCZRoxQX5N1W+RvRs2p5oimqGRL3ApwwA0bg0OZRsgor8nq"
5. 取MD5值(小写)的Ascii码:"dd069b9bb7ce9f3570ae1a2d40ca38b2"
6. 用此MD5的Ascii码作为256位初始密钥,解密KeyFile第4字节以后的内容
7. KeyFile前4字节为明文长度(2Ch)
   解密为:
   00000000h: 78 9C 33 30 A0 1C 98 A7 A5 18 98 5B 58 9A A4 99 ; x?0????X??
   00000010h: 98 A5 98 9A 98 25 25 1A 24 1B 26 25 9A 58 18 24 ; ???%.$.&%?.$
   00000020h: 5B 98 5A 58 58 18 02 00 DF 40 15 30             ; [?XX...呃.0
8. 再用ZLib解压,得到:"000000000000000000000000000000000000000000000000000000000000000000007fd07894f46d546ba0c1ba480c858881"
9. 此字符串的前68字节+特定字符串:"00000000000000000000000000000000000000000000000000000000000000000000bZxvRs2puRGpimSWzVBwwLTExBEHS1CJDJFawAZRwKFs4NCZRoxQX5N1W+RvRs2p5oimqGRL3ApwwA0bg0OZRsgor8nq"
10.取MD5:7fd07894f46d546ba0c1ba480c858881,再转换成Ascii码
   与字符串的后32字节比较,如果相等即注册成功!

后记:其实这篇文章还有很多不完善之处,比如19楼提到的,只是表面上注册成功了,实际上还是有功能限制的。相关算法我现在正在研究之中,过段时间会再发一篇的。

----------------------------------------------------

【版权声明】   本文纯属技术交流, 转载请注明作者并保持文章的完整, 谢谢


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

上传的附件:
收藏
免费 7
支持
分享
最新回复 (40)
雪    币: 846
活跃值: (221)
能力值: (RANK:570 )
在线值:
发帖
回帖
粉丝
2
似乎IDA的调试功能还是有人用的?
但是我怎么都用不惯
2006-11-29 10:05
0
雪    币: 452
活跃值: (72)
能力值: ( LV9,RANK:330 )
在线值:
发帖
回帖
粉丝
3
没用IDA调试过。不过IDA 5.0 的那个看流程图的功能很不错啊
2006-11-29 10:07
0
雪    币: 440
活跃值: (737)
能力值: ( LV9,RANK:690 )
在线值:
发帖
回帖
粉丝
4
精彩
算法够复杂的
2006-11-29 10:32
0
雪    币: 146
活跃值: (72)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
5
呵呵,国华的,一个字汗。
好在楼主自有妙法解之,强~
2006-11-29 10:48
0
雪    币: 1919
活跃值: (901)
能力值: ( LV9,RANK:490 )
在线值:
发帖
回帖
粉丝
6
这个的确比较牛,搞了几次没搞出算法来
文章很精彩,难得一见的好帖,强烈支持~~~~~~~~
2006-11-29 10:50
0
雪    币: 1919
活跃值: (901)
能力值: ( LV9,RANK:490 )
在线值:
发帖
回帖
粉丝
7
对了,在自效验检测中改为jmp不行,应该改为nop,askformore的帖子也是说的改为nop
2006-11-29 11:14
0
雪    币: 452
活跃值: (72)
能力值: ( LV9,RANK:330 )
在线值:
发帖
回帖
粉丝
8
失误,写错了
多谢提醒,已经改了
2006-11-29 11:17
0
雪    币: 846
活跃值: (221)
能力值: (RANK:570 )
在线值:
发帖
回帖
粉丝
9
刚学逆向的时候也觉得流程图不错,可是现在看起来,反而越看越乱了。

主要是循环不够直观。

楼主无论耐性和理解能力都很强,这么长的代码,我是肯定没耐性的
2006-11-29 11:24
0
雪    币: 452
活跃值: (72)
能力值: ( LV9,RANK:330 )
在线值:
发帖
回帖
粉丝
10
我觉得循环很直观啊
看见往回指的箭头就是循环了啊
还有,这段代码,我分析了一个星期,累坏了……
2006-11-29 11:28
0
雪    币: 267
活跃值: (44)
能力值: ( LV9,RANK:330 )
在线值:
发帖
回帖
粉丝
11
太强了,支持!
2006-11-29 11:58
0
雪    币: 405
活跃值: (10)
能力值: ( LV9,RANK:1130 )
在线值:
发帖
回帖
粉丝
12
收藏,学习

加密算法

我的最爱!   等下我也弄弄

确实不行啊。要keyfile的,我这里。不过楼主研究了这么就值得瞻仰
2006-11-29 12:03
0
雪    币: 312
活跃值: (27)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
惊叹楼主技艺之精!感谢楼主的详细解说!
2006-11-29 12:04
0
雪    币: 441
活跃值: (149)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
14
太强了,要是我脑袋可能晕掉。
2006-11-29 12:34
0
雪    币: 417
活跃值: (475)
能力值: ( LV9,RANK:1250 )
在线值:
发帖
回帖
粉丝
15
膜拜。
收藏作为参考。
谢谢楼主,强就一个字!
2006-11-29 12:35
0
雪    币: 370
活跃值: (15)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
16
解剖EASYCHM
过程、书写都确实精彩
没看完,已经晕了,不由得佩服
收藏之
2006-11-29 12:53
0
雪    币: 136
活跃值: (429)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
17
真是太强了
2006-11-29 13:10
0
雪    币: 210
活跃值: (11)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
18
学到好多东西 强啊 支持楼主!
2006-11-29 13:11
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
好像只是表面注册成功,请试试编译或反编译功能,生成的文件一样有未注册提示
2006-11-29 13:12
0
雪    币: 647
活跃值: (564)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
20
只能膜拜
2006-11-29 13:18
0
雪    币: 205
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
wsj
21
拜一下,收藏之。
2006-11-29 13:48
0
雪    币: 452
活跃值: (72)
能力值: ( LV9,RANK:330 )
在线值:
发帖
回帖
粉丝
22
感谢19楼的提醒,我再研究一下
2006-11-29 13:51
0
雪    币: 1919
活跃值: (901)
能力值: ( LV9,RANK:490 )
在线值:
发帖
回帖
粉丝
23
我这里注册都成功不了。以前的注册码有3段。
给个参考码:
注册名:jeike
注册码:QE33C382354-1161-AF9DA499
2006-11-29 14:07
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24
好像这个软件没有作者的keyfile是无法破解的,我这里有一个正版注册码可供参考,不过只能用于1.96版

尊敬的注册用户 jeike 先生/女士 您好,

  感谢您对软件作者的支持!
  您注册的是“EasyCHM”的 单用户标准版,以后可以得到免费的版本升级。

  Email附件里面是专用注册文件(文件名是: chm14769d299915.dll ),请双击本邮件,选择保存文件到“EasyCHM”所在的目录下。

     您的注册名是:jeike
     您的注册码是:QE33C382354-1161-AF9DA499

还有一个chm14769d299915.dll,怎么传给你,大小是836 字节

32030000C155A950B5F59EFB66D06A97F215C2715E0D8200DAA621442030E482F16E63C43E277123FF12F0B1C9D27AB1BD951F85939B4AD1DD205462288C2303D9CAAD1A41239A7C1A5510952F9A0BEC5E3B3B4765D63B57C50A0BC1C6B66B0166B8C7FAAB6220BDC64B9D26199D5FBFECDCEF892BE61EA640702BE5905BDD853B50B02C4E40B0F9AC7E9D445153B17CC160E8829D9610EAB2C29BD6D68E1658DDE0A935D1960956C735DA065D2643E1BF42BA89C7CFBACDA4CD09EA8905D218F06D358507398EA1A2D630DB6B1ACB429313D606629F69DEEF66C44AB1E83189BB56CCFA3E71EB75E41A379A25312BE7F39512331660D2AC0AA56DBBC67283604CCF2789CDE32A937043C3DF37A262692AB196B2BAC515CC6AB6FDBCB4BF91CA1ACDC4FBEC44FA58E020FE004D659945727DC9A0521461296A4B7B46E936F153763FA94F93A7A619FD72F24646EF902CAA8A7E344AE67712181D7A64D8AC7769B98A4026016D13BA511122CEA625E1CF90CA96453F6A05C0A52005B83CDC3FF0D1AB6AAD81F0A16C0F3CC54615C0AE265BB84C048ECF7935C0C821E2C1F41B353F08855D24DD9B83398C974E260ADA481186CC030FAC925CF3B3013413CDD20CC96D2124A3DF4F78D081931F5A3D302F16638302BF3BA5A1C5D1F89B065683C0E89F3836B4637B38BF34186A733B96CBF0F95A0B6FCFDA909DA239755D08352D2C02CCE6D6EF2805778949E9C2F6C9CA5743CC52A3F594CE696EB96A76E6797B95D4D2438420E1262D80709A51659EF6F451E3B58B7E97D9AA43E3DBB22FDBACFCBC619CA5B7B6069FE055AD1429BEB59EA34678AFF9EDE877FF85D1791624AF80F7A304FDC935D82D25A7E7EF1CACB4F04039BCED8DD832486953DCA227F43F2E344EFCF4A14A54BD8CC59981DFD742DB6635CAC8D729908EC8F5C0E8AD5DC8084B917F7233E75A7959DB0385429F9E125AB54642AF7554589EF90435A42BF63F096913A9947BA7EDD205AF62BF5CCD3582F73D7650082A56E4C5D1E0C9D9DB5B42CD2A7F0E4FC27859D920B841C8FC2C087531928CD9539A717AC10727AA00171AB313ED4DFF58B1AFDF6086F3031E4FF13ED1C165F0F3B3DBB5F4BCE963E8ED132505E09198C5DDD378FDA5529073252FC5FB5127E7D429792A3ED35298372F453DC4
2006-11-29 14:15
0
雪    币: 256
活跃值: (268)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
25
楼主学习的榜样啊!技术加耐力!
2006-11-29 14:46
0
游客
登录 | 注册 方可回帖
返回
//