IDA背后的原理入门(一):简介&函数识别

admin 2025-12-29 00:54:52 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 文章解析IDA反汇编器背后的原理,重点阐述从PE加载、汇编到高级IL的提升过程及函数识别技术。详细介绍了Windowsx64环境下通过扫描call/jmp指令、解析CFG保护、处理导入表及函数存根来识别函数的方法,并对比了自研工具与IDA、BinaryNinja的识别差异,最后指出编译器优化与虚表处理是识别难点。 综合评分: 88 文章分类: 逆向分析,二进制安全,安全工具,漏洞分析


cover_image

IDA背后的原理入门(一): 简介&函数识别

原创

为了安全鸭

冲鸭安全

2025年1月25日 10:00 北京

简介

在《2024年终: 木马病毒自动化特征提取&云端机器学习的思路分享》

2024年终: 木马病毒自动化特征提取&云端机器学习的思路分享 中我提到过

具体细节在明年2025年我会开一整个系列介绍实现,原理与思路,其实这种操作效果就是手写了一套IDA,但是比IDA更小,更可控。让我们回到正题,继续介绍模式匹配的具体用法

现在,2025年,让我们开始系统从头设计一个”IDA”,从基本原理入手,逐步变成可”一键F5”的工具。

免责声明: 我不是专业搞编译器的,整个过程的路线是能跑就行,要是有高手发现我写的有问题,评论区跟我说一下,我们一起探讨一下

原理

IDA识别到能一键F5实际上可以分为几个具体步骤(略有不同,IDA是微码, 不是IL):

  1. PE识别,导入表,导出表,TLS 等等
  2. 基于(1),进行函数识别,标记哪些位置是函数
  3. 基于(2),提升为 LLIL 也就是 low level IL,这个主要负责将 汇编 转为自己的通用翻译语言。这代表上层不需要关系汇编的架构什么的(比如,X64,MIPS,等等 转IL后都不需要关心了)
  4. 基于(3) 提升为MIDDLE LEVEL IL,而这个过程我们需要根据RSP/RBP 访问标记函数,解析符号,并且识别函数内容
  5. 基于(4) 做进一步优化,总而成为HIGHT LLIL。这一步后,就已经是IDA F5后的形状了

需要注意的是,这个过程并不是严格线性的。比如在LLIL提升过程中,可能会发现新的函数,这时需要回到第2步重新进行函数识别。整个过程是迭代式的,每一步都可能影响其他步骤。

我们以BN为例子:

  1. bn的汇编模式: 你可以看到,在这个阶段,bn只是显示纯汇编(虽然可能有一些标注)
  2. BN的llil模式: 这个时候,原来的汇编已经变成了BN的一种中间码,这样BN就能很愉快的处理各种乱七八糟的平台的汇编,比如ARM,mips等等 3.MLIL模式: 这个模式下的BN,在LLIL的基础上已经标识了 函数调用/函数参数/符号及代码做了优化
  3. HLIL模式与C语言模式: 这个时候,已经跟本来的C语言没什么区别了.可能没有C语言能导出去运行的功能而已,这个是C语言的

函数识别

初级函数识别

我们整个旅程的第一步,就是识别函数.如何做到在没符号识别函数是一个学问,我们不能太宽泛,就先假定目标是windows x64。

识别winx64的 函数 最基本的办法是遍历text段找call,我们可以遍历出 所有的 call imm指令以及JMP 指令,这些指令通常是一个函数. 基本代码如下: 其中call后就是我们识别的函数。 此外,msvc编译器编译出来的程序,会带cfg保护区段

CFG(Control Flow Guard)是微软推出的漏洞利用缓解机制,从Windows 8.1开始引入,并且需要编译器的支持,编译器的版本为Virtual Studio 2015 Updated 2版本以上。 在开启了CFG支持以后,编译生成exe程序中,所有间接调用前面都会插入一个_guard_check_icall的检查函数,如果系统不支持CFG机制,则该函数不会生效。

如下就是一个经典的例子:

eax,[esi]
ecx, eax
call _guard_check_icall  // CFG检查函数
call eax

_guard_check_icall函数的地址,在PE程序被系统加载的时候会被替换成nt!LdrpValidateUserCallTarget函数的地址 nt!LdrpValidateUserCallTarget函数的参数就是上面ecx的值,也就是间接调用的函数地址

校验逻辑如下:

1)间接调用函数地址共4字节,取高3字节的值加上CFGBitmap表的基址,得到CFGBitmap表中的值 2)判断间接调用地址是否0x10对齐: 2.1) 如果是对齐的,函数地址的第4-8位的值,就是上面获取的CFGBitmap表值的位偏移 2.2) 如果不是对齐的,函数地址的第4-8位的值,再或上1,得到的值就是CFGBitmap表值的位偏移 3)验证CFGBitmap表值的位偏移处的bit位,如果是1,则说明这个函数是有效的,否则产生异常

在PE结构的loadConfig信息中保存了:

1)_guard_check_icall的函数地址 2)CFGBitmap表的RVA,这里面是该程序的每个函数的RVA转换成1bit的值,制作成的一个CFGBitmap表 3)CFGBitmap中函数的数量

来源: https://blog.csdn.net/cssxn/article/details/101285088 因此我们也必须要识别是否是来自cfg控制区段的跳转,否则我们是没办法检测到函数的 基本代码如下:

值得注意的是,这个只是最基本的函数识别,这没办法处理其他情况,尤其是对于VT函数,我们应该需要搜索rdata去处理,除此之外,我们还需要从如下地方找:

  1. 暴力特征函数序言
  2. 异常处理表
  3. TLS回调
  4. 虚表/class

除了直接的call/jmp指令识别,我们还需要处理以下情况:

// 典型的间接跳转模式
mov rax, [some_address]
call rax

跳转表

// 常见于switch-case实现
jmp qword ptr [rax*8 + jump_table]

这些情况需要进行数据流分析才能准确识别目标函数。 一个完整的代码如下:

function symbol

ida的symbol有几种:

  1. 导入表
  2. 导出表
  3. lumina
  4. pdb
  5. ida sig

比如如下是基于导入表的符号识别:

而如下是基于lumina的识别 这是基于IDA sigs的函数识别 而我们先做简单一点,只识别导入/导出表

function stub

对于调试的程序你可以看到很多 function stub,这些都是指向真实函数,这方便调试,对于我们来说需要特殊处理这些.否则,背后跳转的函数我们会被忽略 而我们对其的处理可以粗暴一点,直接看是否是rip跳转

注意: 除了RIP相对寻址,function stub还有其他形式: 间接寻址

mov rax, gs:[60h] ; TEB
mov rax, [rax+...] ; 通过TEB间接寻址
jmp rax

导入表跳板

jmp cs:__imp_Function ; 通过导入表间接跳转

我们需要处理这些特殊情况,才能完整地识别所有函数。

效果

IDA寻找出了320个函数 我们寻找出了297个函数 而作为对比,BN是460

一个显而易见的事实是,各家算法不同,差异也就越大.比如我们是不看debug jmp table的,而bn和ida是看的。而BN和IDA通过模拟执行能发现我们目前无法发现的间接call,而通过crt sigs,能直接标记已知的函数.这些是我们暂时没有的

函数识别的难点与挑战

在基础函数识别之外,实际场景中还存在许多复杂情况需要处理: 编译器优化导致的函数识别困难

// 尾调用优化
void funcA() {
    return funcB();  // 编译器会直接优化为 jmp funcB
}

// 内联优化
inline void funcC() {
    // 函数体直接被插入调用处
}

反调试技术的影响 一些程序会使用特殊技术干扰函数识别:

// 花指令
push rax
jmp $+5
db 0xE8  // 假call指令
pop rax
// 真实代码继续...

虚函数表的处理 需要专门的算法来处理C++的虚函数表:

struct VTable {
    void* func1;
    void* func2;
};

class Base {
    virtual void vfunc() = 0;
    VTable* vtable;
};

改进的函数识别算法 我们可以通过以下方式提高函数识别的准确率:

  1. 启发式规则 检查函数序言模式(非仅prolog) 分析栈平衡情况 追踪寄存器使用模式
  2. 交叉引用
  3. 数据流分析

未完待续

下一章,我们将介绍如何做程序控制流识别,以及一些关于IDA控制流追踪为什么那么不好使的原因.当文章阅读过1000就马上更新!

另外帮鸭鸭解决了滞销的米塔帽的兄弟们,可以在本公众号的微信群询问鸭哥要关于本章的DEMO以及指导(如果对做IDA感兴趣的话).感谢各位兄弟们的支持!


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:冲鸭安全 为了安全鸭《IDA背后的原理入门(一): 简介&函数识别》

评论:0   参与:  0