diff --git a/diaphora/diaphora.sh b/diaphora/diaphora.sh old mode 100644 new mode 100755 index aaedfb8..19794bc --- a/diaphora/diaphora.sh +++ b/diaphora/diaphora.sh @@ -1,5 +1,117 @@ +#!/bin/zsh + +# ============================================================================== +# Diaphora & IDA Pro 自动化批处理脚本 +# ============================================================================== + +# --- 配置区 (Configuration) --- + +# 1. 存放所有 .a 文件的**源目录** (The directory containing all .a files) +# !!! 请将此路径替换为您的实际目录 !!! +A_FILES_SOURCE_DIR="/Users/yincong/go/src/github.com/yincongcyincong/mars/mars/cmake_build/OSX/Darwin.out/" + +# 2. 存放 .o 文件提取、以及最终 .i64/.sqlite 结果的**工作目录** +# 建议使用 /tmp,脚本运行完毕后可以手动删除此目录。 +WORK_DIR="/tmp/diaphora_batch_$(date +%s)" + +# 3. IDA Pro 可执行文件路径 (基于您提供的路径) +IDA_EXECUTABLE="/Applications/IDA Professional 9.1.app/Contents/MacOS/ida" + +# 4. Diaphora 脚本路径 (基于您提供的路径) +DIAPHORA_SCRIPT="/Users/yincong/go/src/github.com/yincongcyincong/diaphora/diaphora.py" + +# --- 脚本执行 (Script Execution) --- + +echo "--- Diaphora 自动化分析开始 ---" +echo "源目录: ${A_FILES_SOURCE_DIR}" +echo "工作目录: ${WORK_DIR}" + +# 路径检查 +if [ ! -x "${IDA_EXECUTABLE}" ]; then + echo "错误: 找不到 IDA 可执行文件或无执行权限: ${IDA_EXECUTABLE}" >&2 + exit 1 +fi +if [ ! -f "${DIAPHORA_SCRIPT}" ]; then + echo "错误: 找不到 Diaphora 脚本: ${DIAPHORA_SCRIPT}" >&2 + exit 1 +fi + +# 创建工作目录 +mkdir -p "${WORK_DIR}" || { echo "错误: 无法创建工作目录 ${WORK_DIR}" >&2; exit 1; } + -export DIAPHORA_EXPORT_FILE=/Users/yincong/go/src/github.com/yincongcyincong/weixin-macos/diaphora/database.sqlite -export DIAPHORA_AUTO=1 -/Applications/IDA\ Professional\ 9.1.app/Contents/MacOS/ida -A -B -L/tmp/ida.txt -S/Users/yincong/go/src/github.com/yincongcyincong/diaphora/diaphora.py /Users/yincong/go/src/github.com/yincongcyincong/mars/mars/cmake_build/OSX/Darwin.out/mars.framework/mars +# 1. 循环查找所有 .a 文件 +find "${A_FILES_SOURCE_DIR}" -name "*.a" -print0 | while IFS= read -r -d $'\0' archive_file; do + + # 提取 .a 文件名作为前缀 (例如: libmars) + archive_base=$(basename "${archive_file}" .a) + + # 为当前 .a 文件创建一个专门的提取子目录 + EXTRACTION_DIR="${WORK_DIR}/${archive_base}_o_files" + mkdir -p "${EXTRACTION_DIR}" + + echo "" + echo ">>> 处理归档文件: ${archive_file}" + + # 切换到提取目录并使用 'ar -x' 提取所有 .o 文件 + ( + cd "${EXTRACTION_DIR}" || exit 1 + echo " -> 正在提取 .o 文件到: ${EXTRACTION_DIR}" + # 使用 ar -x 提取所有目标文件 + ar -x "${archive_file}" + ) + + if [ $? -ne 0 ]; then + echo " -> 警告: 提取 ${archive_file} 失败,跳过。" + continue + fi + + # 2. 循环处理所有提取出来的 .o 文件 + # 使用 find 确保只处理当前目录下的 .o 文件 (maxdepth 1) + find "${EXTRACTION_DIR}" -maxdepth 1 -name "*.o" -print0 | while IFS= read -r -d $'\0' object_file; do + + # 提取 .o 文件名 (例如: tcpclient_fsm.cc) + object_base=$(basename "${object_file}" .o) + + # 构造唯一的输出文件名,以防止不同 .o 文件覆盖彼此的结果 + OUTPUT_BASE="${archive_base}__${object_base}" + IDA_IDB_PATH="${WORK_DIR}/${OUTPUT_BASE}.i64" + DIAPHORA_SQLITE_PATH="${WORK_DIR}/${OUTPUT_BASE}.sqlite" + IDA_LOG_PATH="${WORK_DIR}/${OUTPUT_BASE}.log" + + echo " -> 正在分析 .o 文件: ${object_file}" + echo " 输出 IDB: ${IDA_IDB_PATH}" + echo " 输出 SQLite: ${DIAPHORA_SQLITE_PATH}" + + # 配置 Diaphora 环境变量 + export DIAPHORA_EXPORT_FILE="${DIAPHORA_SQLITE_PATH}" + export DIAPHORA_AUTO=1 + + # 执行 IDA Pro 无头模式命令 + "${IDA_EXECUTABLE}" -A -B \ + -o"${IDA_IDB_PATH}" \ + -L"${IDA_LOG_PATH}" \ + -S"${DIAPHORA_SCRIPT}" \ + "${object_file}" + + if [ $? -ne 0 ]; then + echo " !!! 警告: IDA Pro 分析 ${object_base}.o 失败 (请检查 ${IDA_LOG_PATH})" + else + echo " <<< 分析成功: ${DIAPHORA_SQLITE_PATH} 已生成" + fi + + # 清除环境变量,确保下次循环是干净的 + unset DIAPHORA_EXPORT_FILE + unset DIAPHORA_AUTO + + done + + # 可选:删除提取出的 .o 文件以节省空间 + # rm -rf "${EXTRACTION_DIR}" + +done + +echo "" +echo "--- 所有归档文件处理完毕 ---" +echo "分析结果 (IDB/SQLITE/LOG) 位于目录: ${WORK_DIR}" diff --git a/diaphora/merge_disphora.sh b/diaphora/merge_disphora.sh new file mode 100755 index 0000000..93d42e8 --- /dev/null +++ b/diaphora/merge_disphora.sh @@ -0,0 +1,109 @@ +#!/bin/zsh + +# --- 配置区 --- +# 1. 存放所有源 SQLite 文件的目录 +WORK_DIR="/tmp/diaphora_batch_1764836774/" +# 2. 最终合并生成的主数据库文件名 +MASTER_DB_NAME="diaphora_merged_results.sqlite" + +# 排除 SQLite 内部使用的特殊表 +IGNORED_TABLES="(sqlite_sequence|android_metadata)" + +# ------------------------------------------------------------------------------ + +echo "--- SQLite 数据库批量合并开始 ---" +echo "工作目录: ${WORK_DIR}" +echo "主数据库: ${MASTER_DB_NAME}" +echo "--------------------------------------" + +# 查找所有源文件(排除目标主文件自身) +source_files=$(find "$WORK_DIR" -maxdepth 1 -name "*.sqlite" -not -name "$MASTER_DB_NAME" | sort) + +if [ -z "$source_files" ]; then + echo "⚠️ 警告: 未找到任何源数据库文件 (.sqlite)。" + exit 0 +fi + +# 确保主数据库文件存在 (如果不存在则创建) +if [ ! -f "$MASTER_DB_NAME" ]; then + echo "-> 主数据库文件不存在,正在创建: ${MASTER_DB_NAME}" + sqlite3 "$MASTER_DB_NAME" "VACUUM;" +fi + +# 尝试从第一个源数据库中获取所有表名 (用于定义结构和合并) +FIRST_SOURCE=$(echo "$source_files" | head -n 1) + +# 使用 sqlite3 的 .tables 命令和一些文本处理来获取表名列表 +TABLES=$(sqlite3 "$FIRST_SOURCE" ".tables" | tr ' ' '\n' | grep -v '^$' | sort | uniq | grep -vE "$IGNORED_TABLES") + +if [ -z "$TABLES" ]; then + echo "❌ 错误: 无法从第一个源数据库 (${FIRST_SOURCE}) 中获取可合并的表名。" >&2 + exit 1 +fi + +echo "找到以下需要合并的表: ${TABLES}" +echo "--------------------------------------" + + +## 🛠️ 关键步骤 1: 复制表结构到主数据库 +echo ">>> 正在从 ${FIRST_SOURCE} 复制表结构到 ${MASTER_DB_NAME}..." + +# 附加第一个源数据库,用于结构复制 +sqlite3 "$MASTER_DB_NAME" "ATTACH DATABASE '$FIRST_SOURCE' AS source;" + +# 循环创建表结构 +for table_name in $TABLES; do + echo " -> 确保表结构存在: ${table_name}" + + # 使用双引号 \"...\" 包裹表名,防止关键字冲突 + sqlite3 "$MASTER_DB_NAME" " + CREATE TABLE IF NOT EXISTS \"${table_name}\" AS + SELECT * FROM source.\"${table_name}\" LIMIT 0; + " +done + +# 分离数据库 +sqlite3 "$MASTER_DB_NAME" "DETACH DATABASE source;" + +echo "<<< 表结构复制完成" +echo "--------------------------------------" + + +## 💾 关键步骤 2: 循环合并数据 (已修复连接问题) +for source_db in $source_files; do + + SOURCE_BASE=$(basename "$source_db") + echo ">>> 正在合并源数据库: ${SOURCE_BASE}" + + # 1. 构建完整的 SQL 批处理命令 (包含 ATTACH) + # 这样所有操作都在同一个 sqlite3 进程中执行 + SQL_BATCH_COMMAND="ATTACH DATABASE '$source_db' AS source;" + + # 2. 循环插入数据 + for table_name in $TABLES; do + # 使用双引号 \"...\" 包裹表名,防止关键字冲突 + SQL_BATCH_COMMAND="${SQL_BATCH_COMMAND} INSERT OR IGNORE INTO \"${table_name}\" SELECT * FROM source.\"${table_name}\";" + done + + # 3. 添加分离命令(在同一批次执行) + SQL_BATCH_COMMAND="${SQL_BATCH_COMMAND} DETACH DATABASE source;" + + echo " -> 正在执行数据插入批处理..." + + # 4. 集中执行所有命令 (ATTACH, INSERTS, DETACH) + sqlite3 -batch --bail "$MASTER_DB_NAME" "$SQL_BATCH_COMMAND" + + if [ $? -ne 0 ]; then + echo "❌ 错误: 数据插入过程中发生错误,停止合并。" >&2 + # 此时 DETACH 应该已在批处理中被执行,但如果 ATTACH 失败,DETACH 也会失败。 + # 我们已经停止脚本,不再需要额外的清理 DETACH。 + exit 1 + fi + + echo "<<< ${SOURCE_BASE} 合并完成" + echo "--------------------------------------" + +done + +echo "🎉 所有数据库已成功合并到 ${MASTER_DB_NAME}。" +echo "--- 合并脚本结束 ---" \ No newline at end of file