软件保护和反编译 - 起点信息
软件保护和反编译软件作为一种新的破解方法
引言
本文是为初学者开发者准备的快速入门通用信息,旨在让他们了解他们的软件可能如何被破解,以及应该避免哪些方法。
软件锁定方法
- 固定序列号:在此方法中,软件会在安装或首次运行时要求输入序列号。序列号可以轻松分发。事实上,序列号只是为了告知用户这不是免费软件,他应该购买它。
- 激活码:在此方法中,软件会生成一个机器 ID,并要求用户提供激活码,该激活码可从供应商处获取。软件破解可以通过调试器或部分反编译进行。
- 网络激活:与激活码相同,但激活会通过互联网运行。破解可以通过注入错误的 hosts 文件条目将激活页面重定向到本地或错误的页面,甚至可以通过自定义 DNS 转发器来完成。
- 加密锁:提供商会提供一个可以被软件检测到的小硬件设备。加密锁包含用于特定版本或软件的信息。破解可以通过破解软件与加密锁之间的通信库来完成。
- 受保护的光盘:安装只能从原始受保护的光盘运行,该光盘可能通过激光生成坏扇区或某些无效内容,或在光盘结束标记后写入数据进行保护。破解可以通过使用特殊程序复制光盘或破解安装过程来完成。
- 闪存 U 盘:软件可能会使用闪存的物理序列号并与数据库进行比较,然后才运行,或者将部分软件代码写入闪存盘的未分配区域。破解可以通过破解软件来完成。
- 售后支持:一些软件供应商提供非常好的支持,因此买家不会试图获取破解软件。
- 直接安装方法:一些供应商会通过开发公司员工直接安装软件,而不分发安装程序。
软件破解
这是对软件的修改,以移除或禁用被认为是不受欢迎的功能,特别是
- 禁用复制保护功能
- 移除未注册用户的限制使用
- 禁用与软件关联的广告软件,供未注册用户使用
破解可能通过以下方式完成:
- 重新分发序列号,
- 注册机,
- 补丁,
- 加载器。
最常见的软件破解是通过修改应用程序的二进制文件来导致或阻止程序特定部分的执行。这是通过逆向工程实现的。这可以通过以下方式完成:
- 使用调试器运行程序代码,直到软件破解者到达包含软件主要保护方法的子程序。
- 反汇编或反编译可执行文件。
- 有时破解是通过监视安装和应用程序首次运行时进行的注册表或文件系统更改来完成的。
软件开发人员不断开发各种技术,如代码混淆、加密和自修改代码,以增加破解的难度。
汇编破解
反汇编
- 反汇编是一种逆向工程。
- 反汇编是将程序的可执行(即时运行)形式转换为汇编语言。
- 汇编语言是人类可读的。
- 用于完成此任务的程序称为反汇编器。
- 另一个称为反编译器的程序会将目标代码转换回高级语言代码。
汇编语言
- 汇编语言是为可编程设备设计的低级编程语言。
- 用汇编语言编写的程序包含一系列(助记符)处理器指令以及元语句、注释和数据。
- 汇编语言指令通常由操作码助记符后跟数据列表组成。
汇编语言示例
; This program displays "Hello, World!" in a windows message box and then quits.
;
; Written by Stewart Moss - May 2006
;
; Assemble using TASM 5.0 and TLINK32
.486p
.model flat,STDCALL
include win32.inc
extrn MessageBoxA:PROC
extrn ExitProcess:PROC
.data
HelloWorld db "Hello, world!",0
msgTitle db "Hello world program",0
.code
Start:
push MB_ICONQUESTION + MB_APPLMODAL + MB_OK
push offset msgTitle
push offset HelloWorld
push 0
call MessageBoxA
push 0
call ExitProcess
ends
end Start
汇编控制流与破解
最常用的破解技术是:
- 运行调试器,例如 OllyDbg
- 在调试器中打开应用程序并运行它
- 记下应用程序结束前的最后一个跳转。
- 修改感兴趣的跳转函数。
修改代码可以通过以下方式完成:
- 反转跳转条件。例如:将 Ja 转换为 Jna。
- 将跳转代码更改为 Nops 的数量。例如:在调试器中指定代码,右键单击并选择“填充为”。
- 将条件跳转更改为相同长度的无条件跳转。
汇编指令链接
汇编无条件跳转指令
函数 | 操作码 | 十六进制 |
创建堆栈帧 | 回车 | C8 i0 i1 i0 |
停止处理器 | hlt | F4 |
销毁当前堆栈 | leave | C9 |
下一个指令的锁定前缀 | lock | F0 |
等待 FPU 完成其最后一次计算。 | wait | 9B |
跳转 sl | Jmp | EB r0 |
JMP np | Jmp | E9 o0 o1 |
JMP rmw | Jmp | FF /4 d0 d1 |
JMP DWORD PTR [rmw] | Jmp | FF /5 d0 d1 |
JMP FAR PTR fp | Jmp | EA o0 o1 s0 s1 |
CALL np | 呼叫 | E8 o0 o1 |
CALL rw | 呼叫 | FF /2 d0 d1 |
CALL DWORD PTR[rw] | 呼叫 | FF /3 d0 d1 |
CALL FAR PTR fp | 呼叫 | 9A o0 o1 sl sh |
RET | Ret | C3 |
RET iw | Ret | C2 i0 i1 |
RETF | Ret | CB |
RETF iw | Ret | CA i0 i1 |
条件跳转
函数 | 操作码 | 十六进制 2字节地址 | 十六进制 1字节地址 |
如果大于,无符号比较 | Ja | 0F 87 r0 r1 | 77 r0 |
如果不大于 | Jna | 0f 86 r0 r1 | 76 r0 |
如果大于或等于,无符号比较 | Jae | 0F 83 r0 r1 | 73 r0 |
如果不大于或等于 | Jnae | 0f 82 r0 r1 | 72 r0 |
如果小于,无符号比较 | Jb | 0f 82 r0 r1 | 72 r0 |
如果不小于,无符号比较 | Jnb | 0F 83 r0 r1 | 73 r0 |
如果小于或等于,无符号比较 | Jbe | 0F 86 r0 r1 | 76 r0 |
如果不小于或等于,无符号比较 | Jnbe | 0f 87 r0 r1 | 77 r0 |
如果相等 | Je | 0f 84 r0 r1 | 74 r0 |
如果不相等 | Jne | 0f 85 r0 r1 | 75 r0 |
如果大于 | Jg | 0f 8f r0 r1 | 7F r0 |
如果不大于 | Jng | 0f 8e r0 r1 | 7E r0 |
如果大于或等于 | Jge | 0f 8d r0 r1 | 7D r0 |
如果不大于或等于 | Jnge | 0f 8c r0 r1 | 7C r0 |
如果小于 | Jl | 0f 8c r0 r1 | 7C r0 |
如果不小于 | Jnl | 0f 8d r0 r1 | 7D r0 |
如果小于或等于 | Jle | 0f 8e r0 r1 | 7E r0 |
如果 (!(小于或等于)) | Jnle | 0f 8f r0 r1 | 7F r0 |
如果溢出 | Jo | 0F 80 r0 r1 | 70 r0 |
如果不溢出 | Jno | 0F 81 r0 r1 | 71 r0 |
如果为符号位 | Js | 0F 88 r0 r1 | 78 r0 |
如果不是符号位 | Jns | 0F 89 r0 r1 | 79 r0 |
如果为零 | Jz | 0F 84 r0 r1 | 74 r0 |
如果不为零 | Jnz | 0F 85 r0 r1 | 75 r0 |
循环 | loop | / | E2 r0 |
循环(如果相等) | loope | / | E1 r0 |
循环(如果不相等) | loopne | / | E0 r0 |
循环(如果为零) | loopz | / | E1 r0 |
循环(如果不为零) | loopnz | / | E0 r0 |
反编译
- 反编译是将可执行(即时运行)程序代码转换为某种形式的高级编程语言。
- 生成的代码可以被人阅读。
- 反编译是一种逆向工程,它执行与编译器相反的操作。
- 完成此任务的工具称为反编译器。
- 一个类似的工具,称为反汇编器,会将目标代码翻译成汇编语言。
- 反编译最初在 20 世纪 60 年代用于促进程序从一个平台迁移到另一个平台。
- 反编译并非总是成功的。
- 反编译有时被不道德地使用,以在未经版权所有人许可的情况下重用或改编源代码。
- 程序可以通过混淆等保护手段设计成抗反编译。
反编译和反汇编的其他用途
- 理解程序,
- 恢复源代码以进行归档或更新,
- 查找病毒,
- 调试程序,
- 翻译过时代码。
反编译失败原因
- 并非所有程序都可以反编译,
- 数据和代码难以区分,
- 在大多数当前计算机系统中,数据和代码的表示方式相似。
- 程序员给变量和函数起的有意义的名称(以便于识别)并不总是存储在可执行文件中,因此它们并不总是能在反编译中恢复。
将反编译作为破解方法
- 虽然反汇编器作为一种破解方法而闻名,但反编译功能更强大。
- 反汇编器通常会攻击正在系统上运行的程序。
- 反编译主要针对未运行的应用程序,它可以覆盖整个应用程序。
- 它会将程序转换为其自身的编程语言。
- 生成的代码易于编辑和修补。
- 破解者会搜索您的应用程序可能显示的错误消息,其中包含注册或激活代码。
- 然后他们会搜索使用此字符串的代码,尝试理解它并按需进行编辑。
- 反编译比其他破解方法耗时更多,但结果更灵活。
防止解锁代码
糟糕的保护代码
直接输入比较
If input_serial_nimber = real_serial_number Then
Unlock
Else
MsgBox("Wrong serial number")
End if
绕过此代码
- 运行调试器,例如 OllyDbg
- 在调试器中打开要破解的程序
- 运行代码直到要求输入序列号。
- 输入错误的序列号
- 逐行执行代码,直到找到处理您输入的序列号的汇编比较代码。
- 反转比较
软件调试防护
许多新软件都具备调试器检测技术,如果检测到调试器,它们会以不同的方式响应。调试器是破解最常用的技术;许多破解者不会尝试反编译您的代码。添加反调试代码可以增强您的软件保护,即使您不想使用混淆。结合混淆和调试防护效果更好。许多破解者在调试之前会进行反编译。如果没有混淆,他们可以跳转到代码中的其他位置来绕过调试器检查。
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
static extern bool CheckRemoteDebuggerPresent(IntPtr hProcess, ref bool isDebuggerPresent);
public static void Test()
{
bool isDebuggerPresent = false;
CheckRemoteDebuggerPresent(Process.GetCurrentProcess().Handle, ref isDebuggerPresent);
//if isDebuggerPresent then do something or raise an error
}
软件打包
许多软件会将软件代码打包成特殊格式,应用程序会在内存中解包代码以防止反编译或调试。破解者会先解包软件,然后在内存中进行调试或反编译。
混淆(已编译代码混淆)
混淆方法
- 您像往常一样开发应用程序。
- 运行和调试您的应用程序
- 使用编译器进行构建
- 运行一个编译后工具,将可再发行版本转换为混淆模式。
混淆目的
- 它使得反编译困难,并且许多反编译器将无法反编译应用程序。
- 许多反编译器将拒绝完全反编译此文件。要做到这一点。
- 如果反编译器成功,生成的代码将更难理解或分析。
混淆可以应用于以下一个或多个方面:
- 名称混淆
- 这将删除 EXE 文件中所有函数、窗体、模块、对象以及各种签名的名称。
- 新名称将是随机的,并包含在编程语言中无法使用的不可打印字符和符号。
- 字符串加密
- 控制流混淆是通过修改程序,使其运行时产生相同的结果,但流不同,以防止反编译成结构良好的源代码。
- 代码加密和添加您的代码加载器。加载器将在需要时解密 MSIL。
- 代码虚拟化将您的 MSIL 代码转换为只有混淆器添加到您的代码中的虚拟机才能理解的虚拟操作码。如果使用不当,代码虚拟化会显著降低性能。
- 有关更多信息,请参阅 .NET 混淆器列表。
- 有关已编译的非 .Net 代码(例如 C++)的混淆器,请参阅 x86 汇编器混淆器。
- 请参阅 混淆 (软件)。
混淆后反编译代码的示例
loc_B6FE91: MemVar_F903A0 = &HFF
If (MemVar_F9039E = &HFF) Then 'B70001
If MemVar_F903A0 Then 'B6FFDD
loc_B6FFD5: Function_A15FF8()
loc_B6FFDA: GoTo loc_B70001
End If
If Not(Function_A83D7C(1)) Then 'B70001
loc_B6FFED: Function_ADC870(0)
If arg_8(206) Then 'B6FFFF
loc_B6FFFA: Function_B07AC8()
End If
loc_B6FFFF: End 'Application End
End If
loc_B70001: ' Referenced from: B6FFDA
End If
- 破解者会查看代码,并看到应用程序结束代码,这可能表明测试解锁。
- 破解者尝试修改代码,将地址 loc_B6FFFF 处的 End 替换为 nop。
- 其中一个 if 语句可能会被更改以避免应用程序结束。
- 反编译器将为变量和函数生成随机名称,因为混淆在名称中放置了不可打印字符。
混淆与解锁软件
- 良好的混淆会使许多反编译器无法反编译您的代码,但强大的反编译器仍能反编译它。
- 反编译后的代码将难以理解和分析,并且可能需要非常努力才能理解如何解锁您的应用程序。
- 良好的混淆使得解锁代码的成本远远高于购买。
源代码混淆
- 许多开发者称之为“不切实际的混淆”,因为它处理的是源代码而不是已编译的代码。
- 一些提供跨平台软件的公司倾向于以混淆的源代码形式发布软件,并期望客户在他们选择的任何平台上构建该软件。
- 某些语言没有编译器,您的应用程序将以源代码形式发布,例如 PHP 和 Javascript。
- 混淆器使源代码难以理解。
Stunnix Obfuscator 是源代码混淆的一个例子,它将执行以下操作:
- 将符号名称替换为无意义的名称,例如将 list_of_customers 替换为 zcadaa4fc81。
- 将数字常量替换为表达式,例如将 232 替换为 (0x14b6+2119-0x1c15)。
- 将字符串中的字符替换为其十六进制转义,例如将字符串 "cust" 转换为 "\x63\x75\x73\x74"。
- 独特!重命名源代码文件和目录,例如将 /lib/context.c 重命名为 /7a84b51/b4e8c5.c。
- 删除或混淆注释。
- 删除代码行中的空格和制表符。
- 将所有代码行合并。
- 他们有针对 C++、Javascript、VB Script 和 Prel 的独立混淆器。
C++ 混淆代码
main( argc, char * argv[ ] )
{
int j;
char version[ 80] ;
while ( ( j = getopt_helper( argc, argv, "n:o:vV:",
((char)(0x10b4+390-0x11d2)), ((char)(0xeb+9378-0x2537))) ) != - 1) {
switch ( j) {
case ((char)(0x607+6157-0x1da6)):
name_wide = MYMIN( atoi( optarg) , 0xff) ;
break;
}
PHP 混淆器
使用哪些工具来检查我们软件的破解能力?
- OllyDbg:它是一款用于 Microsoft Windows 的 32 位汇编器级别分析调试器。
- Softice:它允许在外部应用程序运行时逐行调试代码。
- WDASM32:WDASM32 是一款反汇编器,它接收机器语言并将其翻译成汇编语言。
- IDA 是一款托管于 Windows、Linux 或 Mac OS X 的多处理器反汇编器。
- 十六进制编辑器:h:十六进制编辑器。
- RegMon:Windows 注册表监视器。
- FileMon:文件系统监视器。
- Net Mon 用于网络和互联网监视。
- VB 反编译器
- Jetbrains de-compiler 适用于 .net,
- C-Decompiler
- Boomerang:开源 C 反编译器。
- RetDec 是一款开源机器代码反编译器。
- ExeToC Decompiler
- Snowman 是一款原生代码到 C/C++ 的反编译器,支持 ARM、x86 和 x86-64 架构。
如何保护我的软件?
- 将您的应用程序构建为 64 位应用程序,64 位应用程序更难破解。
- 加密错误消息:例如,请参阅此 链接。
- 使用调试器检测技术:请参阅此 链接。
- 使用计算机 ID:这是一个简单的软件密钥,用于识别用户计算机,以便为每台计算机提供单独的许可证,请参阅:C++ 简单的软件密钥。
- 使用混淆,可以删除 EXE 文件中所有函数、窗体、模块、对象以及各种签名的名称。它将使使用此反编译器分析程序变得困难,并且许多反编译器将拒绝完全反编译此文件。要做到这一点,请参阅 Eazfuscator.NET。
- 为您的程序集 进行强命名:通过为程序集进行强命名,您可以确保程序集自构建以来未被篡改。
- lARP64Pro:这是一款 64 位防盗版和反破解程序,具有代码压缩功能,使得反编译更加困难。
- Soft Activate:它提供通过许可证密钥和软件激活进行保护的工具。
- 加密锁并非总是正确的选择,它可能会增加被破解的可能性。
- 尝试破解您的软件。
- 在网上搜索您软件的破解版,并要求搜索引擎删除搜索结果。
- 让检查逻辑在许多关键时间点(不仅仅是启动时)运行,并使用不同的方式。
- 让检查逻辑在某些检查中反转条件,而在另一些检查中直接执行。
- 以不同的方式执行检查。
- 某些检查仅在每周的特定日期执行。然后会告诉他们联系支持部门。
- 当您检测到许可证失败时,每次以不同的方式关闭应用程序,您可以直接关闭、应用程序退出、引发错误使应用程序崩溃,甚至进入无限循环以使您的应用程序不稳定。
- 最后,我们将修改 EXE 本身,所以在实际 EXE 的末尾存储文件的哈希值,并在运行时检查 EXE 文件是否被修改。
- 如果您有任何其他想法,请在评论中提出,我将修改文章以包含它。
为什么破解者攻击某些软件而放过另一些?
- 破解并非总是为了金钱,它可能是一种挑战或惩罚。
- 如果您有破解您软件的人的联系电子邮件;礼貌地写一封消息询问他们是否可以停止破解您的软件。他们可能会这样做。
- 如果软件声称难以破解,那么 破解者 就会攻击它,通常其中一个人会成功。
- 如果您设置了过高的价格,或者设置了隐藏费用,或者要求用户为格式化硬盘支付新许可证,或者有任何不良做法;那么您的软件可能会因惩罚而被攻击。
注意
请评论您希望我添加到文章中的任何有用数据。