惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
Tailwind CSS Blog
博客园 - Franky
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Y
Y Combinator Blog
Hugging Face - Blog
Hugging Face - Blog
博客园 - 聂微东
L
LangChain Blog
博客园_首页
Recent Announcements
Recent Announcements
月光博客
月光博客
酷 壳 – CoolShell
酷 壳 – CoolShell
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
H
Hackread – Cybersecurity News, Data Breaches, AI and More
爱范儿
爱范儿
博客园 - 叶小钗
博客园 - 【当耐特】
The Cloudflare Blog
J
Java Code Geeks
G
Google Developers Blog
云风的 BLOG
云风的 BLOG
Blog — PlanetScale
Blog — PlanetScale
博客园 - 司徒正美
aimingoo的专栏
aimingoo的专栏
A
About on SuperTechFans

博客园 - GKLBB

软件神器 --- ctf靶场 之 pwn.college 术语俗话 --- 什么是加密狗 软件神器 --- 自动电脑锁屏软件 软件研发 --- 网络安全 之 putty生成无密码登录密钥 软件神器 --- 视频剪辑 之 Avidemux MP4Joiner Shotcut 软件神器 --- 视频格式转化 之 handbrake 软件研发 --- 经验之谈 这个是什么图标,经常看到 软件研发 --- 术语俗话 之 多模态 术语俗话 --- 什么是大数据开发 软件研发 --- 术语俗话 之 什么是边缘计算 软件研发 --- 应知应会 之 什么是云计算开发 应知应会 --- 如何不装软件查看网速 常见问题解决 --- 360拦截接触 常见问题解决 --- 加入会议摄像头无法打开 网络安全 --- CTF打靶 之 ZIP伪加密 → Robot36慢扫电视 → 二维码补齐 → DeepSound隐写 → GPG解密 → Base64图片 → SilentEye隐写 软件研发 --- 应知应会 之 无错误的闪退如何解决 软件研发 --- 应知应会 之 为什么别人的软件如此复杂我的如此简单 网络安全 --- 应知应会 之 什么是旁站 应知应会 --- 如何查询备案 软件神器 --- 格式转化 之 jpg 2 svg 网络安全 --- CTF打靶 之 flag搜索 软件神器 --- 互联网测速 之 软件神器 --- 局域网测速 之 iperf 常见问题解决 --- 模拟器USG6000打开后,启动设备失败,错误40 软件研发 --- AI网络 之 ensp配置生成 软件研发 --- AI编程 之 极简流程 软件研发 --- AI生图产品比较 常见问题解答 --- 为什么我的服务一直被人DDOS 软件研发 --- 开发万能格式转化工具
应用安全 --- IDA签名 之 原理分析
GKLBB · 2026-06-08 · via 博客园 - GKLBB

FLIRT(Fast Library Identification and Recognition Technology)是 IDA 的库函数快速识别技术,核心原理是基于编译器生成的库函数特征模板(签名),用树状模式匹配 + CRC 校验识别二进制中的库函数,把无名的 sub_xxxx 恢复为 strlen/printf 等标准名称。

以识别 strlen 为例


总览

┌─────────────────────────────────────────────────────────────┐
│                    完整识别流程                               │
│                                                             │
│  [静态库] → [提取特征] → [生成签名] → [IDA匹配] → [标注]    │
│   .lib        .pat          .sig        识别          函数名  │
└─────────────────────────────────────────────────────────────┘

第一阶段:准备签名库(离线完成)

1.1 原始函数机器码

; strlen 编译后的机器码
; 地址无关,只看字节内容

偏移  机器码          汇编
+00:  55              push ebp
+01:  8B EC           mov  ebp, esp
+03:  8B 45 08        mov  eax, [ebp+8]    ; eax = s (参数)
+06:  8A 08           mov  cl, [eax]       ; cl = *s
+08:  84 C9           test cl, cl
+0A:  74 09           jz   +09             ; ← 偏移可变!
+0C:  90              nop
+0D:  40              inc  eax
+0E:  8A 08           mov  cl, [eax]
+10:  84 C9           test cl, cl
+12:  75 FB           jnz  -05             ; ← 偏移可变!
+14:  2B 45 08        sub  eax, [ebp+8]
+17:  5D              pop  ebp
+18:  C3              ret
; 函数总长 = 0x19 = 25 字节

1.2 FLAIR工具提取特征 → 生成 .pat

Step1: 提取前32字节
55 8B EC 8B 45 08 8A 08 84 C9 74 09 90 40 8A 08
84 C9 75 FB 2B 45 08 5D C3
(本函数只有25字节,不足32字节则全取)

Step2: 标记可变字节(跳转偏移)
偏移+0A 的 09 → 可变 → 掩码为 ..
偏移+12 的 FB → 可变 → 掩码为 ..

Step3: 生成 pat 条目
55 8B EC 8B 45 08 8A 08 84 C9 74 .. 90 40 8A 08 84 C9 75 .. 2B 45 08 5D C3
                              ^^                        ^^
                           掩码                       掩码

pat完整一行:
55 8B EC 8B 45 08 8A 08 84 C9 74 .. 90 40 8A 08 84 C9 75 .. 2B 45 08 5D C3 19 A1B2 0019 :0000 _strlen
│                                                                           │  │    │    └─── 函数名
│                                                                           │  │    └──────── 函数总长(0x19=25)
│                                                                           │  └───────────── CRC16值
│                                                                           └────────────────可变区长度
└──────────────────────────────────────────────────────────────────────────────────────────── 掩码后的前缀

1.3 sigmake 生成 .sig

运行命令:
sigmake msvcrt.pat msvcrt.sig

内部构建 Trie 树:

└─[55]
  └─[8B EC]
    └─[8B 45 08]
      └─[8A 08 84 C9 74 ..]
        └─[90 40 8A 08 84 C9 75 ..]
          └─[2B 45 08 5D C3]
            └─ 叶子节点
               ├── crc_len : 0x05
               ├── crc16   : 0xA1B2
               ├── total   : 0x19
               └── name    : "_strlen"

第二阶段:IDA 加载分析(在线识别)

2.1 IDA 发现未知函数

IDA 反汇编视图:

.text:00401080 sub_401080:          ; ← 未识别,显示为sub_XXXXXX
.text:00401080     push    ebp
.text:00401081     mov     ebp, esp
.text:00401083     mov     eax, [ebp+8]
.text:00401086     mov     cl, [eax]
.text:00401088     test    cl, cl
.text:0040108A     jz      short loc_401095
.text:0040108C     nop
.text:0040108D loc_40108D:
.text:0040108D     inc     eax
.text:0040108E     mov     cl, [eax]
.text:00401090     test    cl, cl
.text:00401092     jnz     short loc_40108D
.text:00401094 loc_401095:
.text:00401094     sub     eax, [ebp+8]
.text:00401097     pop     ebp
.text:00401098     retn

2.2 加载 .sig 文件

IDA操作:
File → Load File → FLIRT Signature File
选择 msvcrt.sig

或快捷键: Shift+F5

2.3 IDA 提取函数字节

从地址 0x00401080 读取字节:

原始字节:
55 8B EC 8B 45 08 8A 08 84 C9 74 [09] 90 40 8A 08
84 C9 75 [FB] 2B 45 08 5D C3

对可变位置应用掩码:
55 8B EC 8B 45 08 8A 08 84 C9 74 [..] 90 40 8A 08
84 C9 75 [..] 2B 45 08 5D C3

掩码后用于Trie匹配的序列:
55 8B EC 8B 45 08 8A 08 84 C9 74 .. 90 40 8A 08 84 C9 75 .. 2B 45 08 5D C3

2.4 Trie 树匹配过程

逐字节在Trie中查找:

输入:  55  → 匹配根节点子节点[55] ✓
输入:  8B  → 匹配下一层[8B EC]   ✓
输入:  EC  →                      ✓
输入:  8B  → 匹配[8B 45 08]      ✓
输入:  45  →                      ✓
输入:  08  →                      ✓
...
输入:  C3  → 到达叶子节点!

叶子节点数据:
┌──────────────────────────────┐
│ 候选函数: _strlen            │
│ crc_len:  5                  │
│ crc16:    0xA1B2             │
│ total:    0x19               │
└──────────────────────────────┘

结果:找到1个候选 → 进入CRC验证

2.5 CRC16 精确验证

确定CRC计算范围:
函数起始地址:  0x401080
前缀长度:      25字节(函数总长不足32字节的情况)
CRC区域:       这里直接对非可变字节计算

实际参与CRC计算的字节(跳过可变字节):
偏移  字节  是否参与
+00:  55   ✓
+01:  8B   ✓
+02:  EC   ✓
+03:  8B   ✓
+04:  45   ✓
+05:  08   ✓
+06:  8A   ✓
+07:  08   ✓
+08:  84   ✓
+09:  C9   ✓
+0A:  74   ✓
+0B:  09   ✗ 跳过(可变)
+0C:  90   ✓
...
+12:  75   ✓
+13:  FB   ✗ 跳过(可变)
+14:  2B   ✓
...

计算 CRC16 结果 = 0xA1B2

对比签名:
计算值 0xA1B2 == 存储值 0xA1B2  → ✓ 验证通过!

2.6 确认并标注函数名

验证通过!IDA 执行标注:

操作:
sub_401080  →  strlen

同时:
1. 函数注释自动添加
2. 参数名称恢复(如果sig包含类型信息)
3. 相关引用同步更新

第三阶段:识别结果

标注前

.text:00401080 sub_401080 proc near
.text:00401080     push    ebp
.text:00401081     mov     ebp, esp
.text:00401083     mov     eax, [ebp+arg_0]
...
.text:00401098     retn
.text:00401098 sub_401080 endp

标注后

.text:00401080 strlen proc near          ; ← 自动识别!
.text:00401080     push    ebp
.text:00401081     mov     ebp, esp
.text:00401083     mov     eax, [ebp+s]  ; ← 参数名也恢复了
...
.text:00401098     retn
.text:00401098 strlen endp

; 调用处也自动更新:
.text:00401200     push    eax
.text:00401201     call    strlen         ; ← 原来是 call sub_401080

完整流程一图总结

离线阶段                              在线阶段
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
                                      
msvcrt.lib                            待分析的 binary
    │                                      │
    ▼                                      ▼
[pelf工具]                          IDA 反汇编
提取每个函数字节                     发现 sub_401080
    │                                      │
    ▼                                      ▼
标记可变字节(..)                     读取函数字节
74 09 → 74 ..                        55 8B EC ...
    │                                      │
    ▼                                      ▼
生成 .pat 文件                       应用 .. 掩码
[前缀+CRC+函数名]                    74 09 → 74 ..
    │                                      │
    ▼                                      ▼
[sigmake工具]                        Trie 前缀匹配
构建压缩Trie树                       找到候选: strlen
    │                                      │
    ▼                                      ▼
生成 .sig 文件  ──────加载──────►    CRC16 验证
                                     0xA1B2 == 0xA1B2 ✓
                                    标注函数名
                                    sub_401080 → strlen ✓

关键点回顾

步骤核心操作目的
提取前缀 取函数前32字节 快速过滤
掩码处理 跳转偏移置.. 消除地址相关性
Trie匹配 逐字节查树 找到候选函数
CRC验证 计算非可变字节校验值 精确区分相似函数
标注结果 写入函数名/参数名 辅助逆向分析

免责声明 本文档所有内容仅供安全研究、学术交流与技术学习使用,严禁用于任何未经授权的逆向破解、网络攻击、隐私窃取、恶意软件开发及其他违反《中华人民共和国网络安全法》《数据安全法》等法律法规的行为,使用者应确保已获得目标软件权利人的合法授权并自行承担因使用本文档内容所产生的一切法律责任与后果,作者不对任何直接或间接损害承担任何责任,继续阅读即视为您已知悉并同意上述全部条款。