首页
社区
课程
招聘
[原创] Arm静态分析引擎原理三 - 控制流构建基础
发表于: 2026-8-12 18:32 1487

[原创] Arm静态分析引擎原理三 - 控制流构建基础

2026-8-12 18:32
1487

上文


当反汇编引擎完成之后,下一步就是对 ELF 建立控制流。

对于一个完整的 ELF 控制流分析引擎来说,通常可以拆分为以下几个部分:

二进制加载器(Binary Loader):解析 ELF,并识别初始分析入口

递归向下(Recursive Descent):从已知入口开始递归构建控制流

特殊控制结构识别:处理普通递归向下难以覆盖的控制流结构,例如 jump table、br间接跳转等

其中,第一步决定了我们从哪里开始分析,第二步负责沿着控制流扩展,第三步则负责解决真实世界二进制中大量存在的特殊控制结构。


Android App 中存在各种各样的 ELF。

除了使用 GCC/Clang 编译出来的标准 ELF 之外,还会遇到 Dart VM、Cocos2d、Unity3D 等各种大型运行时或游戏引擎生成的 ELF。

这里的elf入口其实是分析入口,因此,在 Rosemary 中,我将这些统一抽象成 analysis entry。

elf的入口定义:

其中BL和BLR是在递归向下的识别汇编指令的时候发现的。


递归向下的构建控制流的过程就是静态分析软件建模的过程。

这个过程中涉及到的东西有控制流的node、edge、end instruction、branch instruction、trap function

还是以ARM64举例,构建控制流需要的辅助方法就是arm的汇编代码的理解,如下:


当发现指令调用下面这些函数的时候,比如bl 0x1234 // 0x1234是__stack_chk_fail,那么这里应该是basic block的结束。


构建控制流最经典的方法就是worklist



上面的3个步骤就是构建elf控制流的基础方法,这里还有很多很多细节,例如


instruction/cfg的存储结构

一个30M左右的so,能产生的指令会有700~800w条,控制流图的node和edge也百万级别的,因为构建过程中需要查询,所以数据结构十分十分重要。


basic block的切分

控制流jump到一个已知的node的情况



传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!!

最后于 2026-8-12 18:42 被neocanable编辑 ,原因:
收藏
免费 48
打赏
分享
最新回复 (24)
雪    币: 102
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
2
我去,还有第三关
2026-8-12 22:36
0
雪    币: 1209
活跃值: (3691)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
这里还有很多,感觉写不下,比如jumptable识别的时候是有用ir的方式的,有的是pattern match的方式的;vtable和pointer array的识别也是这样;是全量分析和单函数分析,都是要有考量的。

写完了这个东西才能发现ida到底是多高的一座山
2026-8-12 23:10
0
雪    币: 3593
活跃值: (7320)
能力值: ( LV11,RANK:185 )
在线值:
发帖
回帖
粉丝
4
1
2026-8-13 10:35
0
雪    币: 2
活跃值: (2226)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
666
2026-8-13 10:41
0
雪    币: 5123
活跃值: (6455)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
6
2026-8-13 10:58
0
雪    币: 3593
活跃值: (7320)
能力值: ( LV11,RANK:185 )
在线值:
发帖
回帖
粉丝
7
仔细看了你写的内容,首先这个控制流的构建,或者是递归向下,我感觉你没有阐述清楚,或者说我没看懂
根据我的一些分析,ida,是以函数为单个控制流分析的单位,所以,所有的控制流分析,都是建立在,首先分析出汇编是一个函数的基础上,这个可以通过栈指令之类的分析.当分析完一个汇编函数等等起始和结束以后,在通过这个汇编函数的指令,来构建控制流,这种情况下,通过各种跳转指令的分割,很容就可以构建出控制流了,置于剩下的swith分析,if分析,代码优化这些都是在这个之上了,目前大规模的使用中间码进行指令归约,然后在进行二次的数据分析,中间码本来就是一种偏向于高级语言的表达形式
2026-8-13 11:04
1
雪    币: 411
活跃值: (761)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
6
2026-8-13 11:06
0
雪    币: 1209
活跃值: (3691)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
Thehepta 仔细看了你写的内容,首先这个控制流的构建,或者是递归向下,我感觉你没有阐述清楚,或者说我没看懂 根据我的一些分析,ida,是以函数为单个控制流分析的单位,所以,所有的控制流分析,都是建立在,首先分析 ...

第一个函数的确认问题:应该是我没有描述清楚,我写的elf的入口,有的时候就是函数,但是又不全是,比如c++的异常部分,它在elf里面的表现就是一个入口,要是强制说它是一个函数有的时候也没有错,一个异常处理块编译器优化的时候是会做share的。

第二个问题函数边界的问题:从elf的角度来说,你可以规约出一个function head,但是没有办法提前确定一个function的end,比如我举的bl _exit。

第三个问题:elf function的控制流跟jvm或者dalvik的fucntion完全不一样,他们有边界,知道end在哪里。elf的完全不知道;

比如一个函数 fun_0x1111, 它的basic block可能是连续的,也可能是跳跃的,因为basic block在编译器优化的过程中也是可以share的。

所以就elf的控制流就是一堆pass堆积着递归的过程。

2026-8-13 11:20
0
雪    币: 1209
活跃值: (3691)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
Thehepta 仔细看了你写的内容,首先这个控制流的构建,或者是递归向下,我感觉你没有阐述清楚,或者说我没看懂 根据我的一些分析,ida,是以函数为单个控制流分析的单位,所以,所有的控制流分析,都是建立在,首先分析 ...
感谢你的回复,我觉得这个是发了这么多东西,第一次遇到能讨论的人。
2026-8-13 11:27
0
雪    币: 3593
活跃值: (7320)
能力值: ( LV11,RANK:185 )
在线值:
发帖
回帖
粉丝
11
neocanable Thehepta 仔细看了你写的内容,首先这个控制流的构建,或者是递归向下,我感觉你没有阐述清楚,或者说我没看懂 根据我的一些分析,ida,是以函数为单个控 ...
我觉得你这个说法不是完全对的,elf function 的函数边界是可以分析出来的,而且只要不是用什么内联汇编,汇编函数,裸函数这些,一般都能分析出来,比如c代码编译的函数,是符合一定的的编译规则的,这是现代编译工具中的做法,你可以理解为反编译可以取巧的办法,你的想法是纯汇编来还原的思路,像ida这种工具,就像我说的,他是以函数为单位进行反编译,所以如果一个汇编函数没法分析出来,反编译也会失败,汇编函数如果分析失败,反编译也会失败
2026-8-13 11:40
0
雪    币: 3593
活跃值: (7320)
能力值: ( LV11,RANK:185 )
在线值:
发帖
回帖
粉丝
12
neocanable Thehepta 仔细看了你写的内容,首先这个控制流的构建,或者是递归向下,我感觉你没有阐述清楚,或者说我没看懂 根据我的一些分析,ida,是以函数为单个控 ...
做这个的比较少,因为ida 或者说某些工具做的很好,你只会一点完全撼动不了他的地位,而且国内公司没有相关工作岗位,一般后续都变成搞逆向了
2026-8-13 11:42
0
雪    币: 1209
活跃值: (3691)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13

我觉得这个是一个误区,反汇编确实没有函数边界,IDA本身它也不知道function end,它也是递归向下的一点点的发现的,在整体的递归向下后有linear scan等等pass来补漏,看着像能发现一个函数而已。



2026-8-13 11:52
0
雪    币: 1209
活跃值: (3691)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
Thehepta 做这个的比较少,因为ida 或者说某些工具做的很好,你只会一点完全撼动不了他的地位,而且国内公司没有相关工作岗位,一般后续都变成搞逆向了
IDA/binary ninja这些工具值钱的是积累,国内确实没有人做这方面的产品,不赚钱,白忙活。而且还有破解的用。
2026-8-13 11:58
0
雪    币: 3532
活跃值: (7285)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
15
77fK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6*7K9s2g2*7K9s2g2Q4x3X3c8f1L8%4m8Q4x3V1k6^5k6r3g2U0i4K6t1$3L8X3u0K6M7q4)9K6b7W2!0q4y4g2!0n7x3g2)9^5y4g2!0q4y4#2)9^5y4q4!0n7y4W2!0q4y4W2)9&6b7#2)9^5z5g2!0q4y4q4!0n7b7g2!0n7b7g2!0q4z5q4!0n7y4#2)9&6c8W2!0q4y4W2)9^5z5q4)9&6x3g2!0q4y4q4!0n7z5q4)9^5x3q4!0q4y4W2!0m8x3q4!0n7y4#2!0q4y4g2)9&6b7#2!0m8z5q4!0q4y4g2)9^5x3g2)9&6b7g2!0q4y4g2)9&6x3q4)9^5b7#2!0q4y4W2!0m8x3q4!0n7y4#2!0q4y4#2)9&6b7g2)9^5y4q4!0q4y4q4!0n7b7g2)9^5b7W2!0q4y4W2)9^5x3#2)9^5y4g2)9J5y4X3&6T1M7%4m8Q4x3@1t1`.
2026-8-13 15:07
0
雪    币: 1209
活跃值: (3691)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
zhuzhu_biu 01eK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6*7K9s2g2*7K9s2g2Q4x3X3c8f1L8%4m8Q4x3V1k6^5k6r3g2U0 居然有人跟我一样在做同样的事情 [em_0106]
我仔细看了xdec这个repo,我认为解码的部分还有很长的路要走,加油
2026-8-13 17:01
0
雪    币: 112
活跃值: (9260)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
tql
2026-8-13 17:43
0
雪    币: 3532
活跃值: (7285)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
18
neocanable 我仔细看了xdec这个repo,我认为解码的部分还有很长的路要走,加油
ce0K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6*7K9s2g2*7K9s2g2Q4x3X3c8f1L8%4m8Q4x3V1k6^5k6r3g2U0i4K6u0r3j5X3I4G2j5W2)9J5c8X3#2S2M7%4c8W2M7W2)9J5c8Y4y4H3k6h3y4K6i4K6u0r3j5i4u0E0y4U0c8Q4x3X3g2^5M7%4m8W2j5#2!0q4z5q4!0m8y4#2!0m8x3#2!0q4y4#2!0m8x3q4)9^5x3g2!0q4z5g2)9^5x3#2!0m8z5q4!0q4y4g2)9^5z5q4)9^5y4W2!0q4y4g2!0n7y4#2!0n7x3W2!0q4y4#2!0n7b7W2)9^5c8W2!0q4y4g2)9&6c8W2!0n7b7g2!0q4y4W2)9&6b7#2!0m8b7#2!0q4z5q4!0n7y4W2)9^5b7W2!0q4y4q4!0n7b7g2)9^5c8g2!0q4y4g2!0m8c8g2)9^5b7#2!0q4y4g2)9&6y4W2)9^5y4q4!0q4y4q4!0n7b7g2)9^5y4R3`.`.
2026-8-13 20:26
0
雪    币: 1209
活跃值: (3691)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
zhuzhu_biu 9f4K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6*7K9s2g2*7K9s2g2Q4x3X3c8f1L8%4m8Q4x3V1k6^5k6r3g2U0i4K6u0r3j5X3I4G2j5W2)9J5c8X3#2S2M7%4c8W2M7W2)9J5c8Y4y4H3k6h3y4K6i4K6u0r3j5i4u0E0y4U0c8Q4x3X3g2^5M7%4m8W2j5#2!0q4z5q4!0m8y4#2!0m8x3#2!0q4y4#2!0m8x3q4)9^5x3g2!0q4z5g2)9^5x3#2!0m8z5q4!0q4y4g2)9^5z5q4)9^5y4W2!0q4y4g2!0n7y4#2!0n7x3W2!0q4y4#2!0n7b7W2)9^5c8W2!0q4y4g2)9&6c8W2!0n7b7g2!0q4y4W2)9&6b7#2!0m8b7#2!0q4z5q4!0n7y4W2)9^5b7W2!0q4y4q4!0n7b7g2)9^5c8g2!0q4y4g2!0m8c8g2)9^5b7#2!0q4y4g2)9&6y4W2)9^5y4q4!0q4y4q4!0n7b7g2)9^5y4W2)9#2b7X3g2E0i4K6g2X3x3o6p5H3y4W2)9#2c8l9`.`.

我跑了一下xdec,我的感觉:
第一:simd的指令集是没有的,现在的很多流式的计算是靠NEON来实现的,后续还有SVE/SVE2/SME/SME2,我没有看过apple的东西不知道apple有没有sve和sve2,android上见过不少了。
第二:lift的结果不错,这个IR我想学习一下
第三:decompile的时候遇到jumptable会crash或者dead loop,这个我不知道的死循环还是没有对jumptable做识别;按道理来说,有了ir的话,jumptable识别起来很简单。
第四:disasm这个不应该这样实现,应该指的一个address,然后顺藤摸瓜的递归向下走,如果指定了数量,其实跟objdump没什么区别,可能是错误的,如果bb之间有空洞/数据/全局变量,出来的结果一定是错误的。


加油!

最后于 2026-8-16 14:17 被neocanable编辑 ,原因:
2026-8-16 14:16
1
雪    币: 573
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
20
来了
2026-8-18 09:16
0
雪    币: 2790
活跃值: (6865)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
21
感谢分享!
2026-8-18 10:09
0
雪    币: 200
活跃值: (203)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
学习
2026-8-20 13:58
0
雪    币: 9375
活跃值: (4299)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
谢谢分享
2026-8-23 16:38
0
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
24
Thehepta 我觉得你这个说法不是完全对的,elf function 的函数边界是可以分析出来的,而且只要不是用什么内联汇编,汇编函数,裸函数这些,一般都能分析出来,比如c代码编译的函数,是符合一定的的编译规则的, ...
Thehepta大佬的意思是,IDA做完函数识别之后,对每个函数内部的指令序列拆分基本块做CFG恢复是吗?我觉得这个做法也比较合理
1. 正常代码同时受架构的ABI规约和工具链偏好,所以这块应该是有内嵌相应的pattern规则加速函数边界发现这一部分的
2. 手动把一块内存区域标记为function,函数为粒度的话这时候反汇编引擎可以只做增量反汇编,不用触发全局的重新分析
2026-8-24 18:13
0
雪    币: 1209
活跃值: (3691)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
mb_ririxjzk Thehepta大佬的意思是,IDA做完函数识别之后,对每个函数内部的指令序列拆分基本块做CFG恢复是吗?我觉得这个做法也比较合理 1. 正常代码同时受架构的ABI规约和工具链偏好,所以这块应该是有 ...
首先需要知道的是function head,也就是函数头,也可能是任何一种elf/pe/macho的分析入口,这些东西是可以确定的;如果识别函数是指的这样的动作,那么没有问题。如果是指的一个function的range,那么肯定是不对了的
2026-8-24 19:52
0
游客
登录 | 注册 方可回帖
返回