前言
逆向分析在网络安全技术中算是较难一块的了,但其运用场景也及其丰富,不光是日常破解还是CTF竞赛都是不可获取的,但往往在拿到某一程序时会发现,开发者并不会简单的将他开发的程序任人摆布,还会加入一些干扰分析的技巧阻碍逆向工程师对其程序的逆向分析,下面是几种常见的干扰分析技术也是CTF竞赛中重要的考点!
花指令
花指令(junk code)程序代码的保护中算是最常见也是最基础的技巧了,在CTF中也是百出不厌,其原理为在代码中加入无用的以及能干扰反汇编引擎代码,加入的代码在整个程序代码中也只起着干扰分析的功能!说人话就是看似复杂实际并没有什么用的代码。
花指令的影响主体为静态分析,在逆向分析工具中会影响一些指令无法识别导致函数识别错误!例如:
在分析过程中可以手动吧patch改为nop空指令,或是通过分析此代码中花指令的特定模式编写自动化的搜索脚本进行patch。
反调试
反调试技术,顾名思义就是为了干扰逆向工程师进行调试所作的工作,其原理也非常简单,就是在程序运行时探测是否处于被调试状态,如果正在被调试,则无法正常运行!
常见的反调试技术的具体实现有:
修改标志位:通过改变进程环境块(PEB)中的标志位来检测是否被调试。例如,检查BeingDebugged
成员的值来判断进程是否正在调试。
进程和窗口检测:检测是否存在调试器进程或特定的窗口类名和标题。例如,通过遍历进程快照来查找调试器进程,或者使用FindWindow
函数查找与调试器相关的窗口。
断点检测:检测软件断点、硬件断点和内存断点。例如,通过检测代码中的0xCC
指令来判断是否存在软件断点。
代码校验和:对代码进行完整性校验,判断是否处于被调试状态。例如,使用CRC32算法或各种哈希算法来计算代码的校验和。
时间差异检测:在关键逻辑前后计算时间差异,如果超出正常范围则认为代码正在被调试。
Dalvik虚拟机内检测:利用Dalvik虚拟机自带的内部检测机制来识别调试器。
使用Windows API:调用特定的Windows API函数来检测调试器的存在,如IsDebuggerPresent
和CheckRemoteDebuggerPresent。
挂钩函数:通过挂钩特定的系统函数,使其返回未被调试时应有的值,从而绕过调试器的检测。
Inotify监控:在Linux系统中,使用inotify
机制监控文件系统事件,如读写操作,以检测调试器的痕迹。
过滤常见反调试的方法也很简单,OD中的StringOD插件,IDA,Ghidra,AntiDebug等等逆向工具都有相应的过滤方法。
加壳
加壳,加壳其实也可以从它的名字去理解它,就是对程序代码套上一层保护壳,而在代码层面这个保护壳就是加密,其原理是在二进制的代码中加入加壳代码,这段代码在程序运行时才会对其解密还原,并且将程序控制器交予原始代码,执行程序。
通俗来说就是真正的代码放在二进制文件中,只有在程序开始执行时才会从内存中解密还原出来执行。
常见的加壳方式有:
-
UPX:
-
UPX(Ultimate Packer for eXecutables)是一个广泛使用的开源压缩和加壳工具。它支持多种操作系统和处理器架构。
-
特点:高压缩率、快速解压缩、良好的兼容性。
-
Aspack:
-
Aspack是一款老牌的加壳工具,主要用于Windows平台。
-
特点:简单易用、压缩效果较好,但已被部分现代安全软件检测为恶意软件。
-
PECompact:
-
PECompact是一款功能强大的加壳工具,支持多种压缩算法和加密选项。
-
特点:高度可配置、支持多种保护选项、难以被检测。
-
CodeVirtualizer:
-
CodeVirtualizer是一款专注于代码虚拟化的加壳工具,可以将代码转换为虚拟机指令。
-
特点:高效的虚拟化技术、强大的反调试和反逆向工程保护、适用于各种编程语言。
-
x64dbg:
-
x64dbg是一款开源的调试器,虽然主要用于调试,但也常用于分析和去除某些简单的壳。
-
特点:开源免费、支持插件扩展、适用于x86和x64架构。
对于加壳程序是无法直接进行静态分析的,需要逆向者先进行“脱壳”操作,对于不同的加壳方式则有对应不同的脱壳方式,例如对于上述加壳方式1.UPX壳:
可以通过upx -d命令脱壳:
双进程保护
双进程保护(Debug Blocker),老规矩先从名字看起,顾名思义就是存在两个进程的保护方式,两个进程存在“调试”与“被调试”的关系,调试进程(主进程)是开发者主要防御逆向破解的手段,而被调试进程(子进程)就是实际的功能代码,也就是逆向者的目标,主程序能够处理子程序进程异常,控制子程序代码执行流程和对代码进行动态修改。
常见的双进程保护(Debug Blocker)方式:
-
进程互锁:在双进程中,一个进程负责执行主要功能,而另一个进程则负责监控和保护。如果主进程被终止或调试,监控进程会检测到这一行为并采取相应措施,如终止自身、删除关键文件或发送警报。
-
进程通信:双进程之间可以通过多种方式进行通信,如管道、消息队列、共享内存等。监控进程可以使用这些通信机制来接收主进程的状态信息,并根据这些信息做出决策。
-
反调试技术:监控进程可以实现各种反调试技术,如检测调试器的存在、处理调试事件、隐藏自身等。这些技术可以防止调试器附加到主进程或监控进程。
-
代码注入:监控进程可以将代码注入到主进程中,以实现更深层次的保护。这种方法可以提高保护的隐蔽性,因为注入的代码可以直接在主进程的地址空间中运行。
-
加密与解密:双进程保护中,可以将关键数据或代码进行加密,只有当两个进程都正常运行时,才能完成解密过程。这样,即使攻击者能够绕过一个进程的保护,也无法获取到完整的信息。
对于双进程保护的逆向,因为其子程序也就是被调试进程在运行时处于调试状态,所以这时也就不能再使用其他调试工具进行逆向调试了,对于双进程保护的逆向小伙伴们看到这里不知道有没有头绪,实际上,对于双进程保护的逆向我们需要从其程序特点入手,既然子程序在调试状态,所以我们只需断开主程序的调试器链接即可,重难点在是于如何解决切断调试器链接后的子进程无法工作问题!
控制流混淆
控制流混淆,先看名字!控制流结构代码的混淆,原理与其名字相似也就是通过改变程序的控制流结构去增大逆向工程的难度,对于有着控制流混淆程序代码的逆向通常是极其考验逆向者代码能力的,因为本质来说,开发者的目的就是混淆控制结构,让你分析不出来代码的控制作用及运行流程以此达到干扰分析的目的。
常见的控制流混淆方式:
-
代码重排:将代码块重新排序,使得程序的控制流看起来更加复杂和难以跟踪。这种方法可以打乱代码的执行顺序,使得线性分析变得更加困难。
-
插入无用代码:在程序中插入大量无用的代码或“垃圾代码”,这些代码不会影响程序的功能,但会增加逆向工程的难度。无用代码可以包括无效的函数调用、空循环等。
-
条件分支混淆:使用复杂的条件语句和嵌套的条件分支来混淆程序的控制流。例如,可以使用多个条件分支来替代简单的if-else结构,或者使用switch-case语句来替代连续的if-else链。
-
异常处理混淆:通过引入异常处理机制来混淆程序的控制流。例如,可以在正常的控制流中引入异常抛出和捕获机制,使得程序的控制流变得不直观。
-
虚拟化和解释器:将程序的核心逻辑转换为虚拟机指令或解释执行的代码,使得程序的控制流更加难以理解和分析。这种方法可以隐藏程序的实际逻辑,增加逆向工程的难度。
-
自修改代码:让程序在运行时动态修改自身的代码,使得静态分析变得更加困难。自修改代码可以通过解密、加密或直接修改内存中的指令来实现。
-
多线程和异步编程:通过引入多线程和异步编程来混淆程序的控制流。多线程和异步编程可以使程序的控制流变得复杂和难以预测,增加了逆向工程的难度。
-
函数指针和回调:使用函数指针和回调函数来动态改变程序的控制流。函数指针和回调函数可以让程序的控制流变得不固定和难以预测,增加了逆向工程的难度。
-
内联汇编和低级语言:使用内联汇编和低级语言来编写程序的关键部分,使得程序的控制流更加难以理解和分析。内联汇编和低级语言可以让程序的控制流变得不直观和难以预测,增加了逆向工程的难度。
-
符号混淆:通过改变变量名、函数名等符号来混淆程序的控制流。符号混淆可以让程序的控制流变得不直观和难以预测,增加了逆向工程的难度。
虚拟机保护
虚拟机保护(Virtual Machine Protection),这个就不能从名字看起了,虚拟机保护技术是将部分或全部程序代码去翻译为机器与逆向者都无法识别的伪代码,只有在程序运行时才会对这些伪代码进行逐个翻译,解密,还原为原代码执行,而虚拟机保护技术中的虚拟机就是指负责翻译与程序执行的子程序。
虚拟机保护(Virtual Machine Protection)的原理:
-
代码转换:将原始代码转换成自定义虚拟机的指令集。这些指令在标准的硬件或软件环境下无法直接执行,只能在特定的虚拟机环境中解释或执行。
-
虚拟机监控:自定义虚拟机充当代码执行的环境,负责解释或执行转换后的指令。它可能会实现一些额外的安全措施,比如检测调试行为、抵抗篡改等。
-
环境隔离:由于代码在定制的虚拟机中运行,与宿主系统的直接交互被限制或控制,这增加了从外部干预或分析代码的难度。
-
动态特性:某些高级虚拟机保护系统可能还会采用动态变换技术,比如每次运行时改变指令集或执行路径,使得静态分析和重复利用成为不可能。
原文始发于微信公众号(flower安全):一文看懂关于逆向中的干扰分析技术!
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论