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

admin 2025年1月26日23:48:22评论23 views字数 3281阅读10分56秒阅读模式

简介

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

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

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

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

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

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

原理

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

函数识别

初级函数识别

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

识别winx64的 函数 最基本的办法是遍历text段找call,我们可以遍历出 所有的 call imm指令以及JMP 指令,这些指令通常是一个函数.
基本代码如下:
IDA背后的原理入门(一): 简介&函数识别
其中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控制区段的跳转,否则我们是没办法检测到函数的
基本代码如下:
IDA背后的原理入门(一): 简介&函数识别

值得注意的是,这个只是最基本的函数识别,这没办法处理其他情况,尤其是对于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]

这些情况需要进行数据流分析才能准确识别目标函数。
一个完整的代码如下:
IDA背后的原理入门(一): 简介&函数识别

function symbol

ida的symbol有几种:

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

比如如下是基于导入表的符号识别:
IDA背后的原理入门(一): 简介&函数识别

而如下是基于lumina的识别
IDA背后的原理入门(一): 简介&函数识别
这是基于IDA sigs的函数识别
IDA背后的原理入门(一): 简介&函数识别
而我们先做简单一点,只识别导入/导出表
IDA背后的原理入门(一): 简介&函数识别

function stub

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

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

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

导入表跳板

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

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

效果

IDA寻找出了320个函数
IDA背后的原理入门(一): 简介&函数识别
我们寻找出了297个函数
IDA背后的原理入门(一): 简介&函数识别
而作为对比,BN是460
IDA背后的原理入门(一): 简介&函数识别

一个显而易见的事实是,各家算法不同,差异也就越大.比如我们是不看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背后的原理入门(一): 简介&函数识别

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年1月26日23:48:22
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   IDA背后的原理入门(一): 简介&函数识别https://cn-sec.com/archives/3673980.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息