AppThreat/atom
GitHub: AppThreat/atom
atom 是一种应用程序中间表示工具,将多语言源码转化为优化的图网络结构,支持数据流分析、程序切片和可达性查询,服务于安全分析、供应链追踪和代码摘要等场景。
Stars: 95 | Forks: 9
# atom (⚛)
atom 是一种用于应用程序的新型中间表示,也是一个由 [chen](https://github.com/AppThreat/chen) 库支持的独立工具。这种中间表示(一个包含节点和链接的网络)针对应用程序分析和机器学习中常用的操作(包括[切片](./specification/docs/slices.md)和向量化)进行了优化。
我们的愿景是让 atom 能够适用于多种用例,例如:
- **供应链分析:** 生成外部库使用的证据,包括从数据源到数据汇的数据流。atom 被 [OWASP cdxgen](https://github.com/CycloneDX/cdxgen) 使用,以提高生成的 CycloneDX 文档的精确性和全面性。
- **漏洞分析:** 通过受影响的符号、调用路径和数据流的证据来描述漏洞。实现大规模的变体分析和[可达性分析](https://github.com/AppThreat/atom/blob/main/specification/docs/slices.md#reachables-slice)。
- **漏洞利用预测:** 利用漏洞、库和应用程序的精确表示来预测漏洞利用。
- **威胁模型和攻击向量生成:** 大规模地为应用程序生成精确的威胁模型和攻击向量。
- **应用程序上下文检测:** 生成可用于摘要生成和风险画像创建的上下文(例如,服务、端点和数据属性)。
- **应用程序的思维导图:** 作为一种开发人员工具,自动对大型和复杂的应用程序进行摘要。
以及其他更多用例。
[](https://github.com/cdxgen/cdxgen)


## 支持的语言
- C/C++
- H (仅限 C/C++ Header 和预处理过的 .i 文件)
- Java (需要编译)
- Jar
- Android APK 和拆分包 (.apkm, .apks, .xapk)。需要 Android SDK。设置环境变量 `ANDROID_HOME` 或使用容器镜像。
- JavaScript
- Flow
- TypeScript
- Python (支持 3.x 到 3.13)
- PHP (需要 PHP >= 7.4。支持 PHP 7.0 到 8.4,对 PHP 5.x 的支持有限)
- Ruby (需要 Ruby 4.0.x。支持 Ruby 1.8 - 4.0.x 语法)
- Scala (WIP)
## 安装说明
atom 包含一个带有 Node.js 包装模块的 scala 核心。目前它作为 npm 包分发。
```
npm install -g @appthreat/atom @appthreat/atom-parsetools
atom --help
```
安装 cdxgen npm 包以生成软件物料清单 (SBOM),这是进行 reachables 切片所必需的。
```
npm install -g @cyclonedx/cdxgen --omit=optional
```
## 容器使用
```
docker run --rm -v /tmp:/tmp -v $HOME:$HOME -v $(pwd):/app:rw -t ghcr.io/appthreat/atom atom --help
# podman run --rm -v /tmp:/tmp -v $HOME:$HOME -v $(pwd):/app:rw -t ghcr.io/appthreat/atom atom --help
```
Java 项目的示例。
```
docker run --rm -v /tmp:/tmp -v $HOME:$HOME -v $(pwd):/app:rw -t ghcr.io/appthreat/atom atom -l java -o /app/app.atom /app
# podman run --rm -v /tmp:/tmp -v $HOME:$HOME -v $(pwd):/app:rw -t ghcr.io/appthreat/atom atom -l java -o /app/app.atom /app
```
## atom native-image (仅供高级用户使用)
```
curl -LO https://github.com/AppThreat/atom/releases/latest/download/atom-amd64
chmod +x atom-amd64
./atom-amd64 --help
```
在 Windows 上
```
curl -LO https://github.com/AppThreat/atom/releases/latest/download/atom.exe
.\atom.exe --help
```
注意:诸如 astgen、rbastgen、phpastgen 等命令并未捆绑在此 native image 中。请安装 npm 包 `@appthreat/atom-parsetools` 来获取这些命令。
```
npm install -g @appthreat/atom-parsetools
which astgen
which phpastgen
```
## CLI 用法
```
Usage: atom [parsedeps|data-flow|usages|reachables|export|algorithms] [options] [input]
input source file or directory
-o, --output output filename. Default app.⚛ or app.atom in windows
-s, --slice-outfile
export intra-procedural slices as json
-l, --language source language
--frontend-args Advanced frontend configuration (key=value). E.g. --frontend-args defines=DEBUG,cpp-standard=c++17
--with-data-deps generate the atom with data-dependencies - defaults to `false`
--remove-atom do not persist the atom file - defaults to `false`
--reuse-atom reuse existing atom file - defaults to `false`
-x, --export-atom export the atom file with data-dependencies to graphml - defaults to `false`
--export-dir export directory. Default: atom-exports
--file-filter the name of the source file to generate slices from. Uses regex.
--method-name-filter
filters in slices that go through specific methods by names. Uses regex.
--method-parameter-filter
filters in slices that go through methods with specific types on the method parameters. Uses regex.
--method-annotation-filter
filters in slices that go through methods with specific annotations on the methods. Uses regex.
--max-num-def maximum number of definitions in per-method data flow calculation - defaults to 2000
--legacy-dataflow use the classic data-flow engine and disable mini-graph fragment caching and method flow summaries. By default atom uses the faster, lower-allocation Flux engine with fragment caching and summary-guided pruning enabled.
--validation-config path to a JSON file declaring validators/sanitisers (chennai.json schema). Reachable flows passing through a declared sanitiser are dropped for its categories.
Command: parsedeps
Extract dependencies from the build file and imports
Command: data-flow [options]
Extract backward data-flow slices
--slice-depth the max depth to traverse the DDG for the data-flow slice - defaults to 7.
--sink-filter filters on the sink's `code` property. Uses regex.
Command: usages [options]
Extract local variable and parameter usages
--min-num-calls the minimum number of calls required for a usage slice - defaults to 1.
--include-source includes method source code in the slices - defaults to false.
--extract-endpoints extract http endpoints and convert to openapi format using atom-tools - defaults to false.
Command: reachables [options]
Extract reachable data-flow slices based on automated framework tags
--source-tag source tag - defaults to framework-input. Comma-separated values allowed.
--sink-tag sink tag - defaults to framework-output. Comma-separated values allowed.
--include-crypto includes crypto library flows - defaults to false.
Command: export [options]
Export the atom to a graph format (dot, graphml, gexf, graphson, neo4jcsv, gnn)
--format export format: dot, graphml, gexf, graphson, neo4jcsv or gnn
--scope export scope: whole or methods. Default: whole
--out output directory. Default: atom-exports
Command: algorithms [options]
Run a graph algorithm over the atom and write the result as JSON
--type algorithm: scc, toposort, dominators, paths or centrality
--source source method full-name pattern for the paths algorithm. Uses regex.
--target target method full-name pattern for the paths algorithm. Uses regex.
--max-depth maximum path depth for the paths algorithm
--config path to a JSON config file for the export and algorithms commands
--help display this help message
```
## export 和 algorithms 命令
`export` 和 `algorithms` 命令作用于 `.atom` 文件。如果使用 `-o` 指定的文件已经存在,则会被重用;否则 atom 会首先从输入构建它,因此无需记住单独的构建步骤。
`export` 会以多种格式之一写入图。使用 `--scope whole` 导出整个 atom,或者使用 `--scope methods` 为每个方法写入一个文件(除了 neo4jcsv 之外,每种格式都支持按方法作用域)。`gnn` 格式将并行的 id、label 和 edge 数组以 JSON 格式写入,适用于机器学习流水线。
```
atom export -l python --format graphml --scope whole -o app.atom --out exports app.py
atom export -l python --format gnn --scope methods -o app.atom --out gnn-out app.py
```
`algorithms` 运行图算法并将结果以 JSON 格式写入切片输出文件:
- `centrality` 根据 PageRank 和入度对调用图中的方法进行排名。
- `scc` 报告强连通分量,这可以标记调用图中的递归。
- `toposort` 返回方法的被调用者先于调用者的顺序。递归方法会被分阶段分组(每个都标记为递归),这样即使调用图包含循环,排序也能正常工作。
- `dominators` 写入每个方法的控制流支配树。
- `paths` 查找通过正则表达式选择的源方法和目标方法之间的路径。
```
atom algorithms -l python --type centrality -o app.atom -s centrality.json app.py
atom algorithms -l python --type paths --source '.*main$' --target '.*helper$' -o app.atom -s paths.json app.py
```
可以通过 `--config `(一个 JSON 文件)提供冗长或可重复的参数。命令行标志会覆盖文件中的值。例如,一个 algorithms 配置文件:
```
{
"type": "paths",
"source": ".*main$",
"target": ".*helper$",
"maxDepth": 20,
"out": "paths.json"
}
```
## 数据流引擎
atom 默认使用 **Flux** 引擎 (*Flow-Lattice Update eXecutor*) 计算数据依赖关系——这是一个低分配的到达定值求解器,它能生成与经典引擎相同的 `REACHING_DEF` 边,同时在处理大型(例如打包/转译过的 JavaScript)方法时占用更少的内存和 GC 时间。默认情况下也会启用按文件的迷你图(片段)AST 缓存,因此未更改的文件会从 `.chen` 缓存中恢复,而不是重新解析。
传递 `--legacy-dataflow` 以回退到经典引擎并禁用片段缓存(这对于 A/B 比较或故障排除很有用)。还可以通过 `-Dchen.cache.disabled=true` 系统属性独立控制缓存。
### 存储压缩 (`-Dodb.storage.compression`)
在大型代码库中,图会溢出堆内存,未使用的节点会被转储到磁盘;转储/保存路径在单线程上运行,因此它使用的压缩器会主导生成和切片时间。通过系统属性选择它(无需重新构建):
```
atom ... -Dodb.storage.compression=none|lzf|deflate
```
- `deflate` (**默认**) — 最慢但生成的 `.atom` 最小;之所以设为默认,是因为在大型代码库中 atom 文件的大小最为重要。
- `lzf` — 快速压缩;最适合溢出堆内存的大型图,在这些图中 DEFLATE 占用了大量的生成/切片时间。
- `none` — 无压缩;转储最快,生成的 `.atom` 最大。
压缩器是按块记录的,因此使用任何模式写入的 atom 在任何其他模式下仍然可读(一个 `lzf` atom 在 `deflate` 默认模式下也能正常加载)。给 JVM 更多的堆内存 (`-Xmx`) 也会减少转储——最省事的办法就是根本不发生溢出。
## 方法流摘要
`reachables` 命令在运行反向查询之前,会为每个方法构建一个与上下文无关的流摘要。摘要记录了方法的哪些参数会到达其返回值或输出参数。reachables 引擎使用这些摘要来跳过那些经证明不会携带污点的跨调用工作,例如探索被调用者从未写入的参数,或者深入其返回值不可能携带污点的被调用者。这种修剪只会移除空的工作,因此报告的流与不使用摘要运行的结果完全相同。
方法流摘要属于默认的 Flux 包的一部分——没有单独的标志。只要使用了 Flux 引擎(默认情况),它们就会被启用,并且只有在指定 `--legacy-dataflow` 时才会被关闭,这也会同时恢复到经典的数据流引擎。
摘要通过两种方式持久化:作为每个 `METHOD` 节点上的 CPG 原生 `flow-summary` 标签(这样它们就会随 atom 序列化,并在重用/缓存 atom 时被免费重用),以及作为位于 atom 旁边的 `flowsummary-.json` 伴随文件,用于不带标签的运行。当任何方法体发生改变时,指纹也会随之改变。与其他缓存一样,可以通过 `-Dchen.cache.disabled=true` 关闭摘要缓存。
```
atom reachables -o app.atom -s reachables.json -l java .
```
## 验证器和净化器
经过真正的验证或净化例程的可达流通常不是真正的发现。你可以在 JSON 文件中声明此类例程,并使用 `--validation-config` 传递。atom 会将每一个对已声明方法的调用标记为净化器,并丢弃经过它们的可达流,其作用范围仅限于该净化器覆盖的数据汇类别。
该文件使用与 `chennai.json` 相同的 schema。`sanitizers` 和 `validators` 的处理方式完全相同;`categories` 是可选的,如果省略,净化器将覆盖每一个流:
```
{
"sanitizers": [
{
"name": "owasp-encode",
"methods": ["org\\.owasp\\.encoder\\.Encode\\..*"],
"categories": ["http"]
},
{
"name": "sql-escape",
"methods": [".*escapeSql.*"],
"categories": ["sql"]
}
],
"validators": [{ "name": "bean-validation", "methods": [".*\\.validate"] }]
}
```
`methods` 条目会与每个调用的方法全名进行匹配(如果包含正则表达式字符,则被视为正则表达式;否则视为精确匹配)。`categories` 会与流的数据汇上的标签进行匹配,因此为 `http` 声明的 HTML 编码器不会抑制 SQL 注入流。
```
atom reachables --validation-config validators.json -o app.atom -s reachables.json -l java .
```
这些声明也可以嵌入到项目的 `chennai.json` 中,而不是在命令行上传递。对于编程式使用,数据流引擎在流迭代器上暴露了 `passesThrough` / `doesNotPassThrough` 方法,接受一个简单的节点谓词。
## 调用示例
### 生成 atom
```
# 编译 java 项目
atom -o app.atom -l java .
```
```
atom -o app.atom -l jar
```
```
export ANDROID_HOME=
atom -o app.atom -l apk
```
也支持拆分包。`.apkm`、`.apks` 或 `.xapk` 文件会自动解压,并分析包含 dalvik 字节码的 apk。
```
export ANDROID_HOME=
atom -o app.atom -l apk
```
在对 Android apk 进行切片时,atom 会在代码属性图上运行 chen 的 Android 标记阶段。这些阶段会为可达切片中的流附加语义标签,包括个人身份信息(如 `pii-email` 和 `pii-device-id`)、受监管的数据(如 `pci-dss`、`gdpr` 和 `phi-medical`)、机密信息、标记为 `tracker` 的第三方追踪器,以及标记为 `service-egress`、`service-ingress` 和 `on-device-ai` 的网络方向。atom-tools 会使用这些标签来归属可达服务,并丰富由 blint 生成的 CycloneDX SBOM。
### 为 Java 项目创建 reachables 切片。
```
cd
cdxgen -t java --deep -o bom.json .
atom reachables -o app.atom -s reachables.json -l java .
```
传递参数 `--reuse-atom` 可基于现有的 atom 文件进行切片。
```
atom reachables --reuse-atom -o app.atom -s reachables.json -l java .
```
基于容器调用的示例。
```
docker run --rm -v /tmp:/tmp -v $HOME:$HOME -v $(pwd):/app:rw -t ghcr.io/appthreat/atom atom reachables -l java -o /app/app.atom -s /app/reachables.slices.json /app
# podman run --rm -v /tmp:/tmp -v $HOME:$HOME -v $(pwd):/app:rw -t ghcr.io/appthreat/atom atom reachables -l java -o /app/app.atom -s /app/reachables.slices.json /app
```
### 为 Java 项目创建 usages 切片。
```
atom usages -o app.atom --slice-outfile usages.json -l java .
```
使用基于容器调用的 Ruby 4 项目示例。
```
docker run --rm -v /tmp:/tmp -v $(pwd):/app:rw -t ghcr.io/appthreat/atom atom usages -l ruby -o /app/app.atom -s /app/usages.slices.json /app
# podman run --rm -v /tmp:/tmp -v $(pwd):/app:rw -t ghcr.io/appthreat/atom atom usages -l ruby -o /app/app.atom -s /app/usages.slices.json /app
```
如果在 arm64 架构上遇到 Java 或 Ruby 构建问题,请传递参数 `--platform=linux/amd64`。
```
docker run --rm --platform=linux/amd64 -v /tmp:/tmp -v $(pwd):/app:rw -t ghcr.io/appthreat/atom atom usages -l ruby -o /app/app.atom -s /app/usages.slices.json /app
# podman run --rm --platform=linux/amd64 -v /tmp:/tmp -v $(pwd):/app:rw -t ghcr.io/appthreat/atom atom usages -l ruby -o /app/app.atom -s /app/usages.slices.json /app
```
对于 Ruby 4,提供了一个基于 alpine 的版本。
```
docker run --rm -v /tmp:/tmp -v $(pwd):/app:rw -t ghcr.io/appthreat/atom-alpine-ruby atom usages --extract-endpoints -l ruby -o /app/app.atom -s /app/usages.slices.json /app
# podman run --rm -v /tmp:/tmp -v $(pwd):/app:rw -t ghcr.io/appthreat/atom-alpine-ruby atom usages --extract-endpoints -l ruby -o /app/app.atom -s /app/usages.slices.json /app
```
Alpine 也提供了 Ruby 3 的变体。
```
docker run --rm -v /tmp:/tmp -v $(pwd):/app:rw -t ghcr.io/appthreat/atom-alpine-ruby3 atom usages --extract-endpoints -l ruby -o /app/app.atom -s /app/usages.slices.json /app
# podman run --rm -v /tmp:/tmp -v $(pwd):/app:rw -t ghcr.io/appthreat/atom-alpine-ruby3 atom usages --extract-endpoints -l ruby -o /app/app.atom -s /app/usages.slices.json /app
```
### 为 Java 项目创建 data-flow 切片。
了解更多关于[切片](./specification/docs/slices.md)的信息,或查看一些[示例](https://github.com/AppThreat/atom-samples)
### 使用 atom-tools 提取 openapi 格式的 HTTP 端点
atom 可以自动调用 [atom-tools](https://github.com/AppThreat/atom-tools) 的 `convert` 命令,从 usages 切片中提取 http 端点。传递参数 `--extract-endpoints` 来启用此功能。
```
pip install atom-tools
atom usages --extract-endpoints -o app.atom --slice-outfile usages.json -l java .
```
会创建一个包含端点信息的 `openapi.json` 文件。使用环境变量 `ATOM_TOOLS_OPENAPI_FILENAME` 自定义文件名。
```
ATOM_TOOLS_OPENAPI_FILENAME=openapi.json atom usages --extract-endpoints -o app.atom --slice-outfile usages.json -l ruby .
```
基于容器的调用:
```
docker run --rm -v /tmp:/tmp -e ATOM_TOOLS_OPENAPI_FILENAME=openapi.json -v $(pwd):/app:rw -t ghcr.io/appthreat/atom atom usages --extract-endpoints -l ruby -o /app/app.atom -s /app/usages.slices.json /app
# podman run --rm -v /tmp:/tmp -e ATOM_TOOLS_OPENAPI_FILENAME=openapi.json -v $(pwd):/app:rw -t ghcr.io/appthreat/atom atom usages --extract-endpoints -l ruby -o /app/app.atom -s /app/usages.slices.json /app
```
### 将 atom 导出为 graphml 或 dot 格式
可以将 atom 中的每个方法及其数据依赖关系导出为 graphml 或 dot 格式。只需传递 `--export` 即可启用此功能。
```
atom -o app.atom -l java --export-atom --export-dir
```
生成的 graphml 文件可以导入到 [Neo4j](https://neo4j.com/labs/apoc/4.1/import/graphml/) 或 NetworkX 中进行进一步分析。使用参数 `--export-format` 指定为 dot 格式。
```
atom -o app.atom -l java --export-atom --export-format dot --export-dir
```
在 dot 格式下,像 ast、cdg 和 cfg 这样的独立表示也会被导出。
要在导出的文件中计算并包含数据依赖图 (DDG) 信息,请传递 `--with-data-deps`
```
atom -o app.atom -l java --export-atom --export-dir --with-data-deps
```
## 环境变量
| 变量 | 描述 |
| --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **CHEN_IGNORE_DIRS** | 所有语言前端都要忽略的目录列表(以逗号分隔)。 |
| **CHEN_IGNORE_TEST_DIRS** | 设置为 true 可为所有语言前端忽略常见的测试目录(`test`、`tests`、`mocks`)。 |
| **CHEN_C_IGNORE_DIRS** | 为 C/C++ 和 Header 前端额外指定的忽略目录列表(以逗号分隔)。 |
| **CHEN_CPP_IGNORE_DIRS** | 为 C++ 前端额外指定的忽略目录列表(以逗号分隔)。 |
| **CHEN_JAVA_IGNORE_DIRS** | 为 Java 源码前端额外指定的忽略目录列表(以逗号分隔)。 |
| **CHEN_JIMPLE_IGNORE_DIRS** | 为 Jimple/JAR/Android/APK/DEX 前端忽略的目录列表(以逗号分隔)。 |
| **CHEN_SCALA_IGNORE_DIRS** | 为 Scala 前端忽略的目录列表(以逗号分隔)。 |
| **CHEN_JAVASCRIPT_IGNORE_DIRS** | 为 JavaScript、TypeScript 和 Flow 前端忽略的目录列表(以逗号分隔)。 |
| **CHEN_JS_IGNORE_DIRS** | JavaScript、TypeScript 和 Flow 忽略目录的别名。 |
| **CHEN_TYPESCRIPT_IGNORE_DIRS** | TypeScript 和 Flow 忽略目录的别名。 |
| **CHEN_PYTHON_IGNORE_DIRS** | 为 Python 忽略的目录列表(以逗号分隔)。如果未设置,atom 会使用 Python 默认的忽略目录。 |
| **CHEN_PHP_IGNORE_DIRS** | 为 PHP 前端额外指定的忽略目录列表(以逗号分隔)。 |
| **CHEN_RUBY_IGNORE_DIRS** | 为 Ruby 前端额外指定的忽略目录列表(以逗号分隔)。 |
| **CHEN_DELOMBOK_MODE** | Java 前端的 Delombok 模式(`no-delombok`、`default`、`types-only`、`run-delombok`)。 |
| **CHEN_INCLUDE_PATH** | C 前端的包含目录。用 `:` 或 `;` 分隔路径。 |
| **CHEN_ASTGEN_OUT** | 现有的 astgen 输出目录。通过重用现有的 AST json 数据,提高 JavaScript、TypeScript 和 Flow 在重复调用时的性能。 |
| **ATOM_TOOLS_OPENAPI_FORMAT** | atom-tools 的 OpenAPI 格式。默认:`openapi3.1.0`;备选:`openapi3.0.1`。 |
| **ATOM_TOOLS_WORK_DIR** | atom-tools 的工作目录。默认为 atom 输入路径。 |
| **ATOM_SCALASEM_WORK_DIR** | scalasem 的工作目录。默认为 atom 输入路径。 |
| **ATOM_SCALASEM_SLICES_FILE** | 切片文件名。默认为 `semantics.slices.json`。 |
| **ATOM_JVM_ARGS** | 覆盖由 atom Node.js 包装器构建的 JVM 参数,包括堆内存值。 |
| **ATOM_JAVA_HOME** | atom 要使用的 Java 21 或更高版本。 |
| **PHP_CMD** | 覆盖 PHP 前端使用的 PHP 命令。 |
| **PHP_PARSER_BIN** | 覆盖 PHP 前端使用的 php-parse 命令。 |
| **SCALA_CMD** | 覆盖 scala 命令。 |
| **SCALAC_CMD** | 覆盖 scala 前端使用的 scalac 命令。 |
| **ASTGEN_IGNORE_DIRS** | JavaScript astgen 预处理命令要忽略的目录列表(以逗号分隔)。 |
| **ASTGEN_IGNORE_FILE_PATTERN** | JavaScript astgen 预处理命令要忽略的文件模式。 |
| **ASTGEN_INCLUDE_NODE_MODULES_BUNDLES** | 同时包含来自 node_modules 目录的源代码。这会使流变得更加完整,但代价是增加内存使用量。 |
| **JAVA_CMD** | 覆盖 java 命令。 |
| **RUBY_CMD** | 覆盖 Ruby 命令。 |
## atom 规范
atom 使用的中间表示基于同样的开源许可 (MIT) 提供。规范支持 [protobuf](./specification/atom.proto)、[markdown](./specification/docs/spec.md) 和 [html](./specification/docs/spec.html) 格式。
当前规范版本为 1.0.0
## 生成 atom 文件
atom 文件 (app.⚛ 或 app.atom) 是包含序列化 protobuf 数据的 zip 文件。推荐使用 atom cli 来生成这些文件。也可以使用 [proto 规范](./specification/atom.proto) 从头开始编写生成器工具。我们为感兴趣的用户提供了一个 [Python](./specification/samples/python-atomgen/README.md) 示例。我们还提供了其他语言的 proto 绑定,可以在[这里](./specification/bindings/)找到。
在 python 中生成 atom 的示例代码片段。
```
# 创建一个具有 fullname property 的 method
methodFullName = atom.CpgStructNodeProperty(
name=atom.NodePropertyName.FULL_NAME, value=atom.PropertyValue("main")
)
# 创建一个带有 fullname property 的 method node
method = atom.CpgStructNode(
key=1, type=atom.NodeType.METHOD, property=[methodFullName]
)
# 创建一个包含单个 node 的 atom
atom_struct = atom.CpgStruct(node=[method])
# 通过将这些数据序列化到 zip 文件中来创建一个 atom (app.atom)
with ZipFile("app.atom", "w") as zip_file:
zip_file.writestr("cpg.proto", bytes(atom_struct))
```
## 许可证
MIT
## 结合 chennai 使用 atom
[chennai](https://github.com/AppThreat/chen) 是处理 atom 的推荐查询接口。
```
chennai> importAtom("/home/almalinux/work/sandbox/apollo/app.atom")
```
## atom 工具
查看 [atom-tools](https://github.com/AppThreat/atom-tools),获取一些涉及 atom 切片的项目灵感。
## devenv 设置
按照官方[说明](https://devenv.sh/getting-started/)安装 devenv。
```
devenv shell
```
特定语言的配置:
```
# Ruby 环境
devenv --option config.profile:string ruby shell
# php 环境
devenv --option config.profile:string php shell
```
## 高级配置
对于复杂的项目,特别是用 C 或 C++ 编写的项目,你可能需要将细粒度的配置选项传递给底层的语言前端。你可以通过使用 `--frontend-args` 标志来实现。
此标志接受以逗号分隔的 `key=value` 键值对列表。
### 用法
```
--frontend-args key1=value1,key2=value2,key3=value3
```
### 支持的参数 (C/C++)
当 `--language` 设置为 `c`、`cpp` 或 `c++` 时,支持以下参数。
| Key | Type | Description | Example |
| :--------------------- | :------ | :------------------------------------------------------------------------------ | :---------------------------- |
| `defines` | List | 逗号分隔的预处理器定义。 | `defines=DEBUG,VERSION=2` |
| `includes` | List | 额外的 Header 包含路径。 | `includes=/opt/local/include` |
| `cpp-standard` | String | 要使用的 C++ 标准版本。 | `cpp-standard=c++17` |
| `function-bodies` | Boolean | 是否提取函数体。 | `function-bodies=false` |
| `parse-inactive-code` | Boolean | 解析处于禁用状态预处理器块内的代码(例如,`#if 0` 内部)。 | `parse-inactive-code=true` |
| `with-image-locations` | Boolean | 创建镜像位置(解释名称是如何进入翻译单元的)。 | `with-image-locations=true` |
| `enable-ast-cache` | Boolean | 将解析后的 AST 缓存到磁盘,以加速未更改文件的后续运行。 | `enable-ast-cache=true` |
| `ast-cache-dir` | String | 存储 AST 缓存文件的目录。默认为输入目录下的 `ast_out`。 | `ast-cache-dir=/tmp/cache` |
| `only-ast-cache` | Boolean | 仅生成 AST 缓存文件并退出。对于大型项目可避免 OOM。 | `only-ast-cache=true` |
### 示例
**1. 设置 C++ 标准和定义**
使用 C++17 为 C++ 项目生成 atom。
```
java -jar atom.jar \
--language c++ \
--frontend-args cpp-standard=c++17 \
./my-cpp-project
```
**2. 处理自定义包含路径**
如果你的项目依赖于位于源码树之外的 Header:
```
java -jar atom.jar \
--language c \
--frontend-args includes=/usr/local/include,/opt/mylib/include \
./src
```
**3. 解析非活动代码**
包含隐藏在预处理器指令后面的代码(例如在 Linux 上运行时的 `#ifdef WINDOWS`):
```
java -jar atom.jar \
--language c \
--frontend-args parse-inactive-code=true \
./src
```
**4. 大型项目:两阶段生成(内存优化)**
对于非常庞大的 C/C++ 代码库,一次性生成完整的图可能会消耗过多内存。你可以使用 AST 缓存将过程分为两个阶段。
_阶段 1:仅生成 AST 缓存_
这会逐个解析文件并将其 AST 保存到磁盘(默认为 `./src/ast_out`),从而保持较低的内存使用量。
```
java -jar atom.jar \
--language c \
--frontend-args only-ast-cache=true,ast-cache-dir=/tmp/cache \
./src
```
_阶段 2:从缓存生成 atom_
在启用缓存的情况下再次运行该命令。它将从磁盘加载预计算的 AST,从而显著加快图的创建速度。
```
java -jar atom.jar \
--language c \
--frontend-args enable-ast-cache=true,ast-cache-dir=/tmp/cache \
./src
```
## 故障排除
### 大型 JS/TS 项目的 atom 文件不完整
对于大型的 JavaScript 项目(尤其是 flow 项目),astgen 可能需要大量的堆内存。使用环境变量 `NODE_OPTIONS` 来增加可用内存。
```
export NODE_OPTIONS="--expose-gc --max-old-space-size=16288"
```
对于像 React 19 这样的大型项目,astgen 需要超过 80 GB 的堆内存!请使用环境变量 `CHEN_ASTGEN_OUT` 让 atom 和 chen 重用任何包含 astgen 生成的 json 和 typemap 文件的现有目录。
为了进一步提高准确性,可以通过设置 `ASTGEN_INCLUDE_NODE_MODULES_BUNDLES` 来包含 `node_modules` 目录中的源代码。
```
export ASTGEN_INCLUDE_NODE_MODULES_BUNDLES=true
export ASTGEN_IGNORE_DIRS=""
```
atom 是一种用于应用程序的新型中间表示,也是一个由 [chen](https://github.com/AppThreat/chen) 库支持的独立工具。这种中间表示(一个包含节点和链接的网络)针对应用程序分析和机器学习中常用的操作(包括[切片](./specification/docs/slices.md)和向量化)进行了优化。
我们的愿景是让 atom 能够适用于多种用例,例如:
- **供应链分析:** 生成外部库使用的证据,包括从数据源到数据汇的数据流。atom 被 [OWASP cdxgen](https://github.com/CycloneDX/cdxgen) 使用,以提高生成的 CycloneDX 文档的精确性和全面性。
- **漏洞分析:** 通过受影响的符号、调用路径和数据流的证据来描述漏洞。实现大规模的变体分析和[可达性分析](https://github.com/AppThreat/atom/blob/main/specification/docs/slices.md#reachables-slice)。
- **漏洞利用预测:** 利用漏洞、库和应用程序的精确表示来预测漏洞利用。
- **威胁模型和攻击向量生成:** 大规模地为应用程序生成精确的威胁模型和攻击向量。
- **应用程序上下文检测:** 生成可用于摘要生成和风险画像创建的上下文(例如,服务、端点和数据属性)。
- **应用程序的思维导图:** 作为一种开发人员工具,自动对大型和复杂的应用程序进行摘要。
以及其他更多用例。
[](https://github.com/cdxgen/cdxgen)


## 支持的语言
- C/C++
- H (仅限 C/C++ Header 和预处理过的 .i 文件)
- Java (需要编译)
- Jar
- Android APK 和拆分包 (.apkm, .apks, .xapk)。需要 Android SDK。设置环境变量 `ANDROID_HOME` 或使用容器镜像。
- JavaScript
- Flow
- TypeScript
- Python (支持 3.x 到 3.13)
- PHP (需要 PHP >= 7.4。支持 PHP 7.0 到 8.4,对 PHP 5.x 的支持有限)
- Ruby (需要 Ruby 4.0.x。支持 Ruby 1.8 - 4.0.x 语法)
- Scala (WIP)
## 安装说明
atom 包含一个带有 Node.js 包装模块的 scala 核心。目前它作为 npm 包分发。
```
npm install -g @appthreat/atom @appthreat/atom-parsetools
atom --help
```
安装 cdxgen npm 包以生成软件物料清单 (SBOM),这是进行 reachables 切片所必需的。
```
npm install -g @cyclonedx/cdxgen --omit=optional
```
## 容器使用
```
docker run --rm -v /tmp:/tmp -v $HOME:$HOME -v $(pwd):/app:rw -t ghcr.io/appthreat/atom atom --help
# podman run --rm -v /tmp:/tmp -v $HOME:$HOME -v $(pwd):/app:rw -t ghcr.io/appthreat/atom atom --help
```
Java 项目的示例。
```
docker run --rm -v /tmp:/tmp -v $HOME:$HOME -v $(pwd):/app:rw -t ghcr.io/appthreat/atom atom -l java -o /app/app.atom /app
# podman run --rm -v /tmp:/tmp -v $HOME:$HOME -v $(pwd):/app:rw -t ghcr.io/appthreat/atom atom -l java -o /app/app.atom /app
```
## atom native-image (仅供高级用户使用)
```
curl -LO https://github.com/AppThreat/atom/releases/latest/download/atom-amd64
chmod +x atom-amd64
./atom-amd64 --help
```
在 Windows 上
```
curl -LO https://github.com/AppThreat/atom/releases/latest/download/atom.exe
.\atom.exe --help
```
注意:诸如 astgen、rbastgen、phpastgen 等命令并未捆绑在此 native image 中。请安装 npm 包 `@appthreat/atom-parsetools` 来获取这些命令。
```
npm install -g @appthreat/atom-parsetools
which astgen
which phpastgen
```
## CLI 用法
```
Usage: atom [parsedeps|data-flow|usages|reachables|export|algorithms] [options] [input]
input source file or directory
-o, --output 标签:DNS重绑定攻击, MITM代理, 暗色界面, 请求拦截, 通知系统