Skip to content

1.30 (107)

Choose a tag to compare

@wojiaoyishang wojiaoyishang released this 09 Jun 06:57
· 23 commits to master since this release

更新至 1.30 (107)

JS API 返回值稳定化

  • 所有保留到 JS 层的主要接口统一改为返回 JS 对象 / JS 数组,避免脚本直接遍历 Java List<Map>Map<List> 等不稳定结构。

  • 新增 JS 返回值规范化工具,用于将 Java 层返回的 MapList、数组、ThrowableFileClass 等转换为 JS 可稳定读取的结构。

  • 推荐脚本使用点访问和数组访问:

    • ret.paths
    • results[i].className
    • methods[i].methodName
  • 不再推荐旧写法:

    • ret.get("sources")
    • sources.get(i).get("path")
    • item.get("className")
  • sourcesdetails 等字段保留为调试信息,不建议脚本逻辑依赖。

Dex Dump 与 Dex 搜索 API

  • dex.dumpDexCookies(options) 返回结构稳定化。

    • 新增 ok
    • 新增 count
    • 新增 outputDir
    • 新增 paths
    • 新增 dumpedPaths
    • 保留 sources 作为调试详情
  • dex.dumpDexCookies 默认输出文件名使用 cookie_ 前缀。

    • 默认格式:cookie_<index>_<addressHex>_<fileSize>.dex
    • 示例:cookie_000_71d518e000_3777364.dex
  • dex.findMethods(query) 改为返回 JS 数组。

  • dex.findMethod(query) 未找到时返回 null

  • dex.findMethods(query) 新增 / 完善 smali 特征搜索。

    • 支持 smaliContains
    • 兼容 smaliKeywords
    • 兼容 smaliKeyword
    • 兼容 smali
  • dex.findMethods 支持仅通过 smali 特征定位方法,不再要求必须提供 classNamemethodNameproto

  • dex.findMethods 返回结果统一包含:

    • className
    • methodName
    • proto
    • descriptor
    • path
    • score
    • reasons
    • strings
    • invokes
    • smaliHead
  • dex.inspectMethodInFile(options) 严格化。

    • path 必填
    • className 必填
    • methodName 必填
    • proto 可选
    • 不再默认历史目标方法
    • 不再承担搜索职责,只用于精确检查指定方法
  • dex.locateMethodInCookieDumps(options) 严格化。

    • className 必填
    • methodName 必填
    • proto 可选
    • 不再默认历史目标方法
  • dex.dumpClassDex(options) 返回稳定字段:

    • ok
    • count
    • paths
    • dumped
    • failed
  • dex.dumpLoadedClassDex(options) 返回稳定字段:

    • ok
    • className
    • path
    • paths
    • size
  • dex.dumpMemory(options) 返回稳定字段:

    • ok
    • count
    • outputDir
    • paths
    • dumped
  • dex.scanMemory(options) / dex.dumpMemoryRaw(options) 增加稳定 candidates 字段。

  • dex.runtimeSources() 改为返回 JS 数组。

  • dex.runtimeLoaders() 改为返回 JS 数组。

  • dex.registerLoader(loader, path) 严格化。

    • loader 必须是 ClassLoader
    • path 必须是非空字符串
    • 非法参数不再兜底为默认 loader
  • dex.setLimits(options) / dex.limits() 返回稳定 JS 对象。

移除 Dex 旧式过渡接口

  • 移除或不再作为 JS 推荐接口暴露以下过渡 API:

    • dex.scanDumpDir
    • dex.fromDumpDir
    • dex.dumpCookieDex
    • dex.dumpFromCookies
    • dex.dumpRawDex
    • dex.traceStrings
    • dex.inspectDumpedMethod
    • dex.findMethodInCookieDumps
    • dex.dumpUnpackedDexForMethod
    • dex.dumpTargetDex
    • dex.dumpDexForMethod
  • 新脚本应直接使用:

    • dex.dumpDexCookies(...)
    • ret.paths
    • dex.findMethods(...)
    • dex.inspectMethodInFile(...)

JS 对象与 Java 对象边界

  • 新增对象类型判断 API:

    • xhh.objectKind(value)
    • xhh.isJsObject(value)
    • xhh.isJavaObject(value)
  • xhh.objectKind(value) 返回稳定 JS 对象,包含:

    • kind
    • isJsObject
    • isJavaObject
    • isPrimitive
    • isNull
    • isUndefined
    • rawClass
    • javaClass
    • text
  • 文档中明确推荐使用 JS 对象 / JS 数组编写脚本逻辑。

  • Java 对象仅用于调用 Android / Xposed / App 运行时方法,不建议把 Java Map/List 当作脚本数据结构使用。

Rhino / JS 语法边界

  • JS 运行时继续基于 Rhino。

  • 运行时显式启用 ES6 语言版本。

  • 新增 xhh.jsEngine(),用于查看当前 JS 引擎能力。

  • 发现并记录 Rhino 在循环体内 const / let 词法绑定上的局限:

    • for (...) { const path = paths[i]; } 在部分 Rhino 场景可能不能可靠地每轮重新绑定。
  • 取消 “ES6 词法绑定自检失败即阻断脚本启动” 的行为。

  • 当检测到 Rhino 不支持可靠循环词法绑定时,脚本仍可继续运行,并通过 xhh.jsEngine() 查看状态。

  • 新增稳定遍历 API:

    • xhh.each(items, callback)
  • 推荐遍历 ret.pathsresults 等数组时使用:

    • xhh.each(paths, function (path, i) { ... })
  • 文档中新增 “JS 脚本语法边界说明”,明确 const 的适用范围与推荐通用语法。

Xposed JS API

  • xposed.e(tag, msg, any) 第三参处理增强。

    • 支持 Java Throwable
    • 支持 JS Error
    • 支持普通对象
    • 支持字符串
    • 支持 null / undefined
  • xposed.getJavaStackTrace() 返回 JS 数组。

  • xposed.getAppStackTrace() 返回 JS 数组。

  • xposed.stackTrace() 返回 JS 数组。

  • xposed.listRemoteFiles() 返回 JS 字符串数组。

  • xposed.getFrameworkProperties() 返回稳定 JS 对象。

  • xposed.getModuleApplicationInfo() 返回稳定 JS 对象。

  • xposed.raw.call(...) 返回值经过 JS 稳定化转换。

  • Hook 回调中的 chain.getArgs() 返回 JS 数组。

XHH / RPC / MCP API

  • xhh.info() 返回稳定 JS 对象。
  • xhh.hasGrant(name) 保持布尔返回。
  • xhh.rpc.register_method(name, callback) 返回稳定 JS 对象。
  • xhh.rpc.unregister_method(name) 返回稳定 JS 对象。
  • xhh.rpc.unregister_all_methods() 返回稳定 JS 对象。
  • MCP list_methods 返回 methods: [],每一项为稳定 JS 对象。
  • MCP invoke_methodresult 尽量经过 JSON-safe / JS-safe 转换。
  • RPC 回调返回值统一经过稳定化处理,减少 Java 对象泄漏到 JS/MCP 边界。

Settings / Env / Console / Java API

  • settings.get(key) 返回值经过 JS 稳定化转换。

  • settings.all() 返回稳定 JS 对象。

  • env 文档补充常用字段说明。

  • console 文档补充与 xposed 日志的推荐使用方式。

  • Java.type(name) 文档补充 Java 对象边界说明。

  • 明确 Java 对象与 JS 对象的职责划分:

    • Java 对象用于反射和运行时调用。
    • JS 对象用于脚本配置、返回值和业务逻辑。

示例脚本

  • 更新脱壳示例为新版推荐格式:

    • dex.dumpDexCookies(...)
    • ret.paths
    • xhh.isJsObject(ret)
  • 更新 Smali 特征查找示例:

    • 使用 dex.findMethods({ path, smaliContains, limit })
    • 使用 xhh.each(paths, callback) 遍历
    • 找到第一个匹配后 return false 停止搜索
    • 最后输出命中的 dex 文件、类名、方法名和方法签名
  • 移除旧示例中的:

    • scanDumpDir
    • fromDumpDir
    • Java Map.get
    • Java List.get
    • 正则解析 dumpRet.toString()
  • 新增 / 更新 smoke test 示例,覆盖主要 JS API 返回值稳定性。

文档

  • 参考 Python 文档风格重写 JS API 文档。
  • API 参考改为 “一个标题一个方法” 的形式,便于查阅。
  • scripts/js_api.rst 重写为 JS API 总参考。
  • scripts/dynamic_dex_scan/source_api.rst 重写为 Dex Source API 参考。
  • scripts/examples.rst 更新为新版推荐脚本。
  • scripts/boundaries.rst 补充 JS 语法边界、对象边界和 Rhino 限制。
  • scripts/dynamic_dex_scan/examples.rst 更新脱壳与特征查找示例。
  • 修复 RST 标题下划线过短导致的 Title underline too short 警告。

WebIDE 运行控制优化

  • 优化 WebIDE 中目标应用重启与终止逻辑。

  • “重启并同步” 现在会优先使用 Root 权限关闭并重新打开目标应用。

  • “重启同步并调试” 现在会优先使用 Root 权限关闭并重新打开目标应用,再进入调试流程。

  • 当设备具备 Root 权限时,WebIDE 可通过 Root 执行 force-stop 与启动命令,不再要求 XiaoHeiHook 当前处于前台。

  • 当设备没有 Root 权限时,仍使用普通 Android 启动方式,此时需要 XiaoHeiHook 处于前台才能可靠拉起目标应用。

  • 优化 Root 启动策略。

    • 优先使用 am start 启动目标应用入口 Activity。
    • 无法解析入口 Activity 时,回退使用 monkey 启动目标应用。
  • “终止调试/运行” 按钮行为调整。

    • 无论当前是否处于调试模式,都会强制终止目标应用。
    • 有 Root 权限时使用 Root force-stop
    • 无 Root 权限时使用普通终止能力。
  • WebIDE API 返回信息增加运行控制状态字段,便于前端判断执行结果。

    • launchMode
    • rootLaunchOk
    • rootLaunchMessage
    • terminated
    • terminate

JS Runtime Java Bridge 重构

  • 重构 JS Runtime 的 Java Bridge,将原本集中在 JsHookRuntime 内的桥接逻辑拆分为独立模块,提升维护性。
  • Java.type() 现在返回 JS 友好的 JavaClassWrapper,不再直接返回裸 java.lang.Class
  • 新增 JavaClass wrapper 语法,支持直接读取静态字段,例如 Toast.LENGTH_SHORT
  • 新增 JavaClass wrapper 静态方法调用,支持 Looper.getMainLooper() 等自然写法。
  • 新增 JavaClass wrapper 构造函数调用,支持 new Handler(Looper.getMainLooper())
  • 新增 JavaObject wrapper,支持 Java 实例方法直接调用,例如 handler.post(...)toast.show()
  • 新增 Java 对象字段读取与写入的 wrapper 支持。
  • 新增 raw Class 入口,支持 classObjectgetRawClass() 获取原始 java.lang.Class
  • 新增 java.lang.Class 方法透传能力,支持 Application.getDeclaredMethod(...) 等反射写法。
  • 新增 Java varargs 参数转换,支持 getDeclaredMethod("attach", ContextClass) 这类调用。
  • 新增 JS function 到 Java SAM 接口的自动代理转换,支持 handler.post(function () {})
  • 新增显式 Java.proxy() 支持,可用于 Runnable、listener、callback 等 Java 接口实现。
  • 增强 Java.proxy() 对单方法接口 function 写法与多方法接口 object 写法的支持。
  • 增强 Rhino Context 进入逻辑,确保 Java proxy 回调可以安全调用 JS 函数。
  • 增强 Java 方法、构造器和字段解析,统一处理重载评分、参数转换和返回值包装。
  • 优化数字参数重载选择,使整数 JS number 优先匹配 Java int/long,避免误选 double 重载。
  • 修复 StringBuilderAtomicInteger 等构造返回值被错误当作 JS 基础值的问题。
  • 保留低层反射 API,包括 Java.callStatic()Java.call()Java.newInstance()Java.get()Java.set() 等。
  • 调整 xposed.hook() 等入口,支持接收 wrapper 返回的 MethodClass 等对象。

文件与资源桥接 API

  • 新增 xhh.fs 文件与资源桥接接口。

  • 新增目标 App 私有目录查询能力。

    • xhh.fs.appDirs(context)
    • 通过目标 App Context 动态读取私有目录。
    • 不再要求脚本硬编码 /data/user/0/data/data/sdcard
    • 兼容多用户、多 profile 与目标 App 真实运行用户。
  • 新增基础文件操作接口。

    • xhh.fs.join(...)
    • xhh.fs.exists(path)
    • xhh.fs.isFile(path)
    • xhh.fs.isDirectory(path)
    • xhh.fs.mkdirs(path)
    • xhh.fs.readText(path[, charsetOrOptions])
    • xhh.fs.writeText(path, text[, charsetOrOptions])
    • xhh.fs.appendText(path, text[, charsetOrOptions])
    • xhh.fs.readBytes(path[, options])
    • xhh.fs.writeBytes(path, bytes[, options])
    • xhh.fs.copy(src, dst[, options])
  • 文本和二进制读取默认限制为 16MB,避免目标 App 进程因误读大文件导致 OOM。

  • 读取上限可通过参数调整,适合少量配置、HTML、CSS、图片等脚本资源场景。

  • 新增脚本路径查询接口。

    • xhh.fs.scriptRoot()
    • xhh.fs.scriptDir()
    • xhh.fs.assetsDir()
    • xhh.fs.assetPath(relativePath)
  • 脚本根目录默认解析为当前用户 Documents 下的 XiaoHeiHook 目录。

  • 脚本根目录支持通过设置修改,不再在 JS API 实现中硬编码。

  • 新增脚本 assets 读取接口。

    • xhh.fs.readAssetText(relativePath[, charsetOrOptions])
    • xhh.fs.readAssetBytes(relativePath[, options])
  • assets 资源访问严格限制在当前脚本自己的 assets/ 目录内。

  • 禁止通过 assets API 读取脚本源码、其他脚本资源或 assets 外部文件。

  • 新增资源复制到目标 App 私有目录的接口。

    • xhh.fs.appAssetDir(context[, options])
    • xhh.fs.copyAssetToApp(context, assetRelativePath[, targetRelativePath[, options]])
    • xhh.fs.syncAssetsToApp(context[, options])
  • copyAssetToApp 返回值包含复制后的完整目标路径,便于脚本直接用于 ImageViewWebView、本地配置文件等场景。

  • 资源复制目标必须位于目标 App 私有 filesDir 内。

  • 复制目标子路径可由脚本指定,但必须是安全相对路径。

  • 禁止复制目标路径出现绝对路径、../ 目录穿越或符号链接逃逸。

  • syncAssetsToApp 支持递归同步当前脚本 assets/ 目录到目标 App 私有目录。

  • syncAssetsToApp 默认覆盖已有资源。

  • clean=true 时只清理当前脚本自己的资源同步目录,不会删除目标 App 其他私有文件。

  • 本版本不为文件 API 增加独立 grant 权限项,保持与现有脚本权限模型兼容。

多文件脚本与 assets 资源目录

  • 多文件脚本支持在脚本目录中放置 assets/ 目录。

  • 推荐目录结构:

    • index.js
    • main.js
    • lib/
    • assets/data/config.json
    • assets/panel/index.html
    • assets/images/icon.png
  • require() 仍只用于加载 JS 模块。

  • assets/ 只作为资源目录,不会被当作 JS 模块目录执行。

  • 脚本资源在同步时会进入 XiaoHeiHook 的脚本资源体系,目标 App 进程中可通过 xhh.fs 读取或复制。

  • 推荐脚本先将图片、HTML、CSS、JSON 等资源复制到目标 App 私有目录,再交给目标 App 的 ImageViewWebView 或普通文件 API 使用。

  • 不推荐让目标 App 直接访问脚本根目录或外部存储目录。

路径安全与运行边界

  • 明确文件路径边界:脚本目录、脚本 assets 目录、目标 App 私有目录是三个不同边界。
  • 目标 App 私有目录必须从目标 App Context 获取。
  • 不允许脚本作者手动拼接 /data/user/0/<package>
  • 多用户设备、工作资料空间、应用分身等环境下,真实路径可能不是 /data/user/0
  • assets 相对路径禁止使用绝对路径。
  • assets 相对路径禁止使用 ../ 穿越。
  • assets 相对路径禁止包含 NUL 字符。
  • 资源复制目标路径会进行 canonical 校验,确保最终位置仍在目标 App 私有目录内。
  • 普通文件 API 适合操作脚本明确拿到的路径。
  • 资源 API 只适合操作当前脚本自己的 assets/
  • 不建议在脚本中保存或复制敏感源码到目标 App 可读取目录。
  • 不建议把大文件长期放入目标 App 私有目录,避免影响目标 App 存储占用。

示例脚本

  • 更新 Toast 示例,改为推荐的简洁 wrapper 写法。

  • 新增 Java Bridge smoke test 脚本,用于验证静态字段、静态方法、构造函数、实例方法、SAM proxy 和反射 fallback。

  • 新增文件读写示例,演示:

    • xhh.fs.appDirs(context)
    • xhh.fs.mkdirs(path)
    • xhh.fs.writeText(path, text)
    • xhh.fs.readText(path)
  • 新增 assets 单文件复制示例,演示:

    • xhh.fs.readAssetText("data/config.json")
    • xhh.fs.copyAssetToApp(context, "images/icon.png")
    • 使用返回的完整路径加载本地资源
  • 新增 assets 批量同步示例,演示:

    • xhh.fs.syncAssetsToApp(context, { overwrite: true })
    • xhh.fs.appAssetDir(context)
    • 使用同步后的资源目录构造本地文件路径
  • 新增多文件资源展示示例。

    • 示例脚本在应用启动时复制资源文件到目标 App 私有目录。
    • 示例脚本会尝试在首个 Activity 中弹出 Dialog,并使用 ImageView 展示复制后的图片。
    • 完整代码位于 https://github.com/wojiaoyishang/XiaoHeiCat/tree/master/examples/multi_asset_showcase

文档

  • 更新脚本 API 文档,补充 Java Bridge wrapper、自动 SAM 转换和 Java.proxy() 新语法说明。
  • 更新边界文档,说明 JavaClassWrapperJavaObjectWrapper、JS function、JS object 与 Java 对象之间的转换规则。
  • 更新桥接文档,说明 Java.type() 的新行为以及 raw Class 兼容入口。
  • 更新示例文档,加入 Application.attach、主线程 Handler 和 Toast 的推荐写法。
  • 新增文件与资源桥接 API 文档,集中说明 xhh.fs 的参数、返回值、示例和源码位置。
  • 新增文件路径边界说明,重点解释脚本目录、assets 目录、目标 App 私有目录之间的关系。
  • 新增文件 API 常见错误说明。
  • 修复文档搜索中 ChineseStemmer is not defined 导致前端搜索异常的问题。
  • 调整 Sphinx 中文搜索相关配置,补充中文搜索 stemmer fallback。
  • 修复 RST 标题层级与标题下划线长度问题,避免构建时出现 Title underline too short 警告。