
ALEAPP v2026.3.3
Android 日志事件和 Protobuf 解析器

Android Logs Events And Protobuf Parser
如果你想做出贡献,请在这里联系我:https://abrignoni.github.io
博客文章在这里:https://leapps.org/blog
要求
Python 3.10 或更高版本
依赖项
你的 Python 环境的依赖项列在 requirements.txt 中。使用以下命令安装它们。确保
py 部分与你的环境匹配,例如 py、python 或 python3 等。
py -m pip install -r requirements.txt
或
pip3 install -r requirements.txt
要在 Linux 上运行,你还需要单独安装 tkinter,如下所示:
sudo apt-get install python3-tk
编译为可执行文件
要编译为可执行文件,以便你可以在未安装 Python 的系统上运行它。
Windows OS
要创建 aleapp.exe,请运行:
pyinstaller scripts\pyinstaller\aleapp.spec
要创建 aleappGUI.exe,请运行:
pyinstaller scripts\pyinstaller\aleappGUI.spec
macOS
要创建 aleapp,请运行:
pyinstaller scripts/pyinstaller/aleapp_macOS.spec
要创建 aleappGUI.app,请运行:
pyinstaller scripts/pyinstaller/aleappGUI_macOS.spec
Linux
要创建 aleapp,请运行:
pyinstaller scripts/pyinstaller/aleapp_Linux.spec
要创建 aleappGUI,请运行:
pyinstaller scripts/pyinstaller/aleappGUI_Linux.spec
用法
CLI
$ python aleapp.py -t <zip | tar | fs | gz | raw> -i <path_to_extraction> -o <path_for_report_output>
raw 会就地读取磁盘镜像(.img、.dd、.bin,或拆分集中的任意编号 .001 分段),
或 EnCase/EWF .E01 采集文件及其旁边的分段:无需挂载,也无需管理员权限。其 NTFS、FAT32、exFAT、ext2/3/4、
F2FS、HFS+、APFS、QNX6、QNX4、ETFS、EFS、SquashFS、JFFS2、UBI/UBIFS、YAFFS 和 QNX IFS
卷会被直接搜索,并且
只从镜像中读取 artifact 所需的文件。GUI 会针对这些扩展名
自行选择 raw。参见 admin/docs/raw_image_input.md。
tar 还会读取 xz 压缩的 tar(.tar.xz),GUI 会针对该
扩展名选择 tar。压缩的 tar(包括 .tar.gz)会在读取任何文件之前
先解压一次到报告文件夹中,因此运行需要在该处有足够的可用空间来存放解压后的 tar。
运行结束后该副本会被删除,运行日志会说明该步骤耗时多久。
GUI
$ python aleappGUI.py
帮助
$ python aleapp.py --help
贡献 artifact 插件
每个插件都是一个 Python 源文件,应添加到 scripts/artifacts 文件夹中,每次运行 ALEAPP 时都会动态加载。
插件源文件必须在模块的最开头包含一个名为 __artifacts_v2__ 的字典,用于定义该插件处理的 artifacts。__artifacts_v2__ 字典中的键应为 artifact 的 ID,且在 ALEAPP 内必须唯一。值应为包含以下键的字典:
name:artifact 的名称,字符串。description:artifact 的描述,字符串。author:插件的作者,字符串。version:artifact 的版本,字符串。date:artifact 最后更新的日期,字符串。requirements:处理该 artifact 的任何要求,字符串。category:artifact 的类别,字符串。notes:任何附加说明,字符串。paths:一个字符串元组,包含用于匹配插件所期望的 artifact 数据路径的 glob 搜索模式。function:作为 artifact 处理入口点的函数名称,字符串。
例如:
__artifacts_v2__ = {
"cool_artifact_1": {
"name": "Cool Artifact 1",
"description": "Extracts cool data from database files",
"author": "@username",
"version": "0.1",
"date": "2022-10-25",
"requirements": "none",
"category": "Really cool artifacts",
"notes": "",
"paths": ('*/com.android.cooldata/databases/database*.db',),
"function": "get_cool_data1"
},
"cool_artifact_2": {
"name": "Cool Artifact 2",
"description": "Extracts cool data from XML files",
"author": "@username",
"version": "0.1",
"date": "2022-10-25",
"requirements": "none",
"category": "Really cool artifacts",
"notes": "",
"paths": ('*/com.android.cooldata/files/cool.xml',),
"function": "get_cool_data2"
}
}
在 __artifacts__ 字典中作为入口点引用的函数必须接受以下参数:
- 找到的、待处理的文件的可迭代对象(作为字符串)
- ALEAPP 输出文件夹的路径(作为字符串)
- 找到这些文件的 seeker(类型为 FileSeekerBase)
- 一个布尔值,指示插件是否应进行文本换行
例如:
def get_cool_data1(files_found, report_folder, seeker, wrap_text):
pass # do processing here
插件通常应以 ALEAPP 的 HTML 输出格式、TSV 提供输出,并可选择向
时间线提交记录。用于生成此输出的函数可在 artifact_report 和 ilapfuncs 模块中找到。
从高层来看,一个示例可能类似于:
__artifacts_v2__ = {
"cool_artifact_1": {
"name": "Cool Artifact 1",
"description": "Extracts cool data from database files",
"author": "@username", # Replace with the actual author's username or name
"version": "0.1", # Version number
"date": "2022-10-25", # Date of the latest version
"requirements": "none",
"category": "Really cool artifacts",
"notes": "",
"paths": ('*/com.android.cooldata/databases/database*.db',),
"function": "get_cool_data1"
}
}
import datetime
from scripts.artifact_report import ArtifactHtmlReport
import scripts.ilapfuncs
def get_cool_data1(files_found, report_folder, seeker, wrap_text):
# let's pretend we actually got this data from somewhere:
rows = [
(datetime.datetime.now(), "Cool data col 1, value 1", "Cool data col 1, value 2", "Cool data col 1, value 3"),
(datetime.datetime.now(), "Cool data col 2, value 1", "Cool data col 2, value 2", "Cool data col 2, value 3"),
]
headers = ["Timestamp", "Data 1", "Data 2", "Data 3"]
# HTML output:
report = ArtifactHtmlReport("Cool stuff")
report_name = "Cool DFIR Data"
report.start_artifact_report(report_folder, report_name)
report.add_script()
report.write_artifact_data_table(headers, rows, files_found[0]) # assuming only the first file was processed
report.end_artifact_report()
# TSV output:
scripts.ilapfuncs.tsv(report_folder, headers, rows, report_name, files_found[0]) # assuming first file only
# Timeline:
scripts.ilapfuncs.timeline(report_folder, report_name, rows, headers)
为你的 PR 准备测试数据和 sample_data
当添加或更改 artifact 的 PR 附带以下两项内容时,最容易审查和合并:
一个从真实提取中截取的小型测试夹具,以及记录该模块产生了什么的 sample_data 值。
脚本会生成这两者。以下是完整流程。
在开始之前有一条规则:你在这里提交的任何内容都会公开。只使用你 被允许共享的数据,例如你自己填充的测试设备、公开的研究镜像, 或你手动清理过的文件。绝不要使用案件数据。
1. 从你的提取中截取一个夹具
python admin/test/scripts/make_test_data.py <module> --case 1 --input <extraction.zip>
这会从提取中拉取与你的模块 paths 模式匹配的文件,并写入
用例文件 admin/test/cases/testdata.<module>.json,以及每个 artifact 一个小型 zip,
位于 admin/test/cases/data/<module>/ 下。
大小规则:每个 zip 小于 10 MB,随 PR 一起提交。介于 10 到 25 MB 之间,提交 用例文件并将 zip 附加到 PR 评论中。大于该大小,请在 PR 中说明,维护者 会安排交接。
2. 记录预期输出
TZ=UTC python admin/test/scripts/test_module.py <module> -a all -c all
这会针对夹具运行该模块,并在
admin/test/results/<module>/ 下写入输出的快照。也提交该快照。它将成为
合并后守护该模块的基线。保留 TZ=UTC 部分:提交的快照是 UTC,
CI 也以 UTC 运行。
3. 运行 CI 将运行的相同比较
python admin/test/scripts/run_test_cases.py --module <module>
4. 生成 sample_data 值
python admin/scripts/validate_sample_data.py --emit <extraction.zip> --key <image_name>
这会在你的提取上端到端运行 ALEAPP,并为你的分支上更改的模块打印可直接粘贴的 sample_data
块。将它们粘贴到你的模块的
__artifacts_v2__ 中,并添加你在镜像上看到的应用名称和版本。如果某个计数为
零,在记录之前请检查源文件确实为空。
5. 提交所有内容并打开 PR
将模块、用例文件、夹具 zip 和记录的快照一起提交。 更多细节见 admin/docs/testing/create_module_test_cases.md。
如果你的提取无法共享,仍然可以打开 PR 并说明情况。夹具通常可以 改为从公开研究镜像中截取,或者真实文件可以手动清理。在我们解决这个问题的过程中, 审查不会停止。
致谢
此工具是 DFIR 社区许多人协作努力的成果。
ALEAPP 徽标由 Derek Eiri 提供。