Name |
Date |
Size |
#Lines |
LOC |
||
---|---|---|---|---|---|---|
.. | - | - | ||||
include/ | 12-May-2024 | - | 628 | 434 | ||
templates/ | 12-May-2024 | - | 48 | 40 | ||
tests/unittest/ | 12-May-2024 | - | 1,407 | 1,004 | ||
BUILD.gn | D | 12-May-2024 | 3.1 KiB | 97 | 81 | |
README.md | D | 12-May-2024 | 13.2 KiB | 209 | 170 | |
abc_file.cpp | D | 12-May-2024 | 60.3 KiB | 1,474 | 1,342 | |
callee_info.cpp | D | 12-May-2024 | 2.4 KiB | 113 | 81 | |
class.cpp | D | 12-May-2024 | 2.8 KiB | 118 | 85 | |
function.cpp | D | 12-May-2024 | 3.8 KiB | 161 | 124 | |
graph.cpp | D | 12-May-2024 | 5.2 KiB | 209 | 165 | |
module_record.cpp | D | 12-May-2024 | 3.7 KiB | 132 | 101 |
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平台上编译和使用,暂不支持Windows/Mac平台。 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``` 40./build.sh --product-name rk3568 --build-target ark_host_linux_defectscanaux_lib --build-target ark_host_linux_defectscanaux_unittest 41``` 42 43`out/rk3568/clang_x64/arkcompiler/runtime_core`目录下会生成`libark_defect_scan_aux.so`以及该示例文件对应的可执行程序文件。 44 45### 3.4 如何生成`abc`文件 46 47#### 3.4.1 使用命令行 48参考《[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`文件。 49 50#### 3.4.2 使用DevEco Studio 51通过DevEco Studio编译应用,编译成功后,解压应用`hap`包,找到其中的`abc`文件。 52 53### 3.5 执行扫描 54 55将需要扫描的`abc`文件放到示例代码中指定的文件路径后,执行示例代码对应的可执行程序即可。 56 57```shell 58cd out/rk3568/clang_x64/arkcompiler/runtime_core 59./defect_scan_aux_demo 60``` 61 62## 4.接口说明 63 64### 4.1 `AbcFile` 65 66| 接口名及参数 | 描述 | 67| ----------- | ---- | 68| static std::unique_ptr\<const AbcFile\> Open(std::string_view abc_filename) | 根据文件名打开方舟字节码文件并返回该文件 | 69| bool IsMergeAbc() const | 返回方舟字节码文件是否为合并格式 | 70| const std::set\<std::string\> GetFileRecordList() const | 若为合并abc,返回所有文件描述名 | 71| size_t GetFileRecordCount() const | 若为合并abc,返回abc中的文件个数 | 72| const std::string &GetAbcFileName() const | 返回方舟字节码文件的名称 | 73| const std::vector\<std::shared_ptr\<Class\>\> &GetClassList() const | 返回包含所有类的列表 | 74| size_t GetDefinedFunctionCount() const | 返回定义的函数个数 | 75| size_t GetDefinedClassCount() const | 返回定义的类的个数 | 76| const Function \*GetFunctionByName(std::string_view func_name) const | 根据名称返回指定函数 | 77| const Function \*GetExportFunctionByExportName(std::string_view export_func_name, std::string_view record_name = "") const | 根据导出名返回指定的导出函数,若为合并abc,需指定文件描述名 | 78| const Class \*GetClassByName(std::string_view class_name) const | 根据类名返回指定类 | 79| const Class \*GetExportClassByExportName(std::string_view export_class_name, std::string_view record_name = "") const | 根据导出名返回指定的导出类,若为合并abc,需指定文件描述名 | 80| size_t GetLineNumberByInst(const Function \*func, const Inst &inst) const | 根据指令返回该指令对应源码的行号 | 81| std::string GetLocalNameByExportName(std::string_view export_name, std::string_view record_name = "") const | 根据变量的导出名返回其本地的名称,若为合并abc,需指定文件描述名 | 82| std::string GetImportNameByExportName(std::string_view export_name, std::string_view record_name = "") const | 根据变量的导出名返回其导入的名称,若为合并abc,需指定文件描述名 | 83| std::string GetModuleNameByExportName(std::string_view export_name, std::string_view record_name = "") const | 根据变量的导出名返回导入该变量的模块名,若为合并abc,需指定文件描述名 | 84| std::string GetModuleNameByLocalName(std::string_view local_name, std::string_view record_name = "") const | 根据变量的本地名返回导入该变量的模块名,若为合并abc,需指定文件描述名 | 85| std::string GetImportNameByLocalName(std::string_view local_name, std::string_view record_name = "") const | 根据变量的本地名返回该变量的导入名,若为合并abc,需指定文件描述名 | 86 87### 4.2 `Function` 88 89| 接口名及参数 | 描述 | 90| ----------- | ---- | 91| const std::string &GetFunctionName() const | 返回函数名 | 92| const AbcFile \*GetAbcFileInstance() const | 返回该函数所在的方舟字节码文件 | 93| const std::string &GetRecordName() const | 若为合并abc,返回该函数所在的文件描述名 | 94| const Graph &GetGraph() const | 返回该函数的构图 | 95| const Class \*GetClass() const | 返回定义该函数的类 | 96| const Function \*GetParentFunction() const | 返回定义该函数的函数 | 97| uint32_t GetArgCount() const | 返回参数个数 | 98| size_t GetDefinedClassCount() const | 返回函数中定义的类的个数 | 99| size_t GetDefinedFunctionCount() const | 返回函数中定义的函数的个数 | 100| size_t GetCalleeInfoCount() const | 返回调用信息的个数 | 101| const CalleeInfo \*GetCalleeInfoByCallInst(const Inst &call_inst) const | 根据调用指令返回调用信息 | 102 103### 4.3 `Class` 104 105| 接口名及参数 | 描述 | 106| ----------- | ---- | 107| const std::string &GetClassName() const | 返回类名 | 108| const AbcFile *GetAbcFileInstance() const | 返回该类所在的方舟字节码文件 | 109| const std::string &GetRecordName() const | 若为合并abc,返回该类所在的文件描述名 | 110| Function *GetDefiningFunction() const | 返回定义该类的函数 | 111| size_t GetMemberFunctionCount() const | 返回成员函数的数量 | 112| const Function *GetMemberFunctionByName(std::string_view func_name) const | 根据名称返回成员函数 | 113| const std::vector<const Function *> &GetMemberFunctionList() const | 返回所有成员函数 | 114| const Class *GetParentClass() const | 返回父类 | 115| const std::string &GetParentClassName() const | 返回父类名 | 116| const std::string &GetParClassExternalModuleName() const | 返回导入父类的模块名 | 117| const std::string &GetParClassGlobalVarName() const | 返回父类的全局变量名 | 118 119### 4.4 `CalleeInfo` 120 121| 接口名及参数 | 描述 | 122| ----------- | ---- | 123| int GetCalleeArgCount() const | 返回该被调者的参数个数 | 124| const Inst &GetCallInst() const | 返回该被调者相关的调用指令 | 125| const Function \*GetCaller() const | 返回该被调者的调用者 | 126| const Class \*GetClass() const | 返回该被调者所在的类 | 127| const Function \*GetCallee() const | 返回该被调者的对应函数 | 128| const std::string &GetFunctionName() const | 返回该被调者的函数名 | 129| const std::string &GetClassName() const | 返回该被调者所在的类名 | 130| const std::string &GetExternalModuleName() const | 返回导入该被调者的模块名 | 131| const std::string &GetGlobalVarName() const | 返回该被调者所在的全局变量名 | 132 133### 4.5 `Graph` 134| 接口名及参数 | 描述 | 135| ----------- | ---- | 136| BasicBlock GetStartBasicBlock() const | 返回第一个基块 | 137| BasicBlock GetEndBasicBlock() const | 返回最后一个基块 | 138| std::vector<BasicBlock> GetBasicBlockList() const | 返回所有基块 | 139| void VisitAllInstructions(const InstVisitor visitor) const | 遍历所有指令 | 140 141### 4.6 `BasicBlock` 142 143| 接口名及参数 | 描述 | 144| ----------- | ---- | 145| std::vector\<BasicBlock\> GetPredBlocks() const | 返回前驱基块 | 146| std::vector\<BasicBlock\> GetSuccBlocks() const | 返回后继基块 | 147| std::vector\<Inst\> GetInstList() const | 返回基块中所有指令 | 148 149### 4.7 `Inst` 150| 接口名及参数 | 描述 | 151| ----------- | ---- | 152| InstType GetType() const | 返回指令类型 | 153| bool IsInstStLexVar() const | 返回指令是否为`stlexvar`类型 | 154| bool IsInstLdLexVar() const | 返回指令是否为`ldlexvar`类型 | 155| bool IsInstStGlobal() const | 返回指令是否为`stglobalvar`类型 | 156| bool IsInstLdGlobal() const | 返回指令是否为`ldglobalvar`类型 | 157| uint32_t GetPc() const | 返回指令的程序计数器 | 158| BasicBlock GetBasicBlock() const | 返回该指令所属的基块 | 159| Graph GetGraph() const | 返回该指令所属的基块所属的图 | 160| std::vector\<Inst\> GetInputInsts() const | 返回该指令的输入指令 | 161| std::vector\<Inst\> GetUserInsts() const | 返回将该指令作为输入的指令 | 162 163## 5.已知问题 164### 5.1 `Try catch`块包含`throw`语法的场景中构图存在问题 165对于如下在`Try catch`块中包含`throw`语法的示例, 166```javascript 167try { 168 throw 1; 169} catch (e) { 170} 171``` 172正确的基块结构简化后如下所示,即`Throw Block`的后继为`Catch Block`。 173``` 174+----------------+ +----------------+ 175| Start Block | ----> | Throw Block | 176+----------------+ +----------------+ 177 | 178 v 179 +----------------+ 180 | Catch Block | 181 +----------------+ 182 | 183 v 184 +----------------+ 185 | End Block | 186 +----------------+ 187``` 188 189但是,当前实现会将`Throw Block`指向当前函数的结束块,导致某些场景下`Catch Block`块没有前驱,简化后的基块结构如下所示: 190``` 191+----------------+ +----------------+ 192| Start Block | ----> | Throw Block | ------ 193+----------------+ +----------------+ | 194 | 195 +----------------+ | 196 | Catch Block | | 197 +----------------+ | 198 | | 199 v | 200 +----------------+ | 201 | End Block | <----- 202 +----------------+ 203``` 204 205### 5.2 接口所提供的类的继承关系和函数调用关系等不完全准确 206 207由于不存在完美的静态分析,本工具所提供的类的继承关系和函数调用关系接口(如`GetCaller`和`GetCalleee`)等为尽力分析的结果,但可能并不完全准确。 208 209开发者可根据构图和指令等确定的信息,定制化进行更准确地漏洞扫描分析。