吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 141630|回复: 717
收起左侧

[原创] 金盾视频加密2010.5正式版加密文件破解浅析 by wuhanqi[LCG]

    [复制链接]
wuhanqi 发表于 2010-2-27 02:23
本帖最后由 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

免费评分

参与人数 1威望 +1 收起 理由
CHHSun + 1 感谢发布原创作品,[吾爱破解]因你更精彩!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

头像被屏蔽
小举 发表于 2010-2-27 09:15
学习啦!楼主很强大
cxx54007 发表于 2010-2-27 08:42
CHHSun 发表于 2010-2-27 08:42
本帖最后由 CHHSun 于 2010-2-27 09:05 编辑

分析的好有深度,三个字,“看不懂”
没有7-16位算出来的这5位数字是不会播放的,但是这5位是固定。
但是他一定是数字,没有事的可以从00000-99999一个一个猜哈。
coolqqt 发表于 2010-2-27 04:04
看不懂这些喔
kankan 发表于 2010-2-27 02:40
CC大叔对这情有独钟
 楼主| wuhanqi 发表于 2010-2-27 02:31
sf自占备用了
cleanspace 发表于 2010-2-27 09:32
站在前辈的肩膀上进步
dpll 发表于 2010-2-27 09:57
学习啦!楼主很强大
井跳蛙 发表于 2010-2-27 11:16
在Unpack看到了
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-25 16:21

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表