VirtualApp Documentation

Virtual Engine for Android(Support 14.0 in business version)

11,107 stars Java Java 9 files · ~23,745 tokens #android#framework#plugin#plugin-manager
RAW Doc

Technical Documentation: asLody/VirtualApp

ℹ️ Provenance: Multi-Tier Ingestion · CodeWiki Reference

Overview (`README.md`)

English Doc

VA是什么?

VirtualApp(简称:VA)是一款运行于Android系统的沙盒产品,可以理解为轻量级的“Android虚拟机”。其产品形态为高可扩展,可定制的集成SDK,您可以基于VA或者使用VA定制开发各种看似不可能完成的项目。VA目前被广泛应用于APP多开、小游戏合集、手游加速器、手游租号、手游手柄免激活、VR程序移植、区块链、移动办公安全、军队政府数据隔离、手机模拟信息、脚本自动化、插件化开发、无感知热更新、云控等技术领域。 Github上代码已在2017年12月份停止更新,商业版代码在持续更新中,如需授权获得最新代码,请联系微信:10890

VA中的术语

术语 解释
宿主 集成VirtualApp类库(lib)的App叫做宿主
宿主插件 用于在同一个手机,运行另一种ABI的宿主包,又称做插件包,扩展包,宿主插件包,宿主扩展包
虚拟App/VApp VA的虚拟环境多开的app
外部App 手机真实环境安装的app

VA技术架构

VA技术一共涉及到了Android的APP层,Framework层以及Native层。
一个APP想要在Android系统上运行,必须要安装后系统才会接纳。安装到VA内部的APP实际上并没有安装到系统中,所以正常情况下是无法运行的。那如何才能让它运行呢?
答:那就只有“欺骗”系统,让系统认为已经安装。而这个“欺骗”过程就是VA Framework的核心工作内容,也是整个VA的核心技术原理。

下面介绍下在这3个层次分别做了什么事情:

层次 主要工作
VA Space 由VA提供了一个内部的空间,用于安装要在其内部运行的APP,这个空间是系统隔离的。
VA Framework 这一层主要给Android Framework和VAPP做代理,这也是VA的核心。VA提供了一套自己的VA Framework,处于Android Framework与VA APP之间。1. 对于VAPP,其访问的所有系统Service均已被 VA Framework 代理,它会修改VAPP的请求参数,将其中与VAPP安装信息相关的全部参数修改为宿主的参数之后发送给Android Framework(有部分请求会发送给自己的VA Server直接处理而不再发送给Android系统)。这样Android Framework收到VAPP请求后检查参数就会认为没有问题。2. 待Android系统对该请求处理完成返回结果时,VA Framework同样也会拦截住该返回结果,此时再将原来修改过的参数全部还原为VAPP请求时发送的。这样VAPP与Android系统的交互也就能跑通了。
VA Native 在这一层主要为了完成2个工作,IO重定向和VA APP与Android系统交互的请求修改。1. IO重定向是因为可能有部分APP会通过写死的绝对路径访问,但是如果APP没有安装到系统,这个路径是不存在的,通过IO重定向,则将其转向VA内部安装的路径。2. 另外有部分jni函数在VA Framework中无法hook的,所以需要在native层来做hook。

总结:
通过上面技术架构可以看到,VA内部的APP实际是跑在VA自己的VA Framework之上。
VA已将其内部APP的全部系统请求进行拦截,通过这项技术也能对APP进行全面控制,而不仅仅只是多开。并且为了方便开发者,VA还提供了SDK以及Hook SDK。

VA进程架构

VA运行时有5类进程:CHILD进程,VA Host Main进程,VA Host Plugin进程,VAPP Client进程,VAServer进程。
VA为了同时支持32位APP与64位APP,需要安装2个包:一个主包,一个插件包(在本文档中主包是32位,插件包是64位)。
2个包也是必须的,因为一个包只能运行在一种模式下,要么32位,要么64位。所以对于32位的APP,VA使用32位的主包去运行,对于64位的APP,VA则使用64位的插件包去运行。
在主包中含了VA的所有代码,插件包中只有一段加载主包代码执行的代码,无其他代码。所以插件包几乎不用更新,只需要更新主包即可。
另外主包是选择用32位还是64位,可以在配置文件中修改(比如对于要上GooglePlay的用户,会修改为主包64位,插件包32位)。

各类进程的作用与解释如下:

进程类型 作用
CHILD 由VA Host集成的其他进程,比如:保活进程,推送进程等。
VA Host Main VA主包的UI主界面所在的进程。默认主包是32位,插件包是64位,可在配置文件中修改切换。
VA Host Plugin 支持64位APP的插件包所在进程。默认主包是32位,插件包是64位,可在配置文件中修改切换。
VAPP Client 安装到VA中的APP启动后产生的进程,在运行时会将io.busniess.va:pxxx进程名修改VAPP的真实进程名。
VAServer VA Server的所在的进程,用于处理VA中不交予系统处理的请求。比如APP的安装处理。

VA几乎能满足您的一切需求

通过上面的技术架构,我们可以了解到VA可以对APP进行全面的控制,并且提供了Hook SDK,几乎能满足您在各个领域的一切需求:

  1. 可以满足您的双开/多开需求
    VA可以让您在同一部手机上安装多个微信/QQ/WhatsApp/Facebook等APP,实现一部手机,多个账号同时登录。

  2. 可以满足您的移动安全需求
    VA提供了一整套内部与外部的隔离机制,包括但不限于(文件隔离/组件隔离/进程通讯隔离),简单的说VA内部就是一个“完全独立的空间”。
    通过VA可将工作事务与个人事务安全的隔离,互不干扰。稍作定制即可实现应用行为审计、数据加密、数据采集、数据防泄漏、防攻击泄密等移动安全相关的需求。
    2.1 应用行为审计
    通过VA提供的HOOK能力可以实现实时监测用户使用行为,将违规信息上传到服务器;并能轻易实现诸如时间围栏(在某个时间段内能否使用应用的某个功能)、地理围栏(在某个区域内能否使用应用的某个功能)、敏感关键字过滤拦截等功能需求。
    2.2 数据加密
    通过VA提供的HOOK能力可以实现对应用的全部数据/文件加密,保证数据/文件落地安全。
    2.3 数据采集
    通过VA提供的HOOK能力可以实现应用数据的实时无感上传需求,如聊天记录、转账记录等,防止事后删除无法追溯。
    2.4 数据防泄漏
    通过VA提供的HOOK能力可以实现应用防复制/粘贴、防截屏/录屏、防分享/转发、水印溯源等需求。
    2.5 防攻击泄密
    通过VA提供的应用管控能力可以将APP获取短信/通讯录/通话记录/后台录音/后台拍照/浏览历史/位置信息等隐私相关的行为完全控制在沙盒中,防止木马/恶意APP获取到用户真实的隐私数据,造成泄密等严重后果。

  3. 可以满足您的免ROOT HOOK需求
    VA提供了Java与Native的Hook能力,通过VA,您可以轻易实现诸如虚拟定位、改机、APP监控管理、移动安全等各种场景需要的功能。

  4. 可以满足您的APP静默安装需求
    VA提供了APP静默安装,静默升级,静默卸载的能力。如应用商店或游戏中心在集成VA后可以避免需要用户手动点击确认安装的操作,做到下载后立即安装到VA内,给用户带来“小程序”搬的体验,彻底避免了应用不易被用户安装上的问题。

  5. 可以满足您的APP管控需求
    您可以通过VA清楚的掌握APP访问了哪些系统API,哪些敏感数据,哪些设备信息等。比如APP是否访问了联系人,相册,通话记录,是否访问了用户的地理位置等信息。
    当然,您还可以通过VA控制或者构造自定义的信息给这些APP。不仅于此,您还可以获取到APP的私有数据,比如聊天数据库等。总之通过VA提供的应用管控能力,您可以轻易控制APP的一切行为,甚至修改APP与服务器交互内容等。

  6. 可以满足您的海外市场需求
    VA实现了对Google服务的支持,以支持海外的App运行,比如Twitter、Messenger、WhatsApp、Instagram、FaceBook、Youtube等。

  7. 可以满足您的VR程序移植需求
    可以通过VA的Hook能力拦截VR设备的API,让您无需改动代码即可将VR程序移植到新的设备。

  8. 可以满足您几乎一切能想到的需求
    VA对于内部的App具有完全的监管和控制能力,几乎能满足您的一切需求!

  9. 同时VA也是该技术领域唯一一款对外商业授权的产品
    截止目前已有上百家授权客户在付费使用VirtualApp商业版代码,集成VirtualApp代码的APP日启动次数超过2亿次,众多安卓工程师向我们提供不同场景下的用户反馈,通过我们技术团队不断优化迭代,不断提升产品性能与兼容性!

VA的特有能力

  • 克隆能力
    可以克隆外部系统中已经安装的App,并在内部运行,互不干扰。典型应用场景为App双开。

  • 免安装能力
    除了克隆已安装之外,VA可以直接在内部安装(外部无感知)apk,并在内部直接运行。典型应用场景为插件化,独立应用市场等。

  • 多开能力
    VA不仅可以“双开”,独特的多用户模式支持用户在内部无限多开同一个App。

  • 内外隔离能力
    VA是一个标准的沙盒,或者说“虚拟机”,提供了一整套内部与外部的隔离机制,包括但不限于(文件隔离/组件隔离/进程通讯隔离),简单的说VA内部就是一个“完全独立的空间”。在此基础之上,稍作定制即可实现一部手机上的“虚拟手机”。当然您也可以发挥想象,定制成应用于数据加密,数据隔离,隐私保护,企业管理的应用系统。

  • 对于内部App的完全控制能力
    VA对于内部的App具有完全的监控和控制能力,这点在未Root的外部环境中是绝对无法实现的。

详细(下拉打开)

  1. 服务请求控制,首先VA直接提供了一些服务请求的拦截,您可以在集成VA的时候方便的定制这些服务请求,包括但远不限于(App请求安装apk/App请求打开某些文件/App请求定位数据/App请求手机信息等等)
  2. 系统API控制,VA虚拟并实现了整个安卓系统框架,这也是VA可以免安装在内部运行apk的原理,您可以对虚拟框架的实现进行修改以动态监测分析App的行为等;除此之外,您还可模拟一些系统行为以实现一些在外部难以实现的需求(例如游戏手柄)。
  3. 内存读写,VA可以无需Root读写内部App进程的内存。
  4. 免Root调试,VA可以免Root调试(ptrace)内部的App进程,基于此您还可以实现免Root的进程注入。
  5. 加载任意“插件”和“行为”,VA内部的App进程由VA的框架Client端代码派生而来,所以您可以在进程的入口代码插入任何“加载”以及“控制”逻辑。这些实现都非常简单。
  6. 方法Hook,VA内置了一套运行于Android各个版本(直到AndroidQ)的Xposed框架以及native hook框架,基于此您可以方便的Hook任意内部App的任意Java/Native方法。可以轻松实现一个免Root的Xposed环境(有实例代码)。
  7. 文件控制,VA内置了完整的文件重定向,可以方便的控制内部App的文件的读写,基于此可以实现对文件的保护加密等功能。
  8. 注:以上控制能力均有实现代码或者实例以作参考。

VA的其他特性

  • 高性能
    进程级“虚拟机”,VA独特的实现方式让其性能几乎于原生App一致,更不需要普通虚拟机漫长的启动。

  • 全版本支持
    支持5.0-17.0,支持32位/64位app,支持ARM以及X86处理器。并且支持未来将更新的Android版本。

  • 易扩展与集成
    VA 的集成方式与普通Android库类似,即使您的App已经完成上线,您也方便的可以集成VA,享受VA带来的能力。

  • 支持Google服务
    提供Google服务的支持,以支持海外的App

VA与其他技术方案对比

在做企业级移动安全时,往往需要对APP进行管控,以下是列出的可能技术方案对比:

技术方案 原理简介 点评 运行性能 兼容稳定性 项目维护成本
二次打包 通过反编译目标APP,加入自己的控制代码,重新打包 1.现在的APP几乎都有加固或防篡改保护,重打包已是一件非常困难的事 2.手机系统也会检测APP是否被重打包,如果重打包,会直接提示用户存在安全风险,甚至不让安装3.针对每一个APP,甚至每一个版本都要深入去逆向分析,耗时耗力,难于维护 优秀 差 高
定制ROM 通过定制系统源码,编译刷到指定手机 只能针对指定的内部手机,局限性太大,无法扩展 优秀 优秀 高
ROOT手机 通过ROOT手机,刷入xposed等类似框架 1.ROOT手机现在本身已是一件不太可能的事 2.现实中也很难让用户能去ROOT自己的手机 优秀 差 高
VA 轻量级虚拟机,速度快,对设备要求低 无上述风险点 优秀 优秀,有上百家企业在同时测试反馈 低,VA提供了API并有专业的技术团队保障项目稳定运行

通过以上对比可以看出,VA是一款优秀的产品,并且能降低您的开发维护成本!

集成VA步骤

第1步:在您的Application中调用VA接口VirtualCore.get().startup()来启动VA引擎
第2步:调用VA接口VirtualCore.get().installPackageAsUser(userId, packageName)将目标APP安装到VA中
第3步:调用VA接口VActivityManager.get().launchApp(userId, packageName)启动APP
仅通过以上3个API就完成了基础使用,VA已屏蔽了复杂的技术细节,并提供了接口API,让您的开发变得很简单!

VA的兼容稳定性

VA已被上百家企业进行了广泛测试,包含数十家上市公司高标准的测试及反馈,几乎涵盖了海内外的各种机型设备和场景!
为您的稳定运行提供了充分的保障!

截止目前,支持的系统版本:

系统版本 是否支持
5.0 支持
5.1 支持
6.0 支持
7.0 支持
8.0 支持
9.1 支持
10.0 支持
11.0 支持
12.0 支持
13.0 支持
14.0 支持
15.0 支持
16.0 支持
17.0 支持

支持的APP类型:

APP类型 是否支持
32位APP 支持
64位APP 支持

支持的HOOK类型:

Hook类型 是否支持
Java Hook 支持
Native Hook 支持

支持的CPU类型:

Hook类型 是否支持
ARM 32 支持
ARM 64 支持

集成VA遇到问题如何反馈?

购买授权后我们会建立微信群,有任何问题可以随时反馈给我们,并根据优先级在第一时间处理!

VA开发文档

VA开发文档请参考:开发文档

授权说明

VirtualApp虚拟机技术归属于:山东盒一网络科技有限公司(原:济宁市罗盒网络科技有限公司),于2015年至2026年申请多项VirtualApp知识产权,受中华人民共和国知识产权法保护。当您需要使用Github上的代码时,请购买商业授权,获取商业授权后将可以收到最新VirtualApp商业版全部源代码。上百家授权客户在付费使用VirtualApp商业版代码,集成VirtualApp代码的APP日启动次数超过2亿次,众多安卓工程师向我们提供不同场景下的用户反馈,通过我们技术团队不断优化迭代,VirtualApp商业版代码性能更好、兼容性更高。当您的公司获取授权后,将成为其中一员,享受这些不断迭代完善后的技术成果。并可以和我们的授权客户进行运营、技术及商业上的互动合作。

负责人:张总
微信:10890

严重声明

您如果未经授权将VirtualApp用于内部使用、商业牟利或上传应用市场,我们将取证后报警(侵犯著作权罪)或起诉,这将对您所属公司造成刑事责任及法律诉讼,影响到您公司的商誉和投资。购买商业授权为您节省大量开发、测试和完善兼容性的时间,让您更多时间用于创新及盈利。罗盒科技已在2020年报警和起诉了一些个人及公司。

为响应国家对于知识产权的保护号召!凡举报自己所在公司或其他公司未经授权,违法使用VirtualApp代码开发产品的,一经核实给予现金奖励。我们会对举报人身份保密!举报联系微信:10890

商业版主要更新

  1. 兼容最新Android 17.0
  2. 支持Binder拦截,不再使用动态代理
  3. 支持Seccomp-Bpf拦截
  4. 不易被杀毒软件误报
  5. 框架优化,性能大幅提升
  6. 手机系统及APP兼容性大幅提升
  7. 完美运行Google服务
  8. 支持运行纯64位App
  9. 内置XPosed Hook框架
  10. 增加定位模拟代码
  11. 增加改机代码
  12. 其他700+项问题的修复和改进,详情请见下表

2017年-2026年商业版代码更新详细

2026年9月1号 至 2026年10月7号 商业版代码更新内容
741、完善ART/JNI方法校验和字符串释放处理,修复初始化发生异常后仍被标记为成功的问题
740、完善ARM Hook安装失败处理,修复内存页范围计算及原有页权限恢复不正确的问题
739、修复UID处理线程初始化失败后一直等待,以及失败重试时状态异常和资源泄漏的问题
738、修复16KB内存页环境下路径检查对齐错误,导致正常文件访问失败的问题
737、修复ARM64指令重定位时负偏移地址计算错误、部分指令字段被错误改写,以及ADRP原始页地址未正确保留的问题
736、修复Binder拦截后异常类型发生变化,导致APP无法正确处理异常的问题
735、适配部分Android 16手机上Service连接回调的参数差异
734、修复账号token失效后清理不完整,仍可能获取到旧token的问题
733、修复普通账号认证成功后token未保存的问题
732、修复自定义账号token缓存命中后仍重复请求认证的问题
731、修复stopService返回状态错误,完善服务启动与停止衔接处理
730、修复调用finishAffinity后Activity结束状态不正确的问题
729、修复Seccomp-Bpf模式下使用相对路径添加inotify监听失败的问题
728、修复futimens更新文件时间时错误返回权限异常的问题
727、修复syscall(truncate)参数传递错误导致文件截断失败的问题
726、修复账号可见性配置在重启后丢失或归属到错误分身的问题
725、修复取消全部闹钟时误取消其他多开APP闹钟的问题
724、修复查询通知时混入其他APP通知,以及使用返回的tag取消通知失败的问题
723、修复查询通知监听权限和气泡配置时出现空指针的问题
722、修复多包安装完成后父安装会话未结束、完成通知缺失的问题
721、完善安装会话权限校验,防止不同APP操作彼此的安装任务
720、修复在非0虚拟用户中安装新APP时,错误安装到用户0的问题
719、修复安装包含重复APK的安装包时,安装线程卡死的问题

2026年8月5号 至 2026年 8月31号 商业版代码更新内容

718、修复部分手机上启动APP后按返回键无反应
717、处理fake_dlopen,解决某些函数无法找到的问题
716、处理hook后的权限恢复
715、处理maps中的VMA,将某些被mprotect拆分的合并
714、修复LocaleManager中的函数名错误

2026年7月17号 至 2026年 8月4号 商业版代码更新内容

713、对sdcard安装的文件进行了系统APP模拟
712、修复getOatFile()函数
711、路径模拟相关的配置调整
710、执行execve时增加对LD_LIBBRAY_PATH的支持
709、修复多个不同类型的与加固/检测相关的导致APP无法启动的问题

2017年 12月 至 2026年 7 月 16 日 商业版代码更新内容(下拉打开)

2026年7月7号 至 2026年 7月16号 商业版代码更新内容

708、修复某些c函数指令较短hook后导致后面的指令被覆盖
707、调整ext插件的进程号,避免p0进程过早启动导致未初始化完全
706、让插件进程也支持生成和加载binder stub dex

2026年6月22号 至 2026年 7月6号 商业版代码更新内容

705、适配17.0 beta5上的IJobCallback
704、适配17.0上startService API增加了包名检测
703、增加对AccessibilityManager API的适配
702、更新 HiddenApiBypass

2026年6月4号 至 2026年 6月21号 商业版代码更新内容

701、修复Parcel解析时候的long与int解析错误
700、修复启动JobService时acore进程容易出现ANR
699、适配IRoleManager API
698、更新依赖项
697、修升级AGP到9.2.1
696、对UI适配无边框
695、修复17.0上遇到的反射错误
694、修复target sdk升级到37后遇到的KeepAliveService崩溃

2026年5月22号 至 2026年 6月3号 商业版代码更新内容

693、将maps文件调整为按行处理,避免bad alloc
692、对部分抗检测的调整
691、增加对某些加固的支持
690、处理有些加固APP的进程在部分设备上无法kill进程
689、修复baidu app在某些手机上无法打开
688、适配某些加固导致的内存错误
687、针对一些特征检测的处理

2026年5月7号 至 2026年 5月21号 商业版代码更新内容

686、增加对proc文件系统的更多特征处理,包括inline hook&seccomp-bpf模式
685、对访问父进程的proc也增加处理
684、适配17.0上ShortcutServiceStub API
683、修复appendFrom的时候crash,使用setDataSize()来清空所有数据
682、修复baidu app在某些手机上无法打开
681、修复Unable to instantiate service
680、修复有些APP因为请求不到android.permission.READ_PHONE_NUMBERS提示:"已禁用该权限,请手动打开该权限"
679、修复包名错误
678、适配特定app提示环境异常

2026年4月16号 至 2026年 5月5号 商业版代码更新内容

677、调整和简化seccomp-bpf配置代码,通过getSeccompBpfHookMode()控制hook范围
676、修复seccomp-bpf调用CallTrustedSyscall后的重入问题
675、修复有些加固后的APP执行su检测的时候提示设备已root
674、增加对/proc/self/pid/fd和/proc/pid/task/map_files的遍历处理
673、对于使用fstat获取maps/status/cgroup等文件时转为获取真实文件信息
672、增加功能配置功能:可以将VA自身日志通过socket发往logd
671、修复通过google play安装后/data/data/app.v/virtual/data/app/com.xx.xx/split_config.arm64_v8a.apk is writeable导致无法加载问题
670、适配IStatusBarService的相关API

2026年4月1号 至 2026年 4月15号 商业版代码更新内容

669、修复WifiManager中与AttributionSource相关的参数
668、修复seccomp-bpf crash的问题

2026年3月17号 至 2026年 3月31号 商业版代码更新内容

667、实现Contacts访问模拟
666、修复11.0+上getLastLocation()参数问题
665、修复canAuthenticate()无权限报错问题
664、增加对IStatusBarService处理

2026年3月5号 至 2026年 3月16号 商业版代码更新内容

663、17.0 beta2上的报错修复
662、 Seccomp-bpf only相关的调整
661、反射代码调整

2026年2月12号 至 2026年 3月4号 商业版代码更新内容

660、增加对部分加固的支持
659、 fp指针调整避免某些App无法打开

2026年2月1号 至 2026年 2月11号 商业版代码更新内容

658、 修复NativeEngine.onGetCallingUid在VisitRoots的时候crash
657、 Secomp-Bpf开启后,执行execve时支持fd
656、fix getFromLocation crash on 15.0+

2025年12月31号 至 2026年 1月30号 商业版代码更新内容

655、增强环境检测方面的处理
654、.0上AdvancedProtectionService以及ISupervisionManager适配
653、fix AttributionSource子类验证报错:AttributionSource should be unparceled during a binder
652、fix ParceledListSlice->getList返回null
651、对于一些没有权限的函数调用进行处理
650、maps处理方式更新
649、对fp指令范围进行判断,避免crash

2025年12月19号 至 2025年 12月30号 商业版代码更新内容

648、从处理openat2与faccessat2,seccomp等调用
647、适配APP中对seccomp-bpf的调用
646、处理某些应用因为检测打不开

2025年12月3号 至 2025年 12月18号 商业版代码更新内容

645、某些svc处理
644、系统路径调整
643、maps调整

2025年11月12号 至 2025年 12月2号 商业版代码更新内容

642、新功能:Native层增加机型模拟支持
641、支持对应用强制开启机型模拟/强制使用真机信息
640、seccomp-bpf对ptrace的一些处理
639、修复执行Java命令时进程可能崩溃的问题
638、修复其他几处崩溃的问题

2025年10月29号 至 2025年 11月11号 商业版代码更新内容

637、新功能:Seccomp-Bpf下增加了对execve的调用支持
636、处理了与反射相关的几个地方
635、对几个内存文件的chmod处理

2025年10月11号 至 2025年 10月28号 商业版代码更新内容

634、修复IBatteryStats相关的空指针

2025年9月18号 至 2025年 10月10号 商业版代码更新内容

633、处理onNewIntent()中的activity Referrer
632、适配NotificationProviderPublic
631、修复15.0+上isDirectlyHandlingTransaction()的多线程处理
630、隐藏Libcore.os的反射获取
629、binderproxy模式支持IBatteryStats
628、适配某些加固APP

2025年9月2号 至 2025年 9月17号 商业版代码更新内容

627、Android 16kb page size 适配
626、fix蓝牙几个代理类的代码错误
625、处理某些APP在Application->attach中获取到宿主Application的场景
624、处理Activity referrer相关的
623、处理processOutsideIntent时intent包含vapp class的情况
622、针对某些oppo 13.0机型适配
621、处理调用ArrayUtils.indexOf时,有的地方按0开始起步有的地方按1开始起步导致异常,都统一为1
620、适配LockSettings/WifiScanner/NetworkScoreManager/WifiManager/SensitiveContentProtectionManager等几个manager
619、新功能模式下BinderProxyInjectManager.addInjector增加判断,避免有些因为class不存在导致crash
618、新功能模式下支持Instrumentation注入
617、增加对native层获取宿主信息的处理

2025年8月9号 至 2025年 9月1号 商业版代码更新内容

616、增加对setxattr/lsetxattr/bind/connect/syscall等几个libc api处理
615、增加对execve启动的进程实现inline hook
614、增加可对application中的全部路径模拟为系统安装路径
613、增加对logcat等命令的过滤处理
612、修复app 崩溃/anr等系列问题
611、修复ParceledListSlice.getList返回Null的问题

2025年7月22号 至 2025年 8月8号 商业版代码更新内容

610、增加对INetworkScoreService的处理
609、修复新功能在release下的一些错误
608、修复某些手机上新功能无法打开APP
607、修复Tethering相关的crash

2025年7月3号 至 2025年 7月21 商业版代码更新内容

606、与新功能相关的路径处理
605、一些bug处理

2025年5月1号 至 2025年 7月2号 商业版代码更新内容

604、新功能开发:基于拦截Binder的方式来实现对系统AIDL调用的拦截。通过这种方式可不再使用动态代理,对于稳定性将会有比较大提升
603、16.0最新版本继续适配

2025年4月16号 至 2025年 4月30号 商业版代码更新内容

602、对Android 16.0 beta 4 适配
601、完善seccomp-bpf重定向相关的功能
600、增加配置可以让APP只使用seccomp-bpf,不使用inline hook
599、将target sdk升级到34
598、修复va core进程由于client为空导致的crash
597、启动进程的时候增加重试,避免在某些机型上由于进程死亡太频繁导致无法启动进程
596、对于某类型加固后是否需要安装provider的部分改为动态判断
595、修复demo在某些设备上由于title为null导致的crash

2025年3月27号 至 2025年 4月15号 商业版代码更新内容

594、修复GMS无法调起登录的问题
593、增加对IInputMethodManagerGlobalInvoker的hook
592、修复工作空间中无法打开VAPP的问题
591、适配微信8.0.57

2025年3月20号 至 2025年 3月26号 商业版代码更新内容

590、增加对AppSearchManager的适配
589、增加对DomainVerificationManager的适配
588、增加对SystemUpdateManager的适配
587、修复多个进程同时启动同一个进程时的crash问题

2025年2月28号 至 2025年 3月19号 商业版代码更新内容

586、seccomp 相关的调整
585、修复微信在14.0+上开启seccomp-bpf无法打开的问题
584、新增对StorageStatsManager的适配
583、UsageStatsManager相关API适配

2025年2月11号 至 2025年 2月27号 商业版代码更新内容

582、适配最新版微信

2025年1月24号 至 2025年 2月10号 商业版代码更新内容

581、对IO进行inline hook时暂停所有Java线程,避免冷启动时因多线程导致的低概率crash

2025年1月8号 至 2025年 1月23号 商业版代码更新内容

580、installer静默安装部分适配
579、修复静态广播收不到消息
578、修复pending intent数据丢失问题
577、input manager 14.0+上的适配
576、蓝牙适配
575、queryStatsForPackage适配
574、修复有些手机上显示不出应用列表
573、其他一些小问题适配

2024年12月21号 至 2025年 1月7号 商业版代码更新内容

572、Seccomp-bpf支持32位
571、修复某些情况下路径多次重定向的问题
570、修复抖音人脸识别时可能白屏的问题
569、去掉几年前为抖音打不开做的一些修改

2024年12月7号 至 2024年 12月20号 商业版代码更新内容

568、修复startIntentSenderFoeResult无法工作的问题
567、修复GMS由于StatsManager无法hook导致crash的问题

2024年11月27号 至 2024年 12月6号 商业版代码更新内容

566、修复release打包后IJobService中的onNetworkChanged等几个函数被混淆导致找不到crash的问题
565、修复由于BluetoothAdapter.sService为null导致IBluetooth hook失败的问题
564、修复packagesettings被覆盖的问题
563、删除getCallingUid()中的缓存代码
562、Seccomp条件判断时处理Application.name为Null的情况
561、AGP升级到8.2.0

2024年11月12号 至 2024年 11月26号 商业版代码更新内容

560、重定向路径调整,区分/data/data/com.xxx以及/data/user/0/com.xxx,使其更符合APP使用实际使用的路径
559、适配fixupAppDir
558、reverseRedirectedPath增加检查,防止路径多次重复转换
557、修复splitNames信息缺失导致部分应用无法正常使用
556、补充一批normal权限,解决部分APP因为权限丢失无法正常使用的问题

2024年10月31号 至 2024年 11月11号 商业版代码更新内容

555、新功能:增加Seccomp-Bpf支持,实现更底层的拦截
554、增加对部分加固APP的支持
553、系统OTA升级时对Split Apks重新安装

2024年10月14号 至 2024年 10月29号 商业版代码更新内容

552、所有手机package.ini版本升级到7,避免某些情况下出现应用丢失
551、修改Demo包名

2024年9月15号 至 2024年 10月13号 商业版代码更新内容

550、移除对Sandhook的依赖
549、移除几处hook,避免部分机型crash
548、移除未使用到的goAsync,避免ANR
547、移除部分对1.X的升级处理废弃代码
546、修复手机系统升级到13.0+上后,应用列表消失的问题

2024年8月23号 至 2024年 9月14号 商业版代码更新内容

545、修复IO重定向中一系列函数未对dfd正确处理

2024年8月9号 至 2024年 8月22号 商业版代码更新内容

544、修复Native的一个空指针问题
543、修复Native的某个函数由于栈上随机数导致判断出错
542、修复unity中的检测问题
541、修复publishService crash问题
540、修复getPid死循环崩溃问题

2024年8月3号 至 2024年 8月8号 商业版代码更新内容

539、修复微信等APP因为webview导致的crash问题

2024年7月19号 至 2024年 8月2号 商业版代码更新内容

538、修复sandhook崩溃问题
537、修复sandhook hook不起效问题
536、替换sandhook中inline hook部分
535、修复android.permission.DETECT_SCREEN_CAPTURE权限导致的crash问题
534、修复静态广播导致的crash问题
533、修复百度搜索crash的问题
532、修复ResolveActivity跳转到外部应用时没有过滤export为false的场景导致crash
531、修复在某些华为设备上微信白屏的问题
530、修复微信流量异常的问题
529、class_linker适配android 15
528、修复 readlinkat参数问题导致的crash
527、解决某些unity路径检测的问题

2024年7月3号 至 2024年 7月18号 商业版代码更新内容

526、适配了几十个API,很大程度提升了稳定性
525、调整stopService不再走initProcess流程,解决了某些情况下的死锁问题
524、修复 startprocess启动App后再次进入VActivityManagerService导致死锁的问题
523、修复锁屏/亮屏广播引起的crash问题

2024年6月17号 至 2024年 7月2号 商业版代码更新内容

522、AttributionSoure中的uid调整
521、修复微信注册,找回账号等几个界面白屏的问题

2024年6月4号 至 2024年 6月16号 商业版代码更新内容

520、将内置的Java hook框架SandHook调整为可选配置
519、修复VA_ENABLE_EXT_FULL_SOURCE_CODE功能选项开启时,加载so错误的问题

2024年5月8号 至 2024年 6月3号 商业版代码更新内容

518、修复微信在鸿蒙4.0+上无法使用的问题
517、调整VA demo package name

2024年4月20号 至 2024年 5月7号 商业版代码更新内容

516、适配华为账户登录和授权登录等功能
515、适配荣耀账户登录和授权登录等功能
514、修复Service中getApplicationContext返回Null的问题

2024年4月4号 至 2024年 4月19号 商业版代码更新内容

513、修复link&unlink参数没有处理重定向的问题
512、修复AutoFillManagerStub未生效问题
511、适配高版本ShadowJobService

2024年3月7号 至 2024年 4月2号 商业版代码更新内容

510、修复数款游因为戏二次注册provider导致无法打开

2024年2月19号 至 2024年 3月6号 商业版代码更新内容

509、修通知跳转Crash
508、AMS API适配
507、DevicePolicyManager API适配
506、BlueTooth API适配
505、修复抖音crash问题

2024年1月25号 至 2024年 2月18号 商业版代码更新内容

504、修复抖音在部分手机无法打开的问题
503、修复抖音在部分手机运行一小段时间后崩溃的问题
502、修复抖音在部分手机crash后一直打不开的问题
501、修复抖音极速版在部分手机无法打开的问题
500、修复抖音极速版在部分手机运行一小段时间后崩溃的问题
499、修复抖音极速版在部分手机crash后一直打不开的问题
498、UserManager相关API适配
497、PackageManager相关API适配
496、Notification相关API适配
495、FingerprintManager相关API适配

2024年1月5号 至 2024年 1月24号 商业版代码更新内容

494、Activity Token获取适配
493、适配最新版微信

2023年12月21号 至 2024年 1月4号 商业版代码更新内容

492、适配libc可能没有R权限的情况

2023年12月5号 至 2023年 12月20号 商业版代码更新内容

491、修复储存空间异常的问题

2023年10月24号 至 2023年 12月4号 商业版代码更新内容

490、取消对Xposed依赖
489、适配最新版微信
488、适配setCompatibilityVersion
487、取消hookGetCallingUid对xposed的依赖
486、蓝牙适配
485、AddToDisplayAsUser处理
478、PendingIntent适配
484、MediaRecorder适配
483、处理dispatchVolumeKeyEvent API
482、修复AttributionSource cast crash
481、增加配置:是否优先使用外部app
480、修复启动前台service crash
479、修复14.0上renameat太短导致hook后覆盖其他函数的问题

2023年10月8号 至 2023年 10月23号 商业版代码更新内容

478、修复Annotation依赖包为空的问题
477、修复抖音等APP由于动态框架导致无法打开Activity的问题
476、修复纯Java APP在64位下以32位模式安装的问题
475、修复了13.0+上的class linker偏移检测问题
474、调整默认使用isUseRealDataDir模拟真实路径
473、JobServiceStub适配
472、IO重定向增加对renameat2的hook
471、修复APK安装模式下某些APP拍照黑屏
470、修复APK安装模式下微信小程序无法使用的问题

2023年9月16号 至 2023年 10月7号 商业版代码更新内容

469、移除已经废弃的虚拟定位代码
468、修复WhatsApp 来电通知bug
467、修复GMS相关问题
466、修复WhatsApp无法跳过短息验证界面问题
465、修复WhatsApp等部分APP启动后界面白屏问题
464、适配Alarms 相关API

2023年9月6号 至 2023年 9月15号 商业版代码更新内容

463、14.0上JobScheduler API适配
462、修复从sdcard上安装时signature可能获取的可能不是最旧的问题
461、LocaleManager适配

2023年8月16号 至 2023年 9月5号 商业版代码更新内容

460、14.0上JobScheduler适配
459、修复API broadcastIntentWithFeature
458、修复WhatsApp验证跳转的问题
457、内部Provider访问适配

2023年8月2号 至 2023年 8月15号 商业版代码更新内容

456、修复Twitter白屏的问题
455、修复ContentProvider在12.0+上的适配问题
454、修复微信在nova9z上崩溃的问题
453、修复微信等APP发送定位时黑屏的问题
452、编译SDK版本升级到14.0

2023年7月13号 至 2023年 8月1号 商业版代码更新内容

451、适配12.0+上蓝牙相关的10来个API
450、适配UserManager相关的10来个API

2023年6月30号 至 2023年 7月12号 商业版代码更新内容

449、修复JobService unbind崩溃问题
448、修复JobService persisted崩溃问题

2023年5月26号 至 2023年 6月29号 商业版代码更新内容

447、修复部分APP无法录音的问题
446、修复从Sdcard安装APK失败的问题
445、更改VA Demo包名

2023年4月28号 至 2023年 5月25号 商业版代码更新内容

444、适配Android 14.0

2023年3月18号 至 2023年 4月27号 商业版代码更新内容

443、修复GMS支持,修复各种crash,权限等问题
442、修复GooglePlay无法打开的问题
441、修复GooglePlay无法登录Google账号的问题
440、修复Youtube,WhatsApp等APP无法登录Google账号的问题
439、修复Facebook无法打开的问题

2023年2月17号 至 2023年 3月17号 商业版代码更新内容

438、修setPictureInPictureParams crash

2023年1月27号 至 2023年 2月16号 商业版代码更新内容

437、修复mOpPackageName空指针
436、修复13.0上PackageManager几个flags参数导致的crash
435、修复VAPP返回主页的Intent crash
434、TelecomManagerStub API适配

2022年12月9号 至 2023年 1月26号 商业版代码更新内容

433、修复PendingIntent flag处理问题

2022年11月9号 至 2022年 12月8号 商业版代码更新内容

432、修复Facebook在某些情况下无法启动的问题
431、启动外部App时,排除对VA自身的判断
430、修复queryIntentServices过滤规则

2022年10月9号 至 2022年 11月8号 商业版代码更新内容

429、修复当VA_AUTHORITY_PREFIX不等于包名时找不到Provider的问题:"Failed to find provider info ..."
428、getPermissionActivityIntent处理
427、修复特殊情况下,检查权限无限弹窗
426、强调Intent使用外部通讯录(如果被第三方接管,建议使用外部可见)
425、新增几个Java API适配
424、修复修复部分后台Activity跳转问题
423、修复在10.0+上后台Activity无法启动的问题

2022年 8月20号 至 2022年 10月8号 商业版代码更新内容

422、新功能:增加启动插件Activity代理,绕过后台5s限制
421、修复Provider在10.0+上crash的问题
420、适配最新版微信
419、适配克隆时不显示sdcard上的APK
418、适配12.0+上PendingIntent Flags必须为FLAG_UPDATE_CURRENT/FLAG_IMMUTABLE
417、修复MediaProvider因为ACCESS_MEDIA_LOCATION 权限检查导致的crash
416、修复12.0+上debug模式下hook失败的问题
415、适配在Multi User账户下crash的问题
414、适配由于后台限制导致VA Core启动插件中Activity失败的问题

2022年 7月27号 至 2022年 8月19号 商业版代码更新内容

413、Android 13.0继续适配
412、主版调整为64bit
411、修复某些华为手机上App无法打开的问题
410、修复OPPO 13.0上无法打开应用的问题
409、修复百度语音TTS的调用问题
408、修复数据隔离后仍可以访问sdcard根目录的问题
407、修复鸿蒙手机上的崩溃问题
406、修复Debug模式下Hook失效问题
405、添加对BinderInvocationStub的混淆处理,避免混淆后崩溃问题
404、修复Native层调用free函数可能导致崩溃的问题
403、修复微信由于虚拟文件系统导致的崩溃问题

2022年 7月9号 至 2022年 7月26号 商业版代码更新内容

402、Android 13.0适配
401、修复开启虚拟储存后文件路径的处理问题
400、修复12.0上Notification没有提示的问题

2022年 4月28号 至 2022年 5月31号 商业版代码更新内容

399、修复onGetCallingUid hook引起的崩溃问题
398、修复微信8.0.22启动崩溃的问题

2022年 4月5号 至 2022年 4月27号 商业版代码更新内容

397、去掉sandhook中一些多余的hook代码,避免某些APP无法启动

2022年 3月13号 至 2022年 4月5号 商业版代码更新内容

396、新增功能:在VA中实现内置media provider,以支持媒体库隔离等需求
395、修复微信/QQ使用语音时崩溃
394、蓝牙崩溃问题适配
393、增加部分Log
392、删除一些无用代码

2022年 1月22号 至 2022年 3月12号 商业版代码更新内容

391、修复华为手机上StorageManager没有被hook的问题
390、修复最新版微信无法从SD卡启动的问题
389、PackageInfo中增加对requestedPermissionsFlags字段的处理
388、新增VSettingsProvider,避免内置应用没有权限操作settings provider导致异常
387、修复微信等APP启动黑屏,ANR等问题
386、新增对MediaProvider的hook
385、新增对插件shareUserId的处理,从而可以配置将插件的数据放到主包中
384、新增可以配置是否将Tinker禁用
383、修复Android 12权限处理适配

2021年 12月30号 至 2022年 1月21号 商业版代码更新内容

382、Sandhook适配12.0
381、修复Sandhook在部分11.0上不生效的问题
380、增加编译选项VA_FULL_EXT控制是否将VA源码编译到插件,满足加固场景。

2021年 11月24号 至 2021年 12月29号 商业版代码更新内容

379、Android 12.0第一轮适配已完成
378、Demo App在11.0上增加文件权限检测
377、修复静态广播接收者在独立进程无法接收广播的问题
376、修复微信第一次登录可能crash问题
375、修复部分APP无法显示头像问题
374、修复在部分OPPO手机上打不开问题

2021年 9月21号 至 2021年 11月23号 商业版代码更新内容

373、修复WhatsApp在360手机上黑屏问题
372、增加VA内外广播通信测试demo
371、修复抖音极速版兼容性问题
370、修复readlinkat返回值精度
369、修复从外部安装app,没有引用org.apache.http.legacy的问题
368、修复华为Nova 5i, 64位主包兼容性
367、修复11.0上外部存储重定向问题
366、修复11.0上GMS登录问题
365、修复11.0 部分APP读写sdcard报错的问题
364、修复va core进程死亡后,APP可能打不开的问题
363、增加未安装插件时无法启动的错误日志

2021年 8月22号 至 2021年 9月20号 商业版代码更新内容

362、横屏重新适配
361、修复部分APP通过file协议安装后无法打开的问题
360、修复传递给JobIntentService中Intent数据丢失问题
359、修复JobIntentService第二次调用无法工作的问题
358、修复华为手机上某些APP奔溃的问题
357、修复小米手机上游戏登录问题
356、修复某些应用加固后无法打开的问题
355、增加对关联启动权限检测
354、targetSdk 30适配
353、修复targetSdk为30时,某些应用无法上网的问题
352、修复targetSdk为30时,sdcard无法访问的问题
351、编译脚本中使用cmake替换gradle task
350、移除过时文档

2021年 8月7号 至 2021年 8月21号 商业版代码更新内容

349、调整优化gradle脚本
348、hidedenApiBypass支持Android R+
347、targetSdk 30 支持
346、修复VIVO系统服务bug
345、修复VIVO手机无法使用摄像头的bug
344、修复dex加载异常状态的获取
343、修复Android R上libart.so路径问题
342、修复Andoid Q+ 删除通知的bug
341、修复APN uri的权限检查
340、修复Android R暂停恢复线程状态
339、修复debug模式下部分hook失效情况
338、修复hook在R之后的一些bug

2021年 4月25号 至 2021年 8月6号 商业版代码更新内容

337、修复探探部分手机不能上传头像问题
336、修复Android 10 华为设备IO重定向问题
335、调整横竖屏逻辑,减少异常情况发生
334、添加Activity生命周期的回调接口
333、修复Android 12的广播问题
332、修复微信部分界面状态异常的BUG
331、修复Outlook、One drive、Teams、Zoom等海外app的支持
330、修复Android 11 一个权限请求BUG
329、修复部分cocos2d引擎只显示半屏的问题
328、修复微信在多用户下不能发送文件的问题
327、split apk 支持
326、Android S 支持

2021年 2月24号 至 2021年 4月24号 商业版代码更新内容

325、适配多用户环境
324、修复新版微信的兼容问题
323、兼容更多企业级加固
322、支持VAPP设置电源优化
321、修复缺失权限声明
320、修复Android 11上android.test.base库的引用
319、优化ext插件判断
318、优化安装时ABI的选择
317、修复Google文档在Android 11上崩溃的问题

2020年 10月15号 至 2021年 2月23号 商业版代码更新内容

316、解决新版爱加密、邦邦等加固的兼容性
315、修复WhatsApp不显示冷启动Splash的问题
314、优化对系统app的识别
313、完善多用户环境下的支持
312、解决ext插件部分情况下卡死的问题
311、支持Google Play在容器中下载APP
310、修复Android 11 QQ无法显示图片的问题
309、兼容Android 11运行Google Service
308、解决Android 11无法运行chromium
307、支持Hook @CriticalNative Method
306、修复JDK 13无法编译运行的问题
305、修复Service部分情况可能crash的问题
304、修复Android 11无法加载外部存储私有数据的问题
303、修复低版本app无法使用org.apache.http.legacy的问题
302、修复某些情况系统任务栈只显示最后一个的问题
301、完善不同平台的构建脚本
300、修复Android 11无法读取obb的问题
299、解决软件无法向后兼容的问题
298、重构VApp安装框架
297、重构virtual文件系统
296、修复某些情况下WebView无法启动的问题
295、修复VApp卸载重装的BUG
294、修复LOL手游的登录异常问题
293、支持安装Splits APK
292、支持动态配置主包环境
291、修复32位QQ调用64位微信卡顿的问题
290、修复Messenger调用Facebook崩溃的问题
289、优化对Google服务框架的支持
288、实现新的扩展包同步机制
287、修复Android 11正式版的异常问题
286、添加系统Package缓存,优化性能
285、修复disabled组件还能被PMS查询的BUG
284、修复微信部分界面Launch行为异常的问题
283、修复ContentProvider.getCallingPackage返回Host包名的BUG
282、修复uid虚拟化的BUG,解决部分app权限检查失败的问题
281、重写PendingIntent, IntentSender的实现
280、优化进程管理,修复长期存在的概率性进程死锁问题
279、重写Service实现,Service生命周期更准确,不容易被杀死

2020年 9月13号 至 2020年 10月15号 商业版代码更新内容

278、修复 64 位 App 无法调用 32 位 App 的问题
277、修复 Android R 加载 HttpClient 的问题
276、修复 Android R debug 模式下的崩溃问题

2020年 8月23号 至 2020年 9月12号 商业版代码更新内容

275、添加缺失的 service hook
274、修复百度翻译无法启动的问题
273、修复 GP 下载的 split app 无法启动的问题

2020年 7月10号 至 2020年 8月22号 商业版代码更新内容

272、修复 Service 创建
271、添加 NotificationService 缺失的 Hook
270、修复 Yotube 崩溃

2020年 5月19号 至 2020年 7月9号 商业版代码更新内容

269、初步适配 Android 11 beta1
268、修复小红书多开闪退的问题
267、修复某些 App 多开报“应用签名被篡改”的问题

2020年 4月24号 至 2020年 5月18号 商业版代码更新内容

266、修复 sh 调用错误
265、修复 9.0 以上最新版 Facebook 无法登陆的问题
264、帮助企业微信修复启动虚拟存储的情况下无法拍照的问题
263、修复某些情况下 64位 app 打不开 Activity 的问题

2020年 3月24号 至 2020年 4月23号 商业版代码更新内容

262、修复 Vivo 设备提示安装游戏 SDK 的问题
261、修复 Android Q 无法加载部分系统 so 的问题
260、修复华为设备微博未响应
259、忽略不必要的权限检查造成的崩溃
258、修复 WPS 分享文件崩溃的问题
257、部分 10.0 设备的闪退问题

2020年 3月7号 至 2020年 3月23号 商业版代码更新内容

256、修复微信同时打开两个页面问题
255、修复微信登陆成功但是返回登陆页面的问题
254、修复最新版 QQ 无法下载附件的问题
253、更新 SandHook 版本
252、修复 9.0 以上安装未签名Apk问题
251、修复 10.0 的定位问题

2020年 1月16号 至 2020年 3月6号 商业版代码更新内容

250、调整 lib 重定向逻辑
249、修复三星 10.0 系统上的崩溃问题
248、修复 release build 的 hook 异常
247、增加 SandHook 的 proguard 规则
246、修复对部分 App 中 VirtualApk 的兼容问题
245、修复 VA 内部请求安装 apk 失败的问题

2019年 12月26号 至 2020年 1月15号 商业版代码更新内容

244、修复 Android Q 遗漏的 hook
243、禁用 Emui10 的 AutoFill
242、增加新 api 结束所有 activity

2019年 12月15号 至 2019年 12月25号 商业版代码更新内容

241、修复 Emui10 上企业微信等 App 无法启动的问题
240、修复在 4.x 可能导致的崩溃
239、升级 SandHook 修复对 Thread 类的 Hook
238、修复 Android Q 某些接口导致的权限问题

2019年 11月20号 至 2019年 12月14号 商业版代码更新内容

237、修复 Notification 缓存导致的崩溃
236、修复高版本 Notification 的 classloader 问题

2019年 11月9号 至 2019年 11月19号 商业版代码更新内容

235、修复 Android 5.x 的 ART Hook
234、修复 ART Hook 可能导致的死锁问题

2019年 11月2号 至 2019年 11月8号 商业版代码更新内容

233、修复 WPS, 网易邮箱等在 Q 设备上崩溃的问题
232、修复汤姆猫跑酷在部分 Q 设备上崩溃的问题
231、修复 QQ 在部分 Q 设备上崩溃的问题

2019年 10月25号 至 2019年 11月1号 商业版代码更新内容

230、修复克隆 Google Play 下载的 64位 App
229、修复企业微信
228、修复 Telegram

2019年 10月8号 至 2019年 10月24号 商业版代码更新内容

227、修复 Android P 下 AppOspManager 的异常
226、添加 Android P 下 ActivityTaskManager 丢失的 Hook
225、修复 Android P 下 Activity Top Resume 异常
224、支持在系统多用户模式下运行!

2019年 10月8号 商业版代码更新内容

223、修复Android P 以上内部 app 返回桌面异常的问题
222、64位分支支持 Android Q

2019年 9月20号 至 2019年 10月7号 商业版代码更新内容

221、修复安装在扩展插件中的 apk 无法正确显示图标和名称的问题
220、修复 twitter 无法打开的问题
219、正式兼容 Android Q 正式版!
218、修复 Android Q 某些 Activity 无法再次打开的问题
217、初步适配 Android Q 正式版
216、修复数个64位分支的 Bug
215、新增加支持32位插件的64位分支,该分支支持32位旧设备并且64位设备在32位插件的情况下可以支持32位旧应用

2017年 12月 至 2019年 7月 30 日 商业版代码更新内容

214、改进 App 层提示信息
213、改进部分编码
212、修复从宿主向插件发送广播的方法
211、兼容最新版 gradle 插件
210、增加广播命名空间以避免多个使用 VA 技术的 App 互相干扰
209、修复 IMO 打不开的问题
208、修复部分 ContentProvider 找不到的问题
207、支持纯32位模式,以兼容老设备
206、初步支持纯64位模式,以应对8月份的谷歌市场的策略变化
205、适配到 Android Q beta4
204、修复了货拉拉无法安装的问题
203、优化了64位apk的判定逻辑
202、修复配置网络证书的 App 的联网
201、重构组件状态管理
200、优化 MIUI/EMUI ContentProvider 兼容性
199、修复 StorageStats Hook
198、修复快手无法登陆
197、修复 YY 无法启动,更好的兼容插件化框架
196、修复 Facebook 登陆
195、修复 Google Play 下载的 App 无法找到 so 的问题(皇室战争)
194、修复 split apk 支持
193、修复 Youtube 无法启动
192、修复优酷无法启动的问题
191、修复多开时app间可能存在广播namespace冲突的BUG
190、采用新的策略绕过Android P以后的Hidden Policy API
189、适配Android Q(beta1)
188、修复华为设备部分app无法识别存储的问题
187、修复启动进程可能失败导致app无法运行的问题
186、修复4.4设备部分native符号无法找到的问题
185、修复部分设备WebView包名获取失败的问题
184、修复Service细节处理的问题
183、优化启动速度
182、修复WebView在少数机型加载失败的情况
181、修复Lib决策的问题
180、修复部分华为机型无法读取内存卡的问题
179、修复Service可能存在的问题
178、允许根据intent判断Activity是否在外部启动
177、修复部分机型上Gms和Google Play启动到了不正确的环境
176、修复新实现的StaticBroadcast导致的兼容性问题
175、修复Android P上无法使用apache.http.legacy的问题
174、实现Native trace
173、优化IO Redirect性能
172、修复wechat部分时候出现网络无法连接的问题
171、修复小概率process attach不正确的BUG
170、开始下一阶段的ROADMAP
169、解决Android P无法注册超过1000个广播导致的问题
168、修复可能导致ANR的DeadLock
167、修复部分app动态加载so失败的问题
166、修复免安装运行环境下部分机型第一次打开出现黑屏的问题
165、兼容适配多款主流的Android模拟器
164、优化启动性能
163、解决多个内存泄露问题
162、修复IO Redirect优先级的问题
161、修复8.0以下设备Messenger无网络连接的问题
160、修复双开时外部app卸载时内部app仍然保留的BUG
159、修复部分腾讯加固无法运行的问题
158、修复Instagram无法登录Facebook的BUG
157、修复进程小概率可能重复启动的BUG
156、修复GET_PERMISSIONS没有获取权限的BUG
155、修复startActivityIntentSender的BUG
154、修复vivo设备部分Activity无法启动的问题
153、修复app无法调用外部app选择文件的问题
152、完善Android P的兼容
151、兼容Android P的Google服务
150、解决Messenger部分功能异常
149、完善IO Redirect
148、大量适配Gms, 修复Gms运行过程中进程无限重启的问题
147、重新实现Service的运行机制
146、完善64bit,提供了部分ROM配置64bit Engine权限的API
145、修复了4.4设备上的Activity启动问题
144、支持excludeFromRecent属性
143、修复Instagram无法Facebook登录的问题
142、修复Facebook第一次登录闪退的问题
141、支持以64位模式运行Gms、Google play、Play game
140、支持在双开/免安装运行的Google play中下载和安装app
139、修复DownloadManager的BUG
138、修复Google play返回上层时重启界面的BUG
137、修复免安装模式下so决策问题
136、优化构建脚本,便于引入项目
135、修复移动MM SDK无法启动的问题
134、修复微信摇一摇的BUG
133、修复中兴设备不稳定的BUG
132、支持ARM64下的IO Redirect
131、修复USE_OUTSIDE模式下外部app更新时,内部app没有更新的BUG
130、兼容最新Android 9.0(代号: pie) 及正式版之前发布的四个Preview版本
129、兼容内置houdini的x86设备
128、WindowPreview技术,使app启动与真实app达到一样的速度
127、新的ActivityStack以提高app运行质量
126、解决接入Atlas Framework的app运行异常的问题
125、现在可以定义虚拟app返回桌面的具体行为
124、现在双开模式下app随系统动态更新,不需要手动检查
123、支持targetSdkVersion >= 26时仍可正常运行低版本的app
122、兼容腾讯游戏管家的QDroid虚拟引擎 (beta)
121、大量重构底层代码,大幅提升运行速度
120、修复网易新闻分享到微博后无法取消的问题
119、修复App自定义权限无法识别的问题
118、修复墨迹天气app无法启动的问题
117、修复部分政府app无法启动的问题
116、API的变动详见代码
115、修复三星系列应用的相互调用问题
114、修复小米应用在非小米系统的账号问题
113、修复分享/发送等第三方调用,返回页面不正常
112、修复应用宝提示不能安装
111、调用第三方app,对uri进行加密
110、适配前刘海
109、适配小米rom的hook
108、适配努比亚录音问题
107、内部悬浮窗权限控制
106、优化自定义通知栏的处理
105、修复Context的INCLUDE_CODE权限问题
104、适配华为,oppo的角标
103、修复百度视频的进程重启问题
102、修复某些snapchat的无法启动问题
101、适配autofill服务,例如piexl系列
100、完善64位的io hook
99、优化hook库的兼容性,加回dlopen
98、64位扩展包的so移到32位主包。(jni代码改动后,在Run之前,请先build一次)
97、通知栏改动:适配8.1的通知渠道;移除应用时,移除应用的全部通知
96、兼容部分app,需要设置android:largeHeap=true
95、修复ffmpeg库的视频无法播放问题
94、优化横竖屏切换
93、降低通过Intent.ACTION_VIEW调用外部Activity限制。
92、兼容MG SDK
91、64位支持还在开发阶段
90、更新混淆配置app/proguard-rules.pro,必须加规则-dontshrink
89、优化模拟机型,例如:模拟后,某些app不出现设备验证
88、提高dex2oat兼容性
87、优化模拟定位
86、移除dlopen
85、targetVersion可以改为26:支持targetVersion<23的app动态权限申请,支持targetVersion<24的文件Uri
84、installPackage改为默认异步形式
83、为了支持64位模式,换回aidl
82、去掉SettingHandler现在可以动态设置特殊规则,规则会存储,不需要重复设置
81、增加2个native_setup
80、提高jobService兼容性
79、ShortcutService相关:关联VASettings.ENABLE_INNER_SHORTCUT
78、为了稳定性和运行效率,去掉上个版本的蓝牙,wifi,不声明权限的适配。
77、增加app启动异常的广播Constants.ACTION_PROCESS_ERROR
76、修复少数游戏横屏判断问题
75、demo增加机型模拟
74、适配vivo一个自定义权限(后台弹窗)VA是把一个历史acitivty返回前台,vivo需要这个权限。
73、如果没有蓝牙权限,返回默认值(海外用)
72、修复uid权限检查问题
71、安全性更新,内部应用的文件权限控制
70、提高内部app调用的兼容性,第三方登录,分享
69、自动过滤没权限的外部ContentProvider
68、增加功能:内部app的权限检查(默认关闭)
67、机型模拟:Build类和build.prop
66、提高对乐固加固的app兼容性
65、适配三星wifimanager
64、修复ipc框架一个参数传递问题(IPCMethod这个类必须更新)
63、补全7.0通知栏的hook
62、修正8.0动态快捷菜单的hook
61、SettingHandler新增一个适配接口,主要适配各种游戏
60、功能改动:google自动安装改为手动安装,避免第一次启动时间过久
59、可以禁止访问外部某个ContentProvider
58、适配华为桌面图标数量
57、权限分类注释,标注可删除权限。
56、增加双开模式的app跟随外部升级的开关。
55、提高app的jni兼容性。
54、提高对app集成其他插件框架的兼容性。
53、增加设置接口,根据包名进行设置。
52、增加Uri的适配范围,支持通过Uri分享和查看文件。
51、修复一个在三星8.0的问题。
50、提高对系统自带的app组件兼容性,更好兼容chrome webview,google service。
49、提高ART稳定性
48、增加相机适配范围
47、支持内部App在8.0下的快捷方式管理
46、修复exec异常
45、提高稳定性(修复微信登录闪退)
44、解决微信数据库崩溃问题
43、修复部分4.4设备崩溃问题
42、修复后台应用易被杀死,土豆视频黑屏,新浪微博无法打开,优酷两次返回无法退出。
41、增加应用的保活机制,双开APP更不易被杀死。
40、优化虚拟引擎启动性能。
39、兼容了大部分的加固,第三方APP兼容性对比上一版提升40%+。
38、修复某些rom下,快捷方式图标不正确
37、兼容以前组件StubFileProvider
36、适配部分新ROM的虚拟IMEI
35、改善进程初始化代码,增加稳定性
34、添加内部发送Intent.ACTION_BOOT_COMPLETED的广播,可以设置开关
33、适配关联google play游戏,支持游戏使用google登录
32、适配android O的google service框架
31、适配android O 快捷方式
30、适配耳机模式
29、某些rom对intent的大小限制,demo添加缩放快捷方式图标代码
28、修复多开情况下一个bug
27、修复某些情况下MediaController的bug
26、修复4.1.2的StubFileProvider报错
25、分享的uri处理
24、修复跨app调用Activity的回调
23、前台服务的通知栏拦截开关
22、附带doc
21、完善VA内部的intent的CHOOSE回调
20、Android O的通知栏适配2
19、ipc框架优化, 提高判断binder的存活准确性
18、jni的log开关 Android.mk:LOCAL_CFLAGS += -DLOG_ENABLE
17、混淆配置
16、Android O的通知栏适配
15、修复部分app网络卡的问题
14、适配 android 8.0的dl_open(jni加载)
13、修复华为emui8.0的一个bug
12、完善定位
11、设置手机信息,imei伪装算法
10、适配8.0某个功能(主要app:whatsapp)
9、修复内部微信等应用,无法更新图片,视频
8、demo增加安装监听,自动升级克隆模式的应用
7、7.0的file provider适配
6、增加了定位代码
5、代码进行了架构优化
4、与开源版不同的特征
3、解决了微信被封的一些问题
2、修复了部分机型兼容性
1、修复了12个小BUG


Overview (`VirtualApp/lib/src/main/jni/HookZz/README.md`)

What is HookZz ?

a hook framwork for arm/arm64/ios/android

ref to: frida-gum and minhook and substrate.

special thanks to frida-gum perfect code and modular architecture, frida is aircraft carrier, HookZz is boat, but still with some tricks

thanks for @lauos with contributing android code

Features

  • solidify inlinehook without Jailbreak [new-90%]

  • GOT hook with HookZz(i.e. change fishhook to inlinehook), better for APM [new-0%]

  • HookZz-Modules help you to hook.

  • the power to access registers directly

  • hook function with replace_call

  • hook function with pre_call and post_call

  • hook address(a piece of code) with pre_call and half_call

  • (almost)only one instruction to hook(i.e. hook short funciton, even only one instruction) [arm/thumb/arm64]

  • runtime code patch, without codesign limit

  • it's cute

Getting Started

Move to HookZz Getting Started [need update]

How it works ?

Move to HookFrameworkDesign.md [need update]

Why I do this?

  1. for arsenal - zzdeps
  2. for low-level control

Who use this?

VirtualApp An open source implementation of MultiAccount.(Support 4.0 - 8.0)

AppleTrace Trace tool for iOS/macOS (similar to systrace for Android)

Docs

Move to HookZz docs [need update]

Example

Move to HookZz example [need update]

Modules

Move to HookZzModules [need update]

Compile

build for arm64-ios

1. build `libhookzz.dylib` and `libhookzz.static.a`

text
/* Detailed source-code truncated for AI context efficiency. */

check build/ios-arm64/*.

2. build tests dylib

text
jmpews at jmpewsdeMBP in ~/Desktop/SpiderZz/project/HookZz/tests/arm64-ios
λ : >>> make clean; make
clean all *.o success!
build [test_hook_oc.dylib] success for arm64-ios!
build [test_hook_address.dylib] success for arm64-ios!
build [test_hook_printf.dylib] success for arm64-ios!
build [test] success for arm64-ios-hookzz!

check build/ios-arm64/*.

build for arm-ios

ignore...

build for arm-android

1. build `libhookzz.so` and `libhookzz.static.a`

text
/* Detailed source-code truncated for AI context efficiency. */

and check build/android-armv7

build tests ELF

text
jmpews at jmpewsdeMBP in ~/Desktop/SpiderZz/project/HookZz/tests/arm-android
λ : >>> make clean; make
clean all *.o success!
build [test_hook_open_arm.dylib] success for armv7-ios!
build [test_hook_address_thumb.dylib] success for armv7-ios!
build [test_hook_printf.dylib] success for armv7-ios!
build [test] success for armv7-android-hookzz!

and check build/android-armv7/*

Quick Example

`test_hook_printf.c` output for arm64-ios

test hook printf with try_near_jump option , and ZzEnableDebugMode() with replace_call, pre_call, post_call.

text
ZzThunkerBuildThunk:
LogInfo: enter_thunk at 0x100162c20, use enter_thunk_template.

ZzThunkerBuildThunk:
LogInfo: leave_thunk at 0x1001500f4, length: 240.

ZzBuildEnterTrampoline:
LogInfo: on_enter_trampoline at 0x1001502d8, length: 44. hook-entry: 0x145e0c720. and will jump to enter_thunk(0x100162c20).

ZzBuildEnterTransferTrampoline:
LogInfo: on_enter_transfer_trampoline at 0x180f1f414, length: 20. and will jump to on_enter_trampoline(0x1001502d8).

ZzBuildInvokeTrampoline:
LogInfo: on_invoke_trampoline at 0x100150304, length: 24. and will jump to rest code(0x181402a60).
ArmInstructionFix: origin instruction at 0x181402a5c, relocator end at 0x181402a60, relocator instruction nums 1
origin_prologue: 0xf4 0x4f 0xbe 0xa9 

ZzBuildLeaveTrampoline:
LogInfo: on_leave_trampoline at 0x10015031c, length: 44. and will jump to leave_thunk(0x1001500f4).

HookZzzzzzz, %d, %p, %d, %d, %d, %d, %d, %d, %d

printf-pre-call
call printf
HookZzzzzzz, 1, 0x2, 3, 4, 5, 6, 7, 8, 9
HookZzzzzzz, %d, %p, %d, %d, %d, %d, %d, %d, %d

printf-post-call

Overview (`VirtualApp/lib/src/main/jni/HookZz/src/zzdeps/README.md`)

zzdeps

common deps, C/C++ is ok and include darwin & common.

common deps

os independent.

darwin deps

about darwin.


VirtualApp Lib Src Main Jni HookZz Docs Hookzz Getting Started (`VirtualApp/lib/src/main/jni/HookZz/docs/hookzz-getting-started.md`)

HookZz Getting Started

Move to HookZz Getting Started

Move to HookZz Example

Move to HookZz docs

Move to HookZzModules

Move to HookZzWebsite

1. build hookzz dylib

clone the repo git clone https://github.com/jmpews/HookZz and build for darwin.ios. btw, you can set the log infomation in hookzz.h.

text
λ : >>> make -f darwin.ios.mk darwin.ios
generate [src/allocator.o]!
generate [src/interceptor.o]!
generate [src/memory.o]!
generate [src/stack.o]!
generate [src/thread.o]!
generate [src/trampoline.o]!
generate [src/platforms/posix/thread-posix.o]!
generate [src/platforms/darwin/memory-darwin.o]!
generate [src/platforms/arm64/reader.o]!
generate [src/platforms/arm64/relocator-arm64.o]!
generate [src/platforms/arm64/thunker-arm64.o]!
generate [src/platforms/arm64/writer-arm64.o]!
generate [src/zzdeps/darwin/macho-utils-darwin.o]!
generate [src/zzdeps/darwin/memory-utils-darwin.o]!
generate [src/zzdeps/common/memory-utils-common.o]!
generate [src/zzdeps/posix/memory-utils-posix.o]!
generate [src/zzdeps/posix/thread-utils-posix.o]!
build success for arm64(IOS)!

check the dylibs in build directory. libhookzz.dylib is shared library, and libhookzz.static.a is static library.

text
λ : >>> ls build
libhookzz.dylib    libhookzz.static.a

2. build the test demo dylib

a demo dylib to hook [UIViewController viewWillAppear]

before build demo dylib, specify the hookzz library path(shared or static).

  1. build with commandline.
text
`xcrun --sdk iphoneos --find clang` -isysroot `xcrun --sdk iphoneos --show-sdk-path` -g -gmodules -I/path/HookZz/include  -L/path/HookZz/build -lhookzz.static -framework Foundation -dynamiclib -arch arm64 test_hook_oc.m -o test_hook_oc.dylib
  1. build with make -f darwin.ios.mk test
text
λ : >>> make -f darwin.ios.mk test
build success for arm64(IOS)!
build [test_hook_oc.dylib] success for arm64(ios)!
build [test_hook_address.dylib] success for arm64(ios)!
build [test_hook_printf.dylib] success for arm64(ios)!
build [test] success for arm64(IOS)!
text
λ : >>> ls build
libhookzz.dylib         test_hook_address.dylib test_hook_printf.dylib
libhookzz.static.a      test_hook_oc.dylib

3. test your demo dylib

build new ios app project. and then Build Phases -> New Run Script Phase add a run script.

text
cd ${BUILT_PRODUCTS_DIR}
cd ${FULL_PRODUCT_NAME}

cp /path/HookZz/build/test_hook_oc.dylib ./
/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} --timestamp=none test_hook_oc.dylib
/Users/jmpews/Desktop/SpiderZz/Pwntools/Darwin/bin/optool install -c load -p "@executable_path/test_hook_oc.dylib" -t ${EXECUTABLE_NAME}

last thing, run the app ,you will get the such output(with open GLOBAL_DEBUG, GLOBAL_INFO)

text
target 0x188525804 near jump to 0x183c9141c
target 0x188525804 call begin-invocation
2017-08-20 16:41:26.155 T007[409:129805] hookzz OC-Method: -[ViewController viewWillAppear:]
0x188525804 call end-invocation
2017-08-20 16:41:26.157 T007[409:129805] function over, and get 'key_x' is: 0x1234
2017-08-20 16:41:26.157 T007[409:129805] function over, and get 'key_y' is: 0x1234

Doc VADev (`doc/VADev.md`)

本文档主要介绍2部分。
第一部分是VA的源码结构介绍,这部分是为了让开发者能快速了解掌握VA源码框架。
第二部分是VA的基础SDK使用说明。
其他更多的开发文档见:VA私有库Wiki
VA产品说明:文档

下面开始第一部分,VA源码结构介绍:

1. VA源码目录介绍

下图是VA源码根目录:

可以看到VA一共有4个源码目录,各个目录介绍如下:

目录名称 作用
app VA Demo主包源码所在目录
app-ext VA Demo插件包源码所在目录
lib VA库源码所在目录
lib-ext VA插件库源码所在目录

2. VA编译配置文件介绍

VA的编译配置文件是VAConfig.gradle:

配置解释:

配置名称 作用
PACKAGE_NAME 用于配置VA主包的包名
EXT_PACKAGE_NAME 用于配置VA插件包的包名
VA_MAIN_PACKAGE_32BIT 用于配置VA主包是32位还是64位,true为32位,false为64位
VA_ACCESS_PERMISSION_NAME 用于配置VA中4大组建的权限名称
VA_AUTHORITY_PREFIX 用于配置VA主包中ContentProvider的authorities
VA_EXT_AUTHORITY_PREFIX 用于配置VA插件包中ContentProvider的authorities
VA_VERSION 用于配置VA库版本,开发者一般不需要关心
VA_VERSION_CODE 用于配置VA库版本代码,开发者一般不需要关心

3. VA核心代码解释

  1. com.lody.virtual.client包下的代码运行在VAPP Client进程中,主要用于VA Framework中的APP Hook部分,完成对各个Service的HOOK处理

  2. com.lody.virtual.server包下的代码运行在VA Server进程中,代码主要用于VA Framework中的APP Server部分,实现处理APP安装以及其他不给Android系统处理的APP请求

  3. mirror包下的代码主要用于对系统隐藏类的引用,属于工具类,减少大量反射代码的编写

  4. cpp包下的代码进行在VAPP Client进程中,主要用于VA Native部分,实现IO重定向和jni函数HOOK。其中:

    • substrate中实现了针对arm32和arm64的hook
    • vfs.cpp中实现了VA的虚拟文件系统,用于控制APP文件访问限制
    • syscall_hook.cpp中实现了对IO的Hook
  5. DelegateApplicationExt.java运行在VA Host Plugin进程中,用于VA插件包,实现了对主包代码的加载执行

下面开始第二部分,VA SDK使用介绍:

1. VA工程接入

用Android Studio打开VirtualApp-Priv项目

可见多个模块:

  • app
  • app-ext
  • lib
  • lib-ext

其中lib和lib-ext属于VirtualApp核心库以及扩展库,app和app-ext则属于示例app。

创建自己的App

新建一个application类型的module,并添加lib模块为依赖

gradle
implementation project(':lib')

根据需求修改VAConfig.gradle:

gradle
ext {
    VA_MAIN_PACKAGE_32BIT = true  // 主包为32位
    VA_ACCESS_PERMISSION_NAME = "io.busniess.va.permission.SAFE_ACCESS"  // VirtualApp组件用到的权限名称
    VA_AUTHORITY_PREFIX = "io.busniess.va"  // VirtualApp中ContentProvider用到的authority,不能与其他app重复
    VA_EXT_AUTHORITY_PREFIX = "io.busniess.va.ext"  // VirtualApp扩展包中ContentProvider用到的authority,不能与其他app重复
    // ...
}

在AndroidManifest.xml添加所需的权限

xml
<uses-permission android:name="${VA_ACCESS_PERMISSION_NAME}" />

权限名称必须与VAConfig.gradle中所声明的保持一致,可以在build.gradle中添加Placeholder来防止出错。

gradle
android {
    // ...
    manifestPlaceholders = [
                VA_ACCESS_PERMISSION_NAME: rootProject.ext.VA_ACCESS_PERMISSION_NAME,
    ]
}

创建一个Application

复写attachBaseContext方法,添加引导VirtualApp的代码:

java
@Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        try {
            VirtualCore.get().startup(base, mConfig);
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

这里传入了一个VirtualApp的一个配置 mConfig

text
/* Detailed source-code truncated for AI context efficiency. */

复写onCreate,添加初始化VirtualApp的代码:

java
@Override
    public void onCreate() {
        super.onCreate();
        VirtualCore virtualCore = VirtualCore.get();
        virtualCore.initialize(new VirtualCore.VirtualInitializer() {
            @Override
            public void onMainProcess() {
                // 主进程回调
            }

            @Override
            public void onVirtualProcess() {
                // 虚拟App进程回调
            }

            @Override
            public void onServerProcess() {
                // 服务端进程回调
            }

            @Override
            public void onChildProcess() {
                // 其他子进程回调
            }
        });
    }

由于VirtualApp会启动多个进程,所以Application会进入N次,不同的进程会走到VirtualInitializer不同的回调,可以在这里根据进程类型添加额外的初始化代码。

2. 安装APP

API:

java
VirtualCore.java

 public VAppInstallerResult installPackage(Uri uri, VAppInstallerParams params);

参数Uri是什么?

Uri决定了需要安装的apk的来源,目前支持 package 和 file 协议。

Package Uri 示例:

java
Uri packageUri = Uri.parse("package:com.hello.world");

File Uri 示例:

java
File apkFile = new File("/sdcard/test.apk"); 
Uri packageUri = Uri.fromFile(apkFile);

两种Uri安装app有何区别?

package协议 安装app,只需要传入包名,不需要具体的APK路径,所以以这种协议安装的app,相当于双开。

app会随外部版本的升级而自动升级,随外部版本的卸载而自动卸载。PackageSetting 中的 dynamic 为 true。

file协议 则是内部安装,apk会被复制到容器内部,与外部版本完全独立. PackageSetting 中的 dynamic 为 false。

安装参数 VAppInstallerParams

安装标志 installFlags

FLAG 说明
FLAG_INSTALL_OVERRIDE_NO_CHECK 允许覆盖安装
FLAG_INSTALL_OVERRIDE_FORBIDDEN 禁止覆盖安装
FLAG_INSTALL_OVERRIDE_DONT_KILL_APP 覆盖安装不kill已经启动的APP

安装模式 mode

FLAG 说明
MODE_FULL_INSTALL 完整安装
MODE_INHERIT_EXISTING 已安装的的安装模式。预留

预留参数,暂时未使用。目前不管设置哪种都一样。

cpuAbiOverride

指定app的abi。特殊需求下,可以强制指定app在指定abi下运行。不指定的情况下默认根据系统规则来决定运行的abi。

可选参数:

  • armeabi
  • armeabi-v7a
  • arm64-v8a

双开app实例代码:

java
VAppInstallerParams params = new VAppInstallerParams(VAppInstallerParams.FLAG_INSTALL_OVERRIDE_NO_CHECK);
VAppInstallerResult result = VirtualCore.get().installPackage(Uri.parse("package:com.tencent.mobileqq"), params);
if (result.status == VAppInstallerResult.STATUS_SUCCESS) {
    Log.e("test", "install apk success.");
}

从sd卡安装apk实例代码:

java
VAppInstallerParams params = new VAppInstallerParams(VAppInstallerParams.FLAG_INSTALL_OVERRIDE_NO_CHECK);
VAppInstallerResult result = VirtualCore.get().installPackage(Uri.fromFile(new File("/sdcard/test.apk")), params);
if (result.status == VAppInstallerResult.STATUS_SUCCESS) {
    Log.e("test", "install apk success.");
}

安装Split apk

先安装base包,然后再安装所有split包即可。

java
File dir = new File("/sdcard/YouTube_XAPK_Unzip/");
VAppInstallerParams params = new VAppInstallerParams(VAppInstallerParams.FLAG_INSTALL_OVERRIDE_NO_CHECK);
VAppInstallerResult result = VirtualCore.get().installPackage(
        Uri.fromFile(new File(dir,"com.google.android.youtube.apk")), params);
for (File file : dir.listFiles()) {
    String name = file.getName();
    if (name.startsWith("config.") && name.endsWith(".apk")) {
        result = VirtualCore.get().installPackage(
            Uri.fromFile(file), params);
    }
}

3. 启动及管理Application

启动App

java
// class VActivityManager
public boolean launchApp(final int userId, String packageName)

实例代码:

java
VActivityManager.get().launchApp(0, "com.tencent.mobileqq");

杀死App

java
// class VActivityManager
public void killAppByPkg(String pkg, int userId)
public void killAllApps()

实例代码:

java
// 杀死userid为0的QQ程序进程
VActivityManager.get().killAppByPkg("com.tencent.mobileqq", 0);
java
// 杀死所有App进程
VActivityManager.get().killAllApps();

卸载App

java
// class VirtualCore
public boolean uninstallPackageAsUser(String pkgName, int userId)
public boolean uninstallPackage(String pkgName)

实例代码:

java
// 卸载userid为0的QQ程序
VirtualCore.get().uninstallPackageAsUser("com.tencent.mobileqq", 0);
// 卸载所有user下安装的QQ程序
VirtualCore.get().uninstallPackage("com.tencent.mobileqq");

查询已安装的App

java
// class VirtualCore
public List<InstalledAppInfo> getInstalledApps(int flags)

4. Java Hook使用

VirtualApp中实现了一套Xposed接口,用户只要会使用Xposed就可以做到原本需要系统内置Xposed才能做到的事情.
但是用户也需要明白,VA中Xposed的作用域是VA这个APP中的,不能越权控制系统或其他外部App.

VA中提供了一个App创建启动的回调接口com.lody.virtual.client.core.AppCallback,接口如下:

java
public interface AppCallback {
    void beforeStartApplication(String packageName, String processName, Context context);

    void beforeApplicationCreate(String packageName, String processName, Application application);

    void afterApplicationCreate(String packageName, String processName, Application application);
}

接口说明:

名称 说明
beforeStartApplication APP启动之前,创建之后
beforeApplicationCreate APP被创建之前,Application已经准备完毕,Application.OnCreate未执行
afterApplicationCreate APP被创建之后,Application.OnCreate已被执行

参数说明:

名称 说明
packageName VAPP的包名
processName VAPP的进程名
context VAPP的Application context
application VAPP的Application

注: APP的创建指的是Application被创建.

接口有了,接下来就是怎么使用了.查看VirualApp进程说明,可以知道,
我们只需要在VAPP进程回调里(onVirtualProcess) 设置App回调 AppCallback 就可以达到目的.

宿主Application代码,参考io/busniess/va/App.java

java
@Override
    public void onCreate() {
        super.onCreate();
        VirtualCore virtualCore = VirtualCore.get();
        virtualCore.initialize(new VirtualCore.VirtualInitializer() {
            @Override
            public void onVirtualProcess() {
                // 设置VAPP启动回调
                virtualCore.setAppCallback(new MyComponentDelegate());
            }
        });
    }

MyComponentDelegate类代码

java
public class MyComponentDelegate implements AppCallback {

    @Override
    public void beforeStartApplication(String packageName, String processName, Context context) {
    }

    @Override
    public void beforeApplicationCreate(String packageName, String processName, Application application) {

        XposedHelpers.findAndHookMethod("android.app.ContextImpl", ClassLoader.getSystemClassLoader(), "getOpPackageName", new XC_MethodHook() {
            @Override
            protected void beforeHookedMethod(MethodHookParam param) {
                VLog.printStackTrace("getOpPackageName");
                param.setResult(VirtualCore.get().getHostPkg());
            }
        });
    }

    @Override
    public void afterApplicationCreate(String packageName, String processName, Application application) {
    }
}

上面示例中,已经添加了一个Xposed的使用案例.Xposed的入口是一个IXposedHookLoadPackage的实例,他提供了一个void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam)的接口,有一个XC_LoadPackage.LoadPackageParam的参数.这里我们虽然不能完全一一对用,但是也完全够用了.loadPackageParam.classsload可以用context.getClassLoader()或者application.getClassLoader()都是可以的.后续XposedHelpers,XposedBridge原来怎么用,这里也一样使用.

5. Native Hook使用

对于ARM 32和ARM 64的Hook,只需要引入头文件CydiaSubstrate.h即可,Hook API:
MSHookFunction(Type_ *symbol, Type_ *replace, Type_ **result)

参数说明:

名称 说明
symbol 要Hook的地址
replace 你自定义的hook函数
result 被hook函数的备份

参考syscall_hook.cpp代码

cpp
auto is_accessible_str = "__dl__ZN19android_namespace_t13is_accessibleERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE";
void *is_accessible_addr = getSym(linker_path, is_accessible_str);
if (is_accessible_addr) {
    MSHookFunction(is_accessible_addr, (void *) new_is_accessible,(void **)     &orig_is_accessible);
}

在MSHookFunction内部会自动判断当前是ARM32还是ARM64:

cpp
_extern void MSHookFunction(void *symbol, void *replace, void **result) {
    if (*result != nullptr) {
        return;
    }
    // ALOGE("[MSHookFunction] symbol(%p) replace(%p) result(%p)", symbol, replace, *result);
#ifdef __aarch64__
    A64HookFunction(symbol, replace, result);
#else
    SubstrateHookFunction(NULL, symbol, replace, result);
#endif
}

其他更多的开发指导请见VA私有库Wiki


Doc VADev Eng (`doc/VADev_eng.md`)

This document mainly introduces 2 parts.
The first part is the introduction of VA source code structure, this part is to allow developers to quickly understand to master the VA source code framework.
The second part is a description of VA's basic SDK. For more development documents, see: VA Private Library Wiki.
For more development documents, see:VA Private Library Wiki
VA Product Description:Document

The following is the first part, the introduction of the VA source code structure:

1. Introduction of VA source code directory

The following figure is the root of the VA source code:

You can see that VA has a total of four source code directories, and each directory is described as follows:

Directory Name Function
app The directory where the VA Demo master package source code is located
app-ext The directory where the source code of VA Demo plug-in package is located
lib The directory where the VA library source code is located
lib-ext The directory where the source code of VA Plugin Library is located

2. Introduction of VA compilation configuration profile

VA compilation configuration profile isVAConfig.gradle:

Configuration explanation:

Configuration Name Function
PACKAGE_NAME Used to configure the package name of the VA main package
EXT_PACKAGE_NAME Used to configure the package name of the VA plug-in package
VA_MAIN_PACKAGE_32BIT Used to configure whether the VA main package is 32-bit or 64-bit, true is 32-bit, false is 64-bit
VA_ACCESS_PERMISSION_NAME Used to configure the permission names of the 4 major components in VA
VA_AUTHORITY_PREFIX Used to configure the authorities of ContentProvider in the VA main packag
VA_EXT_AUTHORITY_PREFIX Used to configure the authorities of the ContentProvider in the VA plug-in package
VA_VERSION Used to configure the VA library version, developers generally do not need to care
VA_VERSION_CODE Used to configure the VA library version code, developers generally do not need to care

3. VA core code explanation

  1. The code under thecom.lody.virtual.clientpackage runs in the VAPP Client process and is mainly used in the APP Hook part of the VA Framework to complete the HOOK processing for each service.

  2. The code under thecom.lody.virtual.serverpackage runs in the VA Server process. The code is mainly used in the APP Server part of the VA Framework to handle APP installation and other APP requests that are not handled by the Android system.

3.The code under the mirrorpackage is mainly used for references to the system's hidden classes, and belongs to the tool class, reducing a lot of reflection code's writing.

4.The code under the cpppackage is carried out in the VAPP Client process and is mainly used in the VA Native part. Implement IO redirection and jni function HOOK. Among them:
- substrateimplements hook for arm32 and arm64
- vfs.cppimplements VA's virtual file system for controlling APP file access restrictions
- syscall_hook.cppimplements Hook for IO

5.DelegateApplicationExt.javaruns in the VA Host Plugin process,used in the VA plug-in package, implementing the loading and execution to the main package code.

The following is the second part, the introduction of using VA SDK:

1. VA Project Integration

Open VirtualApp-Priv project with Android Studio

Multiple modules can be seen:

  • app
  • app-ext
  • lib
  • lib-ext

Among them, lib and lib-ext belong to the VirtualAppcore library and extensions,while app and app-ext belong to thesample app.

Create your own App

Create a module of type application, and add the lib module as a dependency

gradle
implementation project(':lib')

Modify VAConfig.gradle according to demand:

gradle
ext {
    VA_MAIN_PACKAGE_32BIT = true  // The main package is 32-bit
    VA_ACCESS_PERMISSION_NAME = "io.busniess.va.permission.SAFE_ACCESS"  // The name of the permission used by the VirtualApp component
    VA_AUTHORITY_PREFIX = "io.busniess.va"  // The authority used by ContentProvider in VirtualApp cannot be duplicated with other Apps.  
    VA_EXT_AUTHORITY_PREFIX = "io.busniess.va.ext"  // The authority used by the ContentProvider in the VirtualApp extension package cannot be duplicated with other Apps.  
    // ...
}

Add the required permissions in AndroidManifest.xml

xml
<uses-permission android:name="${VA_ACCESS_PERMISSION_NAME}" />

Permission's name must be consistent with those declared in VAConfig.gradle, and adding Placeholder in build.gradle to prevent errors.

gradle
android {
    // ...
    manifestPlaceholders = [
                VA_ACCESS_PERMISSION_NAME: rootProject.ext.VA_ACCESS_PERMISSION_NAME,
    ]
}

Create an Application

Override the attachBaseContext method and add the code to bootstrap the VirtualApp:

java
@Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        try {
            VirtualCore.get().startup(base, mConfig);
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

Here, a configuration of VirtualApp is passed in mConfig

text
/* Detailed source-code truncated for AI context efficiency. */

Override onCreate and add the code of initialize the VirtualApp:

java
@Override
    public void onCreate() {
        super.onCreate();
        VirtualCore virtualCore = VirtualCore.get();
        virtualCore.initialize(new VirtualCore.VirtualInitializer() {
            @Override
            public void onMainProcess() {
                // Main process callback
            }

            @Override
            public void onVirtualProcess() {
                // Virtual App process callback
            }

            @Override
            public void onServerProcess() {
                // Server-side process callback
            }

            @Override
            public void onChildProcess() {
                // Other sub-process callback
            }
        });
    }

Since VirtualApp will start multiple processes, Application will enter N times, and different processes will go to different callbacks of VirtualInitializer, where additional initialization code can be added depending on the process type.

2. Install the APP

API:

java
VirtualCore.java

 public VAppInstallerResult installPackage(Uri uri, VAppInstallerParams params);

What is the parameter Uri?

Uri determines the source of the apk that need to be installed,and currently supports both package and file protocols.

Package Uri Example:

java
Uri packageUri = Uri.parse("package:com.hello.world");

File Uri Example:

java
File apkFile = new File("/sdcard/test.apk"); 
Uri packageUri = Uri.fromFile(apkFile);

What is the difference between the two types of Uri installation apps?

package agreement To install the app, you only need to pass in the package name, not the specific APK path, so the app installed with this protocol is equivalent to double space.

The APP is automatically upgraded as external versions are upgraded and uninstalled as external versions are uninstalled. dynamic in PackageSetting is true。

file agreement It is an internal installation, apk is copied inside the container, completely independent from the external version. dynamic in PackageSetting is false。

Installation Parameters VAppInstallerParams

Installation Flags installFlags

FLAG Instruction
FLAG_INSTALL_OVERRIDE_NO_CHECK Allow overlay installation
FLAG_INSTALL_OVERRIDE_FORBIDDEN Prohibit overlay installation
FLAG_INSTALL_OVERRIDE_DONT_KILL_APP Overwrite installation, and not kill the already launched APP

Installation Mode mode

FLAG Instruction
MODE_FULL_INSTALL Complete installation
MODE_INHERIT_EXISTING The installed installation mode of the installed. Reserve.

Reserve parameters, not used for now. Currently the same no matter which one is set.

cpuAbiOverride

Specify the abi of the App. You can force the App to run under the specified abi in special need. If you don't specify, the default abi is determined by system rules.
Optional parameters:

  • armeabi
  • armeabi-v7a
  • arm64-v8a

Double space App example code:

java
VAppInstallerParams params = new VAppInstallerParams(VAppInstallerParams.FLAG_INSTALL_OVERRIDE_NO_CHECK);
VAppInstallerResult result = VirtualCore.get().installPackage(Uri.parse("package:com.tencent.mobileqq"), params);
if (result.status == VAppInstallerResult.STATUS_SUCCESS) {
    Log.e("test", "install apk success.");
}

Install apk from sd card example code:

java
VAppInstallerParams params = new VAppInstallerParams(VAppInstallerParams.FLAG_INSTALL_OVERRIDE_NO_CHECK);
VAppInstallerResult result = VirtualCore.get().installPackage(Uri.fromFile(new File("/sdcard/test.apk")), params);
if (result.status == VAppInstallerResult.STATUS_SUCCESS) {
    Log.e("test", "install apk success.");
}

Install Split apk

Just install the base package firstly, and then install all the split packages.

java
File dir = new File("/sdcard/YouTube_XAPK_Unzip/");
VAppInstallerParams params = new VAppInstallerParams(VAppInstallerParams.FLAG_INSTALL_OVERRIDE_NO_CHECK);
VAppInstallerResult result = VirtualCore.get().installPackage(
        Uri.fromFile(new File(dir,"com.google.android.youtube.apk")), params);
for (File file : dir.listFiles()) {
    String name = file.getName();
    if (name.startsWith("config.") && name.endsWith(".apk")) {
        result = VirtualCore.get().installPackage(
            Uri.fromFile(file), params);
    }
}

3. Launch and manage Application

Launch App

java
// class VActivityManager
public boolean launchApp(final int userId, String packageName)

Example code:

java
VActivityManager.get().launchApp(0, "com.tencent.mobileqq");

Kill App

java
// class VActivityManager
public void killAppByPkg(String pkg, int userId)
public void killAllApps()

Example code:

java
// Kill the QQ program process with userid 0
VActivityManager.get().killAppByPkg("com.tencent.mobileqq", 0);
java
// Kill all App processes
VActivityManager.get().killAllApps();

Uninstall App

java
// class VirtualCore
public boolean uninstallPackageAsUser(String pkgName, int userId)
public boolean uninstallPackage(String pkgName)

Example code:

java
// Uninstall the QQ program with userid 0
VirtualCore.get().uninstallPackageAsUser("com.tencent.mobileqq", 0);
// Uninstall the QQ programs installed under all user
VirtualCore.get().uninstallPackage("com.tencent.mobileqq");

Check the installed Apps

java
// class VirtualCore
public List<InstalledAppInfo> getInstalledApps(int flags)

4. Java Hook Usage

VirtualApp implements a set of Xposed interface. Users who can use Xposed can do things that originally need the system built-in Xposed to do.
However, users also need to understand that the scope of Xposed in VA is within the VA app. Cannot overstep the authority to control system or other external apps.

VA provides a callback interface of App creation and launch com.lody.virtual.client.core.AppCallback, the interfaces are as follows:

java
public interface AppCallback {
    void beforeStartApplication(String packageName, String processName, Context context);

    void beforeApplicationCreate(String packageName, String processName, Application application);

    void afterApplicationCreate(String packageName, String processName, Application application);
}

Interface Instruction:

Name Instruction
beforeStartApplication Before APP launch, after creation
beforeApplicationCreate Before the APP is created, application has already prepared, Application.OnCreate is not executed.
afterApplicationCreate After the APP is created, Application.OnCreate is executed.

Parameter Instruction:

Name Instruction
packageName Name of VAPP
processName Process name of VAPP
context Application context of VAPP
application Application of VAPP

Note: APP creation means thatApplicationis created.

The interface is there, and the next step is how to use it. View[VirualApp Process Instruction](VirualApp Process Instruction.md), we kan see
We just need to put in theVAPP processcallback(onVirtualProcess) set App callback AppCallback and then achieve the purpose.

Host Application code, please refer io/busniess/va/App.java

java
@Override
    public void onCreate() {
        super.onCreate();
        VirtualCore virtualCore = VirtualCore.get();
        virtualCore.initialize(new VirtualCore.VirtualInitializer() {
            @Override
            public void onVirtualProcess() {
                // Set VAPP launch callback
                virtualCore.setAppCallback(new MyComponentDelegate());
            }
        });
    }

MyComponentDelegateClass Code

java
public class MyComponentDelegate implements AppCallback {

    @Override
    public void beforeStartApplication(String packageName, String processName, Context context) {
    }

    @Override
    public void beforeApplicationCreate(String packageName, String processName, Application application) {

        XposedHelpers.findAndHookMethod("android.app.ContextImpl", ClassLoader.getSystemClassLoader(), "getOpPackageName", new XC_MethodHook() {
            @Override
            protected void beforeHookedMethod(MethodHookParam param) {
                VLog.printStackTrace("getOpPackageName");
                param.setResult(VirtualCore.get().getHostPkg());
            }
        });
    }

    @Override
    public void afterApplicationCreate(String packageName, String processName, Application application) {
    }
}

In the above example, a use case for Xposed has been added. The entry point of Xposed is an example of IXposedHookLoadPackage, it provides an interface of void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam). There is one parameter of XC_LoadPackage.LoadPackageParam. Here we can't use it exactly one by one, but it's enough. loadPackageParam.classsloadcan use context.getClassLoader() or application.getClassLoader() both are ok. Afterwards XposedHelpers, the same way how to useXposedBridge, is also used here.

5. Native Hook Usage

For ARM 32 and ARM 64 Hooks, only the header files CydiaSubstrate.h need to be introduced, i.e. the Hook API:
MSHookFunction(Type_ *symbol, Type_ *replace, Type_ **result)

Parameter Instruction:

Name Instruction
symbol Address to Hook
replace Your custom Hook function
result Backups of hooked function

Refer syscall_hook.cpp code

cpp
auto is_accessible_str = "__dl__ZN19android_namespace_t13is_accessibleERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE";
void *is_accessible_addr = getSym(linker_path, is_accessible_str);
if (is_accessible_addr) {
    MSHookFunction(is_accessible_addr, (void *) new_is_accessible,(void **)     &orig_is_accessible);
}

Within MSHookFunction, it automatically determines whether the current is ARM32 or ARM64:

cpp
_extern void MSHookFunction(void *symbol, void *replace, void **result) {
    if (*result != nullptr) {
        return;
    }
    // ALOGE("[MSHookFunction] symbol(%p) replace(%p) result(%p)", symbol, replace, *result);
#ifdef __aarch64__
    A64HookFunction(symbol, replace, result);
#else
    SubstrateHookFunction(NULL, symbol, replace, result);
#endif
}

Additional development guidance can be found on the VA Private Library Wiki


VirtualApp Lib Src Main Jni HookZz Docs HookFrameworkDesign (`VirtualApp/lib/src/main/jni/HookZz/docs/HookFrameworkDesign.md`)

HookZz

画了一半的流程, 其实另一半还有 invoke trampoline, leave trampoline, 大致相同.

text
enter            enter
function         trampoline       thunk
+------------+   +------------+   +------------+
| hook patch +--->            +--->            |
+------------+   |            |   | storeReg   |
|            |   |            |   |            |
|            |   +------------+   | prep args  |
|            |                    |            |
|            |                    | call func  <---+begin_invocation_func()
|            |                    |            |
+------------+                    | restoreReg |
                                  |            |
                                  +------------+

HookFramework 架构设计 2.0

一般来说可以分为以下几个模块

  1. 内存分配 模块
  2. 指令写 模块
  3. 指令读 模块
  4. 指令修复 模块
  5. 跳板 模块
  6. 调度器 模块
  7. 栈 模块

1. 内存分配 模块

这里主要关注三个点:

  1. 内存的分配
  2. 内存属性修改
  3. 内存布局获取

1.1 内存的分配

设计方面: 1. 提供一个 allocator 去管理/分配内存 2. 需要封装成架构无关的 API.

通常使用 posix 标准的 mmap, darwin 下的 mach kernel 分配内存使用 mmap 实际使用的是 mach_vm_allocate. move to detail

在入口点的 patch, 通常会使用绝对地址跳到 trampoline, 如果使用绝对地址跳, 将会占用 4 条指令, 如下的形式.

text
ldr x17, #0x8
b #0xc
.long 0x0
.long 0x0
br x17

但是如果可以使用 B #0x?, 实现相对地址跳(near jump), 将是最好的, 在 armv8 中的可以想在 +-128MB 范围内进行 near jump, 具体可以参考 ARM Architecture Reference Manual ARMv8, for ARMv8-A architecture profile Page: C6-550. 所以问题转换为找到一块 rx- 的内存写入 enter trampline.

大概有以下几种方法可以获取到 rx- 内存块.

  1. 尝试使用 mmap 的 fixed flag 分配相近内存

  2. 当时获取进程内的所有动态库列表, 之后搜索每一个动态库的 __TEXT, 查找是否存在 code cave.(尝试搜索内存空洞(code cave), 搜索 __text 这个 section 其实更准确来说是搜索 __TEXT 这个 segment. 由于内存页对齐的原因以及其他原因很容易出现 code cave. 所以只需要搜索这个区间内的 00 即可, 00 本身就是无效指令, 所以可以判断该位置无指令使用.)

  3. 获取当前进程的内存布局, 对所有 rx- 属性内存页搜索 code cave. (内存布局的获取会在1.3详细提到)

text
__asm__ {
	// 第一次绝对地址跳, 跳转到修复模块, 执行正常流程
	"ldr x17, #0x8\n"
	"b #0xc\n"
	".long\n"
	".long\n"
	"br x17"

	// double jump, 跳转到 on_enter_trampoline
	"ldr x17, #0x8\n"
	"b #0xc\n"
	".long\n"
	".long\n"
	"br x17"
}

1.2 内存属性修改

通常使用 posix 标准的 mprotect, darwin 下的 mach kernel 修改内存属性使用的是 mach_vm_protect, 注意: ios 不允许引用 #include <mach_vm.h>, 可以用单独拷贝一份该头文件到项目下.

这一部分与具体的操作系统有关. 比如 .

在 lldb 中可以通过 memory region address 查看地址的内存属性.

当然这里也存在一个巨大的坑, ios 下无法分配 rwx 属性的内存页. 这导致 inlinehook 无法在非越狱系统上使用, 并且只有 MobileSafari 才有 VM_FLAGS_MAP_JIT 权限. 具体解释请参下方 [坑 - rwx 与 codesigning].

1.3 内存布局获取

linux 下可以通过 /proc/pid/maps 获取当前进程的内存, 而且也仅有此方法.

darwin 下有 vmmap 这个命令可以在 macOS 使用, darwin 下 pid 与 task_t, 所以具体的内存页管理都在 task_t 这个内核结构体里. 但是可以通过 vm_region 函数遍历获取当前进程的所有属性的内存页. 通常用来爆破 dyld 的地址

2. 指令写 模块

先说坑, 非越狱状态下不允许设置 rw- 为 r-x, 或者 设置 r-x 为 rx-. 具体解释请参考下方坑 [坑-rwx 与 codesigning].

其实这里的指令写有种简单的方法, 就是在本地生成指令的16进制串, 之后直接写即可. 但这种应该是属于 hardcode.

这里使用 frida-gum 和 CydiaSubstrace 都用的方法, 把需要用到的指令都写成一个小函数.

例如:

text
// frida-gum/gum/arch-arm64/gumarm64writer.c
void
gum_arm64_zz_arm64_writer_put_ldr_reg_address (GumArm64Writer * self,
                                      ZzARM64Reg reg,
                                      GumAddress address)
{
  gum_arm64_writer_put_ldr_reg_u64 (self, reg, (zuint64) address);
}

void
gum_arm64_writer_put_ldr_reg_u64 (GumArm64Writer * self,
                                  ZzARM64Reg reg,
                                  zuint64 val)
{
  GumArm64RegInfo ri;

  gum_arm64_zz_arm64_writer_describe_reg (self, reg, &ri);

  g_assert_cmpuint (ri.width, ==, 64);

  gum_arm64_writer_add_literal_reference_here (self, val);
  gum_arm64_zz_arm64_writer_put_instruction (self,
      (ri.is_integer ? 0x58000000 : 0x5c000000) | ri.index);
}

其实有另外一个小思路, 有一点小不足, 就是确定指令片段的长度, 但其实也有解决方法, 可以放几条特殊指令作为结尾标记.

先使用内联汇编写一个函数.

text
__attribute__((__naked__)) static void ctx_save() {
  __asm__ volatile(

      /* reserve space for next_hop */
      "sub sp, sp, #(2*8)\n"

      /* save {q0-q7} */
      "sub sp, sp, #(8*16)\n"
      "stp q6, q7, [sp, #(6*16)]\n"
      "stp q4, q5, [sp, #(4*16)]\n"
      "stp q2, q3, [sp, #(2*16)]\n"
      "stp q0, q1, [sp, #(0*16)]\n"

      /* save {x1-x30} */
      "sub sp, sp, #(30*8)\n"
      "stp fp, lr, [sp, #(28*8)]\n"
      "stp x27, x28, [sp, #(26*8)]\n"
      "stp x25, x26, [sp, #(24*8)]\n"
      "stp x23, x24, [sp, #(22*8)]\n"
      "stp x21, x22, [sp, #(20*8)]\n"
      "stp x19, x20, [sp, #(18*8)]\n"
      "stp x17, x18, [sp, #(16*8)]\n"
      "stp x15, x16, [sp, #(14*8)]\n"
      "stp x13, x14, [sp, #(12*8)]\n"
      "stp x11, x12, [sp, #(10*8)]\n"
      "stp x9, x10, [sp, #(8*8)]\n"
      "stp x7, x8, [sp, #(6*8)]\n"
      "stp x5, x6, [sp, #(4*8)]\n"
      "stp x3, x4, [sp, #(2*8)]\n"
      "stp x1, x2, [sp, #(0*8)]\n"

      /* save sp, x0 */
      "sub sp, sp, #(2*8)\n"
      "add x1, sp, #(2*8 + 8*16 + 30*8 + 2*8)\n"
      "stp x1, x0, [sp, #(0*8)]\n"

      /* alignment padding + dummy PC */
      "sub sp, sp, #(2*8)\n");
}

之后直接复制这块函数内存数据即可, 这一般适合那种指令片段堆.

text
void ZzThunkerBuildEnterThunk(ZzWriter *writer)
{

    // pop x17
    zz_arm64_writer_put_ldr_reg_reg_offset(writer, ZZ_ARM64_REG_X17, ZZ_ARM64_REG_SP, 0);
    zz_arm64_writer_put_add_reg_reg_imm(writer, ZZ_ARM64_REG_SP, ZZ_ARM64_REG_SP, 16);

    zz_arm64_writer_put_bytes(writer, (void *)ctx_save, 26 * 4);

    // call `function_context_begin_invocation`
    zz_arm64_writer_put_bytes(writer, (void *)pass_enter_func_args, 4 * 4);
    zz_arm64_writer_put_ldr_reg_address(
        writer, ZZ_ARM64_REG_X17,
        (zaddr)(zpointer)function_context_begin_invocation);
    zz_arm64_writer_put_blr_reg(writer, ZZ_ARM64_REG_X17);

    zz_arm64_writer_put_bytes(writer, (void *)ctx_restore, 23 * 4);
}

3. 指令读 模块

这一部分实际上就是 disassembler, 这一部分可以直接使用 capstone, 这里需要把 capstone 编译成多种架构.

4. 指令修复 模块

这里的指令修复主要是发生在 hook 函数头几条指令, 由于备份指令到另一个地址, 这就需要对所有 PC(IP) 相关指令进行修复. 对于确定的哪些指令需要修复可以参考 Move to <解析ARM和x86_x64指令格式>.

大致的思路就是: 判断 capstone 读取到的指令 ID, 针对特定指令写一个小函数进行修复.

例如在 frida-gum 中:

text
frida-gum/gum/arch-arm64/gumarm64relocator.c
static gboolean
gum_arm64_relocator_rewrite_b (GumArm64Relocator * self,
                               GumCodeGenCtx * ctx)
{
  const cs_arm64_op * target = &ctx->detail->operands[0];

  (void) self;

  gum_arm64_zz_arm64_writer_put_ldr_reg_address (ctx->output, ZZ_ARM64_REG_X16,
      target->imm);
  gum_arm64_zz_arm64_writer_put_br_reg (ctx->output, ZZ_ARM64_REG_X16);

  return TRUE;
}

5. 跳板 模块

跳板模块的设计是希望各个模块的实现更浅的耦合, 跳板函数主要作用就是进行跳转, 并准备 跳转目标 需要的参数. 举个例子, 被 hook 的函数经过入口跳板(enter_trampoline), 跳转到调度函数(enter_chunk), 需要被 hook 的函数相关信息等, 这个就需要在构造跳板时完成.

6. 调度 模块

可以理解为所有被 hook 的函数都必须经过的函数, 类似于 objc_msgSend, 在这里通过栈返回值来控制函数(replace_call, pre_call, half_call, post_call)调用顺序.

本质有些类似于 objc_msgSend 所有的被 hook 的函数都在经过 enter_trampoline 跳板后, 跳转到 enter_thunk, 在此进行下一步的跳转判断决定, 并不是直接跳转到 replace_call.

7. 栈模块

如果希望在 pre_call 和 post_call 使用同一个局部变量, 就想在同一个函数内一样. 在 frida-js 中也就是 this 这个关键字. 这就需要自建函数栈, 模拟栈的行为. 同时还要避免线程冲突, 所以需要使用 thread local variable, 为每一个线程中的每一个 hook-entry 添加线程栈, 同时为每一次调用添加函数栈. 所以这里存在两种栈. 1. 线程栈(保存了该 hook-entry 的所有当前函数调用栈) 2. 函数调用栈(本次函数调用时的栈)

坑

`ldr` 指令

在进行指令修复时, 需要需要将 PC 相关的地址转换为绝对地址, 其中涉及到保存地址到寄存器. 一般来说是使用指令 ldr. 也就是说如何完成该函数 zz_arm64_writer_put_ldr_reg_address(relocate_writer, ZZ_ARM64_REG_X17, target_addr);

frida-gum 的实现原理是, 有一个相对地址表, 在整体一段写完后进行修复.

text
void
gum_arm64_writer_put_ldr_reg_u64 (GumArm64Writer * self,
                                  ZzARM64Reg reg,
                                  zuint64 val)
{
  GumArm64RegInfo ri;

  gum_arm64_zz_arm64_writer_describe_reg (self, reg, &ri);

  g_assert_cmpuint (ri.width, ==, 64);

  gum_arm64_writer_add_literal_reference_here (self, val);
  gum_arm64_zz_arm64_writer_put_instruction (self,
      (ri.is_integer ? 0x58000000 : 0x5c000000) | ri.index);
}

在 HookZz 中的实现, 直接将地址写在指令后, 之后使用 b 到正常的下一条指令, 从而实现将地址保存到寄存器.

text
void zz_arm64_writer_put_ldr_reg_address(ZzWriter *self, ZzARM64Reg reg, zaddr address)
{
    zz_arm64_writer_put_ldr_reg_imm(self, reg, (zuint)0x8);
    zz_arm64_writer_put_b_imm(self, (zaddr)0xc);
    zz_arm64_writer_put_bytes(self, (zpointer)&address, sizeof(address));
}

也就是下面的样子.

text
__asm__ {
	"ldr x17, #0x8\n"
	"b #0xc\n"
	".long\n"
	".long\n"
	"br x17"
}

寄存器污染

在进行 inlinehook 需要进行各种跳转, 通常会以以下模板进行跳转.

text
0:  ldr x16, 8;
4:  br x16;
8:  0x12345678
12: 0x00000000

问题在于这会造成 x16 寄存器被污染(arm64 中 svc #0x80 使用 x16 传递系统调用号) 所以这里有两种思路解决这个问题.

思路一:

在使用寄存器之前进行 push, 跳转后 pop, 这里存在一个问题就是在原地址的几条指令进行 patch code 时一定会污染一个寄存器(也不能说一定, 如果这时进行压栈, 在之后的 invoke_trampline 会导致函数栈发生改变, 此时有个解决方法可以 pop 出来, 由 hook-entry 或者其他变量暂时保存, 但这时需要处理锁的问题. )

思路二:

挑选合适的寄存器, 不考虑污染问题. 这时可以参考, 下面的资料, 选择 x16 or x17, 或者自己做一个实验 otool -tv ~/Downloads/DiSpecialDriver64 > ~/Downloads/DiSpecialDriver64.txt 通过 dump 一个 arm64 程序的指令, 来判断哪个寄存器用的最少, 但是不要使用 x18 寄存器, 你对该寄存器的修改是无效的.

Tips: 之前还想过为对每一个寄存器都做适配, 用户可以选择当前的 hook-entry 选择哪一个寄存器作为临时寄存器.

参考资料:

text
PAGE: 9-3
Programmer’s Guide for ARMv8-A
9.1 Register use in the AArch64 Procedure Call Standard 
9.1.1 Parameters in general-purpose registers

这里也有一个问题, 这也是 frida-gum 中遇到一个问题, 就是对于 svc #0x80 类系统调用, 系统调用号(syscall number)的传递是利用 x16 寄存器进行传递的, 所以本框架使用 x17 寄存器, 并且在传递参数时使用 push & pop, 在跳转后恢复 x17, 避免了一个寄存器的使用.

`rwx` 与 `codesigning`

对于非越狱, 不能分配可执行内存, 不能进行 code patch.

两篇原理讲解 codesign 的原理

text
https://papers.put.as/papers/ios/2011/syscan11_breaking_ios_code_signing.pdf
http://www.newosxbook.com/articles/CodeSigning.pdf

以及源码分析如下:

crash 异常如下, 其中 0x0000000100714000 是 mmap 分配的页.

text
Exception Type:  EXC_BAD_ACCESS (SIGKILL - CODESIGNING)
Exception Subtype: unknown at 0x0000000100714000
Termination Reason: Namespace CODESIGNING, Code 0x2
Triggered by Thread:  0

寻找对应的错误码

text
xnu-3789.41.3/bsd/sys/reason.h
/*
 * codesigning exit reasons
 */
#define CODESIGNING_EXIT_REASON_TASKGATED_INVALID_SIG 1
#define CODESIGNING_EXIT_REASON_INVALID_PAGE          2
#define CODESIGNING_EXIT_REASON_TASK_ACCESS_PORT      3

找到对应处理函数, 请仔细阅读注释里内容, 不做解释了.

text
/* Detailed source-code truncated for AI context efficiency. */

其他文章:

http://ddeville.me/2014/04/dynamic-linking

Later on, whenever a page fault occurs the vm_fault function in vm_fault.c is called. During the page fault the signature is validated if necessary. The signature will need to be validated if the page is mapped in user space, if the page belongs to a code-signed object, if the page will be writable or simply if it has not previously been validated. Validation happens in the vm_page_validate_cs function inside vm_fault.c (the validation process and how it is enforced continually and not only at load time is interesting, see Charlie Miller’s book for more details).

If for some reason the page cannot be validated, the kernel checks whether the CS_KILL flag has been set and kills the process if necessary. There is a major distinction between iOS and OS X regarding this flag. All iOS processes have this flag set whereas on OS X, although code signing is checked it is not set and thus not enforced.

In our case we can safely assume that the (missing) code signature couldn’t be verified leading to the kernel killing the process.



VirtualApp Lib Src Main Jni HookZz Docs Hookzz Docs (`VirtualApp/lib/src/main/jni/HookZz/docs/hookzz-docs.md`)

HookZz docs

Move to HookZz Getting Started

Move to HookZz Example

Move to HookZz docs

Move to HookZzModules

Move to HookZzWebsite

Export 4 core function

1. `ZzBuildHook`

build hook with replace_call, pre_call, post_call, but not enable. the definition of PRECALL and POSTCALL type is below.

text
@target_ptr: hook function address
@replace_ptr: replace function address
@origin_ptr: origin function address work with @replace_tpr
@pre_call_ptr: pre function call address
@post_call_ptr: post funciton call address

ZZSTATUS ZzBuildHook(zpointer target_ptr, zpointer replace_ptr, zpointer *origin_ptr, PRECALL pre_call_ptr, POSTCALL post_call_ptr);

2. `ZzBuildHookAddress`

build hook address(a piece of code) with pre_call, half_call. the definition of PRECALL and POSTCALL type is below.

text
@target_start_ptr: hook instruction start address
@target_end_ptr: hook instruction end address
@pre_call_ptr: pre function call address
@half_call_ptr: half function call address

ZZSTATUS ZzBuildHookAddress(zpointer target_start_ptr, zpointer target_end_ptr, PRECALL pre_call_ptr, HALFCALL half_call_ptr);

3. `ZzEnableHook`

enable hook with code patch at target_ptr.

text
@target_ptr: target address

ZZSTATUS ZzEnableHook(zpointer target_ptr);

4. `ZzRuntimeCodePatch`

runtime code patch without codesign limit, and will work better with MachoParser.

text
@address: patch address
@codedata: code patch data
@codedata: code ptach data size

ZZSTATUS ZzRuntimeCodePatch(zaddr address, zpointer codedata, zuint codedata_size);

Move to AntiDebugBypass Example

Export 3 core type:

1. `PRECALL`, `POSTCALL`, `HALFCALL`

For RegState:

without the explicit argument, use RegState to replace, you can access all the registers.

For ThreadStack:

Contains all of the current CallStack.

For CallStack:

if you want use variable in pre_call and post_call(half_call), just like the trick variable self, you need CallStack *stack.

text
typedef struct _CallStack
{
    long call_id;
} CallStack;

typedef struct _ThreadStack
{
    long thread_id;
    zsize size;
} ThreadStack;


typedef void (*PRECALL)(RegState *rs, ThreadStack *threadstack, CallStack *callstack);
typedef void (*POSTCALL)(RegState *rs, ThreadStack *threadstack, CallStack *callstack);
typedef void (*HALFCALL)(RegState *rs, ThreadStack *threadstack, CallStack *callstack);

2. `RegState`

current all cpu register state.

text
typedef union FPReg_ {
    __int128_t q;
    struct {
        double d1; // Holds the double (LSB).
        double d2;
    } d;
    struct {
        float f1; // Holds the float (LSB).
        float f2;
        float f3;
        float f4;
    } f;
} FPReg;

typedef struct _RegState {
    uint64_t pc;
    uint64_t sp;

    union {
        uint64_t x[29];
        struct {
            uint64_t x0,x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15,x16,x17,x18,x19,x20,x21,x22,x23,x24,x25,x26,x27,x28;
        } regs;
    } general;

    uint64_t fp;
    uint64_t lr;

    union {
        FPReg q[8];
        FPReg q0,q1,q2,q3,q4,q5,q6,q7;
    } floating;
} RegState;

3. `CallStack`

export 2 method user to get/set callstack

text
// get value with the key
zpointer ZzGetCallStackData(CallStack *callstack_ptr, char *key);

// set value with key.
zbool ZzSetCallStackData(CallStack *callstack_ptr, char *key, zpointer value_ptr, zsize value_size);

but for convenience, the macro is better.

text
#define STACK_CHECK_KEY(callstack, key) (bool)ZzGetCallStackData(callstack, key)
#define STACK_GET(callstack, key, type) *(type *)ZzGetCallStackData(callstack, key)
#define STACK_SET(callstack, key, value, type) ZzSetCallStackData(callstack, key, &(value), sizeof(type))

VirtualApp Lib Src Main Jni HookZz Docs Hookzz Example (`VirtualApp/lib/src/main/jni/HookZz/docs/hookzz-example.md`)

HookZz example

Move to HookZz Getting Started

Move to HookZz Example

Move to HookZz docs

Move to HookZzModules

Move to HookZzWebsite

Simple Example

1. `ZzBuildHookAddress` & `ZzRuntimeCodePatch`

hook at address, and specify the hook length. (i.e. hook a piece of code.)

c
#include "hookzz.h"
#include <stdio.h>
#include <unistd.h>

static void hack_this_function()
{
#ifdef __arm64__
    __asm__("mov X0, #0\n"
            "mov w16, #20\n"
            "svc #0x80");
#endif
}

static void sorry_to_exit()
{
#ifdef __arm64__
    __asm__("mov X0, #0\n"
            "mov w16, #1\n"
            "svc #0x80");
#endif
}

void getpid_pre_call(RegState *rs, ThreadStack *threadstack, CallStack *callstack) {
    unsigned long request = *(unsigned long *)(&rs->general.regs.x16);
    printf("request(x16) is: %ld\n", request);
    printf("x0 is: %ld\n", (long)rs->general.regs.x0);
}

void getpid_half_call(RegState *rs, ThreadStack *threadstack, CallStack *callstack) {
    pid_t x0 = (pid_t)(rs->general.regs.x0);
    printf("getpid() return at x0 is: %d\n", x0);
}

__attribute__((constructor)) void test_hook_address()
{
    void *hack_this_function_ptr = (void *)hack_this_function;
    ZzBuildHookAddress(hack_this_function_ptr + 8, hack_this_function_ptr + 12, getpid_pre_call, getpid_half_call);
    ZzEnableHook((void *)hack_this_function_ptr + 8);


    void *sorry_to_exit_ptr = (void *)sorry_to_exit;
    unsigned long nop_bytes = 0xD503201F;
    ZzRuntimeCodePatch((unsigned long)sorry_to_exit_ptr + 8, (zpointer)&nop_bytes, 4);

    hack_this_function();
    sorry_to_exit();

    printf("hack success -.0\n");
}

breakpoint with lldb.

text
(lldb) disass -n hack_this_function
test_hook_address.dylib`hack_this_function:
    0x1000b0280 <+0>:  mov    x0, #0x0
    0x1000b0284 <+4>:  mov    w16, #0x14
    0x1000b0288 <+8>:  svc    #0x80
    0x1000b028c <+12>: ret    

(lldb) disass -n sorry_to_exit
test_hook_address.dylib`sorry_to_exit:
    0x1000b0290 <+0>:  mov    x0, #0x0
    0x1000b0294 <+4>:  mov    w16, #0x1
    0x1000b0298 <+8>:  svc    #0x80
    0x1000b029c <+12>: ret    

(lldb) c
Process 41414 resuming
request(x16) is: 20
x0 is: 0
getpid() return at x0 is: 41414
hack success -.0
(lldb) disass -n hack_this_function
test_hook_address.dylib`hack_this_function:
    0x1000b0280 <+0>:  mov    x0, #0x0
    0x1000b0284 <+4>:  mov    w16, #0x14
    0x1000b0288 <+8>:  b      0x1001202cc
    0x1000b028c <+12>: ret    

(lldb) disass -n sorry_to_exit
test_hook_address.dylib`sorry_to_exit:
    0x1000b0290 <+0>:  mov    x0, #0x0
    0x1000b0294 <+4>:  mov    w16, #0x1
    0x1000b0298 <+8>:  nop    
    0x1000b029c <+12>: ret

2. use `ZzBuildHook` to hook `OC-Method`

c
#include "hookzz.h"
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import <mach-o/dyld.h>
#import <dlfcn.h>

@interface HookZz : NSObject

@end

@implementation HookZz

+ (void)load {
  [self zzMethodSwizzlingHook];
}

void objcMethod_pre_call(RegState *rs, ThreadStack *threadstack, CallStack *callstack) {
  zpointer t = 0x1234; 
  STACK_SET(callstack ,"key_x", t, void *);
  STACK_SET(callstack ,"key_y", t, zpointer);
  NSLog(@"hookzz OC-Method: -[UIViewController %s]",
        (zpointer)(rs->general.regs.x1));
}

void objcMethod_post_call(RegState *rs, ThreadStack *threadstack, CallStack *callstack) {
  zpointer x = STACK_GET(callstack, "key_x", void *);
  zpointer y = STACK_GET(callstack, "key_y", zpointer);
  NSLog(@"function over, and get 'key_x' is: %p", x);
  NSLog(@"function over, and get 'key_y' is: %p", y);
}

+ (void)zzMethodSwizzlingHook {
  Class hookClass = objc_getClass("UIViewController");
  SEL oriSEL = @selector(viewWillAppear:);
  Method oriMethod = class_getInstanceMethod(hookClass, oriSEL);
  IMP oriImp = method_getImplementation(oriMethod);

  ZzBuildHook((void *)oriImp, NULL, NULL, objcMethod_pre_call, objcMethod_post_call);
  ZzEnableHook((void *)oriImp);

}

@end

breakpoint with lldb.

text
(lldb) disass -n "-[UIViewController viewWillAppear:]" -c 3
UIKit`-[UIViewController viewWillAppear:]:
    0x18881c10c <+0>: adrp   x8, 126868
    0x18881c110 <+4>: ldrsw  x8, [x8, #0x280]
    0x18881c114 <+8>: ldr    x9, [x0, x8]

(lldb) c
Process 41637 resuming
(lldb) c
Process 41637 resuming
(lldb) c
Process 41637 resuming
2017-08-30 02:01:58.954875+0800 T007[41637:10198806] hookzz OC-Method: -[UIViewController viewWillAppear:]
2017-08-30 02:01:58.956558+0800 T007[41637:10198806] function over, and get 'key_x' is: 0x1234
2017-08-30 02:01:58.956654+0800 T007[41637:10198806] function over, and get 'key_y' is: 0x1234
(lldb) disass -n "-[UIViewController viewWillAppear:]" -c 3
UIKit`-[UIViewController viewWillAppear:]:
    0x18881c10c <+0>: b      0x1810b0b4c
    0x18881c110 <+4>: ldrsw  x8, [x8, #0x280]
    0x18881c114 <+8>: ldr    x9, [x0, x8]

3. hook variadic function

text
/* Detailed source-code truncated for AI context efficiency. */

breakpoint with lldb.

text
(lldb) disass -s 0x1815f61d8 -c 3
libsystem_c.dylib`printf:
    0x1815f61d8 <+0>: sub    sp, sp, #0x30             ; =0x30 
    0x1815f61dc <+4>: stp    x20, x19, [sp, #0x10]
    0x1815f61e0 <+8>: stp    x29, x30, [sp, #0x20]
(lldb) c
Process 41408 resuming
HookZzzzzzz, %d, %p, %d, %d, %d, %d, %d, %d, %d

printf-pre-call
call printf
HookZzzzzzz, 1, 0x2, 3, 4, 5, 6, 7, 8, 9
HookZzzzzzz, %d, %p, %d, %d, %d, %d, %d, %d, %d

printf-post-call
(lldb) disass -s 0x1815f61d8 -c 3
libsystem_c.dylib`printf:
    0x1815f61d8 <+0>: b      0x1795f61d8
    0x1815f61dc <+4>: stp    x20, x19, [sp, #0x10]
    0x1815f61e0 <+8>: stp    x29, x30, [sp, #0x20]

Advanced Example

1. AntiDebugBypass

Move to AntiDebugBypass Detail

5. hook `objc_msgSend`

Move to hook_objc_msgSend Detail

6. hook `MGCopyAnswer`

Move to hook_MGCopyAnswer Detail


--- METRICS ---