逆向学习入门

一、逆向工具

1.反汇编反编译工具
IDA pro(Hex-Ray) 绝大部分指令集架构
dnspy(.net/C#)
JADX、GDA、JEB(APK、andriod)
Jd-gui (java)
python字节码(uncomply6反编译,pyc、网上在线的反编译工具https:tool.lu/pyc/,pyinstaller打包:https://github.com/Ravensss/pyintxtractor)
Lua(luadec反编译)
Go(GoalangHelper插件反编译)
2.调试工具
Olldbg、X64dbg(x86、x64、window)
GDB(x86、x64、linux/ iot,需要对应交叉编译
Frida(andriod、windows、linux…)使用Javascript编写脚本
3.Trace类工具
GDB脚本
Dynamino插件
unicorn
Pin插件
OD脚本
IDA脚本
自己写的调试器trace
Qira

4.常用库工具
Z3(约束求解)
Angr(约束求解)
PyDBG(windows调试器python版本)
Triton(基于pin)

二.逆向分析流程

一个可执行程序(Windows图形化界面程序、linux的静态编译程序)中汇编带代码量庞大。
分析步骤:
1.定位出真正需要分析的关键代码。
2.需要对管家代码采用的算法进行分析
3.理清程序功能
4.写出对应脚本,求解出flag

关键代码定位
1.字符串定位法:
OD的字符串搜索
2.函数定位法:
Window(API):GetWindowText、GetDlgltemText、MessageBox、Send、Recv、LoadLibray、VirtualAlloc…
Linux(静态编译):函数库签名、syscall…
Andiord:导入包的关键函数、OKHTTP类、Crypto类…

梳理程序功能
提升代码可读性
梳理程序逻辑
识别各个算法(正向实现、逆向推演)
加密、压缩
常规算法
自定义算法
Flag求解
1.内存获取法
2.算法逆变换
2.线性变换
3.约束求解
5.测信道求解

三、逆向分析方法

逆向还原源码信息:符号信息、数据结构,有助于分析程序原有逻辑和功能。
静态分析 动态分析

静态分析方法
优点:
分析速度快
全局视野好
关联性好
可重命名、便于保存、多次分析、方便共享
缺点:
混淆加固干扰
执行流程不明确
范围太大不好聚焦
数据不真实(没有数据支撑)

动态分析
优点:
执行流程明确
能看到具体数值
数据信息更丰富
缺点:
分析速度慢
不好关联(可以与IDA联动,但效果一般)
分析视角太小,容易走偏

动静结合
主要思路:
(1).优先使用静态分析
(2).动态分析辅助
(3).正向开发思维(程序设计、算法、游戏相结合)
数独、扫雷、连连看、魔方等等
宗旨:静态分析、动态验证

四、主流算法

CTF常见算法包括:
1.base64、TEA、AES、RC4、MD5等算法及其变种
XXTea(较少)、SHA1(较少)、SHA256(较少)
1.base64以及变种
base64主要是将输入每3个字节(共24比特),每6个比特一组,变成一个索引表小于64的索引值,然后通过一个索引表得到4个可见字符
ABCDEFGHIJKLMNOPQRSTUVWXYZabcefghijklmnopqrstuvwxyz0123456789/=
变表
2.TEA、TEA变种、XXTEA
TEA算法是一个常见的分组加密算法,密钥为128比特位,明文为64比特位,主要做了32轮变换。每轮变换中涉及到移位和变换。
TEA算法中有一个基本固定的常数0x9e3779b9或者0x6886471c
3.AES
加密过程涉及4种操作:
字节替代(SubBytes)
行移位(ShiftRows)
列混淆(MixColumns)
轮密钥(AddRoundKey)
标准S盒
0x63,0x7C,0x77,…
标准逆S盒
0向2,0x09,0x6A,…
4.RC4
流加密算法
初始化函数、加解密函数
5.MD5
消息摘要算法
密码散列函数
可产生出一个128位(16字节)的散列值,用于确保信息传输完整一致
MD5_CTX md5c;
MD5lnit(&md5c);
MD5UpdaterString(&md5c, plain);
MD5Final(digest,&md5c);
6.MD5、Sha1、Sha256
这些消息摘要算法可以根据输出长度来区分。

五、自动化分析

辅助分析,较多使用python开发
python逆向工具详见http://pythonarsenal.com/
常用工具
1.IDApython
详细可看文档
能调用的接口位于idaapi、idautils和idc三个模块中
2.Angr
常见Angr脚本包括以下几个步骤:
1.使用angr.Project加载要分析的二进制程序,这里通常会将选项auto_load_libs设置为false使angr不加载动态链接库。
p = angr.Project(’./vul’,load_options={“auto_load_libs”:False})
2、建立程序的一个初始化状态。
使用factory.entry_state 直接在程序入口点建立个初始化状态。 如果此时程序需要传递符号化得输入, 也需要在建立初始化状态时,进行符号化。
argv1 = claripy.BVS(“argv1”,100 * 8)
initial_state = p.factory.entry_state(args=["./program", argv1])
也可以使用factory.black_state在程序的任意指定地址建立一个状态。此时,可以通过memory.store将状态中的部分内存进行符号化。
s = p.factory.blank_state(addr=0x401084)
s.memory.store(0x402159,s.solver.BVS(“ans”,8*40))
3.从初始化状态开始,进行动态符号执行,使用explore进行路 径的探索,通过find参数指定需要到达的地址avoid指定不要到达的地址。
sm = proj.factory.simulation_manager(initial_state)
sm.explore(find=0x400830, avoid=0x400850)
4.探索找到之后,通过约束求解器得到flag。
found = sm.found[0]
flag = found.solvereval(argv1,cast_to=bytes)
3.PythonGDB
PythonGdb使我们可以通过python脚本来编写gdb调试脚本。
详细的文档参见https://sourceware.org/gdb/wiki/PythonGdbTutorial
peda就是用PythonGdb编写的。

5.PyGDB(pwnhub,tvmc)

六、反逆向技术及破解

常规技术:画质零、反调试、加壳、控制流混淆、双进程保护、虚拟机保护等技术。
1.花指令
代码保护技巧之一
原理是再原始代码中插入一段无用的或者你网购干扰反汇编引擎的代码,无任何功能性作用,只是作为扰乱代码分析的手段
识别花指令模式,编写IDApython脚本对花指令自动化的搜索和Patch
2.反调试
反调试技术指在程序运行过程中探测是否处于被调试状态,如果发现被调试,则使程序无法正常运行。
Windows下的反调试方法有很多,比如使用一些API函数如lsDebuggerPresent检测调试器,使用SEH异常处理,时间差检测等方法。也可以通过覆写调试端口、自调试等方法进行保护。
网上有很多文章对其进行了总结,在Windows 下通过OD的StringOD插件可以过掉大多数的反调试方法。
Linux下的反调试:
(1) ptrace检测。一个进程只能被一个程序跟踪,所以如果程序被跟踪了再调用ptrace(PTRACE_ TRACEM)自然会不成功。
(2) proc文件系统检测。/pocs/s/tus在非调试状态下FTracerpid为0,而在处于调试状态下时,TracePid不为而为跟踪进程的Pid号。
(3)父进程检测:通过getppid系统调用获取得到程序的父进程,父进程是gdb、strace或者Itrace,则证明正在被调试。
Andriod下的反调试:
(1) Xposed检测。函数调用信息,包名、进程名。(2) Root检测。su文件、release信息等
(3) Frida检测。函数调用栈、进程名、端口信息。
识别并hook即可。
3.加壳
壳一般会在在二进制程序中植入-段代码, 在运行的时候优先取得程序的控制权,这段代码在执行的过程中对原始的指令进行解密还原,之后再把控制权交还给原始代码,执行原来的代码。
unpack-> execute
直接将程序代码全部解压到内存中再继续执行程序代码
unpack-> execute-> unpack-> execute …
解压部分代码,再边解压边执行
unpack->[decoder | encoded code]-> decode-> execute
程序代码有过编码,在解压后再运行函数将真正的程序代码解码执行
脱壳技术:单步调试法、ESP定律、内存DUMP、IAT修复…
CTF中出现的可通常为已知的壳,因此大多可以使用专用工具或者脚本本来进行脱壳。
比如UPX壳,可以通过UPX -d命令进行脱壳
4.控制流混淆
控制流混淆的技术有多利:
1、OLLVM (最常用的)
2、自定义分发:
基于父子进程修改的混淆
基于sysal的混淆

针对OLLVM混淆,目前有一些去混淆的技术(可以搜到“利用符号执行去除控制流平坦化”),方便F5。
自行开发去除OLLVM的脚本
有的没有办法直接进行静态分析,无法进行反编译。而调试器调试也会陷入到控制流的跳转混乱中。
可以采用Trace的方法。
通过Trace工具记录下程序运行的所有指令,然后在这些运行指令的基础上进行数据流分析。常用的Trace方法可以使用Ptrace的单步执行记录下运行的每一条指令的地址,也可以使用动态二进制插桩工具,如Pin来进行记录。
5.双进程保护
双进程保护又称为Debug blocker,是一种在调试模式下运行自身程序的方法。这种保护通常存在两个进程,它们是调试器与被调试器的关系。
1.防止代码调试。通常实际功能的代码运行在子进程中,不过因为子进程已经处于调试状态了,所以无法再使用其他调试器进行附加操作。
2.父进程能够控制子进程,通过处理子进程的异常,控制子进程的代码执行流程或者对子进程修改动态修改。
CTF中的双进程保护题目通常父进程的功能比较单一
1.首先针对父进程进行分,分析清楚其处理子进程的逻辑,然后对子进程进行Patch,使子进程脱离主进程也能正常运行
2.再对子进程进行分析
6.虚拟机保护(VMCode)
虚拟机保护技术,是指将代码翻译为机器和人都无法识别的一串伪代码字节流:在具体执行时再对这些伪代码进行翻译解释,逐步还原为原始代码并执行。
这段用于翻译伪代码并负贵具体执行的子程序就叫作虚拟机VM(好似一个抽象的CPU)。它以一个函数的形式存在,函数的参数就是字节码的内存地址。
像一些商用的保护软件,如Vmprotect, themida等, 都是采用了虚拟机保护技术。
在CTF中也出现过多次虚拟机保护的程序,不过相对来说虚拟机的指令集较少,因此可以在有限的时间内分析出来。
根据指令集写反编译器,反编译代码
2015 zctf simulator
2016 hctf ASM
2019 qwb debugVM
2021 qwd vmnote

七、VMP部分内容介绍

VMP(VMProtect):虚拟机保护软件,是目前最为流行的保护壳之一。
加壳方式:修改源码或者目标机器码
转换原理:语义等价的虚拟机字节码
运行模式:VMP创建的虚拟环境
常见的虚拟机加壳软件
1、The Enigma Protector
2、Safengine
3、Themida
4、Vmprotect
基本特性:反调试、反跟踪、反附加调试、反内存转储、反APIT挂钩、文件自效验、加密代码和数据、多态代码生成、代码乱序变形混淆、代码虚拟化…
虚拟机保护技术:
将系统的可执行代码转换为字节码系统的代码,以达到保护原有指令不被轻易逆向和篡改的日的。
其中:
字节码指令系统和原有指令系统不在同一个层次中。
字节码指令系统->解释指令执行
原有指令系统-> CPU执行
主流动态语言的虚拟机模式:
Stack- Based模式
Register- Based模式
其中:
VMP属于Stack-Bascd模式
其指令并是先将参数压入堆栈,然后直接从堆栈中读取,如下:
原汇编指令: add eax, ecx
VMP会将汇编指令拆分成右值操作数据(参数)、指令和左值操作数(结果),然后生成如下指令:
Push ecx
Push eax
VAdd
Pop EFL
Pop eax

VStartVM:真实环境->虚拟环境
VMDispatch:虚拟指令调度器
Handler:虚拟指令处理器
VCheckESP:堆栈基本块检查器虚拟环境->真实环境

VMP中的基础指令大体分五类:(1)堆栈操作(元指令)
vPush, vPop
(2)算术运算
vAdd, vShl, vShr, vDiv, vMul…
(3)内存操作
vReadMem, vWriteMem
(4)跳转指令
vJmp
(5)逻辑运算(*)
vNor,相当于and(not(a), not(b))

虚拟环境 VMContext VMContext即虚拟环境结构
struct VMContext {
DWORD v_eax;
DWORD v_ebx;
DWORD v_ecx;
DWORD v_edx;
DWORD v_esi;
DWORD v_edi;
DWORD v_ebp;
DWORD v_efl;
}
完美还原几乎是不可能的
add eax,eax
VPushReg4 VR0
VPushReg4 VR0
VAdd4
VPopReg4 VR1
VPopReg4 VR2

无法确定义映射的原始寄存器
FKVMP插件、xx-vm、zeus插件等等
常见的正针对虚拟机的检测方法
1.字符串
2.虚拟机配置(vmtools之类的、in指令)
3.使用专门配置好的虚拟机,如吾爱破解专用虚拟机
4.从程序入手,修改检测判定标志
VMP加壳程序分析方法:
1、暴力破解法修改特定指令
2、动静态结合分析分析法针对大规模程序
3、虚拟指令分析
没办法的情况下,必须分析虚拟指令

暴力破解法修改特定指令
硬件断点Hook法
实现一个简单的调试器程序,通过设置硬件断点等在程序运行到指定位置之后对代码进行修改再恢复执行。
DLL运行时Patch
利用外壳程序加载的DLL,利用其对关心的代码进行Patch,这种方式实现较为简单,但是需要目标程序DLL加载时关键代码未执行才能进行修改。

动静态结合分析分析法
针对目标:
非虚拟指令替换加壳,
针对大型软件适用
分析方法以及步骤:
1、确定附加时机
2、动态内存dump
3、混淆去除
4、API函数地址对应

猜你喜欢

转载自blog.csdn.net/weixin_51732593/article/details/120490844