当前位置:免费黑客网-黑客技术,黑客工具,黑客联盟,黑客基地,黑客网站,黑客论坛DDOS黑客技术加密解密
日期:2016-04-26 22:13:47  来源:网络

对某个CAD绘图控件的分析

【文章标题】: 某个CAD绘图控件的分析【文章作者】: LiXMX【保护方式】: 序列号【编写语言】: Borland Delphi 6.0 - 7.0【使用工具】: PEiD,Regmon_fix,DEDE,UltraEdit【操作平台】: Win XP【软件介绍】: 一款Delphi和C++Builder环境下的矢量图绘制工具插件,功能简单但是较实用。【作者声明】: 本人菜鸟一枚,发帖原因是从注册后到现在没发过像样的文章,注册好多年了,惭愧哇,主要是技术不到家啊。如果和版规冲突,请管理员删除,谢谢。【分析原因】: 本菜分析它的原因仅仅是因为这个软件的授权方式让我很不爽(PS:我已经花钱买下来了>_<)。目前使用序列号方式授权,每次重装系统都要重新申请,虽然提供加密狗,但是加密狗居然只支持Delphi,不能再C++Builder中使用,让只会C/C++的本小菜很受伤,深感受到了歧视,所以破解之。-------------------------------------------------------------------------------【流程】:初看对方提供的程序,分为三个部分:控件安装程序、机器码生成程序、加密狗一枚。加密狗:这个就不说了,等着过段时间在研究一下吧。机器码生成程序:该程序运行后就会生成一个8位机器码,机器码一般多为CpuID,分区卷序号之类的。然后通过“只要不重装系统,每次的码都是一样的”排除了CpuID,初步判断是分区卷序号。之后使用PEiD查看Import,发现确实有GetVolumeInformation函数被调用,几乎就确定是分区卷序号了。最搞笑的是当我在CMD中输入dir命令时,我发现C盘的序列号赫然就是生成的机器码,晕,明文啊明文……再看看他把我的注册号放到哪里了?使用Regmon_fix监视了一下,发现是写道注册表中了。那么大概就可以确定他的工作流程了:1.获取C盘的序列号作为机器码发送给作者;2.作者根据用户提供的机器码算出注册码后发送给用户;3.用户使用“机器码生成程序”导入注册码到本地注册表中;4.控件在启动时会检查C盘的序列号和注册表中的注册码是否匹配。所以到了这里,第一种破解方式已经有了:用户只要把自己的C盘的序列号修改成和正版用户一样的就可以正常使用该控件了。控件安装程序:知道了大概的授权流程了之后,从授权流程的4步就可以看出,控件本身在启动时也需要获取C盘的序列号,一边使用C盘的序列号和注册码进行某种校验。于是我们从控件程序本身下手,首先查看控件安装目录中的全部DCU文件,看看有没有什么可以的DCU文件。于是发现了两个的文件:Encryption.hpp 和Encryption.dcu(十分明目张胆的文件名啊)。既然如此那就先看看他吧,看看是个诱饵还是个果子。在Encryption.hpp头文件中看到有三个函数定义:extern PACKAGE AnsiString __fastcall GetDiskSerialID(char cDriveName);extern PACKAGE AnsiString __fastcall Encrypt(const AnsiString str);extern PACKAGE AnsiString __fastcall Decrypt(const AnsiString str);我勒个去的,这不就是:获取磁盘序号,编码,解码三个步骤,全齐了(看来作者压根就没想过防破解啥的,嘿嘿,不差钱哦)之后,使用DEDE的DCU Dump功能获得该DCU的反汇编代码。在DCU中的USES中发现有如下声明:Windows{T:DWORD, A:SetErrorMode,A:SEM_FAILCRITICALERRORS,A:MAX_PATH,A:GetVolumeInformation}出现了GetVolumeInformation,看来是找对地方了。既然有了GetVolumeInformation,那么之后就应该是使用Encrypt和Decrypt对C盘序号和注册码进行加密解密了。最初我的想法是修改DCU中判断注册码正误的相关跳转,来一个爆破算了,但是继续往下看,发现作者在这里又给了我一个惊喜……extern PACKAGE AnsiString __fastcall Encrypt(const AnsiString str)函数的反汇编如下:PS:不得不感慨,DEDE确实是DELPHI程序员的噩梦哇!!!function Encrypt (str: System.AnsiString): System.AnsiString;var result Result: System.AnsiString; i: System.Integer; sn: System.AnsiString;begin 00000000 : 55 PUSH EBP 00000001 : 8B EC MOV EBP,ESP 00000003 : 83 C4 EC ADD ESP,-20 00000006 : 53 PUSH EBX 00000007 : 33 C9 XOR ECX,ECX // ECX清零 00000009 : 89 4D EC MOV DWORD PTR [EBP-20],ECX // 初始化为0,此处应该是编译器生成的temp临时变量,存放密码异或的结果 0000000C : 89 4D F0 MOV DWORD PTR [EBP-16{sn}],ECX // sn初始化为0(用于存放处理后的VolumeSerial) 0000000F : 89 55 F8 MOV DWORD PTR [EBP-8{Result}],EDX // result用于返回结果 00000012 : 89 45 FC MOV DWORD PTR [EBP-4{str}],EAX // str就是输入的VolumeSerial 00000015 : 33 C0 XOR EAX,EAX // EAX清零 00000017 : 55 PUSH EBP 00000018 : 68(79 00 00 00 PUSH Encrypt{0x3A}+121 0000001D : 64 FF 30 PUSH DWORD PTR FS:[EAX] 00000020 : 64 89 20 MOV DWORD PTR FS:[EAX],ESP 00000023 : C7 45 F4 01 00 00 00 MOV DWORD PTR [EBP-12{i}],$00000001 // i计数器初值为1,应该是个for循环起始位置 0000002A : 8D 45 EC LEA EAX,DWORD PTR [EBP-20] 0000002D : 8A 55 F4 MOV DL,BYTE PTR [EBP-12{i}] // i放入到DL中 00000030 : 8B 4D F4 MOV ECX,DWORD PTR [EBP-12{i}] // 计数器i放入到ECX中 00000033 : 8B 5D FC MOV EBX,DWORD PTR [EBP-4{str}] // str的首地址放入到EBX中 00000036 : 32 54 0B FF XOR DL,BYTE PTR [EBX+ECX-1] // str[i]和DL异或 0000003A : E8(00 00 00 00 CALL @LStrFromChar{0x21} // 异或后的结果转换成char型 0000003F : 8B 55 EC MOV EDX,DWORD PTR [EBP-20] // @LStrCat的参数,fastcall调用使用了EDX寄存器 00000042 : 8D 45 F0 LEA EAX,DWORD PTR [EBP-16{sn}] // @LStrCat的参数,fastcall调用使用了EAX寄存器 00000045 : E8(00 00 00 00 CALL @LStrCat{0x22} // 追加EDX中的内容到字符串sn尾部 0000004A : FF 45 F4 INC DWORD PTR [EBP-12{i}] // i计数器自增 0000004D : 83 7D F4 09 CMP DWORD PTR [EBP-12{i}],9 // i计数器和9比较 00000051 : 75 D7 JNE -41; (0x2A) // 是否是小于9,小于9继续循环,大于等于则终止(因为VolumeSerial是8个字符长度) 00000053 : 8B 45 F8 MOV EAX,DWORD PTR [EBP-8{Result}] // @LStrAsg的参数,fastcall调用使用了EAX寄存器 00000056 : 8B 55 F0 MOV EDX,DWORD PTR [EBP-16{sn}] // @LStrAsg的参数,fastcall调用使用了EDX寄存器 00000059 : E8(00 00 00 00 CALL @LStrAsg{0x26} // @LStrAsg用于将字符串sn赋值给Result 0000005E : 33 C0 XOR EAX,EAX 00000060 : 5A POP EDX 00000061 : 59 POP ECX 00000062 : 59 POP ECX 00000063 : 64 89 10 MOV DWORD PTR FS:[EAX],EDX 00000066 : 68(80 00 00 00 PUSH Encrypt{0x3A}+128 0000006B : 8D 45 EC LEA EAX,DWORD PTR [EBP-20] 0000006E : BA 02 00 00 00 MOV EDX,$00000002 00000073 : E8(00 00 00 00 CALL @LStrArrayClr{0x29} 00000078 : C3 RET NEAR 00000079 : E9(00 00 00 00 JMP @HandleFinally{0x23} 0000007E : EB EB JMP -21; (0x6B) 00000080 : 5B POP EBX 00000081 : 8B E5 MOV ESP,EBP 00000083 : 5D POP EBP 00000084 : C3 RET NEARend;通过读代码发现关键的编码部分是一个for循环,而且使用的是xor运算……这下子Decrypt函数连看都不用看了,关键代码肯定是一样的,因为A xor B xor B = A上边的汇编的核心代码换成C++大概就是:AnsiString __fastcall Encrypt(AnsiString str){ String sn = ""; for(int i=1; i<9; i++) { sn.cat_sprintf("%c", str[i]^((char)i) ); } return sn;}如果函数入口的str存放的是C盘序列号,那么返回的就是注册码,反之如果函数入口的str存放的事注册码,那么返回的就是C盘序列号。所以最后发现注册码的算法仅仅是将C盘序列号的每一个字符和自己在字符串中的偏移量进行了异或运算,要制作注册机的话,,使用上面那个函数就足够了 本文章原创来源:http://www.hackwd.com/

Tags:[db:关键词]

作者:Hacker

文章评论评论内容只代表网友观点,与本站立场无关!

   评论摘要(共 0 条,得分 0 分,平均 0 分) 查看完整评论
关于本站 - 网站帮助 - 广告合作 - 下载声明 - 友情连接- 网站地图
Copyright © 2015-2016 Hackwd.Com. All Rights Reserved .
本站内容来源网络收集,仅供用于黑客技术安全学习参考,请遵守相关法律法规
打造国内最大的黑客技术资源免费发布站
提供最权威的黑客攻防教程,黑客安全工具
免费黑客网-黑客技术,黑客工具,黑客联盟,黑客基地,黑客网站,黑客论坛