前言
本篇收集整理常见native保护措施,并有一定实践。
尚未完成,持续更新
阻止静态分析
so整体加密
目标:so整体加密,不落地&落地加密、内存解密加载
实现:自定义linker实现
段加密
目的:加密部分so
原理:加载时使用的是头表,因此节头表很多无用的部分,可以用来变形并添加自己的信息。
将任意部分加密后运行时获取信息解密即可
函数加密,运行时解密
目标:加密指定函数
原理:通过符号表定位函数位置、大小。加密即可。解密时可以直接使用函数名当指针解密。
elf加壳
目的:对elf加壳
实现:
常见的有UPX:https://github.com/upx/upx 可以自己修改源码,同时可以压缩elf大小
花指令
目标:干扰反编译器的自动分析
原理:针对常见反汇编算法,手动构造容易引起误会的汇编代码。
实现:
hook更改流程
目的:动态改变执行流程
原理:通过hook要运行的函数,改变程序流程,使程序以不同于静态分析结果。
实现:
如inline hook下Jni_OnLoad实现解密等操作。
混淆
目的:替换等价汇编指令为难以分析的指令
原理:花指令、指令乱序、指令替换、llvm
阻止动态调试
干扰动态调试过程,有效增加逆向成本
基于时间的检测
目的:进程自我检测一定区域的断点调试
原理:通过在一段代码区间获取时间值,如果时间相差过大,则可能是有断点在调试。检测退出时机为区间最后时间判断时,当该区域没有断点时不会退出。
实现:
基于文件的检测
目的:通过系统信息检测是否被调试
原理:查看系统特定文件的信息,获取调试信息
/proc/pid/status 和 /proc/pid/task/pid/status:普通状态下,TracerPid这项应该为0;调试状态下为调试进程的PID。
/proc/pid/stat 和 /proc/pid/task/pid/stat:cpu活跃信息;调试状态下,括号后面的第一个字母应该为t。表示traced状态(追踪)
/proc/pid/wchan 和 /proc/pid/task/pid/wchan:当进程sleep时,kernel当前运行的函数;调试状态下,里面内容为ptrace_stop。
实现:
针对常见调试器检测
目的:干扰常用调试器调试
原理:通过检测常用调试器痕迹,进行反调试。如
程序-android_server,gdb,gdbserver
端口-23946等,信息来源可以是/proc/net/tcp
虚拟机内部相关字段
目的:通过虚拟机信息判断调试
原理:虚拟机保存了是否被调试的相关数据。
实现:
ptrace
目的:阻止调试器附加
原理:linux下的调试是使用ptrace(跟踪)调用,linux每个进程只能被一个跟踪,因此可以先ptrace自己阻止附加。
实现:
断点扫描
目的:直接查找断点的存在
原理:调试器原理是向断点处插入断点汇编指令,触发断点进行系统调用,调试器获得控制权从而处理。此方法暴力查找断点
实现:
信号处理
目的:干扰调试过程中的信号处理
原理:断点指令使被调试进程发出信号SIGTRAP,传递到要处理的地方,通常调试器会截获Linux系统内给被调试进程的各种信号,由调试者可选地传递给被调试进程。但是SIGTRAP是个例外,因为通常的目标程序中不会出现breakpoint,因为这会使得程序自己奔溃。SIGTRAP会被认为是调试器自己设置的-这样会造成不同的错误
在信号处理中处理解密逻辑,此处难以调试
实现:
调试器的错误理解
目的:干扰调试器对汇编指令的解析
原理:Thumb-2模式是Thumb16和Thumb32指令的混合执行,切换依靠跳转时的地址数值,可动态确定。因此难以被判断。
不过ida可手动改分析的汇编指令集
守护进程/线程
目的:时时反调试检测
原理:启动守护进程/线程,相互检测调试,相互检测存活。
设计良好的话反调试效果明显
实现:
防止hook
防止注入
VMP
其它针对性措施
检测frida
fridaserver:进程列表、tcp端口检测
检测注入:检测加载的so中是否有frida特征的