吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 4431|回复: 9
上一主题 下一主题
收起左侧

[CrackMe] 【吾爱破解六周年小玩具-大叔的草莓】题解

[复制链接]
跳转到指定楼层
楼主
MistHill 发表于 2014-3-8 13:44 回帖奖励
CM是什么?Crackme是什么?这是什么东西?楼主发的什么?
他们都是一些公开给别人尝试破解的小程序,制作 Crackme 的人可能是程序员,想测试一下自己的软件保护技术,也可能是一位 Cracker,想挑战一下其它 Cracker 的破解实力,也可能是一些正在学习破解的人,自己编一些小程序给自己破解,KeyGenMe是要求别人做出它的 keygen (序号产生器), ReverseMe 要求别人把它的算法做出逆向分析, UnpackMe 是要求别人把它成功脱壳,本版块禁止回复非技术无关水贴。

本帖最后由 MistHill 于 2014-3-10 18:21 编辑

原帖:
吾爱破解六周年小玩具-大叔的草莓CM20140313
http://www.52pojie.cn/thread-240878-1-1.html
(出处: 吾爱破解论坛 - LCG - LSG |软件安全|病毒分析|破解软件|软件论坛|www.52pojie.cn)



好事情哦,有好玩的,又有丰厚的奖品,真是大叔们的节日,希望大家都来参与,你不会失望的!

拿到题目后,首先静态地检查一下,即俗称“查壳”。嗯,UPX,很好。但是“UPX -d”解压缩失败,看来Kido封装时抹掉了解压信息。
不过我有脚本可以轻松脱掉!推销一下 ,在这里:“UPX完美脱壳脚本”。
这样分析起来方便一些,可以上IDA去理解那些密码学的东西。

先运行一下,唔“弹窗”出来了,提示“硬件码”;点“确定”,正常进入界面,不错。说明脱壳没有问题,困惑的是这个草莓怎么连最基本的文件校验都没有!?(Peace:走着瞧吧,大叔!{:1_912:} )

但是界面显示的是“注册”按钮,“试用版”没有意义。解出KeyFile.dat文件,再来,这次提示"检测到程序被非法篡改或注册文件为伪造!!!",杯具鸟。
…………
分析的结果是:解密KeyFile.dat文件的内容需要硬盘的物理序列号,而序列号可从“硬件码”解密得到。虽然可以从后续代码对KeyFile.dat解密后数据的处理一步一个地分析,这个过程实在痛苦。
蒜辣,偷个懒。昨天去主帖回复,瞧了瞧Key绑定的硬件码。这样,事情就简单了!
…………未玩,待续!

放个“完美破解版”,大家先玩玩。Patch的方法,以后会详细说。学习Kido的UPX压缩处理,逼迫你去用我的脚本!




10/03/2014 编辑
300CB进帐,一高兴,再写一段。
首先感谢那个谁,whoever,帮我加上了原帖链接,否则搞得那些糊涂的小伙伴一头雾水,你这究竟是个啥玩意儿!?
不过,尊敬的Ms. Peace,按原帖某条某款,我这个至少也值1000CB喔:完美破解成品+通用key(虽说这个KeyFile.dat不是我自己生成的 )。
我其实是惦记着秀才娘子家的床(指那2000CB)来着,害怕一不留神让别人抬了去。那也没办法,得承认确实没有孔先生那么学识渊博,“茴香”这两字儿就老是写不对。
屌丝祖辈就是这个Q样,屌得很:说我牛,那是骂我菜鸟(Newbie),说我是大婶,当我神经病迈?总之,精神上先败了一阵。

说到CB,想到另一件事。前段时间,大概是本版有个帖子悬赏1000CB破网络验证,玩了一下,搞定了(就是让服务端返回剩余次数99999那个,看过的人可能有点印象)。明显是求破了,后来被版主删帖。
这位仁兄把大家当傻子,肯定不妥!是的,既不是牛鬼蛇神,就装一回Q。人有时侯傻一点儿好,会过得比较快乐。
该仁兄就PM我了,说要兑现那1000CB,让我帮帮他。回:不用了,玩玩而已。知道那个附件其实是假的、投石问路的东西。回:你这样藏着掖着、不来真家伙我也帮不了。
后来,真东西来了。我一看就明白是啥了,很多年前曾接触过这行,灰色的。主程序在我的虚拟机里界面都出不来,需要Direct3D的支持,折腾了半天终于解决了这个困扰了我好几年的问题。发现我真笨,很简单的,但觉得这比1000CB要值!
然后,分析它用于注入的apphelp.dll,这是个系统DLL,不知是那位老兄弄的,"Bad Idea!"。它由system32里的一个系统DLL载入,程序文件夹里的根本就没用上。阻止操作系统的文件保护后,将其复制到system32文件夹,系统有的功能又不正常。
后来不得不修改主程序,先载入这个DLL。帮他解决问题后,这家伙就杳无音信了。
废话这么多,是想说结果不重要,如果你享受这个过程就好了!

言归正传。本题的破解思路简单明了:想办法正确解密KeyFile.dat文件,然后测试软件的功能是否正常!

有一种手机游戏,当你收集齐那些必须的宝贝后,才能过到下一关。现在,整个过程就象这样!需要找出两个关键的东西,才能通关。
但是这个游戏我们应该从哪里下手呢?
最通用的快速定位办法是在OD里当出现那个"检测到程序被非法篡改或注册文件为伪造!!!"提示时,F12暂停,从"Call stack"里一层一层往回找跳向user32.MessageBoxExA的判断。
这个方法比较啰嗦,还需要一定的经验。针对本题更简单、直接一点的办法是定位对文件KeyFile.dat的读入,即断kernel32.CreateFileA和kernel32.ReadFile。
很基本的操作,为节省篇幅,直接给出关键代码段。
从两个APIs的调用断下后,RET……,直到这里:
[Asm] 纯文本查看 复制代码
00401A1B    68 04000080        PUSH    0x80000004
00401A20    6A 00              PUSH    0x0
00401A22    8B45 FC            MOV     EAX, DWORD PTR [EBP-0x4]
00401A25    85C0               TEST    EAX, EAX
00401A27    75 05              JNZ     SHORT 00401A2E
00401A29    B8 C06C4700        MOV     EAX, 00476CC0
00401A2E    50                 PUSH    EAX
00401A2F    68 01000000        PUSH    0x1
00401A34    BB 103C4000        MOV     EBX, 00403C10
00401A39    E8 67190000        CALL    004033A5
00401A3E    83C4 10            ADD     ESP, 0x10        ; <- 返回这里

这时,"ALT+K"打开"Call stack"窗口。注意最顶一行:"Called from"=0040154E,"Procedure / arguments"=004016E2。
[Plain Text] 纯文本查看 复制代码
Address    Stack      Procedure / arguments     Called from           Frame
0012FD28   00401553   CM201403.004016E2         CM201403.0040154E     0012FD24

好了,我们的游戏就从Sub_004016E2开始:
[Asm] 纯文本查看 复制代码
004016E2    55                 PUSH    EBP
004016E3    8BEC               MOV     EBP, ESP
004016E5    81EC 34000000      SUB     ESP, 0x34
004016EB    C745 FC 00000000   MOV     DWORD PTR [EBP-0x4], 0x0
004016F2    C745 F8 00000000   MOV     DWORD PTR [EBP-0x8], 0x0
...
00402400  |> \B8 01000000      MOV     EAX, 0x1
00402405  |.  E9 00000000      JMP     0040240A
0040240A  |>  8BE5             MOV     ESP, EBP
0040240C  |.  5D               POP     EBP
0040240D  \.  C2 0800          RETN    0x8

OD重新载入"小玩具",断下004016E2。
但凡写过点儿代码的人,包括用E(不是不屑,是羡慕嫉妒恨,我根本就不会:()的人,都知道对函数的调用都需要传递参数,无论是值或引用/指针,一是通过栈,二是通过寄存器。
下面只贴关键CALL的代码,其他一律F8过。注意调用之前的ECX值(输入之一)和调用之后的EAX值(主要输出),然后就是栈上的参数个数及其内容。
很快,遇到第一个关键CALL:
[Asm] 纯文本查看 复制代码
00401727  |.  68 04000080      PUSH    0x80000004
0040172C  |.  6A 00            PUSH    0x0
0040172E  |.  A1 18EA4900      MOV     EAX, DWORD PTR [0x49EA18]
00401733  |.  85C0             TEST    EAX, EAX
00401735  |.  75 05            JNZ     SHORT 0040173C
00401737  |.  B8 C06C4700      MOV     EAX, 00476CC0
0040173C  |>  50               PUSH    EAX
0040173D  |.  68 04000080      PUSH    0x80000004
00401742  |.  6A 00            PUSH    0x0
00401744  |.  68 D06C4700      PUSH    00476CD0         ; ASCII "AD04E9F801BF0DB6"
00401749  |.  68 02000000      PUSH    0x2
0040174E  |.  B8 01000000      MOV     EAX, 0x1
00401753  |.  BB C0AD4400      MOV     EBX, 0044ADC0
00401758  |.  E8 541C0000      CALL    004033B1
Stack:
   0012FCD4   00000002
   0012FCD8   00476CD0  ASCII "AD04E9F801BF0DB6"
   0012FCDC   00000000
   0012FCE0   80000004
   0012FCE4   00476CC5  ASCII "PeaceWorld"
   0012FCE8   00000000
   0012FCEC   80000004
0040175D  |.  83C4 1C          ADD     ESP, 0x1C        ; 平衡栈,此值可用于判断参数个数

先说一下E的调用特征。首先,猜测004033B1只是一个接口,EBX的0044ADC0才是函数的入口地址!切记!
其次,调用传递了三个参数:寄存器一个EAX=0x01;栈上有两个,[0012FCD4]=00000002。
第三,每参数占用3个DWORDs:指向字符串的指针、00000000(含义未知)、数据类型80000004(栈上两个参数的类型为简单的ASCII字符串)。这点和VB类似,虽说E是基于VC6的。
F8,注意EAX返回值,比如00160700。也是一个指向字符串的指针,ASCII "5"(\0x35\0)。后面00401781处会转换其为Hex值,作为计算判断的初始值。意义不详,只有作者自己知道,貌视重要,现在不管它。
提前说一下,显然Sub_0044ADC0是关键的。其功能是后来跟进去才清晰的:一个解密函数。Key在00476CC5,密文在00476CD0,解密后明文在00160700。后面再详细说它,这里我们只管继续F8。
[Asm] 纯文本查看 复制代码
004017A4  |.  68 00000000      PUSH    0x0
004017A9  |.  BB 20344000      MOV     EBX, 00403420    ; 取执行文件所在文件夹
004017AE  |.  E8 F21B0000      CALL    004033A5
...
004017E0  |.  B8 01000000      MOV     EAX, 0x1
004017E5  |.  BB C0AD4400      MOV     EBX, 0044ADC0    ; 解密得到"\KeyFile.dat"
004017EA  |.  E8 C21B0000      CALL    004033B1
Stack:
   0012FCD4   00000002
   0012FCD8   00476CE1  ASCII "C3C67669019F120876D61E59C4CEC2FD"
   0012FCDC   00000000
   0012FCE0   80000004
   0012FCE4   00476CC5  ASCII "PeaceWorld"
   0012FCE8   00000000
   0012FCEC   80000004
...
004017FB  |.  B9 02000000      MOV     ECX, 0x2
00401800  |.  E8 BDFDFFFF      CALL    004015C2         ; strcat,得到"C:\Temp\52CM2013\T240878\KeyFile.dat"
...
00401843  |.  68 00000000      PUSH    0x0
00401848  |.  BB 40344000      MOV     EBX, 00403440    ; 取执行文件名,"CM20140313.exe"
0040184D  |.  E8 531B0000      CALL    004033A5
...
00401871  |.  B8 01000000      MOV     EAX, 0x1
00401876  |.  BB 30AE4400      MOV     EBX, 0044AE30    ; 计算文件Checksum/Hash
0040187B  |.  E8 311B0000      CALL    004033B1         ; 返回 EAX=EE45E211
   0012FCE0   00000001
   0012FCE4   0015D868  ASCII "CM20140313.exe"
   0012FCE8   00000000
   0012FCEC   80000004

这个文件校验和非常重要,后面会一再使用!注意:这里的File_Checksum值EE45E211是我解压缩后调试用执行文件的,非原执行文件的!
继续:
[Asm] 纯文本查看 复制代码
004018E3  |.  B8 01000000      MOV     EAX, 0x1
004018E8  |.  BB 30AC4400      MOV     EBX, 0044AC30    ; 取硬盘序列号
004018ED  |.  E8 BF1A0000      CALL    004033B1         ; 返回 EAX=0015D868 ASCII "01000000000000000001"
   0012FCE0   00000001
   0012FCE4   00000000
   0012FCE8   00000000
   0012FCEC   80000301

不要奇怪,这是我调试虚拟机里第一个硬盘的序列号!记为:Harddisk_SN。这个虚拟系统的第一个硬盘序列号总是这串值,所以最近遇到的几个目标都限制在虚拟机里运行。继续:
[Asm] 纯文本查看 复制代码
0040199D  |.  B8 01000000      MOV     EAX, 0x1
004019A2  |.  BB 50AD4400      MOV     EBX, 0044AD50    ; 加密序列号
004019A7  |.  E8 051A0000      CALL    004033B1         ; 返回 EAX=00160740 ASCII "49C6227137E9F5F18614F3A2C9E58E5493FBD238F68B307E"
   0012FCD4   00000002
   0012FCD8   0015D868  ASCII "01000000000000000001"
   0012FCDC   00000000
   0012FCE0   80000004
   0012FCE4   00476CC5  ASCII "PeaceWorld"
   0012FCE8   00000000
   0012FCEC   80000004

重要:这里我调试机器的“硬件码”就出来了,它简单地由硬盘序列号加密得到。继续:
[Asm] 纯文本查看 复制代码
00401A2F  |.  68 01000000      PUSH    0x1
00401A34  |.  BB 103C4000      MOV     EBX, 00403C10    ; 读入Key
00401A39  |.  E8 67190000      CALL    004033A5         ; 返回 EAX=0015CF68
   0012FCE0   00000001
   0012FCE4   00160710  ASCII "C:\Temp\52CM2013\T240878\KeyFile.dat"
   0012FCE8   00000000
   0012FCEC   80000004

看到了吧,到了我们一开始定位到的文件读取调用Sub_00403C10。返回的指针0015CF68是一个结构/对象:[0015CF68][0]=00000001,大概是引用记数。[0015CF68][4]=00000058为读入KeyFile.dat的字节数。[0015CF68][8]...=Key文件内容。
[Asm] 纯文本查看 复制代码
00401A50  |.  B9 02000000      MOV     ECX, 0x2
00401A55  |.  E8 68FBFFFF      CALL    004015C2         ; strcat, 返回 0015FC10 ASCII "EE45E21101000000000000000001"
   0012FCE8   0015E0C0  |Arg1 = 0015E0C0 ASCII "EE45E211"
   0012FCEC   0015D868  \Arg2 = 0015D868 ASCII "01000000000000000001"
...
00401A8D  |.  B8 01000000      MOV     EAX, 0x1
00401A92  |.  BB 70AC4400      MOV     EBX, 0044AC70
00401A97  |.  E8 15190000      CALL    004033B1
   0012FCD4   00000002
   0012FCD8   0015CF68  Key对象
   0012FCDC   00000000
   0012FCE0   80000005
   0012FCE4   0015FC10  ASCII "EE45E21101000000000000000001"
   0012FCE8   00000000
   0012FCEC   80000004

在处理Key的内容了,Sub_0044AC70又是一个关键CALL,要跟进去!
[Asm] 纯文本查看 复制代码
0044AC70   .  B8 64100000      MOV     EAX, 0x1064
0044AC75   .  E8 56B20000      CALL    00455ED0
0044AC7A   .  55               PUSH    EBP
0044AC7B   .  56               PUSH    ESI
...
0044AC98   .  53               PUSH    EBX
0044AC99   .  57               PUSH    EDI
0044AC9A   .  55               PUSH    EBP
0044AC9B   .  E8 B2A80100      CALL    00465552   ; 请求00000058字节的内存,返回地址00A463E0,并复制Key数据。
...
0044ACDA   .  50               PUSH    EAX
0044ACDB   .  F3:A4            REP     MOVS BYTE PTR ES:[EDI], BYTE PTR [ESI]
0044ACDD   .  8B8C24 84100000  MOV     ECX, DWORD PTR [ESP+0x1084]
0044ACE4   .  33C0             XOR     EAX, EAX
0044ACE6   .  8B51 0C          MOV     EDX, DWORD PTR [ECX+0xC]
0044ACE9   .  83C9 FF          OR      ECX, 0xFFFFFFFF
0044ACEC   .  8BFA             MOV     EDI, EDX
0044ACEE   .  F2:AE            REPNE   SCAS BYTE PTR ES:[EDI]
0044ACF0   .  F7D1             NOT     ECX
0044ACF2   .  49               DEC     ECX
0044ACF3   .  51               PUSH    ECX
0044ACF4   .  52               PUSH    EDX
0044ACF5   .  8D4C24 20        LEA     ECX, DWORD PTR [ESP+0x20]
0044ACF9   .  E8 38290000      CALL    0044D636
   0012EC34   0015FC10  |Arg1 = 0015FC10 ASCII "EE45E21101000000000000000001"
   0012EC38   0000001C  |Arg2 = 0000001C
   0012EC3C   0012EC50  \Arg3 = 0012EC50
0044ACFE   .  6A 00            PUSH    0x0
0044AD00   .  55               PUSH    EBP
0044AD01   .  53               PUSH    EBX
0044AD02   .  53               PUSH    EBX
0044AD03   .  8D4C24 24        LEA     ECX, DWORD PTR [ESP+0x24]
0044AD07   .  E8 1F2D0000      CALL    0044DA2B                 ; ECX=0012EC54, "Key Schedule"
   0012EC30   00A463E0  |Arg1 = 00A463E0                        ; pOutput, 明文
   0012EC34   00A463E0  |Arg2 = 00A463E0                        ; pInput, 密文 - KeyFile.dat的内容
   0012EC38   00000058  |Arg3 = 00000058                        ; Size of Input, 密文长度
   0012EC3C   00000000  \Arg4 = 00000000                        ; 0 - decrypting?
0044AD0C   .  8B03             MOV     EAX, DWORD PTR [EBX]     ; 解密后第一个DWORD的值
0044AD0E   .  3BC5             CMP     EAX, EBP                 ; 是否 > 密文长度?
0044AD10   .  77 16            JA      SHORT 0044AD28           ; YES - Game over!
0044AD12   .  8D4B 04          LEA     ECX, DWORD PTR [EBX+0x4]
0044AD15   .  50               PUSH    EAX
0044AD16   .  51               PUSH    ECX
0044AD17   .  E8 C465FCFF      CALL    004112E0
0044AD1C   .  8B9424 80100000  MOV     EDX, DWORD PTR [ESP+0x1080]
0044AD23   .  83C4 08          ADD     ESP, 0x8
0044AD26   .  8902             MOV     DWORD PTR [EDX], EAX
0044AD28   >  53               PUSH    EBX
0044AD29   .  E8 4DA80100      CALL    0046557B
0044AD2E   .  83C4 04          ADD     ESP, 0x4
0044AD31   .  8D4C24 14        LEA     ECX, DWORD PTR [ESP+0x14]
0044AD35   .  E8 4E2E0000      CALL    0044DB88
0044AD3A   .  5F               POP     EDI
0044AD3B   .  5B               POP     EBX
0044AD3C   >  5E               POP     ESI
0044AD3D   .  5D               POP     EBP
0044AD3E   .  81C4 64100000    ADD     ESP, 0x1064
0044AD44   .  C3               RETN

关键调用Sub_0044D636的作用:用字符串File_Checksum+Harddisk_SN("EE45E21101000000000000000001")作为key去初始化0012EC54处的"Key Schedule"。
关键调用Sub_0044DA2B是一个解密KeyFile.dat文件的函数!

到了这里,再跟下去就没有意义了。首先,我的文件校验值File_Checksum=EE45E211是错的!这不是问题,用未解压缩的原版调试一下就得到了,正确值为:3E9CDB90。
问题在于没有与KeyFile.dat文件对应的Harddisk_SN,即Key文件所绑定机器的序列号!无法得到正确的解密结果!

试想要是弄到那个序列号,哼哼……
这个在实战中是不太可能得到的,只能硬着头皮继续往下走。现在,既然善良的Ms. Peace已经提供了它,也明知快餐不利于健康,但是我决定还是去回帖,偷看那个与Key绑定的硬件码。不知算不算作弊,想知道的,也去回复吧!

有了硬件码,再由它计算序列号就简单了!还记得本文一开始提到00401758处的第一个关键CALL Sub_0044ADC0吗?
[Asm] 纯文本查看 复制代码
0040174E  |.  B8 01000000      MOV     EAX, 0x1
00401753  |.  BB C0AD4400      MOV     EBX, 0044ADC0
00401758  |.  E8 541C0000      CALL    004033B1
   0012FCD4   00000002
   0012FCD8   00476CD0  ASCII "AD04E9F801BF0DB6"  ; <- ***
   0012FCDC   00000000
   0012FCE0   80000004
   0012FCE4   00476CC5  ASCII "PeaceWorld"
   0012FCE8   00000000
   0012FCEC   80000004

演示一下怎么利用它来解密序列号。将密文"AD04E9F801BF0DB6",替换为本机的硬件码:在数据段找块空地儿,比如0048EE00,写入“硬件码”,再相应修改[0012FCD8]的指针为这样:
[Asm] 纯文本查看 复制代码
   0012FCD4   00000002
   0012FCD8   0048EE00  ASCII "49C6227137E9F5F18614F3A2C9E58E5493FBD238F68B307E" ; <- *** 硬件码
   0012FCDC   00000000
   0012FCE0   80000004
   0012FCE4   00476CC5  ASCII "PeaceWorld"
   0012FCE8   00000000
   0012FCEC   80000004

F8,就得到解密的序列号EAX=0015D868 ASCII "01000000000000000001"。

其实作为对称密码算法,加密和解密使用相同的加/解密函数,只是"Key Schedule"的初始化不同!从前面提到的加密序列号"01000000000000000001"为硬件码的地方004019A7跟进去,经过Sub_0044CD1D,直到这里:
[Asm] 纯文本查看 复制代码
0044CE0D   > /8B45 DC          MOV     EAX, DWORD PTR [EBP-0x24]
0044CE10   . |3945 08          CMP     DWORD PTR [EBP+0x8], EAX
0044CE13   . |0F8D AB000000    JGE     0044CEC4
...
0044CE61   .  8B45 E8          MOV     EAX, DWORD PTR [EBP-0x18]
0044CE64   .  8B55 10          MOV     EDX, DWORD PTR [EBP+0x10]
0044CE67   .  57               PUSH    EDI
0044CE68   .  8B48 F8          MOV     ECX, DWORD PTR [EAX-0x8]
0044CE6B   .  8B5A F8          MOV     EBX, DWORD PTR [EDX-0x8]
0044CE6E   .  51               PUSH    ECX
0044CE6F   .  50               PUSH    EAX
0044CE70   .  53               PUSH    EBX
0044CE71   .  8D85 6CFFFFFF    LEA     EAX, DWORD PTR [EBP-0x94]
0044CE77   .  52               PUSH    EDX
0044CE78   .  50               PUSH    EAX
0044CE79   .  E8 0F680000      CALL    0045368D                         ; 循环加/解密8字节的块
   0012FACC   0012FC00  |Arg1 = 0012FC00                                ; 输出内存地址
   0012FAD0   00A46284  |Arg2 = 00A46284 ASCII "01000000"/"00000000"    ; 输入块内容:明文/密文
   0012FAD4   00000008  |Arg3 = 00000008                                ; 输入块字节数
   0012FAD8   00A464D4  |Arg4 = 00A464D4 ASCII "PeaceWorld"             ; Key
   0012FADC   0000000A  |Arg5 = 0000000A                                ; Key字节数
   0012FAE0   00000000  |Arg6 = 00000000                                ; 0 - 加密/1 - 解密
...
0044CEBF   .^\E9 49FFFFFF      JMP     0044CE0D
0044CEC4   >  397D D8          CMP     DWORD PTR [EBP-0x28], EDI
0044CEC7   .  0F8E 99000000    JLE     0044CF66
...
   0044CF26   .  E8 62670000               CALL    0045368D             ; 加/解密不足8字节的块
   0012FACC   0012FC34  |Arg1 = 0012FC34
   0012FAD0   00A46284  |Arg2 = 00A46284 ASCII "0001"
   0012FAD4   00000004  |Arg3 = 00000004
   0012FAD8   00A464D4  |Arg4 = 00A464D4 ASCII "PeaceWorld"             ; Key
   0012FADC   0000000A  |Arg5 = 0000000A
   0012FAE0   00000000  |Arg6 = 00000000                                ; 0 - 加密/1 - 解密
...

整个序列号"01000000000000000001"分三次调用Sub_0045368D进行加密。Sub_0045368D是个啥,跟进去看看:
[Asm] 纯文本查看 复制代码
00453715  |> /FF75 1C          PUSH    DWORD PTR [EBP+0x1C]
00453718  |. |56               PUSH    ESI
00453719  |. |FF75 0C          PUSH    DWORD PTR [EBP+0xC]
0045371C  |. |57               PUSH    EDI
0045371D  |. |E8 97000000      CALL    004537B9
00453722  |. |FF75 14          PUSH    DWORD PTR [EBP+0x14]
00453725  |. |68 64EB4A00      PUSH    004AEB64
0045372A  |. |57               PUSH    EDI
0045372B  |. |57               PUSH    EDI
0045372C  |. |E8 88000000      CALL    004537B9
00453731  |. |FF75 1C          PUSH    DWORD PTR [EBP+0x1C]
00453734  |. |56               PUSH    ESI
00453735  |. |57               PUSH    EDI
00453736  |. |57               PUSH    EDI
00453737  |. |E8 7D000000      CALL    004537B9
0045373C  |. |8345 0C 08       ADD     DWORD PTR [EBP+0xC], 0x8
00453740  |. |83C4 30          ADD     ESP, 0x30
00453743  |. |83C7 08          ADD     EDI, 0x8
00453746  |. |4B               DEC     EBX
00453747  |.^\75 CC            JNZ     SHORT 00453715

Sub_004537B9就是DES加/解密函数,调用时"Key Schedule"不同而已!它同样被调用了三次,所以被称为"Triple DES"(TDEA/Triple DEA)。Key - "PeaceWorld"是这样用的:"PeaceWor"、"ld\0\0\0\0\0\0"、"PeaceWor"。帖出来给那些不了解的人科普一下。
解密KeyFile.dat文件的那个算法还没来得及仔细看,所以没法说。

到这里,我们有了正确的File_Checksum="3E9CDB90",Harddisk_SN="WD-WCAV9T236652",那么File_Checksum+Harddisk_SN="3E9CDB90WD-WCAV9T236652"。原帖的KeyFile.dat文件已经能被正确解密了,读者自己再接着跟下去继续玩吧,文件的编码很有意思——再次解密、比较!

下面说说怎么Patch。就两处:
1. Patching "File Checksum"
[Asm] 纯文本查看 复制代码
00401876  |.  BB 30AE4400      MOV     EBX, 0044AE30
0040187B  |.  E8 311B0000      CALL    004033B1                        ; <- *** ORG: File_checksum = 3E9CDB90
00401880  |.  83C4 10          ADD     ESP, 0x10

本来很简单的事,0040187B处代码5字节,刚好够"MOV EAX, 3E9CDB90",不多不少。这里想分享一下我的心得,弄得复杂了一点。请在OD里载入我Patch的那个版本,会看到我改成了:
[Asm] 纯文本查看 复制代码
0040187B      E8 002B0700               CALL    00474380               ; to my patching code

00474380      8B1424           MOV     EDX, DWORD PTR [ESP]            ; 00401880, 原返回地址
00474383      8D82 362B0700    LEA     EAX, DWORD PTR [EDX+0x72B36]    ; 004743B6, Call 004033B1后的返回地址
00474389      50               PUSH    EAX
0047438A      8D82 311B0000    LEA     EAX, DWORD PTR [EDX+0x1B31]     ; 004033B1
00474390      50               PUSH    EAX
00474391      8B4424 0C        MOV     EAX, DWORD PTR [ESP+0xC]        ; 修正传递给Sub_004033B1的参数
00474395      894424 08        MOV     DWORD PTR [ESP+0x8], EAX
00474399      8B4424 10        MOV     EAX, DWORD PTR [ESP+0x10]
0047439D      894424 0C        MOV     DWORD PTR [ESP+0xC], EAX
004743A1      8B4424 14        MOV     EAX, DWORD PTR [ESP+0x14]
004743A5      894424 10        MOV     DWORD PTR [ESP+0x10], EAX
004743A9      8B4424 18        MOV     EAX, DWORD PTR [ESP+0x18]
004743AD      894424 14        MOV     DWORD PTR [ESP+0x14], EAX
004743B1      895424 18        MOV     DWORD PTR [ESP+0x18], EDX       ; 保存原返回地址
004743B5      C3               RETN                                    ; Call 004033B1 (Get File_Checksum)
004743B6      8B4424 10        MOV     EAX, DWORD PTR [ESP+0x10]       ; 取保存的原返回地址
004743BA      890424           MOV     DWORD PTR [ESP], EAX            ; 设置返回地址
004743BD      B8 90DB9C3E      MOV     EAX, 0x3E9CDB90                 ; Patching File_Checksum
004743C2      C3               RETN                                    ; 返回原调用

这是想说,1) 在原位置不能容下Patch代码时,怎么调整调用参数。2) 避免重定位,一律使用相对地址。这在新增的代码段需要调用API时,显得特别重要!

2. Patching "Harddisk Serial Number"
[Asm] 纯文本查看 复制代码
004018E3  |.  B8 01000000      MOV     EAX, 0x1
004018E8  |.  BB 30AC4400      MOV     EBX, 0044AC30                   ; 取硬盘序列号
004018ED  |.  E8 BF1A0000      CALL    004033B1                        ; 返回 EAX=0015D868 ASCII "01000000000000000001"

跟进Sub_0044AC30,最后会来到:
[Asm] 纯文本查看 复制代码
0044DEAB  /$ 55                PUSH    EBP
0044DEAC  |. 8BEC              MOV     EBP, ESP
0044DEAE  |. 81EC 24050000     SUB     ESP, 524
...
0044DEE2  |. FF15 60524700     CALL    NEAR DWORD PTR [<&KERNEL32.CreateFileA>]
...
0044DF4D  |. FF15 64524700     CALL    NEAR DWORD PTR [<&KERNEL32.DeviceIoControl>]
0044DF53  |. 85C0              TEST    EAX, EAX
0044DF55  |. 5B                POP     EBX
0044DF56  |. 75 04             JNZ     SHORT 0044DF5C              ; API 成功
0044DF58  |> 33C0              XOR     EAX, EAX
0044DF5A  |. EB 41             JMP     SHORT 0044DF9D              ; API 失败
0044DF5C  |> 8D4E 10           LEA     ECX, DWORD PTR [ESI+0x10]   ; ESI - the OutBuffer
0044DF5F  |. 8D85 DCFAFFFF     LEA     EAX, DWORD PTR [EBP-0x524]

Patch点选在0044DF5F处,这时:1) KERNEL32.DeviceIoControl已成功调用,2) ESI指向API返回的结果。改为:
[Asm] 纯文本查看 复制代码
0044DF5F      E8 5F640200      CALL    004743C3
0044DF64      90               NOP

004743C3      57               PUSH    EDI
004743C4      8D7E 24          LEA     EDI, DWORD PTR [ESI+0x24]
004743C7      B8 4457572D      MOV     EAX, 0x2D575744
004743CC      AB               STOS    DWORD PTR ES:[EDI]
004743CD      B8 41433956      MOV     EAX, 0x56394341
004743D2      AB               STOS    DWORD PTR ES:[EDI]
004743D3      B8 32543633      MOV     EAX, 0x33365432
004743D8      AB               STOS    DWORD PTR ES:[EDI]
004743D9      B8 35362032      MOV     EAX, 0x32203635
004743DE      AB               STOS    DWORD PTR ES:[EDI]
004743DF      B0 20            MOV     AL, 0x20
004743E1      803F 00          CMP     BYTE PTR [EDI], 0x0
004743E4      74 03            JE      SHORT 004743E9
004743E6      AA               STOS    BYTE PTR ES:[EDI]
004743E7    ^ EB F8            JMP     SHORT 004743E1
004743E9      5F               POP     EDI
004743EA      8D85 DCFAFFFF    LEA     EAX, DWORD PTR [EBP-0x524]
004743F0      C3               RETN

将硬盘序列号改为:"DWW-AC9V2T6356 2"。为什么不是按"WD-WCAV9T236652"改?请查MSDN文档!
想起很多年前,在温酒舞/酒吧时代,当时为了自己写代码去读这个序列号,分析过CIH病毒简单到约1024字节的代码,学习到从Ring3跳到Ring0的方法,这样就可以不需要经过vxd直接操作端口了。
如果需要对Patch后的文件压缩/加壳,记得要调整一下代码段的虚拟大小:
[Plain Text] 纯文本查看 复制代码
Number  Name   VirtSize   RVA    PhysSize  Offset    Flag
    1 .text    00073376 00001000 00074000 00001000 60000020
这是原帖执行文件正确脱壳后的数据。将00073376修改为Patch后的实际大小000733F1:
[Plain Text] 纯文本查看 复制代码
    1 .text    000733F1 00001000 00074000 00001000 60000020

否则加壳后的程序运行时会崩溃。

小结:1) 作者提供了关键数据,使难度降低。2) 因为是CrackMe/KeygenMe,很理解作者的纠结:太难的话,参与性就差,所以作了简化处理。
实践中,就算是你拿到了序列号之类的HWID,也一定是经过很多次变形/变换,那些算法甚至是用VM保护,才使用。另外,没有反跟踪、反调试,代码也没有变形膨胀,读起来很流畅,有利于大家学习。

这部分结束,有时间再试试看能否Keygen。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册[Register]

x

点评

大叔的草莓20140313活动结束罗 http://www.52pojie.cn/thread-241567-1-1.html (出处: 吾爱破解论坛 - LCG - LSG |软件安全|病毒分析|破解软件|软件论坛|www.52pojie.cn)  发表于 2014-3-11 10:47

免费评分

参与人数 2热心值 +2 收起 理由
Peace + 1 语言幽默、分析透彻
专卖小七 + 1 虽然我看不懂,但是感觉好屌啊。

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

头像被屏蔽
沙发
892644330 发表于 2014-3-8 13:45
提示: 作者被禁止或删除 内容自动屏蔽
3#
 楼主| MistHill 发表于 2014-3-8 13:46 |楼主
本帖最后由 MistHill 于 2014-3-8 14:07 编辑

占楼备用!
差点儿忘记了,女生们,节日快乐!

再补充一句,这个破解版需要原帖的Key文件KeyFile.dat
4#
哥哥是神人 发表于 2014-3-8 14:12
5#
红茶 发表于 2014-3-8 14:40
学习经验的小白
6#
Signal_over 发表于 2014-3-8 15:35
不明觉厉中~~~~~~~~~~~~
7#
ly269935419 发表于 2014-3-9 11:35
本帖最后由 ly269935419 于 2014-3-9 11:39 编辑

感谢大神思路,总算会了,学习了。顺便把我的一些分析拿出来给大神指点下。ida看图比较好说一点,可惜无法上图。我直接说一些关键地方
call 4033B1解字符码(顺便求详细分析,让小菜好好学习解码)jnz loc_40200B这是有KeyFile.dat和无KeyFile.dat的两种结果。不跳为验证,跳为不验证,非注册版。jl short loc_401BB9为非法验证跳(共有2处,ida直接看call sub_4033AB上的跳转,这里必须要ecx赋值正确)。下面的到运行开始可能是正式版功能部分,这个= =,估计要正确文件解出来的赋值(我猜2个call sub_4033B1处,eax赋值0)。剩下的坐等大神发详细解密贴,怒赞大神。
8#
ly269935419 发表于 2014-3-10 13:54
大神又调戏小菜啦。本来一开始就打算Patch,后来没看到注册用户名(其实我看漏了,用户名就在图片上,额。。。。。),一想就算了,分析下就好。后来又看到大神出招,注意到了图片,于是打算patch注册名,后来发现内存里数据长度不够,额。于是向上找了找发现了类硬盘的数据生成注册名,于是偷个懒看大神的,额。。。。好吧,我喜欢偷懒。最后希望大神能分析下类硬盘数据生成注册名的过程,额。。。。。喜欢偷懒,额。。。。。。。。,私聊贵,额。。。。。。。屌丝伤不起。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-24 21:20

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表