好友
阅读权限40
听众
最后登录1970-1-1
|
CM是什么?Crackme是什么?这是什么东西?楼主发的什么?
他们都是一些公开给别人尝试破解的小程序,制作 Crackme 的人可能是程序员,想测试一下自己的软件保护技术,也可能是一位 Cracker,想挑战一下其它 Cracker 的破解实力,也可能是一些正在学习破解的人,自己编一些小程序给自己破解,KeyGenMe是要求别人做出它的 keygen (序号产生器), ReverseMe 要求别人把它的算法做出逆向分析, UnpackMe 是要求别人把它成功脱壳,本版块禁止回复非技术无关水贴。
本帖最后由 playboysen 于 2013-12-25 07:40 编辑
本文是针对下面这个CM的解答:
http://www.52pojie.cn/thread-228419-1-1.html解压出WhiteDecrypt & CrackMe主程序,看到了MFC特有图标
再结合程序入口代码特有的kernel32.GetVersion标示一般可以认为编程语言是C系无疑,使用系统API下断点就相对方便了(C系底层和系统API结合最紧密),不错的开端,继续……
运行程序随便输入测试出现不同错误提示,OD加载主程序查看字符串后轻松定位关键代码
注册码初步验证函数功能如下(具体解释见注释) [AppleScript] 纯文本查看 复制代码 00401486 |. E8 B38A0000 call White_De.00409F3E
0040148B |. 8B8E D4000000 mov ecx,dword ptr ds:[esi+D4] ; userName "White_CrackMe_JUST_For_Fun"
00401491 |. 8BF8 mov edi,eax
00401493 |. 8B86 D8000000 mov eax,dword ptr ds:[esi+D8] ; regCode "Do_You_Like_It_Or_NOT__:)_"
00401499 |. 83C4 08 add esp,8
0040149C |. 8B49 F8 mov ecx,dword ptr ds:[ecx-8] ; ecx = len(userName)
0040149F |. 33D2 xor edx,edx
004014A1 |. 8B40 F8 mov eax,dword ptr ds:[eax-8] ; eax = len(regCode)
004014A4 |. 894D FC mov dword ptr ss:[ebp-4],ecx
004014A7 |. 85C9 test ecx,ecx
004014A9 |. 0F94C2 sete dl
004014AC |. 33C9 xor ecx,ecx
004014AE |. 897D F0 mov dword ptr ss:[ebp-10],edi
004014B1 |. 85C0 test eax,eax
004014B3 |. 0F94C1 sete cl
004014B6 |. 0BD1 or edx,ecx
004014B8 |. 74 1A je short White_De.004014D4 ; 二者不能为空
004014BA |. 6A 10 push 10
004014BC |. 68 28614100 push White_De.00416128 ; 错误
004014C1 |. 68 14614100 push White_De.00416114 ; 请输入用户名和密码
004014C6 |. 8BCE mov ecx,esi
004014C8 |. E8 6BB00000 call White_De.0040C538
004014CD |. 5F pop edi
004014CE |. 5E pop esi
004014CF |. 5B pop ebx
004014D0 |. 8BE5 mov esp,ebp
004014D2 |. 5D pop ebp
004014D3 |. C3 retn
004014D4 |> 8B4D FC mov ecx,dword ptr ss:[ebp-4]
004014D7 |. 33D2 xor edx,edx
004014D9 |. 83F9 17 cmp ecx,17 ; 比较userName和regCode长度是不是23
004014DC |. 0F9CC2 setl dl
004014DF |. 33C9 xor ecx,ecx
004014E1 |. 83F8 17 cmp eax,17
004014E4 |. 0F9CC1 setl cl
004014E7 |. 0BD1 or edx,ecx ; 往下分析就知道23位不够解码完整key
004014E9 |. 74 1A je short White_De.00401505 ; 下面的提示做了误导
004014EB |. 6A 10 push 10
004014ED |. 68 28614100 push White_De.00416128 ; 错误
004014F2 |. 68 00614100 push White_De.00416100 ; 字符串长度等于23
004014F7 |. 8BCE mov ecx,esi
004014F9 |. E8 3AB00000 call White_De.0040C538
004014FE |. 5F pop edi
004014FF |. 5E pop esi
00401500 |. 5B pop ebx
00401501 |. 8BE5 mov esp,ebp
00401503 |. 5D pop ebp
00401504 |. C3 retn
00401505 |> 8B86 D4000000 mov eax,dword ptr ds:[esi+D4]
0040150B |. 50 push eax
0040150C |. 57 push edi
0040150D |. E8 EC0D0000 call White_De.004022FE
00401512 |. 8B96 D8000000 mov edx,dword ptr ds:[esi+D8]
00401518 |. 52 push edx
00401519 |. 53 push ebx
0040151A |. E8 DF0D0000 call White_De.004022FE
0040151F |. 8B86 D4000000 mov eax,dword ptr ds:[esi+D4]
00401525 |. 83C4 10 add esp,10
00401528 |. 33C9 xor ecx,ecx
0040152A |. 8078 04 65 cmp byte ptr ds:[eax+4],65 ; userName[5]="e"
0040152E |. 0F95C1 setne cl
00401531 |. 33D2 xor edx,edx
00401533 |. 8038 57 cmp byte ptr ds:[eax],57 ; userName[1]="W"
00401536 |. 0F95C2 setne dl
00401539 |. 0BCA or ecx,edx
0040153B |. 74 1A je short White_De.00401557
0040153D |. 6A 10 push 10
0040153F |. 68 28614100 push White_De.00416128 ; 错误
00401544 |. 68 F4604100 push White_De.004160F4 ; 错误字符串
00401549 |. 8BCE mov ecx,esi
0040154B |. E8 E8AF0000 call White_De.0040C538
从以上代码可以看出,userName和regCode长度起码不能为空或小于23位,其中userName第一位是“W”,第五位是“e” [AppleScript] 纯文本查看 复制代码 00401577 |. 8B4D F4 mov ecx,dword ptr ss:[ebp-C] ; ecx = Len(regCode)-1
0040157A |. 8B45 F8 mov eax,dword ptr ss:[ebp-8] ; eax = regCode
0040157D |. 03C1 add eax,ecx
0040157F |. 8D51 01 lea edx,dword ptr ds:[ecx+1] ; edx = Len(regCode)
00401582 |> 8A48 FF /mov cl,byte ptr ds:[eax-1]
00401585 |. 8A18 |mov bl,byte ptr ds:[eax]
00401587 |. 32D9 |xor bl,cl
00401589 |. 8ACB |mov cl,bl
0040158B |. 8818 |mov byte ptr ds:[eax],bl ; regCode从最后一位xor前一位并依次替换原值
0040158D |. 0FBE58 FF |movsx ebx,byte ptr ds:[eax-1]
00401591 |. 0FBEC9 |movsx ecx,cl
00401594 |. 03D9 |add ebx,ecx
00401596 |. 48 |dec eax
00401597 |. 4A |dec edx ; 注意regCode第一位xor固定值0x08
00401598 |.^ 75 E8 \jnz short White_De.00401582 ; 变形后的注册码设为regCode1
0040159A |. 8B7D F0 mov edi,dword ptr ss:[ebp-10] ; edi = userName
0040159D |. 8B55 FC mov edx,dword ptr ss:[ebp-4] ; edx = len(userName)-1
004015A0 |. 33F6 xor esi,esi
004015A2 |. 8D043A lea eax,dword ptr ds:[edx+edi] ; eax指向userName最后一字节的地址
004015A5 |> 8A48 FF /mov cl,byte ptr ds:[eax-1]
004015A8 |. 8A10 |mov dl,byte ptr ds:[eax]
004015AA |. 32D1 |xor dl,cl
004015AC |. 8810 |mov byte ptr ds:[eax],dl ; userName从最后一位xor前一位并以次替换原值
004015AE |. 0FBE0C3E |movsx ecx,byte ptr ds:[esi+edi]
004015B2 |. 0FBED2 |movsx edx,dl
004015B5 |. 03CA |add ecx,edx
004015B7 |. 8B55 FC |mov edx,dword ptr ss:[ebp-4]
004015BA |. 46 |inc esi
004015BB |. 48 |dec eax
004015BC |. 3BF2 |cmp esi,edx ; 注意userName第一位xor固定值0x08
004015BE |.^ 76 E5 \jbe short White_De.004015A5 ; 变形后的注册码设为userName1
004015C0 |. 8B45 F8 mov eax,dword ptr ss:[ebp-8]
004015C3 |. 23CB and ecx,ebx
004015C5 |. 51 push ecx
004015C6 |. 57 push edi ; edi = userName1
004015C7 |. 50 push eax ; eax = regCode1
004015C8 |. E8 13000000 call White_De.004015E0 ; (╰_╯)#
004015CD |. 83C4 0C add esp,0C
004015D0 |. 5F pop edi
004015D1 |. 5E pop esi
004015D2 |. 5B pop ebx
004015D3 |. 8BE5 mov esp,ebp
004015D5 |. 5D pop ebp
004015D6 \. C3 retn 主程序读入userName和regCode后分别从最后一位xor前一位并替换原值(第一位xor 0x08),以此来变形userName和regCode,字节变形前后对比见图: regCode
regCode从最后一位依次xor前一位并替换原值(第一位xor 0x08),变形后的注册码设为regCode1
userName
userName从最后一位依次xor前一位并替换原值(第一位xor 0x08),变形后的用户名设为userName1
主程序内置了一组Bytes(见下图黄色选区),设为Key 用合适的用户名和注册码参与解码后就是字符串“Something Is always Changing !”(作为注册成功提示MessageBoxA的内容) 细心人可能发现了该字符串共30位,其中前26位是变形字节,最后4位是明文——也就是说主程序要做的就是解码前26字节
[AppleScript] 纯文本查看 复制代码 0040163F |. 49 dec ecx
00401640 |. 894C24 18 mov dword ptr ss:[esp+18],ecx
00401644 |> 8A0C30 /mov cl,byte ptr ds:[eax+esi] ; Key从首字节开始xor regCode1对应字节
00401647 |. 300C28 |xor byte ptr ds:[eax+ebp],cl
0040164A |. 83F8 0A |cmp eax,0A ; 共解码Key的前11字节
0040164D |. 75 13 |jnz short White_De.00401662
0040164F |. 8D7B F6 |lea edi,dword ptr ds:[ebx-A]
00401652 |. 3BF8 |cmp edi,eax
00401654 |. 72 0C |jb short White_De.00401662
00401656 |> 8A0C06 |/mov cl,byte ptr ds:[esi+eax] ; regCode1从第十二字节开始依次xor前一字节
00401659 |. 304C06 01 ||xor byte ptr ds:[esi+eax+1],cl
0040165D |. 40 ||inc eax
0040165E |. 3BC7 ||cmp eax,edi
00401660 |.^ 76 F4 |\jbe short White_De.00401656 ; 共处理regCode1第12-14字节
00401662 |> 40 |inc eax
00401663 |. 83F8 0A |cmp eax,0A
00401666 |.^ 76 DC \jbe short White_De.00401644
00401668 |. 8B4C24 18 mov ecx,dword ptr ss:[esp+18] ; ecx = len(userName1)
0040166C |. B8 0A000000 mov eax,0A
00401671 |> 8A1C10 /mov bl,byte ptr ds:[eax+edx] ; Key从第11字节开始xor userName1对应字节
00401674 |. 301C28 |xor byte ptr ds:[eax+ebp],bl
00401677 |. 83F8 14 |cmp eax,14 ; 共解码Key的第11-21字节
0040167A |. 75 13 |jnz short White_De.0040168F
0040167C |. 8D79 EC |lea edi,dword ptr ds:[ecx-14]
0040167F |. 3BF8 |cmp edi,eax
00401681 |. 72 0C |jb short White_De.0040168F
00401683 |> 8A1C02 |/mov bl,byte ptr ds:[edx+eax]
00401686 |. 205C02 01 ||and byte ptr ds:[edx+eax+1],bl
0040168A |. 40 ||inc eax
0040168B |. 3BC7 ||cmp eax,edi
0040168D |.^ 76 F4 |\jbe short White_De.00401683
0040168F |> 40 |inc eax
00401690 |. 83F8 14 |cmp eax,14
00401693 |.^ 76 DC \jbe short White_De.00401671
00401695 |. 8BCE mov ecx,esi 第一段解码:Key从首字节开始xor regCode1对应字节,共处理Key的前11字节 (截图是前十一字节解码后的明文) [Python] 纯文本查看 复制代码 for j in range(1,12):
key[j] = chr(ord(key[j]) ^ ord(regCode1[j]))
由于异或运算是可逆的,所以可以根据已知Key和最终对应的“Something Is always Changing !”前十一位逆推出regCode前十位(因为第十一位后续变幻多次,暂无法确定)
[Python] 纯文本查看 复制代码
key = {1:"\x1F",2:"\x44",3:"\x5D",4:"\x63",5:"\x42",6:"\x72",7:"\x43",8:"\x7D",9:"\x42",10:"\x22",11:"\x4F",12:"\x55",13:"\x08",14:"\x5B",15:"\x79",16:"\x68",17:"\x67",18:"\x7E",19:"\x78",20:"\x39",21:"\x63",22:"\x61",23:"\x61",24:"\x6F",25:"\x74",26:"\x7B",27:"\x6E",28:"\x67",29:"\x20",30:"\x21"}
OK = {1:"S",2:"o",3:"m",4:"e",5:"t",6:"h",7:"i",8:"n",9:"g",10:" ",11:"I",12:"s",13:" ",14:"a",15:"l",16:"w",17:"a",18:"y",19:"s",20:" ",21:"C",22:"h",23:"a",24:"n",25:"g",26:"i",27:"n",28:"g",29:" ",30:"!"}
regCode = dict()
for j in range(1,12):
regCode[j]= chr(ord(key[j])^ord(OK[j]))
if i ==1:
regCode[j] = chr(ord(regCode[j])^ord('\x08'))
else:
regCode[j]=chr(ord(regCode[j])^ord(regCode[j-1]))
>>> print regCode
{1: 'D', 2: 'o', 3: '_', 4: 'Y', 5: 'o', 6: 'u', 7: '_', 8: 'L', 9: 'i', 10: 'k', 11: 'm'}
regCode1从第十二字节开始依次xor前一字节,共处理regCode1第12-14字节 [Python] 纯文本查看 复制代码 for j in range(11,14):
regCode1[j+1] = chr(ord(regCode1[j+1]) ^ ord(regCode1[j]))
第二段解码:Key从第11字节开始xor userName1对应字节,共处理Key的第11-21字节 (截图是Key[11-21]解码后的明文) [Python] 纯文本查看 复制代码 for j in range(11,22):
key[j] = chr(ord(key[j]) ^ ord(userName1[j]))
[AppleScript] 纯文本查看 复制代码 004016A0 |> 8A1C01 /mov bl,byte ptr ds:[ecx+eax] ; userName1从首字节开始依次xor regCode1对应字节
004016A3 |. 3018 |xor byte ptr ds:[eax],bl
004016A5 |. 40 |inc eax
004016A6 |. 4F |dec edi ; 共处理userName1的前11字节
004016A7 |.^ 75 F7 \jnz short White_De.004016A0
004016A9 |. 8BFA mov edi,edx ; edi指向变形后的userName1
004016AB |. 8D46 0A lea eax,dword ptr ds:[esi+A]
004016AE |. 2BFE sub edi,esi
004016B0 |. BE 0B000000 mov esi,0B
004016B5 |> 8A1C07 /mov bl,byte ptr ds:[edi+eax] ; regCode1从第11字节开始and userName1对应字节
004016B8 |. 2018 |and byte ptr ds:[eax],bl
004016BA |. 40 |inc eax
004016BB |. 4E |dec esi ; 共处理regCode1的11-21字节
004016BC |.^ 75 F7 \jnz short White_De.004016B5
004016BE |. 8D42 14 lea eax,dword ptr ds:[edx+14] ; eax指向变形后的userName1
004016C1 |. BE 06000000 mov esi,6
004016C6 |> 8A1C08 /mov bl,byte ptr ds:[eax+ecx] ; userName1从第21字节开始and regCode1对应字节
004016C9 |. 2018 |and byte ptr ds:[eax],bl
004016CB |. 40 |inc eax
004016CC |. 4E |dec esi ; 共处理userName1的21-26字节
004016CD |.^ 75 F7 \jnz short White_De.004016C6
004016CF |. 8D45 14 lea eax,dword ptr ss:[ebp+14] ; eax指向key的第21字节
004016D2 |. 2BD5 sub edx,ebp
004016D4 |. BE 06000000 mov esi,6
004016D9 |> 8A0C02 /mov cl,byte ptr ds:[edx+eax] ; Key从第21字节开始xor userName1对应字节
004016DC |. 8A18 |mov bl,byte ptr ds:[eax]
004016DE |. 32D9 |xor bl,cl
004016E0 |. 8818 |mov byte ptr ds:[eax],bl
004016E2 |. 40 |inc eax
004016E3 |. 4E |dec esi ; 共解码Key的第21-26字节
004016E4 |.^ 75 F3 \jnz short White_De.004016D9
004016E6 |. 8B7424 10 mov esi,dword ptr ss:[esp+10]
004016EA |. 55 push ebp
004016EB |. 68 38614100 push White_De.00416138 ; %s
004016F0 |. 56 push esi
004016F1 |. E8 080C0000 call White_De.004022FE
004016F6 |. 83C4 0C add esp,0C
004016F9 |. 6A 40 push 40 ; /Style = MB_OK|MB_ICONASTERISK|MB_APPLMODAL
004016FB |. 68 30614100 push White_De.00416130 ; |info
00401700 |. 56 push esi ; |Text
00401701 |. 6A 00 push 0 ; |hOwner = NULL
00401703 |. FF15 58134100 call dword ptr ds:[<&USER32.Message>; \MessageBoxA
userName1从首字节开始xor regCode1对应字节,共处理userName1的前11字节 [Python] 纯文本查看 复制代码 for j in range(1,12):
userName1[j] = chr(ord(userName1[j]) ^ ord(regCode1[j]))
regCode1从第11字节开始and userName1对应字节,共处理regCode1的11-21字节 [Python] 纯文本查看 复制代码 for j in range(11,22):
regCode1[j] = chr(ord(regCode1[j]) & ord(userName1[j]))
userName1从第21字节开始and regCode1对应字节,共处理userName1的21-26字节 [Python] 纯文本查看 复制代码 for j in range(21,27):
userName1[j] = chr(ord(userName1[j]) & ord(regCode1[j]))
第三段解码:Key从第21字节开始xor userName1对应字节,共处理Key的第21-26字节 (截图是Key[21-26]解码后的明文) [Python] 纯文本查看 复制代码 for j in range(21,27):
key[j] = chr(ord(key[j]) ^ ord(userName1[j]))
整段解码算法并不复杂,简单来说就是程序预置了30位加密Bytes,需要填入合适的用户名和注册码来参与运算解码,最终生成需要的文字“Something Is always Changing !”,运算只是简单的xor和and,不过由于全部都是字节操作编码解码多次,故需全部理解、重现、调试和验证等等需耗大量时间,心力交瘁!我估计到大赛结束,这个“White Decrypt & CrackMe”解答的人也不会太多了
放一段已还原的算法Python示例以供参考 [Python] 纯文本查看 复制代码 #!/usr/bin/env python
##Python 2.7 & Windows 7
import string,random
"""
随机生成用户名和注册码,考虑到后面计算方便,首字节忠于原程序设置为0x08
key是主程序内置的一组加密Bytes(用合适的用户名和注册码参与解密后就是最终的字符串“Something Is always Changing !”)
"""
txt = "ABCDEFGHIGKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!@#$%^&*()_"
key = {1:"\x1F",2:"\x44",3:"\x5D",4:"\x63",5:"\x42",6:"\x72",7:"\x43",8:"\x7D",9:"\x42",10:"\x22",11:"\x4F",12:"\x55",13:"\x08",14:"\x5B",15:"\x79",16:"\x68",17:"\x67",18:"\x7E",19:"\x78",20:"\x39",21:"\x63",22:"\x61",23:"\x61",24:"\x6F",25:"\x74",26:"\x7B",27:"\x6E",28:"\x67",29:"\x20",30:"\x21"}
OK = {1:"S",2:"o",3:"m",4:"e",5:"t",6:"h",7:"i",8:"n",9:"g",10:" ",11:"I",12:"s",13:" ",14:"a",15:"l",16:"w",17:"a",18:"y",19:"s",20:" ",21:"C",22:"h",23:"a",24:"n",25:"g",26:"i",27:"n",28:"g",29:" ",30:"!"}
def bruteAttack():
userName = "\x08" + "Wallet" + string.join(random.sample(txt,20)).replace(' ','')
regCode = "\x08" + "Do_You_Lik" + string.join(random.sample(txt,16)).replace(' ','')
"""
regCode最后一位xor前一位并替换原值(其它字节以此类推,第一位xor 0x08),变形后的注册码设为regCode1
userName计算方法相同
"""
regCode1 =dict()
for j in range(26,0,-1):
regCode1[j] = chr(ord(regCode[j]) ^ ord(regCode[j-1]))
userName1 = dict()
for j in range(26,0,-1):
userName1[j] = chr(ord(userName[j]) ^ ord(userName[j-1]))
"""Key从首字节开始xor regCode1对应字节,共处理Key的前11字节"""
for j in range(1,12):
key[j] = chr(ord(key[j]) ^ ord(regCode1[j]))
"""Key从第11字节开始xor userName1对应字节,共处理Key的第11-21字节"""
for j in range(11,22):
key[j] = chr(ord(key[j]) ^ ord(userName1[j]))
"""regCode1从第十二字节开始xor前一字节,共处理regCode1第12-14字节"""
for j in range(11,14):
regCode1[j+1] = chr(ord(regCode1[j+1]) ^ ord(regCode1[j]))
"""userName1从首字节开始xor regCode1对应字节,共处理userName1的前11字节"""
for j in range(1,12):
userName1[j] = chr(ord(userName1[j]) ^ ord(regCode1[j]))
"""regCode1从第11字节开始and userName1对应字节,共处理regCode1的11-21字节"""
for j in range(11,22):
regCode1[j] = chr(ord(regCode1[j]) & ord(userName1[j]))
"""userName1从第21字节开始and regCode1对应字节,共处理UserName1的21-26字节"""
for j in range(21,27):
userName1[j] = chr(ord(userName1[j]) & ord(regCode1[j]))
"""Key从第21字节开始xor userName1对应字节,共处理Key的第21-26字节"""
for j in range(21,27):
key[j] = chr(ord(key[j]) ^ ord(userName1[j]))
while True:
bruteAttack()
if key == OK:
print "Success!"
break
不能免俗,只为加分O(∩_∩)O~——做个爆破Loader
|
免费评分
-
查看全部评分
|