佳宜客户管理软件 v2.05 注册算法分析
这几天老想找个东西破破,无奈加密都太高明,我又太弱
下午逛 WZ,看到去年发的一个帖子(当时是发个破解混分数),后面有人求新版破解。
于是把新版下载下来研究
发现注册判断一点也没有变
给 MessageBoxA 设断点,随便输入注册码,断住后跳出 MessageBoxA 本身,然后再跳出一层函数,往上看,就找到了判断的地方:
005ED03D 0F85 FE000000 jnz 005ED141
上次是直接把这个 jnz 改成 jmp 的
现在仍然这么做,还是有效,任意注册码可注册成功
这个软件判断注册成功的时候会把正确的注册信息写入注册表,所以下次再开原版也没关系。
本来想就这么搞,继续混一分的。后来想想这太没追求了,于是开始一句一句看。
具体分析如下(里面好多都没用,只是我当时不知道哪些有用哪些没用,一句句看下来了):
005ECF4C 55 push ebp
005ECF4D 68 B2D15E00 push 005ED1B2
005ECF52 64:FF30 push dword ptr fs:[eax]
005ECF55 64:8920 mov dword ptr fs:[eax], esp
005ECF58 8D55 F0 lea edx, dword ptr [ebp-10] ; EDX="hNG"
005ECF5B 8B45 FC mov eax, dword ptr [ebp-4] ; EAX=01660A70
005ECF5E 8B80 04030000 mov eax, dword ptr [eax+304] ; EAX=[EAX+304]=[01660D74]=01656380
005ECF64 E8 3F1BE6FF call 0044EAA8
005ECF69 8B45 F0 mov eax, dword ptr [ebp-10] ; EAX=0163906C="abcd"
005ECF6C 8D55 F4 lea edx, dword ptr [ebp-C] ; [ebp-C]=00000000
005ECF6F E8 18C8E1FF call 0040978C ; 去除用户名首尾空格
005ECF74 837D F4 00 cmp dword ptr [ebp-C], 0 ; [ebp-C]=0163B2D0="abcd"
005ECF78 75 22 jnz short 005ECF9C
005ECF7A 6A 00 push 0
005ECF7C 68 C0D15E00 push 005ED1C0
005ECF81 E8 2AFBFEFF call <jmp.&PunUnitLib.ShowMess> ; 提示填写用户名称
005ECF86 8B45 FC mov eax, dword ptr [ebp-4]
005ECF89 8B80 04030000 mov eax, dword ptr [eax+304]
005ECF8F 8B10 mov edx, dword ptr [eax]
005ECF91 FF92 C0000000 call dword ptr [edx+C0]
005ECF97 E9 B1010000 jmp 005ED14D
005ECF9C 8D55 E8 lea edx, dword ptr [ebp-18] ; EDX=0012F39C, [EDX]=00000000
005ECF9F 8B45 FC mov eax, dword ptr [ebp-4] ; EAX=01660A70
005ECFA2 8B80 FC020000 mov eax, dword ptr [eax+2FC] ; EAX=[01660D6C]=01662F58, [EAX]=004331E8
005ECFA8 E8 FB1AE6FF call 0044EAA8 ; 不知道在干嘛
005ECFAD 8B45 E8 mov eax, dword ptr [ebp-18] ; EAX=0163B2D0="1234"
005ECFB0 8D55 EC lea edx, dword ptr [ebp-14] ; [ebp-14]=00000000
005ECFB3 E8 D4C7E1FF call 0040978C ; 去除注册码首尾空格
005ECFB8 837D EC 00 cmp dword ptr [ebp-14], 0 ; [ebp-14]=01646B4C="1234"
005ECFBC 75 22 jnz short 005ECFE0
005ECFBE 6A 00 push 0
005ECFC0 68 D4D15E00 push 005ED1D4
005ECFC5 E8 E6FAFEFF call <jmp.&PunUnitLib.ShowMess> ; 提示输入注册码
005ECFCA 8B45 FC mov eax, dword ptr [ebp-4]
005ECFCD 8B80 FC020000 mov eax, dword ptr [eax+2FC]
005ECFD3 8B10 mov edx, dword ptr [eax]
005ECFD5 FF92 C0000000 call dword ptr [edx+C0]
005ECFDB E9 6D010000 jmp 005ED14D
005ECFE0 A1 94A96300 mov eax, dword ptr [63A994] ; EAX=[0063A994]=00639D44
005ECFE5 8B00 mov eax, dword ptr [eax] ; EAX=[00639D44]=005DCB44="6J9Y-K3H7"
005ECFE7 E8 0080E1FF call 00404FEC ; 不知道在干嘛
005ECFEC 50 push eax ; EAX=005DCB44="6J9Y-K3H7"
005ECFED 8D55 E4 lea edx, dword ptr [ebp-1C] ; [ebp-1C]=00000000
005ECFF0 8B45 FC mov eax, dword ptr [ebp-4] ; EAX=01660A70
005ECFF3 8B80 F4020000 mov eax, dword ptr [eax+2F4] ; EAX=[01660D64]=01662C98, [EAX]=004331E8
005ECFF9 E8 AA1AE6FF call 0044EAA8 ; 不知道在干嘛
005ECFFE 8B45 E4 mov eax, dword ptr [ebp-1C] ; EAX=[ebp-1C]=0165EC18="WD-WCARY0610755"
005ED001 E8 E67FE1FF call 00404FEC ; 不知道在干嘛
005ED006 50 push eax ; EAX=0165EC18="WD-WCARY0610755", 机器码
005ED007 E8 D4FAFEFF call <jmp.&PunUnitLib.GetRegPass>; 算注册码
005ED00C 8BD0 mov edx, eax ; EDX=EAX=01512524="6J9Y-5353-K3H7-7303"
005ED00E 8D45 F8 lea eax, dword ptr [ebp-8] ; [ebp-8]=[0012F3AC]=00000000
005ED011 E8 167DE1FF call 00404D2C ; [ebp-8]=0165EC34=正确注册码
005ED016 8D55 DC lea edx, dword ptr [ebp-24] ; [ebp-24]=00000000
005ED019 8B45 FC mov eax, dword ptr [ebp-4] ; EAX=[0012F3B0]=01660A70
005ED01C 8B80 FC020000 mov eax, dword ptr [eax+2FC] ; EAX=[01660D6C]=01662F58, [EAX]=004331T8
005ED022 E8 811AE6FF call 0044EAA8 ; 不知道在干嘛
005ED027 8B45 DC mov eax, dword ptr [ebp-24] ; EAX="1234", 错误注册码
005ED02A 8D55 E0 lea edx, dword ptr [ebp-20] ; [ebp-20]=[0012F394]=00000000
005ED02D E8 5AC7E1FF call 0040978C ; 复制字符串?
005ED032 8B45 E0 mov eax, dword ptr [ebp-20] ; EAX=[ebp-20]="1234", 错误注册码
005ED035 8B55 F8 mov edx, dword ptr [ebp-8] ; EDX=0165EC34=正确注册码
005ED038 E8 FB7EE1FF call 00404F38 ; 比较
005ED03D 0F85 FE000000 jnz 005ED141 ; 不同则跳
上面是一段,大体情况已经清楚,注册码中的第一段和第三段是常量,第二段和第四段则是算出来的
下面看算注册码的函数
PunUnitLib.GetRegPass
007D9024 55 push ebp
007D9025 8BEC mov ebp, esp
007D9027 B9 06000000 mov ecx, 6 ; 循环 6 次
007D902C 6A 00 push 0
007D902E 6A 00 push 0
007D9030 49 dec ecx
007D9031 75 F9 jnz short 007D902C ; 循环尾,一共 PUSH 了 12 个 0
007D9033 53 push ebx ; EBX=01628E04="hNG"
007D9034 56 push esi ; ESI=004773E0
007D9035 33C0 xor eax, eax
007D9037 55 push ebp
007D9038 68 F2917D00 push 007D91F2
007D903D 64:FF30 push dword ptr fs:[eax]
007D9040 64:8920 mov dword ptr fs:[eax], esp
007D9043 8D45 EC lea eax, dword ptr [ebp-14]
007D9046 E8 65B5F8FF call 007645B0
007D904B 8D45 F0 lea eax, dword ptr [ebp-10] ; [ebp-10]=[0012F360]=00000000
007D904E 8B55 08 mov edx, dword ptr [ebp+8] ; EDX=[0012F348]=01512400="WD-WCARY0610755"
007D9051 E8 4AB7F8FF call 007647A0
007D9056 8B45 F0 mov eax, dword ptr [ebp-10] ; [ebp-10]=[0012F348]=01512400="WD-WCARY0610755"
007D9059 E8 0AB8F8FF call 00764868 ; 求机器码长度
007D905E 8BF0 mov esi, eax ; ESI=EAX=0000000F
007D9060 85F6 test esi, esi
007D9062 7E 26 jle short 007D908A ; 机器码为空?
007D9064 BB 01000000 mov ebx, 1 ; 记录循环次数(N),下行开始循环
007D9069 8D4D E8 lea ecx, dword ptr [ebp-18] ; [ebp-18]=[0012F340]=00000000
007D906C 8B45 F0 mov eax, dword ptr [ebp-10] ; EAX="WD-WCARY0610755"
007D906F 0FB64418 FF movzx eax, byte ptr [eax+ebx-1] ; EAX=第N个字符='W'=57h
007D9074 33D2 xor edx, edx
007D9076 E8 F905F9FF call 00769674 ; 数值转字符(十六进制)
007D907B 8B55 E8 mov edx, dword ptr [ebp-18] ; EDX=[ebp-18]=[0012F340]=0051241C="57"
007D907E 8D45 FC lea eax, dword ptr [ebp-4] ; [ebp-4]=[0012F354]=00000000
007D9081 E8 EAB7F8FF call 00764870 ; [ebp-4]=0041241C="57"
007D9086 43 inc ebx
007D9087 4E dec esi
007D9088 75 DF jnz short 007D9069 ; 循环尾
007D908A 8B45 FC mov eax, dword ptr [ebp-4] ; EAX=[ebp-4]=0151243C="57442D574341525930363130373535"
; 原来刚才的循环是把每一个字符的 ASCII 码拼起来
007D908D E8 D6B7F8FF call 00764868 ; 求字符串长度
007D9092 8BF0 mov esi, eax ; ESI=EAX=0000001E
007D9094 85F6 test esi, esi
007D9096 7E 2C jle short 007D90C4 ; 又来判断字符串为空?刚才不是判断过了。。
007D9098 BB 01000000 mov ebx, 1 ; 记录循环次数(N),下行开始循环
007D909D 8B45 FC mov eax, dword ptr [ebp-4] ; EAX=[ebp-4]=0151243C="57442D574341525930363130373535"
007D90A0 E8 C3B7F8FF call 00764868 ; 求字符串长度, EAX=0000001E
007D90A5 2BC3 sub eax, ebx ; EAX=EAX-N=1D(N=1)
007D90A7 8B55 FC mov edx, dword ptr [ebp-4] ; EDX=[ebp-4]=0151243C="57442D574341525930363130373535"
007D90AA 8A1402 mov dl, byte ptr [edx+eax] ; DL=倒数第N个字符 1st:DL='5'=35h, 2nd:DL='3'=33h
007D90AD 8D45 E4 lea eax, dword ptr [ebp-1C] ; [ebp-1C]=[0012F33C]=00000000
007D90B0 E8 DBB6F8FF call 00764790
007D90B5 8B55 E4 mov edx, dword ptr [ebp-1C] ; 1st: EDX=[ebp-1C]=[0012F33C]=0151242C, [EDX]=00000035
; 2nd: EDX=[ebp-1C]=[0012F33C]=01512468, [EDX]=00000033
007D90B8 8D45 F8 lea eax, dword ptr [ebp-8] ; 1st: [ebp-8]=[0012F350]=00000000
; 2nd: [ebp-8]=[0012F350]=0151242C="5"
007D90BB E8 B0B7F8FF call 00764870 ; 1st: [ebp-8]=[0012F350]=0151242C="5"
; 2nd: [ebp-8]=[0012F350]=0151242C="53"
; 3st: [ebp-8]=[0012F350]=0151242C="535"
; 4th: [ebp-8]=[0012F350]=01512478="5353"
; 5th: [ebp-8]=[0012F350]=01512478="53537"
; ……
007D90C0 43 inc ebx
007D90C1 4E dec esi
007D90C2 75 D9 jnz short 007D909D ; 循环尾
; [ebp-8]=01512478="535373031363039525143475D24475"
; 刚才那个循环把这字符串倒了一下
007D90C4 8D45 FC lea eax, dword ptr [ebp-4] ; EAX=[ebp-4]=0151243C="57442D574341525930363130373535"
007D90C7 50 push eax ; 00764AC0 的参数四,buffer
007D90C8 B9 04000000 mov ecx, 4 ; 参数三,要取的字符数
007D90CD BA 01000000 mov edx, 1 ; 参数二,从第几位开始取
007D90D2 8B45 F8 mov eax, dword ptr [ebp-8] ; 参数一,要取子串的字符串
; EAX=[ebp-8]=01512478="535373031363039525143475D24475"
007D90D5 E8 E6B9F8FF call 00764AC0 ; 取子串。EAX=0012F354, [EAX]=015124A4="5353"
007D90DA 8D45 F8 lea eax, dword ptr [ebp-8]
007D90DD 50 push eax
007D90DE B9 04000000 mov ecx, 4 ; 取 4 位
007D90E3 BA 05000000 mov edx, 5 ; 从第 5 位开始取
007D90E8 8B45 F8 mov eax, dword ptr [ebp-8] ; 还是那串字符串
007D90EB E8 D0B9F8FF call 00764AC0 ; 取子串。EAX=0012F350, [EAX]=015124B8="7303"
007D90F0 8B45 FC mov eax, dword ptr [ebp-4] ; EAX="5353"
007D90F3 E8 70B7F8FF call 00764868 ; 求字符串长度
007D90F8 83F8 04 cmp eax, 4
007D90FB 7D 2F jge short 007D912C ; 长度为 4, 跳到 007D912C。下面是长度小于 4 的处理
007D90FD 8B45 FC mov eax, dword ptr [ebp-4] ; 假设机器码只有一个"W",EAX="75"
007D9100 E8 63B7F8FF call 00764868 ; 求长
007D9105 8BD8 mov ebx, eax ; EBX=EAX=2
007D9107 83FB 03 cmp ebx, 3
007D910A 7F 20 jg short 007D912C ; 大于 3,仍然跳到 007D912C。这个判断似乎又是多此一举?
007D910C 8D4D E0 lea ecx, dword ptr [ebp-20] ; [ebp-20]=[0012F338]=00000000
007D910F 8BC3 mov eax, ebx ; 1st: EAX=EBX=00000002
; 2nd: EAX=3
007D9111 C1E0 02 shl eax, 2 ; 1st: EAX=EAX*4=00000008
; 2nd: EAX=EAX*4=C
007D9114 33D2 xor edx, edx
007D9116 E8 5905F9FF call 00769674 ; 1st: EAX="8"
; 2nd: EAX="C"
007D911B 8B55 E0 mov edx, dword ptr [ebp-20] ; EDX=[ebp-20]=[0012F338]=015124CC, EDX=59390043
007D911E 8D45 FC lea eax, dword ptr [ebp-4] ; 1st: [ebp-4]=015124A4="758"
; 2nd: [ebp-4]=015124A4="758C"
007D9121 E8 4AB7F8FF call 00764870
007D9126 43 inc ebx
007D9127 83FB 04 cmp ebx, 4 ; 没有补到 4 个则继续
007D912A 75 E0 jnz short 007D910C
007D912C 8B45 F8 mov eax, dword ptr [ebp-8]
007D912F E8 34B7F8FF call 00764868
007D9134 83F8 04 cmp eax, 4
007D9137 7D 2F jge short 007D9168
007D9139 8B45 F8 mov eax, dword ptr [ebp-8]
007D913C E8 27B7F8FF call 00764868
007D9141 8BD8 mov ebx, eax
007D9143 83FB 03 cmp ebx, 3
007D9146 7F 20 jg short 007D9168
007D9148 8D4D DC lea ecx, dword ptr [ebp-24]
007D914B 8BC3 mov eax, ebx
007D914D C1E0 02 shl eax, 2
007D9150 33D2 xor edx, edx
007D9152 E8 1D05F9FF call 00769674
007D9157 8B55 DC mov edx, dword ptr [ebp-24]
007D915A 8D45 F8 lea eax, dword ptr [ebp-8] ; 这里缺位也跟上面一样补,补为 048C
; 不管原来几位最后都是 048C, *48C, **8C, ***C, ****
007D915D E8 0EB7F8FF call 00764870
007D9162 43 inc ebx
007D9163 83FB 04 cmp ebx, 4
007D9166 75 E0 jnz short 007D9148
007D9168 8D45 D8 lea eax, dword ptr [ebp-28] ; [ebp-28]=[0012F330]=00000000
007D916B 8B55 0C mov edx, dword ptr [ebp+C] ; EDX=[0012F364]=005DCB44="6J9Y-K3H7"
007D916E E8 2DB6F8FF call 007647A0
007D9173 8B45 D8 mov eax, dword ptr [ebp-28] ; EAX=[ebp-28]=[0012F330]=01512488="6J9Y-K3H7"
007D9176 8D55 F4 lea edx, dword ptr [ebp-C] ; [ebp-C]=[0012F34C]=00000000
007D9179 E8 DE03F9FF call 0076955C ; [ebp-C]=[0012F34C]=015124A0="6J9Y-K3H7"
007D917E 8D45 D4 lea eax, dword ptr [ebp-2C] ; [ebp-2C]=[0012F32C]=00000000
007D9181 50 push eax
007D9182 B9 04000000 mov ecx, 4
007D9187 BA 01000000 mov edx, 1
007D918C 8B45 F4 mov eax, dword ptr [ebp-C]
007D918F E8 2CB9F8FF call 00764AC0 ; [ebp-2C]=[0012F32C]=015124B8="6J9Y"
007D9194 FF75 D4 push dword ptr [ebp-2C]
007D9197 68 0C927D00 push 007D920C
007D919C FF75 FC push dword ptr [ebp-4]
007D919F 8D45 D0 lea eax, dword ptr [ebp-30]
007D91A2 50 push eax
007D91A3 B9 05000000 mov ecx, 5
007D91A8 BA 05000000 mov edx, 5
007D91AD 8B45 F4 mov eax, dword ptr [ebp-C]
007D91B0 E8 0BB9F8FF call 00764AC0
007D91B5 FF75 D0 push dword ptr [ebp-30] ; [ebp-30]=[0012F328]=015124CC="-K3H7"
007D91B8 68 0C927D00 push 007D920C
007D91BD FF75 F8 push dword ptr [ebp-8]
007D91C0 8D45 EC lea eax, dword ptr [ebp-14]
007D91C3 BA 06000000 mov edx, 6
007D91C8 E8 5BB7F8FF call 00764928 ; 这里就是拼接起来,懒得仔细看了
; 最后是 6J9Y-5353-K3H7-7303
007D91CD 8B45 EC mov eax, dword ptr [ebp-14]
007D91D0 E8 8BB8F8FF call 00764A60
007D91D5 8BD8 mov ebx, eax
007D91D7 33C0 xor eax, eax
007D91D9 5A pop edx
007D91DA 59 pop ecx
007D91DB 59 pop ecx
007D91DC 64:8910 mov dword ptr fs:[eax], edx
007D91DF 68 F9917D00 push 007D91F9
007D91E4 8D45 D0 lea eax, dword ptr [ebp-30]
007D91E7 BA 0C000000 mov edx, 0C
007D91EC E8 E3B3F8FF call 007645D4
007D91F1 C3 retn
007D91F2 E9 1DADF8FF jmp 00763F14
007D91F7 EB EB jmp short 007D91E4
007D91F9 8BC3 mov eax, ebx
007D91FB 5E pop esi
007D91FC 5B pop ebx
007D91FD 8BE5 mov esp, ebp
007D91FF 5D pop ebp
007D9200 C2 0800 retn 8
哈哈,终于熬出头了,再写个
注册机(仅供学习研究,请下载后24小时内删除)
第一次完整地把算法分析出来,真兴奋~
(原发表于 CSDN:https://blog.csdn.net/cnStreamlet/article/details/2505288)