好友
阅读权限25
听众
最后登录1970-1-1
|
本帖最后由 wuhanqi 于 2010-2-27 04:44 编辑
【文章标题】: 金盾视频加密2010.5正式版加密文件破解浅析 by wuhanqi[LCG]
【文章作者】: wuhanqi
【作者主页】: hi.baidu.com/wuhanqi
【下载地址】: 自己搜索下载
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
关于这个软件,CHHSun大叔研究了前面的版本,在这个版本碰到了小问题,请我与他一起探讨,嘿嘿,太看得起我了,不过看得起我自然也会尽全力帮忙,经过了四个晚上(白天学业繁忙..)的研究...大概理解了程序的验证流程..只是流程...算法无能..各位大牛可以自己去分析分析,写点心得与我等小菜分享、
稍微来讲点我的分析结果吧!
首先呢,我们要运行软件主程序,保持密匙不变更改机器码,看看结果是啥:
9d64c560ad53b271d531c76c
9d30c260ad53b2718760c232
大概可以判断机器码验证的是用零替换的那几位:
9d000060ad53b27100000000
而我们指定一下用户水印信息,发现不再是9d开头了:c22e9135a05ab2718134c135f2
原来9d是没有水印的情况.既然我们要破解,又不是逆算法,不管那么多了,我们就9d开头把!
这样我们可以从主程序得到以上信息。
手头有CHHSun大叔送来的正式版加密的文件。并且有真码方便做坏事....那我们就开工吧!
PEID查下壳,Delphi,自然而然想到DELPHI事件脚本。
运行脚本,输入9d000060ad53b27100000000,点击确定会断下来,我们F8加F4狂跟..代码超长..来到提示错误的地方...
004A3D5F . A1 84CE5300 MOV EAX,DWORD PTR DS:[53CE84] ; 53ce84的值是关键,下硬件断点!
004A3D64 . BA 64494A00 MOV EDX,004A4964
004A3D69 . E8 4219F6FF CALL 004056B0
004A3D6E . 75 20 JNZ SHORT 004A3D90
004A3D70 . 8D95 80F7FFFF LEA EDX,DWORD PTR SS:[EBP-880]
004A3D76 . B8 CC494A00 MOV EAX,004A49CC ; ASCII "03A7149157BF40AA03B976A95CD4"
004A3D7B . E8 B4600000 CALL 004A9E34
004A3D80 . 8B85 80F7FFFF MOV EAX,DWORD PTR SS:[EBP-880]
004A3D86 . E8 0180F9FF CALL 0043BD8C ; 这里出错了、
004A3D8B . E9 1E030000 JMP 004A40AE
004A3D90 > A1 84CE5300 MOV EAX,DWORD PTR DS:[53CE84]
重载程序,在点击确定按钮后的第二次中断停下来,我们看下代码:
00405300 |> \F0:FF42 F8 LOCK INC DWORD PTR DS:[EDX-8]
00405304 |> 8710 XCHG DWORD PTR DS:[EAX],EDX ; EDX与EAX所指向的值交换,而我们的EAX是53ce84
00405306 |. 85D2 TEST EDX,EDX ; 停在这
00405308 |. 74 14 JE SHORT 0040531E
上下看下代码,这里是个子程序,所以我们不能让这段子程序执行,我们走出去,来到:
004A38AC . 8B45 F0 MOV EAX,DWORD PTR SS:[EBP-10]
004A38AF 8B55 EC MOV EDX,DWORD PTR SS:[EBP-14]
004A38B2 . E8 F91DF6FF CALL 004056B0
004A38B7 . 74 0F JE SHORT 004A38C8
004A38B9 . B8 84CE5300 MOV EAX,0053CE84
004A38BE . BA 64494A00 MOV EDX,004A4964
004A38C3 . E8 141AF6FF CALL 004052DC ; 这里就干坏事了!
004A38C8 > A1 7C775300 MOV EAX,DWORD PTR DS:[53777C]
记得CHHSun说过:8b55ec→8b55f0
这下懂了为什么了..要保持EAX=EDX不让他修改关键标志位..
那我们Ctrl+b:8b45f08b55ece8????????74
大概有五处...全部修改后,对于0的部分就破解完成了、
那他什么时候验证密匙的呢?
CHHSun大叔提供了一个地址:004A45A5 . 8D85 DCFBFFFF LEA EAX,DWORD PTR SS:[EBP-424]
说此地址EDX很关键,那我们来这里看看。
EAX 00000000
ECX 00000001
EDX 00D3CFE8 ASCII "47600"
EBX 00CF0200
ESP 0012ED00 ASCII "OHJ"
EBP 0012F5B4
ESI 0053CF00 02礼仪.0053CF00
EDI 00417BC0 02礼仪.00417BC0
EIP 004A45A5 02礼仪.004A45A5
我输入的是正确的7-16位。而这里显示了47600。
程序什么时候对这个值进行了验证呢?我直接在D3CFE8下硬件断点.没断下来.
后来想到他可能把00D3CFE8这个地址保存到别的地方,然后再调用..
Alt+M打开内存镜像,Ctrl+b搜索:e8cfd300
0053CE8C E8 CF D3 00 柘?楺?
找到了,那我搜索所有常数,看看哪里调用这个...53ce8c,还是没有,难道有把他也保存到别的地方了?
再次内存镜像中Ctrl+b:8cce5300
005375EC 8C CE 53 00 屛S.埼
004A1DD8 8C CE 53 00 屛S.棼
两个,经测试,第一个是关键,我们右键,搜索所有常数:5375EC
右键,在每个命令上设置断点,然后F9~
来到:
004A778A |. A1 EC755300 MOV EAX,DWORD PTR DS:[5375EC]
004A778F |. 8B00 MOV EAX,DWORD PTR DS:[EAX]
004A7791 |. E8 5A26F6FF CALL 00409DF0
004A7796 |. 8BD0 MOV EDX,EAX
向下看看代码,是解码算法:
004A782C |> /8D55 D3 /LEA EDX,DWORD PTR SS:[EBP-2D]
004A782F |. |B9 01000000 |MOV ECX,1
004A7834 |. |8B45 E0 |MOV EAX,DWORD PTR SS:[EBP-20]
004A7837 |. |8B38 |MOV EDI,DWORD PTR DS:[EAX]
004A7839 |. |FF57 0C |CALL DWORD PTR DS:[EDI+C]
004A783C |. |0FB645 D3 |MOVZX EAX,BYTE PTR SS:[EBP-2D]
004A7840 |. |8BD3 |MOV EDX,EBX
004A7842 |. |C1EA 08 |SHR EDX,8
004A7845 |. |3055 D3 |XOR BYTE PTR SS:[EBP-2D],DL
004A7848 |. |0FB6C0 |MOVZX EAX,AL
004A784B |. |03D8 |ADD EBX,EAX
004A784D |. |0FAF5D D8 |IMUL EBX,DWORD PTR SS:[EBP-28]
004A7851 |. |035D D4 |ADD EBX,DWORD PTR SS:[EBP-2C]
004A7854 |. |8D55 D3 |LEA EDX,DWORD PTR SS:[EBP-2D]
004A7857 |. |B9 01000000 |MOV ECX,1
004A785C |. |8B45 DC |MOV EAX,DWORD PTR SS:[EBP-24]
004A785F |. |8B38 |MOV EDI,DWORD PTR DS:[EAX]
004A7861 |. |FF57 10 |CALL DWORD PTR DS:[EDI+10]
004A7864 |. |4E |DEC ESI
004A7865 |.^\75 C5 \JNZ SHORT 004A782C
我分别输入真码和假码进行对比,发现变量是:[EBP-2D]
正确的前四次调用的字节依次为:31 8C 24 13
EBP-2D这个地址的数据哪里来的呢?
004A782C |> /8D55 D3 /LEA EDX,DWORD PTR SS:[EBP-2D]
不过这一步,我们在EDX右键数据窗口中跟随,BYTE PTR SS:[EBP-2D]还是00
那说明是004A7839 |. |FF57 0C |CALL DWORD PTR DS:[EDI+C]捣鬼,我们下硬件断点,来到:
00403206 > \0FB608 MOVZX ECX,BYTE PTR DS:[EAX]
00403209 . 880A MOV BYTE PTR DS:[EDX],CL
0040320B . C3 RETN
此时寄存器EAX指向地址013086b0,右键数据窗口中跟随:
013086B0 31 8C 24 13 1??
这就是我们的表啊~
为什么当7-16位不正确的时候表的值不对呢?我以为是个解码算法,谁知道跟出来..用的是函数、
我们还是继续吧,13086b0硬件断点,发现这里向13086b0放了数据:
004031BF . 8D4C0A 08 LEA ECX,DWORD PTR DS:[EDX+ECX+8]
004031C3 . 5A POP EDX
004031C4 > DF2C01 FILD QWORD PTR DS:[ECX+EAX]
004031C7 . DF3C11 FISTP QWORD PTR DS:[ECX+EDX]
004031CA . 83C1 08 ADD ECX,8
004031CD .^ 7C F5 JL SHORT 004031C4
004031CF . DF3A FISTP QWORD PTR DS:[EDX]
004031D1 . 5A POP EDX
004031D2 . DF3A FISTP QWORD PTR DS:[EDX]
004031D4 . C3 RETN
看寄存器EBP里面是12fcc80。跟随一下,发现放的是我们的表,这里就是表最先保存的地方了。
但是什么时候解压的数据呢?硬件断点没能帮我们找到答案,这时候我们就要靠F8+F7了
看走过哪个call,数据解压,下个断点,重载,然后跟进,再跟...
经过重复,竟然发现是调用了READFILE函数!不是解压算法....看来固定思维真的很害人...
0040A0E2 |. 6A 00 PUSH 0 ; /pOverlapped = NULL
0040A0E4 |. 8D4424 04 LEA EAX,DWORD PTR SS:[ESP+4] ; |
0040A0E8 |. 50 PUSH EAX ; |pBytesRead
0040A0E9 |. 57 PUSH EDI ; |BytesToRead
0040A0EA |. 56 PUSH ESI ; |Buffer
0040A0EB |. 53 PUSH EBX ; |hFile
0040A0EC |. E8 8BD7FFFF CALL <JMP.&kernel32.ReadFile> ; \ReadFile
这里读出了我们的数据。
他是怎么读出来的呢?
用到的都是函数...先CreateFileA打开文件,然后再设置读取位置SetFilePointer,最后调用ReadFile把内容读取到buffer...在这个验证过程中,createfile的只有.key文件,即程序加密后的文件(金盾加密生成一个EXE和一个.KEY)、程序是把正确的解码表放到加密后的文件的....
那他是怎么判断解码表的位置的呢?这就用到我们的7-16位了...
我们来分析下。重载程序,断在004A778A |. A1 EC755300 MOV EAX,DWORD PTR DS:[5375EC]后,bp SetFilePointer
断下后看堆栈:
00B4FE84 0040A157 /CALL 到 SetFilePointer 来自 02礼仪.0040A152
00B4FE88 00000224 |hFile = 00000224 (窗口)
00B4FE8C FFFF4270 |OffsetLo = FFFF4270 (-48528.)
00B4FE90 00B4FEA4 |pOffsetHi = 00B4FEA4
00B4FE94 00000002 \Origin = FILE_END
从文件末倒数48528个字节...
这个ffff4270怎么出来的呢?
于是乎又重来,再从004A778A开始跟...关键算法就在004A778A下面两三行..
004A778A |. A1 EC755300 MOV EAX,DWORD PTR DS:[5375EC]
004A778F |. 8B00 MOV EAX,DWORD PTR DS:[EAX] ; 获取了我们的47600
004A7791 |. E8 5A26F6FF CALL 00409DF0 ; 转换成16进制,到EAX
004A7796 |. 8BD0 MOV EDX,EAX ; EDX=EAX
004A7798 |. 8B45 F0 MOV EAX,DWORD PTR SS:[EBP-10] ; 常数398到eax
004A779B |. 83C0 08 ADD EAX,8 ; eax+8
004A779E |. 03D0 ADD EDX,EAX ; edx=edx+3a0
004A77A0 |. F7DA NEG EDX ; edx取补,出现了我们的FFFF4270
004A77A2 66:B9 0200 MOV CX,2
原来如此!注册码的7-16先经过运算,转换成五位数字,再经过上面的运算,获取到解码表的位置...密匙就是派这个用处的..
再补一下7-16运算成为五位数字的算法:
004A0F19 . 8D95 F0FDFFFF LEA EDX,DWORD PTR SS:[EBP-210]
004A0F1F . 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4]
004A0F22 . E8 0987F6FF CALL 00409630
004A0F27 . 8B85 F0FDFFFF MOV EAX,DWORD PTR SS:[EBP-210] ; 注册码到EAX
004A0F2D . 8D95 F4FDFFFF LEA EDX,DWORD PTR SS:[EBP-20C] ; 一块空地用来保存结果
004A0F33 . E8 FC8E0000 CALL 004A9E34 ; 关键算法,F7
004A0F38 . 8B95 F4FDFFFF MOV EDX,DWORD PTR SS:[EBP-20C] ; 这里可以看到ebp-20c放了保存运算结果的地址,是八个字节的我这里是 2c02a33437363030
004A0F3E . B8 78CE5300 MOV EAX,0053CE78
004A0F43 . E8 9443F6FF CALL 004052DC
004A0F48 . B2 01 MOV DL,1
004A0F4A . A1 747B4100 MOV EAX,DWORD PTR DS:[417B74]
…………………………省略 ……………………………………
004A1DC1 . 8D8D D8FBFFFF LEA ECX,DWORD PTR SS:[EBP-428]
004A1DC7 . BA 05000000 MOV EDX,5
004A1DCC . E8 6345F9FF CALL 00436334 ; 这里从第四位开始取了五位保存起来,47600
004A1DD1 . 8B95 D8FBFFFF MOV EDX,DWORD PTR SS:[EBP-428]
004A1DD7 . B8 8CCE5300 MOV EAX,0053CE8C
关键call的算法循环部分:
004A9E85 |> /8D45 EC /LEA EAX,DWORD PTR SS:[EBP-14]
004A9E88 |. |50 |PUSH EAX
004A9E89 |. |8B55 F8 |MOV EDX,DWORD PTR SS:[EBP-8]
004A9E8C |. |03D2 |ADD EDX,EDX
004A9E8E |. |4A |DEC EDX
004A9E8F |. |B9 02000000 |MOV ECX,2 ; ecx=2
004A9E94 |. |8B45 FC |MOV EAX,DWORD PTR SS:[EBP-4]
004A9E97 |. |E8 E4B8F5FF |CALL 00405780 ; 取两位注册码
004A9E9C |. |8B4D EC |MOV ECX,DWORD PTR SS:[EBP-14]
004A9E9F |. |8D45 F0 |LEA EAX,DWORD PTR SS:[EBP-10]
004A9EA2 |. |BA 209F4A00 |MOV EDX,004A9F20
004A9EA7 |. |E8 F4B6F5FF |CALL 004055A0
004A9EAC |. |8B45 F0 |MOV EAX,DWORD PTR SS:[EBP-10]
004A9EAF |. |E8 3CFFF5FF |CALL 00409DF0 ; ASCII码变成十六进制 放到eax
004A9EB4 |. |8BD0 |MOV EDX,EAX ; edx=eax
004A9EB6 |. |0FB683 307253>|MOVZX EAX,BYTE PTR DS:[EBX+537230] ; 固定hex值到eax
004A9EBD |. |32D0 |XOR DL,AL ; dl=dl xor al
004A9EBF |. |8D45 F4 |LEA EAX,DWORD PTR SS:[EBP-C]
004A9EC2 |. |E8 A9B5F5FF |CALL 00405470
004A9EC7 |. |8B55 F4 |MOV EDX,DWORD PTR SS:[EBP-C]
004A9ECA |. |8BC7 |MOV EAX,EDI
004A9ECC |. |E8 83B6F5FF |CALL 00405554
004A9ED1 |. |43 |INC EBX ; ebx+1
004A9ED2 |. |81E3 07000080 |AND EBX,80000007
004A9ED8 |. |79 05 |JNS SHORT 004A9EDF
004A9EDA |. |4B |DEC EBX
004A9EDB |. |83CB F8 |OR EBX,FFFFFFF8
004A9EDE |. |43 |INC EBX
004A9EDF |> |FF45 F8 |INC DWORD PTR SS:[EBP-8]
004A9EE2 |. |4E |DEC ESI
004A9EE3 |.^\75 A0 \JNZ SHORT 004A9E85
大概是,把注册码每两位一组,从10进制直接变成十六进制,然后与固定HEX值逐位进行异或运算,再串起来、
固定hex值为:B1 02 A3 54 94 63 82 41
不过我们已经把其他位都爆破了关系到我们的只有7-16位,那我们就可以总结一下7-16位的算法:
设7-16位注册码为A,string.5494638241 设为b,dword. c,string.d dword。
正向:
两位一组取注册码,ASCII码变成十六进制,逐位取b与十六进制做xor运算.串起来保存,结果设为C.
d=格式化字符串(c)
d=NEG(d+3A0).
然后把d作为lDistanceToMove 字节偏移量,把文件指针设置在从文件末开始计算偏移量的位置。这样就可以读到解码表。
逆向
我们需要在.key文件中搜索0x318C2413 获取偏移地址,与文件末地址相减,获取到的就是字节偏移量d
d=neg d
d=d-3a0
c=十六进制转为字符串(d)
逐位取字符串hex值,再逐位取b,做xor运算,把结果串起来,设为B
十六进制转ascii码,即为7-16位注册码。
最后,屏蔽防翻录:004A6367 . /0F84 6E010000 je 004A64DB 跳过OK
屏蔽让复制黏贴失效的功能:0043C724 55 → 0C3
简单,我就不贴过程了,自己跟吧!
--------------------------------------------------------------------------------
【经验总结】
小总结一下
程序在确定的按钮事件里先验证了与机器码有关的注册码部分,在解码之前,要通过正确的7-16位获取到解码表的位置,正
确解码,然后才能播放。机器码部分可以做个搜索与替换补丁,7-16则需要注册机了。
Special thx to:CHHSun upksky BeyondMe 鹭影依凌
--------------------------------------------------------------------------------
【版权声明】: 本文原创于LCG, 转载请注明作者并保持文章的完整, 谢谢!
2010年02月27日 2:31:25
本代码的着色效果由xTiNt自动完成
下载xTiNt http://211.90.75.84/web/kanaun/download/xTiNt.rar |
免费评分
-
查看全部评分
本帖被以下淘专辑推荐:
- · 学习及教程|主题: 1127, 订阅: 1119
|