吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 4006|回复: 4
收起左侧

[CrackMe] 【吾爱2013CM大赛解答】-- White Decrypt & CrackMe 解题思路和方法

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

题目【吾爱2013CM大赛题目】-- White Decrypt & CrackMe

分析文章(以发帖时间为序):
playboysen【吾爱2013CM大赛解答】-- White Decrypt & CrackMe -- White 算法还原(复杂)
ja3klyTim9k【吾爱2013CM大赛解答】 -- White Decrypt & CrackMe -- White
Thend【吾爱2013CM大赛解答】-- White Decrypt & CrackMe -- White 算法详细分析+还原

题目要求很简单:找出合适的Name和Key组合,使得INFO显示“Something Is always Changing!”时,解题成功!

分析就不再重复了。贴段我的笔记来说明问题:
[Plain Text] 纯文本查看 复制代码
***************************************************************************************************************
Offset:         0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
Key:            44 6F 5F 59 6F 75 5F 4C 69 6B 65 5F 49 74 5F 4F 72 5F 4E 4F 54 5F 5F 3A 29 5F   "Do_You_Like_It_Or_NOT__:)_"
Key Variation #1: 00401577
                ALGO: ^= Key[i-1], i = strlen(Key)-1 ~ 0
                44 2B 30 06 36 1A 2A 13 25 02 0E 3A 16 3D 2B 10 3D 2D 11 01 1B 0B 00 65 13 76

Name:           57 68 69 74 65 5F 43 72 61 63 6B 4D 65 5F 4A 55 53 54 5F 46 6F 72 5F 46 75 6E   "White_CrackMe_JUST_For_Fun"
Name Variation #1: 0040159A
                ALGO: ^= Name[i-1], i = strlen(Name)-1 ~ 0
                57 3F 01 1D 11 3A 1C 31 13 02 08 26 28 3A 15 1F 06 07 0B 19 29 1D 2D 19 33 1B

                .  D  ]  c  B  r  C  }  B  "  O  U  .  [  y  h  g  ~  x  9  c  a  a  o  t  {  n  g     !
Preset:         1F 44 5D 63 42 72 43 7D 42 22 4F 55 08 5B 79 68 67 7E 78 39 63 61 61 6F 74 7B 6E 67 20 21 00 00
at address 004160B0

Decoding #1, Key Variation #2: 00401644
for Preset:     ALGO: ^= Key[i], i = 00 ~ 0A;
for Key:        ALGO: Key[i+1] ^= Key[i], i = 0A ~ strlen(Key)-0A if strlen(Key)-0A >= 0A
                <------------------------------>
                [  o  m  e  t  h  i  n  g     A  U  .  [  y  h  g  ~  x  9  c  a  a  o  t  {  n  g     !
Preset:         5B 6F 6D 65 74 68 69 6E 67 20 41 55 08 5B 79 68 67 7E 78 39 63 61 61 6F 74 7B 6E 67 20 21 00 00
                                                 <------>
Key:            44 2B 30 06 36 1A 2A 13 25 02 0E 34 22 1F 2B 10 3D 2D 11 01 1B 0B 00 65 13 76

Decoding #2, Name Variation #2: 00401668
for Preset:     ALGO: ^= Name[i], i = 0A ~ 14
for Name:       ALGO: Name[i+1] &= Name[i], i = 14 ~ strlen(Name)-14 if strlen(Name)-14 >= 14
                                              <------------------------------>
                [  o  m  e  t  h  i  n  g     I  s     a  l  w  a  y  s     J  a  a  o  t  {  n  g     !
Preset:         5B 6F 6D 65 74 68 69 6E 67 20 49 73 20 61 6C 77 61 79 73 20 4A 61 61 6F 74 7B 6E 67 20 21 00 00
                                                                            <----------------, ...
Name:           57 3F 01 1D 11 3A 1C 31 13 02 08 26 28 3A 15 1F 06 07 0B 19 29 1D 2D 19 33 1B

Name Variation #3: 00401695
                ALGO: ^= Key[i], i = 00 ~ 0A
                <------------------------------>
Name:           13 14 31 1B 27 20 36 22 36 00 06 26 28 3A 15 1F 06 07 0B 19 29 1D 2D 19 33 1B

Key Variation #3: 004016A9
                ALGO: &= Name[i], i = 0A ~ 14 <------------------------------>
Key:            44 2B 30 06 36 1A 2A 13 25 02 06 24 20 1A 01 10 04 05 01 01 09 0B 00 65 13 76

Name Variation #4: 004016BE
                ALGO: &= Key[i], i = 14 ~ 19                                <--------------->
Name:           13 14 31 1B 27 20 36 22 36 00 06 26 28 3A 15 1F 06 07 0B 19 09 09 00 01 13 12

Decoding #3: 004016CF
                ALGO: ^= Name[i], i = 14 ~ 19                               <--------------->
                [  o  m  e  t  h  i  n  g     I  s     a  l  w  a  y  s     C  h  a  n  g  i  n  g     !
Preset/Answer:  5B 6F 6D 65 74 68 69 6E 67 20 49 73 20 61 6C 77 61 79 73 20 43 68 61 6E 67 69 6E 67 20 21 00 00
***************************************************************************************************************
Conclusion
Related:        K  K  K  K  K  K  K  K  K  K  KN N  N  N  N  N  N  N  N  N  NK NK NK NK NK NK
Key status:     C  C  C  C  C  C  C  C  C  C  V  v  v  v  v  v  v  v  v  v  V  V  V  V  V  V
Offset:         00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
                <-----------------------------<>----------------------------<>-------------->
                ^= Key                        ^= Name                       ^= Name(#4)
ALGO:           1) 00~09: ^= Key
                2) 0A: ^= Key, ^= Name
                                              3) 0B~13: ^= Name
                                              4) 14: ^= Name, ^= Name & (Key & Name)
                                                                            5) 15~19: ^= (Name & Key)
***************************************************************************************************************

前半部分是Name和Key的变换、答案的解码过程;重点在后半部分的分析总结,那些无关的运算完全可以无视:
  • Key的00~09位是固定的,Preset和Answer决定了它不可变化。在08的机器上为"Do_You_Lik",在00的机器上为"LgWQg}WDac"。“xx的机器上”这种说法有点儿诡异!
  • Key的0A位:对给定的Name,是确定的,没有太多变数。
  • Key的0B~13位:因为正确的答案只受Name的影响,则Key是可自定义的,随便了。可以弄得有意义一点,比如:"_MistHill","_52PoJie_","_It_Or_NO"等等。
  • Key的14位:这个比较讨厌,“与”运算使得结果有相当的不确定性:用Name、Preset和Answer三个条件对Key进行枚举,找出所有的可能;在当前Name下,可能得不到任何结果,还需要修改Name的对应位,重复这个枚举过程。
  • Key的15~19位:与第14位类似,但少一个与第一次变换后Name的“异或”。

对Name来说,其00~0A位不对结果产生影响(只需调整Key[0A]),也是可自定义的。比如:"White_Crack","Weare52PoJi","Weare吾爱__"等等。当然得满足Name[00]和Name[04]的强制要求。
[Plain Text] 纯文本查看 复制代码
Key:
0123456789ABCDEF0123456789ABCDEF
Do_You_Lik
LgWQg}WDac
           _MistHill
           _52PoJie_
           _It_Or_NO

Name:
0123456789ABCDEF0123456789ABCDEF
White_Crack
Weare52PoJi
Weare吾爱__

理解了这些就可以写程序了,用ODbgScript比较方便。本来只想简单地写一个,结果越整越复杂,搞得平安夜还在码字。

脚本对给定的Name,枚举出有效的Key。在某个Name无解时,会自动调整Name。
因为Key的0B~13位是自定义的。对一个给定的合格Name,仅Key在这里的变化就有256的9次方,这个数是很大的。脚本不处理这种简单的罗列!关键在Key[14]~Key[19]的求解上。
结合脚本的输入参数,说一下Keygen使用。
[Plain Text] 纯文本查看 复制代码
    mov szName, "White_CrackMe_JUST_For_Fun"

    mov char_mallocPtrMinus1, 8, 1
    mov dwCountLimitFor1419, 2
    mov bFilterOn, 1
    mov bOutputToFile, 0

先什么都不用改,直接跑一下脚本,看看你能得到什么结果。

变量szName可以指定任意Name,脚本会自动调整的。
长度有要求:至少0x1A(26.)字符,最多0x27(39.)字符。设置最长字符数是为了简化问题(参见上面的Name Variation #2)。Key是要求解的,长度固定为0x1A可省去不少麻烦。

char_mallocPtrMinus1是为解决“xx的机器上”造成答案的差异,即VC运行库函数_malloc返回的指针-1那个字节的值。正常地,任何时候都不应该访问不属于自己请求的地址范围。不过,_malloc大多数情况是从Heap里分配空间,非法访问不易察觉。
我和ja3klyTim9k的这个值为0x00,其它人多为0x08。感谢playboysen在多个平台的测试!

dwCountLimitFor1419用来限制Key的14~19位各种有效组合的输出数量。脚本已经计算出了各位的有效值,完全的组合数同样巨大,没必要全部输出显示。
以题目的示例Name为例,各位的有效个数及取值如下:
[Plain Text] 纯文本查看 复制代码
位    个数    有效值
--    ----    ------
14    20      09 0B 0D 0F 19 1B 1D 1F 49 4B 4D 4F 59 5B 5D 5F 89 8B 8D 8F 99 9B 9D 9F C9 CB CD CF D9 DB DD DF
15    10      09 0B 29 2B 49 4B 69 6B 89 8B A9 AB C9 CB E9 EB
16    10      00 02 10 12 40 42 50 52 80 82 90 92 C0 C2 D0 D2
17    20      01 03 05 07 21 23 25 27 41 43 45 47 61 63 65 67 81 83 85 87 A1 A3 A5 A7 C1 C3 C5 C7 E1 E3 E5 E7
18    10      13 17 1B 1F 53 57 5B 5F 93 97 9B 9F D3 D7 DB DF
19    10      12 16 32 36 52 56 72 76 92 96 B2 B6 D2 D6 F2 F6

这6位的有效数据完全组合为0x40000000 (1,073,741,824)个,就其中的可打印字符组合保守地按1/3计算,也还有0x15555555 (357,913,941)个,保存为文件约有9GB。所以不要小看!

bFilterOn是一个开关,用于过滤那些不可能正确输入到题目编辑框的不可打印组合。只保留Key编码后字符范围在0x20~0x7E之间的组合。也会过滤掉Key为一些怪异的有效中文组合,题目能够通过。
Thend的帖子里有个还原得较好的C源码,可视为题目的命令行版本,稍微完善一下也可以作为验证程序。
其中有两处需要修改补充:1) Key第二次变换的条件及位数;2) 增加可能发生的Name的第二次变换。
我也写了一个验证脚本,奇怪的是脚本验证通过了,有极少数Key在题目里却显示错误答案。后来才发现它是用_sprintf函数来复制对话框的Name和Key,很奇怪的用法。
而这些出问题的Key包含字符'%',这就带来不确定性,要处理的话很麻烦,干脆过滤掉了事。算是一个陷阱吧!

bOutputToFile也是一个开关,决定是否将结果输出到文件,方便验证程序使用。
以下为一些输出示例。
[Plain Text] 纯文本查看 复制代码
Name:
White_CrackMe_JUST_For_Fun
Keys:
Do_You_Like_MistHill!*(/pf
Do_You_Like_MistHill!*(/pb
Do_You_Like_MistHill!*(/tb
Do_You_Like_MistHill!*(/tf
Do_You_Like_MistHill!*(-rd
Do_You_Like_MistHill!*(-r`
Do_You_Like_MistHill!*(-v`
Do_You_Like_MistHill!*(-vd
Do_You_Like_MistHill!**-rd
Do_You_Like_MistHill!**-r`
Do_You_Like_MistHill!**-v`
Do_You_Like_MistHill!**-vd
Do_You_Like_MistHill!**/pf
Do_You_Like_MistHill!**/pb
Do_You_Like_MistHill!**/tb
Do_You_Like_MistHill!**/tf
...

Name:
White_CrackMe_JUST_For_Fun
Keys:
Do_You_Like_52PoJie_Do=>!W
Do_You_Like_52PoJie_Do=>!S
Do_You_Like_52PoJie_Do=<#U
Do_You_Like_52PoJie_Do=<#Q
Do_You_Like_52PoJie_Do=<'Q
Do_You_Like_52PoJie_Do=<'U
Do_You_Like_52PoJie_Do?<#U
Do_You_Like_52PoJie_Do?<#Q
Do_You_Like_52PoJie_Do?<'Q
Do_You_Like_52PoJie_Do?<'U
Do_You_Like_52PoJie_Do?>!W
Do_You_Like_52PoJie_Do?>!S
Do_You_Like_52PoJie_Dm?<#U
Do_You_Like_52PoJie_Dm?<#Q
...

Name:
White_CrackMe_JUST_For_Fun
Keys:
Do_You_Like_It_Or_NOT__8/Y
Do_You_Like_It_Or_NOT__8/]
Do_You_Like_It_Or_NOT__8+]
Do_You_Like_It_Or_NOT__8+Y
Do_You_Like_It_Or_NOT__:-[      ; 我更喜欢这个
Do_You_Like_It_Or_NOT__:-_
Do_You_Like_It_Or_NOT__:)_      ; 题目示例Key
Do_You_Like_It_Or_NOT__:)[
Do_You_Like_It_Or_NOT_M*=K
Do_You_Like_It_Or_NOT_M*=O
Do_You_Like_It_Or_NOT_M*9O
Do_You_Like_It_Or_NOT_M*9K
...

Name:
Weare52PoJiOg]HWQV]Ddmml?-
Keys:
Do_You_LikNtfBX_cBGGFMLOXK
Do_You_LikNtfBX_cBGGFMLOXJ
Do_You_LikNtfBX_cBGGFMLO\O
Do_You_LikNtfBX_cBGGFMLO\N
Do_You_LikNtfBX_cBGGFMLMZI
Do_You_LikNtfBX_cBGGFMLMZH
Do_You_LikNtfBX_cBGGFMLM^M
Do_You_LikNtfBX_cBGGFMLM^L
Do_You_LikNtfBX_cBGGFMMNYJ
...

Name:
Weare吾爱__yQk~ag`krR[[ZI[
Keys:
Do_You_LikmWEa{|@addenol{h
Do_You_LikmWEa{|@addenol{i
Do_You_LikmWEa{|@addenonyj
Do_You_LikmWEa{|@addenonyk
Do_You_LikmWEa{|@addenon}n
Do_You_LikmWEa{|@addenon}o
Do_You_LikmWEa{|@addennmzi
Do_You_LikmWEa{|@addennmzh
...

最后一个,Name里有中文,题目会崩溃;而Key里含有中文却不会。不知道原因。

感谢White提供这个有趣的游戏!

祝各位圣诞快乐!

本帖子中包含更多资源

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

x

免费评分

参与人数 1热心值 +1 收起 理由
Chief + 1 吾爱破解2013CM大赛,有你更精彩!

查看全部评分

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

马斯维尔 发表于 2013-12-24 22:18
MistHill的每篇文章都值得好好研读,分析得不错。
头像被屏蔽
Ylca 发表于 2013-12-24 23:58
 楼主| MistHill 发表于 2013-12-26 17:49
本帖最后由 MistHill 于 2013-12-26 17:59 编辑

还是说一下吧!
这个CM暴露出的问题,是每个写程序的人都可能碰到、而且经常犯的错误,吸取经验和教训总是有益的。从某种程度上讲,我觉得比分析和解答CM自身更有意义!

前面提到Name里的中文字符会造成目标崩溃,仔细看下来后发现,原因不是中文引起的,西文同样可能使目标崩溃。
在程序对话框的编辑框里随便输入点儿字符串会“搞死”程序,这无论如何是说不过去的,看来程序有很严重的Bug。

这次问题出在Key和Name的第二次变换那两个循环:
[Plain Text] 纯文本查看 复制代码
0040161F  |. 8B7424 20      MOV     ESI, [ESP+0x20]             pKey(After Variation #1)
00401623  |. 83C9 FF        OR      ECX, 0xFFFFFFFF
00401626  |. 8BFE           MOV     EDI, ESI                    pKey
00401628  |. 83C4 08        ADD     ESP, 0x8
0040162B  |. F2:AE          REPNE   SCAS BYTE PTR ES:[EDI]
0040162D  |. 8B5424 1C      MOV     EDX, [ESP+0x1C]             pName(After Variation #1)
00401631  |. F7D1           NOT     ECX
00401633  |. 49             DEC     ECX                         ECX=strlen(pKey)
00401634  |. 8BFA           MOV     EDI, EDX                    pName
00401636  |. 8BD9           MOV     EBX, ECX                    EBX=strlen(pKey)
00401638  |. 83C9 FF        OR      ECX, 0xFFFFFFFF
0040163B  |. F2:AE          REPNE   SCAS BYTE PTR ES:[EDI]
0040163D  |. F7D1           NOT     ECX
0040163F  |. 49             DEC     ECX                         ECX=strlen(pName)
00401640  |. 894C24 18      MOV     [ESP+0x18], ECX             ECX->[ESP+0x18], save to local variable
00401644  |> 8A0C30       / MOV     CL, [EAX+ESI]               ESI=pKey, EAX=0 Init.
00401647  |. 300C28       | XOR     [EAX+EBP], CL               EBP=pPreset, Decoding #1 with Key
0040164A  |. 83F8 0A      | CMP     EAX, 0xA
0040164D  |. 75 13        | JNZ     SHORT 00401662
0040164F  |. 8D7B F6      | LEA     EDI, [EBX-0xA]              EDI=strlen(pKey)-0A, EDI: unsigned int
00401652  |. 3BF8         | CMP     EDI, EAX
00401654  |. 72 0C        | JB      SHORT 00401662              <- *** BUG!
00401656  |> 8A0C06       |/MOV     CL, [ESI+EAX]               <- Memory access violation if strlen(pKey) < 0A
00401659  |. 304C06 01    ||XOR     [ESI+EAX+0x1], CL           <- write
0040165D  |. 40           ||INC     EAX
0040165E  |. 3BC7         ||CMP     EAX, EDI                    <- *** Never stop!
00401660  |. 76 F4        |\JBE     SHORT 00401656
00401662  |> 40           | INC     EAX
00401663  |. 83F8 0A      | CMP     EAX, 0xA
00401666  |. 76 DC        \ JBE     SHORT 00401644
00401668  |. 8B4C24 18      MOV     ECX, [ESP+0x18]             ECX<-strlen(pName)
0040166C  |. B8 0A000000    MOV     EAX, 0xA                    EAX=0A Init.
00401671  |> 8A1C10       / MOV     BL, [EAX+EDX]               EDX=pName
00401674  |. 301C28       | XOR     [EAX+EBP], BL               EBP=pPreset, Decoding #2 with Name
00401677  |. 83F8 14      | CMP     EAX, 0x14
0040167A  |. 75 13        | JNZ     SHORT 0040168F
0040167C  |. 8D79 EC      | LEA     EDI, [ECX-0x14]             EDI=strlen(pName)-14, EDI: unsigned int
0040167F  |. 3BF8         | CMP     EDI, EAX
00401681  |. 72 0C        | JB      SHORT 0040168F              <- *** BUG!
00401683  |> 8A1C02       |/MOV     BL, [EDX+EAX]               <- Memory access violation if strlen(pName) < 14
00401686  |. 205C02 01    ||AND     [EDX+EAX+0x1], BL           <- write
0040168A  |. 40           ||INC     EAX
0040168B  |. 3BC7         ||CMP     EAX, EDI                    <- *** Never stop!
0040168D  |. 76 F4        |\JBE     SHORT 00401683
0040168F  |> 40           | INC     EAX
00401690  |. 83F8 14      | CMP     EAX, 0x14
00401693  |. 76 DC        \ JBE     SHORT 00401671
00401695  |. 8BCE           MOV     ECX, ESI
在00401644和00401671处的外层循环是分别用Key和Name解码预设值得到答案;现在我们重点关注00401656和00401683两处内层循环。
搞这么个Key和Name的第二次变换无非是想增加一点解Key的难度。实际上也没啥作用,我在Keygen的脚本中写有一个针对Key第二次变换的逆过程,后来发现调用这个子过程与否对获得正确结果没太大影响,为节省运行时间就将那个调用注释掉了。

进入这两个循环的条件是:strlen(pKey)-0A >= 0和strlen(pName)-14 >= 0;换言之,即strlen(pKey) >= 0A和strlen(pName) >= 14。
“换言之”是我的第一反应,看起来strlen(pKey)=01~09,strlen(pName)=01~13都不会进入循环。可事实却完全不是我们想象的那样。
比如strlen(pKey)=09或strlen(pName)=13时,09-0A或13-14都等于-1,在32位系统里表示为0xFFFFFFFF。进入循环的条件就变成:FFFFFFFF与0A或14比较,紧接着的那条JB指令(00401654和00401681)就出问题了,这是一定要进循环的!
而结束循环的条件是:EAX++ > FFFFFFFF(0040165E和0040168B)。将永远不可能退出循环滴!于是它会读写4G内存空间的每一个地址,直到出现“内存访问冲突”,操作系统忍无可忍、不得不终止这个失控的进程。

由于Key和Name的第一次变换算法为两相邻字符进行异或,只要两个相邻字符相同,就得到一个字符串结尾NULL。在中文字符串的情况下不易察觉:比如“吾爱破解”中的“破”字,其两字节内码为0xC60 xC6,同样得到一个NULL字符。
下面这张表可用于对比测试:
[Plain Text] 纯文本查看 复制代码
        0123456789ABCDEF0123456789
        <-------->                       Key 紧邻字符相同崩溃区
         <----------------->            Name 紧邻字符相同崩溃区
Name:   White_CrackMe_JUST_For_Fun      标准输入
Key:    Do_You_Like_It_Or_NOT__:)_

会造成崩溃的Name:
        White_CrackMe_JUST__or_Fun      strlen(pName)=13
        White_CrackMe_JUSTFFor_Fun      strlen(pName)=13
        WWite_CrackMe_JUST_For_Fun      strlen(pName)=01
会造成崩溃的Key:
        Do_You_Liie_It_Or_NOT__:)_      strlen(pKey)=09
        Do_You_Lkke_It_Or_NOT__:)_      strlen(pKey)=09
        DD_You_Like_It_Or_NOT__:)_      strlen(pKey)=01
        oo_You_Like_It_Or_NOT__:)_      strlen(pKey)=01
显然,写程序的人用错了数据类型声明,没有达到预期的设想。编译器只是忠实地将源代码变成机器指令。

先将目标这两处:
[Plain Text] 纯文本查看 复制代码
00401654  72 0C        JB      SHORT 00401662
00401681  72 0C        JB      SHORT 0040168F
改为:
[Plain Text] 纯文本查看 复制代码
00401654  7C 0C        JL      SHORT 00401662
00401681  7C 0C        JL      SHORT 0040168F
再试试,就不会出问题了。不要忽视这一个字节的差异:JB用于无符号数,而JL用于有符号数!

模仿题目写了一个命令行的东西,数据声明部分如下:
[C] 纯文本查看 复制代码
void __cdecl sub_4015E0(char *pKey, char *pName, int DisplayMode)
{
        char *pPreset;
        unsigned int i;
/* Correct data type declaration: */
        int nKeyLength;
        int nNameLength;
/* Wrong data type declaration: */
//      unsigned int nKeyLength;
//      unsigned int nNameLength;
...
数据声明分别为int和unsigned int时,生成的代码对比如下:
[Plain Text] 纯文本查看 复制代码
正确(int):                                         #  错误(unsigned int):
00401523  8A0C30       / MOV     CL, [EAX+ESI]      #  00401523  8A0C30       / MOV     CL, [EAX+ESI]
00401526  300C28       | XOR     [EAX+EBP], CL      #  00401526  300C28       | XOR     [EAX+EBP], CL
00401529  83F8 0A      | CMP     EAX, 0xA           #  00401529  83F8 0A      | CMP     EAX, 0xA
0040152C  75 16        | JNZ     SHORT 00401544     #  0040152C  75 13        | JNZ     SHORT 00401541
0040152E  8D4B F6      | LEA     ECX, [EBX-0xA]     #  0040152E  8D7B F6      | LEA     EDI, [EBX-0xA]
00401531  3BC8         | CMP     ECX, EAX           #  00401531  3BF8         | CMP     EDI, EAX
00401533  7C 0F        | JL      SHORT 00401544     #  00401533  72 0C        | JB      SHORT 00401541
00401535  8D7B F6      | LEA     EDI, [EBX-0xA]     #  00401535  8A0C06       |/MOV     CL, [ESI+EAX]
00401538  8A0C06       |/MOV     CL, [ESI+EAX]      #  00401538  304C06 01    ||XOR     [ESI+EAX+0x1], CL
0040153B  304C06 01    ||XOR     [ESI+EAX+0x1], CL  #  0040153C  40           ||INC     EAX
0040153F  40           ||INC     EAX                #  0040153D  3BC7         ||CMP     EAX, EDI
00401540  3BC7         ||CMP     EAX, EDI           #  0040153F  76 F4        |\JBE     SHORT 00401535
00401542  76 F4        |\JBE     SHORT 00401538     #  00401541  40           | INC     EAX
00401544  40           | INC     EAX                #  00401542  83F8 0A      | CMP     EAX, 0xA
00401545  83F8 0A      | CMP     EAX, 0xA           #  00401545  76 DC        \ JBE     SHORT 00401523
00401548  76 D9        \ JBE     SHORT 00401523     #  00401547  8B4C24 14      MOV     ECX, [ESP+0x14]
0040154A  8B4C24 14      MOV     ECX, [ESP+0x14]    #  0040154B  B8 0A000000    MOV     EAX, 0xA
0040154E  B8 0A000000    MOV     EAX, 0xA           #  00401550  8A1C10       / MOV     BL, [EAX+EDX]
00401553  8A1C10       / MOV     BL, [EAX+EDX]      #  00401553  301C28       | XOR     [EAX+EBP], BL
00401556  301C28       | XOR     [EAX+EBP], BL      #  00401556  83F8 14      | CMP     EAX, 0x14
00401559  83F8 14      | CMP     EAX, 0x14          #  00401559  75 13        | JNZ     SHORT 0040156E
0040155C  75 16        | JNZ     SHORT 00401574     #  0040155B  8D79 EC      | LEA     EDI, [ECX-0x14]
0040155E  8D79 EC      | LEA     EDI, [ECX-0x14]    #  0040155E  3BF8         | CMP     EDI, EAX
00401561  3BF8         | CMP     EDI, EAX           #  00401560  72 0C        | JB      SHORT 0040156E
00401563  7C 0F        | JL      SHORT 00401574     #  00401562  8A1C02       |/MOV     BL, [EDX+EAX]
00401565  8D79 EC      | LEA     EDI, [ECX-0x14]    #  00401565  205C02 01    ||AND     [EDX+EAX+0x1], BL
00401568  8A1C02       |/MOV     BL, [EDX+EAX]      #  00401569  40           ||INC     EAX
0040156B  205C02 01    ||AND     [EDX+EAX+0x1], BL  #  0040156A  3BC7         ||CMP     EAX, EDI
0040156F  40           ||INC     EAX                #  0040156C  76 F4        |\JBE     SHORT 00401562
00401570  3BC7         ||CMP     EAX, EDI           #  0040156E  40           | INC     EAX
00401572  76 F4        |\JBE     SHORT 00401568     #  0040156F  83F8 14      | CMP     EAX, 0x14
00401574  40           | INC     EAX                #  00401572  76 DC        \ JBE     SHORT 00401550
00401575  83F8 14      | CMP     EAX, 0x14
00401578  76 D9        \ JBE     SHORT 00401553
从对比可以看到:1) JL和JB的差异;2) 右边的错误代码与目标代码几乎完全一致!

下面说说附件里的东西。
[Plain Text] 纯文本查看 复制代码
   Date      Time            Size  Name
-------------------  ------------  ----------------
2013-12-25 18:23:00          5968  WDC Verifier.c
2013-12-25 22:41:47         16384  WDC Verifier.exe
在命令提示符下不带参数运行会显示用法:
[Plain Text] 纯文本查看 复制代码
A Verification Program for "White Decrypt & CrackMe"
By MistHill, 25/12/2013

SYNTAX:
        "WDC Verifier.exe" "Name" "Key"
or
        "WDC Verifier.exe" "Log file created by my ODbgScript T228419.Keygen.osc"

You can get the script at:
        [url=http://www.52pojie.cn/thread-230338-1-1.html]http://www.52pojie.cn/thread-230338-1-1.html[/url]
第一种用法类似题目的命令行版本,即输入Name和Key参数会显示结果,自己检查与标准答案是否匹配。
运行实例:
[Plain Text] 纯文本查看 复制代码
"WDC Verifier.exe" "White_CrackMe_JUST_For_Fun" "Do_You_Like吾爱破解_V__^As"
INFO:
        Something Is always Changing !

"WDC Verifier.exe" "White_CrackMe_JUST_For_Fun" "Do_You_Like吾爱破解_V__\O]"
INFO:
        Something Is always Changing !

"WDC Verifier.exe" "Weare_ChildBjPEZ\[PII@@AR@" "Do_You_LikeMMwb}{|wn%,,->,"
INFO:
        Something Is always changing !

"WDC Verifier.exe" "Weare吾爱__yQk~ag`krR[[ZI[" "Do_You_LikmWEa{|@addenol{h"
INFO:
        Something Is always Changing !
因为已经修正了已知Bug,所以不会崩溃,也能正确处理字符'%'。

但受命令提示符传递给程序main函数的命令行参数的影响,通常Name和Key字符串必须用西文字符'"'封闭。在Name或Key存在'"'字符的情况下,见以下示例:
[Plain Text] 纯文本查看 复制代码
Name:   Weare_ChildBjPEZ\[PII@@AR@
Key1:   Do_You_LikeMCQD[]ZQH*##"1#
Key2:   Do_You_LikeMCQD[]ZQH+""#0"

"WDC Verifier.exe" "Weare_ChildBjPEZ\[PII@@AR@" "Do_You_LikeMCQD[]ZQH*##""1#"
INFO:
        Something Is always changing !

"WDC Verifier.exe" "Weare_ChildBjPEZ\[PII@@AR@" Do_You_LikeMCQD[]ZQH+\"\"#0\"
INFO:
        Something Is always changing !
即在只有一个'"'的情况下,多加一个'"'字符;在有多个'"'的情况下,不使用'"'进行封闭,其中的'"'字符前加脱字符'\'。
上面例子中,有几个答案是不正确的,注意'c'和'C'的区别。这是最早调试脚本时的记录,现在一时找不到适合的样本。

总之,这时使用命令行是很麻烦的。对这个感兴趣的可参阅:Everyone quotes command line arguments the wrong way[http://blogs.msdn.com/b/twistylittlepassagesallalike/archive/2011/04/23/everyone-quotes-arguments-the-wrong-way.aspx]。

还是把Name和Key放到文件比较方便,第二种用法:
只需一个参数,为Key的记录文件,其格式用Keygen脚本生成一个就清楚了。
文件里包含一个Name和多个Key,进行批量自动验证。合格的Key后面会显示'V'字符,而无效的Key会以'X'字符表示。

本帖子中包含更多资源

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

x
yangyongyoyo 发表于 2014-9-3 20:01
mark    下次看!
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

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

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

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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