• Home
Name Date Size #Lines LOC

..--

include/06-May-2025-630436

templates/06-May-2025-4840

tests/unittest/06-May-2025-2,2371,661

BUILD.gnD06-May-20253.2 KiB9981

README.mdD06-May-202514.3 KiB246197

abc_file.cppD06-May-202564.3 KiB1,5541,413

callee_info.cppD06-May-20252.4 KiB11381

class.cppD06-May-20253.4 KiB135101

function.cppD06-May-20253.8 KiB161124

graph.cppD06-May-20255.2 KiB209165

module_record.cppD06-May-20253.7 KiB132101

README.md

1# 基于方舟字节码文件的安全扫描接口
2
3## 1.背景
4
5JS/TS 应用中对关键敏感函数的调用参数,如果直接来自用户的外部输入,没有进行有效性判断,容易导致注入攻击或者应用程序崩溃。因此,需要提供基于方舟字节码文件(Ark ByteCode, 简称`abc`)的安全漏洞扫描工具,以提高应用的可靠性、安全性。
6
7在此,我们为安全漏洞扫描工具提供基于`abc`文件的分析接口,以供分析相关函数的调用链和参数信息,进行漏洞检测。
8
9## 2.原理
10
11工具的大致实现流程如下:
12
13```mermaid
14flowchart LR;
15  A((.abc file))-->B[Iterate All Methods];
16  A((.abc file))-->C[Parse Module Import/Export Entry];
17  B[Iterate All Methods]-->D[Generate Method CFG/DFG];
18  D[Generate Method CFG/DFG]<-->G[Compiler IRBuilder];
19  D[Generate Method CFG/DFG]-->E[Extract Defined Function/Class];
20  D[Generate Method CFG/DFG]-->F[Extract Callee Function/ Extract Class Inheritance Info];
21  C[Parse Module Import/Export Entry]-->F[Extract Callee Function/ Extract Class Inheritance Info];
22  E[Extract Defined Function/Class]-->F[Extract Callee Function/ Extract Class Inheritance Info];
23```
24
25对一个`abc`文件,我们会解析它导入和导出的模块间信息,遍历所有函数,调用IR Builder的接口,生成所有函数的控制流图和数据流图。根据生成图以及模块间的导入导出信息,构建函数之间的调用关系以及类的继承关系,并提供相应的接口。
26
27## 3.使用方法
28
29### 3.1 支持平台说明
30
31安全扫描工具当前支持在Linux/MacOS平台上编译和运行,以及在Linux平台上交叉编译能够在Windows平台上运行的可执行程序。
32
33### 3.2 自定义代码
34
35我们在`runtime_core/libark_defect_scan_aux/tests/unittest/defect_scan_aux_demo.cpp`提供了简单的示例代码,其中指定了`abc`文件路径(例如,`test.abc`),开发者可根据需求修改该示例代码文件,然后编译运行。
36
37### 3.3 编译命令
38
39#### Linux
40```
41./build.sh --product-name rk3568 --build-target ark_host_linux_defectscanaux_unittest
42```
43
44`out/rk3568/clang_x64/arkcompiler/runtime_core`目录下会生成示例文件对应的可执行程序文件。
45
46#### Windows
47```
48./build.sh --product-name rk3568 --build-target ark_host_win_defectscanaux_unittest
49```
50
51`out/rk3568/mingw_x86_64/arkcompiler/runtime_core`目录下会生成示例文件对应的可执行程序文件。
52
53#### Mac M1
54```
55cd ${OpenHarmony}
56
57./prebuilts/build-tools/darwin-arm64/bin/gn gen ./out/mac_arm64 \
58--root=. \
59--dotfile=./arkcompiler/toolchain/build/compile_script/.gn \
60--args="target_os=\"mac\" target_cpu=\"arm64\" is_debug=false"
61
62./prebuilts/build-tools/darwin-arm64/bin/ninja  -d keeprsp -C out/mac_arm64 ark_host_defectscanaux_tools -k 1
63```
64
65`out/mac_arm64/arkcompiler/runtime_core`目录下会生成示例文件对应的可执行程序文件。
66
67#### Mac x64
68```
69cd ${OpenHarmony}
70
71./prebuilts/build-tools/darwin-x86/bin/gn gen ./out/mac_x64 \
72--root=. \
73--dotfile=./arkcompiler/toolchain/build/compile_script/.gn \
74--args="target_os=\"mac\" target_cpu=\"x64\" is_debug=false"
75
76./prebuilts/build-tools/darwin-x86/bin/ninja  -d keeprsp -C out/mac_x64 ark_host_defectscanaux_tools -k 1
77```
78
79`out/mac_x64/arkcompiler/runtime_core/`目录下会生成示例文件对应的可执行程序文件。
80
81### 3.4 如何生成`abc`文件
82
83#### 3.4.1 使用命令行
84参考《[es2panda使用方式](https://gitee.com/openharmony/arkcompiler_ets_frontend/blob/master/README_zh.md#%E7%BC%96%E8%AF%91%E6%9E%84%E5%BB%BA)》编译js/ts文件生成`abc`文件。
85
86#### 3.4.2 使用DevEco Studio
87通过DevEco Studio编译应用,编译成功后,解压应用`hap`包,找到其中的`abc`文件。
88
89### 3.5 执行扫描
90
91将需要扫描的`abc`文件放到示例代码中指定的文件路径后,执行示例代码对应的可执行程序即可。
92
93以 Linux 为例
94```shell
95cd out/rk3568/clang_x64/arkcompiler/runtime_core
96./defect_scan_aux_demo
97```
98
99## 4.接口说明
100
101### 4.1 `AbcFile`
102
103| 接口名及参数 | 描述 |
104| ----------- | ---- |
105| static std::unique_ptr\<const AbcFile\> Open(std::string_view abc_filename)                                                | 根据文件名打开方舟字节码文件并返回该文件 |
106| bool IsMergeAbc() const                                                                                                    | 返回方舟字节码文件是否为合并格式 |
107| const std::set\<std::string\> GetFileRecordList() const                                                                    | 若为合并abc,返回所有文件描述名 |
108| size_t GetFileRecordCount() const                                                                                          | 若为合并abc,返回abc中的文件个数 |
109| const std::string &GetAbcFileName() const                                                                                  | 返回方舟字节码文件的名称 |
110| const std::vector\<std::shared_ptr\<Class\>\> &GetClassList() const                                                        | 返回包含所有类的列表 |
111| size_t GetDefinedFunctionCount() const                                                                                     | 返回定义的函数个数 |
112| size_t GetDefinedClassCount() const                                                                                        | 返回定义的类的个数 |
113| const Function \*GetFunctionByName(std::string_view func_name) const                                                       | 根据名称返回指定函数 |
114| const Function \*GetExportFunctionByExportName(std::string_view export_func_name, std::string_view record_name = "") const | 根据导出名返回指定的导出函数,若为合并abc,需指定文件描述名 |
115| const Class \*GetClassByName(std::string_view class_name) const                                                            | 根据类名返回指定类 |
116| const Class \*GetExportClassByExportName(std::string_view export_class_name, std::string_view record_name = "") const      | 根据导出名返回指定的导出类,若为合并abc,需指定文件描述名 |
117| size_t GetLineNumberByInst(const Function \*func, const Inst &inst) const                                                  | 根据指令返回该指令对应源码的行号 |
118| std::string GetLocalNameByExportName(std::string_view export_name, std::string_view record_name = "") const                | 根据变量的导出名返回其本地的名称,若为合并abc,需指定文件描述名 |
119| std::string GetImportNameByExportName(std::string_view export_name, std::string_view record_name = "") const               | 根据变量的导出名返回其导入的名称,若为合并abc,需指定文件描述名 |
120| std::string GetModuleNameByExportName(std::string_view export_name, std::string_view record_name = "") const               | 根据变量的导出名返回导入该变量的模块名,若为合并abc,需指定文件描述名 |
121| std::string GetModuleNameByLocalName(std::string_view local_name, std::string_view record_name = "") const                 | 根据变量的本地名返回导入该变量的模块名,若为合并abc,需指定文件描述名 |
122| std::string GetImportNameByLocalName(std::string_view local_name, std::string_view record_name = "") const                 | 根据变量的本地名返回该变量的导入名,若为合并abc,需指定文件描述名 |
123
124### 4.2 `Function`
125
126| 接口名及参数 | 描述 |
127| ----------- | ---- |
128| const std::string &GetFunctionName() const                              | 返回函数名 |
129| const AbcFile \*GetAbcFileInstance() const                              | 返回该函数所在的方舟字节码文件 |
130| const std::string &GetRecordName() const                                | 若为合并abc,返回该函数所在的文件描述名 |
131| const Graph &GetGraph() const                                           | 返回该函数的构图 |
132| const Class \*GetClass() const                                          | 返回定义该函数的类 |
133| const Function \*GetParentFunction() const                              | 返回定义该函数的函数 |
134| uint32_t GetArgCount() const                                            | 返回参数个数 |
135| size_t GetDefinedClassCount() const                                     | 返回函数中定义的类的个数  |
136| size_t GetDefinedFunctionCount() const                                  | 返回函数中定义的函数的个数 |
137| size_t GetCalleeInfoCount() const                                       | 返回调用信息的个数 |
138| const CalleeInfo \*GetCalleeInfoByCallInst(const Inst &call_inst) const | 根据调用指令返回调用信息 |
139
140### 4.3 `Class`
141
142| 接口名及参数 | 描述 |
143| ----------- | ---- |
144| const std::string &GetClassName() const                                   | 返回类名 |
145| const AbcFile *GetAbcFileInstance() const                                 | 返回该类所在的方舟字节码文件 |
146| const std::string &GetRecordName() const                                  | 若为合并abc,返回该类所在的文件描述名 |
147| Function *GetDefiningFunction() const                                     | 返回定义该类的函数 |
148| size_t GetMemberFunctionCount() const                                     | 返回成员函数的数量 |
149| const Function *GetMemberFunctionByName(std::string_view func_name) const | 根据名称返回成员函数 |
150| const std::vector<const Function *> &GetMemberFunctionList() const        | 返回所有成员函数 |
151| const Class *GetParentClass() const                                       | 返回父类 |
152| const std::string &GetParentClassName() const                             | 返回父类名 |
153| const std::string &GetParClassExternalModuleName() const                  | 返回导入父类的模块名 |
154| const std::string &GetParClassGlobalVarName() const                       | 返回父类的全局变量名 |
155
156### 4.4 `CalleeInfo`
157
158| 接口名及参数 | 描述 |
159| ----------- | ---- |
160| int GetCalleeArgCount() const                    | 返回该被调者的参数个数 |
161| const Inst &GetCallInst() const                  | 返回该被调者相关的调用指令 |
162| const Function \*GetCaller() const               | 返回该被调者的调用者 |
163| const Class \*GetClass() const                   | 返回该被调者所在的类 |
164| const Function \*GetCallee() const               | 返回该被调者的对应函数 |
165| const std::string &GetFunctionName() const       | 返回该被调者的函数名 |
166| const std::string &GetClassName() const          | 返回该被调者所在的类名 |
167| const std::string &GetExternalModuleName() const | 返回导入该被调者的模块名 |
168| const std::string &GetGlobalVarName() const      | 返回该被调者所在的全局变量名 |
169
170### 4.5 `Graph`
171| 接口名及参数 | 描述 |
172| ----------- | ---- |
173| BasicBlock GetStartBasicBlock() const                      | 返回第一个基块 |
174| BasicBlock GetEndBasicBlock() const                        | 返回最后一个基块 |
175| std::vector<BasicBlock> GetBasicBlockList() const          | 返回所有基块 |
176| void VisitAllInstructions(const InstVisitor visitor) const | 遍历所有指令 |
177
178### 4.6 `BasicBlock`
179
180| 接口名及参数 | 描述 |
181| ----------- | ---- |
182| std::vector\<BasicBlock\> GetPredBlocks() const | 返回前驱基块 |
183| std::vector\<BasicBlock\> GetSuccBlocks() const | 返回后继基块 |
184| std::vector\<Inst\> GetInstList() const         | 返回基块中所有指令 |
185
186### 4.7 `Inst`
187| 接口名及参数 | 描述 |
188| ----------- | ---- |
189| InstType GetType() const                   | 返回指令类型 |
190| bool IsInstStLexVar() const                | 返回指令是否为`stlexvar`类型 |
191| bool IsInstLdLexVar() const                | 返回指令是否为`ldlexvar`类型 |
192| bool IsInstStGlobal() const                | 返回指令是否为`stglobalvar`类型 |
193| bool IsInstLdGlobal() const                | 返回指令是否为`ldglobalvar`类型 |
194| uint32_t GetPc() const                     | 返回指令的程序计数器 |
195| BasicBlock GetBasicBlock() const           | 返回该指令所属的基块 |
196| Graph GetGraph() const                     | 返回该指令所属的基块所属的图 |
197| std::vector\<Inst\> GetInputInsts() const  | 返回该指令的输入指令 |
198| std::vector\<Inst\> GetUserInsts() const   | 返回将该指令作为输入的指令 |
199
200## 5.已知问题
201### 5.1 `Try catch`块包含`throw`语法的场景中构图存在问题
202对于如下在`Try catch`块中包含`throw`语法的示例,
203```javascript
204try {
205  throw 1;
206} catch (e) {
207}
208```
209正确的基块结构简化后如下所示,即`Throw Block`的后继为`Catch Block`。
210```
211+----------------+       +----------------+
212|   Start Block  | ----> |  Throw Block   |
213+----------------+       +----------------+
214                                 |
215                                 v
216                         +----------------+
217                         |  Catch Block   |
218                         +----------------+
219                                 |
220                                 v
221                         +----------------+
222                         |   End Block    |
223                         +----------------+
224```
225
226但是,当前实现会将`Throw Block`指向当前函数的结束块,导致某些场景下`Catch Block`块没有前驱,简化后的基块结构如下所示:
227```
228+----------------+       +----------------+
229|   Start Block  | ----> |  Throw Block   | ------
230+----------------+       +----------------+      |
231                                                 |
232                         +----------------+      |
233                         |  Catch Block   |      |
234                         +----------------+      |
235                                 |               |
236                                 v               |
237                         +----------------+      |
238                         |    End Block   | <-----
239                         +----------------+
240```
241
242### 5.2 接口所提供的类的继承关系和函数调用关系等不完全准确
243
244由于不存在完美的静态分析,本工具所提供的类的继承关系和函数调用关系接口(如`GetCaller`和`GetCalleee`)等为尽力分析的结果,但可能并不完全准确。
245
246开发者可根据构图和指令等确定的信息,定制化进行更准确地漏洞扫描分析。