好友
阅读权限40
听众
最后登录1970-1-1
|
CM是什么?Crackme是什么?这是什么东西?楼主发的什么?
他们都是一些公开给别人尝试破解的小程序,制作 Crackme 的人可能是程序员,想测试一下自己的软件保护技术,也可能是一位 Cracker,想挑战一下其它 Cracker 的破解实力,也可能是一些正在学习破解的人,自己编一些小程序给自己破解,KeyGenMe是要求别人做出它的 keygen (序号产生器), ReverseMe 要求别人把它的算法做出逆向分析, UnpackMe 是要求别人把它成功脱壳,本版块禁止回复非技术无关水贴。
本帖最后由 playboysen 于 2013-12-16 13:19 编辑
本文是针对下面这个CM的解答:
http://www.52pojie.cn/thread-228420-1-1.html
本着“授人以渔”的思路,本文写的比较详细,高手觉得啰嗦拉到最下面即可{:1_912:}
主程序名“2013CM.exe”,本机Win7 x64用OD无法加载运行,被迫转移到虚拟机XP,OD加载F9运行直接退出,换个OD后使用ODbyDYK加载成功跑起
踩踩点,OD查找字符串嘛玩意儿木有,猜测应该是将敏感字符放在了资源文件或者加密待程序运行时动态解密显示,eXeScope加载主程序依次看到“资源——字符串——518”中有“8280,注册成功!”字样,十进制8280转换为十六进制是0x2058,有门儿!
大概看看程序入口觉得像C或C++代码(可以用PEid确认),F9运行程序填写用户名“playboysen”注册码随便,然后下断点GetWindowTextA(C代码最常用的取文本API),点击Register断在了User32.dll中,不急,F8慢慢走回主程序代码处
[AppleScript] 纯文本查看 复制代码 00401B83 |. 68 04010000 push 104 ; /Count = 104 (260.)
00401B88 |. 8D85 F0FEFFFF lea eax,dword ptr ss:[ebp-110] ; |
00401B8E |. 50 push eax ; |Buffer
00401B8F |. FF35 78534000 push dword ptr ds:[405378] ; |hWnd = NULL
00401B95 |. FF15 60414000 call dword ptr ds:[<&USER32.GetWindowTextA>] ; \GetWindowTextA
00401B9B |. 68 04010000 push 104 ; /n = 104 (260.)
00401BA0 |. 6A 00 push 0 ; |c = 00
00401BA2 |. 83F8 04 cmp eax,4 ; |用户名必须大于等于4位
00401BA5 |. 7D 1C jge short 2013CM.00401BC3 ; |
00401BA7 |. FF35 D0534000 push dword ptr ds:[4053D0] ; |s = NULL
00401BAD |. E8 D6150000 call <jmp.&MSVCR110.memset> ; \memset
00401BB2 |. 83C4 0C add esp,0C
......
00401BD8 |. 68 04010000 push 104 ; /Count = 104 (260.)
00401BDD |. 50 push eax ; |Buffer
00401BDE |. FF35 74534000 push dword ptr ds:[405374] ; |hWnd = NULL
00401BE4 |. FF15 60414000 call dword ptr ds:[<&USER32.GetWindowTextA>] ; \GetWindowTextA
00401BEA |. 68 04010000 push 104 ; /n = 104 (260.)
00401BEF |. 6A 00 push 0 ; |c = 00
00401BF1 |. FF35 D4534000 push dword ptr ds:[4053D4] ; |s = NULL
00401BF7 |. E8 8C150000 call <jmp.&MSVCR110.memset> ; \memset
00401BFC |. 8D8D F0FEFFFF lea ecx,dword ptr ss:[ebp-110] ; 注册码放入ecx
00401C02 |. 83C4 0C add esp,0C
00401C05 |. 8D51 01 lea edx,dword ptr ds:[ecx+1] ; *****begin*****
00401C08 |> 8A01 /mov al,byte ptr ds:[ecx]
00401C0A |. 41 |inc ecx
00401C0B |. 84C0 |test al,al ; 求出并判断注册码长度
00401C0D |.^ 75 F9 \jnz short 2013CM.00401C08
00401C0F |. 2BCA sub ecx,edx
00401C11 |. 83F9 04 cmp ecx,4 ; 注册码必须大于4位
00401C14 |. 7C 29 jl short 2013CM.00401C3F ; *****end*****
00401C16 |. 8D85 F0FEFFFF lea eax,dword ptr ss:[ebp-110]
00401C1C |. 50 push eax
00401C1D |. 68 04010000 push 104
00401C22 |. FF35 D4534000 push dword ptr ds:[4053D4]
00401C28 |. FF15 FC404000 call dword ptr ds:[<&MSVCR110.strcpy_s>] ; MSVCR110.strcpy_s
00401C2E |. 83C4 0C add esp,0C ; ESP指向注册码
00401C31 |. E8 FA0A0000 call 2013CM.00402730 ; 注册码验证关键算法
一路走到00401C31,进入主算法依个人习惯Ctrl+A分析完代码后,一路滚轮下去先看看关键API,猜猜作者在玩什么游戏——GetVolumeInformationW、_itoa_s、CharUpperBuffW嗯好像在获取分区信息然后做了什么计算后将计算值转为文本后大写,关键代码如下:
[AppleScript] 纯文本查看 复制代码 00402787 |. 68 04010000 push 104 ; /pFileSystemNameSize = 00000104
0040278C |. 8D85 D8F6FFFF lea eax,dword ptr ss:[ebp-928] ; |
00402792 |. 50 push eax ; |pFileSystemNameBuffer
00402793 |. 8D85 CCF6FFFF lea eax,dword ptr ss:[ebp-934] ; |
00402799 |. 50 push eax ; |pFileSystemFlags
0040279A |. 8D85 D0F6FFFF lea eax,dword ptr ss:[ebp-930] ; |
004027A0 |. 50 push eax ; |pMaxFilenameLength
004027A1 |. 8D85 D4F6FFFF lea eax,dword ptr ss:[ebp-92C] ; |
004027A7 |. 50 push eax ; |pVolumeSerialNumber
004027A8 |. 68 04010000 push 104 ; |MaxVolumeNameSize = 104 (260.)
004027AD |. 8D85 E0F8FFFF lea eax,dword ptr ss:[ebp-720] ; |
004027B3 |. 50 push eax ; |VolumeNameBuffer
004027B4 |. 6A 00 push 0 ; |RootPathName = NULL
004027B6 |. C785 D0F6FFFF>mov dword ptr ss:[ebp-930],0FF ; |
004027C0 |. FF15 58404000 call dword ptr ds:[<&KERNEL32.GetVolu>; \GetVolumeInformationW
004027C6 |. 33C9 xor ecx,ecx
004027C8 |. 85F6 test esi,esi
004027CA |. 7E 11 jle short 2013CM.004027DD
004027CC |. 8B15 D0534000 mov edx,dword ptr ds:[4053D0] ; "playboysen161564"
004027D2 |> 0FBE040A /movsx eax,byte ptr ds:[edx+ecx]
004027D6 |. 41 |inc ecx
004027D7 |. 03F8 |add edi,eax
004027D9 |. 3BCE |cmp ecx,esi
004027DB |.^ 7C F5 \jl short 2013CM.004027D2 ; "playboysen161564"十六进制之和转化成大写文本“57D”
004027DD |> 8B35 04414000 mov esi,dword ptr ds:[<&MSVCR110._ito>; MSVCR110._itoa_s
......
0040287A |. FFD6 call esi ; <&MSVCR110.strcpy_s>
0040287C |. 8D85 F0FCFFFF lea eax,dword ptr ss:[ebp-310] ; GetVolumeInformationW得到C盘十进制ID值“886854821”
00402882 |. 50 push eax
00402883 |. 8D85 F4FDFFFF lea eax,dword ptr ss:[ebp-20C] ; “57D”
00402889 |. 68 04010000 push 104
0040288E |. 50 push eax
0040288F |. FF15 08414000 call dword ptr ds:[<&MSVCR110.strcat_>; MSVCR110.strcat_s
00402895 |. 68 04010000 push 104 ; /n = 104 (260.)
0040289A |. 6A 00 push 0 ; |c = 00
0040289C |. FF35 CC534000 push dword ptr ds:[4053CC] ; |s = 00168998
004028A2 |. E8 E1080000 call <jmp.&MSVCR110.memset> ; \memset
004028A7 |. 8D85 F4FDFFFF lea eax,dword ptr ss:[ebp-20C]
004028AD |. 50 push eax
004028AE |. 68 04010000 push 104
004028B3 |. FF35 CC534000 push dword ptr ds:[4053CC]
004028B9 |. FFD6 call esi ; <&MSVCR110.strcpy_s>
一路F8过去知道这段代码功能大概就是将"playboysen161564"十六进制之和转化成大写文本“57D”,GetVolumeInformationW得到C盘十进制ID值“886854821”,二者相连接组成一个新字符串“57D886854821”我们设为tempCode,然后呢?这个函数结束了……
F8走出当前函数,到了这里
[AppleScript] 纯文本查看 复制代码 00401C2E |. 83C4 0C add esp,0C ; ESP指向注册码
00401C31 |. E8 FA0A0000 call 2013CM.00402730 ; 注册码验证关键算法
00401C36 |. 85C0 test eax,eax
00401C38 |. 74 05 je short 2013CM.00401C3F
00401C3A |. E8 11000000 call 2013CM.00401C50 ; 第二个关键点
00401C3F |> 8B4D FC mov ecx,dword ptr ss:[ebp-4]
00401C42 |. 33CD xor ecx,ebp
嗯,F7进入00401C3A看看,依次发现了VirtualAllocEx、memset、OpenProcess、strcpy、LoadStringA、GetModuleHandleA、GetProcAddress、WriteProcessMemory、CreateRemoteThread等API,程序在干什么??你猜猜……
(还记得开头我们看资源中“8280,注册成功!”字符串的ID值吗?十进制8280转换为十六进制是0x2058,你也可以将OD代码窗口滚动到首行,右键查找——常量——2058,也可以找到这个关键验证函数)
[AppleScript] 纯文本查看 复制代码 00401D2C |. /0F84 F6020000 je 2013CM.00402028
00401D32 |> |8B35 7C404000 mov esi,dword ptr ds:[<&KERNEL32.Open>; kernel32.OpenProcess
00401D38 |. |50 push eax ; /ProcessId
00401D39 |. |6A 00 push 0 ; |Inheritable = FALSE
00401D3B |. |68 FFFF1F00 push 1FFFFF ; |Access = TERMINATE|CREATE_THREAD|VM_OPERATION|VM_READ|VM_WRITE|DUP_HANDLE|CREATE_PROCESS|SET_QUOTA|SET_INFORMATION|QUERY_INFORMATION|SYNCHRONIZE|STANDARD_RIGHTS_REQUIRED|F804
00401D40 |. |FFD6 call esi ; \OpenProcess
......
00401DD7 |. |8B35 58414000 mov esi,dword ptr ds:[<&USER32.LoadSt>; USER32.LoadStringA
00401DDD |. |6A 0D push 0D ; /Count = D (13.)
00401DDF |. |FFB5 B0FDFFFF push dword ptr ss:[ebp-250] ; |Buffer
00401DE5 |. |2BCA sub ecx,edx ; |
00401DE7 |. |68 52200000 push 2052 ; |RsrcID = STRING "Kernel32.dll"
00401DEC |. |FF35 B0534000 push dword ptr ds:[4053B0] ; |hInst = 00400000
00401DF2 |. |898D C4FDFFFF mov dword ptr ss:[ebp-23C],ecx ; |
00401DF8 |. |FFD6 call esi ; \LoadStringA
00401DFA |. |FFB5 B0FDFFFF push dword ptr ss:[ebp-250] ; /pModule
00401E00 |. |FF15 78404000 call dword ptr ds:[<&KERNEL32.GetModu>; \GetModuleHandleA
......
00401E24 |. |57 push edi ; /ProcNameOrOrdinal
00401E25 |. |FFB5 C8FDFFFF push dword ptr ss:[ebp-238] ; |hModule
00401E2B |. |FF15 74404000 call dword ptr ds:[<&KERNEL32.GetProc>; \GetProcAddress
00401E31 |. |8BBD A8FDFFFF mov edi,dword ptr ss:[ebp-258]
00401E37 |. |6A 0C push 0C
00401E39 |. |57 push edi
00401E3A |. |68 56200000 push 2056 ; “MessageBoxA”
00401E3F |. |FF35 B0534000 push dword ptr ds:[4053B0] ; 2013CM.00400000
00401E45 |. |8945 F4 mov dword ptr ss:[ebp-C],eax
00401E48 |. |FFD6 call esi ; USER32.LoadStringA
......
00401E9A |. |FFB5 ACFDFFFF push dword ptr ss:[ebp-254]
00401EA0 |. |8D45 EA lea eax,dword ptr ss:[ebp-16]
00401EA3 |. |6A 0C push 0C
00401EA5 |. |50 push eax ; “注册成功!”
00401EA6 |. |FFD7 call edi ; <&MSVCR110.strcpy_s>
00401EA8 |. |8B35 44404000 mov esi,dword ptr ds:[<&KERNEL32.Virt>; kernel32.VirtualAllocEx
00401EAE |. |83C4 0C add esp,0C
00401EB1 |. |6A 04 push 4
00401EB3 |. |68 00300000 push 3000
00401EB8 |. |68 00100000 push 1000
00401EBD |. |6A 00 push 0
00401EBF |. |53 push ebx
00401EC0 |. |FFD6 call esi ; <&KERNEL32.VirtualAllocEx>
00401EC2 |. |8BF8 mov edi,eax
00401EC4 |. |89BD BCFDFFFF mov dword ptr ss:[ebp-244],edi
00401ECA |. |85FF test edi,edi
00401ECC |. |0F84 F5000000 je 2013CM.00401FC7
00401ED2 |. |6A 00 push 0 ; /pBytesWritten = NULL
00401ED4 |. |68 38020000 push 238 ; |BytesToWrite = 238 (568.)
00401ED9 |. |8D85 C0FDFFFF lea eax,dword ptr ss:[ebp-240] ; |
00401EDF |. |50 push eax ; |Buffer
00401EE0 |. |57 push edi ; |Address
00401EE1 |. |53 push ebx ; |hProcess
00401EE2 |. |FF15 18404000 call dword ptr ds:[<&KERNEL32.WritePr>; \WriteProcessMemory
00401EE8 |. |85C0 test eax,eax ; 将注册成功字符串、假注册码、用户名计算生成的字符串等等信息写入新申请的内存
......
00401F44 |. 6A 00 push 0 ; /pBytesWritten = NULL
00401F46 |. 68 00080000 push 800 ; |BytesToWrite = 800 (2048.)
00401F4B |. 68 50234000 push 2013CM.00402350 ; |Buffer = 2013CM.00402350
00401F50 |. 56 push esi ; |Address
00401F51 |. 53 push ebx ; |hProcess
00401F52 |. FF15 18404000 call dword ptr ds:[<&KERNEL32.WritePr>; \WriteProcessMemory
00401F58 |. 85C0 test eax,eax ; 将00402350处的2048字节数据写入新申请的内存
......
00401FB2 |> |6A 00 push 0
00401FB4 |. |6A 00 push 0
00401FB6 |. |57 push edi ; 数据区块地址
00401FB7 |. |56 push esi ; 代码区段地址
00401FB8 |. |6A 00 push 0
00401FBA |. |6A 00 push 0
00401FBC |. |53 push ebx ; OpenProcess ID
00401FBD |. |FF15 24404000 call dword ptr ds:[<&KERNEL32.CreateR>; kernel32.CreateRemoteThread
整段代码上百行,上面是关键部分
好像程序随机打开某个进程,然后申请两个内存将注册成功字符串、假注册码、用户名计算生成的字符串等等信息和00402350处的2048字节数据写入新申请的内存中,最后创建了远程线程,主程序的主验证函数结束了
嗯,关键的地方来了,我们怎么用OD去调试新线程呢???
大概思路是新开一个OD去附加目标进程,然后在新线程入口处下断点即可
通过OpenProcess参数ProcessId可知目标进程的PID、CreateRemoteThread参数可知新线程执行的代码入口(具体见上段代码注释)
好滴,先在CreateRemoteThread即00401FBD处下断点(这个API一过,新线程已经运行,我们就不能附加调试了)再打开一个ODbyDYK附加目标进程,然后F9也让目标进程正常运行,在新开的OD代码窗口Ctrl+G跳转到新线程入口(比如00C40000),代码如下:
[AppleScript] 纯文本查看 复制代码 00C40000 60 pushad
00C40001 8B0B mov ecx,dword ptr ds:[ebx]
00C40003 8B53 04 mov edx,dword ptr ds:[ebx+4]
00C40006 3BCA cmp ecx,edx
00C40008 74 02 je short 00C4000C ; 这里直接跳过去,否则线程会检测退出
00C4000A 61 popad
00C4000B C3 retn
00C4000C 8BC3 mov eax,ebx ; ebx指向主程序写入该进程的数据区
00C4000E 51 push ecx ; len(tempCode)
00C4000F BF 1C000000 mov edi,1C
00C40014 BE 20010000 mov esi,120
00C40019 03F8 add edi,eax ; edi = 假注册码
00C4001B 03F0 add esi,eax ; esi = tempCode
00C4001D 57 push edi
00C4001E 56 push esi
00C4001F 83F9 0F cmp ecx,0F ; len(tempCode) < 16
00C40022 72 05 jb short 00C40029
00C40024 83E9 0F sub ecx,0F
00C40027 ^ EB F6 jmp short 00C4001F
00C40029 33C0 xor eax,eax
00C4002B 8BF7 mov esi,edi ; esi = edi = tempCode
00C4002D FC cld
00C4002E AC lods byte ptr ds:[esi] ; 将tempCode从前往后逐位参与计算
00C4002F 3C 2D cmp al,2D ; 若当前字符为“-”则跳过
00C40031 74 02 je short 00C40035 ; 即“-”符号原封不动保留
00C40033 33C1 xor eax,ecx
00C40035 AA stos byte ptr es:[edi] ; 将计算后的eax逐字节存入[edi]地址,同时ecx-1
00C40036 ^ E2 F6 loopd short 00C4002E
00C40038 5E pop esi
00C40039 5F pop edi
00C4003A 59 pop ecx
00C4003B FC cld
00C4003C F3:A6 repe cmps byte ptr es:[edi],byte ptr ds:[esi] ;比较edi和esi
00C4003E 74 02 je short 00C40042
00C40040 61 popad
00C40041 C3 retn
上面代码量不大,主要功能就两个:一个是简单检测是否被调试修改,第二就是再次验证注册码,细节见注释
其实在00C40038这里已经可以看到明码了(见图右下角),而且如果直接修改00C40008和00C4003E两处的je为jmp即可爆破(有人说这个是临时线程你修改了也没用啊,其实换种思路即可,临时线程的代码全部都是主程序中复制过来的,可以直接在主程序中搜索到相同代码,修改主程序即可)
到这里,理论上所有算法已经分析完毕了,不过在逆向注册机时又发现个问题
上面说到生成tempCode时用到了"playboysen161564"(设为tempUserName)??这个是什么玩意儿??开头测试输入的用户名不是“playboysen”吗?嗯,用户名后多出一串数字,根据前面的分析觉得以作者的编程习惯,这里应该是用户名和什么一起做了运算得出的数字,既然这样数字总要转成文本,输入用户名时下断_itoa_s函数,轻松找到关键点:
[AppleScript] 纯文本查看 复制代码 00402655 |. E8 2E0B0000 call <jmp.&MSVCR110.memset> ; \memset
0040265A |. 8BF3 mov esi,ebx ; 实时监测用户名输入,输入完自动计算
0040265C |. 83C4 0C add esp,0C
0040265F |. 8D4E 01 lea ecx,dword ptr ds:[esi+1]
00402662 |> 8A06 /mov al,byte ptr ds:[esi]
00402664 |. 46 |inc esi
00402665 |. 84C0 |test al,al
00402667 |.^ 75 F9 \jnz short 2013CM.00402662
00402669 |. 2BF1 sub esi,ecx ; 用户名位数ESI
0040266B |. 89B5 E8FEFFFF mov dword ptr ss:[ebp-118],esi
00402671 |. 83FE 04 cmp esi,4 ; 用户名应不小于4位
00402674 |. 0F8C A3000000 jl 2013CM.0040271D
0040267A |. 57 push edi
0040267B |. FFB5 F4FEFFFF push dword ptr ss:[ebp-10C]
00402681 |. 8D46 01 lea eax,dword ptr ds:[esi+1]
00402684 |. 50 push eax
00402685 |. FF35 D0534000 push dword ptr ds:[4053D0]
0040268B |. 33FF xor edi,edi
0040268D |. 33DB xor ebx,ebx
0040268F |. FF15 FC404000 call dword ptr ds:[<&MSVCR110.strcpy_>; MSVCR110.strcpy_s
00402695 |. 8B95 F4FEFFFF mov edx,dword ptr ss:[ebp-10C]
0040269B |. 83C4 0C add esp,0C
0040269E |. 33C9 xor ecx,ecx
004026A0 |. 83FE 02 cmp esi,2
004026A3 |. 7C 25 jl short 2013CM.004026CA
004026A5 |. 8D46 FF lea eax,dword ptr ds:[esi-1]
004026A8 |. 8985 ECFEFFFF mov dword ptr ss:[ebp-114],eax
004026AE |. 8BF0 mov esi,eax
004026B0 |> 0FBE040A /movsx eax,byte ptr ds:[edx+ecx] ; 用户名逐位参与运算
004026B4 |. 03F8 |add edi,eax
004026B6 |. 0FBE440A 01 |movsx eax,byte ptr ds:[edx+ecx+1]
004026BB |. 83C1 02 |add ecx,2
004026BE |. 03D8 |add ebx,eax
004026C0 |. 3BCE |cmp ecx,esi
004026C2 |.^ 7C EC \jl short 2013CM.004026B0
004026C4 |. 8BB5 E8FEFFFF mov esi,dword ptr ss:[ebp-118]
004026CA |> 3BCE cmp ecx,esi
004026CC |. 7D 0A jge short 2013CM.004026D8
004026CE |. 0FBE040A movsx eax,byte ptr ds:[edx+ecx]
004026D2 |. 8985 F0FEFFFF mov dword ptr ss:[ebp-110],eax
004026D8 |> 8B8D F0FEFFFF mov ecx,dword ptr ss:[ebp-110]
004026DE |. 6A 0A push 0A
004026E0 |. 68 04010000 push 104
004026E5 |. 8D85 F8FEFFFF lea eax,dword ptr ss:[ebp-108]
004026EB |. 50 push eax
004026EC |. 81C1 DD070000 add ecx,7DD ; +0x7DD
004026F2 |. 8D043B lea eax,dword ptr ds:[ebx+edi]
004026F5 |. 03C1 add eax,ecx
004026F7 |. 6BC0 34 imul eax,eax,34 ; 结果 * 0x34
004026FA |. 50 push eax
004026FB |. FF15 04414000 call dword ptr ds:[<&MSVCR110._itoa_s>; MSVCR110._itoa_s
00402701 |. 8D85 F8FEFFFF lea eax,dword ptr ss:[ebp-108]
哈哈,至此全部分析完成,我们来总结一下算法概要,程序的验证逻辑分两段:
一、主算法(主程序中):
1.(用户名十六进制总和+0x7DD) * 0x34形成一个十进制常数,然后再与用户名相连接组成tempUserName
2.tempUserName逐位相加得出十六进制总和,直接将求出的十六进制数转为大写字符串
3.GetVolumeInformation得出C盘序列号(十进制),然后与第2步的字符串相连接组成tempCode
到这里主程序中存在的所有算法结束,不过此时的tempCode只能说是半个注册码,因为程序随机附加了某个进程并创建了个远程线程
二、辅算法(新线程中):
将tempCode从前往后逐字节与len(tempCode)-1异或计算,不过“-”符号不参与异或直接保留,最终形成RegCode!!!
用Python写了段注册机生成代码(本想用论坛注册机生成器,但其1.01版本无法运行,1.0版也无法获取分区ID,被迫放弃):
Python注册机算法表示(调试XP X86/Python 2.7/pywin32):
[Python] 纯文本查看 复制代码 from win32api import GetVolumeInformation
"""求给定字符串各字符十六进制总和,返回十进制数"""
def addBytes(Str):
i = 0
for b in Str:
i = i + ord(b)
return i
"""
主算法(主程序中):
1.(用户名十六进制总和+0x7DD) * 0x34形成一个十进制常数,然后再与用户名相连接组成tempUserName
2.tempUserName十六进制总和(十六进制),直接将求出的十六进制数转为大写字符串
3.GetVolumeInformation得出C盘序列号(十进制),然后与第2步的字符串相连接组成tempCode
到这里主程序中存在的所有算法都结束了,不过此时的tempCode只能说是半个注册码
因为程序随机附加了某个进程并创建了个远程线程,还有一些算法在新线程中验证,所以主程序中是木有明码滴~~
"""
def geneTempCode(UserName):
tempUserName = UserName + str((addBytes(UserName) + 0x7DD)*0x34)
tempCode = hex(addBytes(tempUserName)).upper()[2:] + str(GetVolumeInformation("C:\\")[1])
return tempCode
"""
辅算法(新线程中):
将tempCode从前往后逐字节与len(tempCode)-1异或计算,不过“-”符号不参与异或直接保留,最终形成RegCode!!!
"""
def geneCode(tempCode):
i = 0
Code = ""
if len(tempCode)<0x0F:
tempLen = len(tempCode) + 1
else:
tempLen = len(tempCode) + 1 - 0x0F
for b in tempCode:
tempLen = tempLen-1
if b == "-":
Code = Code + b
else:
Code = Code + chr(ord(b) ^ tempLen)
return Code
"""使用playboysen作为用户名计算注册码"""
print geneCode(geneTempCode("playboysen"))
最后说一下个人感受:
研究分析还原算法用时2个多小时,但编写测试注册机写文章也用了近3个小时,汗
整体来说这个CM也蛮别出心裁,自带调试器基本防护,注册码绑定磁盘,没有错误提示,注册码正确与否都一视同仁ShowWindow一下(防止Cracker以此作区别下断点),部分验证算法在另外一个进程的新线程中进行(有效浪费分析者蛮多时间)
但还是有些地方考虑不尽周全,建议加密字串(防止别人在资源列表中查看突破)用的时候新线程动态解密,关键函数尽量少用系统API或者添加混淆(防止一目了然,也防止了在IDA中F5),注册码部分不要只是简单加减可以考虑来点大数运算什么的,需要写入新进程的代码应该加密存储于主程序中,使用时先动态解密还原(防止在主程序爆破)
附件“吾爱破解2013CM Loader”是使用吾爱破解内存补丁生成器做的Loader(注意用户名和密码都要不小于4位)
|
免费评分
-
查看全部评分
|