本文旨在保证"抽丝剥茧代码属性图CPG"系列文章的完整性,笔者认为图数据库****Neo4j也是该系列中不可或缺的一部分,本文起到一个抛砖引玉的作用,后续大概率会对CPG中的Neo4j做详细的讲解,大家敬请期待~
为什么要写CPG中的Neo4j呢,在花大把时间肝完CPG中的DFG(Data Flow Graph)后,笔者闲下来再去回顾这些东西时,虽然写得很全面也很细节了, 但看起来还不是那么的直观,尤其是验证各条边的构建过程时,必须在特定代码场景下debug调试,然后从程序断点处寻找我们想要的DFG信息,想必大家在阅读过程中也是比较痛苦的。
基于上述原因,再加上CPG自身集成了图数据库Neo4j,其支持把翻译后的产物TranslationResult
序列化到数据库,然后我们就可以通过Neo4j Browser直观地看到生成的图了,各节点间的关系,各节点间连接着什么边,节点都有哪些属性等等以图的形式呈现,一目了然,对读者极其友好。
所以嘞,笔者打算以后的文章中若涉及到验证或者是需要看CPG的构建效果时,直接给大家上图!
大家可以先看一张图,直观地感受一下图形化展示的效果(此图不是完整的图,是笔者本地测试的一张图,主要是让大家感受下neo4j带来的便利)。
红色的边都是DFG边(neo4j browser提供的渲染,可自定义样式),另外,节点是什么类型,其有哪些属性都可以点击节点,直观地看到。
Neo4j 是一款高性能的、开源的 NoSQL 图形数据库。其采用图形数据模型,将数据表示为节点、关系以及节点之间的连接,并且节点及关系都可以携带属性来扩充信息,非常适合那些需要揭示复杂数据间隐含关系的应用场景。其存储的内容如下:
Node 节点
Relationship 节点间的关系
Property 节点属性
使用Cypher查询语言
支持完整的ACID事务特性(原子性,一致性,隔离性和持久性)
支持将查询的数据导出为JSON和XSL格式
提供REST API,可以被任何编程语言访问
解压后进入bin文件夹下,执行如下命令:
`neo4j.bat console `
如下效果即执行成功
输入默认账号neo4j,默认密码neo4j,然后再修改密码后即可正常访问。
tips:需先本地安装neo4j,并启动neo4j服务
`// 克隆cpg到本地 git clone https://github.com/Fraunhofer-AISEC/cpg.git // 进入cpg-neo4j目录 cd cpg/cpg-neo4j //gradle 构建 gralde installDist `
构建完成后,会在build/install/cpg-neo4j/bin
目录下生成打包好的可执行文件
cpg-neo4j
cpg-neo4j.bat
命令行调用可执行程序:
`./build/install/cpg-neo4j/bin/cpg-neo4j [--infer-nodes] [--load-includes] [--no-default-passes] [--no-neo4j] [--no-purge-db] [--print-benchmark] [--use-unity-build] [--benchmark-json=<benchmarkJson>] [--custom-pass-list=<customPasses>] [--export-json=<exportJsonFile>] [--host=<host>] [--includes-file=<includesFile>] [--password=<neo4jPassword>] [--port=<port>] [--save-depth=<depth>] [--top-level=<topLevel>] [--user=<neo4jUsername>] ([<files>...] | -S=<String=String> [-S=<String=String>]... | --json-compilation-database=<jsonCompilationDatabase> | --list-passes) [<files>...] The paths to analyze. If module support is enabled, the paths will be looked at if they contain modules --benchmark-json=<benchmarkJson> Save benchmark results to json file --custom-pass-list=<customPasses> Add custom list of passes (includes --no-default-passes) which is passed as a comma-separated list; give either pass name if pass is in list, or its FQDN (e.g. --custom-pass-list=DFGPass,CallResolver) --export-json=<exportJsonFile> Export cpg as json --host=<host> Set the host of the neo4j Database (default: localhost). --includes-file=<includesFile> Load includes from file --infer-nodes Create inferred nodes for missing declarations --json-compilation-database=<jsonCompilationDatabase> The path to an optional a JSON compilation database --list-passes Prints the list available passes --load-includes Enable TranslationConfiguration option loadIncludes --no-default-passes Do not register default passes [used for debugging] --no-neo4j Do not push cpg into neo4j [used for debugging] --no-purge-db Do no purge neo4j database before pushing the cpg --password=<neo4jPassword> Neo4j password (default: password --port=<port> Set the port of the neo4j Database (default: 7687). --print-benchmark Print benchmark result as markdown table -S, --softwareComponents=<String=String> Maps the names of software components to their respective files. The files are separated by commas (No whitespace!). Example: -S App1=./file1.c,./file2.c -S App2=. /Main.java,./Class.java --save-depth=<depth> Performance optimisation: Limit recursion depth form neo4j OGM when leaving the AST. -1 (default) means no limit is used. --top-level=<topLevel> Set top level directory of project structure. Default: Largest common path of all source files --use-unity-build Enable unity build mode for C++ (requires --load-includes) --user=<neo4jUsername> Neo4j user name (default: neo4j) `
我们需要注意以下参数:
--host neo4j服务器(默认localhost)
--port 服务器端口(默认7687)
--user neo4j用户名(默认 neo4j)
--password neo4j密码(默认 password)
--export-json 是否输出json格式的结果
--no-neo4j 不将结果push至neo4j数据库
使用示例:(其余参数默认即可)
`.\cpg-neo4j D:\Example.java --password yourPassword`
有如下响应证明TranslationResult
已成功push至neo4j
然后,就可以访问**http://localhost:7474/browser**查看CPG翻译后的代码属性图了
`@Test @Throws(InterruptedException::class) fun myNeo4jTest() { val cmd = CommandLine(Application::class.java) cmd.parseArgs("Example.java") val application = cmd.getCommand<Application>() val translationConfiguration = application.setupTranslationConfiguration() val translationResult = TranslationManager.builder().config(translationConfiguration).build().analyze().get() application.pushToNeo4j(translationResult) } `
当然,你也可以参考CPG的测试代码进行修改:cpg-neo4j/src/test/kotlin/de/fraunhofer/aisec/cpg_vis_neo4j/Neo4JTest.kt
代码属性图CPG系列文章(白盒/静态代码分析方向):超万字的详细讲解,文章理论与实践相结合,示例代码可拿来即用,通俗易懂,这样的文章你爱了吗!
社群大佬云集,可与各领域大咖面对面交流技术
定期做优质技术分享,提升自己的技术能力
自我提升,不仅限于技术,还有圈子
与笔者交个朋友
点击公众号底部菜单栏“点击进群”,扫码加笔者好友(备注"进群")
能够看到这篇文章,就是我们的缘分,坚持输出优质内容是笔者一直在做的事情。若文章对你有帮助,感谢点个免费的 点赞、在看,大家的鼓励是我最大的动力
关注我,交个朋友~