某文件夹软件的破解+算法分析+keyGen源码(VB版)
本帖最后由 GGLHY 于 2012-8-30 21:18 编辑****文件夹软件的破解 + 算法分析 + keyGen源码(VB版)
为尊重软件作者版权,保护国软,特以“****文件夹软件”替代软件原名,下同!如有火眼金睛的XDJM知道这软件,还请不要摆出它的大名。虽说这正式版的软件本身非常难得,但对名字保密一事还敬请见谅。(感谢下坛里的K大大{:biggrin:})
OK,手握倚天剑,祭起屠龙刀。OD载入。
运行软件后,有NAG出现,提示要求注册,并给出了机器码。于是输入注册信息如下:
软件注册名:GGLHY祝大家天天快乐!
产品序列号:12345-67890-abcde-fghij-klmno(注册框5个部分,且每个部分最多只能输入5个字符!这一点会在后面算法部分得到印证。)
点注册,有出错的弹窗。通过F12的方法,我们可以看到:
005B852E E8 B9F4F6FF CALL other.005279EC ; JMP 到 user32.MessageBoxW很显然,程序目前是停在一个叫other.dll的领空。
我们用回溯的方法,可以看到如下内容:
(省略部分代码...)
005B84DD 8B55 FC MOV EDX,DWORD PTR SS:
005B84E0 E8 1B90FCFF CALL other.00581500 ; 关键CALL
005B84E5 84C0 TEST AL,AL ; 经典的标志位!
005B84E7 74 34 JE SHORT other.005B851D ; 跳不跳是个烦恼的事吗?
005B84E9 68 40000400 PUSH 40040
005B84EE 68 74855B00 PUSH other.005B8574
005B84F3 68 A4855B00 PUSH other.005B85A4
005B84F8 6A 00 PUSH 0
005B84FA E8 EDF4F6FF CALL other.005279EC ; JMP 到 user32.MessageBoxW
005B84FF 68 18865B00 PUSH other.005B8618 ; ASCII "****文件夹MESSAGE"
005B8504 E8 4BF5F6FF CALL other.00527A54 ; JMP 到 user32.RegisterWindowMessageA
005B8509 6A 00 PUSH 0
005B850B 68 39120000 PUSH 1239
005B8510 50 PUSH EAX
005B8511 68 FFFF0000 PUSH 0FFFF
005B8516 E8 89F5F6FF CALL other.00527AA4 ; JMP 到 user32.SendNotifyMessageA
005B851B EB 16 JMP SHORT other.005B8533
005B851D 68 10000400 PUSH 40010
005B8522 68 74855B00 PUSH other.005B8574
005B8527 68 30865B00 PUSH other.005B8630
005B852C 6A 00 PUSH 0
005B852E E8 B9F4F6FF CALL other.005279EC ; 出错啦!(往上找这该死的从哪来)
005B8533 33C0 XOR EAX,EAX
很显然,005B84E0处的 CALL other.00581500 是我们应该开门进去瞧一瞧的地方。于是在这一段的段首下个断点,重新注册:
(省略部分代码...)
005B834E E8 099AFFFF CALL other.005B1D5C
005B8353 8B45 EC MOV EAX,DWORD PTR SS: ; 输入的注册码第一部分“12345”
(省略部分代码...)
005B8363 E8 68CEF6FF CALL other.005251D0
005B8368 0F84 94000000 JE other.005B8402 ; 注册码第一部分为空则跳向错误提示
005B836E 8D55 E4 LEA EDX,DWORD PTR SS:
005B8371 8B83 98030000 MOV EAX,DWORD PTR DS:
005B8377 E8 E099FFFF CALL other.005B1D5C
005B837C 8B45 E4 MOV EAX,DWORD PTR SS: ; 输入的注册码第二部分“67890”
(省略部分代码...)
005B838C E8 3FCEF6FF CALL other.005251D0
005B8391 74 6F JE SHORT other.005B8402 ; 注册码第二部分为空则跳向错误提示
005B8393 8D55 DC LEA EDX,DWORD PTR SS:
005B8396 8B83 9C030000 MOV EAX,DWORD PTR DS:
005B839C E8 BB99FFFF CALL other.005B1D5C
005B83A1 8B45 DC MOV EAX,DWORD PTR SS: ; 输入的注册码第三部分“abcde”
(省略部分代码...)
005B83B1 E8 1ACEF6FF CALL other.005251D0
005B83B6 74 4A JE SHORT other.005B8402 ; 注册码第三部分为空则跳向错误提示
(省略部分代码...)
005B83CC E8 030EF7FF CALL other.005291D4
005B83D1 8B45 D8 MOV EAX,DWORD PTR SS: ; 输入的注册码第四部分“fghij”
005B83D4 33D2 XOR EDX,EDX
005B83D6 E8 F5CDF6FF CALL other.005251D0 ; 注册码第四部分为空则跳向错误提示
005B83DB 74 25 JE SHORT other.005B8402
005B83DD 8D55 CC LEA EDX,DWORD PTR SS:
005B83E0 8B83 A4030000 MOV EAX,DWORD PTR DS:
005B83E6 E8 7199FFFF CALL other.005B1D5C
005B83EB 8B45 CC MOV EAX,DWORD PTR SS: ; 输入的注册码第五部分“klmno”
005B83EE 8D55 D0 LEA EDX,DWORD PTR SS:
005B83F1 E8 DE0DF7FF CALL other.005291D4
005B83F6 8B45 D0 MOV EAX,DWORD PTR SS:
005B83F9 33D2 XOR EDX,EDX
005B83FB E8 D0CDF6FF CALL other.005251D0
005B8400 75 1B JNZ SHORT other.005B841D ; 注册码第五部分不为空则跳!
005B8402 68 40000400 PUSH 40040
005B8407 68 74855B00 PUSH other.005B8574
005B840C 68 84855B00 PUSH other.005B8584
005B8411 6A 00 PUSH 0
005B8413 E8 D4F5F6FF CALL other.005279EC ; JMP 到 user32.MessageBoxW
005B8418 E9 16010000 JMP other.005B8533
005B841D 8D55 C0 LEA EDX,DWORD PTR SS:
005B8420 8B83 94030000 MOV EAX,DWORD PTR DS:
005B8426 E8 3199FFFF CALL other.005B1D5C
005B842B 8B45 C0 MOV EAX,DWORD PTR SS: ; 输入的注册码第一部分““12345”
(省略部分代码...)
005B8442 E8 1599FFFF CALL other.005B1D5C
005B8447 8B45 B8 MOV EAX,DWORD PTR SS: ; 输入的注册码第二部分“67890”
(省略部分代码...)
005B8463 8B45 B0 MOV EAX,DWORD PTR SS: ; 输入的注册码第三部分“abcde”
(省略部分代码...)
005B847F 8B45 A8 MOV EAX,DWORD PTR SS: ; 输入的注册码第四部分“fghij”
(省略部分代码...)
005B849B 8B45 A0 MOV EAX,DWORD PTR SS: ; 输入的注册码第五部分“klmno”
005B849E 8D55 A4 LEA EDX,DWORD PTR SS:
005B84A1 E8 2E0DF7FF CALL other.005291D4
005B84A6 FF75 A4 PUSH DWORD PTR SS:
005B84A9 8D45 C8 LEA EAX,DWORD PTR SS:
005B84AC BA 05000000 MOV EDX,5
005B84B1 E8 D2CCF6FF CALL other.00525188
005B84B6 8B55 C8 MOV EDX,DWORD PTR SS: ; 5部分联接起来 (UNICODE "1234567890abcdefghijklmno")
(省略部分代码...)
005B84D5 E8 06C5F6FF CALL other.005249E0
005B84DA 8B45 9C MOV EAX,DWORD PTR SS:
005B84DD 8B55 FC MOV EDX,DWORD PTR SS: ; 5部分联接起来的注册码"1234567890abcdefghijklmno"
005B84E0 E8 1B90FCFF CALL other.00581500 ; 关键CALL
005B84E5 84C0 TEST AL,AL ; 经典的标志位!
005B84E7 74 34 JE SHORT other.005B851D
恩,同志们,现在到了考验我们的时候了~~~005B84E0处的CALL other.00581500
我们F7进入:
00581519 55 PUSH EBP
0058151A 68 90165800 PUSH other.00581690
0058151F 64:FF30 PUSH DWORD PTR FS:
00581522 64:8920 MOV DWORD PTR FS:,ESP
00581525 C645 FF 00 MOV BYTE PTR SS:,0 ; 绝佳的爆破点之一,改0为1。哈哈~~~
00581529 8D45 F0 LEA EAX,DWORD PTR SS:
0058152C E8 53FCFFFF CALL other.00581184
00581531 8D55 EC LEA EDX,DWORD PTR SS:
00581534 8B45 F0 MOV EAX,DWORD PTR SS: ; 机器码出现 (ASCII "Y3M75HN3QPJBYBD")
00581537 E8 C0FCFFFF CALL other.005811FC ; 算法核心CALL,KG的实现就指望着它了
0058153C 8B45 EC MOV EAX,DWORD PTR SS: ; 真码啊~~~,爱死你了!
0058153F 8BD3 MOV EDX,EBX ; 输入的假码 "1234567890abcdefghijklmno"
00581541 E8 1636FAFF CALL other.00524B5C
00581546 0F85 29010000 JNZ other.00581675 ; 跳?还是不跳? 这是个问题吗?
0058154C B2 01 MOV DL,1 ; 不跳则开始写注册信息咯
0058154E A1 90145400 MOV EAX,DWORD PTR DS:
(省略部分代码...)
005815A5 8D55 E4 LEA EDX,DWORD PTR SS:
005815A8 B8 AC165800 MOV EAX,other.005816AC ; ASCII "user"
005815AD E8 3AF4FFFF CALL other.005809EC
005815B2 8B55 E4 MOV EDX,DWORD PTR SS:
005815B5 8B45 F8 MOV EAX,DWORD PTR SS:
005815B8 59 POP ECX
005815B9 E8 0E06FCFF CALL other.00541BCC
005815BE 8D55 E0 LEA EDX,DWORD PTR SS:
005815C1 8BC3 MOV EAX,EBX
005815C3 E8 24F4FFFF CALL other.005809EC
005815C8 8B45 E0 MOV EAX,DWORD PTR SS:
005815CB 50 PUSH EAX
005815CC 8D55 DC LEA EDX,DWORD PTR SS:
005815CF B8 BC165800 MOV EAX,other.005816BC ; ASCII "cpsn"
005815D4 E8 13F4FFFF CALL other.005809EC
005815D9 8B55 DC MOV EDX,DWORD PTR SS:
005815DC 8B45 F8 MOV EAX,DWORD PTR SS:
005815DF 59 POP ECX
005815E0 E8 E705FCFF CALL other.00541BCC
005815E5 C645 FF 01 MOV BYTE PTR SS:,1 ; <<== 众里寻1千百度!
005815E9 8B45 F8 MOV EAX,DWORD PTR SS:
005815EC E8 0F00FCFF CALL other.00541600
005815F1 B1 01 MOV CL,1
005815F3 BA CC165800 MOV EDX,other.005816CC ; ASCII "lfte"
005815F8 8B45 F8 MOV EAX,DWORD PTR SS:
005815FB E8 9800FCFF CALL other.00541698
00581600 84C0 TEST AL,AL
00581602 74 20 JE SHORT other.00581624
00581604 8B4D F0 MOV ECX,DWORD PTR SS:
00581607 BA DC165800 MOV EDX,other.005816DC ; ASCII "edoccam"
0058160C 8B45 F8 MOV EAX,DWORD PTR SS:
0058160F E8 B805FCFF CALL other.00541BCC
00581614 8B4D F4 MOV ECX,DWORD PTR SS:
00581617 BA EC165800 MOV EDX,other.005816EC ; ASCII "yekger"
0058161C 8B45 F8 MOV EAX,DWORD PTR SS:
0058161F E8 A805FCFF CALL other.00541BCC
00581624 33C0 XOR EAX,EAX
(省略部分代码...)
00581690^ E9 272AFAFF JMP other.005240BC
00581695^ EB EB JMP SHORT other.00581682
00581697 8A45 FF MOV AL,BYTE PTR SS: ; 你若为0,便无晴天~~
0058169A 5F POP EDI
0058169B 5E POP ESI
0058169C 5B POP EBX
0058169D 8BE5 MOV ESP,EBP
0058169F 5D POP EBP
005816A0 C3 RETN
看起来,前面005B84E5处这里标志位AL的值是由00581697 处的PTR SS:的值决定的。如果单纯的爆破的话,至少有以下的几种方法: 方法1(掐头).00581525 处 MOV BYTE PTR SS:,0 ; 将0改为1
方法2(拦腰).00581546 处 JNZ other.00581675 ;把JNZ来nop
方法3(截尾).00581697 处 MOV AL,BYTE PTR SS: ; 改为MOV AL,1
显然,第一种方法改动的效率高,而且更保险。
但是,如果你单纯只改这个DLL文件的话,呵呵,我不会告诉你主程序中会有这么一段:
004AF17C 3B4D F0 CMP ECX,DWORD PTR SS:
004AF17F 7E 05 JLE SHORT ****文件夹软件.004AF186
004AF181 B9 01000000 MOV ECX,1
(省略部分代码...)
004AF1A0 BF 18000000 MOV EDI,18
(省略部分代码...)
004AF1AF 83FB 19 CMP EBX,19
004AF1B2^ 75 C8 JNZ SHORT ****文件夹软件.004AF17C
004AF1B4 BB 19000000 MOV EBX,19
004AF1B9 8D75 8C LEA ESI,DWORD PTR SS:我也不会告诉你还有这样的东东:
004B3114 E8 A71BF5FF CALL ****文件夹软件.00404CC0
004B3119 6A 00 PUSH 0
004B311B E8 7495FEFF CALL ****文件夹软件.0049C694 ; JMP到other.Other_JCSYQ(有兴趣就进去看看)
004B3120 8D95 ECFBFFFF LEA EDX,DWORD PTR SS:
004B3126 E8 A96FF5FF CALL ****文件夹软件.0040A0D4
004B312B 8B95 ECFBFFFF MOV EDX,DWORD PTR SS: ; 存在着注册名吗?
004B3131 B8 A4B04B00 MOV EAX,****文件夹软件.004BB0A4
004B3136 E8 D518F5FF CALL ****文件夹软件.00404A10 ; !!!!
004B313B 833D A4B04B00 0>CMP DWORD PTR DS:,0
004B3142 0F9505 8DB04B00 SETNE BYTE PTR DS: ; 哈哈,全局变量!
004B3149 E8 8E9EFEFF CALL ****文件夹软件.0049CFDC
004B314E A2 8CB04B00 MOV BYTE PTR DS:,AL
恩,现在明白了吧。{:tongue:}
好,我们接着来看那个算法核心CALL里有些啥宝贝:
00581205 33C9 XOR ECX,ECX
00581207 894D 88 MOV DWORD PTR SS:,ECX
0058120A 894D F4 MOV DWORD PTR SS:,ECX
0058120D 8955 F8 MOV DWORD PTR SS:,EDX
00581210 8945 FC MOV DWORD PTR SS:,EAX ; 机器码 (ASCII "Y3M75HN3QPJBYBD")
00581213 33C0 XOR EAX,EAX
00581215 55 PUSH EBP
00581216 68 CB125800 PUSH other.005812CB
0058121B 64:FF30 PUSH DWORD PTR FS:
0058121E 64:8920 MOV DWORD PTR FS:,ESP
00581221 8B45 F8 MOV EAX,DWORD PTR SS:
00581224 E8 3735FAFF CALL other.00524760
00581229 8B45 FC MOV EAX,DWORD PTR SS: ;(ASCII "Y3M75HN3QPJBYBD")
0058122C E8 E737FAFF CALL other.00524A18
00581231 8945 F0 MOV DWORD PTR SS:,EAX ; 机器码的长度 本例F=15
00581234 837D F0 00 CMP DWORD PTR SS:,0 ; 机器码长度为空吗?
00581238 74 73 JE SHORT other.005812AD
0058123A B9 01000000 MOV ECX,1 ; 计数器ECX初始化为1
0058123F 33DB XOR EBX,EBX
00581241 8D75 8C LEA ESI,DWORD PTR SS:
00581244 3B4D F0 CMP ECX,DWORD PTR SS: ; 计数器ECX : 机器码的长度
00581247 7E 05 JLE SHORT other.0058124E ; 不大于则跳
00581249 B9 01000000 MOV ECX,1
0058124E 8B45 FC MOV EAX,DWORD PTR SS: ; 机器码 (ASCII "Y3M75HN3QPJBYBD")
00581251 0FB67C08 FF MOVZX EDI,BYTE PTR DS: ; 依次取机器码的每一位ASC
00581256 8BC7 MOV EAX,EDI
00581258 99 CDQ
00581259 F7F9 IDIV ECX ; /计数器(ECX)
0058125B 8BC2 MOV EAX,EDX ; 保存余数
0058125D 8BD3 MOV EDX,EBX ; 计数器EBX(初始=0),每循环 + 1
0058125F 0FAFD7 IMUL EDX,EDI ; 依次取的机器码每一位ASC*计数器EBX
00581262 03C2 ADD EAX,EDX ; 余数 + 乘积
00581264 2BC3 SUB EAX,EBX ; (余数 + 乘积)的和 - 计数器EBX
00581266 03C1 ADD EAX,ECX ; 差值 + 计数器ECX
00581268 BF 18000000 MOV EDI,18
0058126D 99 CDQ
0058126E F7FF IDIV EDI ; (差值 + 计数器ECX) /18H
00581270 8916 MOV DWORD PTR DS:,EDX ; 余数保存起来~~~
00581272 41 INC ECX
00581273 43 INC EBX
00581274 83C6 04 ADD ESI,4
00581277 83FB 19 CMP EBX,19 ; 计数器EBX:19H(注册码长度现在清楚了吧)
0058127A^ 75 C8 JNZ SHORT other.00581244
0058127C BB 19000000 MOV EBX,19 ; 25位!!!!
00581281 8D75 8C LEA ESI,DWORD PTR SS:
00581284 8D45 88 LEA EAX,DWORD PTR SS:
00581287 8A16 MOV DL,BYTE PTR DS: ; 上面循环所保存的每一位余数
00581289 80C2 41 ADD DL,41 ; 每一位余数asc + 41H
0058128C E8 AF36FAFF CALL other.00524940
00581291 8B55 88 MOV EDX,DWORD PTR SS: ; 转化为对应的字符
00581294 8D45 F4 LEA EAX,DWORD PTR SS:
00581297 E8 8437FAFF CALL other.00524A20
0058129C 83C6 04 ADD ESI,4
0058129F 4B DEC EBX ; 计数器!
005812A0^ 75 E2 JNZ SHORT other.00581284
005812A2 8B45 F8 MOV EAX,DWORD PTR SS:
005812A5 8B55 F4 MOV EDX,DWORD PTR SS: ; 转化对应的字符后相连而成的真码~~~~
005812A8 E8 0735FAFF CALL other.005247B4
005812AD 33C0 XOR EAX,EAX
005812AF 5A POP EDX
005812B0 59 POP ECX
005812B1 59 POP ECX
005812B2 64:8910 MOV DWORD PTR FS:,EDX
005812B5 68 D2125800 PUSH other.005812D2
005812BA 8D45 88 LEA EAX,DWORD PTR SS:
005812BD E8 9E34FAFF CALL other.00524760
005812C2 8D45 F4 LEA EAX,DWORD PTR SS:
005812C5 E8 9634FAFF CALL other.00524760
005812CA C3 RETN
005812CB^ E9 EC2DFAFF JMP other.005240BC
005812D0^ EB E8 JMP SHORT other.005812BA
005812D2 5F POP EDI
恩,我们先来看看这个核心CALL里的几个关键信息:
第一处:
00581244 3B4D F0 CMP ECX,DWORD PTR SS: ; 计数器ECX:机器码的长度
00581247 7E 05 JLE SHORT other.0058124E ; 不大于则跳
00581249 B9 01000000 MOV ECX,1
显然,如果机器码取完后,则计数器ECX则又从1开始。第二处:
00581277 83FB 19 CMP EBX,19 ; 计数器EBX :19H=25
和
0058127C BB 19000000 MOV EBX,19 ; 25位!!!!
这说明机器码会循环取值运算直到25位为止第三处:
00581289 80C2 41 ADD DL,41 ; 每一位余数asc + 41H
0058128C E8 AF36FAFF CALL other.00524940
00581291 8B55 88 MOV EDX,DWORD PTR SS: ; 转化为对应的字符
这里就是将每一循环运算的余数 + 41H ,然后输出对应的字符并保存起来。
好了,结合上面这3个关键信息,上面循环中的算法实现过程呢,我们可以这样来理解:
a.计数器ECX其实就是所取机器码中的某位字符在机器码中的位置值。显然ECX是从1到len(机器码)。
b.计数器EBX是循环取机器码直到25位为止。即EBX是从0 到 24。
机器码长度 < 25位时,则机器码复制并相连直到满足25位长度为止,设为JQMS。
本例机器码为"Y3M75HN3QPJBYBD",长度=15位,则JQMS应该为"Y3M75HN3QPJBYBDY3M75HN3QP";
计数器ECX则为1 到 15,循环计算;
计数器EBX依次从0到24,共25位。正好=len(JQMS)的值。
现在,以实例来表示这个算法的实现过程:
当取JQMS的第一位"Y"的时候其(16进制)ASC为59,10进制=89,ECX = 1 ,EBX =0 ,41H=65,18H =24
则运算过程为:
ASC ECX ASCEBX EBX ECX
((( 89 mod 1) + ( 89 *0 )-0 +1 )) mod 24 + 65= 66
( 0 + 0 -0 +1 )mod 24 + 65= 66
66的16进制为42,对应的字符为“B”
同理,当取JQMS的第16位"Y"时,ECX=1,EBX=15,则:
ASC ECX ASCEBX EBX ECX
(( 89 mod 1) + ( 89 * 15 )- 15 +1 )mod 24 + 65= 66
( 0 + 1335- 15 +1 )mod 24 + 65= 66
显然,结果又是对应的字符正好为“B”。
算法过程应该很清楚了吧。下面小结一下:
1.注册码与软件注册名无关
2.取机器码的1~25位(不足则复制机器码并连接直到满足25位为止),设为JQMS
3.机器码位置值(ECX)设为I(1 to 机器码长度),设JQMS的位置值Q(= 1 to 25),J为Q MOD I 的余数(若余数=0时则J=I)
4.依次取JQMS的每一位ASC mod 机器码位置值 的余数+取JQMS的每一位ASC * (Q-1) -(Q-1) + J
其和 mod 24
余数再 + 65
得到对应的字符。直至运算完毕。
好了,搞清楚了算法实现过程就可以顺便KeyGen了。附上写的很烂的代码(处女作,哈哈)如下:**** Hidden Message *****
软件的附加码其实就是注册码的变形存在注册表中的。即注册码的每一位ASC xor 23 的结果转化为对应的字符而已。这里就不再罗嗦了。
最近流行无图无真 相,只好贴2张。哈哈
本文如有错误还望大牛们指正!
谢谢观看~~~
这个软件多年来算法都没变过,过去内存注册机遍地都是 kiss-you 发表于 2012-8-30 06:26 static/image/common/back.gif
这个软件多年来算法都没变过,过去内存注册机遍地都是
{:biggrin:},向K大学习。。。。
前排学习~~ {:3_164:}软件作者不靠卖软件,玩的是娱乐,或做其他的事 谢谢分享。学习啦 支持原创分析,学习算法
网络验证的,不合法还会清空原来的注册信息变成未注册版 谢谢分享。好好学习啦 本帖最后由 GGLHY 于 2012-8-31 10:17 编辑
wxq 发表于 2012-8-30 23:06 https://www.chinapyg.com/static/image/common/back.gif
网络验证的,不合法还会清空原来的注册信息变成未注册版
是有网验,可在防火墙中禁止即可。
但这不是本文的目的。我主要是看它的算法来进行分析而已