diff --git a/CHINESE.md b/CHINESE.md deleted file mode 100644 index 3b8e41ede..000000000 --- a/CHINESE.md +++ /dev/null @@ -1,95 +0,0 @@ -[![VA banner](https://raw.githubusercontent.com/asLody/VirtualApp/master/Logo.png)](https://github.com/asLody/VirtualApp) - -简介 ---- -**VirtualApp**是一个**App虚拟化引擎**(简称`VA`)。 - -**VirtualApp已兼容Android 0(8.0 Preview)。** - -VirtualApp在你的App内创建一个`虚拟空间`,你可以在虚拟空间内任意的`安装`、`启动`和`卸载`APK,这一切都与外部隔离,如同一个`沙盒`。 - -运行在`VA`中的APK无需在外部安装,即VA支持**免安装运行APK**。 - -VA目前被广泛应用于双开/多开、应用市场、模拟定位、一键改机、隐私保护、游戏修改、自动化测试、无感知热更新等技术领域,但它决不仅限于此,Android本身就是一个极其开放的平台,免安装运行APK这一Feature打开了无限可能--------这都取决于您的想象力。 - -申明 ---- -当您需要将VirtualApp用于**商业用途**时,请务必联系QQ:10890 购买商业授权。您如果未经授权将VirtualApp的App模块作为您自己的App用于牟利或上传软件市场,我们取证后将直接报警(侵犯著作权罪)。购买商业授权是对我们最大的支持和认可,我们将投入更多精力和时间来不断完善优化VirtualApp,作为购买商业授权的回报,您可以获得未开放的商业版本和1vs1的支持(技术、运营、预警)!同时我们也支持基于VirtualApp的APP订制开发,请联系:QQ:10890 洽谈。 - -请注意 ------ -VirtualApp代码的更新频率非常快(`以小时为单位`),每一次代码的更新都有可能修复重大BUG,所以请 `watch` 本项目,并注意随时更新代码,以免给您带来损失! - - -已支持的加固(不断更新) ----------- -* 360加固 -* 腾讯加固 -* 梆梆加固 -* 梆梆企业版(12306客户端 Pass) -* 爱加密 -* 百度加固 -* 娜迦加固 -* 乐变加固 -* 网易易盾 -* 通付盾 -* (已支持的加固均可通过VA来脱壳,本技术不公开) - - -在VA使用Google服务 ------------ -VA支持运行官方的Google服务套件,同时我们也提供了对`MicroG`的支持。 - -您可以通过在VA中安装`MicroG`来支持`Google服务`, - -这样,即使外部没有Google服务,用户也可以在VA中享受Google服务。 - -MicroG套件可在此下载:[Download MicroG](https://microg.org/download.html) - -MicroG的必要模块: -* Services Core -* Services Framework Proxy -* Store - -如果您需要在VA中使用官方的Google服务套件(外部已安装的前提下), - -则可以通过 `GmsSupport.installGms(userId)` 来安装。 - -##### 注意,您不能同时安装MicroGms和官方的Gms。 - - -使用说明 ----------- - -**前往你的Application并添加如下代码:** -```java - @Override - protected void attachBaseContext(Context base) { - super.attachBaseContext(base); - try { - VirtualCore.getCore().startup(base); - } catch (Throwable e) { - e.printStackTrace(); - } - } -``` -**安装App:** -```java - VirtualCore.getCore().installApp({APK PATH}, flags); -``` -**启动App:** -```java - VirtualCore.getCore().launchApp({PackageName}); -``` -**移除App:** -```java - VirtualCore.getCore().uninstallApp({PackageName}); -``` -**该App的基本信息:** -```java - VirtualCore.getCore().findApp({PackageName}); -``` - -技术支持 ------------- -QQ群:598536 diff --git a/README.md b/README.md index e96791aac..a2f30d7ec 100644 --- a/README.md +++ b/README.md @@ -1,76 +1,1237 @@ -[![VA banner](https://raw.githubusercontent.com/asLody/VirtualApp/master/Logo.png)](https://github.com/asLody/VirtualApp) - -[中国人猛戳这里](CHINESE.md "中文") - -About ------ -**VirtualApp** is an open platform for Android that allows you to create a `Virtual Space`, -you can install and run apk inside. Beyond that, VirtualApp is also a `Plugin Framework`, -the plugins running on VirtualApp does not require any constraints. -VirtualApp does **not** require root, it is running on the `local process`. - -NOTICE -------- -**This project has been authorized by the business.** - -**You are not allowed to modify the app module and put to the software market, if you do that, The consequences you know :)** - -**VirtualApp is not free, If you need to use the lib code, please send email to me :)** - -Background ----------- - -VirtualApp was born in early 2015, Originally, it is just a simple plugin framework, -But as time goes on, -the compatibility of it is getting better and better. -in the end, it evolved into a `Virtual Container`. - - -Get started ------------ -If you use latest android studio (version 2.0 or above), please disable `Instant Run`. -Open `Setting | Build,Exception,Deployment`, and disable `Enable Instant Run to hot swap...` - -**Goto your Application and insert the following code:** -```java - @Override - protected void attachBaseContext(Context base) { - super.attachBaseContext(base); - try { - VirtualCore.get().startup(base); - } catch (Throwable e) { - e.printStackTrace(); - } - } -``` - -**Install a virtual App:** -```java - VirtualCore.get().installPackage({APK PATH}, flags); - -``` - -**Launch a virtual App:** -```java - //VirtualApp support multi-user-mode which can run multiple instances of a same app. - //if you don't need this feature, just set `{userId}` to 0. - Intent intent = VirtualCore.get().getLaunchIntent({PackageName}, {userId}); - VActivityManager.get().startActivity(intent, {userId}); -``` - -**Uninstall a virtual App:** -```java - VirtualCore.get().uninstallPackage({PackageName}); -``` - -More details, please read the source code of demo app, :-) - -Documentation -------------- - -VirtualApp currently has **no documentation**, If you are interested in VirtualApp, please send email to me. - -About Author ------------- - - Lody (imlody@foxmail.com) + +[English Doc](README_eng.md "English") + +

VA产品说明&开发指导

+ +## 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技术架构 ## +![](https://cdn.jsdelivr.net/gh/xxxyanchenxxx/temp@1.0/doc/va_architecture.jpg) +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进程架构 # +![](https://cdn.jsdelivr.net/gh/xxxyanchenxxx/temp@1.0/doc/va_process.jpg) +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-16.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 | 支持 +
+ + +支持的APP类型: + +APP类型 | 是否支持 +---- | --- +32位APP | 支持 +64位APP | 支持 +
+ +支持的HOOK类型: + +Hook类型 | 是否支持 +---- | --- +Java Hook | 支持 +Native Hook | 支持 + +支持的CPU类型: + +Hook类型 | 是否支持 +---- | --- +ARM 32 | 支持 +ARM 64 | 支持 +
+ +## 集成VA遇到问题如何反馈? ## +购买授权后我们会建立微信群,有任何问题可以随时反馈给我们,并根据优先级在第一时间处理! + +## VA开发文档 ## +VA开发文档请参考:[开发文档](doc/VADev.md) + + + +授权说明 +------ +VirtualApp虚拟机技术归属于:山东盒一网络科技有限公司(原:济宁市罗盒网络科技有限公司),于2015年至2026年申请多项VirtualApp知识产权,`受中华人民共和国知识产权法保护`。当您需要使用Github上的代码时,**请购买商业授权**,获取商业授权后将可以收到最新VirtualApp商业版全部源代码。上百家授权客户在付费使用VirtualApp商业版代码,集成VirtualApp代码的APP日启动次数超过2亿次,众多安卓工程师向我们提供不同场景下的用户反馈,通过我们技术团队不断优化迭代,VirtualApp商业版代码性能更好、兼容性更高。`当您的公司获取授权后,将成为其中一员,享受这些不断迭代完善后的技术成果。并可以和我们的授权客户进行运营、技术及商业上的互动合作。` + +
+负责人:张总
+微信:10890
+
+ + +严重声明 +------ +您如果未经授权将VirtualApp用于**内部使用、商业牟利或上传应用市场**,我们将取证后报警(侵犯著作权罪)或起诉,这将对您所属公司造成刑事责任及法律诉讼,影响到您公司的商誉和投资。`购买商业授权为您节省大量开发、测试和完善兼容性的时间,让您更多时间用于创新及盈利。`罗盒科技已在2020年报警和起诉了一些个人及公司。
+ +**为响应国家对于知识产权的保护号召!凡举报自己所在公司或其他公司未经授权,违法使用VirtualApp代码开发产品的,一经核实给予现金奖励。我们会对举报人身份保密!举报联系微信:10890** + +
+ +商业版主要更新 +------ + +1. 兼容最新Android 16.0 +2. 支持Binder拦截,不再使用动态代理 +3. 支持Seccomp-Bpf拦截 +4. 不易被杀毒软件误报 +5. 框架优化,性能大幅提升 +6. 手机系统及APP兼容性大幅提升 +7. 完美运行Google服务 +8. 支持运行纯64位App +9. 内置`XPosed Hook`框架 +10. 增加定位模拟代码 +11. 增加改机代码 +12. 其他600+项问题的修复和改进,详情请见下表 + +
+ +2017年-2026年商业版代码更新详细 +------ + +**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调整
+ +
+2017年 12月 至 2025年 12 月 2 日 商业版代码更新内容(下拉打开)
+ +**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
+
+ + + + + + diff --git a/README_eng.md b/README_eng.md new file mode 100644 index 000000000..a55ad7ef2 --- /dev/null +++ b/README_eng.md @@ -0,0 +1,257 @@ + +[中文文档](README.md "中文") + +

VA Product description & Development guidance

+ +## What is VA? ## +VirtualAPP (abbreviation: VA) is a sandbox product running on Android system, which can be understood as a lightweight "Android virtual machine". Its product form is a highly extensible, customizable, integrated SDK that allows you to develop a variety of seemingly impossible projects based on or using VA. Now, VA is widely used in many technology fields as following: mini game collection, blockchain, cloud control, silent hot fix and so on. On the one hand, you can realize cloud control mobile office security and achieve military and government data isolation with VA. On the other hand, you can implement script automation, device-info-mock, and plug-in development. Meanwhile, you can realize multi space and games booster. You can also rent the mobile game account and use the mobile controller without activation by VA.
**The code on Github has stopped updating in December 2017. The code of business version is continuously being updated. If you need license to obtain the latest code, please contact WeChat: 10890.** + + +## Terminology in VA ## +Terminology | Explanation +---- | --- +Host | The APP that integrates the VirtualAPP SDK is called host. +Host Plug-in | A host package is used to run another ABI on the same device. It also called plug-in package,extension package, host plug-in package, host extension package. +Virtual APP / VAPP | App installed in the VA space +External APP | App installed in the device +
+ +## VA Technical architecture ## +![](https://cdn.jsdelivr.net/gh/xxxyanchenxxx/temp@1.0/doc/va_architecture.jpg) +VA technology involves the APP layer, Framework layer and Native layer of Android in total. +App must be installed on the system before it can run. The APP installed inside the VA space is not actually installed into the system, so it cannot run. Then how to get it to run? +Answer: The only way to do this is to "cheat" the system into thinking it has been installed. This "cheat" process is the core work of the VA Framework, and is also the core technical principle of the VA. + +**Here is the description of what did each layer do:** + +Layer | Main work +---- | --- +VA Space | An internal space is provided by the VA for the installation of the APP to be run inside it, and this space is system isolated. +VA Framework | This layer is mainly a proxy for Android Framework and VAPP, which is the core of VA. And VA provides a set of VA Framework of its own, which is between Android Framework and VA APP.
1. For VAPP, all the system services it accesses have been proxied by VA Framework, which will modify the request parameters of VAPP and send all the parameters related to VAPP installation information to Android Framework after changing them to the parameters of the host (Some of the requests will be sent to their own VA Server to be processed directly, and no longer send to the Android system). This way Android Framework receives the VAPP request and checks the parameters, and it will think there is no problem.
2. When the Android system finishes processing the request and returns the result, the VA Framework will also intercept the return result and restore all the parameters that have been original modified to those that were sent during the VAPP request. This way the interaction between VAPP and Android system can work. +VA Native | The main purpose of this layer is to accomplish 2 tasks: IO redirection and the request modification for VA APP to interact with Android system.
1. IO redirection is some APPs may be accessed through the hard code absolute path. But if the APP is not installed to the system, this path does not exist. Through IO redirection, it will be redirected to the path to install inside VA.
2. In addition, there are some jni functions that cannot be hooked in VA Framework, so they need to be hooked in the native layer. +
+ +In summary: +As you can see from the above technical architecture, the internal VA APP actually runs on top of VA's own VA Framework. VA has intercepted all system requests from its internal APP, and through this technology it can also have full control over the APP, not just the multi space. And for the convenience of developers, VA also provides SDK and Hook SDK. + + +## VA Process architecture# +![](https://cdn.jsdelivr.net/gh/xxxyanchenxxx/temp@1.0/doc/va_process.jpg) +There are five types of processes in the VA’s runtime: CHILD process, VA Host Main process, VA Host Plugin process, VAPP Client process, and VAServer process. +To support both 32-bit and 64-bit APPs, VA needs to install two packages: a master package and a plug-in package ( In this document, the main package is 32 bits and the plug-in package is 64 bit ). +Two packages are also necessary because a package can only run in one mode, either 32-bit or 64-bit. So for 32-bit APPs, VA uses the 32-bit main package to run, and for 64-bit APPs, VA uses the 64-bit plug-in package to run. +The main package contains all the code of VA, and the plug-in package contains only one piece of code that loads the main package code for execution, no other code. So plug-in package rarely needs to be updated, just the main package. +In addition, whether the main package is chosen to use 32-bit or 64-bit can be modified in the configuration file ( For example, for users who want to access GooglePlay, it will be modified to 64-bit for the main package and 32-bit for the plug-in package ). + +**The functions and explanations of the each type of process are as follows:**
+ +Process Type | Function +---- | --- +CHILD | Other processes integrated by VA Host, such as: keepalive process, push process, etc. +VA Host Main | The process where the UI main interface of the VA main package is located. The default main package is 32-bit and the plug-in package is 64-bit, which can be modified and switched in the configuration file +VA Host Plugin | The process that supports the plug-in package of 64-bit APP. The default main package is 32-bit and the plug-in package is 64-bit, which can be modified and switched in the configuration file. +VAPP Client | The process generated by the APP installed into VA after it starts, it will modify io.busniess.va:pxxx process name to the real process name of VAPP when it runs. +VAServer | The process where the VA Server is located, it is used to handle requests in VA that are not assigned to the system for processing, such as APP installation processing. +
+ +## VA can satisfy almost all your needs ## +Through the above technical architecture, we can know that VA can fully control APP and provide Hook SDK, which can satisfy almost all your needs in various fields: + +1. Satisfy the need of **dual/multi space** +VA allows you to install multiple WeChat/QQ/WhatsAPP/Facebook and other APPs on the same mobile phone, so you can have one phone with multiple accounts logged in at the same time. + +2. Satisfy the need of **mobile security** +VA provides a set of internal and external isolation mechanisms, including but not limited to (file isolation / component isolation / process communication isolation). Simply speaking, VA internal is a "completely independent space". +Through VA, work affairs and personal affairs can be safely separated without mutual interference. With a little customization, you can achieve mobile security-related needs such as application behavior audit, data encryption, data acquisition, data leakage prevention, anti-attack leaks and so on. + **2.1 Application behavior audit** +The HOOK capability provided by VA can realize real-time monitoring of user usage behavior and upload violation information to the server. And it's easy to implement things like Time Fence ( whether a feature of the APP can be used in a certain time ), Geo Fence ( whether a feature of the APP can be used in a certain area ), sensitive keyword filtering interception and other functional requirements. + **2.2 Data encryption** +The HOOK capability provided by VA can realize all data/file encryption of the application, ensuring data/file landing security. + **2.3 Data acquisition** +The HOOK capability provided by VA can realize the demand for real-time silent upload of application data, such as chat records and transfer records, preventing them from being deleted afterwards without traceability. + **2.4 Data leakage prevention** +The HOOK capability provided by VA can realize application anti-copy/paste, anti-screenshot/recording, anti-sharing/forwarding, watermark traceability and other requirements. + **2.5 Anti-attack leaks** +With the application control capability provided by VA, privacy-related behaviors such as SMS/ address book/call log/ background recording/background photo/ browsing history and location information can be completely controlled in sandbox, prevent Trojan horses/malicious APPs from acquiring users' real private data, causing serious consequences such as leakage of secrets. +3. Satisfy the need of **ROOT without HOOK** +VA provides Hook capability of Java and Native. With VA, you can easily achieve functions required by various scenarios, such as virtual positioning, changing device, APP monitoring and management, mobile security and so on. + +4. Satisfy the need of **silent installation** +VA provides the ability to silently install, silently upgrade and silently uninstall APPs. For example, the application store or game center can be integrated with VA to avoid the need for users to manually click to confirm the installation operation, so that it can be installed into VA immediately after downloading, bringing users an experience like "small program" , completely avoiding the problem of applications not easily installed by users. + +5. Satisfy the need of **APP controlled** +You can clearly grasp the system API, sensitive data, device information, etc. accessed by the APP through VA. For example, whether the APP accesses the contacts, photo albums, call log, whether it accesses the user's geographic location and other information. +Of course, you can also control or construct custom messages to these APPs via VA, and not only that, you can also get access to the APP's private data, such as chat database and so on. In a word, through the application control capability provided by VA, you can easily control all the behaviors of the APP, even modify the content of the APP and server interaction and so on .
+ + +6. Satisfy the need of **overseas markets** +VA implements support for Google services to support overseas APPs running, such as Twitter, Messenger, WhatsAPP, Instagram, FaceBook, Youtube and so on. + +7. Satisfy the need of **almost everything you can think of** +VA has complete oversight and control over the internal APP, and can meet almost any of your needs! +8. VA is also the only commercially licensed product in this technology area +**Hundreds of** licensed customers are currently paying to use the business version of VirtualAPP code, and the APP integrated with VirtualAPP code is launched more than 200 million times per day. Many Android engineers provide us with user feedback in different scenarios, and through our technical team's continuous optimization and iteration, we continue to improve product performance and compatibility. + + +VA Specialized capabilities +--- + +- Cloning ability
+You can clone the APP already installed in the external system and run it internally without mutual interference. Typical application scenario is double space. + +- Without installation ability
+In addition to cloning already installed, VA can install (externally silent ) apk's directly internally and run them directly internally. Typical application scenarios are plug-in, standalone APP marketplace and so on. + +- Double space ability
+VA is not only "double space", but also has a unique multi-user mode that allows users to open the same APP internally for an unlimited number of times. + +- Internal and external isolation ability
+VA is a standard sandbox, or "virtual machine", that provides a set of internal and external isolation mechanisms, including but not limited to (file isolation/component isolation/process communication isolation). Simply put, the inside of a VA is a "completely separate space". Simply put, the inside of a VA is a "completely separate space". Based on it, you can realize a "virtual phone" on your cell phone with a little customization. Of course, you can also use your imagination to customize it for data encryption, data isolation, privacy protection, and enterprise management applications. + +- Full control over internal APPs ability
+VA has complete monitoring and control over the internal APP, which is absolutely impossible to achieve in an external environment without Root. + +
+Details(Drop down to open) + 1. Service request control. First, VA directly provides some service request interception, you can easily customize these service requests when integrating VA, including but far from limited to (APP request to install apk / APP request to open certain files / APP request for location data / APP request for phone information, etc.)

+ 2. System API control. VA virtualizes and implements the entire Android system framework, which is the principle that VA can run apk internally without installation. And you can through modify the virtual framework's implementation to dynamically monitor and analyze the behavior of the app, etc. In addition, you can also mock some system behavior to achieve some needs that are difficult to achieve externally (e.g. game controller).

+ 3. Memory read and write. VA can read and write the memory of internal APP processes without Root.

+ 4. Root without debugging. VA can debug (ptrace) internal APP processes without Root, based on which you can also achieve Root-free process injection.

+ 5. Load arbitrary "plug-in" and "behaviors". The APP process inside VA is derived from the Client side code of the VA framework, so you can insert any "load" and "control" logic into the entry code of the process. These are very simple to implement.

+ 6. Hook. VA has a set of built-in Xposed framework and native hook framework running on all versions of Android (until AndroidQ), based on it, you can easily Hook any Java/Native of any internal APP.

+ 7. File control. VA built in a complete file redirection, which allows easy control of reading and writing of files from internal apps. Based on it, you can realize many functions such as protection and encryption of files can be achieved.

+ 8. Note: The above control capabilities are implemented with code or examples for reference. +
+ + +VA Other features +--- + +- High performance
+Process-level "virtual machine", VA's unique implementation model makes its performance almost the same as that of the native APP, and does not need a long startup of ordinary virtual machines. + +- Full version support
+Support 5.0-16.0, 32-bit/64-bit APP, ARM and X86 processor. And support Android version in the future which will be updated. + +- Easy Expansion and Integration
+The integration of VA is similar to the normal Android library, even if your APP has been online, you can conveniently integrate VA and enjoy the capability brought by VA. + +- Support Google services
+Provide support for Google services in order to support overseas APPs. + + +## Comparison between VA and other technical solutions ## +When doing enterprise-level mobile security, it is often necessary to control the APP, and the following is a comparison of possible technical solutions listed: + +Technical solution | Principle introduction | Comment | Running performance | Compatibility stability | Project maintenance cost +---- | --- | --- | --- | --- | --- +Repackage | Repackage the target APP by decompiling it and adding your own control code | 1. Nowadays, almost all APPs have hardened or tamper-proof protection, and repackaging is already a very difficult task
2.The mobile phone system will also detect whether the APP is repackaged, if it is repackaged, it will directly prompt the user that there is a security risk, and even not allow the installation
3.For each APP, even each version to go deep to reverse analysis, time-consuming and difficult to maintain | Excellent | Poor | High +Custom ROM | By customizing the system source code and compiling it to flash to the designated mobile phone | Only for specified internal mobile phones, too limited to be extended | Excellent | Excellent | High +ROOT the mobile phone | By rooting the mobile phone,flashing a framework which is similar to Xposed | 1.Now, root the mobile phone is an unlikely thing
2.In reality, it is difficult for users to root their own mobile phones | Excellent | Poor | High +VA | Lightweight virtual machine with high speed and low device requirements | No risk point mentioned above | Excellent | Excellent. Hundreds of companies testing feedback at the same time | Low. +VA provides API and a professional technical team to ensure the stable operation of the project +
+As you can see from the above comparison, VA is an excellent product and can reduce your development and maintenance costs. + +## Integrating VA Steps ## +Step 1: Call the VA interface```VirtualCore.get().startup()```in your application to start the VA engine. +Step 2: Call VA interface```VirtualCore.get().installPackageAsUser(userId, packageName)```to install the target APP into VA. +Step 3: Call VA interface```VActivityManager.get().launchApp(userId, packageName)```to start the APP. +**With only the above 3 APIs to complete the basic use, VA has shielded the complex technical details and provided the interface API to make your development easy.** + +## VA compatible stability ## +VA has been extensively tested by ** hundreds of **companies, including **high standards of testing and feedback of dozens of listed companies**, covering almost all types of equipment and scenarios at home and abroad, providing full protection for your stable operation! + + +Up to now, the supported system versions: + +System version | Whether to support +---- | --- +5.0 | support +5.1 | support +6.0 | support +7.0 | support +8.0 | support +9.1 | support +10.0 | support +11.0 | support +12.0 | support +13.0 | support +14.0 | support +15.0 | support +16.0 | support +
+ + +Supported App Types: + +App Type | Whether to support +---- | --- +32-bit APP | support +64-bit APP | support +
+ +Supported HOOK Types: + +Hook Type | Whether to support +---- | --- +Java Hook | support +Native Hook | support + +Supported CPU Types: + +Hook Type | Whether to support +---- | --- +ARM 32 | support +ARM 64 | support +
+ +## How to give feedback on problems encountered with integrated VA ? ## +After the purchase of the license we will establish a WeChat group, any problems can always feedback to us, and according to the priority in the first time to deal with. + +## VA Development document ## +Please refer to the VA development documentation:[Development document](doc/VADev_eng.md) + + +License Instructions +------ +VirtualApp virtual machine technology belongs to: Jining Luohe Network Technology Co., LTD. It applied for several VirtualApp intellectual property rights from 2015 to 2026 and` is protected by the Intellectual property Law of the People's Republic of China`.When you need to use the code on Github, **please purchase a business license**,and receive the full source code of the latest VirtualApp business version.Hundreds of licensed customers are paying to use the business version of VirtualApp code, and the app integrated with VirtualApp code is launched more than 200 million times a day. Many Android engineers provided us with user feedback in different scenarios, and through our technical team's continuous optimization and iteration, VirtualApp Business Edition code has better performance and higher compatibility. `The company of that year will become one of them after obtaining the license, and enjoy the technological achievements after the continuous iteration. And we can interact and collaborate with our licensed customers operationally, technically and commercially.` + +
+Person in charge: Mr. Zhang
+WeChat:10890
+
+ + +Serious statement +------ +If you use VirtualApp for **internal use, business profit or upload it to the application market**without licensing. We will take evidence and then report you to the police (for copyright infringement) or prosecute you. It will cause your company to undertake criminal liability and legal action, and affect your company's goodwill and investment.`Purchasing a business license can save you a lot of time developing, testing and refining compatibility, leaving you more time for innovation and profitability.`Luo He Technology has called to the police and sued a number of individuals and companies in 2020.
+ +**In response to the national call for the protection of intellectual property rights! Anyone who reports that his or her company or other companies are using VirtualApp code to develop products without licensing will be given a cash reward upon verification. We will keep the identity of the whistleblower confidential! Reporting WeChat: 10890.** + +
+ +Major updates of the business version +------ + +1. Support Android 16.0 +2. Support Seccomp-Bpf. +3. Not easily misreported by anti-virus software +4. Framework optimization, performance greatly improved +5. Mobile system and APP compatibility greatly improved +6. Run Google services perfectly +7. Supports running pure 64-bit Apps +8. Built-in `XPosed Hook` framework +9. Add positioning mock code +10. Add code to change device +11. Nearly 700 other fixes and improvements +
+ + + + + + + + + diff --git a/VirtualApp/app/build.gradle b/VirtualApp/app/build.gradle index acee148a4..6fee2f9fe 100644 --- a/VirtualApp/app/build.gradle +++ b/VirtualApp/app/build.gradle @@ -1,10 +1,9 @@ apply plugin: 'com.android.application' -apply plugin: 'me.tatarka.retrolambda' android { - compileSdkVersion 25 - buildToolsVersion "25.0.2" + compileSdkVersion 26 + buildToolsVersion '26.0.2' defaultConfig { applicationId "io.virtualapp" minSdkVersion 15 @@ -53,13 +52,13 @@ dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') compile project(':lib') //Android Lib - compile 'com.android.support:multidex:1.0.1' - compile 'com.android.support:appcompat-v7:25.0.1' + compile 'com.android.support:multidex:1.0.2' + compile 'com.android.support:appcompat-v7:25.4.0' compile 'com.melnykov:floatingactionbutton:1.3.0' - compile 'com.android.support:recyclerview-v7:25.0.1' - compile 'com.android.support:percent:25.0.1' - compile 'com.android.support:design:25.0.1' - compile 'com.android.support:cardview-v7:25.0.1' + compile 'com.android.support:recyclerview-v7:25.4.0' + compile 'com.android.support:percent:25.4.0' + compile 'com.android.support:design:25.4.0' + compile 'com.android.support:cardview-v7:25.4.0' //Promise Support compile 'org.jdeferred:jdeferred-android-aar:1.2.4' // ThirdParty diff --git a/VirtualApp/app/src/main/res/values-zh-rTW/strings.xml b/VirtualApp/app/src/main/res/values-zh-rTW/strings.xml new file mode 100644 index 000000000..84b69e6f8 --- /dev/null +++ b/VirtualApp/app/src/main/res/values-zh-rTW/strings.xml @@ -0,0 +1,24 @@ + + VirtualApp + 桌面 + 新增App + 正在打開App,請稍候… + 刪除 + 建立捷徑 + 新的用戶 + 開啟 + 儲存 + 儲存成功! + 製造商 + 請稍候… + 品牌 + 機型 + 偽造裝置資訊 + Wifi狀態 + 配置裝置資訊 + 關於 + 克隆App + 外部空間 + 安裝 (%d) + 不能一次性安裝超過 9 個程式! + diff --git a/VirtualApp/build.gradle b/VirtualApp/build.gradle index 7aa701d03..cc3fc8ce5 100644 --- a/VirtualApp/build.gradle +++ b/VirtualApp/build.gradle @@ -3,11 +3,14 @@ buildscript { repositories { jcenter() + maven { + url 'https://maven.google.com/' + name 'Google' + } } dependencies { - classpath 'com.android.tools.build:gradle:2.3.1' - classpath 'me.tatarka:gradle-retrolambda:3.6.0' - classpath 'com.android.tools.build:gradle-experimental:0.8.0' + classpath 'com.android.tools.build:gradle:3.0.1' + classpath 'com.android.tools.build:gradle-experimental:0.11.0' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } @@ -19,6 +22,10 @@ allprojects { maven { url "https://jitpack.io" } + maven { + url 'https://maven.google.com/' + name 'Google' + } } } diff --git a/VirtualApp/gradle/wrapper/gradle-wrapper.properties b/VirtualApp/gradle/wrapper/gradle-wrapper.properties index 00a91bd00..074ca5298 100644 --- a/VirtualApp/gradle/wrapper/gradle-wrapper.properties +++ b/VirtualApp/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Sun Jan 15 17:29:32 CST 2017 +#Sun Nov 19 13:36:42 CST 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip diff --git a/VirtualApp/lib/build.gradle b/VirtualApp/lib/build.gradle index d0dd7fa60..6008db59a 100644 --- a/VirtualApp/lib/build.gradle +++ b/VirtualApp/lib/build.gradle @@ -1,8 +1,8 @@ apply plugin: 'com.android.library' android { - compileSdkVersion 24 - buildToolsVersion "25.0.2" + compileSdkVersion 26 + buildToolsVersion '26.0.2' defaultConfig { minSdkVersion 14 @@ -11,7 +11,7 @@ android { versionName "1.0" externalNativeBuild { ndkBuild { - abiFilters "armeabi", "armeabi-v7a" + abiFilters "armeabi-v7a", "x86" } } } diff --git a/VirtualApp/lib/src/main/aidl/com/lody/virtual/server/IAccountManager.aidl b/VirtualApp/lib/src/main/aidl/com/lody/virtual/server/IAccountManager.aidl deleted file mode 100644 index 0847ff426..000000000 --- a/VirtualApp/lib/src/main/aidl/com/lody/virtual/server/IAccountManager.aidl +++ /dev/null @@ -1,47 +0,0 @@ -package com.lody.virtual.server; - -import android.accounts.IAccountManagerResponse; -import android.accounts.Account; -import android.accounts.AuthenticatorDescription; -import android.os.Bundle; - - -/** - * Central application service that provides account management. - * @hide - */ -interface IAccountManager { - AuthenticatorDescription[] getAuthenticatorTypes(int userId); - void getAccountsByFeatures(int userId, in IAccountManagerResponse response, in String type, in String[] features); - String getPreviousName(int userId, in Account account); - Account[] getAccounts(int userId, in String type); - void getAuthToken(int userId, in IAccountManagerResponse response, in Account account, in String authTokenType, in boolean notifyOnAuthFailure, in boolean expectActivityLaunch, in Bundle loginOptions); - void setPassword(int userId, in Account account, in String password); - void setAuthToken(int userId, in Account account, in String authTokenType, in String authToken); - void setUserData(int userId, in Account account, in String key, in String value); - void hasFeatures(int userId, in IAccountManagerResponse response, - in Account account, in String[] features); - void updateCredentials(int userId, in IAccountManagerResponse response, in Account account, - in String authTokenType, in boolean expectActivityLaunch, - in Bundle loginOptions); - void editProperties(int userId, in IAccountManagerResponse response, in String accountType, - in boolean expectActivityLaunch); - void getAuthTokenLabel(int userId, in IAccountManagerResponse response, in String accountType, - in String authTokenType); - String getUserData(int userId, in Account account, in String key); - String getPassword(int userId, in Account account); - void confirmCredentials(int userId, in IAccountManagerResponse response, in Account account, in Bundle options, in boolean expectActivityLaunch); - void addAccount(int userId, in IAccountManagerResponse response, in String accountType, - in String authTokenType, in String[] requiredFeatures, - in boolean expectActivityLaunch, in Bundle optionsIn); - boolean addAccountExplicitly(int userId, in Account account, in String password, in Bundle extras); - boolean removeAccountExplicitly(int userId, in Account account); - void renameAccount(int userId, in IAccountManagerResponse response, in Account accountToRename, in String newName); - void removeAccount(in int userId, in IAccountManagerResponse response, in Account account, - in boolean expectActivityLaunch); - void clearPassword(int userId, in Account account); - boolean accountAuthenticated(int userId, in Account account); - void invalidateAuthToken(int userId, in String accountType, in String authToken); - String peekAuthToken(int userId, in Account account, in String authTokenType); - -} \ No newline at end of file diff --git a/VirtualApp/lib/src/main/aidl/com/lody/virtual/server/IActivityManager.aidl b/VirtualApp/lib/src/main/aidl/com/lody/virtual/server/IActivityManager.aidl deleted file mode 100644 index 94d8625b5..000000000 --- a/VirtualApp/lib/src/main/aidl/com/lody/virtual/server/IActivityManager.aidl +++ /dev/null @@ -1,116 +0,0 @@ -// IActivityManager.aidl -package com.lody.virtual.server; - -import com.lody.virtual.remote.VParceledListSlice; -import com.lody.virtual.remote.AppTaskInfo; -import com.lody.virtual.remote.PendingIntentData; -import com.lody.virtual.remote.PendingResultData; -import com.lody.virtual.remote.BadgerInfo; -import android.content.Intent; -import android.content.pm.ActivityInfo; -import android.app.Notification; -import android.app.IServiceConnection; -import android.app.IActivityManager.ContentProviderHolder; -import com.lody.virtual.server.interfaces.IProcessObserver; - - -interface IActivityManager { - - int initProcess(in String packageName, in String processName, int userId); - - int getFreeStubCount(); - - int getSystemPid(); - - int getUidByPid(int pid); - - boolean isAppProcess(String processName); - - boolean isAppRunning(String packageName, int userId); - - boolean isAppPid(int pid); - - String getAppProcessName(int pid); - - List getProcessPkgList(int pid); - - void killAllApps(); - - void killAppByPkg(String pkg, int userId); - - void killApplicationProcess(String procName, int vuid); - - void dump(); - - void registerProcessObserver(in IProcessObserver observer); - - void unregisterProcessObserver(in IProcessObserver observer); - - String getInitialPackage(int pid); - - void handleApplicationCrash(); - - void appDoneExecuting(); - - int startActivities(in Intent[] intents, in String[] resolvedTypes, in IBinder token, in Bundle options, in int userId); - - int startActivity(in Intent intent, in ActivityInfo info, in IBinder resultTo, in Bundle options, String resultWho, int requestCode, int userId); - - void onActivityCreated(in ComponentName component, in ComponentName caller, in IBinder token, in Intent intent, in String affinity, int taskId, int launchMode, int flags); - - void onActivityResumed(int userId, in IBinder token); - - boolean onActivityDestroyed(int userId, in IBinder token); - - ComponentName getActivityClassForToken(int userId, in IBinder token); - - String getCallingPackage(int userId, in IBinder token); - - ComponentName getCallingActivity(int userId, in IBinder token); - - AppTaskInfo getTaskInfo(int taskId); - - String getPackageForToken(int userId, in IBinder token); - - boolean isVAServiceToken(in IBinder token); - - ComponentName startService(in IBinder caller,in Intent service, String resolvedType, int userId); - - int stopService(in IBinder caller, in Intent service, String resolvedType, int userId); - - boolean stopServiceToken(in ComponentName className, in IBinder token, int startId, int userId); - - void setServiceForeground(in ComponentName className, in IBinder token, int id, - in Notification notification, boolean removeNotification, int userId); - - int bindService(in IBinder caller, in IBinder token, in Intent service, - String resolvedType, in IServiceConnection connection, int flags, int userId); - - boolean unbindService(in IServiceConnection connection, int userId); - - void unbindFinished(in IBinder token, in Intent service, in boolean doRebind, int userId); - - void serviceDoneExecuting(in IBinder token, in int type, in int startId, in int res, int userId); - - IBinder peekService(in Intent service, String resolvedType, int userId); - - void publishService(in IBinder token, in Intent intent, in IBinder service, int userId); - - VParceledListSlice getServices(int maxNum, int flags, int userId); - - IBinder acquireProviderClient(int userId, in ProviderInfo info); - - PendingIntentData getPendingIntent(IBinder binder); - - void addPendingIntent(IBinder binder, String packageName); - - void removePendingIntent(IBinder binder); - - String getPackageForIntentSender(IBinder binder); - - void processRestarted(in String packageName, in String processName, int userId); - - void broadcastFinish(in PendingResultData res); - - void notifyBadgerChange(in BadgerInfo info); -} diff --git a/VirtualApp/lib/src/main/aidl/com/lody/virtual/server/IAppManager.aidl b/VirtualApp/lib/src/main/aidl/com/lody/virtual/server/IAppManager.aidl deleted file mode 100644 index ca665ed60..000000000 --- a/VirtualApp/lib/src/main/aidl/com/lody/virtual/server/IAppManager.aidl +++ /dev/null @@ -1,35 +0,0 @@ -// IAppManager.aidl -package com.lody.virtual.server; - -import com.lody.virtual.server.interfaces.IPackageObserver; -import com.lody.virtual.server.interfaces.IAppRequestListener; -import com.lody.virtual.remote.InstalledAppInfo; -import com.lody.virtual.remote.InstallResult; - -interface IAppManager { - int[] getPackageInstalledUsers(String packageName); - void scanApps(); - void addVisibleOutsidePackage(String pkg); - void removeVisibleOutsidePackage(String pkg); - boolean isOutsidePackageVisible(String pkg); - InstalledAppInfo getInstalledAppInfo(String pkg, int flags); - InstallResult installPackage(String path, int flags); - boolean isPackageLaunched(int userId, String packageName); - void setPackageHidden(int userId, String packageName, boolean hidden); - boolean installPackageAsUser(int userId, String packageName); - boolean uninstallPackageAsUser(String packageName, int userId); - boolean uninstallPackage(String packageName); - List getInstalledApps(int flags); - List getInstalledAppsAsUser(int userId, int flags); - int getInstalledAppCount(); - boolean isAppInstalled(String packageName); - boolean isAppInstalledAsUser(int userId, String packageName); - - void registerObserver(IPackageObserver observer); - void unregisterObserver(IPackageObserver observer); - - void setAppRequestListener(IAppRequestListener listener); - void clearAppRequestListener(); - IAppRequestListener getAppRequestListener(); - -} diff --git a/VirtualApp/lib/src/main/aidl/com/lody/virtual/server/IDeviceInfoManager.aidl b/VirtualApp/lib/src/main/aidl/com/lody/virtual/server/IDeviceInfoManager.aidl deleted file mode 100644 index 3305d799d..000000000 --- a/VirtualApp/lib/src/main/aidl/com/lody/virtual/server/IDeviceInfoManager.aidl +++ /dev/null @@ -1,12 +0,0 @@ -// IDeviceInfoManager.aidl -package com.lody.virtual.server; - -import com.lody.virtual.remote.VDeviceInfo; - -interface IDeviceInfoManager { - - VDeviceInfo getDeviceInfo(int userId); - - void updateDeviceInfo(int userId, in VDeviceInfo info); - -} diff --git a/VirtualApp/lib/src/main/aidl/com/lody/virtual/server/IJobScheduler.aidl b/VirtualApp/lib/src/main/aidl/com/lody/virtual/server/IJobScheduler.aidl deleted file mode 100644 index 5e230364c..000000000 --- a/VirtualApp/lib/src/main/aidl/com/lody/virtual/server/IJobScheduler.aidl +++ /dev/null @@ -1,13 +0,0 @@ -package com.lody.virtual.server; - -import android.app.job.JobInfo; - - /** - * IPC interface that supports the app-facing {@link #JobScheduler} api. - */ -interface IJobScheduler { - int schedule(in JobInfo job); - void cancel(int jobId); - void cancelAll(); - List getAllPendingJobs(); -} diff --git a/VirtualApp/lib/src/main/aidl/com/lody/virtual/server/INotificationManager.aidl b/VirtualApp/lib/src/main/aidl/com/lody/virtual/server/INotificationManager.aidl deleted file mode 100644 index c48b2320d..000000000 --- a/VirtualApp/lib/src/main/aidl/com/lody/virtual/server/INotificationManager.aidl +++ /dev/null @@ -1,14 +0,0 @@ -// INotificationManager.aidl -package com.lody.virtual.server; - -// Declare any non-default types here with import statements -import android.app.Notification; - -interface INotificationManager { - int dealNotificationId(int id, String packageName, String tag, int userId); - String dealNotificationTag(int id, String packageName, String tag, int userId); - boolean areNotificationsEnabledForPackage(String packageName, int userId); - void setNotificationsEnabledForPackage(String packageName, boolean enable, int userId); - void addNotification(int id, String tag, String packageName, int userId); - void cancelAllNotification(String packageName, int userId); -} diff --git a/VirtualApp/lib/src/main/aidl/com/lody/virtual/server/IPackageManager.aidl b/VirtualApp/lib/src/main/aidl/com/lody/virtual/server/IPackageManager.aidl deleted file mode 100644 index 973cbf7ef..000000000 --- a/VirtualApp/lib/src/main/aidl/com/lody/virtual/server/IPackageManager.aidl +++ /dev/null @@ -1,78 +0,0 @@ -// IPackageManager.aidl -package com.lody.virtual.server; - -import android.content.ComponentName; -import android.content.Intent; -import android.content.pm.PackageInfo; -import android.content.pm.ActivityInfo; -import android.content.pm.ServiceInfo; -import android.content.pm.ProviderInfo; -import android.content.pm.ResolveInfo; -import android.content.pm.ApplicationInfo; -import android.content.IntentFilter; -import android.content.pm.PermissionInfo; -import android.content.pm.PermissionGroupInfo; - -import com.lody.virtual.remote.ReceiverInfo; -import com.lody.virtual.remote.VParceledListSlice; - -import com.lody.virtual.server.IPackageInstaller; - -interface IPackageManager { - - int getPackageUid(String packageName, int userId); - - String[] getPackagesForUid(int vuid); - - List getSharedLibraries(String pkgName); - - int checkPermission(String permName, String pkgName, int userId); - - PackageInfo getPackageInfo(String packageName, int flags, int userId); - - ActivityInfo getActivityInfo(in ComponentName componentName, int flags, int userId); - - boolean activitySupportsIntent(in ComponentName component, in Intent intent, - in String resolvedType); - ActivityInfo getReceiverInfo(in ComponentName componentName, int flags, int userId); - - ServiceInfo getServiceInfo(in ComponentName componentName, int flags, int userId); - - ProviderInfo getProviderInfo(in ComponentName componentName, int flags, int userId); - - ResolveInfo resolveIntent(in Intent intent, in String resolvedType, int flags, int userId); - - List queryIntentActivities(in Intent intent,in String resolvedType, int flags, int userId); - - List queryIntentReceivers(in Intent intent, String resolvedType, int flags, int userId); - - ResolveInfo resolveService(in Intent intent, String resolvedType, int flags, int userId); - - List queryIntentServices(in Intent intent, String resolvedType, int flags, int userId); - - List queryIntentContentProviders(in Intent intent, String resolvedType, int flags, int userId); - - VParceledListSlice getInstalledPackages(int flags, int userId); - - VParceledListSlice getInstalledApplications(int flags, int userId); - - PermissionInfo getPermissionInfo(in String name, int flags); - - List queryPermissionsByGroup(in String group, int flags); - - PermissionGroupInfo getPermissionGroupInfo(in String name, int flags); - - List getAllPermissionGroups(int flags); - - ProviderInfo resolveContentProvider(in String name, int flags, int userId); - - ApplicationInfo getApplicationInfo(in String packageName, int flags, int userId); - - VParceledListSlice queryContentProviders(in String processName, int vuid, int flags); - - List querySharedPackages(in String packageName); - - String getNameForUid(int uid); - - IPackageInstaller getPackageInstaller(); -} diff --git a/VirtualApp/lib/src/main/aidl/com/lody/virtual/server/IUserManager.aidl b/VirtualApp/lib/src/main/aidl/com/lody/virtual/server/IUserManager.aidl deleted file mode 100644 index 1f0faded3..000000000 --- a/VirtualApp/lib/src/main/aidl/com/lody/virtual/server/IUserManager.aidl +++ /dev/null @@ -1,23 +0,0 @@ -package com.lody.virtual.server; - -import android.os.ParcelFileDescriptor; -import com.lody.virtual.os.VUserInfo; -import android.graphics.Bitmap; - -/** -* - */ -interface IUserManager { - VUserInfo createUser(in String name, int flags); - boolean removeUser(int userHandle); - void setUserName(int userHandle, String name); - void setUserIcon(int userHandle, in Bitmap icon); - Bitmap getUserIcon(int userHandle); - List getUsers(boolean excludeDying); - VUserInfo getUserInfo(int userHandle); - void setGuestEnabled(boolean enable); - boolean isGuestEnabled(); - void wipeUser(int userHandle); - int getUserSerialNumber(int userHandle); - int getUserHandle(int userSerialNumber); -} diff --git a/VirtualApp/lib/src/main/aidl/com/lody/virtual/server/IVirtualLocationManager.aidl b/VirtualApp/lib/src/main/aidl/com/lody/virtual/server/IVirtualLocationManager.aidl deleted file mode 100644 index 750319aa8..000000000 --- a/VirtualApp/lib/src/main/aidl/com/lody/virtual/server/IVirtualLocationManager.aidl +++ /dev/null @@ -1,30 +0,0 @@ -// IVirtualLocationManager.aidl -package com.lody.virtual.server; - -import com.lody.virtual.remote.vloc.VCell; -import com.lody.virtual.remote.vloc.VWifi; -import com.lody.virtual.remote.vloc.VLocation; - -interface IVirtualLocationManager { - - int getMode(int userId, in String pkg); - void setMode(int userId, in String pkg, int mode); - - void setCell(in int userId, in String pkg, in VCell cell); - void setAllCell(in int userId, in String pkg, in List cell); - void setNeighboringCell(in int userId, in String pkg, in List cell); - - void setGlobalCell(in VCell cell); - void setGlobalAllCell(in List cell); - void setGlobalNeighboringCell(in List cell); - - VCell getCell(in int userId, in String pkg); - List getAllCell(in int userId, in String pkg); - List getNeighboringCell(in int userId, in String pkg); - - void setLocation(in int userId, in String pkg, in VLocation loc); - VLocation getLocation(in int userId, in String pkg); - - void setGlobalLocation(in VLocation loc); - VLocation getGlobalLocation(); -} \ No newline at end of file diff --git a/VirtualApp/lib/src/main/aidl/com/lody/virtual/server/IVirtualStorageService.aidl b/VirtualApp/lib/src/main/aidl/com/lody/virtual/server/IVirtualStorageService.aidl deleted file mode 100644 index 042b8254b..000000000 --- a/VirtualApp/lib/src/main/aidl/com/lody/virtual/server/IVirtualStorageService.aidl +++ /dev/null @@ -1,15 +0,0 @@ -// IVirtualStorageService.aidl -package com.lody.virtual.server; - - -interface IVirtualStorageService { - - void setVirtualStorage(in String packageName, in int userId, in String vsPath); - - String getVirtualStorage(in String packageName, in int userId); - - void setVirtualStorageState(in String packageName, in int userId, in boolean enable); - - boolean isVirtualStorageEnable(in String packageName, in int userId); - -} diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/client/VClientImpl.java b/VirtualApp/lib/src/main/java/com/lody/virtual/client/VClientImpl.java index ff8b8349b..3d9bdffc3 100644 --- a/VirtualApp/lib/src/main/java/com/lody/virtual/client/VClientImpl.java +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/client/VClientImpl.java @@ -12,6 +12,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ProviderInfo; +import android.content.res.Configuration; import android.os.Binder; import android.os.Build; import android.os.ConditionVariable; @@ -20,6 +21,7 @@ import android.os.IInterface; import android.os.Looper; import android.os.Message; +import android.os.Parcelable; import android.os.Process; import android.os.RemoteException; import android.os.StrictMode; @@ -60,11 +62,17 @@ import mirror.android.app.ActivityThread; import mirror.android.app.ActivityThreadNMR1; import mirror.android.app.ContextImpl; +import mirror.android.app.ContextImplKitkat; import mirror.android.app.IActivityManager; import mirror.android.app.LoadedApk; +import mirror.android.app.LoadedApkICS; +import mirror.android.app.LoadedApkKitkat; import mirror.android.content.ContentProviderHolderOreo; +import mirror.android.content.res.CompatibilityInfo; import mirror.android.providers.Settings; import mirror.android.renderscript.RenderScriptCacheDir; +import mirror.android.view.CompatibilityInfoHolder; +import mirror.android.view.DisplayAdjustments; import mirror.android.view.HardwareRenderer; import mirror.android.view.RenderScript; import mirror.android.view.ThreadedRenderer; @@ -266,6 +274,7 @@ private void bindApplicationNoCheck(String packageName, String processName, Cond } else { codeCacheDir = context.getCacheDir(); } + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { if (HardwareRenderer.setupDiskCache != null) { HardwareRenderer.setupDiskCache.call(codeCacheDir); @@ -289,6 +298,17 @@ private void bindApplicationNoCheck(String packageName, String processName, Cond mirror.android.app.ActivityThread.AppBindData.info.set(boundApp, data.info); VMRuntime.setTargetSdkVersion.call(VMRuntime.getRuntime.call(), data.appInfo.targetSdkVersion); + Configuration configuration = context.getResources().getConfiguration(); + Object compatInfo = CompatibilityInfo.ctor.newInstance(data.appInfo, configuration.screenLayout, configuration.smallestScreenWidthDp, false); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { + DisplayAdjustments.setCompatibilityInfo.call(ContextImplKitkat.mDisplayAdjustments.get(context), compatInfo); + } + DisplayAdjustments.setCompatibilityInfo.call(LoadedApkKitkat.mDisplayAdjustments.get(mBoundApplication.info), compatInfo); + } else { + CompatibilityInfoHolder.set.call(LoadedApkICS.mCompatibilityInfo.get(mBoundApplication.info), compatInfo); + } + boolean conflict = SpecialComponentList.isConflictingInstrumentation(packageName); if (!conflict) { InvocationStubManager.getInstance().checkEnv(AppInstrumentation.class); @@ -358,6 +378,7 @@ private void setupUncaughtHandler() { groups.add(newRoot); mirror.java.lang.ThreadGroup.groups.set(root, groups); for (ThreadGroup group : newGroups) { + if (group == newRoot) continue; mirror.java.lang.ThreadGroup.parent.set(group, newRoot); } } @@ -369,6 +390,7 @@ private void setupUncaughtHandler() { ThreadGroupN.groups.set(newRoot, newGroups); ThreadGroupN.groups.set(root, new ThreadGroup[]{newRoot}); for (Object group : newGroups) { + if (group == newRoot) continue; ThreadGroupN.parent.set(group, newRoot); } ThreadGroupN.ngroups.set(root, 1); diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/client/core/InvocationStubManager.java b/VirtualApp/lib/src/main/java/com/lody/virtual/client/core/InvocationStubManager.java index 55cc89fab..a7712f023 100644 --- a/VirtualApp/lib/src/main/java/com/lody/virtual/client/core/InvocationStubManager.java +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/client/core/InvocationStubManager.java @@ -47,6 +47,7 @@ import com.lody.virtual.client.hook.proxies.usage.UsageStatsManagerStub; import com.lody.virtual.client.hook.proxies.user.UserManagerStub; import com.lody.virtual.client.hook.proxies.vibrator.VibratorStub; +import com.lody.virtual.client.hook.proxies.view.AutoFillManagerStub; import com.lody.virtual.client.hook.proxies.wifi.WifiManagerStub; import com.lody.virtual.client.hook.proxies.wifi_scanner.WifiScannerStub; import com.lody.virtual.client.hook.proxies.window.WindowManagerStub; @@ -179,6 +180,9 @@ private void injectInternal() throws Throwable { addInjector(new ShortcutServiceStub()); addInjector(new DevicePolicyManagerStub()); } + if (Build.VERSION.SDK_INT >= 26) { + addInjector(new AutoFillManagerStub()); + } } } diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/client/core/VirtualCore.java b/VirtualApp/lib/src/main/java/com/lody/virtual/client/core/VirtualCore.java index 2a9d7a4fc..bf77a3fe3 100644 --- a/VirtualApp/lib/src/main/java/com/lody/virtual/client/core/VirtualCore.java +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/client/core/VirtualCore.java @@ -16,6 +16,7 @@ import android.graphics.Bitmap; import android.os.Bundle; import android.os.ConditionVariable; +import android.os.IBinder; import android.os.Looper; import android.os.Process; import android.os.RemoteException; @@ -28,17 +29,20 @@ import com.lody.virtual.client.hook.delegate.ComponentDelegate; import com.lody.virtual.client.hook.delegate.PhoneInfoDelegate; import com.lody.virtual.client.hook.delegate.TaskDescriptionDelegate; -import com.lody.virtual.client.ipc.LocalProxyUtils; import com.lody.virtual.client.ipc.ServiceManagerNative; import com.lody.virtual.client.ipc.VActivityManager; import com.lody.virtual.client.ipc.VPackageManager; import com.lody.virtual.client.stub.VASettings; import com.lody.virtual.helper.compat.BundleCompat; +import com.lody.virtual.helper.ipcbus.IPCBus; +import com.lody.virtual.helper.ipcbus.IPCSingleton; +import com.lody.virtual.helper.ipcbus.IServerCache; import com.lody.virtual.helper.utils.BitmapUtils; import com.lody.virtual.os.VUserHandle; import com.lody.virtual.remote.InstallResult; import com.lody.virtual.remote.InstalledAppInfo; -import com.lody.virtual.server.IAppManager; +import com.lody.virtual.server.interfaces.IAppManager; +import com.lody.virtual.server.ServiceCache; import com.lody.virtual.server.interfaces.IAppRequestListener; import com.lody.virtual.server.interfaces.IPackageObserver; import com.lody.virtual.server.interfaces.IUiCallback; @@ -82,7 +86,7 @@ public final class VirtualCore { */ private String processName; private ProcessType processType; - private IAppManager mService; + private IPCSingleton singleton = new IPCSingleton<>(IAppManager.class); private boolean isStartUp; private PackageInfo hostPkgInfo; private int systemPid; @@ -178,6 +182,17 @@ public void startup(Context context) throws Throwable { mainThread = ActivityThread.currentActivityThread.call(); unHookPackageManager = context.getPackageManager(); hostPkgInfo = unHookPackageManager.getPackageInfo(context.getPackageName(), PackageManager.GET_PROVIDERS); + IPCBus.initialize(new IServerCache() { + @Override + public void join(String serverName, IBinder binder) { + ServiceCache.addService(serverName, binder); + } + + @Override + public IBinder query(String serverName) { + return ServiceManagerNative.getService(serverName); + } + }); detectProcessType(); InvocationStubManager invocationStubManager = InvocationStubManager.getInstance(); invocationStubManager.init(); @@ -252,19 +267,7 @@ private void detectProcessType() { } private IAppManager getService() { - if (mService == null - || (!VirtualCore.get().isVAppProcess() && !mService.asBinder().isBinderAlive())) { - synchronized (this) { - Object remote = getStubInterface(); - mService = LocalProxyUtils.genProxy(IAppManager.class, remote); - } - } - return mService; - } - - private Object getStubInterface() { - return IAppManager.Stub - .asInterface(ServiceManagerNative.getService(ServiceManagerNative.APP)); + return singleton.get(); } /** diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/client/env/SpecialComponentList.java b/VirtualApp/lib/src/main/java/com/lody/virtual/client/env/SpecialComponentList.java index 9d1872b22..91c95e88f 100644 --- a/VirtualApp/lib/src/main/java/com/lody/virtual/client/env/SpecialComponentList.java +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/client/env/SpecialComponentList.java @@ -43,6 +43,7 @@ public final class SpecialComponentList { SYSTEM_BROADCAST_ACTION.add(Intent.ACTION_BATTERY_OKAY); SYSTEM_BROADCAST_ACTION.add(Intent.ACTION_POWER_CONNECTED); SYSTEM_BROADCAST_ACTION.add(Intent.ACTION_POWER_DISCONNECTED); + SYSTEM_BROADCAST_ACTION.add(Intent.ACTION_USER_PRESENT); SYSTEM_BROADCAST_ACTION.add("android.provider.Telephony.SMS_RECEIVED"); SYSTEM_BROADCAST_ACTION.add("android.provider.Telephony.SMS_DELIVER"); SYSTEM_BROADCAST_ACTION.add("android.net.wifi.STATE_CHANGE"); diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/am/ActivityManagerStub.java b/VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/am/ActivityManagerStub.java index 077514925..329f54207 100644 --- a/VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/am/ActivityManagerStub.java +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/am/ActivityManagerStub.java @@ -115,27 +115,6 @@ public Object call(Object who, Method method, Object... args) throws Throwable { return _infos; } }); - addMethodProxy(new StaticMethodProxy("getRunningTasks") { - @Override - public Object call(Object who, Method method, Object... args) throws Throwable { - Object _infos = method.invoke(who, args); - //noinspection unchecked - List infos = - ParceledListSliceCompat.isReturnParceledListSlice(method) - ? ParceledListSlice.getList.call(_infos) - : (List) _infos; - for (ActivityManager.RunningTaskInfo info : infos) { - AppTaskInfo taskInfo = VActivityManager.get().getTaskInfo(info.id); - if (taskInfo == null) { - continue; - } - info.description = "Virtual"; - info.topActivity = taskInfo.topActivity; - info.baseActivity = taskInfo.baseActivity; - } - return _infos; - } - }); } } diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/am/MethodProxies.java b/VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/am/MethodProxies.java index d49d1052f..2ae83489f 100644 --- a/VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/am/MethodProxies.java +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/am/MethodProxies.java @@ -28,6 +28,7 @@ import android.os.IInterface; import android.os.RemoteException; import android.text.TextUtils; +import android.util.Log; import android.util.TypedValue; import com.lody.virtual.client.VClientImpl; @@ -55,6 +56,7 @@ import com.lody.virtual.helper.utils.BitmapUtils; import com.lody.virtual.helper.utils.ComponentUtils; import com.lody.virtual.helper.utils.DrawableUtils; +import com.lody.virtual.helper.utils.FileUtils; import com.lody.virtual.helper.utils.Reflect; import com.lody.virtual.helper.utils.VLog; import com.lody.virtual.os.VUserHandle; @@ -63,6 +65,10 @@ import com.lody.virtual.server.interfaces.IAppRequestListener; import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.lang.ref.WeakReference; import java.lang.reflect.Method; import java.util.List; @@ -74,6 +80,8 @@ import mirror.android.content.IIntentReceiverJB; import mirror.android.content.pm.UserInfo; +import static com.lody.virtual.client.stub.VASettings.INTERCEPT_BACK_HOME; + /** * @author Lody */ @@ -360,6 +368,7 @@ static class StartActivity extends MethodProxy { private static final String SCHEME_FILE = "file"; private static final String SCHEME_PACKAGE = "package"; + private static final String SCHEME_CONTENT = "content"; @Override public String getMethodName() { @@ -368,6 +377,9 @@ public String getMethodName() { @Override public Object call(Object who, Method method, Object... args) throws Throwable { + + Log.d("Q_M", "---->StartActivity 类"); + int intentIndex = ArrayUtils.indexOfObject(args, Intent.class, 1); if (intentIndex < 0) { return ActivityManagerCompat.START_INTENT_NOT_RESOLVED; @@ -427,9 +439,22 @@ public Object call(Object who, Method method, Object... args) throws Throwable { ActivityInfo activityInfo = VirtualCore.get().resolveActivityInfo(intent, userId); if (activityInfo == null) { VLog.e("VActivityManager", "Unable to resolve activityInfo : " + intent); + + Log.d("Q_M", "---->StartActivity who=" + who); + Log.d("Q_M", "---->StartActivity intent=" + intent); + Log.d("Q_M", "---->StartActivity resultTo=" + resultTo); + if (intent.getPackage() != null && isAppPkg(intent.getPackage())) { return ActivityManagerCompat.START_INTENT_NOT_RESOLVED; } + + if (INTERCEPT_BACK_HOME && Intent.ACTION_MAIN.equals(intent.getAction()) + && intent.getCategories().contains("android.intent.category.HOME") + && resultTo != null) { + VActivityManager.get().finishActivity(resultTo); + return 0; + } + return method.invoke(who, args); } int res = VActivityManager.get().startActivity(intent, activityInfo, resultTo, options, resultWho, requestCode, VUserHandle.myUserId()); @@ -475,6 +500,32 @@ private boolean handleInstallRequest(Intent intent) { } catch (RemoteException e) { e.printStackTrace(); } + } else if (SCHEME_CONTENT.equals(packageUri.getScheme())) { + InputStream inputStream = null; + OutputStream outputStream = null; + File sharedFileCopy = new File(getHostContext().getCacheDir(), packageUri.getLastPathSegment()); + try { + inputStream = getHostContext().getContentResolver().openInputStream(packageUri); + outputStream = new FileOutputStream(sharedFileCopy); + byte[] buffer = new byte[1024]; + int count; + while ((count = inputStream.read(buffer)) > 0) { + outputStream.write(buffer, 0, count); + } + outputStream.flush(); + + } catch (IOException e) { + e.printStackTrace(); + } finally { + FileUtils.closeQuietly(inputStream); + FileUtils.closeQuietly(outputStream); + } + try { + listener.onRequestInstall(sharedFileCopy.getPath()); + return true; + } catch (RemoteException e) { + e.printStackTrace(); + } } } diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/bluetooth/BluetoothStub.java b/VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/bluetooth/BluetoothStub.java index 9590cab43..1eb15b4ff 100644 --- a/VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/bluetooth/BluetoothStub.java +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/bluetooth/BluetoothStub.java @@ -9,6 +9,7 @@ import java.lang.reflect.Method; import mirror.android.bluetooth.IBluetooth; +import mirror.android.bluetooth.IBluetoothManager; /** * @see android.bluetooth.BluetoothManager @@ -19,7 +20,8 @@ public class BluetoothStub extends BinderInvocationProxy { "bluetooth"; public BluetoothStub() { - super(IBluetooth.Stub.asInterface, SERVICE_NAME); + super(Build.VERSION.SDK_INT >= 17 ? IBluetoothManager.Stub.asInterface : IBluetooth.Stub.asInterface, + SERVICE_NAME); } @Override diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/job/JobServiceStub.java b/VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/job/JobServiceStub.java index 2682c4032..8b665938a 100644 --- a/VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/job/JobServiceStub.java +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/job/JobServiceStub.java @@ -3,91 +3,142 @@ import android.annotation.TargetApi; import android.app.job.JobInfo; import android.content.Context; +import android.content.Intent; import android.os.Build; +import android.os.Build.VERSION; import com.lody.virtual.client.hook.base.MethodProxy; import com.lody.virtual.client.hook.base.BinderInvocationProxy; import com.lody.virtual.client.ipc.VJobScheduler; +import com.lody.virtual.helper.utils.ComponentUtils; import java.lang.reflect.Method; import mirror.android.app.job.IJobScheduler; +import mirror.android.app.job.JobWorkItem; /** * @author Lody - * * @see android.app.job.JobScheduler */ @TargetApi(Build.VERSION_CODES.LOLLIPOP) public class JobServiceStub extends BinderInvocationProxy { - public JobServiceStub() { - super(IJobScheduler.Stub.asInterface, Context.JOB_SCHEDULER_SERVICE); - } - - @Override - protected void onBindMethods() { - super.onBindMethods(); - addMethodProxy(new schedule()); - addMethodProxy(new getAllPendingJobs()); - addMethodProxy(new cancelAll()); - addMethodProxy(new cancel()); - } - - - private class schedule extends MethodProxy { - - @Override - public String getMethodName() { - return "schedule"; - } - - @Override - public Object call(Object who, Method method, Object... args) throws Throwable { - JobInfo jobInfo = (JobInfo) args[0]; - return VJobScheduler.get().schedule(jobInfo); - } - } - - private class getAllPendingJobs extends MethodProxy { - - @Override - public String getMethodName() { - return "getAllPendingJobs"; - } - - @Override - public Object call(Object who, Method method, Object... args) throws Throwable { - return VJobScheduler.get().getAllPendingJobs(); - } - } - - private class cancelAll extends MethodProxy { - - @Override - public String getMethodName() { - return "cancelAll"; - } - - @Override - public Object call(Object who, Method method, Object... args) throws Throwable { - VJobScheduler.get().cancelAll(); - return 0; - } - } - - private class cancel extends MethodProxy { - - @Override - public String getMethodName() { - return "cancel"; - } - - @Override - public Object call(Object who, Method method, Object... args) throws Throwable { - int jobId = (int) args[0]; - VJobScheduler.get().cancel(jobId); - return 0; - } - } + public JobServiceStub() { + super(IJobScheduler.Stub.asInterface, Context.JOB_SCHEDULER_SERVICE); + } + + @Override + protected void onBindMethods() { + super.onBindMethods(); + addMethodProxy(new schedule()); + addMethodProxy(new getAllPendingJobs()); + addMethodProxy(new cancelAll()); + addMethodProxy(new cancel()); + + if (VERSION.SDK_INT >= 24) { + addMethodProxy(new getPendingJob()); + } + if (VERSION.SDK_INT >= 26) { + addMethodProxy(new enqueue()); + } + } + + + private class schedule extends MethodProxy { + + @Override + public String getMethodName() { + return "schedule"; + } + + @Override + public Object call(Object who, Method method, Object... args) throws Throwable { + JobInfo jobInfo = (JobInfo) args[0]; + return VJobScheduler.get().schedule(jobInfo); + } + } + + private class getAllPendingJobs extends MethodProxy { + + @Override + public String getMethodName() { + return "getAllPendingJobs"; + } + + @Override + public Object call(Object who, Method method, Object... args) throws Throwable { + return VJobScheduler.get().getAllPendingJobs(); + } + } + + private class cancelAll extends MethodProxy { + + @Override + public String getMethodName() { + return "cancelAll"; + } + + @Override + public Object call(Object who, Method method, Object... args) throws Throwable { + VJobScheduler.get().cancelAll(); + return 0; + } + } + + private class cancel extends MethodProxy { + + @Override + public String getMethodName() { + return "cancel"; + } + + @Override + public Object call(Object who, Method method, Object... args) throws Throwable { + int jobId = (int) args[0]; + VJobScheduler.get().cancel(jobId); + return 0; + } + } + + private class getPendingJob extends MethodProxy { + private getPendingJob() { + } + + public Object call(Object who, Method method, Object... args) throws Throwable { + return VJobScheduler.get().getPendingJob((Integer) args[0]); + } + + public String getMethodName() { + return "getPendingJob"; + } + } + + private class enqueue extends MethodProxy { + private enqueue() { + } + + public Object call(Object who, Method method, Object... args) throws Throwable { + return VJobScheduler.get().enqueue( + (JobInfo) args[0], + JobServiceStub.this.redirect(args[1], MethodProxy.getAppPkg()) + ); + } + + public String getMethodName() { + return "enqueue"; + } + } + + private Object redirect(Object item, String pkg) { + if (item == null) { + return null; + } + Intent redirectIntentSender = ComponentUtils.redirectIntentSender(4, pkg, (Intent) JobWorkItem.getIntent.call(item, new Object[0]), null); + Object newInstance = JobWorkItem.ctor.newInstance(redirectIntentSender); + JobWorkItem.mWorkId.set(newInstance, JobWorkItem.mWorkId.get(item)); + JobWorkItem.mGrants.set(newInstance, JobWorkItem.mGrants.get(item)); + JobWorkItem.mDeliveryCount.set(newInstance, JobWorkItem.mDeliveryCount.get(item)); + return newInstance; + } } diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/location/MethodProxies.java b/VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/location/MethodProxies.java index 7aa156b8e..9edefbb3e 100644 --- a/VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/location/MethodProxies.java +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/location/MethodProxies.java @@ -282,7 +282,7 @@ public String getMethodName() { @Override public Object afterCall(Object who, Method method, Object[] args, Object result) throws Throwable { - if (isFakeLocationEnable()) { + if (!isFakeLocationEnable()) { return super.afterCall(who, method, args, result); } try { diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/view/AutoFillManagerStub.java b/VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/view/AutoFillManagerStub.java new file mode 100644 index 000000000..27c898c2c --- /dev/null +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/view/AutoFillManagerStub.java @@ -0,0 +1,83 @@ +package com.lody.virtual.client.hook.proxies.view; + +import android.annotation.SuppressLint; +import android.util.Log; + +import com.lody.virtual.client.hook.base.BinderInvocationProxy; +import com.lody.virtual.client.hook.base.MethodProxy; +import com.lody.virtual.client.hook.utils.MethodParameterUtils; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +import mirror.android.view.IAutoFillManager; + +/** + * @author 陈磊. + */ + +public class AutoFillManagerStub extends BinderInvocationProxy { + + private static final String TAG = "AutoFillManagerStub"; + + private static final String AUTO_FILL_NAME = "autofill"; + public AutoFillManagerStub() { + super(IAutoFillManager.Stub.asInterface, AUTO_FILL_NAME); + } + + @SuppressLint("WrongConstant") + @Override + public void inject() throws Throwable { + super.inject(); + try { + Object AutoFillManagerInstance = getContext().getSystemService(AUTO_FILL_NAME); + if (AutoFillManagerInstance == null) { + throw new NullPointerException("AutoFillManagerInstance is null."); + } + Object AutoFillManagerProxy = getInvocationStub().getProxyInterface(); + if (AutoFillManagerProxy == null) { + throw new NullPointerException("AutoFillManagerProxy is null."); + } + Field AutoFillManagerServiceField = AutoFillManagerInstance.getClass().getDeclaredField("mService"); + AutoFillManagerServiceField.setAccessible(true); + AutoFillManagerServiceField.set(AutoFillManagerInstance, AutoFillManagerProxy); + } catch (Throwable tr) { + Log.e(TAG, "AutoFillManagerStub inject error.", tr); + return; + } + addMethodProxy(new MethodProxy() { + @Override + public String getMethodName() { + return "startSession"; + } + @Override + public boolean beforeCall(Object who, Method method, Object... args) { + MethodParameterUtils.replaceLastAppPkg(args); + return super.beforeCall(who, method, args); + } + }); + addMethodProxy(new MethodProxy() { + @Override + public String getMethodName() { + return "updateOrRestartSession"; + } + @Override + public boolean beforeCall(Object who, Method method, Object... args) { + MethodParameterUtils.replaceLastAppPkg(args); + return super.beforeCall(who, method, args); + } + }); + addMethodProxy(new MethodProxy() { + @Override + public String getMethodName() { + return "isServiceEnabled"; + } + @Override + public boolean beforeCall(Object who, Method method, Object... args) { + MethodParameterUtils.replaceLastAppPkg(args); + return super.beforeCall(who, method, args); + } + }); + } + +} diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/client/ipc/VAccountManager.java b/VirtualApp/lib/src/main/java/com/lody/virtual/client/ipc/VAccountManager.java index 084adaf37..075b779be 100644 --- a/VirtualApp/lib/src/main/java/com/lody/virtual/client/ipc/VAccountManager.java +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/client/ipc/VAccountManager.java @@ -10,11 +10,11 @@ import android.os.Handler; import android.os.RemoteException; -import com.lody.virtual.client.core.VirtualCore; import com.lody.virtual.client.env.VirtualRuntime; import com.lody.virtual.client.stub.AmsTask; +import com.lody.virtual.helper.ipcbus.IPCSingleton; import com.lody.virtual.os.VUserHandle; -import com.lody.virtual.server.IAccountManager; +import com.lody.virtual.server.interfaces.IAccountManager; import static com.lody.virtual.helper.compat.AccountManagerCompat.KEY_ANDROID_PACKAGE_NAME; @@ -26,31 +26,19 @@ public class VAccountManager { private static VAccountManager sMgr = new VAccountManager(); - private IAccountManager mRemote; + private IPCSingleton singleton = new IPCSingleton<>(IAccountManager.class); public static VAccountManager get() { return sMgr; } - public IAccountManager getRemote() { - if (mRemote == null || - (!mRemote.asBinder().isBinderAlive() && !VirtualCore.get().isVAppProcess())) { - synchronized (VAccountManager.class) { - Object remote = getStubInterface(); - mRemote = LocalProxyUtils.genProxy(IAccountManager.class, remote); - } - } - return mRemote; - } - - private Object getStubInterface() { - return IAccountManager.Stub - .asInterface(ServiceManagerNative.getService(ServiceManagerNative.ACCOUNT)); + public IAccountManager getService() { + return singleton.get(); } public AuthenticatorDescription[] getAuthenticatorTypes() { try { - return getRemote().getAuthenticatorTypes(VUserHandle.myUserId()); + return getService().getAuthenticatorTypes(VUserHandle.myUserId()); } catch (RemoteException e) { return VirtualRuntime.crash(e); } @@ -58,7 +46,7 @@ public AuthenticatorDescription[] getAuthenticatorTypes() { public void removeAccount(IAccountManagerResponse response, Account account, boolean expectActivityLaunch) { try { - getRemote().removeAccount(VUserHandle.myUserId(), response, account, expectActivityLaunch); + getService().removeAccount(VUserHandle.myUserId(), response, account, expectActivityLaunch); } catch (RemoteException e) { e.printStackTrace(); } @@ -66,7 +54,7 @@ public void removeAccount(IAccountManagerResponse response, Account account, boo public void getAuthToken(IAccountManagerResponse response, Account account, String authTokenType, boolean notifyOnAuthFailure, boolean expectActivityLaunch, Bundle loginOptions) { try { - getRemote().getAuthToken(VUserHandle.myUserId(), response, account, authTokenType, notifyOnAuthFailure, expectActivityLaunch, loginOptions); + getService().getAuthToken(VUserHandle.myUserId(), response, account, authTokenType, notifyOnAuthFailure, expectActivityLaunch, loginOptions); } catch (RemoteException e) { e.printStackTrace(); } @@ -74,7 +62,7 @@ public void getAuthToken(IAccountManagerResponse response, Account account, Stri public boolean addAccountExplicitly(Account account, String password, Bundle extras) { try { - return getRemote().addAccountExplicitly(VUserHandle.myUserId(), account, password, extras); + return getService().addAccountExplicitly(VUserHandle.myUserId(), account, password, extras); } catch (RemoteException e) { return VirtualRuntime.crash(e); } @@ -82,7 +70,7 @@ public boolean addAccountExplicitly(Account account, String password, Bundle ext public Account[] getAccounts(int userId, String type) { try { - return getRemote().getAccounts(userId, type); + return getService().getAccounts(userId, type); } catch (RemoteException e) { return VirtualRuntime.crash(e); } @@ -90,7 +78,7 @@ public Account[] getAccounts(int userId, String type) { public Account[] getAccounts(String type) { try { - return getRemote().getAccounts(VUserHandle.myUserId(), type); + return getService().getAccounts(VUserHandle.myUserId(), type); } catch (RemoteException e) { return VirtualRuntime.crash(e); } @@ -98,7 +86,7 @@ public Account[] getAccounts(String type) { public String peekAuthToken(Account account, String authTokenType) { try { - return getRemote().peekAuthToken(VUserHandle.myUserId(), account, authTokenType); + return getService().peekAuthToken(VUserHandle.myUserId(), account, authTokenType); } catch (RemoteException e) { return VirtualRuntime.crash(e); } @@ -106,7 +94,7 @@ public String peekAuthToken(Account account, String authTokenType) { public String getPreviousName(Account account) { try { - return getRemote().getPreviousName(VUserHandle.myUserId(), account); + return getService().getPreviousName(VUserHandle.myUserId(), account); } catch (RemoteException e) { return VirtualRuntime.crash(e); } @@ -114,7 +102,7 @@ public String getPreviousName(Account account) { public void hasFeatures(IAccountManagerResponse response, Account account, String[] features) { try { - getRemote().hasFeatures(VUserHandle.myUserId(), response, account, features); + getService().hasFeatures(VUserHandle.myUserId(), response, account, features); } catch (RemoteException e) { e.printStackTrace(); } @@ -122,7 +110,7 @@ public void hasFeatures(IAccountManagerResponse response, Account account, Strin public boolean accountAuthenticated(Account account) { try { - return getRemote().accountAuthenticated(VUserHandle.myUserId(), account); + return getService().accountAuthenticated(VUserHandle.myUserId(), account); } catch (RemoteException e) { return VirtualRuntime.crash(e); } @@ -130,7 +118,7 @@ public boolean accountAuthenticated(Account account) { public void clearPassword(Account account) { try { - getRemote().clearPassword(VUserHandle.myUserId(), account); + getService().clearPassword(VUserHandle.myUserId(), account); } catch (RemoteException e) { e.printStackTrace(); } @@ -138,7 +126,7 @@ public void clearPassword(Account account) { public void renameAccount(IAccountManagerResponse response, Account accountToRename, String newName) { try { - getRemote().renameAccount(VUserHandle.myUserId(), response, accountToRename, newName); + getService().renameAccount(VUserHandle.myUserId(), response, accountToRename, newName); } catch (RemoteException e) { e.printStackTrace(); } @@ -146,7 +134,7 @@ public void renameAccount(IAccountManagerResponse response, Account accountToRen public void setPassword(Account account, String password) { try { - getRemote().setPassword(VUserHandle.myUserId(), account, password); + getService().setPassword(VUserHandle.myUserId(), account, password); } catch (RemoteException e) { e.printStackTrace(); } @@ -154,7 +142,7 @@ public void setPassword(Account account, String password) { public void addAccount(int userId, IAccountManagerResponse response, String accountType, String authTokenType, String[] requiredFeatures, boolean expectActivityLaunch, Bundle optionsIn) { try { - getRemote().addAccount(userId, response, accountType, authTokenType, requiredFeatures, expectActivityLaunch, optionsIn); + getService().addAccount(userId, response, accountType, authTokenType, requiredFeatures, expectActivityLaunch, optionsIn); } catch (RemoteException e) { e.printStackTrace(); } @@ -162,7 +150,7 @@ public void addAccount(int userId, IAccountManagerResponse response, String acco public void addAccount(IAccountManagerResponse response, String accountType, String authTokenType, String[] requiredFeatures, boolean expectActivityLaunch, Bundle optionsIn) { try { - getRemote().addAccount(VUserHandle.myUserId(), response, accountType, authTokenType, requiredFeatures, expectActivityLaunch, optionsIn); + getService().addAccount(VUserHandle.myUserId(), response, accountType, authTokenType, requiredFeatures, expectActivityLaunch, optionsIn); } catch (RemoteException e) { e.printStackTrace(); } @@ -170,7 +158,7 @@ public void addAccount(IAccountManagerResponse response, String accountType, Str public void updateCredentials(IAccountManagerResponse response, Account account, String authTokenType, boolean expectActivityLaunch, Bundle loginOptions) { try { - getRemote().updateCredentials(VUserHandle.myUserId(), response, account, authTokenType, expectActivityLaunch, loginOptions); + getService().updateCredentials(VUserHandle.myUserId(), response, account, authTokenType, expectActivityLaunch, loginOptions); } catch (RemoteException e) { e.printStackTrace(); } @@ -178,7 +166,7 @@ public void updateCredentials(IAccountManagerResponse response, Account account, public boolean removeAccountExplicitly(Account account) { try { - return getRemote().removeAccountExplicitly(VUserHandle.myUserId(), account); + return getService().removeAccountExplicitly(VUserHandle.myUserId(), account); } catch (RemoteException e) { return VirtualRuntime.crash(e); } @@ -186,7 +174,7 @@ public boolean removeAccountExplicitly(Account account) { public void setUserData(Account account, String key, String value) { try { - getRemote().setUserData(VUserHandle.myUserId(), account, key, value); + getService().setUserData(VUserHandle.myUserId(), account, key, value); } catch (RemoteException e) { e.printStackTrace(); } @@ -194,7 +182,7 @@ public void setUserData(Account account, String key, String value) { public void editProperties(IAccountManagerResponse response, String accountType, boolean expectActivityLaunch) { try { - getRemote().editProperties(VUserHandle.myUserId(), response, accountType, expectActivityLaunch); + getService().editProperties(VUserHandle.myUserId(), response, accountType, expectActivityLaunch); } catch (RemoteException e) { e.printStackTrace(); } @@ -202,7 +190,7 @@ public void editProperties(IAccountManagerResponse response, String accountType, public void getAuthTokenLabel(IAccountManagerResponse response, String accountType, String authTokenType) { try { - getRemote().getAuthTokenLabel(VUserHandle.myUserId(), response, accountType, authTokenType); + getService().getAuthTokenLabel(VUserHandle.myUserId(), response, accountType, authTokenType); } catch (RemoteException e) { e.printStackTrace(); } @@ -210,7 +198,7 @@ public void getAuthTokenLabel(IAccountManagerResponse response, String accountTy public void confirmCredentials(IAccountManagerResponse response, Account account, Bundle options, boolean expectActivityLaunch) { try { - getRemote().confirmCredentials(VUserHandle.myUserId(), response, account, options, expectActivityLaunch); + getService().confirmCredentials(VUserHandle.myUserId(), response, account, options, expectActivityLaunch); } catch (RemoteException e) { e.printStackTrace(); } @@ -218,7 +206,7 @@ public void confirmCredentials(IAccountManagerResponse response, Account account public void invalidateAuthToken(String accountType, String authToken) { try { - getRemote().invalidateAuthToken(VUserHandle.myUserId(), accountType, authToken); + getService().invalidateAuthToken(VUserHandle.myUserId(), accountType, authToken); } catch (RemoteException e) { e.printStackTrace(); } @@ -226,7 +214,7 @@ public void invalidateAuthToken(String accountType, String authToken) { public void getAccountsByFeatures(IAccountManagerResponse response, String type, String[] features) { try { - getRemote().getAccountsByFeatures(VUserHandle.myUserId(), response, type, features); + getService().getAccountsByFeatures(VUserHandle.myUserId(), response, type, features); } catch (RemoteException e) { e.printStackTrace(); } @@ -234,7 +222,7 @@ public void getAccountsByFeatures(IAccountManagerResponse response, String type, public void setAuthToken(Account account, String authTokenType, String authToken) { try { - getRemote().setAuthToken(VUserHandle.myUserId(), account, authTokenType, authToken); + getService().setAuthToken(VUserHandle.myUserId(), account, authTokenType, authToken); } catch (RemoteException e) { e.printStackTrace(); } @@ -242,7 +230,7 @@ public void setAuthToken(Account account, String authTokenType, String authToken public Object getPassword(Account account) { try { - return getRemote().getPassword(VUserHandle.myUserId(), account); + return getService().getPassword(VUserHandle.myUserId(), account); } catch (RemoteException e) { return VirtualRuntime.crash(e); } @@ -250,7 +238,7 @@ public Object getPassword(Account account) { public String getUserData(Account account, String key) { try { - return getRemote().getUserData(VUserHandle.myUserId(), account, key); + return getService().getUserData(VUserHandle.myUserId(), account, key); } catch (RemoteException e) { return VirtualRuntime.crash(e); } @@ -265,7 +253,6 @@ public String getUserData(Account account, String key) { *

This method may be called from any thread, but the returned * {@link AccountManagerFuture} must not be used on the main thread. *

- * */ public AccountManagerFuture addAccount(final int userId, final String accountType, final String authTokenType, final String[] requiredFeatures, diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/client/ipc/VActivityManager.java b/VirtualApp/lib/src/main/java/com/lody/virtual/client/ipc/VActivityManager.java index c9ab8e09f..b4a7a537b 100644 --- a/VirtualApp/lib/src/main/java/com/lody/virtual/client/ipc/VActivityManager.java +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/client/ipc/VActivityManager.java @@ -18,6 +18,7 @@ import com.lody.virtual.client.env.VirtualRuntime; import com.lody.virtual.client.hook.secondary.ServiceConnectionDelegate; import com.lody.virtual.helper.compat.ActivityManagerCompat; +import com.lody.virtual.helper.ipcbus.IPCSingleton; import com.lody.virtual.helper.utils.ComponentUtils; import com.lody.virtual.os.VUserHandle; import com.lody.virtual.remote.AppTaskInfo; @@ -25,8 +26,7 @@ import com.lody.virtual.remote.PendingIntentData; import com.lody.virtual.remote.PendingResultData; import com.lody.virtual.remote.VParceledListSlice; -import com.lody.virtual.server.IActivityManager; -import com.lody.virtual.server.interfaces.IProcessObserver; +import com.lody.virtual.server.interfaces.IActivityManager; import java.util.HashMap; import java.util.List; @@ -42,27 +42,14 @@ public class VActivityManager { private static final VActivityManager sAM = new VActivityManager(); private final Map mActivities = new HashMap(6); - private IActivityManager mRemote; + private IPCSingleton singleton = new IPCSingleton<>(IActivityManager.class); public static VActivityManager get() { return sAM; } public IActivityManager getService() { - if (mRemote == null || - (!mRemote.asBinder().isBinderAlive() && !VirtualCore.get().isVAppProcess())) { - synchronized (VActivityManager.class) { - final Object remote = getRemoteInterface(); - mRemote = LocalProxyUtils.genProxy(IActivityManager.class, remote); - } - } - return mRemote; - } - - - private Object getRemoteInterface() { - return IActivityManager.Stub - .asInterface(ServiceManagerNative.getService(ServiceManagerNative.ACTIVITY)); + return singleton.get(); } @@ -331,14 +318,6 @@ public void killApplicationProcess(String procName, int uid) { } } - public void registerProcessObserver(IProcessObserver observer) { - try { - getService().registerProcessObserver(observer); - } catch (RemoteException e) { - e.printStackTrace(); - } - } - public void killAppByPkg(String pkg, int userId) { try { getService().killAppByPkg(pkg, userId); @@ -347,14 +326,6 @@ public void killAppByPkg(String pkg, int userId) { } } - public void unregisterProcessObserver(IProcessObserver observer) { - try { - getService().unregisterProcessObserver(observer); - } catch (RemoteException e) { - e.printStackTrace(); - } - } - public void appDoneExecuting() { try { getService().appDoneExecuting(); diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/client/ipc/VDeviceManager.java b/VirtualApp/lib/src/main/java/com/lody/virtual/client/ipc/VDeviceManager.java index 680037efe..4bd0cb06e 100644 --- a/VirtualApp/lib/src/main/java/com/lody/virtual/client/ipc/VDeviceManager.java +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/client/ipc/VDeviceManager.java @@ -1,12 +1,11 @@ package com.lody.virtual.client.ipc; -import android.os.IBinder; import android.os.RemoteException; -import com.lody.virtual.client.core.VirtualCore; import com.lody.virtual.client.env.VirtualRuntime; +import com.lody.virtual.helper.ipcbus.IPCSingleton; import com.lody.virtual.remote.VDeviceInfo; -import com.lody.virtual.server.IDeviceInfoManager; +import com.lody.virtual.server.interfaces.IDeviceInfoManager; /** * @author Lody @@ -15,7 +14,7 @@ public class VDeviceManager { private static final VDeviceManager sInstance = new VDeviceManager(); - private IDeviceInfoManager mRemote; + private IPCSingleton singleton = new IPCSingleton<>(IDeviceInfoManager.class); public static VDeviceManager get() { @@ -23,27 +22,15 @@ public static VDeviceManager get() { } - public IDeviceInfoManager getRemote() { - if (mRemote == null || - (!mRemote.asBinder().isBinderAlive() && !VirtualCore.get().isVAppProcess())) { - synchronized (this) { - Object remote = getRemoteInterface(); - mRemote = LocalProxyUtils.genProxy(IDeviceInfoManager.class, remote); - } - } - return mRemote; - } - - private Object getRemoteInterface() { - final IBinder binder = ServiceManagerNative.getService(ServiceManagerNative.DEVICE); - return IDeviceInfoManager.Stub.asInterface(binder); + public IDeviceInfoManager getService() { + return singleton.get(); } public VDeviceInfo getDeviceInfo(int userId) { try { - return getRemote().getDeviceInfo(userId); + return getService().getDeviceInfo(userId); } catch (RemoteException e) { return VirtualRuntime.crash(e); } } -} +} \ No newline at end of file diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/client/ipc/VJobScheduler.java b/VirtualApp/lib/src/main/java/com/lody/virtual/client/ipc/VJobScheduler.java index d51de1732..6d89e8506 100644 --- a/VirtualApp/lib/src/main/java/com/lody/virtual/client/ipc/VJobScheduler.java +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/client/ipc/VJobScheduler.java @@ -1,12 +1,12 @@ package com.lody.virtual.client.ipc; import android.app.job.JobInfo; -import android.os.IBinder; +import android.os.Parcelable; import android.os.RemoteException; -import com.lody.virtual.client.core.VirtualCore; import com.lody.virtual.client.env.VirtualRuntime; -import com.lody.virtual.server.IJobScheduler; +import com.lody.virtual.helper.ipcbus.IPCSingleton; +import com.lody.virtual.server.interfaces.IJobService; import java.util.List; @@ -18,31 +18,19 @@ public class VJobScheduler { private static final VJobScheduler sInstance = new VJobScheduler(); - private IJobScheduler mRemote; + private IPCSingleton singleton = new IPCSingleton<>(IJobService.class); public static VJobScheduler get() { return sInstance; } - public IJobScheduler getRemote() { - if (mRemote == null || - (!mRemote.asBinder().isBinderAlive() && !VirtualCore.get().isVAppProcess())) { - synchronized (this) { - Object remote = getRemoteInterface(); - mRemote = LocalProxyUtils.genProxy(IJobScheduler.class, remote); - } - } - return mRemote; - } - - private Object getRemoteInterface() { - final IBinder binder = ServiceManagerNative.getService(ServiceManagerNative.JOB); - return IJobScheduler.Stub.asInterface(binder); + public IJobService getService() { + return singleton.get(); } public int schedule(JobInfo job) { try { - return getRemote().schedule(job); + return getService().schedule(job); } catch (RemoteException e) { return VirtualRuntime.crash(e); } @@ -50,7 +38,7 @@ public int schedule(JobInfo job) { public List getAllPendingJobs() { try { - return getRemote().getAllPendingJobs(); + return getService().getAllPendingJobs(); } catch (RemoteException e) { return VirtualRuntime.crash(e); } @@ -58,7 +46,7 @@ public List getAllPendingJobs() { public void cancelAll() { try { - getRemote().cancelAll(); + getService().cancelAll(); } catch (RemoteException e) { e.printStackTrace(); } @@ -66,9 +54,30 @@ public void cancelAll() { public void cancel(int jobId) { try { - getRemote().cancel(jobId); + getService().cancel(jobId); } catch (RemoteException e) { e.printStackTrace(); } } + + + public JobInfo getPendingJob(int jobId) { + try { + return getService().getPendingJob(jobId); + } catch (RemoteException e) { + return (JobInfo) VirtualRuntime.crash(e); + } + } + + + public int enqueue(JobInfo job, Object workItem) { + if (workItem == null) { + return -1; + } + try { + return getService().enqueue(job, (Parcelable) workItem); + } catch (RemoteException e) { + return (Integer) VirtualRuntime.crash(e); + } + } } diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/client/ipc/VNotificationManager.java b/VirtualApp/lib/src/main/java/com/lody/virtual/client/ipc/VNotificationManager.java index a1402e0c8..19cfb61b1 100644 --- a/VirtualApp/lib/src/main/java/com/lody/virtual/client/ipc/VNotificationManager.java +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/client/ipc/VNotificationManager.java @@ -1,11 +1,11 @@ package com.lody.virtual.client.ipc; import android.app.Notification; -import android.os.IBinder; import android.os.RemoteException; import com.lody.virtual.client.core.VirtualCore; -import com.lody.virtual.server.INotificationManager; +import com.lody.virtual.helper.ipcbus.IPCSingleton; +import com.lody.virtual.server.interfaces.INotificationManager; import com.lody.virtual.server.notification.NotificationCompat; /** @@ -14,7 +14,7 @@ public class VNotificationManager { private static final VNotificationManager sInstance = new VNotificationManager(); private final NotificationCompat mNotificationCompat; - private INotificationManager mRemote; + private IPCSingleton singleton = new IPCSingleton<>(INotificationManager.class); private VNotificationManager() { mNotificationCompat = NotificationCompat.create(); @@ -25,18 +25,11 @@ public static VNotificationManager get() { } public INotificationManager getService() { - if (mRemote == null || - (!mRemote.asBinder().isBinderAlive() && !VirtualCore.get().isVAppProcess())) { - synchronized (VNotificationManager.class) { - final IBinder pmBinder = ServiceManagerNative.getService(ServiceManagerNative.NOTIFICATION); - mRemote = INotificationManager.Stub.asInterface(pmBinder); - } - } - return mRemote; + return singleton.get(); } public boolean dealNotification(int id, Notification notification, String packageName) { - if(notification == null)return false; + if (notification == null) return false; return VirtualCore.get().getHostPkg().equals(packageName) || mNotificationCompat.dealNotification(id, notification, packageName); } diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/client/ipc/VPackageManager.java b/VirtualApp/lib/src/main/java/com/lody/virtual/client/ipc/VPackageManager.java index 317b0180e..2bff2d514 100644 --- a/VirtualApp/lib/src/main/java/com/lody/virtual/client/ipc/VPackageManager.java +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/client/ipc/VPackageManager.java @@ -10,13 +10,12 @@ import android.content.pm.ProviderInfo; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; -import android.os.IBinder; import android.os.RemoteException; -import com.lody.virtual.client.core.VirtualCore; import com.lody.virtual.client.env.VirtualRuntime; +import com.lody.virtual.helper.ipcbus.IPCSingleton; import com.lody.virtual.server.IPackageInstaller; -import com.lody.virtual.server.IPackageManager; +import com.lody.virtual.server.interfaces.IPackageManager; import java.util.List; @@ -26,31 +25,19 @@ public class VPackageManager { private static final VPackageManager sMgr = new VPackageManager(); - private IPackageManager mRemote; + private IPCSingleton singleton = new IPCSingleton<>(IPackageManager.class); public static VPackageManager get() { return sMgr; } - public IPackageManager getInterface() { - if (mRemote == null || - (!mRemote.asBinder().isBinderAlive() && !VirtualCore.get().isVAppProcess())) { - synchronized (VPackageManager.class) { - Object remote = getRemoteInterface(); - mRemote = LocalProxyUtils.genProxy(IPackageManager.class, remote); - } - } - return mRemote; - } - - private Object getRemoteInterface() { - final IBinder pmBinder = ServiceManagerNative.getService(ServiceManagerNative.PACKAGE); - return IPackageManager.Stub.asInterface(pmBinder); + public IPackageManager getService() { + return singleton.get(); } public int checkPermission(String permName, String pkgName, int userId) { try { - return getInterface().checkPermission(permName, pkgName, userId); + return getService().checkPermission(permName, pkgName, userId); } catch (RemoteException e) { return VirtualRuntime.crash(e); } @@ -58,7 +45,7 @@ public int checkPermission(String permName, String pkgName, int userId) { public ResolveInfo resolveService(Intent intent, String resolvedType, int flags, int userId) { try { - return getInterface().resolveService(intent, resolvedType, flags, userId); + return getService().resolveService(intent, resolvedType, flags, userId); } catch (RemoteException e) { return VirtualRuntime.crash(e); } @@ -66,7 +53,7 @@ public ResolveInfo resolveService(Intent intent, String resolvedType, int flags, public PermissionGroupInfo getPermissionGroupInfo(String name, int flags) { try { - return getInterface().getPermissionGroupInfo(name, flags); + return getService().getPermissionGroupInfo(name, flags); } catch (RemoteException e) { return VirtualRuntime.crash(e); } @@ -75,7 +62,7 @@ public PermissionGroupInfo getPermissionGroupInfo(String name, int flags) { public List getInstalledApplications(int flags, int userId) { try { // noinspection unchecked - return getInterface().getInstalledApplications(flags, userId).getList(); + return getService().getInstalledApplications(flags, userId).getList(); } catch (RemoteException e) { return VirtualRuntime.crash(e); } @@ -83,7 +70,7 @@ public List getInstalledApplications(int flags, int userId) { public PackageInfo getPackageInfo(String packageName, int flags, int userId) { try { - return getInterface().getPackageInfo(packageName, flags, userId); + return getService().getPackageInfo(packageName, flags, userId); } catch (RemoteException e) { return VirtualRuntime.crash(e); } @@ -91,7 +78,7 @@ public PackageInfo getPackageInfo(String packageName, int flags, int userId) { public ResolveInfo resolveIntent(Intent intent, String resolvedType, int flags, int userId) { try { - return getInterface().resolveIntent(intent, resolvedType, flags, userId); + return getService().resolveIntent(intent, resolvedType, flags, userId); } catch (RemoteException e) { return VirtualRuntime.crash(e); } @@ -99,7 +86,7 @@ public ResolveInfo resolveIntent(Intent intent, String resolvedType, int flags, public List queryIntentContentProviders(Intent intent, String resolvedType, int flags, int userId) { try { - return getInterface().queryIntentContentProviders(intent, resolvedType, flags, userId); + return getService().queryIntentContentProviders(intent, resolvedType, flags, userId); } catch (RemoteException e) { return VirtualRuntime.crash(e); } @@ -107,7 +94,7 @@ public List queryIntentContentProviders(Intent intent, String resol public ActivityInfo getReceiverInfo(ComponentName componentName, int flags, int userId) { try { - return getInterface().getReceiverInfo(componentName, flags, userId); + return getService().getReceiverInfo(componentName, flags, userId); } catch (RemoteException e) { return VirtualRuntime.crash(e); } @@ -115,7 +102,7 @@ public ActivityInfo getReceiverInfo(ComponentName componentName, int flags, int public List getInstalledPackages(int flags, int userId) { try { - return getInterface().getInstalledPackages(flags, userId).getList(); + return getService().getInstalledPackages(flags, userId).getList(); } catch (RemoteException e) { return VirtualRuntime.crash(e); } @@ -123,7 +110,7 @@ public List getInstalledPackages(int flags, int userId) { public List queryPermissionsByGroup(String group, int flags) { try { - return getInterface().queryPermissionsByGroup(group, flags); + return getService().queryPermissionsByGroup(group, flags); } catch (RemoteException e) { return VirtualRuntime.crash(e); } @@ -131,7 +118,7 @@ public List queryPermissionsByGroup(String group, int flags) { public PermissionInfo getPermissionInfo(String name, int flags) { try { - return getInterface().getPermissionInfo(name, flags); + return getService().getPermissionInfo(name, flags); } catch (RemoteException e) { return VirtualRuntime.crash(e); } @@ -139,7 +126,7 @@ public PermissionInfo getPermissionInfo(String name, int flags) { public ActivityInfo getActivityInfo(ComponentName componentName, int flags, int userId) { try { - return getInterface().getActivityInfo(componentName, flags, userId); + return getService().getActivityInfo(componentName, flags, userId); } catch (RemoteException e) { return VirtualRuntime.crash(e); } @@ -147,7 +134,7 @@ public ActivityInfo getActivityInfo(ComponentName componentName, int flags, int public List queryIntentReceivers(Intent intent, String resolvedType, int flags, int userId) { try { - return getInterface().queryIntentReceivers(intent, resolvedType, flags, userId); + return getService().queryIntentReceivers(intent, resolvedType, flags, userId); } catch (RemoteException e) { return VirtualRuntime.crash(e); } @@ -155,7 +142,7 @@ public List queryIntentReceivers(Intent intent, String resolvedType public List getAllPermissionGroups(int flags) { try { - return getInterface().getAllPermissionGroups(flags); + return getService().getAllPermissionGroups(flags); } catch (RemoteException e) { return VirtualRuntime.crash(e); } @@ -163,7 +150,7 @@ public List getAllPermissionGroups(int flags) { public List queryIntentActivities(Intent intent, String resolvedType, int flags, int userId) { try { - return getInterface().queryIntentActivities(intent, resolvedType, flags, userId); + return getService().queryIntentActivities(intent, resolvedType, flags, userId); } catch (RemoteException e) { return VirtualRuntime.crash(e); } @@ -171,7 +158,7 @@ public List queryIntentActivities(Intent intent, String resolvedTyp public List queryIntentServices(Intent intent, String resolvedType, int flags, int userId) { try { - return getInterface().queryIntentServices(intent, resolvedType, flags, userId); + return getService().queryIntentServices(intent, resolvedType, flags, userId); } catch (RemoteException e) { return VirtualRuntime.crash(e); } @@ -179,7 +166,7 @@ public List queryIntentServices(Intent intent, String resolvedType, public ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) { try { - return getInterface().getApplicationInfo(packageName, flags, userId); + return getService().getApplicationInfo(packageName, flags, userId); } catch (RemoteException e) { return VirtualRuntime.crash(e); } @@ -187,7 +174,7 @@ public ApplicationInfo getApplicationInfo(String packageName, int flags, int use public ProviderInfo resolveContentProvider(String name, int flags, int userId) { try { - return getInterface().resolveContentProvider(name, flags, userId); + return getService().resolveContentProvider(name, flags, userId); } catch (RemoteException e) { return VirtualRuntime.crash(e); } @@ -195,7 +182,7 @@ public ProviderInfo resolveContentProvider(String name, int flags, int userId) { public ServiceInfo getServiceInfo(ComponentName componentName, int flags, int userId) { try { - return getInterface().getServiceInfo(componentName, flags, userId); + return getService().getServiceInfo(componentName, flags, userId); } catch (RemoteException e) { return VirtualRuntime.crash(e); } @@ -203,7 +190,7 @@ public ServiceInfo getServiceInfo(ComponentName componentName, int flags, int us public ProviderInfo getProviderInfo(ComponentName componentName, int flags, int userId) { try { - return getInterface().getProviderInfo(componentName, flags, userId); + return getService().getProviderInfo(componentName, flags, userId); } catch (RemoteException e) { return VirtualRuntime.crash(e); } @@ -211,7 +198,7 @@ public ProviderInfo getProviderInfo(ComponentName componentName, int flags, int public boolean activitySupportsIntent(ComponentName component, Intent intent, String resolvedType) { try { - return getInterface().activitySupportsIntent(component, intent, resolvedType); + return getService().activitySupportsIntent(component, intent, resolvedType); } catch (RemoteException e) { return VirtualRuntime.crash(e); } @@ -220,7 +207,7 @@ public boolean activitySupportsIntent(ComponentName component, Intent intent, St public List queryContentProviders(String processName, int uid, int flags) { try { // noinspection unchecked - return getInterface().queryContentProviders(processName, uid, flags).getList(); + return getService().queryContentProviders(processName, uid, flags).getList(); } catch (RemoteException e) { return VirtualRuntime.crash(e); } @@ -228,7 +215,7 @@ public List queryContentProviders(String processName, int uid, int public List querySharedPackages(String packageName) { try { - return getInterface().querySharedPackages(packageName); + return getService().querySharedPackages(packageName); } catch (RemoteException e) { return VirtualRuntime.crash(e); } @@ -236,7 +223,7 @@ public List querySharedPackages(String packageName) { public String[] getPackagesForUid(int uid) { try { - return getInterface().getPackagesForUid(uid); + return getService().getPackagesForUid(uid); } catch (RemoteException e) { return VirtualRuntime.crash(e); } @@ -244,7 +231,7 @@ public String[] getPackagesForUid(int uid) { public int getPackageUid(String packageName, int userId) { try { - return getInterface().getPackageUid(packageName, userId); + return getService().getPackageUid(packageName, userId); } catch (RemoteException e) { return VirtualRuntime.crash(e); } @@ -252,7 +239,7 @@ public int getPackageUid(String packageName, int userId) { public String getNameForUid(int uid) { try { - return getInterface().getNameForUid(uid); + return getService().getNameForUid(uid); } catch (RemoteException e) { return VirtualRuntime.crash(e); } @@ -261,7 +248,7 @@ public String getNameForUid(int uid) { public IPackageInstaller getPackageInstaller() { try { - return getInterface().getPackageInstaller(); + return IPackageInstaller.Stub.asInterface(getService().getPackageInstaller()); } catch (RemoteException e) { return VirtualRuntime.crash(e); } diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/client/ipc/VirtualLocationManager.java b/VirtualApp/lib/src/main/java/com/lody/virtual/client/ipc/VirtualLocationManager.java index e9e5393f9..98160ffce 100644 --- a/VirtualApp/lib/src/main/java/com/lody/virtual/client/ipc/VirtualLocationManager.java +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/client/ipc/VirtualLocationManager.java @@ -1,14 +1,13 @@ package com.lody.virtual.client.ipc; -import android.os.IBinder; import android.os.RemoteException; -import com.lody.virtual.client.core.VirtualCore; import com.lody.virtual.client.env.VirtualRuntime; import com.lody.virtual.client.hook.base.MethodProxy; +import com.lody.virtual.helper.ipcbus.IPCSingleton; import com.lody.virtual.remote.vloc.VCell; import com.lody.virtual.remote.vloc.VLocation; -import com.lody.virtual.server.IVirtualLocationManager; +import com.lody.virtual.server.interfaces.IVirtualLocationManager; import java.util.List; @@ -19,7 +18,7 @@ public class VirtualLocationManager { private static final VirtualLocationManager sInstance = new VirtualLocationManager(); - private IVirtualLocationManager mRemote; + private IPCSingleton singleton = new IPCSingleton<>(IVirtualLocationManager.class); public static final int MODE_CLOSE = 0; public static final int MODE_USE_GLOBAL = 1; @@ -31,25 +30,14 @@ public static VirtualLocationManager get() { } - public IVirtualLocationManager getRemote() { - if (mRemote == null || - (!mRemote.asBinder().isBinderAlive() && !VirtualCore.get().isVAppProcess())) { - synchronized (this) { - Object remote = getRemoteInterface(); - mRemote = LocalProxyUtils.genProxy(IVirtualLocationManager.class, remote); - } - } - return mRemote; + public IVirtualLocationManager getService() { + return singleton.get(); } - private Object getRemoteInterface() { - final IBinder binder = ServiceManagerNative.getService(ServiceManagerNative.VIRTUAL_LOC); - return IVirtualLocationManager.Stub.asInterface(binder); - } public int getMode(int userId, String pkg) { try { - return getRemote().getMode(userId, pkg); + return getService().getMode(userId, pkg); } catch (RemoteException e) { return VirtualRuntime.crash(e); } @@ -61,7 +49,7 @@ public int getMode() { public void setMode(int userId, String pkg, int mode) { try { - getRemote().setMode(userId, pkg, mode); + getService().setMode(userId, pkg, mode); } catch (RemoteException e) { VirtualRuntime.crash(e); } @@ -69,7 +57,7 @@ public void setMode(int userId, String pkg, int mode) { public void setCell(int userId, String pkg, VCell cell) { try { - getRemote().setCell(userId, pkg, cell); + getService().setCell(userId, pkg, cell); } catch (RemoteException e) { VirtualRuntime.crash(e); } @@ -77,7 +65,7 @@ public void setCell(int userId, String pkg, VCell cell) { public void setAllCell(int userId, String pkg, List cell) { try { - getRemote().setAllCell(userId, pkg, cell); + getService().setAllCell(userId, pkg, cell); } catch (RemoteException e) { VirtualRuntime.crash(e); } @@ -85,7 +73,7 @@ public void setAllCell(int userId, String pkg, List cell) { public void setNeighboringCell(int userId, String pkg, List cell) { try { - getRemote().setNeighboringCell(userId, pkg, cell); + getService().setNeighboringCell(userId, pkg, cell); } catch (RemoteException e) { VirtualRuntime.crash(e); } @@ -93,7 +81,7 @@ public void setNeighboringCell(int userId, String pkg, List cell) { public VCell getCell(int userId, String pkg) { try { - return getRemote().getCell(userId, pkg); + return getService().getCell(userId, pkg); } catch (RemoteException e) { return VirtualRuntime.crash(e); } @@ -101,7 +89,7 @@ public VCell getCell(int userId, String pkg) { public List getAllCell(int userId, String pkg) { try { - return getRemote().getAllCell(userId, pkg); + return getService().getAllCell(userId, pkg); } catch (RemoteException e) { return VirtualRuntime.crash(e); } @@ -109,7 +97,7 @@ public List getAllCell(int userId, String pkg) { public List getNeighboringCell(int userId, String pkg) { try { - return getRemote().getNeighboringCell(userId, pkg); + return getService().getNeighboringCell(userId, pkg); } catch (RemoteException e) { return VirtualRuntime.crash(e); } @@ -118,7 +106,7 @@ public List getNeighboringCell(int userId, String pkg) { public void setGlobalCell(VCell cell) { try { - getRemote().setGlobalCell(cell); + getService().setGlobalCell(cell); } catch (RemoteException e) { VirtualRuntime.crash(e); } @@ -126,7 +114,7 @@ public void setGlobalCell(VCell cell) { public void setGlobalAllCell(List cell) { try { - getRemote().setGlobalAllCell(cell); + getService().setGlobalAllCell(cell); } catch (RemoteException e) { VirtualRuntime.crash(e); } @@ -134,7 +122,7 @@ public void setGlobalAllCell(List cell) { public void setGlobalNeighboringCell(List cell) { try { - getRemote().setGlobalNeighboringCell(cell); + getService().setGlobalNeighboringCell(cell); } catch (RemoteException e) { VirtualRuntime.crash(e); } @@ -142,7 +130,7 @@ public void setGlobalNeighboringCell(List cell) { public void setLocation(int userId, String pkg, VLocation loc) { try { - getRemote().setLocation(userId, pkg, loc); + getService().setLocation(userId, pkg, loc); } catch (RemoteException e) { VirtualRuntime.crash(e); } @@ -150,7 +138,7 @@ public void setLocation(int userId, String pkg, VLocation loc) { public VLocation getLocation(int userId, String pkg) { try { - return getRemote().getLocation(userId, pkg); + return getService().getLocation(userId, pkg); } catch (RemoteException e) { return VirtualRuntime.crash(e); } @@ -162,7 +150,7 @@ public VLocation getLocation() { public void setGlobalLocation(VLocation loc) { try { - getRemote().setGlobalLocation(loc); + getService().setGlobalLocation(loc); } catch (RemoteException e) { VirtualRuntime.crash(e); } @@ -170,7 +158,7 @@ public void setGlobalLocation(VLocation loc) { public VLocation getGlobalLocation() { try { - return getRemote().getGlobalLocation(); + return getService().getGlobalLocation(); } catch (RemoteException e) { return VirtualRuntime.crash(e); } diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/client/ipc/VirtualStorageManager.java b/VirtualApp/lib/src/main/java/com/lody/virtual/client/ipc/VirtualStorageManager.java index 58f8844ec..81d7b6b1e 100644 --- a/VirtualApp/lib/src/main/java/com/lody/virtual/client/ipc/VirtualStorageManager.java +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/client/ipc/VirtualStorageManager.java @@ -1,12 +1,11 @@ package com.lody.virtual.client.ipc; -import android.os.IBinder; import android.os.RemoteException; -import com.lody.virtual.client.core.VirtualCore; import com.lody.virtual.client.env.VirtualRuntime; -import com.lody.virtual.server.IVirtualStorageService; +import com.lody.virtual.helper.ipcbus.IPCSingleton; +import com.lody.virtual.server.interfaces.IVirtualStorageService; /** * @author Lody @@ -15,7 +14,7 @@ public class VirtualStorageManager { private static final VirtualStorageManager sInstance = new VirtualStorageManager(); - private IVirtualStorageService mRemote; + private IPCSingleton singleton = new IPCSingleton<>(IVirtualStorageService.class); public static VirtualStorageManager get() { @@ -24,19 +23,7 @@ public static VirtualStorageManager get() { public IVirtualStorageService getRemote() { - if (mRemote == null || - (!mRemote.asBinder().isBinderAlive() && !VirtualCore.get().isVAppProcess())) { - synchronized (this) { - Object remote = getRemoteInterface(); - mRemote = LocalProxyUtils.genProxy(IVirtualStorageService.class, remote); - } - } - return mRemote; - } - - private Object getRemoteInterface() { - final IBinder binder = ServiceManagerNative.getService(ServiceManagerNative.VS); - return IVirtualStorageService.Stub.asInterface(binder); + return singleton.get(); } public void setVirtualStorage(String packageName, int userId, String vsPath) { diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/client/stub/StubJob.java b/VirtualApp/lib/src/main/java/com/lody/virtual/client/stub/StubJob.java index 18d87075d..113e054eb 100644 --- a/VirtualApp/lib/src/main/java/com/lody/virtual/client/stub/StubJob.java +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/client/stub/StubJob.java @@ -12,6 +12,7 @@ import android.os.Build; import android.os.IBinder; import android.os.RemoteException; +import android.util.Log; import com.lody.virtual.client.core.InvocationStubManager; import com.lody.virtual.client.hook.proxies.am.ActivityManagerStub; @@ -109,6 +110,8 @@ public void onCreate() { super.onCreate(); InvocationStubManager.getInstance().checkEnv(ActivityManagerStub.class); mScheduler = (JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE); + + Log.d("Q_M", "StubJob-->onCreate"); } @Override diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/client/stub/VASettings.java b/VirtualApp/lib/src/main/java/com/lody/virtual/client/stub/VASettings.java index 8c662c38d..46bc8717e 100644 --- a/VirtualApp/lib/src/main/java/com/lody/virtual/client/stub/VASettings.java +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/client/stub/VASettings.java @@ -20,6 +20,16 @@ public class VASettings { "com.google.android.gms" }; + /** + * 是否禁止插件应用直接调用返回桌面的 intent + *

+ * Intent home = new Intent(Intent.ACTION_MAIN); + * home.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + * home.addCategory(Intent.CATEGORY_HOME); + * startActivity(home); + */ + public static boolean INTERCEPT_BACK_HOME = true; + /** * If enable, * App run in VA will allowed to create shortcut on your Desktop. diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/helper/ipcbus/IPCBus.java b/VirtualApp/lib/src/main/java/com/lody/virtual/helper/ipcbus/IPCBus.java new file mode 100644 index 000000000..aa066b410 --- /dev/null +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/helper/ipcbus/IPCBus.java @@ -0,0 +1,42 @@ +package com.lody.virtual.helper.ipcbus; + + +import android.os.IBinder; + +import java.lang.reflect.Proxy; + +/** + * @author Lody + */ +public class IPCBus { + + private static IServerCache sCache; + + public static void initialize(IServerCache cache) { + sCache = cache; + } + + private static void checkInitialized() { + if (sCache == null) { + throw new IllegalStateException("please call initialize() at first."); + } + } + + public static void register(Class interfaceClass, Object server) { + checkInitialized(); + ServerInterface serverInterface = new ServerInterface(interfaceClass); + TransformBinder binder = new TransformBinder(serverInterface, server); + sCache.join(serverInterface.getInterfaceName(), binder); + } + + public static T get(Class interfaceClass) { + checkInitialized(); + ServerInterface serverInterface = new ServerInterface(interfaceClass); + IBinder binder = sCache.query(serverInterface.getInterfaceName()); + if (binder == null) { + return null; + } + //noinspection unchecked + return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class[]{interfaceClass}, new IPCInvocationBridge(serverInterface, binder)); + } +} diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/helper/ipcbus/IPCInvocationBridge.java b/VirtualApp/lib/src/main/java/com/lody/virtual/helper/ipcbus/IPCInvocationBridge.java new file mode 100644 index 000000000..cff24a10f --- /dev/null +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/helper/ipcbus/IPCInvocationBridge.java @@ -0,0 +1,29 @@ +package com.lody.virtual.helper.ipcbus; + +import android.os.IBinder; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; + +/** + * @author Lody + */ +public class IPCInvocationBridge implements InvocationHandler { + + private ServerInterface serverInterface; + private IBinder binder; + + public IPCInvocationBridge(ServerInterface serverInterface, IBinder binder) { + this.serverInterface = serverInterface; + this.binder = binder; + } + + @Override + public Object invoke(Object o, Method method, Object[] args) throws Throwable { + IPCMethod ipcMethod = serverInterface.getIPCMethod(method); + if (ipcMethod == null) { + throw new IllegalStateException("Can not found the ipc method : " + method.getDeclaringClass().getName() + "@" + method.getName()); + } + return ipcMethod.callRemote(binder, args); + } +} diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/helper/ipcbus/IPCMethod.java b/VirtualApp/lib/src/main/java/com/lody/virtual/helper/ipcbus/IPCMethod.java new file mode 100644 index 000000000..12ebcde04 --- /dev/null +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/helper/ipcbus/IPCMethod.java @@ -0,0 +1,174 @@ +package com.lody.virtual.helper.ipcbus; + +import android.os.Binder; +import android.os.IBinder; +import android.os.IInterface; +import android.os.Parcel; +import android.os.Parcelable; +import android.os.RemoteException; + +import java.lang.reflect.Array; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +/** + * @author Lody + */ +public class IPCMethod { + + private int code; + private Method method; + private String interfaceName; + private MethodParamConverter[] converters; + private MethodParamConverter resultConverter; + + + public IPCMethod(int code, Method method, String interfaceName) { + this.code = code; + this.method = method; + this.interfaceName = interfaceName; + Class[] parameterTypes = method.getParameterTypes(); + converters = new MethodParamConverter[parameterTypes.length]; + for (int i = 0; i < parameterTypes.length; i++) { + if (isAidlParam(parameterTypes[i])) { + converters[i] = new AidlParamConverter(parameterTypes[i]); + } + } + Class returnType = method.getReturnType(); + if (isAidlParam(returnType)) { + resultConverter = new AidlParamConverter(returnType); + } + } + + private boolean isAidlParam(Class type) { + return type.isInterface() && IInterface.class.isAssignableFrom(type); + } + + + public String getInterfaceName() { + return interfaceName; + } + + public Method getMethod() { + return method; + } + + public void handleTransact(Object server, Parcel data, Parcel reply) { + data.enforceInterface(interfaceName); + Object[] parameters = data.readArray(getClass().getClassLoader()); + if (parameters != null && parameters.length > 0) { + for (int i = 0; i < parameters.length; i++) { + if (converters[i] != null) { + parameters[i] = converters[i].convert(parameters[i]); + } + } + } + try { + Object res = method.invoke(server, parameters); + reply.writeNoException(); + reply.writeValue(res); + } catch (IllegalAccessException e) { + e.printStackTrace(); + reply.writeException(e); + } catch (InvocationTargetException e) { + e.printStackTrace(); + reply.writeException(e); + } + } + + private static Method findAsInterfaceMethod(Class type) { + for (Class innerClass : type.getDeclaredClasses()) { + // public static class Stub extends Binder implements IType + if (Modifier.isStatic(innerClass.getModifiers()) + && Binder.class.isAssignableFrom(innerClass) + && type.isAssignableFrom(innerClass)) { + // public static IType asInterface(android.os.IBinder obj) + for (Method method : innerClass.getDeclaredMethods()) { + if (Modifier.isStatic(method.getModifiers())) { + Class[] types = method.getParameterTypes(); + if (types.length == 1 && types[0] == IBinder.class) { + return method; + } + } + } + } + } + throw new IllegalStateException("Can not found the " + type.getName() + "$Stub.asInterface method."); + } + + public Object callRemote(IBinder server, Object[] args) throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + Object result; + try { + data.writeInterfaceToken(interfaceName); + data.writeArray(args); + server.transact(code, data, reply, 0); + reply.readException(); + result = readValue(reply); + if (resultConverter != null) { + result = resultConverter.convert(result); + } + } finally { + data.recycle(); + reply.recycle(); + } + return result; + } + + private Object readValue(Parcel replay) { + Object result = replay.readValue(getClass().getClassLoader()); + if (result instanceof Parcelable[]) { + Parcelable[] parcelables = (Parcelable[]) result; + Object[] results = (Object[]) Array.newInstance(method.getReturnType().getComponentType(), parcelables.length); + System.arraycopy(parcelables, 0, results, 0, results.length); + return results; + } + return result; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + IPCMethod ipcMethod = (IPCMethod) o; + + return method != null ? method.equals(ipcMethod.method) : ipcMethod.method == null; + } + + public interface MethodParamConverter { + Object convert(Object param); + } + + private class AidlParamConverter implements MethodParamConverter { + + private Method asInterfaceMethod; + private Class type; + + AidlParamConverter(Class type) { + this.type = type; + } + + @Override + public Object convert(Object param) { + if (param != null) { + if (asInterfaceMethod == null) { + synchronized (this) { + if (asInterfaceMethod == null) { + asInterfaceMethod = findAsInterfaceMethod(type); + } + } + } + try { + return asInterfaceMethod.invoke(null, param); + } catch (Throwable e) { + throw new IllegalStateException(e); + } + } + return null; + } + } + +} diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/helper/ipcbus/IPCSingleton.java b/VirtualApp/lib/src/main/java/com/lody/virtual/helper/ipcbus/IPCSingleton.java new file mode 100644 index 000000000..56c3f00c1 --- /dev/null +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/helper/ipcbus/IPCSingleton.java @@ -0,0 +1,26 @@ +package com.lody.virtual.helper.ipcbus; + +/** + * @author Lody + */ +public class IPCSingleton { + + private Class ipcClass; + private T instance; + + public IPCSingleton(Class ipcClass) { + this.ipcClass = ipcClass; + } + + public T get() { + if (instance == null) { + synchronized (this) { + if (instance == null) { + instance = IPCBus.get(ipcClass); + } + } + } + return instance; + } + +} diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/helper/ipcbus/IServerCache.java b/VirtualApp/lib/src/main/java/com/lody/virtual/helper/ipcbus/IServerCache.java new file mode 100644 index 000000000..63d3c8cd6 --- /dev/null +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/helper/ipcbus/IServerCache.java @@ -0,0 +1,11 @@ +package com.lody.virtual.helper.ipcbus; + +import android.os.IBinder; + +/** + * @author Lody + */ +public interface IServerCache { + void join(String serverName, IBinder binder); + IBinder query(String serverName); +} diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/helper/ipcbus/ServerInterface.java b/VirtualApp/lib/src/main/java/com/lody/virtual/helper/ipcbus/ServerInterface.java new file mode 100644 index 000000000..103f039cf --- /dev/null +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/helper/ipcbus/ServerInterface.java @@ -0,0 +1,48 @@ +package com.lody.virtual.helper.ipcbus; + +import android.os.Binder; + +import com.lody.virtual.helper.collection.SparseArray; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +/** + * @author Lody + */ +public class ServerInterface { + + private Class interfaceClass; + private final SparseArray codeToInterfaceMethod; + private final Map methodToIPCMethodMap; + + public ServerInterface(Class interfaceClass) { + this.interfaceClass = interfaceClass; + Method[] methods = interfaceClass.getMethods(); + codeToInterfaceMethod = new SparseArray<>(methods.length); + methodToIPCMethodMap = new HashMap<>(methods.length); + for (int i = 0; i < methods.length; i++) { + int code = Binder.FIRST_CALL_TRANSACTION + i; + IPCMethod ipcMethod = new IPCMethod(code, methods[i], interfaceClass.getName()); + codeToInterfaceMethod.put(code, ipcMethod); + methodToIPCMethodMap.put(methods[i], ipcMethod); + } + } + + public Class getInterfaceClass() { + return interfaceClass; + } + + public String getInterfaceName() { + return interfaceClass.getName(); + } + + public IPCMethod getIPCMethod(int code) { + return codeToInterfaceMethod.get(code); + } + + public IPCMethod getIPCMethod(Method method) { + return methodToIPCMethodMap.get(method); + } +} diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/helper/ipcbus/TransformBinder.java b/VirtualApp/lib/src/main/java/com/lody/virtual/helper/ipcbus/TransformBinder.java new file mode 100644 index 000000000..459b786a6 --- /dev/null +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/helper/ipcbus/TransformBinder.java @@ -0,0 +1,38 @@ +package com.lody.virtual.helper.ipcbus; + +import android.os.Binder; +import android.os.Parcel; +import android.os.RemoteException; + + +/** + * @author Lody + */ +public class TransformBinder extends Binder { + + private ServerInterface serverInterface; + private Object server; + + public TransformBinder(ServerInterface serverInterface, Object server) { + this.serverInterface = serverInterface; + this.server = server; + } + + @Override + protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { + if (code == INTERFACE_TRANSACTION) { + reply.writeString(serverInterface.getInterfaceName()); + return true; + } + IPCMethod method = serverInterface.getIPCMethod(code); + if (method != null) { + try { + method.handleTransact(server, data, reply); + } catch (Throwable e) { + e.printStackTrace(); + } + return true; + } + return super.onTransact(code, data, reply, flags); + } +} diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/helper/utils/ComponentUtils.java b/VirtualApp/lib/src/main/java/com/lody/virtual/helper/utils/ComponentUtils.java index c6007143f..91de7c8f2 100644 --- a/VirtualApp/lib/src/main/java/com/lody/virtual/helper/utils/ComponentUtils.java +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/helper/utils/ComponentUtils.java @@ -9,7 +9,15 @@ import com.lody.virtual.client.core.VirtualCore; import com.lody.virtual.client.env.SpecialComponentList; import com.lody.virtual.GmsSupport; +import com.lody.virtual.client.ipc.VActivityManager; +import com.lody.virtual.client.stub.StubPendingActivity; +import com.lody.virtual.client.stub.StubPendingReceiver; +import com.lody.virtual.client.stub.StubPendingService; import com.lody.virtual.helper.compat.ObjectsCompat; +import com.lody.virtual.os.VUserHandle; + +import android.os.IBinder; +import android.os.Parcelable; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE; @@ -127,4 +135,44 @@ public static Intent redirectBroadcastIntent(Intent intent, int userId) { } return newIntent; } + + + public static Intent redirectIntentSender(int type, String creator, Intent intent, IBinder iBinder) { + Intent cloneFilter = intent.cloneFilter(); + switch (type) { + case 1: + cloneFilter.setClass(VirtualCore.get().getContext(), StubPendingReceiver.class); + break; + case 2: + if (VirtualCore.get().resolveActivityInfo(intent, VUserHandle.myUserId()) != null) { + cloneFilter.setClass(VirtualCore.get().getContext(), StubPendingActivity.class); + cloneFilter.setFlags(intent.getFlags()); + if (iBinder != null) { + try { + Parcelable activityForToken = VActivityManager.get().getActivityForToken(iBinder); + if (activityForToken != null) { + cloneFilter.putExtra("_VA_|_caller_", activityForToken); + break; + } + } catch (Throwable th) { + break; + } + } + } + break; + case 4: + if (VirtualCore.get().resolveServiceInfo(intent, VUserHandle.myUserId()) != null) { + cloneFilter.setClass(VirtualCore.get().getContext(), StubPendingService.class); + break; + } + break; + default: + return null; + } + cloneFilter.putExtra("_VA_|_user_id_", VUserHandle.myUserId()); + cloneFilter.putExtra("_VA_|_intent_", intent); + cloneFilter.putExtra("_VA_|_creator_", creator); + cloneFilter.putExtra("_VA_|_from_inner_", true); + return cloneFilter; + } } diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/os/VEnvironment.java b/VirtualApp/lib/src/main/java/com/lody/virtual/os/VEnvironment.java index be1d1ae51..72a5a4ee9 100644 --- a/VirtualApp/lib/src/main/java/com/lody/virtual/os/VEnvironment.java +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/os/VEnvironment.java @@ -4,6 +4,7 @@ import android.os.Build; import com.lody.virtual.client.core.VirtualCore; +import com.lody.virtual.client.env.VirtualRuntime; import com.lody.virtual.helper.utils.FileUtils; import com.lody.virtual.helper.utils.VLog; @@ -116,7 +117,7 @@ public static File getDalvikCacheDirectory() { } public static File getOdexFile(String packageName) { - return new File(DALVIK_CACHE_DIRECTORY, "base.odex"); + return new File(DALVIK_CACHE_DIRECTORY, "data@app@" + packageName + "-1@base.apk@classes.dex"); } public static File getDataAppPackageDirectory(String packageName) { diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/os/VUserManager.java b/VirtualApp/lib/src/main/java/com/lody/virtual/os/VUserManager.java index aeef66ccb..20b6e4537 100644 --- a/VirtualApp/lib/src/main/java/com/lody/virtual/os/VUserManager.java +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/os/VUserManager.java @@ -4,13 +4,11 @@ import android.os.RemoteException; import android.util.Log; -import com.lody.virtual.client.ipc.ServiceManagerNative; -import com.lody.virtual.server.IUserManager; +import com.lody.virtual.helper.ipcbus.IPCBus; +import com.lody.virtual.server.interfaces.IUserManager; import java.util.List; -import static com.lody.virtual.client.ipc.ServiceManagerNative.USER; - /** * Manages users and user details on a multi-user system. */ @@ -108,7 +106,7 @@ public class VUserManager { /** @hide */ public synchronized static VUserManager get() { if (sInstance == null) { - IUserManager remote = IUserManager.Stub.asInterface(ServiceManagerNative.getService(USER)); + IUserManager remote = IPCBus.get(IUserManager.class); sInstance = new VUserManager(remote); } return sInstance; diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/server/BinderProvider.java b/VirtualApp/lib/src/main/java/com/lody/virtual/server/BinderProvider.java index 327ce44a4..76dc4a546 100644 --- a/VirtualApp/lib/src/main/java/com/lody/virtual/server/BinderProvider.java +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/server/BinderProvider.java @@ -11,14 +11,24 @@ import android.os.RemoteException; import com.lody.virtual.client.core.VirtualCore; -import com.lody.virtual.client.ipc.ServiceManagerNative; import com.lody.virtual.client.stub.DaemonService; import com.lody.virtual.helper.compat.BundleCompat; +import com.lody.virtual.helper.ipcbus.IPCBus; import com.lody.virtual.server.accounts.VAccountManagerService; import com.lody.virtual.server.am.BroadcastSystem; import com.lody.virtual.server.am.VActivityManagerService; import com.lody.virtual.server.device.VDeviceManagerService; +import com.lody.virtual.server.interfaces.IAccountManager; +import com.lody.virtual.server.interfaces.IActivityManager; +import com.lody.virtual.server.interfaces.IAppManager; +import com.lody.virtual.server.interfaces.IDeviceInfoManager; +import com.lody.virtual.server.interfaces.IJobService; +import com.lody.virtual.server.interfaces.INotificationManager; +import com.lody.virtual.server.interfaces.IPackageManager; import com.lody.virtual.server.interfaces.IServiceFetcher; +import com.lody.virtual.server.interfaces.IUserManager; +import com.lody.virtual.server.interfaces.IVirtualLocationManager; +import com.lody.virtual.server.interfaces.IVirtualStorageService; import com.lody.virtual.server.job.VJobSchedulerService; import com.lody.virtual.server.location.VirtualLocationService; import com.lody.virtual.server.notification.VNotificationManagerService; @@ -27,6 +37,8 @@ import com.lody.virtual.server.pm.VUserManagerService; import com.lody.virtual.server.vs.VirtualStorageService; +import mirror.android.app.job.IJobScheduler; + /** * @author Lody */ @@ -42,38 +54,36 @@ public boolean onCreate() { return true; } VPackageManagerService.systemReady(); - addService(ServiceManagerNative.PACKAGE, VPackageManagerService.get()); + IPCBus.register(IPackageManager.class, VPackageManagerService.get()); VActivityManagerService.systemReady(context); - addService(ServiceManagerNative.ACTIVITY, VActivityManagerService.get()); - addService(ServiceManagerNative.USER, VUserManagerService.get()); + IPCBus.register(IActivityManager.class, VActivityManagerService.get()); + IPCBus.register(IUserManager.class, VUserManagerService.get()); VAppManagerService.systemReady(); - addService(ServiceManagerNative.APP, VAppManagerService.get()); + IPCBus.register(IAppManager.class, VAppManagerService.get()); BroadcastSystem.attach(VActivityManagerService.get(), VAppManagerService.get()); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - addService(ServiceManagerNative.JOB, VJobSchedulerService.get()); + IPCBus.register(IJobService.class, VJobSchedulerService.get()); } VNotificationManagerService.systemReady(context); - addService(ServiceManagerNative.NOTIFICATION, VNotificationManagerService.get()); + IPCBus.register(INotificationManager.class, VNotificationManagerService.get()); VAppManagerService.get().scanApps(); VAccountManagerService.systemReady(); - addService(ServiceManagerNative.ACCOUNT, VAccountManagerService.get()); - addService(ServiceManagerNative.VS, VirtualStorageService.get()); - addService(ServiceManagerNative.DEVICE, VDeviceManagerService.get()); - addService(ServiceManagerNative.VIRTUAL_LOC, VirtualLocationService.get()); + IPCBus.register(IAccountManager.class, VAccountManagerService.get()); + IPCBus.register(IVirtualStorageService.class, VirtualStorageService.get()); + IPCBus.register(IDeviceInfoManager.class, VDeviceManagerService.get()); + IPCBus.register(IVirtualLocationManager.class, VirtualLocationService.get()); return true; } - - private void addService(String name, IBinder service) { - ServiceCache.addService(name, service); - } - @Override public Bundle call(String method, String arg, Bundle extras) { if ("@".equals(method)) { Bundle bundle = new Bundle(); BundleCompat.putBinder(bundle, "_VA_|_binder_", mServiceFetcher); return bundle; + } + if ("register".equals(method)) { + } return null; } diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/server/accounts/VAccountManagerService.java b/VirtualApp/lib/src/main/java/com/lody/virtual/server/accounts/VAccountManagerService.java index fb37458fb..db74c4ff9 100644 --- a/VirtualApp/lib/src/main/java/com/lody/virtual/server/accounts/VAccountManagerService.java +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/server/accounts/VAccountManagerService.java @@ -34,8 +34,8 @@ import com.lody.virtual.os.VBinder; import com.lody.virtual.os.VEnvironment; import com.lody.virtual.os.VUserHandle; -import com.lody.virtual.server.IAccountManager; import com.lody.virtual.server.am.VActivityManagerService; +import com.lody.virtual.server.interfaces.IAccountManager; import com.lody.virtual.server.pm.VPackageManagerService; import org.xmlpull.v1.XmlPullParser; @@ -62,7 +62,7 @@ /** * @author Lody */ -public class VAccountManagerService extends IAccountManager.Stub { +public class VAccountManagerService implements IAccountManager { private static final AtomicReference sInstance = new AtomicReference<>(); private static final long CHECK_IN_TIME = 30 * 24 * 60 * 1000L; @@ -185,16 +185,6 @@ private List getAccountList(int userId, String type) { } } - @Override - public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { - try { - return super.onTransact(code, data, reply, flags); - } catch (Throwable e) { - e.printStackTrace(); - throw e; - } - } - @Override public final void getAuthToken(final int userId, final IAccountManagerResponse response, final Account account, final String authTokenType, final boolean notifyOnAuthFailure, boolean expectActivityLaunch, final Bundle loginOptions) { if (response == null) { diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/server/am/BroadcastSystem.java b/VirtualApp/lib/src/main/java/com/lody/virtual/server/am/BroadcastSystem.java index d6f701aaf..8d7a98251 100644 --- a/VirtualApp/lib/src/main/java/com/lody/virtual/server/am/BroadcastSystem.java +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/server/am/BroadcastSystem.java @@ -8,18 +8,22 @@ import android.content.pm.ActivityInfo; import android.os.Build; import android.os.Handler; +import android.os.HandlerThread; import android.os.IBinder; +import android.os.Looper; import android.os.Message; import com.lody.virtual.client.core.VirtualCore; import com.lody.virtual.client.env.SpecialComponentList; import com.lody.virtual.helper.collection.ArrayMap; +import com.lody.virtual.helper.utils.Reflect; import com.lody.virtual.helper.utils.VLog; import com.lody.virtual.remote.PendingResultData; import com.lody.virtual.server.pm.PackageSetting; import com.lody.virtual.server.pm.VAppManagerService; import com.lody.virtual.server.pm.parser.VPackage; +import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -61,8 +65,12 @@ private BroadcastSystem(Context context, VActivityManagerService ams, VAppManage this.mContext = context; this.mApp = app; this.mAMS = ams; - mScheduler = new StaticScheduler(); - mTimeoutHandler = new TimeoutHandler(); + HandlerThread broadcastThread = new HandlerThread("BroadcastThread"); + HandlerThread anrThread = new HandlerThread("BroadcastAnrThread"); + broadcastThread.start(); + anrThread.start(); + mScheduler = new StaticScheduler(broadcastThread.getLooper()); + mTimeoutHandler = new TimeoutHandler(anrThread.getLooper()); fuckHuaWeiVerifier(); } @@ -97,7 +105,15 @@ private void fuckHuaWeiVerifier() { if (packageInfo != null) { Object receiverResource = LoadedApkHuaWei.mReceiverResource.get(packageInfo); if (receiverResource != null) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + if (Build.VERSION.SDK_INT >= 26) { + Map> whiteListMap = Reflect.on(receiverResource).get("mWhiteListMap"); + List whiteList = whiteListMap.get(0); + if (whiteList == null) { + whiteList = new ArrayList<>(); + whiteListMap.put(0, whiteList); + } + whiteList.add(mContext.getPackageName()); + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { if (ReceiverResourceN.mWhiteList != null) { List whiteList = ReceiverResourceN.mWhiteList.get(receiverResource); List newWhiteList = new ArrayList<>(); @@ -108,7 +124,6 @@ private void fuckHuaWeiVerifier() { } ReceiverResourceN.mWhiteList.set(receiverResource, newWhiteList); } - } else { if (ReceiverResourceM.mWhiteList != null) { String[] whiteList = ReceiverResourceM.mWhiteList.get(receiverResource); @@ -198,6 +213,9 @@ void broadcastSent(int vuid, ActivityInfo receiverInfo, PendingResultData res) { private static final class StaticScheduler extends Handler { + StaticScheduler(Looper looper) { + super(looper); + } } private static final class BroadcastRecord { @@ -213,6 +231,11 @@ private static final class BroadcastRecord { } private final class TimeoutHandler extends Handler { + + TimeoutHandler(Looper looper) { + super(looper); + } + @Override public void handleMessage(Message msg) { IBinder token = (IBinder) msg.obj; diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/server/am/VActivityManagerService.java b/VirtualApp/lib/src/main/java/com/lody/virtual/server/am/VActivityManagerService.java index a034a5649..e6f720835 100644 --- a/VirtualApp/lib/src/main/java/com/lody/virtual/server/am/VActivityManagerService.java +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/server/am/VActivityManagerService.java @@ -49,7 +49,7 @@ import com.lody.virtual.remote.PendingIntentData; import com.lody.virtual.remote.PendingResultData; import com.lody.virtual.remote.VParceledListSlice; -import com.lody.virtual.server.IActivityManager; +import com.lody.virtual.server.interfaces.IActivityManager; import com.lody.virtual.server.interfaces.IProcessObserver; import com.lody.virtual.server.pm.PackageCacheManager; import com.lody.virtual.server.pm.PackageSetting; @@ -68,12 +68,13 @@ import mirror.android.app.IServiceConnectionO; import static android.os.Process.killProcess; +import static com.lody.virtual.os.VBinder.getCallingPid; import static com.lody.virtual.os.VUserHandle.getUserId; /** * @author Lody */ -public class VActivityManagerService extends IActivityManager.Stub { +public class VActivityManagerService implements IActivityManager { private static final boolean BROADCAST_NOT_STARTED_PKG = false; @@ -233,7 +234,7 @@ private void processDead(ProcessRecord record) { public IBinder acquireProviderClient(int userId, ProviderInfo info) { ProcessRecord callerApp; synchronized (mPidsSelfLocked) { - callerApp = findProcessLocked(VBinder.getCallingPid()); + callerApp = findProcessLocked(getCallingPid()); } if (callerApp == null) { throw new SecurityException("Who are you?"); @@ -263,17 +264,6 @@ public String getCallingPackage(int userId, IBinder token) { return mMainStack.getCallingPackage(userId, token); } - - @Override - public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { - try { - return super.onTransact(code, data, reply, flags); - } catch (Throwable e) { - e.printStackTrace(); - throw e; - } - } - private void addRecord(ServiceRecord r) { mHistory.add(r); } @@ -389,7 +379,7 @@ private void stopServiceCommon(ServiceRecord r, ComponentName className) { // Report to all of the connections that the service is no longer // available. try { - if(Build.VERSION.SDK_INT >= 26) { + if (Build.VERSION.SDK_INT >= 26) { IServiceConnectionO.connected.call(connection, className, null, true); } else { connection.connected(className, null); @@ -560,7 +550,7 @@ public void publishService(IBinder token, Intent intent, IBinder service, int us } } - private void connectService(IServiceConnection conn, ComponentName component, ServiceRecord.IntentBindRecord r,boolean dead) { + private void connectService(IServiceConnection conn, ComponentName component, ServiceRecord.IntentBindRecord r, boolean dead) { try { BinderDelegateService delegateService = new BinderDelegateService(component, r.binder); if (Build.VERSION.SDK_INT >= 26) { @@ -718,7 +708,7 @@ private void attachClient(int pid, final IBinder clientBinder) { } try { final ProcessRecord record = app; - clientBinder.linkToDeath(new DeathRecipient() { + clientBinder.linkToDeath(new IBinder.DeathRecipient() { @Override public void binderDied() { clientBinder.unlinkToDeath(this, 0); @@ -941,16 +931,6 @@ public void dump() { } - @Override - public void registerProcessObserver(IProcessObserver observer) { - - } - - @Override - public void unregisterProcessObserver(IProcessObserver observer) { - - } - @Override public String getInitialPackage(int pid) { synchronized (mPidsSelfLocked) { @@ -970,7 +950,7 @@ public void handleApplicationCrash() { @Override public void appDoneExecuting() { synchronized (mPidsSelfLocked) { - ProcessRecord r = mPidsSelfLocked.get(VBinder.getCallingPid()); + ProcessRecord r = mPidsSelfLocked.get(getCallingPid()); if (r != null) { r.doneExecuting = true; r.lock.open(); @@ -1118,7 +1098,7 @@ public void broadcastFinish(PendingResultData res) { } @Override - public void notifyBadgerChange(BadgerInfo info) throws RemoteException { + public void notifyBadgerChange(BadgerInfo info) { Intent intent = new Intent(VASettings.ACTION_BADGER_CHANGE); intent.putExtra("userId", info.userId); intent.putExtra("packageName", info.packageName); diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/server/device/VDeviceManagerService.java b/VirtualApp/lib/src/main/java/com/lody/virtual/server/device/VDeviceManagerService.java index 326fa8bee..8064737fb 100644 --- a/VirtualApp/lib/src/main/java/com/lody/virtual/server/device/VDeviceManagerService.java +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/server/device/VDeviceManagerService.java @@ -6,7 +6,7 @@ import com.lody.virtual.helper.collection.SparseArray; import com.lody.virtual.remote.VDeviceInfo; -import com.lody.virtual.server.IDeviceInfoManager; +import com.lody.virtual.server.interfaces.IDeviceInfoManager; import java.util.ArrayList; import java.util.Collections; @@ -17,7 +17,7 @@ * @author Lody */ -public class VDeviceManagerService extends IDeviceInfoManager.Stub { +public class VDeviceManagerService implements IDeviceInfoManager { private static VDeviceManagerService sInstance = new VDeviceManagerService(); private final SparseArray mDeviceInfos = new SparseArray<>(); @@ -53,7 +53,7 @@ private void addDeviceInfoToPool(VDeviceInfo info) { } @Override - public VDeviceInfo getDeviceInfo(int userId) throws RemoteException { + public VDeviceInfo getDeviceInfo(int userId) { VDeviceInfo info; synchronized (mDeviceInfos) { info = mDeviceInfos.get(userId); @@ -67,7 +67,7 @@ public VDeviceInfo getDeviceInfo(int userId) throws RemoteException { } @Override - public void updateDeviceInfo(int userId, VDeviceInfo info) throws RemoteException { + public void updateDeviceInfo(int userId, VDeviceInfo info) { synchronized (mDeviceInfos) { if (info != null) { mDeviceInfos.put(userId, info); diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/server/interfaces/IAccountManager.java b/VirtualApp/lib/src/main/java/com/lody/virtual/server/interfaces/IAccountManager.java new file mode 100644 index 000000000..6a2d85871 --- /dev/null +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/server/interfaces/IAccountManager.java @@ -0,0 +1,61 @@ +package com.lody.virtual.server.interfaces; + +import android.accounts.Account; +import android.accounts.AuthenticatorDescription; +import android.accounts.IAccountManagerResponse; +import android.os.Bundle; +import android.os.RemoteException; + +/** + * @author Lody + */ +public interface IAccountManager { + + AuthenticatorDescription[] getAuthenticatorTypes(int userId) throws RemoteException; + + void getAccountsByFeatures(int userId, IAccountManagerResponse response, String type, String[] features) throws RemoteException; + + String getPreviousName(int userId, Account account) throws RemoteException; + + Account[] getAccounts(int userId, String type) throws RemoteException; + + void getAuthToken(int userId, IAccountManagerResponse response, Account account, String authTokenType, boolean notifyOnAuthFailure, boolean expectActivityLaunch, Bundle loginOptions) throws RemoteException; + + void setPassword(int userId, Account account, String password) throws RemoteException; + + void setAuthToken(int userId, Account account, String authTokenType, String authToken) throws RemoteException; + + void setUserData(int userId, Account account, String key, String value) throws RemoteException; + + void hasFeatures(int userId, IAccountManagerResponse response, Account account, String[] features) throws RemoteException; + + void updateCredentials(int userId, IAccountManagerResponse response, Account account, String authTokenType, boolean expectActivityLaunch, Bundle loginOptions) throws RemoteException; + + void editProperties(int userId, IAccountManagerResponse response, String accountType, boolean expectActivityLaunch) throws RemoteException; + + void getAuthTokenLabel(int userId, IAccountManagerResponse response, String accountType, String authTokenType) throws RemoteException; + + String getUserData(int userId, Account account, String key) throws RemoteException; + + String getPassword(int userId, Account account) throws RemoteException; + + void confirmCredentials(int userId, IAccountManagerResponse response, Account account, Bundle options, boolean expectActivityLaunch) throws RemoteException; + + void addAccount(int userId, IAccountManagerResponse response, String accountType, String authTokenType, String[] requiredFeatures, boolean expectActivityLaunch, Bundle optionsIn) throws RemoteException; + + boolean addAccountExplicitly(int userId, Account account, String password, Bundle extras) throws RemoteException; + + boolean removeAccountExplicitly(int userId, Account account) throws RemoteException; + + void renameAccount(int userId, IAccountManagerResponse response, Account accountToRename, String newName) throws RemoteException; + + void removeAccount(int userId, IAccountManagerResponse response, Account account, boolean expectActivityLaunch) throws RemoteException; + + void clearPassword(int userId, Account account) throws RemoteException; + + boolean accountAuthenticated(int userId, Account account) throws RemoteException; + + void invalidateAuthToken(int userId, String accountType, String authToken) throws RemoteException; + + String peekAuthToken(int userId, Account account, String authTokenType) throws RemoteException; +} diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/server/interfaces/IActivityManager.java b/VirtualApp/lib/src/main/java/com/lody/virtual/server/interfaces/IActivityManager.java new file mode 100644 index 000000000..408b06add --- /dev/null +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/server/interfaces/IActivityManager.java @@ -0,0 +1,106 @@ +package com.lody.virtual.server.interfaces; + +import android.app.*; +import android.content.*; +import android.content.pm.*; +import android.os.*; + +import com.lody.virtual.remote.*; + +/** + * @author Lody + */ +public interface IActivityManager { + + int initProcess(String packageName, String processName, int userId) throws RemoteException; + + int getFreeStubCount() throws RemoteException; + + int getSystemPid() throws RemoteException; + + int getUidByPid(int pid) throws RemoteException; + + boolean isAppProcess(String processName) throws RemoteException; + + boolean isAppRunning(String packageName, int userId) throws RemoteException; + + boolean isAppPid(int pid) throws RemoteException; + + String getAppProcessName(int pid) throws RemoteException; + + java.util.List getProcessPkgList(int pid) throws RemoteException; + + void killAllApps() throws RemoteException; + + void killAppByPkg(String pkg, int userId) throws RemoteException; + + void killApplicationProcess(String processName, int vuid) throws RemoteException; + + void dump() throws RemoteException; + + String getInitialPackage(int pid) throws RemoteException; + + void handleApplicationCrash() throws RemoteException; + + void appDoneExecuting() throws RemoteException; + + int startActivities(Intent[] intents, String[] resolvedTypes, IBinder token, Bundle options, int userId) throws RemoteException; + + int startActivity(Intent intent, ActivityInfo info, IBinder resultTo, Bundle options, String resultWho, int requestCode, int userId) throws RemoteException; + + void onActivityCreated(ComponentName component, ComponentName caller, IBinder token, Intent intent, String affinity, int taskId, int launchMode, int flags) throws RemoteException; + + void onActivityResumed(int userId, IBinder token) throws RemoteException; + + boolean onActivityDestroyed(int userId, IBinder token) throws RemoteException; + + ComponentName getActivityClassForToken(int userId, IBinder token) throws RemoteException; + + String getCallingPackage(int userId, IBinder token) throws RemoteException; + + ComponentName getCallingActivity(int userId, IBinder token) throws RemoteException; + + AppTaskInfo getTaskInfo(int taskId) throws RemoteException; + + String getPackageForToken(int userId, IBinder token) throws RemoteException; + + boolean isVAServiceToken(IBinder token) throws RemoteException; + + ComponentName startService(IBinder caller, Intent service, String resolvedType, int userId) throws RemoteException; + + int stopService(IBinder caller, Intent service, String resolvedType, int userId) throws RemoteException; + + boolean stopServiceToken(ComponentName className, IBinder token, int startId, int userId) throws RemoteException; + + void setServiceForeground(ComponentName className, IBinder token, int id, Notification notification, boolean removeNotification, int userId) throws RemoteException; + + int bindService(IBinder caller, IBinder token, Intent service, String resolvedType, IServiceConnection connection, int flags, int userId) throws RemoteException; + + boolean unbindService(IServiceConnection connection, int userId) throws RemoteException; + + void unbindFinished(IBinder token, Intent service, boolean doRebind, int userId) throws RemoteException; + + void serviceDoneExecuting(IBinder token, int type, int startId, int res, int userId) throws RemoteException; + + IBinder peekService(Intent service, String resolvedType, int userId) throws RemoteException; + + void publishService(IBinder token, Intent intent, IBinder service, int userId) throws RemoteException; + + VParceledListSlice getServices(int maxNum, int flags, int userId) throws RemoteException; + + IBinder acquireProviderClient(int userId, ProviderInfo info) throws RemoteException; + + PendingIntentData getPendingIntent(IBinder binder) throws RemoteException; + + void addPendingIntent(IBinder binder, String packageName) throws RemoteException; + + void removePendingIntent(IBinder binder) throws RemoteException; + + String getPackageForIntentSender(IBinder binder) throws RemoteException; + + void processRestarted(String packageName, String processName, int userId) throws RemoteException; + + void broadcastFinish(PendingResultData res) throws RemoteException; + + void notifyBadgerChange(BadgerInfo info) throws RemoteException; +} diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/server/interfaces/IAppManager.java b/VirtualApp/lib/src/main/java/com/lody/virtual/server/interfaces/IAppManager.java new file mode 100644 index 000000000..cbf2e085f --- /dev/null +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/server/interfaces/IAppManager.java @@ -0,0 +1,58 @@ +package com.lody.virtual.server.interfaces; + +import android.os.RemoteException; + +import com.lody.virtual.remote.InstallResult; +import com.lody.virtual.remote.InstalledAppInfo; + +import java.util.List; + +/** + * @author Lody + */ +public interface IAppManager { + + int[] getPackageInstalledUsers(String packageName) throws RemoteException; + + void scanApps() throws RemoteException; + + void addVisibleOutsidePackage(String pkg) throws RemoteException; + + void removeVisibleOutsidePackage(String pkg) throws RemoteException; + + boolean isOutsidePackageVisible(String pkg) throws RemoteException; + + InstalledAppInfo getInstalledAppInfo(String pkg, int flags) throws RemoteException; + + InstallResult installPackage(String path, int flags) throws RemoteException; + + boolean isPackageLaunched(int userId, String packageName) throws RemoteException; + + void setPackageHidden(int userId, String packageName, boolean hidden) throws RemoteException; + + boolean installPackageAsUser(int userId, String packageName) throws RemoteException; + + boolean uninstallPackageAsUser(String packageName, int userId) throws RemoteException; + + boolean uninstallPackage(String packageName) throws RemoteException; + + List getInstalledApps(int flags) throws RemoteException; + + List getInstalledAppsAsUser(int userId, int flags) throws RemoteException; + + int getInstalledAppCount() throws RemoteException; + + boolean isAppInstalled(String packageName) throws RemoteException; + + boolean isAppInstalledAsUser(int userId, String packageName) throws RemoteException; + + void registerObserver(IPackageObserver observer) throws RemoteException; + + void unregisterObserver(IPackageObserver observer) throws RemoteException; + + void setAppRequestListener(IAppRequestListener listener) throws RemoteException; + + void clearAppRequestListener() throws RemoteException; + + IAppRequestListener getAppRequestListener() throws RemoteException; +} diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/server/interfaces/IDeviceInfoManager.java b/VirtualApp/lib/src/main/java/com/lody/virtual/server/interfaces/IDeviceInfoManager.java new file mode 100644 index 000000000..c7470892d --- /dev/null +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/server/interfaces/IDeviceInfoManager.java @@ -0,0 +1,16 @@ +package com.lody.virtual.server.interfaces; + +import android.os.RemoteException; + +import com.lody.virtual.remote.VDeviceInfo; + +/** + * @author Lody + */ +public interface IDeviceInfoManager { + + VDeviceInfo getDeviceInfo(int userId) throws RemoteException; + + void updateDeviceInfo(int userId, VDeviceInfo info) throws RemoteException; + +} diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/server/interfaces/IJobService.java b/VirtualApp/lib/src/main/java/com/lody/virtual/server/interfaces/IJobService.java new file mode 100644 index 000000000..37e8d4f83 --- /dev/null +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/server/interfaces/IJobService.java @@ -0,0 +1,25 @@ +package com.lody.virtual.server.interfaces; + +import android.app.job.JobInfo; +import android.os.Parcelable; +import android.os.RemoteException; + +import java.util.List; + +/** + * @author Lody + */ +public interface IJobService { + + int schedule(JobInfo job) throws RemoteException; + + void cancel(int jobId) throws RemoteException; + + void cancelAll() throws RemoteException; + + List getAllPendingJobs() throws RemoteException; + + int enqueue(JobInfo jobInfo, Parcelable parcelable) throws RemoteException; + + JobInfo getPendingJob(int i) throws RemoteException; +} diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/server/interfaces/INotificationManager.java b/VirtualApp/lib/src/main/java/com/lody/virtual/server/interfaces/INotificationManager.java new file mode 100644 index 000000000..9bc7d41c4 --- /dev/null +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/server/interfaces/INotificationManager.java @@ -0,0 +1,21 @@ +package com.lody.virtual.server.interfaces; + +import android.os.RemoteException; + +/** + * @author Lody + */ +public interface INotificationManager { + + int dealNotificationId(int id, String packageName, String tag, int userId) throws RemoteException; + + String dealNotificationTag(int id, String packageName, String tag, int userId) throws RemoteException; + + boolean areNotificationsEnabledForPackage(String packageName, int userId) throws RemoteException; + + void setNotificationsEnabledForPackage(String packageName, boolean enable, int userId) throws RemoteException; + + void addNotification(int id, String tag, String packageName, int userId) throws RemoteException; + + void cancelAllNotification(String packageName, int userId) throws RemoteException; +} \ No newline at end of file diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/server/interfaces/IPackageManager.java b/VirtualApp/lib/src/main/java/com/lody/virtual/server/interfaces/IPackageManager.java new file mode 100644 index 000000000..c2e98bd4c --- /dev/null +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/server/interfaces/IPackageManager.java @@ -0,0 +1,72 @@ +package com.lody.virtual.server.interfaces; + +import android.content.*; +import android.content.pm.*; +import android.os.IBinder; +import android.os.RemoteException; + +import com.lody.virtual.remote.VParceledListSlice; + +import java.util.List; + +/** + * @author Lody + */ +public interface IPackageManager { + + int getPackageUid(String packageName, int userId) throws RemoteException; + + String[] getPackagesForUid(int vuid) throws RemoteException; + + List getSharedLibraries(String pkgName) throws RemoteException; + + int checkPermission(String permName, String pkgName, int userId) throws RemoteException; + + PackageInfo getPackageInfo(String packageName, int flags, int userId) throws RemoteException; + + ActivityInfo getActivityInfo(ComponentName componentName, int flags, int userId) throws RemoteException; + + boolean activitySupportsIntent(ComponentName component, Intent intent, String resolvedType) throws RemoteException; + + ActivityInfo getReceiverInfo(ComponentName componentName, int flags, int userId) throws RemoteException; + + ServiceInfo getServiceInfo(ComponentName componentName, int flags, int userId) throws RemoteException; + + ProviderInfo getProviderInfo(ComponentName componentName, int flags, int userId) throws RemoteException; + + ResolveInfo resolveIntent(Intent intent, String resolvedType, int flags, int userId) throws RemoteException; + + List queryIntentActivities(Intent intent, String resolvedType, int flags, int userId) throws RemoteException; + + List queryIntentReceivers(Intent intent, String resolvedType, int flags, int userId) throws RemoteException; + + ResolveInfo resolveService(Intent intent, String resolvedType, int flags, int userId) throws RemoteException; + + List queryIntentServices(Intent intent, String resolvedType, int flags, int userId) throws RemoteException; + + List queryIntentContentProviders(Intent intent, String resolvedType, int flags, int userId) throws RemoteException; + + VParceledListSlice getInstalledPackages(int flags, int userId) throws RemoteException; + + VParceledListSlice getInstalledApplications(int flags, int userId) throws RemoteException; + + PermissionInfo getPermissionInfo(String name, int flags) throws RemoteException; + + List queryPermissionsByGroup(String group, int flags) throws RemoteException; + + PermissionGroupInfo getPermissionGroupInfo(String name, int flags) throws RemoteException; + + List getAllPermissionGroups(int flags) throws RemoteException; + + ProviderInfo resolveContentProvider(String name, int flags, int userId) throws RemoteException; + + ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) throws RemoteException; + + VParceledListSlice queryContentProviders(String processName, int vuid, int flags) throws RemoteException; + + List querySharedPackages(String packageName) throws RemoteException; + + String getNameForUid(int uid) throws RemoteException; + + IBinder getPackageInstaller() throws RemoteException; +} diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/server/interfaces/IUserManager.java b/VirtualApp/lib/src/main/java/com/lody/virtual/server/interfaces/IUserManager.java new file mode 100644 index 000000000..c3497596a --- /dev/null +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/server/interfaces/IUserManager.java @@ -0,0 +1,37 @@ +package com.lody.virtual.server.interfaces; + +import android.graphics.Bitmap; +import android.os.RemoteException; + +import com.lody.virtual.os.VUserInfo; + +import java.util.List; + +/** + * @author Lody + */ +public interface IUserManager { + VUserInfo createUser(String name, int flags) throws RemoteException; + + boolean removeUser(int userHandle) throws RemoteException; + + void setUserName(int userHandle, String name) throws RemoteException; + + void setUserIcon(int userHandle, Bitmap icon) throws RemoteException; + + Bitmap getUserIcon(int userHandle) throws RemoteException; + + List getUsers(boolean excludeDying) throws RemoteException; + + VUserInfo getUserInfo(int userHandle) throws RemoteException; + + void setGuestEnabled(boolean enable) throws RemoteException; + + boolean isGuestEnabled() throws RemoteException; + + void wipeUser(int userHandle) throws RemoteException; + + int getUserSerialNumber(int userHandle) throws RemoteException; + + int getUserHandle(int userSerialNumber) throws RemoteException; +} diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/server/interfaces/IVirtualLocationManager.java b/VirtualApp/lib/src/main/java/com/lody/virtual/server/interfaces/IVirtualLocationManager.java new file mode 100644 index 000000000..f7097b5d8 --- /dev/null +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/server/interfaces/IVirtualLocationManager.java @@ -0,0 +1,44 @@ +package com.lody.virtual.server.interfaces; + +import android.os.RemoteException; + +import com.lody.virtual.remote.vloc.VCell; +import com.lody.virtual.remote.vloc.VLocation; + +import java.util.List; + +/** + * @author Lody + */ +public interface IVirtualLocationManager { + + int getMode(int userId, String pkg) throws RemoteException; + + void setMode(int userId, String pkg, int mode) throws RemoteException; + + void setCell(int userId, String pkg, VCell cell) throws RemoteException; + + void setAllCell(int userId, String pkg, List cell) throws RemoteException; + + void setNeighboringCell(int userId, String pkg, List cell) throws RemoteException; + + void setGlobalCell(VCell cell) throws RemoteException; + + void setGlobalAllCell(List cell) throws RemoteException; + + void setGlobalNeighboringCell(List cell) throws RemoteException; + + VCell getCell(int userId, String pkg) throws RemoteException; + + List getAllCell(int userId, String pkg) throws RemoteException; + + List getNeighboringCell(int userId, String pkg) throws RemoteException; + + void setLocation(int userId, String pkg, VLocation loc) throws RemoteException; + + VLocation getLocation(int userId, String pkg) throws RemoteException; + + void setGlobalLocation(VLocation loc) throws RemoteException; + + VLocation getGlobalLocation() throws RemoteException; +} diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/server/interfaces/IVirtualStorageService.java b/VirtualApp/lib/src/main/java/com/lody/virtual/server/interfaces/IVirtualStorageService.java new file mode 100644 index 000000000..a998ad288 --- /dev/null +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/server/interfaces/IVirtualStorageService.java @@ -0,0 +1,17 @@ +package com.lody.virtual.server.interfaces; + +import android.os.RemoteException; + +/** + * @author Lody + */ +public interface IVirtualStorageService { + + void setVirtualStorage(String packageName, int userId, String vsPath) throws RemoteException; + + String getVirtualStorage(String packageName, int userId) throws RemoteException; + + void setVirtualStorageState(String packageName, int userId, boolean enable) throws RemoteException; + + boolean isVirtualStorageEnable(String packageName, int userId) throws RemoteException; +} diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/server/job/VJobSchedulerService.java b/VirtualApp/lib/src/main/java/com/lody/virtual/server/job/VJobSchedulerService.java index b4f0a8f87..9b4a7ce59 100644 --- a/VirtualApp/lib/src/main/java/com/lody/virtual/server/job/VJobSchedulerService.java +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/server/job/VJobSchedulerService.java @@ -3,14 +3,15 @@ import android.annotation.TargetApi; import android.app.job.JobInfo; import android.app.job.JobScheduler; +import android.app.job.JobWorkItem; import android.content.ComponentName; import android.content.Context; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.os.PersistableBundle; -import android.os.RemoteException; import android.text.TextUtils; +import android.util.Log; import com.lody.virtual.client.core.VirtualCore; import com.lody.virtual.client.ipc.VJobScheduler; @@ -18,7 +19,7 @@ import com.lody.virtual.helper.utils.Singleton; import com.lody.virtual.os.VBinder; import com.lody.virtual.os.VEnvironment; -import com.lody.virtual.server.IJobScheduler; +import com.lody.virtual.server.interfaces.IJobService; import java.io.File; import java.io.FileInputStream; @@ -28,13 +29,14 @@ import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Map.Entry; /** * @author Lody */ @TargetApi(Build.VERSION_CODES.LOLLIPOP) -public class VJobSchedulerService extends IJobScheduler.Stub { +public class VJobSchedulerService implements IJobService { private static final String TAG = VJobScheduler.class.getSimpleName(); @@ -179,7 +181,7 @@ public JobConfig[] newArray(int size) { @Override - public int schedule(JobInfo job) throws RemoteException { + public int schedule(JobInfo job) { int vuid = VBinder.getCallingUid(); int id = job.getId(); ComponentName service = job.getService(); @@ -257,7 +259,7 @@ private void readJobs() { } @Override - public void cancel(int jobId) throws RemoteException { + public void cancel(int jobId) { int vuid = VBinder.getCallingUid(); synchronized (mJobStore) { boolean changed = false; @@ -280,7 +282,7 @@ public void cancel(int jobId) throws RemoteException { } @Override - public void cancelAll() throws RemoteException { + public void cancelAll() { int vuid = VBinder.getCallingUid(); synchronized (mJobStore) { boolean changed = false; @@ -303,7 +305,7 @@ public void cancelAll() throws RemoteException { } @Override - public List getAllPendingJobs() throws RemoteException { + public List getAllPendingJobs() { int vuid = VBinder.getCallingUid(); List jobs = mScheduler.getAllPendingJobs(); synchronized (mJobStore) { @@ -345,4 +347,47 @@ public Map.Entry findJobByVirtualJobId(int virtualJobId) { } } + @TargetApi(24) + public JobInfo getPendingJob(int jobId) { + int callingUid = VBinder.getCallingUid(); + JobInfo jobInfo = null; + synchronized (this.mJobStore) { + for (Entry key : this.mJobStore.entrySet()) { + JobId jobId2 = (JobId) key.getKey(); + if (jobId2.vuid == callingUid && jobId2.clientJobId == jobId) { + jobInfo = this.mScheduler.getPendingJob(jobId2.clientJobId); + break; + } + } + } + return jobInfo; + } + + @TargetApi(26) + public int enqueue(JobInfo job, Parcelable workItem) { + if (!(workItem instanceof JobWorkItem)) { + Log.d("Q_M","!(workItem instanceof JobWorkItem)"); + return -1; + } + Log.d("Q_M","(workItem instanceof JobWorkItem)"); + int callingUid = VBinder.getCallingUid(); + int id = job.getId(); + ComponentName service = job.getService(); + JobId jobId = new JobId(callingUid, service.getPackageName(), id); + JobConfig jobConfig = (JobConfig) this.mJobStore.get(jobId); + if (jobConfig == null) { + int i = this.mGlobalJobId; + this.mGlobalJobId = i + 1; + jobConfig = new JobConfig(i, service.getClassName(), job.getExtras()); + this.mJobStore.put(jobId, jobConfig); + } else { + jobConfig.serviceName = service.getClassName(); + jobConfig.extras = job.getExtras(); + } + saveJobs(); + mirror.android.app.job.JobInfo.jobId.set(job, jobConfig.virtualJobId); + mirror.android.app.job.JobInfo.service.set(job, this.mJobProxyComponent); + return this.mScheduler.enqueue(job, (JobWorkItem) workItem); + } + } diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/server/location/VirtualLocationService.java b/VirtualApp/lib/src/main/java/com/lody/virtual/server/location/VirtualLocationService.java index dcd387906..e7dedff10 100644 --- a/VirtualApp/lib/src/main/java/com/lody/virtual/server/location/VirtualLocationService.java +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/server/location/VirtualLocationService.java @@ -9,7 +9,7 @@ import com.lody.virtual.os.VEnvironment; import com.lody.virtual.remote.vloc.VCell; import com.lody.virtual.remote.vloc.VLocation; -import com.lody.virtual.server.IVirtualLocationManager; +import com.lody.virtual.server.interfaces.IVirtualLocationManager; import java.util.HashMap; import java.util.List; @@ -19,7 +19,7 @@ * @author Lody */ -public class VirtualLocationService extends IVirtualLocationManager.Stub { +public class VirtualLocationService implements IVirtualLocationManager { private static final VirtualLocationService sInstance = new VirtualLocationService(); private final SparseArray> mLocConfigs = new SparseArray<>(); @@ -123,7 +123,7 @@ private VirtualLocationService() { } @Override - public int getMode(int userId, String pkg) throws RemoteException { + public int getMode(int userId, String pkg) { synchronized (mLocConfigs) { VLocConfig config = getOrCreateConfig(userId, pkg); mPersistenceLayer.save(); @@ -132,7 +132,7 @@ public int getMode(int userId, String pkg) throws RemoteException { } @Override - public void setMode(int userId, String pkg, int mode) throws RemoteException { + public void setMode(int userId, String pkg, int mode) { synchronized (mLocConfigs) { getOrCreateConfig(userId, pkg).mode = mode; mPersistenceLayer.save(); @@ -155,43 +155,43 @@ private VLocConfig getOrCreateConfig(int userId, String pkg) { } @Override - public void setCell(int userId, String pkg, VCell cell) throws RemoteException { + public void setCell(int userId, String pkg, VCell cell) { getOrCreateConfig(userId, pkg).cell = cell; mPersistenceLayer.save(); } @Override - public void setAllCell(int userId, String pkg, List cell) throws RemoteException { + public void setAllCell(int userId, String pkg, List cell) { getOrCreateConfig(userId, pkg).allCell = cell; mPersistenceLayer.save(); } @Override - public void setNeighboringCell(int userId, String pkg, List cell) throws RemoteException { + public void setNeighboringCell(int userId, String pkg, List cell) { getOrCreateConfig(userId, pkg).neighboringCell = cell; mPersistenceLayer.save(); } @Override - public void setGlobalCell(VCell cell) throws RemoteException { + public void setGlobalCell(VCell cell) { mGlobalConfig.cell = cell; mPersistenceLayer.save(); } @Override - public void setGlobalAllCell(List cell) throws RemoteException { + public void setGlobalAllCell(List cell) { mGlobalConfig.allCell = cell; mPersistenceLayer.save(); } @Override - public void setGlobalNeighboringCell(List cell) throws RemoteException { + public void setGlobalNeighboringCell(List cell) { mGlobalConfig.neighboringCell = cell; mPersistenceLayer.save(); } @Override - public VCell getCell(int userId, String pkg) throws RemoteException { + public VCell getCell(int userId, String pkg) { VLocConfig config = getOrCreateConfig(userId, pkg); mPersistenceLayer.save(); switch (config.mode) { @@ -206,7 +206,7 @@ public VCell getCell(int userId, String pkg) throws RemoteException { } @Override - public List getAllCell(int userId, String pkg) throws RemoteException { + public List getAllCell(int userId, String pkg) { VLocConfig config = getOrCreateConfig(userId, pkg); mPersistenceLayer.save(); switch (config.mode) { @@ -221,7 +221,7 @@ public List getAllCell(int userId, String pkg) throws RemoteException { } @Override - public List getNeighboringCell(int userId, String pkg) throws RemoteException { + public List getNeighboringCell(int userId, String pkg) { VLocConfig config = getOrCreateConfig(userId, pkg); mPersistenceLayer.save(); switch (config.mode) { @@ -236,13 +236,13 @@ public List getNeighboringCell(int userId, String pkg) throws RemoteExcep } @Override - public void setLocation(int userId, String pkg, VLocation loc) throws RemoteException { + public void setLocation(int userId, String pkg, VLocation loc) { getOrCreateConfig(userId, pkg).location = loc; mPersistenceLayer.save(); } @Override - public VLocation getLocation(int userId, String pkg) throws RemoteException { + public VLocation getLocation(int userId, String pkg) { VLocConfig config = getOrCreateConfig(userId, pkg); mPersistenceLayer.save(); switch (config.mode) { @@ -257,12 +257,12 @@ public VLocation getLocation(int userId, String pkg) throws RemoteException { } @Override - public void setGlobalLocation(VLocation loc) throws RemoteException { + public void setGlobalLocation(VLocation loc) { mGlobalConfig.location = loc; } @Override - public VLocation getGlobalLocation() throws RemoteException { + public VLocation getGlobalLocation() { return mGlobalConfig.location; } diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/server/memory/MappedMemoryRegion.java b/VirtualApp/lib/src/main/java/com/lody/virtual/server/memory/MappedMemoryRegion.java new file mode 100644 index 000000000..832707fdc --- /dev/null +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/server/memory/MappedMemoryRegion.java @@ -0,0 +1,47 @@ +package com.lody.virtual.server.memory; + +/** + * @author Lody + */ +public class MappedMemoryRegion { + + public static class FileMapping { + public final long offset; + public final long majorDeviceNumber; + public final long minorDeviceNumber; + public final long inode; + + public FileMapping(long off, long major, long minor, long inode) { + this.offset = off; + this.majorDeviceNumber = major; + this.minorDeviceNumber = minor; + this.inode = inode; + } + } + + public final long startAddress; + public final long endAddress; + public final boolean isReadable; + public final boolean isWritable; + public final boolean isExecutable; + public final boolean isShared; + + public final FileMapping fileMapInfo; + + public final String description; + + public MappedMemoryRegion(long start, long end, boolean read, boolean write, boolean exec, boolean shared, long off, long majorDevNum, long minorDevNum, long inode, String desc) { + this.startAddress = start; + this.endAddress = end; + this.isReadable = read; + this.isWritable = write; + this.isExecutable = exec; + this.isShared = shared; + this.fileMapInfo = (inode == 0) ? null : new FileMapping(off, majorDevNum, minorDevNum, inode); + this.description = desc; + } + + public boolean isMappedFromFile() { + return this.fileMapInfo != null; + } +} \ No newline at end of file diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/server/memory/MemoryRegionParser.java b/VirtualApp/lib/src/main/java/com/lody/virtual/server/memory/MemoryRegionParser.java new file mode 100644 index 000000000..5491db5bd --- /dev/null +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/server/memory/MemoryRegionParser.java @@ -0,0 +1,70 @@ +package com.lody.virtual.server.memory; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @author Lody + */ +public class MemoryRegionParser { + /** + * Regular Expression for /proc/self/maps line is + *

+ * ([0-9a-f]+) - ([0-9a-f]+) \s ([r-]) ([w-]) ([x-]) ([sp]) \s ([0-9a-f]+) \s ([0-9a-f]+) : ([0-9a-f]+) \s (\d+) \s? (.*) + * StartAddress EndAddress Read Write Execute Shared Filemap Offset Major devnum Minor devnum Inode Description + */ + public static final String PATTERN = "([0-9a-f]+)-([0-9a-f]+)\\s([r-])([w-])([x-])([sp])\\s([0-9a-f]+)\\s([0-9a-f]+):([0-9a-f]+)\\s(\\d+)\\s?(.*)"; + public final static Pattern MAPS_LINE_PATTERN = Pattern.compile(PATTERN, Pattern.CASE_INSENSITIVE); + + private static long parseHex(String s) { + return Long.parseLong(s, 16); + } + + private static MappedMemoryRegion parseMapLine(String line) { + line = line.trim(); + Matcher m = MAPS_LINE_PATTERN.matcher(line); + if (!m.matches()) { + throw new IllegalArgumentException(String.format("The provided line does not match the pattern for /proc/$pid/maps lines. Given: %s", line)); + } + + if (m.groupCount() != 11) // group(0) not included in this. + { + throw new InternalError(String.format(Locale.ENGLISH, "Invalid group count: Found %d, but expected %d", m.groupCount(), 12)); + } + + long start = parseHex(m.group(1)); + long end = parseHex(m.group(2)); + boolean read = m.group(3).equals("r"); + boolean write = m.group(4).equals("w"); + boolean exec = m.group(5).equals("x"); + boolean shared = m.group(6).equals("s"); + long fileOffset = parseHex(m.group(7)); + long majorDevNum = parseHex(m.group(8)); + long minorDevNum = parseHex(m.group(9)); + long inode = parseHex(m.group(10)); + String desc = m.group(11); + + return new MappedMemoryRegion(start, end, read, write, exec, shared, fileOffset, majorDevNum, minorDevNum, inode, desc); + } + + + public static List getMemoryRegions(int pid) throws IOException { + List list = new LinkedList<>(); + BufferedReader reader = new BufferedReader(new FileReader(String.format(Locale.ENGLISH, "/proc/%d/maps", pid))); + String line; + while ((line = reader.readLine()) != null) { + MappedMemoryRegion region = parseMapLine(line); + if (region.isReadable && region.isWritable && !region.description.endsWith("(deleted)")) { + list.add(region); + } + } + return list; + } +} \ No newline at end of file diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/server/memory/MemoryScanEngine.java b/VirtualApp/lib/src/main/java/com/lody/virtual/server/memory/MemoryScanEngine.java new file mode 100644 index 000000000..c9b21c385 --- /dev/null +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/server/memory/MemoryScanEngine.java @@ -0,0 +1,111 @@ +package com.lody.virtual.server.memory; + +import com.lody.virtual.helper.utils.VLog; + +import java.io.IOException; +import java.util.LinkedList; +import java.util.List; + +/** + * @author Lody + */ +public class MemoryScanEngine { + + private List regions; + + private int pid; + private ProcessMemory memory; + private static final int PAGE = 4096; + private List matches; + + public MemoryScanEngine(int pid) throws IOException { + this.pid = pid; + this.memory = new ProcessMemory(pid); + updateMemoryLayout(); + } + + public void updateMemoryLayout() { + try { + regions = MemoryRegionParser.getMemoryRegions(pid); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + public List getMatches() { + return matches; + } + + public void search(MemoryValue value) throws IOException { + matches = new LinkedList<>(); + byte[] bytes = new byte[PAGE]; + byte[] valueBytes = value.toBytes(); + for (MappedMemoryRegion region : regions) { + long start = region.startAddress; + long end = region.endAddress; + try { + while (start < end) { + int read = Math.min(bytes.length, (int) (end - start)); + read = memory.read(start, bytes, read); + matches.addAll(matchBytes(region, start, bytes, read, valueBytes)); + start += PAGE; + } + } catch (IOException e) { + VLog.e(getClass().getSimpleName(), "Unable to read region : " + region.description); + } + } + } + + public void modify(Match match, MemoryValue value) throws IOException { + memory.write(match.address, value.toBytes()); + } + + public void modifyAll(MemoryValue value) throws IOException { + for (Match match : matches) { + modify(match, value); + } + } + + public class Match { + MappedMemoryRegion region; + long address; + int len; + + public Match(MappedMemoryRegion region, long address, int len) { + this.region = region; + this.address = address; + this.len = len; + } + } + + + private List matchBytes(MappedMemoryRegion region, long startAddress, byte[] page, int read, byte[] value) { + List matches = new LinkedList<>(); + int start = 0; + int len = value.length; + int step = 2; + while (start < read) { + boolean match = true; + for (int i = 0; i < len && i + start < read; i++) { + if (page[start + i] != value[i]) { + match = false; + break; + } + } + if (match) { + matches.add(new Match(region, startAddress + start, len)); + } + start += step; + } + return matches; + } + + + public void close() { + try { + memory.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/server/memory/MemoryValue.java b/VirtualApp/lib/src/main/java/com/lody/virtual/server/memory/MemoryValue.java new file mode 100644 index 000000000..59f7cd3c8 --- /dev/null +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/server/memory/MemoryValue.java @@ -0,0 +1,67 @@ +package com.lody.virtual.server.memory; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * @author Lody + */ +public abstract class MemoryValue { + + private static final ByteOrder BYTE_ORDER = ByteOrder.BIG_ENDIAN; + + public enum ValueType { + INT2, // short + INT4, // int + INT8, // long + } + + public abstract byte[] toBytes(); + + + public static class INT2 extends MemoryValue { + + private short val; + + public INT2(short val) { + this.val = val; + } + + @Override + public byte[] toBytes() { + ByteBuffer buffer = ByteBuffer.allocate(2); + return buffer.putShort(val).order(BYTE_ORDER).array(); + } + } + + public static class INT4 extends MemoryValue { + + private int val; + + public INT4(int val) { + this.val = val; + } + + @Override + public byte[] toBytes() { + ByteBuffer buffer = ByteBuffer.allocate(4); + return buffer.order(BYTE_ORDER).putInt(val).array(); + } + } + + public static class INT8 extends MemoryValue { + + private long val; + + public INT8(long val) { + this.val = val; + } + + @Override + public byte[] toBytes() { + ByteBuffer buffer = ByteBuffer.allocate(8); + return buffer.order(BYTE_ORDER).putLong(val).array(); + } + } + +} diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/server/memory/ProcessMemory.java b/VirtualApp/lib/src/main/java/com/lody/virtual/server/memory/ProcessMemory.java new file mode 100644 index 000000000..0c86baae5 --- /dev/null +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/server/memory/ProcessMemory.java @@ -0,0 +1,33 @@ +package com.lody.virtual.server.memory; + +import java.io.IOException; +import java.io.RandomAccessFile; +import java.util.Locale; + +/** + * @author Lody + */ +public class ProcessMemory { + + private int pid; + private RandomAccessFile memFile; + + public ProcessMemory(int pid) throws IOException { + this.pid = pid; + this.memFile = new RandomAccessFile(String.format(Locale.ENGLISH, "/proc/%d/mem", pid), "rw"); + } + + public void write(long offset, byte[] bytes) throws IOException { + memFile.seek(offset); + memFile.write(bytes); + } + + public int read(long offset, byte[] bytes, int len) throws IOException { + memFile.seek(offset); + return memFile.read(bytes, 0, len); + } + + public void close() throws IOException { + memFile.close(); + } +} diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/server/notification/NotificationFixer.java b/VirtualApp/lib/src/main/java/com/lody/virtual/server/notification/NotificationFixer.java index 499c3444f..84e3c616d 100644 --- a/VirtualApp/lib/src/main/java/com/lody/virtual/server/notification/NotificationFixer.java +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/server/notification/NotificationFixer.java @@ -142,8 +142,7 @@ boolean fixRemoteViewActions(Context appContext, boolean installed, final Remote mActions.remove(action); continue; } - if (ReflectionActionCompat.isInstance(action) - || (action.getClass().getSimpleName().endsWith("ReflectionAction"))) { + if (ReflectionActionCompat.isInstance(action)) { int viewId = Reflect.on(action).get("viewId"); String methodName = Reflect.on(action).get("methodName"); diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/server/notification/VNotificationManagerService.java b/VirtualApp/lib/src/main/java/com/lody/virtual/server/notification/VNotificationManagerService.java index 8ba98af09..a3093b5e2 100644 --- a/VirtualApp/lib/src/main/java/com/lody/virtual/server/notification/VNotificationManagerService.java +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/server/notification/VNotificationManagerService.java @@ -5,14 +5,14 @@ import android.text.TextUtils; import com.lody.virtual.helper.utils.VLog; -import com.lody.virtual.server.INotificationManager; +import com.lody.virtual.server.interfaces.INotificationManager; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.concurrent.atomic.AtomicReference; -public class VNotificationManagerService extends INotificationManager.Stub { +public class VNotificationManagerService implements INotificationManager { private static final AtomicReference gService = new AtomicReference<>(); private NotificationManager mNotificationManager; static final String TAG = NotificationCompat.class.getSimpleName(); diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/PrivilegeAppOptimizer.java b/VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/PrivilegeAppOptimizer.java index 20b84cf5a..02ce3fbab 100644 --- a/VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/PrivilegeAppOptimizer.java +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/PrivilegeAppOptimizer.java @@ -1,6 +1,7 @@ package com.lody.virtual.server.pm; import android.content.Intent; +import android.util.Log; import com.lody.virtual.client.stub.VASettings; import com.lody.virtual.os.VUserHandle; diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/VAppManagerService.java b/VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/VAppManagerService.java index 41c569e37..01541163b 100644 --- a/VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/VAppManagerService.java +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/VAppManagerService.java @@ -3,6 +3,7 @@ import android.content.Intent; import android.net.Uri; import android.os.Build; +import android.os.IBinder; import android.os.RemoteCallbackList; import android.os.RemoteException; @@ -19,11 +20,11 @@ import com.lody.virtual.os.VUserHandle; import com.lody.virtual.remote.InstallResult; import com.lody.virtual.remote.InstalledAppInfo; -import com.lody.virtual.server.IAppManager; import com.lody.virtual.server.accounts.VAccountManagerService; import com.lody.virtual.server.am.BroadcastSystem; import com.lody.virtual.server.am.UidSystem; import com.lody.virtual.server.am.VActivityManagerService; +import com.lody.virtual.server.interfaces.IAppManager; import com.lody.virtual.server.interfaces.IAppRequestListener; import com.lody.virtual.server.interfaces.IPackageObserver; import com.lody.virtual.server.pm.parser.PackageParserEx; @@ -42,7 +43,7 @@ /** * @author Lody */ -public class VAppManagerService extends IAppManager.Stub { +public class VAppManagerService implements IAppManager { private static final String TAG = VAppManagerService.class.getSimpleName(); private static final AtomicReference sService = new AtomicReference<>(); @@ -513,7 +514,7 @@ public void setAppRequestListener(final IAppRequestListener listener) { this.mAppRequestListener = listener; if (listener != null) { try { - listener.asBinder().linkToDeath(new DeathRecipient() { + listener.asBinder().linkToDeath(new IBinder.DeathRecipient() { @Override public void binderDied() { listener.asBinder().unlinkToDeath(this, 0); diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/VPackageManagerService.java b/VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/VPackageManagerService.java index 4c5a1f7af..1de66fdf0 100644 --- a/VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/VPackageManagerService.java +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/VPackageManagerService.java @@ -13,8 +13,7 @@ import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.os.Build; -import android.os.Parcel; -import android.os.RemoteException; +import android.os.IBinder; import android.text.TextUtils; import android.util.Log; @@ -25,13 +24,15 @@ import com.lody.virtual.os.VUserHandle; import com.lody.virtual.remote.VParceledListSlice; import com.lody.virtual.server.IPackageInstaller; -import com.lody.virtual.server.IPackageManager; +import com.lody.virtual.server.interfaces.IPackageManager; import com.lody.virtual.server.pm.installer.VPackageInstallerService; import com.lody.virtual.server.pm.parser.PackageParserEx; import com.lody.virtual.server.pm.parser.VPackage; import java.io.File; import java.io.PrintWriter; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -40,12 +41,11 @@ import java.util.Map; import java.util.concurrent.atomic.AtomicReference; -import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE; /** * @author Lody */ -public class VPackageManagerService extends IPackageManager.Stub { +public class VPackageManagerService implements IPackageManager { static final String TAG = "PackageManager"; static final Comparator sResolvePrioritySorter = new Comparator() { @@ -269,7 +269,7 @@ private int updateFlagsNought(int flags) { // give them what they want } else { // Caller expressed no opinion, so match based on user state - flags |= PackageManager.MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE; + flags |= PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE; } return flags; } @@ -400,22 +400,36 @@ private ResolveInfo chooseBestActivity(Intent intent, String resolvedType, int f // If we have saved a preference for a preferred activity for // this Intent, use that. + //从候选列表中查找一个最合适的,如果候选列表没有最合适的返回null + //然后从系统中查找合适的打开intent ResolveInfo ri = findPreferredActivity(intent, resolvedType, flags, query, r0.priority); //noinspection ConstantConditions if (ri != null) { return ri; } - return query.get(0); + + return null; } } return null; } private ResolveInfo findPreferredActivity(Intent intent, String resolvedType, int flags, List query, int priority) { - return null; + + try { + Class clazz = Class.forName("com.virtual.helper.VALibHelper"); + Method method = clazz.getDeclaredMethod("findPreferredActivity", Intent.class, String.class, int.class, List.class, int.class); + return (ResolveInfo) method.invoke(null, intent, resolvedType, flags, query, priority); + } catch (Exception e) { + e.printStackTrace(); + return query.get(0); + } + +// return null; } + @Override public List queryIntentActivities(Intent intent, String resolvedType, int flags, int userId) { checkUserId(userId); @@ -774,17 +788,7 @@ public List querySharedPackages(String packageName) { } @Override - public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { - try { - return super.onTransact(code, data, reply, flags); - } catch (Throwable e) { - e.printStackTrace(); - throw e; - } - } - - @Override - public IPackageInstaller getPackageInstaller() { + public IBinder getPackageInstaller() { return VPackageInstallerService.get(); } diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/VUserManagerService.java b/VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/VUserManagerService.java index b45ca62ad..320dc3be1 100644 --- a/VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/VUserManagerService.java +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/VUserManagerService.java @@ -25,7 +25,7 @@ import com.lody.virtual.os.VUserInfo; import com.lody.virtual.os.VUserManager; import com.lody.virtual.server.am.VActivityManagerService; -import com.lody.virtual.server.IUserManager; +import com.lody.virtual.server.interfaces.IUserManager; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -47,7 +47,7 @@ /** * @author Lody */ -public class VUserManagerService extends IUserManager.Stub { +public class VUserManagerService implements IUserManager { private static final String LOG_TAG = "VUserManagerService"; @@ -317,7 +317,7 @@ public void makeInitialized(int userId) { if (info == null || info.partial) { VLog.w(LOG_TAG, "makeInitialized: unknown user #" + userId); } - if ((info.flags& VUserInfo.FLAG_INITIALIZED) == 0) { + if ((info.flags & VUserInfo.FLAG_INITIALIZED) == 0) { info.flags |= VUserInfo.FLAG_INITIALIZED; writeUserLocked(info); } @@ -360,6 +360,7 @@ private void writeBitmapLocked(VUserInfo info, Bitmap bitmap) { /** * Returns an array of user ids. This array is cached here for quick access, so do not modify or * cache it elsewhere. + * * @return the array of user ids. */ public int[] getUserIds() { @@ -513,7 +514,7 @@ private void writeUserLocked(VUserInfo userInfo) { serializer.attribute(null, ATTR_LAST_LOGGED_IN_TIME, Long.toString(userInfo.lastLoggedInTime)); if (userInfo.iconPath != null) { - serializer.attribute(null, ATTR_ICON_PATH, userInfo.iconPath); + serializer.attribute(null, ATTR_ICON_PATH, userInfo.iconPath); } if (userInfo.partial) { serializer.attribute(null, ATTR_PARTIAL, "true"); @@ -699,7 +700,7 @@ public VUserInfo createUser(String name, int flags) { Intent addedIntent = new Intent(Constants.ACTION_USER_ADDED); addedIntent.putExtra(Constants.EXTRA_USER_HANDLE, userInfo.id); VActivityManagerService.get().sendBroadcastAsUser(addedIntent, VUserHandle.ALL, - null); + null); } finally { Binder.restoreCallingIdentity(ident); } @@ -709,6 +710,7 @@ public VUserInfo createUser(String name, int flags) { /** * Removes a user and all data directories created for that user. This method should be called * after the user's processes have been terminated. + * * @param userHandle the user's id */ public boolean removeUser(int userHandle) { @@ -728,15 +730,16 @@ public boolean removeUser(int userHandle) { } if (DBG) VLog.i(LOG_TAG, "Stopping user " + userHandle); int res = VActivityManagerService.get().stopUser(userHandle, - new IStopUserCallback.Stub() { - @Override - public void userStopped(int userId) { - finishRemoveUser(userId); - } - @Override - public void userStopAborted(int userId) { - } - }); + new IStopUserCallback.Stub() { + @Override + public void userStopped(int userId) { + finishRemoveUser(userId); + } + + @Override + public void userStopAborted(int userId) { + } + }); return res == ActivityManagerCompat.USER_OP_SUCCESS; } @@ -749,14 +752,14 @@ void finishRemoveUser(final int userHandle) { Intent addedIntent = new Intent(Constants.ACTION_USER_REMOVED); addedIntent.putExtra(Constants.EXTRA_USER_HANDLE, userHandle); VActivityManagerService.get().sendOrderedBroadcastAsUser(addedIntent, VUserHandle.ALL, - null, + null, new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (DBG) { VLog.i(LOG_TAG, "USER_REMOVED broadcast sent, cleaning up user data " - + userHandle); + + userHandle); } new Thread() { public void run() { @@ -843,6 +846,7 @@ private void updateUserIdsLocked() { /** * Make a note of the last started time of a user. + * * @param userId the user that was just foregrounded */ public void userForeground(int userId) { @@ -864,6 +868,7 @@ public void userForeground(int userId) { * Returns the next available user id, filling in any holes in the ids. * TODO: May not be a good idea to recycle ids, in case it results in confusion * for data and battery stats collection, or unexpected cross-talk. + * * @return */ private int getNextAvailableIdLocked() { @@ -880,8 +885,4 @@ private int getNextAvailableIdLocked() { } } - @Override - protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - - } } diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/server/vs/VirtualStorageService.java b/VirtualApp/lib/src/main/java/com/lody/virtual/server/vs/VirtualStorageService.java index 8eedbc776..2e8e04b96 100644 --- a/VirtualApp/lib/src/main/java/com/lody/virtual/server/vs/VirtualStorageService.java +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/server/vs/VirtualStorageService.java @@ -3,7 +3,7 @@ import android.os.RemoteException; import android.util.SparseArray; -import com.lody.virtual.server.IVirtualStorageService; +import com.lody.virtual.server.interfaces.IVirtualStorageService; import com.lody.virtual.server.pm.VUserManagerService; import java.util.HashMap; @@ -12,7 +12,7 @@ * @author Lody */ -public class VirtualStorageService extends IVirtualStorageService.Stub { +public class VirtualStorageService implements IVirtualStorageService { private static final VirtualStorageService sService = new VirtualStorageService(); private final VSPersistenceLayer mLayer = new VSPersistenceLayer(this); @@ -31,7 +31,7 @@ SparseArray> getConfigs() { } @Override - public void setVirtualStorage(String packageName, int userId, String vsPath) throws RemoteException { + public void setVirtualStorage(String packageName, int userId, String vsPath) { checkUserId(userId); synchronized (mConfigs) { VSConfig config = getOrCreateVSConfigLocked(packageName, userId); @@ -57,7 +57,7 @@ private VSConfig getOrCreateVSConfigLocked(String packageName, int userId) { @Override - public String getVirtualStorage(String packageName, int userId) throws RemoteException { + public String getVirtualStorage(String packageName, int userId) { checkUserId(userId); synchronized (mConfigs) { VSConfig config = getOrCreateVSConfigLocked(packageName, userId); @@ -66,7 +66,7 @@ public String getVirtualStorage(String packageName, int userId) throws RemoteExc } @Override - public void setVirtualStorageState(String packageName, int userId, boolean enable) throws RemoteException { + public void setVirtualStorageState(String packageName, int userId, boolean enable) { checkUserId(userId); synchronized (mConfigs) { VSConfig config = getOrCreateVSConfigLocked(packageName, userId); @@ -77,7 +77,7 @@ public void setVirtualStorageState(String packageName, int userId, boolean enabl } @Override - public boolean isVirtualStorageEnable(String packageName, int userId) throws RemoteException { + public boolean isVirtualStorageEnable(String packageName, int userId) { checkUserId(userId); synchronized (mConfigs) { VSConfig config = getOrCreateVSConfigLocked(packageName, userId); diff --git a/VirtualApp/lib/src/main/java/mirror/android/app/ContextImplKitkat.java b/VirtualApp/lib/src/main/java/mirror/android/app/ContextImplKitkat.java index 8618f7160..6f92c656d 100644 --- a/VirtualApp/lib/src/main/java/mirror/android/app/ContextImplKitkat.java +++ b/VirtualApp/lib/src/main/java/mirror/android/app/ContextImplKitkat.java @@ -10,4 +10,5 @@ public class ContextImplKitkat { public static RefObject mExternalCacheDirs; public static RefObject mExternalFilesDirs; public static RefObject mOpPackageName; + public static RefObject mDisplayAdjustments; } diff --git a/VirtualApp/lib/src/main/java/mirror/android/app/LoadedApkICS.java b/VirtualApp/lib/src/main/java/mirror/android/app/LoadedApkICS.java new file mode 100644 index 000000000..0cc032450 --- /dev/null +++ b/VirtualApp/lib/src/main/java/mirror/android/app/LoadedApkICS.java @@ -0,0 +1,10 @@ +package mirror.android.app; + + +import mirror.RefClass; +import mirror.RefObject; + +public class LoadedApkICS { + public static Class Class = RefClass.load(LoadedApkICS.class, "android.app.LoadedApk"); + public static RefObject mCompatibilityInfo; +} \ No newline at end of file diff --git a/VirtualApp/lib/src/main/java/mirror/android/app/LoadedApkKitkat.java b/VirtualApp/lib/src/main/java/mirror/android/app/LoadedApkKitkat.java new file mode 100644 index 000000000..344abcd58 --- /dev/null +++ b/VirtualApp/lib/src/main/java/mirror/android/app/LoadedApkKitkat.java @@ -0,0 +1,10 @@ +package mirror.android.app; + + +import mirror.RefClass; +import mirror.RefObject; + +public class LoadedApkKitkat { + public static Class Class = RefClass.load(LoadedApkKitkat.class, "android.app.LoadedApk"); + public static RefObject mDisplayAdjustments; +} \ No newline at end of file diff --git a/VirtualApp/lib/src/main/java/mirror/android/app/job/JobWorkItem.java b/VirtualApp/lib/src/main/java/mirror/android/app/job/JobWorkItem.java new file mode 100644 index 000000000..c3f8ec52d --- /dev/null +++ b/VirtualApp/lib/src/main/java/mirror/android/app/job/JobWorkItem.java @@ -0,0 +1,21 @@ +package mirror.android.app.job; + +import android.annotation.TargetApi; +import android.content.Intent; +import mirror.MethodParams; +import mirror.RefClass; +import mirror.RefConstructor; +import mirror.RefInt; +import mirror.RefMethod; +import mirror.RefObject; + +@TargetApi(26) +public class JobWorkItem { + public static Class TYPE = RefClass.load(JobWorkItem.class, android.app.job.JobWorkItem.class); + @MethodParams({Intent.class}) + public static RefConstructor ctor; + public static RefMethod getIntent; + public static RefInt mDeliveryCount; + public static RefObject mGrants; + public static RefInt mWorkId; +} \ No newline at end of file diff --git a/VirtualApp/lib/src/main/java/mirror/android/bluetooth/IBluetoothManager.java b/VirtualApp/lib/src/main/java/mirror/android/bluetooth/IBluetoothManager.java new file mode 100644 index 000000000..ad06679ca --- /dev/null +++ b/VirtualApp/lib/src/main/java/mirror/android/bluetooth/IBluetoothManager.java @@ -0,0 +1,23 @@ +package mirror.android.bluetooth; + +import android.os.IBinder; +import android.os.IInterface; + +import mirror.MethodParams; +import mirror.RefClass; +import mirror.RefStaticMethod; + +public class IBluetoothManager { + /** + * @see android.bluetooth.IBluetoothManager + * */ + public static Class TYPE = RefClass.load(IBluetoothManager.class, "android.bluetooth.IBluetoothManager"); + /** + * @see android.bluetooth.IBluetoothManager.Stub + * */ + public static class Stub { + public static Class TYPE = RefClass.load(Stub.class, "android.bluetooth.IBluetoothManager$Stub"); + @MethodParams({IBinder.class}) + public static RefStaticMethod asInterface; + } +} diff --git a/VirtualApp/lib/src/main/java/mirror/android/view/CompatibilityInfoHolder.java b/VirtualApp/lib/src/main/java/mirror/android/view/CompatibilityInfoHolder.java new file mode 100644 index 000000000..c149afc29 --- /dev/null +++ b/VirtualApp/lib/src/main/java/mirror/android/view/CompatibilityInfoHolder.java @@ -0,0 +1,12 @@ +package mirror.android.view; + + +import mirror.MethodReflectParams; +import mirror.RefClass; +import mirror.RefMethod; + +public class CompatibilityInfoHolder { + public static Class Class = RefClass.load(CompatibilityInfoHolder.class, "android.view.CompatibilityInfoHolder"); + @MethodReflectParams({"android.content.res.CompatibilityInfo"}) + public static RefMethod set; +} \ No newline at end of file diff --git a/VirtualApp/lib/src/main/java/mirror/android/view/DisplayAdjustments.java b/VirtualApp/lib/src/main/java/mirror/android/view/DisplayAdjustments.java new file mode 100644 index 000000000..190010cac --- /dev/null +++ b/VirtualApp/lib/src/main/java/mirror/android/view/DisplayAdjustments.java @@ -0,0 +1,12 @@ +package mirror.android.view; + + +import mirror.MethodReflectParams; +import mirror.RefClass; +import mirror.RefMethod; + +public class DisplayAdjustments { + public static Class Class = RefClass.load(DisplayAdjustments.class, "android.view.DisplayAdjustments"); + @MethodReflectParams({"android.content.res.CompatibilityInfo"}) + public static RefMethod setCompatibilityInfo; +} \ No newline at end of file diff --git a/VirtualApp/lib/src/main/java/mirror/android/view/IAutoFillManager.java b/VirtualApp/lib/src/main/java/mirror/android/view/IAutoFillManager.java new file mode 100644 index 000000000..2669e4497 --- /dev/null +++ b/VirtualApp/lib/src/main/java/mirror/android/view/IAutoFillManager.java @@ -0,0 +1,24 @@ +package mirror.android.view; + +import android.os.IBinder; +import android.os.IInterface; + +import mirror.MethodParams; +import mirror.RefClass; +import mirror.RefStaticMethod; + +/** + * @author 陈磊. + */ + +public class IAutoFillManager { + + public static Class TYPE = RefClass.load(IAutoFillManager.class, "android.view.autofill.IAutoFillManager"); + + public static class Stub { + public static Class TYPE = RefClass.load(Stub.class, "android.view.autofill.IAutoFillManager$Stub"); + @MethodParams(IBinder.class) + public static RefStaticMethod asInterface; + } + +} diff --git a/VirtualApp/lib/src/main/jni/Android.mk b/VirtualApp/lib/src/main/jni/Android.mk index 7b720825b..ee971bd28 100644 --- a/VirtualApp/lib/src/main/jni/Android.mk +++ b/VirtualApp/lib/src/main/jni/Android.mk @@ -16,10 +16,13 @@ LOCAL_SRC_FILES := Jni/VAJni.cpp \ Foundation/SymbolFinder.cpp \ Foundation/Path.cpp \ Foundation/SandboxFs.cpp \ + Substrate/hde64.c \ + Substrate/SubstrateDebug.cpp \ + Substrate/SubstrateHook.cpp \ + Substrate/SubstratePosixMemory.cpp \ LOCAL_LDLIBS := -llog -latomic -LOCAL_STATIC_LIBRARIES := hookzz fb +LOCAL_STATIC_LIBRARIES := fb include $(BUILD_SHARED_LIBRARY) -include $(MAIN_LOCAL_PATH)/HookZz/Android.mk include $(MAIN_LOCAL_PATH)/fb/Android.mk \ No newline at end of file diff --git a/VirtualApp/lib/src/main/jni/Application.mk b/VirtualApp/lib/src/main/jni/Application.mk index 5e56b2e91..7ec75bdf1 100644 --- a/VirtualApp/lib/src/main/jni/Application.mk +++ b/VirtualApp/lib/src/main/jni/Application.mk @@ -1,4 +1,4 @@ -APP_ABI := armeabi armeabi-v7a +APP_ABI := armeabi-v7a x86 APP_PLATFORM := android-14 APP_STL := gnustl_static APP_OPTIM := release diff --git a/VirtualApp/lib/src/main/jni/Foundation/IOUniformer.cpp b/VirtualApp/lib/src/main/jni/Foundation/IOUniformer.cpp index 081091ffc..d48debd21 100644 --- a/VirtualApp/lib/src/main/jni/Foundation/IOUniformer.cpp +++ b/VirtualApp/lib/src/main/jni/Foundation/IOUniformer.cpp @@ -4,11 +4,7 @@ #include #include #include - -extern "C" { -#include -} - +#include #include "IOUniformer.h" #include "SandboxFs.h" @@ -75,7 +71,7 @@ hook_function(void *handle, const char *symbol, void *new_func, void **old_func) if (addr == NULL) { return; } - ZzHookReplace(addr, new_func, old_func); + MSHookFunction(addr, new_func, old_func); } @@ -86,7 +82,8 @@ void IOUniformer::redirect(const char *orig_path, const char *new_path) { } const char *IOUniformer::query(const char *orig_path) { - return reverse_relocate_path(orig_path); + int res; + return relocate_path(orig_path, &res); } void IOUniformer::whitelist(const char *_path) { @@ -553,7 +550,7 @@ HOOK_DEF(int, execve, const char *pathname, char *argv[], char *const envp[]) { * * We will support 64Bit to adopt it. */ - ALOGE("execve : %s", pathname); + // ALOGE("execve : %s", pathname); // any output can break exec. See bug: https://issuetracker.google.com/issues/109448553 int res; const char *redirect_path = relocate_path(pathname, &res); char *ld = getenv("LD_PRELOAD"); @@ -568,6 +565,7 @@ HOOK_DEF(int, execve, const char *pathname, char *argv[], char *const envp[]) { char **new_envp = build_new_env(envp); int ret = syscall(__NR_execve, redirect_path, argv, new_envp); FREE(redirect_path, pathname); + free(new_envp); return ret; } int ret = syscall(__NR_execve, redirect_path, argv, envp); @@ -643,19 +641,19 @@ void hook_dlopen(int api_level) { if (api_level > 23) { if (findSymbol("__dl__Z9do_dlopenPKciPK17android_dlextinfoPv", "linker", (unsigned long *) &symbol) == 0) { - ZzHookReplace(symbol, (void *) new_do_dlopen_V24, + MSHookFunction(symbol, (void *) new_do_dlopen_V24, (void **) &orig_do_dlopen_V24); } } else if (api_level >= 19) { if (findSymbol("__dl__Z9do_dlopenPKciPK17android_dlextinfo", "linker", (unsigned long *) &symbol) == 0) { - ZzHookReplace(symbol, (void *) new_do_dlopen_V19, + MSHookFunction(symbol, (void *) new_do_dlopen_V19, (void **) &orig_do_dlopen_V19); } } else { if (findSymbol("__dl_dlopen", "linker", (unsigned long *) &symbol) == 0) { - ZzHookReplace(symbol, (void *) new_dlopen, (void **) &orig_dlopen); + MSHookFunction(symbol, (void *) new_dlopen, (void **) &orig_dlopen); } } } diff --git a/VirtualApp/lib/src/main/jni/Foundation/SandboxFs.cpp b/VirtualApp/lib/src/main/jni/Foundation/SandboxFs.cpp index f9c3f5a5b..9f352d20c 100644 --- a/VirtualApp/lib/src/main/jni/Foundation/SandboxFs.cpp +++ b/VirtualApp/lib/src/main/jni/Foundation/SandboxFs.cpp @@ -80,7 +80,7 @@ int get_replace_item_count() { return replace_item_count; } -inline bool match_path(bool is_folder, size_t size, char *item_path, char *path) { +inline bool match_path(bool is_folder, size_t size, const char *item_path, const char *path) { if (is_folder) { if (strlen(path) < size) { // ignore the last '/' @@ -91,18 +91,16 @@ inline bool match_path(bool is_folder, size_t size, char *item_path, char *path) } -const char *relocate_path(const char *_path, int *result) { - if (_path == NULL) { +const char *relocate_path(const char *path, int *result) { + if (path == NULL) { *result = NOT_MATCH; return NULL; } - char *path = canonicalize_filename(_path); for (int i = 0; i < keep_item_count; ++i) { PathItem &item = keep_items[i]; if (strcmp(item.path, path) == 0) { *result = KEEP; - free(path); - return _path; + return path; } } for (int i = 0; i < forbidden_item_count; ++i) { @@ -111,22 +109,27 @@ const char *relocate_path(const char *_path, int *result) { *result = FORBID; // Permission denied errno = 13; - free(path); return NULL; } } for (int i = 0; i < replace_item_count; ++i) { ReplaceItem &item = replace_items[i]; if (match_path(item.is_folder, item.orig_size, item.orig_path, path)) { - std::string redirect_path(item.new_path); - redirect_path += path + item.orig_size; *result = MATCH; - free(path); - return strdup(redirect_path.c_str()); + int len = strlen(path); + if (len < item.orig_size) { + //remove last / + std::string redirect_path(item.new_path, 0, item.new_size - 1); + return strdup(redirect_path.c_str()); + } else { + std::string redirect_path(item.new_path); + redirect_path += path + item.orig_size; + return strdup(redirect_path.c_str()); + } } } *result = NOT_MATCH; - return _path; + return path; } @@ -159,10 +162,18 @@ const char *reverse_relocate_path(const char *_path) { for (int i = 0; i < replace_item_count; ++i) { ReplaceItem &item = replace_items[i]; if (match_path(item.is_folder, item.new_size, item.new_path, path)) { - std::string reverse_path(item.orig_path); - reverse_path += path + item.new_size; - free(path); - return strdup(reverse_path.c_str()); + int len = strlen(path); + if (len < item.new_size) { + //remove last / + std::string reverse_path(item.orig_path, 0, item.orig_size - 1); + free(path); + return strdup(reverse_path.c_str()); + } else { + std::string reverse_path(item.orig_path); + reverse_path += path + item.new_size; + free(path); + return strdup(reverse_path.c_str()); + } } } return _path; diff --git a/VirtualApp/lib/src/main/jni/HookZz/.gitignore b/VirtualApp/lib/src/main/jni/HookZz/.gitignore index 5713f6d07..93f0552df 100644 --- a/VirtualApp/lib/src/main/jni/HookZz/.gitignore +++ b/VirtualApp/lib/src/main/jni/HookZz/.gitignore @@ -5,7 +5,6 @@ darwin.ios.release.mk .vscode/ cmake-build-debug/ MachoParser.xcworkspace/ -CMakeLists.txt # Prerequisites *.d diff --git a/VirtualApp/lib/src/main/jni/HookZz/Android.mk b/VirtualApp/lib/src/main/jni/HookZz/Android.mk index 7c0ff5671..e56863372 100644 --- a/VirtualApp/lib/src/main/jni/HookZz/Android.mk +++ b/VirtualApp/lib/src/main/jni/HookZz/Android.mk @@ -22,6 +22,9 @@ ifeq ($(TARGET_ARCH), arm) else ifeq ($(TARGET_ARCH), arm64) ZZ_SRC += $(wildcard $(LOCAL_PATH)/src/platforms/arch-arm64/*.c) \ $(wildcard $(LOCAL_PATH)/src/platforms/backend-arm64/*.c) +else ifeq ($(TARGET_ARCH), x86) + ZZ_SRC += $(wildcard $(LOCAL_PATH)/src/platforms/arch-x86/*.c) \ + $(wildcard $(LOCAL_PATH)/src/platforms/backend-x86/*.c) endif LOCAL_MODULE := hookzz diff --git a/VirtualApp/lib/src/main/jni/HookZz/Makefile b/VirtualApp/lib/src/main/jni/HookZz/Makefile index 5ad7f240e..a8cd29d72 100644 --- a/VirtualApp/lib/src/main/jni/HookZz/Makefile +++ b/VirtualApp/lib/src/main/jni/HookZz/Makefile @@ -8,7 +8,7 @@ HOOKZZ_DIR := $(abspath .) LOCAL_PATH := $(abspath .) OUTPUT_DIR := $(abspath build) -CFLAGS ?= -O0 -g -std=c99 +CFLAGS ?= -O0 -g CXXFLAGS = $(CFLAGS) -stdlib=libc++ -std=c++11 -gmodules LDFLAGS ?= LIBS_CFLAGS ?= -fPIC @@ -57,6 +57,32 @@ ifeq ($(BACKEND), ios) CFLAGS += -arch $(ZZ_ARCH) + ZZ_GCC_SOURCE := $(ZZ_GCC_BIN) -isysroot $(ZZ_SDK_ROOT) + ZZ_GXX_SOURCE := $(ZZ_GXX_BIN) -isysroot $(ZZ_SDK_ROOT) + ZZ_GCC_TEST := $(ZZ_GCC_BIN) -isysroot $(ZZ_SDK_ROOT) + ZZ_GXX_TEST := $(ZZ_GXX_BIN) -isysroot $(ZZ_SDK_ROOT) +else ifeq ($(BACKEND), macos) + ifeq ($(ARCH), x86) + ZZ_ARCH := i386 + else ifeq ($(ARCH), x86_64) + ZZ_ARCH := x86_64 + endif + + ZZ_BACKEND := macos + ZZ_GXX_BIN := $(shell xcrun --sdk macosx --find clang++) + ZZ_GCC_BIN := $(shell xcrun --sdk macosx --find clang) + ZZ_SDK_ROOT := $(shell xcrun --sdk macosx --show-sdk-path) + ZZ_AR_BIN := $(shell which ar) + ZZ_RANLIB_BIN := $(shell which ranlib) + + ZZ_DEPS_SRCS += $(wildcard $(ZZ_DEPS_PATH)/darwin/*.c) + ZZ_SRCS += $(wildcard $(ZZ_SRCS_PATH)/platforms/backend-darwin/*.c) + + ZZ_CFLAGS := -g -fPIC -shared -dynamiclib + ZZ_DLL := lib$(HOOKZZ_NAME).dylib + + CFLAGS += -arch $(ZZ_ARCH) + ZZ_GCC_SOURCE := $(ZZ_GCC_BIN) -isysroot $(ZZ_SDK_ROOT) ZZ_GXX_SOURCE := $(ZZ_GXX_BIN) -isysroot $(ZZ_SDK_ROOT) ZZ_GCC_TEST := $(ZZ_GCC_BIN) -isysroot $(ZZ_SDK_ROOT) @@ -68,19 +94,27 @@ else ifeq ($(BACKEND), android) ZZ_ARCH := armv7 ZZ_API_LEVEL := android-19 ZZ_CROSS_PREFIX := arm-linux-androideabi- + ZZ_BIN_CROSS_PREFIX := arm-linux-androideabi- else ifeq ($(ARCH), arm64) ZZ_ARCH := arm64 ZZ_API_LEVEL := android-21 ZZ_CROSS_PREFIX := aarch64-linux-android- + ZZ_BIN_CROSS_PREFIX := aarch64-linux-android- + else ifeq ($(ARCH), x86) + ZZ_ARCH := x86 + ZZ_API_LEVEL := android-21 + ZZ_CROSS_PREFIX := x86- + ZZ_BIN_CROSS_PREFIX := i686-linux-android- + endif HOST_DIR := $(shell echo $(HOST) | tr A-Z a-z)-$(HOST_ARCH) ZZ_NDK_HOME := $(shell dirname `which ndk-build`) ZZ_SDK_ROOT := $(ZZ_NDK_HOME)/platforms/$(ZZ_API_LEVEL)/arch-$(ARCH) - ZZ_GCC_BIN := $(ZZ_NDK_HOME)/toolchains/$(ZZ_CROSS_PREFIX)4.9/prebuilt/$(HOST_DIR)/bin/$(ZZ_CROSS_PREFIX)gcc - ZZ_GXX_BIN := $(ZZ_NDK_HOME)/toolchains/$(ZZ_CROSS_PREFIX)4.9/prebuilt/$(HOST_DIR)/bin/$(ZZ_CROSS_PREFIX)g++ - ZZ_AR_BIN := $(ZZ_NDK_HOME)/toolchains/$(ZZ_CROSS_PREFIX)4.9/prebuilt/$(HOST_DIR)/bin/$(ZZ_CROSS_PREFIX)ar - ZZ_RANLIB_BIN := $(ZZ_NDK_HOME)/toolchains/$(ZZ_CROSS_PREFIX)4.9/prebuilt/$(HOST_DIR)/bin/$(ZZ_CROSS_PREFIX)ranlib + ZZ_GCC_BIN := $(ZZ_NDK_HOME)/toolchains/$(ZZ_CROSS_PREFIX)4.9/prebuilt/$(HOST_DIR)/bin/$(ZZ_BIN_CROSS_PREFIX)gcc + ZZ_GXX_BIN := $(ZZ_NDK_HOME)/toolchains/$(ZZ_CROSS_PREFIX)4.9/prebuilt/$(HOST_DIR)/bin/$(ZZ_BIN_CROSS_PREFIX)g++ + ZZ_AR_BIN := $(ZZ_NDK_HOME)/toolchains/$(ZZ_CROSS_PREFIX)4.9/prebuilt/$(HOST_DIR)/bin/$(ZZ_BIN_CROSS_PREFIX)ar + ZZ_RANLIB_BIN := $(ZZ_NDK_HOME)/toolchains/$(ZZ_CROSS_PREFIX)4.9/prebuilt/$(HOST_DIR)/bin/$(ZZ_BIN_CROSS_PREFIX)ranlib ZZ_DEPS_SRCS += $(wildcard $(ZZ_DEPS_PATH)/linux/*.c) ZZ_SRCS += $(wildcard $(ZZ_SRCS_PATH)/platforms/backend-linux/*.c) diff --git a/VirtualApp/lib/src/main/jni/HookZz/README.md b/VirtualApp/lib/src/main/jni/HookZz/README.md index d051bc50e..c14c9889f 100644 --- a/VirtualApp/lib/src/main/jni/HookZz/README.md +++ b/VirtualApp/lib/src/main/jni/HookZz/README.md @@ -6,9 +6,11 @@ ref to: [frida-gum](https://github.com/frida/frida-gum) and [minhook](https://gi **special thanks to [frida-gum](https://github.com/frida/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 -- **inlinehook without Jailbreak [new-90%]** +- **solidify inlinehook without Jailbreak [new-90%]** - **GOT hook with HookZz(i.e. change fishhook to inlinehook), better for APM [new-0%]** @@ -22,7 +24,7 @@ ref to: [frida-gum](https://github.com/frida/frida-gum) and [minhook](https://gi - 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**) [arm64] +- (almost)only **one instruction** to hook(i.e. hook **short funciton, even only one instruction**) [arm/thumb/arm64] - runtime code patch, without codesign limit @@ -163,7 +165,7 @@ and check `build/android-armv7/*` #### `test_hook_printf.c` output for arm64-ios -test hook `printf` with `try_near_jump` option and `replace_call`, `pre_call`, `post_call` +test hook `printf` with `try_near_jump` option , and `ZzEnableDebugMode()` with `replace_call`, `pre_call`, `post_call`. ``` ZzThunkerBuildThunk: diff --git a/VirtualApp/lib/src/main/jni/HookZz/include/hookzz.h b/VirtualApp/lib/src/main/jni/HookZz/include/hookzz.h index 9d118699b..34eb953d5 100644 --- a/VirtualApp/lib/src/main/jni/HookZz/include/hookzz.h +++ b/VirtualApp/lib/src/main/jni/HookZz/include/hookzz.h @@ -100,7 +100,12 @@ typedef struct _RegState { zuint32 lr; } RegState; +#elif defined(__i386__) +typedef struct _RegState { +} RegState; #elif defined(__x86_64__) +typedef struct _RegState { +} RegState; #endif #endif diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/allocator.c b/VirtualApp/lib/src/main/jni/HookZz/src/allocator.c index deee6fcf2..2dbbe6ed4 100644 --- a/VirtualApp/lib/src/main/jni/HookZz/src/allocator.c +++ b/VirtualApp/lib/src/main/jni/HookZz/src/allocator.c @@ -144,8 +144,9 @@ ZZSTATUS ZzAddMemoryPage(ZzAllocator *allocator, ZzMemoryPage *page) { ZzCodeSlice *ZzNewCodeSlice(ZzAllocator *allocator, zsize code_slice_size) { ZzCodeSlice *code_slice = NULL; ZzMemoryPage *page = NULL; + int i; - for (int i = 0; i < allocator->size; i++) { + for (i = 0; i < allocator->size; i++) { page = allocator->memory_pages[i]; // 1. page is initialized // 2. can't be codecave @@ -195,8 +196,8 @@ ZzCodeSlice *ZzNewNearCodeSlice(ZzAllocator *allocator, zaddr address, zsize red zsize code_slice_size) { ZzCodeSlice *code_slice = NULL; ZzMemoryPage *page = NULL; - - for (int i = 0; i < allocator->size; i++) { + int i; + for (i = 0; i < allocator->size; i++) { page = allocator->memory_pages[i]; // 1. page is initialized // 2. can't be codecave diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/interceptor.c b/VirtualApp/lib/src/main/jni/HookZz/src/interceptor.c index c773cd822..4e513f0c8 100644 --- a/VirtualApp/lib/src/main/jni/HookZz/src/interceptor.c +++ b/VirtualApp/lib/src/main/jni/HookZz/src/interceptor.c @@ -15,24 +15,29 @@ */ #include +#include #include "interceptor.h" #include "trampoline.h" +#include "zzinfo.h" #define ZZHOOKENTRIES_DEFAULT 100 ZzInterceptor *g_interceptor = NULL; -ZZSTATUS -ZzInitializeInterceptor(void) { +ZZSTATUS ZzInitializeInterceptor(void) { ZzInterceptor *interceptor = g_interceptor; ZzHookFunctionEntrySet *hook_function_entry_set; if (NULL == interceptor) { interceptor = (ZzInterceptor *)malloc(sizeof(ZzInterceptor)); + memset(interceptor, 0, sizeof(ZzInterceptor)); + hook_function_entry_set = &(interceptor->hook_function_entry_set); hook_function_entry_set->capacity = ZZHOOKENTRIES_DEFAULT; hook_function_entry_set->entries = (ZzHookFunctionEntry **)malloc(sizeof(ZzHookFunctionEntry *) * hook_function_entry_set->capacity); + memset(hook_function_entry_set->entries, 0, sizeof(ZzHookFunctionEntry *) * hook_function_entry_set->capacity); + if (!hook_function_entry_set->entries) { return ZZ_FAILED; } @@ -58,7 +63,8 @@ ZzHookFunctionEntry *ZzFindHookFunctionEntry(zpointer target_ptr) { ZzHookFunctionEntrySet *hook_function_entry_set = &(interceptor->hook_function_entry_set); - for (int i = 0; i < hook_function_entry_set->size; ++i) { + int i; + for (i = 0; i < hook_function_entry_set->size; ++i) { if ((hook_function_entry_set->entries)[i] && target_ptr == (hook_function_entry_set->entries)[i]->target_ptr) { return (hook_function_entry_set->entries)[i]; } @@ -92,27 +98,24 @@ void ZzInitializeHookFunctionEntry(ZzHookFunctionEntry *entry, int hook_type, zp ZzInterceptor *interceptor = g_interceptor; ZzHookFunctionEntrySet *hook_function_entry_set = &(interceptor->hook_function_entry_set); + memset(entry, 0, sizeof(ZzHookFunctionEntry)); + entry->hook_type = hook_type; entry->id = hook_function_entry_set->size; entry->isEnabled = 0; entry->try_near_jump = try_near_jump; entry->interceptor = interceptor; - entry->target_ptr = target_ptr; entry->target_end_ptr = target_end_ptr; - entry->replace_call = replace_call; entry->pre_call = (zpointer)pre_call; entry->half_call = (zpointer)half_call; entry->post_call = (zpointer)post_call; - entry->on_enter_trampoline = NULL; entry->on_invoke_trampoline = NULL; entry->on_half_trampoline = NULL; entry->on_leave_trampoline = NULL; - entry->origin_prologue.address = target_ptr; - entry->thread_local_key = ZzThreadNewThreadLocalKeyPtr(); /* key function */ @@ -122,6 +125,10 @@ void ZzInitializeHookFunctionEntry(ZzHookFunctionEntry *entry, int hook_type, zp ZZSTATUS ZzBuildHook(zpointer target_ptr, zpointer replace_call_ptr, zpointer *origin_ptr, PRECALL pre_call_ptr, POSTCALL post_call_ptr, zbool try_near_jump) { +#if defined(__i386__) || defined(__x86_64__) + ZzInfoLog("%s", "x86 & x86_64 arch not support"); + return ZZ_FAILED; +#endif ZZSTATUS status = ZZ_DONE_HOOK; ZzInterceptor *interceptor = g_interceptor; @@ -148,6 +155,8 @@ ZZSTATUS ZzBuildHook(zpointer target_ptr, zpointer replace_call_ptr, zpointer *o } entry = (ZzHookFunctionEntry *)malloc(sizeof(ZzHookFunctionEntry)); + memset(entry, 0, sizeof(ZzHookFunctionEntry)); + ZzInitializeHookFunctionEntry(entry, HOOK_FUNCTION_TYPE, target_ptr, 0, replace_call_ptr, pre_call_ptr, NULL, post_call_ptr, try_near_jump); @@ -160,7 +169,10 @@ ZZSTATUS ZzBuildHook(zpointer target_ptr, zpointer replace_call_ptr, zpointer *o ZZSTATUS ZzBuildHookAddress(zpointer target_start_ptr, zpointer target_end_ptr, PRECALL pre_call_ptr, HALFCALL half_call_ptr, zbool try_near_jump) { - +#if defined(__i386__) || defined(__x86_64__) + ZzInfoLog("%s", "x86 & x86_64 arch not support"); + return ZZ_FAILED; +#endif ZZSTATUS status = ZZ_DONE_HOOK; ZzInterceptor *interceptor = g_interceptor; ZzHookFunctionEntrySet *hook_function_entry_set = NULL; @@ -186,6 +198,8 @@ ZZSTATUS ZzBuildHookAddress(zpointer target_start_ptr, zpointer target_end_ptr, } entry = (ZzHookFunctionEntry *)malloc(sizeof(ZzHookFunctionEntry)); + memset(entry, 0, sizeof(ZzHookFunctionEntry)); + ZzInitializeHookFunctionEntry(entry, HOOK_ADDRESS_TYPE, target_start_ptr, target_end_ptr, NULL, pre_call_ptr, half_call_ptr, NULL, try_near_jump); diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/interceptor.h b/VirtualApp/lib/src/main/jni/HookZz/src/interceptor.h index fa729c5f2..92c26fb57 100644 --- a/VirtualApp/lib/src/main/jni/HookZz/src/interceptor.h +++ b/VirtualApp/lib/src/main/jni/HookZz/src/interceptor.h @@ -50,7 +50,6 @@ struct _ZzInterceptor; struct _ZzHookFunctionEntryBackend; typedef struct _ZzHookFunctionEntry { int hook_type; - zbool isNearJump; unsigned long id; zbool isEnabled; zbool try_near_jump; diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/instructions.c b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/instructions.c index 6456bfdb1..00ec11d1c 100644 --- a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/instructions.c +++ b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/instructions.c @@ -1,5 +1,4 @@ #include "instructions.h" - #include zuint32 get_insn_sub(zuint32 insn, int start, int length) { return (insn >> start) & ((1 << length) - 1); } @@ -7,7 +6,8 @@ zuint32 get_insn_sub(zuint32 insn, int start, int length) { return (insn >> star zbool insn_equal(zuint32 insn, char *opstr) { zuint32 mask = 0, value = 0; zsize length = strlen(opstr); - for (int i = length - 1, j = 0; i >= 0 && j < length; i--, j++) { + int i, j; + for (i = length - 1, j = 0; i >= 0 && j < length; i--, j++) { if (opstr[i] == 'x') { mask = mask | (0 << j); } else if (opstr[i] == '0') { diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/instructions.h b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/instructions.h index 835aaa9a5..f8b41e269 100644 --- a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/instructions.h +++ b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/instructions.h @@ -39,6 +39,12 @@ typedef struct _Instruction { zuint16 insn2; } ZzInstruction; +typedef struct _ZzRelocateInstruction { + const ZzInstruction *insn_ctx; + zaddr relocated_offset; + zsize relocated_length; +} ZzRelocateInstruction; + zuint32 get_insn_sub(zuint32 insn, int start, int length); zbool insn_equal(zuint32 insn, char *opstr); diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/reader-arm.c b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/reader-arm.c index 834191b59..1274db44f 100644 --- a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/reader-arm.c +++ b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/reader-arm.c @@ -16,38 +16,7 @@ #include "reader-arm.h" -// static csh handle; - -// void zz_arm_reader_capstone_init(void) { -// cs_err err = 0; - -// err = cs_open(CS_ARCH_ARM, CS_MODE_ARM, &handle); -// if (err) { -// Xerror("Failed on cs_open() with error returned: %u\n", err); -// exit(-1); -// } - -// cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); -// } - -// cs_insn *zz_arm_reader_disassemble_at(zpointer address) { -// if (!handle) -// zz_arm_reader_capstone_init(); -// cs_insn *insn; -// size_t count; -// count = cs_disasm(handle, address, 16, (unsigned long)address, 0, &insn); -// if (!insn) { -// #if defined(DEBUG_MODE) -// debug_break(); -// #endif -// Xerror("zz_arm_reader_disassemble_at error at %p", (zpointer)address); -// } -// return insn; -// } - zpointer zz_arm_reader_read_one_instruction(ZzInstruction *insn_ctx, zpointer address) { - // ZzInstruction *insn = (ZzInstruction *)malloc(sizeof(ZzInstruction)); - insn_ctx->type = ARM_INSN; insn_ctx->address = (zaddr)address; insn_ctx->pc = (zaddr)address + 8; @@ -60,34 +29,30 @@ zpointer zz_arm_reader_read_one_instruction(ZzInstruction *insn_ctx, zpointer ad // A5 ARM Instruction Set Encoding // A5.3 Load/store word and unsigned byte ARMInsnType GetARMInsnType(zuint32 insn) { - zuint32 op, op1; - op1 = get_insn_sub(insn, 20, 5); - if (insn_equal(insn, "xxxx0000100xxxxxxxxxxxxxxxx0xxxx")) { + if (insn_equal(insn, "xxxx0000100xxxxxxxxxxxxxxxx0xxxx") && (get_insn_sub(insn, 28, 4) != 0xF)) { return ARM_INS_ADD_register_A1; } - if (insn_equal(insn, "xxxx0101x0011111xxxxxxxxxxxxxxxx")) { + if (insn_equal(insn, "xxxx0101x0011111xxxxxxxxxxxxxxxx") && (get_insn_sub(insn, 28, 4) != 0xF)) { return ARM_INS_LDR_literal_A1; } - if (insn_equal(insn, "xxxx001010001111xxxxxxxxxxxxxxxx")) { + if (insn_equal(insn, "xxxx001010001111xxxxxxxxxxxxxxxx") && (get_insn_sub(insn, 28, 4) != 0xF)) { return ARM_INS_ADR_A1; } - - if (insn_equal(insn, "xxxx001001001111xxxxxxxxxxxxxxxx")) { + if (insn_equal(insn, "xxxx001001001111xxxxxxxxxxxxxxxx") && (get_insn_sub(insn, 28, 4) != 0xF)) { return ARM_INS_ADR_A2; } - - if (insn_equal(insn, "xxxx1010xxxxxxxxxxxxxxxxxxxxxxxx")) { + if (insn_equal(insn, "xxxx1010xxxxxxxxxxxxxxxxxxxxxxxx") && (get_insn_sub(insn, 28, 4) != 0xF)) { return ARM_INS_B_A1; } - - if (insn_equal(insn, "xxxx1011xxxxxxxxxxxxxxxxxxxxxxxx")) { + if (insn_equal(insn, "xxxx1011xxxxxxxxxxxxxxxxxxxxxxxx") && (get_insn_sub(insn, 28, 4) != 0xF)) { return ARM_INS_BLBLX_immediate_A1; } if (insn_equal(insn, "1111101xxxxxxxxxxxxxxxxxxxxxxxxx")) { return ARM_INS_BLBLX_immediate_A2; } + return ARM_UNDEF; } \ No newline at end of file diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/reader-thumb.c b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/reader-thumb.c index 622ea6ddc..652433b79 100644 --- a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/reader-thumb.c +++ b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/reader-thumb.c @@ -16,35 +16,6 @@ #include "reader-thumb.h" -// static csh handle; - -// void zz_thumb_reader_capstone_init(void) { -// cs_err err = 0; - -// err = cs_open(CS_ARCH_ARM, CS_MODE_THUMB, &handle); -// if (err) { -// Xerror("Failed on cs_open() with error returned: %u\n", err); -// exit(-1); -// } - -// cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); -// } - -// cs_insn *zz_thumb_reader_disassemble_at(zpointer address) { -// if (!handle) -// zz_thumb_reader_capstone_init(); -// cs_insn *insn; -// size_t count; -// count = cs_disasm(handle, address, 16, (unsigned long)address, 0, &insn); -// if (!insn) { -// #if defined(DEBUG_MODE) -// debug_break(); -// #endif -// Xerror("zz_thumb_reader_disassemble_at error at %p", (zpointer)address); -// } -// return insn; -// } - zbool insn_is_thumb2(zuint32 insn) { // PAGE: A6-221 // PAGE: A6-230 @@ -81,55 +52,57 @@ zpointer zz_thumb_reader_read_one_instruction(ZzInstruction *insn_ctx, zpointer // ARM Manual // A5 ARM Instruction Set Encoding // A5.3 Load/store word and unsigned byte -THUMBInsnType GetTHUMBInsnType(zuint32 insn) { - // zuint32 insn = insn_ctx->insn; - zuint32 op, op1; +THUMBInsnType GetTHUMBInsnType(zuint16 insn1, zuint16 insn2) { + + if (!insn_is_thumb2(insn1) && insn_equal(insn1, "1011x0x1xxxxxxxx")) { + return THUMB_INS_CBNZ_CBZ; + } - if (!insn_is_thumb2(insn) && insn_equal(insn, "01000100xxxxxxxx")) { + if (!insn_is_thumb2(insn1) && insn_equal(insn1, "01000100xxxxxxxx")) { return THUMB_INS_ADD_register_T2; } - if (!insn_is_thumb2(insn) && insn_equal(insn, "01001xxxxxxxxxxx")) { + if (!insn_is_thumb2(insn1) && insn_equal(insn1, "01001xxxxxxxxxxx")) { return THUMB_INS_LDR_literal_T1; } - if (insn_is_thumb2(insn) && insn_equal(insn, "11111000x1011111xxxxxxxxxxxxxxxx")) { + if (insn_is_thumb2(insn1) && insn_equal(insn1, "11111000x1011111") && insn_equal(insn2, "xxxxxxxxxxxxxxxx")) { return THUMB_INS_LDR_literal_T2; } - if (!insn_is_thumb2(insn) && insn_equal(insn, "10100xxxxxxxxxxx")) { + if (!insn_is_thumb2(insn1) && insn_equal(insn1, "10100xxxxxxxxxxx")) { return THUMB_INS_ADR_T1; } - if (insn_is_thumb2(insn) && insn_equal(insn, "11110x10101011110xxxxxxxxxxxxxxx")) { + if (insn_is_thumb2(insn1) && insn_equal(insn1, "11110x1010101111") && insn_equal(insn2, "0xxxxxxxxxxxxxxx")) { return THUMB_INS_ADR_T2; } - if (insn_is_thumb2(insn) && insn_equal(insn, "11110x10000011110xxxxxxxxxxxxxxx")) { + if (insn_is_thumb2(insn1) && insn_equal(insn1, "11110x1000001111") && insn_equal(insn2, "0xxxxxxxxxxxxxxx")) { return THUMB_INS_ADR_T3; } - if (!insn_is_thumb2(insn) && insn_equal(insn, "1101xxxxxxxxxxxx")) { + if (!insn_is_thumb2(insn1) && insn_equal(insn1, "1101xxxxxxxxxxxx")) { return THUMB_INS_B_T1; } - if (!insn_is_thumb2(insn) && insn_equal(insn, "11100xxxxxxxxxxx")) { + if (!insn_is_thumb2(insn1) && insn_equal(insn1, "11100xxxxxxxxxxx")) { return THUMB_INS_B_T2; } - if (insn_is_thumb2(insn) && insn_equal(insn, "11110xxxxxxxxxxx10x0xxxxxxxxxxxx")) { + if (insn_is_thumb2(insn1) && insn_equal(insn1, "11110xxxxxxxxxxx") && insn_equal(insn2, "10x0xxxxxxxxxxxx")) { return THUMB_INS_B_T3; } - if (insn_is_thumb2(insn) && insn_equal(insn, "11110xxxxxxxxxxx10x0xxxxxxxxxxxx")) { + if (insn_is_thumb2(insn1) && insn_equal(insn1, "11110xxxxxxxxxxx") && insn_equal(insn2, "10x1xxxxxxxxxxxx")) { return THUMB_INS_B_T4; } - if (insn_is_thumb2(insn) && insn_equal(insn, "11110xxxxxxxxxxx11x1xxxxxxxxxxxx")) { + if (insn_is_thumb2(insn1) && insn_equal(insn1, "11110xxxxxxxxxxx") && insn_equal(insn2, "11x1xxxxxxxxxxxx")) { return THUMB_INS_BLBLX_immediate_T1; } - if (insn_is_thumb2(insn) && insn_equal(insn, "11110xxxxxxxxxxx11x0xxxxxxxxxxxx")) { + if (insn_is_thumb2(insn1) && insn_equal(insn1, "11110xxxxxxxxxxx") && insn_equal(insn2, "11x0xxxxxxxxxxxx")) { return THUMB_INS_BLBLX_immediate_T2; } diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/reader-thumb.h b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/reader-thumb.h index 883bdb6d4..3d1dee803 100644 --- a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/reader-thumb.h +++ b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/reader-thumb.h @@ -27,6 +27,7 @@ #include "zzdeps/zz.h" typedef enum _THUMBInsnType { + THUMB_INS_CBNZ_CBZ, THUMB_INS_ADD_register_T2, THUMB_INS_LDR_literal_T1, THUMB_INS_LDR_literal_T2, @@ -42,7 +43,7 @@ typedef enum _THUMBInsnType { THUMB_UNDEF } THUMBInsnType; -THUMBInsnType GetTHUMBInsnType(zuint32 insn); +THUMBInsnType GetTHUMBInsnType(zuint16 insn1, zuint16 insn2); zpointer zz_thumb_reader_read_one_instruction(ZzInstruction *insn_ctx, zpointer address); #endif \ No newline at end of file diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/relocator-arm.c b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/relocator-arm.c index 25d2fa83f..ca7c55838 100644 --- a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/relocator-arm.c +++ b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/relocator-arm.c @@ -24,31 +24,43 @@ void zz_arm_relocator_init(ZzArmRelocator *relocator, zpointer input_code, ZzArmWriter *output) { relocator->inpos = 0; relocator->outpos = 0; - relocator->input_start = input_code; relocator->input_cur = input_code; relocator->input_pc = (zaddr)input_code; + relocator->output = output; + relocator->relocate_literal_insns_size = 0; + relocator->try_relocated_length = 0; relocator->input_insns = (ZzInstruction *)malloc(MAX_RELOCATOR_INSTRUCIONS_SIZE * sizeof(ZzInstruction)); memset(relocator->input_insns, 0, MAX_RELOCATOR_INSTRUCIONS_SIZE * sizeof(ZzInstruction)); - - relocator->output = output; + relocator->output_insns = + (ZzRelocateInstruction *)malloc(MAX_RELOCATOR_INSTRUCIONS_SIZE * sizeof(ZzRelocateInstruction)); + memset(relocator->output_insns, 0, MAX_RELOCATOR_INSTRUCIONS_SIZE * sizeof(ZzRelocateInstruction)); + relocator->relocate_literal_insns = + (ZzLiteralInstruction **)malloc(MAX_LITERAL_INSN_SIZE * sizeof(ZzLiteralInstruction *)); + memset(relocator->relocate_literal_insns, 0, MAX_LITERAL_INSN_SIZE * sizeof(ZzLiteralInstruction *)); } void zz_arm_relocator_reset(ZzArmRelocator *self, zpointer input_code, ZzArmWriter *output) { self->input_cur = input_code; self->input_start = input_code; self->input_pc = (zaddr)input_code; - self->inpos = 0; self->outpos = 0; - self->output = output; + self->relocate_literal_insns_size = 0; + self->try_relocated_length = 0; + + memset(self->input_insns, 0, MAX_RELOCATOR_INSTRUCIONS_SIZE * sizeof(ZzInstruction)); + memset(self->output_insns, 0, MAX_RELOCATOR_INSTRUCIONS_SIZE * sizeof(ZzRelocateInstruction)); + memset(self->relocate_literal_insns, 0, MAX_LITERAL_INSN_SIZE * sizeof(ZzLiteralInstruction *)); } zsize zz_arm_relocator_read_one(ZzArmRelocator *self, ZzInstruction *instruction) { ZzInstruction *insn_ctx = &self->input_insns[self->inpos]; + ZzRelocateInstruction *re_insn_ctx = &self->output_insns[self->inpos]; + re_insn_ctx->insn_ctx = insn_ctx; zz_arm_reader_read_one_instruction(insn_ctx, self->input_cur); // switch (1) {} @@ -64,17 +76,76 @@ zsize zz_arm_relocator_read_one(ZzArmRelocator *self, ZzInstruction *instruction return self->input_cur - self->input_start; } void zz_arm_relocator_try_relocate(zpointer address, zuint min_bytes, zuint *max_bytes) { - *max_bytes = 16; + int tmp_size = 0; + zpointer target_addr; + ZzInstruction insn_ctx; + zbool early_end = FALSE; + target_addr = (zpointer)address; + + do { + zz_arm_reader_read_one_instruction(&insn_ctx, target_addr); + switch (GetARMInsnType(insn_ctx.insn)) { + case ARM_INS_B_A1: { + zuint32 cond = get_insn_sub(insn_ctx.insn, 28, 4); + if (cond == 0xE) + early_end = TRUE; + }; break; + default:; + } + tmp_size += insn_ctx.size; + target_addr = target_addr + insn_ctx.size; + } while (tmp_size < min_bytes); + + if (early_end) { + *max_bytes = tmp_size; + } return; } +zaddr zz_arm_relocator_get_insn_relocated_offset(ZzArmRelocator *self, zaddr address) { + const ZzInstruction *insn_ctx; + const ZzRelocateInstruction *re_insn_ctx; + int i; + for (i = 0; i < self->inpos; i++) { + re_insn_ctx = &self->output_insns[i]; + insn_ctx = re_insn_ctx->insn_ctx; + if (insn_ctx->address == address && re_insn_ctx->relocated_offset) { + return re_insn_ctx->relocated_offset; + } + } + return 0; +} + +void zz_arm_relocator_relocate_writer(ZzArmRelocator *relocator, zaddr code_address) { + ZzArmWriter *arm_writer; + arm_writer = relocator->output; + if (relocator->relocate_literal_insns_size) { + int i; + zaddr literal_address, relocated_offset, relocated_address, *literal_address_ptr; + for (i = 0; i < relocator->relocate_literal_insns_size; i++) { + literal_address_ptr = (zaddr *)relocator->relocate_literal_insns[i]->literal_address_ptr; + literal_address = *literal_address_ptr; + relocated_offset = zz_arm_relocator_get_insn_relocated_offset(relocator, literal_address); + if (relocated_offset) { + relocated_address = code_address + relocated_offset; + *literal_address_ptr = relocated_address; + } + } + } +} + void zz_arm_relocator_write_all(ZzArmRelocator *self) { zuint count = 0; + zuint outpos = self->outpos; + ZzArmWriter arm_writer = *self->output; + while (zz_arm_relocator_write_one(self)) count++; } + // PAGE: A8-312 -static zbool zz_arm_relocator_rewrite_ADD_register_A1(ZzArmRelocator *self, const ZzInstruction *insn_ctx) { +static zbool zz_arm_relocator_rewrite_ADD_register_A1(ZzArmRelocator *self, const ZzInstruction *insn_ctx, + ZzRelocateInstruction *re_insn_ctx) { zuint32 insn = insn_ctx->insn; zuint32 Rn_ndx, Rd_ndx, Rm_ndx; @@ -86,19 +157,20 @@ static zbool zz_arm_relocator_rewrite_ADD_register_A1(ZzArmRelocator *self, cons return FALSE; } // push R7 - zz_arm_writer_put_push_reg(self->output, 1 << 7); + zz_arm_writer_put_push_reg(self->output, ZZ_ARM_REG_R7); zz_arm_writer_put_ldr_b_reg_address(self->output, ZZ_ARM_REG_R7, insn_ctx->pc); - zz_arm_writer_put_instruction(self->output, (insn & 0xFFFF0FFF) | ZZ_ARM_REG_R7 << 16); + zz_arm_writer_put_instruction(self->output, (insn & 0xFFF0FFFF) | ZZ_ARM_REG_R7 << 16); // pop R7 - zz_arm_writer_put_pop_reg(self->output, 1 << 7); + zz_arm_writer_put_pop_reg(self->output, ZZ_ARM_REG_R7); return TRUE; } // PAGE: A8-410 -static zbool zz_arm_relocator_rewrite_LDR_literal_A1(ZzArmRelocator *self, const ZzInstruction *insn_ctx) { +static zbool zz_arm_relocator_rewrite_LDR_literal_A1(ZzArmRelocator *self, const ZzInstruction *insn_ctx, + ZzRelocateInstruction *re_insn_ctx) { zuint32 insn = insn_ctx->insn; zuint32 imm12 = get_insn_sub(insn, 0, 12); - zuint32 imm32 = imm12 << 2; + zuint32 imm32 = imm12; zbool add = get_insn_sub(insn, 7 + 16, 1) == 1; zaddr target_address; if (add) @@ -109,100 +181,155 @@ static zbool zz_arm_relocator_rewrite_LDR_literal_A1(ZzArmRelocator *self, const zz_arm_writer_put_ldr_b_reg_address(self->output, Rt_ndx, target_address); zz_arm_writer_put_ldr_reg_reg_imm(self->output, Rt_ndx, Rt_ndx, 0); + return TRUE; } // PAGE: A8-322 -static zbool zz_arm_relocator_rewrite_ADR_A1(ZzArmRelocator *self, const ZzInstruction *insn_ctx) { +static zbool zz_arm_relocator_rewrite_ADR_A1(ZzArmRelocator *self, const ZzInstruction *insn_ctx, + ZzRelocateInstruction *re_insn_ctx) { zuint32 insn = insn_ctx->insn; zuint32 imm12 = get_insn_sub(insn, 0, 12); - zuint32 imm32 = imm12 << 2; + zuint32 imm32 = imm12; zaddr target_address; target_address = insn_ctx->pc + imm32; int Rt_ndx = get_insn_sub(insn, 12, 4); + zz_arm_writer_put_ldr_b_reg_address(self->output, Rt_ndx, target_address); + return TRUE; } // PAGE: A8-322 -static zbool zz_arm_relocator_rewrite_ADR_A2(ZzArmRelocator *self, const ZzInstruction *insn_ctx) { +static zbool zz_arm_relocator_rewrite_ADR_A2(ZzArmRelocator *self, const ZzInstruction *insn_ctx, + ZzRelocateInstruction *re_insn_ctx) { zuint32 insn = insn_ctx->insn; zuint32 imm12 = get_insn_sub(insn, 0, 12); - zuint32 imm32 = imm12 << 2; + zuint32 imm32 = imm12; zaddr target_address; target_address = insn_ctx->pc - imm32; int Rt_ndx = get_insn_sub(insn, 12, 4); + zz_arm_writer_put_ldr_b_reg_address(self->output, Rt_ndx, target_address); + return TRUE; } +// 0x000 : b.cond 0x0; +// 0x004 : b 0x4 +// 0x008 : ldr pc, [pc, #0] +// 0x00c : .long 0x0 +// 0x010 : remain code + // PAGE: A8-334 -static zbool zz_arm_relocator_rewrite_B_A1(ZzArmRelocator *self, const ZzInstruction *insn_ctx) { +static zbool zz_arm_relocator_rewrite_B_A1(ZzArmRelocator *self, const ZzInstruction *insn_ctx, + ZzRelocateInstruction *re_insn_ctx) { zuint32 insn = insn_ctx->insn; zuint32 imm24 = get_insn_sub(insn, 0, 24); zuint32 imm32 = imm24 << 2; zaddr target_address; target_address = insn_ctx->pc + imm32; + + zz_arm_writer_put_instruction(self->output, (insn & 0xFF000000) | 0); + zz_arm_writer_put_b_imm(self->output, 0x4); zz_arm_writer_put_ldr_reg_address(self->output, ZZ_ARM_REG_PC, target_address); + return TRUE; } +// 0x000 : bl.cond 0x0; + +// 0x004 : b 0x10 + +// 0x008 : ldr lr, [pc, #0] +// 0x00c : b 0x0 +// 0x010 : .long 0x0 + +// 0x014 : ldr pc, [pc, #0] +// 0x018 : .long 0x0 + +// 0x01c : remain code + // PAGE: A8-348 -static zbool zz_arm_relocator_rewrite_BLBLX_immediate_A1(ZzArmRelocator *self, const ZzInstruction *insn_ctx) { +static zbool zz_arm_relocator_rewrite_BLBLX_immediate_A1(ZzArmRelocator *self, const ZzInstruction *insn_ctx, + ZzRelocateInstruction *re_insn_ctx) { zuint32 insn = insn_ctx->insn; zuint32 imm24 = get_insn_sub(insn, 0, 24); zuint32 imm32 = imm24 << 2; zaddr target_address; - target_address = insn_ctx->pc + imm32; - zz_arm_writer_put_ldr_b_reg_address(self->output, ZZ_ARM_REG_LR, insn_ctx->pc + 2 * 4); + target_address = ALIGN_4(insn_ctx->pc) + imm32; + + // CurrentInstrSet = thumb + // targetInstrSet = arm + + // convert 'bl' to 'b', but save 'cond' + zz_arm_writer_put_instruction(self->output, (insn & 0xF0000000) | 0b1010 << 24 | 0); + + ZzArmWriter ouput_bak = *self->output; + + zz_arm_writer_put_b_imm(self->output, 0); + ZzLiteralInstruction **literal_insn_ptr = &(self->relocate_literal_insns[self->relocate_literal_insns_size++]); + zz_arm_writer_put_ldr_b_reg_relocate_address(self->output, ZZ_ARM_REG_LR, insn_ctx->pc - 4, literal_insn_ptr); zz_arm_writer_put_ldr_reg_address(self->output, ZZ_ARM_REG_PC, target_address); + + // overwrite `zz_arm_writer_put_b_imm` + zz_arm_writer_put_b_imm(&ouput_bak, self->output->pc - ouput_bak.pc - 8); return TRUE; } // PAGE: A8-348 -static zbool zz_arm_relocator_rewrite_BLBLX_immediate_A2(ZzArmRelocator *self, const ZzInstruction *insn_ctx) { +static zbool zz_arm_relocator_rewrite_BLBLX_immediate_A2(ZzArmRelocator *self, const ZzInstruction *insn_ctx, + ZzRelocateInstruction *re_insn_ctx) { zuint32 insn = insn_ctx->insn; zuint32 H = get_insn_sub(insn, 24, 1); zuint32 imm24 = get_insn_sub(insn, 0, 24); zuint32 imm32 = (imm24 << 2) | (H << 1); zaddr target_address; target_address = insn_ctx->pc + imm32; - zz_arm_writer_put_ldr_b_reg_address(self->output, ZZ_ARM_REG_LR, insn_ctx->pc + 2 * 4); + + ZzLiteralInstruction **literal_insn_ptr = &(self->relocate_literal_insns[self->relocate_literal_insns_size++]); + zz_arm_writer_put_ldr_b_reg_relocate_address(self->output, ZZ_ARM_REG_LR, insn_ctx->pc - 4, literal_insn_ptr); zz_arm_writer_put_ldr_reg_address(self->output, ZZ_ARM_REG_PC, target_address); + return TRUE; } zbool zz_arm_relocator_write_one(ZzArmRelocator *self) { const ZzInstruction *insn_ctx; + ZzRelocateInstruction *re_insn_ctx; zbool rewritten = FALSE; if (self->inpos != self->outpos) { insn_ctx = &self->input_insns[self->outpos]; + re_insn_ctx = &self->output_insns[self->outpos]; + self->outpos++; } else return FALSE; + re_insn_ctx->relocated_offset = (zaddr)self->output->pc - (zaddr)self->output->base; + switch (GetARMInsnType(insn_ctx->insn)) { case ARM_INS_ADD_register_A1: - rewritten = zz_arm_relocator_rewrite_ADD_register_A1(self, insn_ctx); + rewritten = zz_arm_relocator_rewrite_ADD_register_A1(self, insn_ctx, re_insn_ctx); break; case ARM_INS_LDR_literal_A1: - rewritten = zz_arm_relocator_rewrite_LDR_literal_A1(self, insn_ctx); + rewritten = zz_arm_relocator_rewrite_LDR_literal_A1(self, insn_ctx, re_insn_ctx); break; case ARM_INS_ADR_A1: - rewritten = zz_arm_relocator_rewrite_ADR_A1(self, insn_ctx); + rewritten = zz_arm_relocator_rewrite_ADR_A1(self, insn_ctx, re_insn_ctx); break; case ARM_INS_ADR_A2: - rewritten = zz_arm_relocator_rewrite_ADR_A2(self, insn_ctx); + rewritten = zz_arm_relocator_rewrite_ADR_A2(self, insn_ctx, re_insn_ctx); break; case ARM_INS_B_A1: - rewritten = zz_arm_relocator_rewrite_B_A1(self, insn_ctx); + rewritten = zz_arm_relocator_rewrite_B_A1(self, insn_ctx, re_insn_ctx); break; case ARM_INS_BLBLX_immediate_A1: - rewritten = zz_arm_relocator_rewrite_BLBLX_immediate_A1(self, insn_ctx); + rewritten = zz_arm_relocator_rewrite_BLBLX_immediate_A1(self, insn_ctx, re_insn_ctx); break; case ARM_INS_BLBLX_immediate_A2: - rewritten = zz_arm_relocator_rewrite_BLBLX_immediate_A2(self, insn_ctx); + rewritten = zz_arm_relocator_rewrite_BLBLX_immediate_A2(self, insn_ctx, re_insn_ctx); break; case ARM_UNDEF: rewritten = FALSE; @@ -210,71 +337,8 @@ zbool zz_arm_relocator_write_one(ZzArmRelocator *self) { } if (!rewritten) zz_arm_writer_put_bytes(self->output, (zbyte *)&insn_ctx->insn, insn_ctx->size); + + re_insn_ctx->relocated_length = + (zaddr)self->output->pc - (zaddr)self->output->base - (zaddr)re_insn_ctx->relocated_offset; return TRUE; } - -// static zbool zz_arm_relocator_rewrite_ldr(ZzArmRelocator *self, const ZzInstruction *insn_ctx) { - -// const cs_arm_op *dst = &insn_ctx->detail->operands[0]; -// const cs_arm_op *src = &insn_ctx->detail->operands[1]; -// zint disp; - -// if (src->type != ARM_OP_MEM || src->mem.base != ARM_REG_PC) -// return TRUE; - -// disp = src->mem.disp; - -// zz_arm_writer_put_ldr_b_reg_address(self->output, dst->reg, insn_ctx->pc); -// if (disp > 0xff) { -// zz_arm_writer_put_add_reg_reg_imm(self->output, dst->reg, dst->reg, 0xc00 | ((disp >> 8) & 0xff)); -// } -// zz_arm_writer_put_add_reg_reg_imm(self->output, dst->reg, dst->reg, disp & 0xff); -// zz_arm_writer_put_ldr_reg_reg_imm(self->output, dst->reg, dst->reg, 0); - -// return TRUE; -// } - -// static zbool zz_arm_relocator_rewrite_add(ZzArmRelocator *self, const ZzInstruction *insn_ctx) { -// const cs_arm_op *dst = &insn_ctx->detail->operands[0]; -// const cs_arm_op *left = &insn_ctx->detail->operands[1]; -// const cs_arm_op *right = &insn_ctx->detail->operands[2]; - -// if (left->reg != ARM_REG_PC || right->type != ARM_OP_REG) -// return FALSE; - -// if (right->reg == dst->reg) { -// zz_arm_writer_put_add_reg_reg_imm(self->output, dst->reg, dst->reg, insn_ctx->pc & 0xff); -// zz_arm_writer_put_add_reg_reg_imm(self->output, dst->reg, dst->reg, 0xc00 | ((insn_ctx->pc >> 8) & 0xff)); -// zz_arm_writer_put_add_reg_reg_imm(self->output, dst->reg, dst->reg, 0x800 | ((insn_ctx->pc >> 16) & 0xff)); -// zz_arm_writer_put_add_reg_reg_imm(self->output, dst->reg, dst->reg, 0x400 | ((insn_ctx->pc >> 24) & 0xff)); -// } else { -// zz_arm_writer_put_ldr_reg_address(self->output, dst->reg, insn_ctx->pc); -// zz_arm_writer_put_add_reg_reg_imm(self->output, dst->reg, right->reg, 0); -// } - -// return TRUE; -// } - -// static zbool zz_arm_relocator_rewrite_b(ZzArmRelocator *self, cs_mode target_mode, ZzInstruction *insn_ctx) { -// cs_insn *insn_cs = insn_ctx->insn_cs; -// const cs_arm_op *target = &insn_ctx->detail->operands[0]; - -// if (target->type != ARM_OP_IMM) -// return FALSE; - -// zz_arm_writer_put_ldr_reg_address(self->output, ARM_REG_PC, -// (target_mode == CS_MODE_THUMB) ? target->imm | 1 : target->imm); -// return TRUE; -// } - -// static zbool zz_arm_relocator_rewrite_bl(ZzArmRelocator *self, cs_mode target_mode, ZzInstruction *insn_ctx) { -// const cs_arm_op *target = &insn_ctx->detail->operands[0]; - -// if (target->type != ARM_OP_IMM) -// return FALSE; - -// zz_arm_writer_put_ldr_reg_address(self->output, ARM_REG_LR, (zaddr)self->output->pc + (2 * 4)); -// zz_arm_writer_put_ldr_reg_address(self->output, ARM_REG_PC, -// (target_mode == CS_MODE_THUMB) ? target->imm | 1 : target->imm); -// return TRUE; -// } \ No newline at end of file diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/relocator-arm.h b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/relocator-arm.h index f8df420e9..a1ee866ed 100644 --- a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/relocator-arm.h +++ b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/relocator-arm.h @@ -33,14 +33,18 @@ #include "zzdeps/zz.h" typedef struct _ZzArmRelocator { + zbool try_relocated_again; + zsize try_relocated_length; zpointer input_start; zpointer input_cur; zaddr input_pc; - ZzInstruction *input_insns; - ZzArmWriter *output; - zuint inpos; zuint outpos; + ZzInstruction *input_insns; + ZzRelocateInstruction *output_insns; + ZzLiteralInstruction **relocate_literal_insns; + zsize relocate_literal_insns_size; + ZzArmWriter *output; } ZzArmRelocator; void zz_arm_relocator_init(ZzArmRelocator *relocator, zpointer input_code, ZzArmWriter *output); @@ -49,4 +53,5 @@ void zz_arm_relocator_write_all(ZzArmRelocator *self); zsize zz_arm_relocator_read_one(ZzArmRelocator *self, ZzInstruction *instruction); void zz_arm_relocator_try_relocate(zpointer address, zuint min_bytes, zuint *max_bytes); zbool zz_arm_relocator_write_one(ZzArmRelocator *self); +void zz_arm_relocator_relocate_writer(ZzArmRelocator *relocator, zaddr code_address); #endif \ No newline at end of file diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/relocator-thumb.c b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/relocator-thumb.c index 30c8fbbb3..f56f71f5e 100644 --- a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/relocator-thumb.c +++ b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/relocator-thumb.c @@ -21,31 +21,49 @@ #define MAX_RELOCATOR_INSTRUCIONS_SIZE 64 -void zz_thumb_relocator_init(ZzThumbRelocator *relocator, zpointer input_code, ZzThumbWriter *writer) { +void zz_thumb_relocator_init(ZzThumbRelocator *relocator, zpointer input_code, ZzThumbWriter *output) { + + memset(relocator, 0, sizeof(ZzThumbRelocator)); + relocator->inpos = 0; relocator->outpos = 0; - relocator->input_start = input_code; relocator->input_cur = input_code; relocator->input_pc = (zaddr)input_code; + relocator->output = output; + relocator->relocate_literal_insns_size = 0; + relocator->try_relocated_length = 0; + relocator->input_insns = (ZzInstruction *)malloc(MAX_RELOCATOR_INSTRUCIONS_SIZE * sizeof(ZzInstruction)); memset(relocator->input_insns, 0, MAX_RELOCATOR_INSTRUCIONS_SIZE * sizeof(ZzInstruction)); + relocator->output_insns = + (ZzRelocateInstruction *)malloc(MAX_RELOCATOR_INSTRUCIONS_SIZE * sizeof(ZzRelocateInstruction)); + memset(relocator->output_insns, 0, MAX_RELOCATOR_INSTRUCIONS_SIZE * sizeof(ZzRelocateInstruction)); + relocator->relocate_literal_insns = + (ZzLiteralInstruction **)malloc(MAX_LITERAL_INSN_SIZE * sizeof(ZzLiteralInstruction *)); + memset(relocator->relocate_literal_insns, 0, MAX_LITERAL_INSN_SIZE * sizeof(ZzLiteralInstruction *)); } void zz_thumb_relocator_reset(ZzThumbRelocator *self, zpointer input_code, ZzThumbWriter *output) { self->input_cur = input_code; self->input_start = input_code; self->input_pc = (zaddr)input_code; - self->inpos = 0; self->outpos = 0; - self->output = output; + self->relocate_literal_insns_size = 0; + self->try_relocated_length = 0; + + memset(self->input_insns, 0, MAX_RELOCATOR_INSTRUCIONS_SIZE * sizeof(ZzInstruction)); + memset(self->output_insns, 0, MAX_RELOCATOR_INSTRUCIONS_SIZE * sizeof(ZzRelocateInstruction)); + memset(self->relocate_literal_insns, 0, MAX_LITERAL_INSN_SIZE * sizeof(ZzLiteralInstruction *)); } zsize zz_thumb_relocator_read_one(ZzThumbRelocator *self, ZzInstruction *instruction) { ZzInstruction *insn_ctx = &self->input_insns[self->inpos]; + ZzRelocateInstruction *re_insn_ctx = &self->output_insns[self->inpos]; + re_insn_ctx->insn_ctx = insn_ctx; zz_thumb_reader_read_one_instruction(insn_ctx, self->input_cur); // switch (1) {} @@ -53,7 +71,7 @@ zsize zz_thumb_relocator_read_one(ZzThumbRelocator *self, ZzInstruction *instruc self->inpos++; if (instruction != NULL) - instruction = insn_ctx; + *instruction = *insn_ctx; self->input_cur += insn_ctx->size; self->input_pc += insn_ctx->size; @@ -62,18 +80,123 @@ zsize zz_thumb_relocator_read_one(ZzThumbRelocator *self, ZzInstruction *instruc } void zz_thumb_relocator_try_relocate(zpointer address, zuint min_bytes, zuint *max_bytes) { - *max_bytes = 16; + int tmp_size = 0; + zbool is_thumb; + zpointer target_addr; + ZzInstruction insn_ctx; + zbool early_end = FALSE; + is_thumb = INSTRUCTION_IS_THUMB((zaddr)address); + target_addr = (zpointer)address; + + do { + zz_thumb_reader_read_one_instruction(&insn_ctx, target_addr); + switch (GetTHUMBInsnType(insn_ctx.insn1, insn_ctx.insn2)) { + case THUMB_INS_B_T2: + early_end = TRUE; + break; + case THUMB_INS_B_T4: + early_end = TRUE; + break; + default:; + } + tmp_size += insn_ctx.size; + target_addr = target_addr + insn_ctx.size; + } while (tmp_size < min_bytes); + + if (early_end) { + *max_bytes = tmp_size; + } return; } +zaddr zz_thumb_relocator_get_insn_relocated_offset(ZzThumbRelocator *self, zaddr address) { + const ZzInstruction *insn_ctx; + const ZzRelocateInstruction *re_insn_ctx; + int i; + + for (i = 0; i < self->inpos; i++) { + re_insn_ctx = &self->output_insns[i]; + insn_ctx = re_insn_ctx->insn_ctx; + if (insn_ctx->address == address && re_insn_ctx->relocated_offset) { + return re_insn_ctx->relocated_offset; + } + } + return 0; +} + +void zz_thumb_relocator_relocate_writer(ZzThumbRelocator *relocator, zaddr code_address) { + ZzThumbWriter *thumb_writer; + thumb_writer = relocator->output; + if (relocator->relocate_literal_insns_size) { + int i; + zaddr literal_address, relocated_offset, relocated_address, *literal_address_ptr; + for (i = 0; i < relocator->relocate_literal_insns_size; i++) { + literal_address_ptr = (zaddr *)relocator->relocate_literal_insns[i]->literal_address_ptr; + literal_address = *literal_address_ptr; + relocated_offset = zz_thumb_relocator_get_insn_relocated_offset(relocator, literal_address & ~(zaddr)1); + if (relocated_offset) { + relocated_address = code_address + relocated_offset + 1; + *literal_address_ptr = relocated_address; + } + } + } +} + void zz_thumb_relocator_write_all(ZzThumbRelocator *self) { zuint count = 0; + zuint outpos = self->outpos; + ZzThumbWriter thumb_writer = *self->output; while (zz_thumb_relocator_write_one(self)) count++; } +// A8-357 +// 0: cbz #0 +// 2: b #6 +// 4: ldr pc, #0 +// 8: .long ? +// c: next insn +static zbool zz_thumb_relocator_rewrite_CBNZ_CBZ(ZzThumbRelocator *self, const ZzInstruction *insn_ctx, + ZzRelocateInstruction *re_insn_ctx) { + + zuint32 insn1 = insn_ctx->insn1; + zuint16 op, i, imm5, Rn_ndx; + zuint32 imm32, nonzero; + + op = get_insn_sub(insn1, 11, 1); + i = get_insn_sub(insn1, 9, 1); + imm5 = get_insn_sub(insn1, 3, 5); + Rn_ndx = get_insn_sub(insn1, 0, 3); + + imm32 = imm5 << 1 | i << (5 + 1); + nonzero = (op == 1); + + zaddr target_address = insn_ctx->pc + imm32; + + /* for align , simple solution, maybe the correct solution is get `ldr_reg_address` length and adjust the immediate + * of `b_imm`. */ + if ((zaddr)self->output->pc % 4) { + zz_thumb_writer_put_nop(self->output); + } + zz_thumb_writer_put_instruction(self->output, (insn1 & 0b1111110100000111) | 0); + + zz_thumb_writer_put_b_imm(self->output, 0x6); + ZzLiteralInstruction **literal_insn_ptr = &(self->relocate_literal_insns[self->relocate_literal_insns_size++]); + zz_thumb_writer_put_ldr_reg_relocate_address(self->output, ZZ_ARM_REG_PC, target_address + 1, literal_insn_ptr); + + // zz_thumb_writer_put_b_imm(self->output, 0x10); + // zz_thumb_writer_put_push_reg(self->output, ZZ_ARM_REG_R0); + // zz_thumb_writer_put_push_reg(self->output, ZZ_ARM_REG_R0); + // zz_thumb_writer_put_ldr_b_reg_address(self->output, ZZ_ARM_REG_R0, target_address + 1); + // zz_thumb_writer_put_str_reg_reg_offset(self->output, ZZ_ARM_REG_R0, ZZ_ARM_REG_SP, 4); + // zz_thumb_writer_put_pop_reg(self->output, ZZ_ARM_REG_R0); + // zz_thumb_writer_put_pop_reg(self->output, ZZ_ARM_REG_PC); + return TRUE; +} + // PAGE: A8-310 -zbool zz_thumb_relocator_rewrite_ADD_register_T2(ZzThumbRelocator *self, const ZzInstruction *insn_ctx) { +static zbool zz_thumb_relocator_rewrite_ADD_register_T2(ZzThumbRelocator *self, const ZzInstruction *insn_ctx, + ZzRelocateInstruction *re_insn_ctx) { zuint32 insn1 = insn_ctx->insn1; zuint16 Rm_ndx, Rdn_ndx, DN, Rd_ndx; @@ -85,32 +208,33 @@ zbool zz_thumb_relocator_rewrite_ADD_register_T2(ZzThumbRelocator *self, const Z if (Rm_ndx != ZZ_ARM_REG_PC) { return FALSE; } - // push R7 - zz_thumb_writer_put_push_reg(self->output, 1 << 7); - // zz_thumb_writer_put_str_index_reg_reg_offset(self->output, ZZ_ARM_REG_R7, ZZ_ARM_REG_SP, -4, 1); + + zz_thumb_writer_put_push_reg(self->output, ZZ_ARM_REG_R7); zz_thumb_writer_put_ldr_b_reg_address(self->output, ZZ_ARM_REG_R7, insn_ctx->pc); zz_thumb_writer_put_instruction(self->output, (insn1 & 0b1111111110000111) | ZZ_ARM_REG_R7 << 3); - // zz_thumb_writer_put_add_reg_reg_reg(self->output, Rd_ndx, Rd_ndx, ZZ_ARM_REG_R7); - // pop R7 - zz_thumb_writer_put_pop_reg(self->output, 1 << 7); - // zz_thumb_writer_put_ldr_index_reg_reg_offset(self->output, ZZ_ARM_REG_R7, ZZ_ARM_REG_SP, 4, 0); + zz_thumb_writer_put_pop_reg(self->output, ZZ_ARM_REG_R7); + return TRUE; } // PAGE: A8-410 -zbool zz_thumb_relocator_rewrite_LDR_literal_T1(ZzThumbRelocator *self, const ZzInstruction *insn_ctx) { +zbool zz_thumb_relocator_rewrite_LDR_literal_T1(ZzThumbRelocator *self, const ZzInstruction *insn_ctx, + ZzRelocateInstruction *re_insn_ctx) { zuint32 insn1 = insn_ctx->insn1; zuint32 imm8 = get_insn_sub(insn1, 0, 8); zuint32 imm32 = imm8 << 2; - zaddr target_address = insn_ctx->pc + imm32; + zaddr target_address = ALIGN_4(insn_ctx->pc) + imm32; int Rt_ndx = get_insn_sub(insn1, 8, 3); + zz_thumb_writer_put_ldr_b_reg_address(self->output, Rt_ndx, target_address); zz_thumb_writer_put_ldr_reg_reg_offset(self->output, Rt_ndx, Rt_ndx, 0); + return TRUE; } // PAGE: A8-410 -zbool zz_thumb_relocator_rewrite_LDR_literal_T2(ZzThumbRelocator *self, const ZzInstruction *insn_ctx) { +zbool zz_thumb_relocator_rewrite_LDR_literal_T2(ZzThumbRelocator *self, const ZzInstruction *insn_ctx, + ZzRelocateInstruction *re_insn_ctx) { zuint32 insn1 = insn_ctx->insn1; zuint32 insn2 = insn_ctx->insn2; @@ -120,18 +244,20 @@ zbool zz_thumb_relocator_rewrite_LDR_literal_T2(ZzThumbRelocator *self, const Zz zbool add = get_insn_sub(insn_ctx->insn1, 7, 1) == 1; zaddr target_address; if (add) - target_address = insn_ctx->pc + imm32; + target_address = ALIGN_4(insn_ctx->pc) + imm32; else - target_address = insn_ctx->pc - imm32; + target_address = ALIGN_4(insn_ctx->pc) - imm32; int Rt_ndx = get_insn_sub(insn_ctx->insn2, 12, 4); zz_thumb_writer_put_ldr_b_reg_address(self->output, Rt_ndx, target_address); zz_thumb_writer_put_ldr_reg_reg_offset(self->output, Rt_ndx, Rt_ndx, 0); + return TRUE; } // PAGE: A8-322 -zbool zz_thumb_relocator_rewrite_ADR_T1(ZzThumbRelocator *self, const ZzInstruction *insn_ctx) { +zbool zz_thumb_relocator_rewrite_ADR_T1(ZzThumbRelocator *self, const ZzInstruction *insn_ctx, + ZzRelocateInstruction *re_insn_ctx) { zuint32 insn1 = insn_ctx->insn1; zuint32 imm8 = get_insn_sub(insn1, 0, 8); @@ -144,7 +270,8 @@ zbool zz_thumb_relocator_rewrite_ADR_T1(ZzThumbRelocator *self, const ZzInstruct } // PAGE: A8-322 -zbool zz_thumb_relocator_rewrite_ADR_T2(ZzThumbRelocator *self, const ZzInstruction *insn_ctx) { +zbool zz_thumb_relocator_rewrite_ADR_T2(ZzThumbRelocator *self, const ZzInstruction *insn_ctx, + ZzRelocateInstruction *re_insn_ctx) { zuint32 insn1 = insn_ctx->insn1; zuint32 insn2 = insn_ctx->insn2; @@ -159,7 +286,8 @@ zbool zz_thumb_relocator_rewrite_ADR_T2(ZzThumbRelocator *self, const ZzInstruct } // PAGE: A8-322 -zbool zz_thumb_relocator_rewrite_ADR_T3(ZzThumbRelocator *self, const ZzInstruction *insn_ctx) { +zbool zz_thumb_relocator_rewrite_ADR_T3(ZzThumbRelocator *self, const ZzInstruction *insn_ctx, + ZzRelocateInstruction *re_insn_ctx) { zuint32 insn1 = insn_ctx->insn1; zuint32 insn2 = insn_ctx->insn2; @@ -169,12 +297,20 @@ zbool zz_thumb_relocator_rewrite_ADR_T3(ZzThumbRelocator *self, const ZzInstruct zaddr target_address; target_address = insn_ctx->pc + imm32; int Rt_ndx = get_insn_sub(insn_ctx->insn2, 8, 4); + zz_thumb_writer_put_ldr_b_reg_address(self->output, Rt_ndx, target_address); return TRUE; } +// 0x000 : b.cond 0x0; +// 0x002 : b 0x6 +// 0x004 : ldr pc, [pc, #0] +// 0x008 : .long 0x0 +// 0x00c : remain code + // PAGE: A8-334 -zbool zz_thumb_relocator_rewrite_B_T1(ZzThumbRelocator *self, const ZzInstruction *insn_ctx) { +zbool zz_thumb_relocator_rewrite_B_T1(ZzThumbRelocator *self, const ZzInstruction *insn_ctx, + ZzRelocateInstruction *re_insn_ctx) { zuint32 insn1 = insn_ctx->insn1; // zuint32 insn2 = insn_ctx->insn2; @@ -182,27 +318,39 @@ zbool zz_thumb_relocator_rewrite_B_T1(ZzThumbRelocator *self, const ZzInstructio zuint32 imm32 = imm8 << 1; zaddr target_address = insn_ctx->pc + imm32; - zz_thumb_writer_put_instruction(self->output, (insn1 & 0xFF00)); + /* for align , simple solution, maybe the correct solution is get `ldr_reg_address` length and adjust the immediate + * of `b_imm`. */ + if ((zaddr)self->output->pc % 4) { + zz_thumb_writer_put_nop(self->output); + } + zz_thumb_writer_put_instruction(self->output, (insn1 & 0xFF00) | 0); zz_thumb_writer_put_b_imm(self->output, 0x6); - zz_thumb_writer_put_ldr_reg_address(self->output, ZZ_ARM_REG_PC, target_address); + zz_thumb_writer_put_ldr_reg_address(self->output, ZZ_ARM_REG_PC, target_address + 1); return TRUE; } // PAGE: A8-334 -zbool zz_thumb_relocator_rewrite_B_T2(ZzThumbRelocator *self, const ZzInstruction *insn_ctx) { +zbool zz_thumb_relocator_rewrite_B_T2(ZzThumbRelocator *self, const ZzInstruction *insn_ctx, + ZzRelocateInstruction *re_insn_ctx) { zuint32 insn1 = insn_ctx->insn1; - // zuint32 insn2 = insn_ctx->insn2; zuint32 imm11 = get_insn_sub(insn1, 0, 11); zuint32 imm32 = imm11 << 1; zaddr target_address = insn_ctx->pc + imm32; - zz_thumb_writer_put_ldr_reg_address(self->output, ZZ_ARM_REG_PC, target_address); + zz_thumb_writer_put_ldr_reg_address(self->output, ZZ_ARM_REG_PC, target_address + 1); return TRUE; } +// 0x002 : b.cond.W 0x2; +// 0x006 : b 0x6 +// 0x008 : ldr pc, [pc, #0] +// 0x00c : .long 0x0 +// 0x010 : remain code + // PAGE: A8-334 -zbool zz_thumb_relocator_rewrite_B_T3(ZzThumbRelocator *self, const ZzInstruction *insn_ctx) { +zbool zz_thumb_relocator_rewrite_B_T3(ZzThumbRelocator *self, const ZzInstruction *insn_ctx, + ZzRelocateInstruction *re_insn_ctx) { zuint32 insn1 = insn_ctx->insn1; zuint32 insn2 = insn_ctx->insn2; @@ -216,14 +364,21 @@ zbool zz_thumb_relocator_rewrite_B_T3(ZzThumbRelocator *self, const ZzInstructio zaddr target_address; target_address = insn_ctx->pc + imm32; - zz_thumb_writer_put_instruction(self->output, (insn_ctx->insn & 0b11010000000000001111101111000000) | 0b1); + /* for align , simple solution, maybe the correct solution is get `ldr_reg_address` length and adjust the immediate + * of `b_imm`. */ + if ((zaddr)self->output->pc % 4 == 0) { + zz_thumb_writer_put_nop(self->output); + } + zz_thumb_writer_put_instruction(self->output, insn_ctx->insn1 & 0b1111101111000000); + zz_thumb_writer_put_instruction(self->output, (insn_ctx->insn2 & 0b1101000000000000) | 0b1); zz_thumb_writer_put_b_imm(self->output, 0x6); - zz_thumb_writer_put_ldr_reg_address(self->output, ZZ_ARM_REG_PC, target_address); + zz_thumb_writer_put_ldr_reg_address(self->output, ZZ_ARM_REG_PC, target_address + 1); return TRUE; } // PAGE: A8-334 -zbool zz_thumb_relocator_rewrite_B_T4(ZzThumbRelocator *self, const ZzInstruction *insn_ctx) { +zbool zz_thumb_relocator_rewrite_B_T4(ZzThumbRelocator *self, const ZzInstruction *insn_ctx, + ZzRelocateInstruction *re_insn_ctx) { zuint32 insn1 = insn_ctx->insn1; zuint32 insn2 = insn_ctx->insn2; @@ -232,19 +387,20 @@ zbool zz_thumb_relocator_rewrite_B_T4(ZzThumbRelocator *self, const ZzInstructio zuint32 J1 = get_insn_sub(insn_ctx->insn2, 13, 1); zuint32 imm10 = get_insn_sub(insn_ctx->insn1, 0, 10); zuint32 imm11 = get_insn_sub(insn_ctx->insn2, 0, 11); - zuint32 I1 = (~(J1 ^ S)); - zuint32 I2 = (~(J2 ^ S)); + zuint32 I1 = (~(J1 ^ S)) & 0x1; + zuint32 I2 = (~(J2 ^ S)) & 0x1; zuint32 imm32 = imm11 << 1 | imm10 << (1 + 11) | I1 << (1 + 11 + 6) | I2 << (1 + 11 + 6 + 1) | S << (1 + 11 + 6 + 1 + 1); zaddr target_address; target_address = insn_ctx->pc + imm32; - zz_thumb_writer_put_ldr_reg_address(self->output, ZZ_ARM_REG_PC, target_address); + zz_thumb_writer_put_ldr_reg_address(self->output, ZZ_ARM_REG_PC, target_address + 1); return TRUE; } // PAGE: A8-348 -zbool zz_thumb_relocator_rewrite_BLBLX_immediate_T1(ZzThumbRelocator *self, const ZzInstruction *insn_ctx) { +zbool zz_thumb_relocator_rewrite_BLBLX_immediate_T1(ZzThumbRelocator *self, const ZzInstruction *insn_ctx, + ZzRelocateInstruction *re_insn_ctx) { zuint32 insn1 = insn_ctx->insn1; zuint32 insn2 = insn_ctx->insn2; @@ -253,20 +409,25 @@ zbool zz_thumb_relocator_rewrite_BLBLX_immediate_T1(ZzThumbRelocator *self, cons zuint32 J1 = get_insn_sub(insn_ctx->insn2, 13, 1); zuint32 imm10 = get_insn_sub(insn_ctx->insn1, 0, 10); zuint32 imm11 = get_insn_sub(insn_ctx->insn2, 0, 11); - zuint32 I1 = (~(J1 ^ S)); - zuint32 I2 = (~(J2 ^ S)); + zuint32 I1 = (~(J1 ^ S)) & 0x1; + zuint32 I2 = (~(J2 ^ S)) & 0x1; zuint32 imm32 = imm11 << 1 | imm10 << (1 + 11) | I1 << (1 + 11 + 6) | I2 << (1 + 11 + 6 + 1) | S << (1 + 11 + 6 + 1 + 1); zaddr target_address; + + // CurrentInstrSet = thumb + // targetInstrSet = arm target_address = insn_ctx->pc + imm32; - zz_thumb_writer_put_ldr_b_reg_address(self->output, ZZ_ARM_REG_LR, insn_ctx->pc + 2 * 4); + ZzLiteralInstruction **literal_insn_ptr = &(self->relocate_literal_insns[self->relocate_literal_insns_size++]); + zz_thumb_writer_put_ldr_b_reg_relocate_address(self->output, ZZ_ARM_REG_LR, insn_ctx->pc + 1, literal_insn_ptr); zz_thumb_writer_put_ldr_reg_address(self->output, ZZ_ARM_REG_PC, target_address + 1); return TRUE; } // PAGE: A8-348 -zbool zz_thumb_relocator_rewrite_BLBLX_T2(ZzThumbRelocator *self, const ZzInstruction *insn_ctx) { +zbool zz_thumb_relocator_rewrite_BLBLX_T2(ZzThumbRelocator *self, const ZzInstruction *insn_ctx, + ZzRelocateInstruction *re_insn_ctx) { zuint32 insn1 = insn_ctx->insn1; zuint32 insn2 = insn_ctx->insn2; @@ -274,65 +435,78 @@ zbool zz_thumb_relocator_rewrite_BLBLX_T2(ZzThumbRelocator *self, const ZzInstru zuint32 J2 = get_insn_sub(insn_ctx->insn2, 11, 1); zuint32 J1 = get_insn_sub(insn_ctx->insn2, 13, 1); zuint32 imm10_1 = get_insn_sub(insn_ctx->insn1, 0, 10); - zuint32 imm10_16 = get_insn_sub(insn_ctx->insn2, 1, 10); - zuint32 I1 = (~(J1 ^ S)); - zuint32 I2 = (~(J2 ^ S)); + zuint32 imm10_2 = get_insn_sub(insn_ctx->insn2, 1, 10); + zuint32 I1 = (~(J1 ^ S)) & 0x1; + zuint32 I2 = (~(J2 ^ S)) & 0x1; + ; + zuint32 H = get_insn_sub(insn_ctx->insn2, 0, 1); zuint32 imm32 = - imm10_1 << 2 | imm10_16 << (2 + 10) | I1 << (2 + 10 + 6) | I2 << (2 + 10 + 6 + 1) | S << (2 + 10 + 6 + 1 + 1); + imm10_2 << 2 | imm10_1 << (2 + 10) | I1 << (2 + 10 + 6) | I2 << (2 + 10 + 6 + 1) | S << (2 + 10 + 6 + 1 + 1); zaddr target_address; - target_address = insn_ctx->pc + imm32; - zz_thumb_writer_put_ldr_b_reg_address(self->output, ZZ_ARM_REG_LR, insn_ctx->pc + 2 * 4); - zz_thumb_writer_put_ldr_reg_address(self->output, ZZ_ARM_REG_PC, target_address + 1); + // CurrentInstrSet = thumb + // targetInstrSet = arm + target_address = ALIGN_4(insn_ctx->pc) + imm32; + + ZzLiteralInstruction **literal_insn_ptr = &(self->relocate_literal_insns[self->relocate_literal_insns_size++]); + zz_thumb_writer_put_ldr_b_reg_relocate_address(self->output, ZZ_ARM_REG_LR, insn_ctx->pc + 1, literal_insn_ptr); + zz_thumb_writer_put_ldr_reg_address(self->output, ZZ_ARM_REG_PC, target_address); return TRUE; } zbool zz_thumb_relocator_write_one(ZzThumbRelocator *self) { const ZzInstruction *insn_ctx; + ZzRelocateInstruction *re_insn_ctx; zbool rewritten = FALSE; if (self->inpos != self->outpos) { insn_ctx = &self->input_insns[self->outpos]; + re_insn_ctx = &self->output_insns[self->outpos]; self->outpos++; } else return FALSE; - switch (GetTHUMBInsnType(insn_ctx->insn)) { + re_insn_ctx->relocated_offset = (zaddr)self->output->pc - (zaddr)self->output->base; + + switch (GetTHUMBInsnType(insn_ctx->insn1, insn_ctx->insn2)) { + case THUMB_INS_CBNZ_CBZ: + rewritten = zz_thumb_relocator_rewrite_CBNZ_CBZ(self, insn_ctx, re_insn_ctx); + break; case THUMB_INS_ADD_register_T2: - rewritten = zz_thumb_relocator_rewrite_ADD_register_T2(self, insn_ctx); + rewritten = zz_thumb_relocator_rewrite_ADD_register_T2(self, insn_ctx, re_insn_ctx); break; case THUMB_INS_LDR_literal_T1: - rewritten = zz_thumb_relocator_rewrite_LDR_literal_T1(self, insn_ctx); + rewritten = zz_thumb_relocator_rewrite_LDR_literal_T1(self, insn_ctx, re_insn_ctx); break; case THUMB_INS_LDR_literal_T2: - rewritten = zz_thumb_relocator_rewrite_LDR_literal_T2(self, insn_ctx); + rewritten = zz_thumb_relocator_rewrite_LDR_literal_T2(self, insn_ctx, re_insn_ctx); break; case THUMB_INS_ADR_T1: - rewritten = zz_thumb_relocator_rewrite_ADR_T1(self, insn_ctx); + rewritten = zz_thumb_relocator_rewrite_ADR_T1(self, insn_ctx, re_insn_ctx); break; case THUMB_INS_ADR_T2: - rewritten = zz_thumb_relocator_rewrite_ADR_T2(self, insn_ctx); + rewritten = zz_thumb_relocator_rewrite_ADR_T2(self, insn_ctx, re_insn_ctx); break; case THUMB_INS_ADR_T3: - rewritten = zz_thumb_relocator_rewrite_ADR_T3(self, insn_ctx); + rewritten = zz_thumb_relocator_rewrite_ADR_T3(self, insn_ctx, re_insn_ctx); break; case THUMB_INS_B_T1: - rewritten = zz_thumb_relocator_rewrite_B_T1(self, insn_ctx); + rewritten = zz_thumb_relocator_rewrite_B_T1(self, insn_ctx, re_insn_ctx); break; case THUMB_INS_B_T2: - rewritten = zz_thumb_relocator_rewrite_B_T2(self, insn_ctx); + rewritten = zz_thumb_relocator_rewrite_B_T2(self, insn_ctx, re_insn_ctx); break; case THUMB_INS_B_T3: - rewritten = zz_thumb_relocator_rewrite_B_T3(self, insn_ctx); + rewritten = zz_thumb_relocator_rewrite_B_T3(self, insn_ctx, re_insn_ctx); break; case THUMB_INS_B_T4: - rewritten = zz_thumb_relocator_rewrite_B_T4(self, insn_ctx); + rewritten = zz_thumb_relocator_rewrite_B_T4(self, insn_ctx, re_insn_ctx); break; case THUMB_INS_BLBLX_immediate_T1: - rewritten = zz_thumb_relocator_rewrite_BLBLX_immediate_T1(self, insn_ctx); + rewritten = zz_thumb_relocator_rewrite_BLBLX_immediate_T1(self, insn_ctx, re_insn_ctx); break; case THUMB_INS_BLBLX_immediate_T2: - rewritten = zz_thumb_relocator_rewrite_BLBLX_T2(self, insn_ctx); + rewritten = zz_thumb_relocator_rewrite_BLBLX_T2(self, insn_ctx, re_insn_ctx); break; case THUMB_UNDEF: rewritten = FALSE; @@ -340,5 +514,9 @@ zbool zz_thumb_relocator_write_one(ZzThumbRelocator *self) { } if (!rewritten) zz_thumb_writer_put_bytes(self->output, (zbyte *)&insn_ctx->insn, insn_ctx->size); + + re_insn_ctx->relocated_length = + (zaddr)self->output->pc - (zaddr)self->output->base - (zaddr)re_insn_ctx->relocated_offset; + return TRUE; } diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/relocator-thumb.h b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/relocator-thumb.h index 679bbd2f4..1baeac0eb 100644 --- a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/relocator-thumb.h +++ b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/relocator-thumb.h @@ -32,12 +32,16 @@ #include "zzdeps/zz.h" typedef struct _ZzThumbRelocator { + zbool try_relocated_again; + zsize try_relocated_length; zpointer input_start; zpointer input_cur; zaddr input_pc; ZzInstruction *input_insns; + ZzRelocateInstruction *output_insns; + ZzLiteralInstruction **relocate_literal_insns; + zsize relocate_literal_insns_size; ZzThumbWriter *output; - zuint inpos; zuint outpos; } ZzThumbRelocator; @@ -46,12 +50,8 @@ void zz_thumb_relocator_init(ZzThumbRelocator *relocator, zpointer input_code, Z void zz_thumb_relocator_reset(ZzThumbRelocator *self, zpointer input_code, ZzThumbWriter *output); zsize zz_thumb_relocator_read_one(ZzThumbRelocator *self, ZzInstruction *instruction); zbool zz_thumb_relocator_write_one(ZzThumbRelocator *self); +void zz_thumb_relocator_relocate_writer(ZzThumbRelocator *relocator, zaddr code_address); void zz_thumb_relocator_write_all(ZzThumbRelocator *self); void zz_thumb_relocator_try_relocate(zpointer address, zuint min_bytes, zuint *max_bytes); -zbool zz_thumb_relocator_rewrite_ldr(ZzThumbRelocator *self, ZzInstruction *insn_ctx); -zbool zz_thumb_relocator_rewrite_add(ZzThumbRelocator *self, ZzInstruction *insn_ctx); -zbool zz_thumb_relocator_rewrite_b(ZzThumbRelocator *self, ZzInstruction *insn_ctx); -zbool zz_thumb_relocator_rewrite_b_cond(ZzThumbRelocator *self, ZzInstruction *insn_ctx); -zbool zz_thumb_relocator_rewrite_bl(ZzThumbRelocator *self, ZzInstruction *insn_ctx); #endif \ No newline at end of file diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/writer-arm.c b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/writer-arm.c index f1bbb59d0..d9883eddf 100644 --- a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/writer-arm.c +++ b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/writer-arm.c @@ -20,39 +20,69 @@ // ATTENTION !!!: // 写 writer 部分, 需要参考, `Instrcution Set Encoding` 部分 -// `witer` REF: `ZzInstruction Set Encoding` +// `writer` REF: `ZzInstruction Set Encoding` ZzArmWriter *zz_arm_writer_new(zpointer data_ptr) { ZzArmWriter *writer = (ZzArmWriter *)malloc(sizeof(ZzArmWriter)); - int t = 4 - (zaddr)data_ptr % 4; + memset(writer, 0, sizeof(ZzArmWriter)); - writer->codedata = data_ptr + t; - writer->base = data_ptr + t; - writer->pc = data_ptr + t; + zaddr align_address = (zaddr)data_ptr & ~(zaddr)3; + writer->codedata = (zpointer)align_address; + writer->base = (zpointer)align_address; + writer->pc = align_address; writer->size = 0; + + writer->literal_insn_size = 0; + memset(writer->literal_insns, 0, sizeof(ZzLiteralInstruction) * MAX_LITERAL_INSN_SIZE); + return writer; } void zz_arm_writer_init(ZzArmWriter *self, zpointer data_ptr) { zz_arm_writer_reset(self, data_ptr); } void zz_arm_writer_reset(ZzArmWriter *self, zpointer data_ptr) { - int t = (zaddr)data_ptr % 4; - self->codedata = data_ptr + t; - self->base = data_ptr + t; - self->pc = data_ptr + t + 8; + zaddr align_address = (zaddr)data_ptr & ~(zaddr)3; + self->codedata = (zpointer)align_address; + self->base = (zpointer)align_address; + self->pc = align_address; + + self->literal_insn_size = 0; + memset(self->literal_insns, 0, sizeof(ZzLiteralInstruction) * MAX_LITERAL_INSN_SIZE); + self->size = 0; } zsize zz_arm_writer_near_jump_range_size() { return ((1 << 23) << 2); } +// ------- relocator ------- + +ZzLiteralInstruction *zz_arm_writer_put_ldr_b_reg_relocate_address(ZzArmWriter *self, ZzARMReg reg, zaddr address, + ZzLiteralInstruction **literal_insn_ptr) { + zz_arm_writer_put_ldr_b_reg_address(self, reg, address); + ZzLiteralInstruction *literal_insn = &(self->literal_insns[self->literal_insn_size - 1]); + *literal_insn_ptr = literal_insn; + return literal_insn; +} + +ZzLiteralInstruction *zz_arm_writer_put_ldr_reg_relocate_address(ZzArmWriter *self, ZzARMReg reg, zaddr address, + ZzLiteralInstruction **literal_insn_ptr) { + zz_arm_writer_put_ldr_reg_address(self, reg, address); + ZzLiteralInstruction *literal_insn = &(self->literal_insns[self->literal_insn_size - 1]); + *literal_insn_ptr = literal_insn; + return literal_insn; +} + // ------- user custom ------- void zz_arm_writer_put_ldr_b_reg_address(ZzArmWriter *self, ZzARMReg reg, zaddr address) { + self->literal_insns[self->literal_insn_size].literal_insn_ptr = self->codedata; zz_arm_writer_put_ldr_reg_reg_imm(self, reg, ZZ_ARM_REG_PC, 0); zz_arm_writer_put_b_imm(self, 0x0); + self->literal_insns[self->literal_insn_size++].literal_address_ptr = self->codedata; zz_arm_writer_put_bytes(self, (zpointer)&address, sizeof(zpointer)); } + void zz_arm_writer_put_bx_to_thumb(ZzArmWriter *self) { zz_arm_writer_put_sub_reg_reg_imm(self, ZZ_ARM_REG_SP, ZZ_ARM_REG_SP, 0x8); zz_arm_writer_put_str_reg_reg_imm(self, ZZ_ARM_REG_R1, ZZ_ARM_REG_SP, 0x0); @@ -150,8 +180,11 @@ void zz_arm_writer_put_str_reg_reg_imm(ZzArmWriter *self, ZzARMReg dst_reg, ZzAR zz_arm_writer_put_instruction(self, 0xe4000000 | rd.index << 12 | rs.index << 16 | P << 24 | U << 23 | W << 21 | (imm & ZZ_INT12_MASK)); } + void zz_arm_writer_put_ldr_reg_address(ZzArmWriter *self, ZzARMReg reg, zaddr address) { + self->literal_insns[self->literal_insn_size].literal_insn_ptr = self->codedata; zz_arm_writer_put_ldr_reg_reg_imm(self, reg, ZZ_ARM_REG_PC, -4); + self->literal_insns[self->literal_insn_size++].literal_address_ptr = self->codedata; zz_arm_writer_put_bytes(self, (zpointer)&address, sizeof(zpointer)); } @@ -181,18 +214,17 @@ void zz_arm_writer_put_bx_reg(ZzArmWriter *self, ZzARMReg reg) { void zz_arm_writer_put_nop(ZzArmWriter *self) { zz_arm_writer_put_instruction(self, 0xe320f000); } -zpointer zz_arm_writer_put_push_reg(ZzArmWriter *self, zint32 regs) { - zuint32 register_list; - register_list = regs & 0xFFFF; - - zz_arm_writer_put_instruction(self, 0b11011001001011010000000000000000 | register_list); - return self->pc; +void zz_arm_writer_put_push_reg(ZzArmWriter *self, ZzARMReg reg) { + ZzArmRegInfo ri; + zz_arm_register_describe(reg, &ri); + zz_arm_writer_put_instruction(self, 0b11100101001011010000000000000100 | ri.index << 12); + return; } -zpointer zz_arm_writer_put_pop_reg(ZzArmWriter *self, zint32 regs) { - zuint32 register_list; - register_list = regs & 0xFFFF; +void zz_arm_writer_put_pop_reg(ZzArmWriter *self, ZzARMReg reg) { + ZzArmRegInfo ri; + zz_arm_register_describe(reg, &ri); - zz_arm_writer_put_instruction(self, 0b11011000101111010000000000000000 | register_list); - return self->pc; + zz_arm_writer_put_instruction(self, 0b11100100100111010000000000000100 | ri.index << 12); + return; } \ No newline at end of file diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/writer-arm.h b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/writer-arm.h index c62227a15..95826608c 100644 --- a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/writer-arm.h +++ b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/writer-arm.h @@ -62,7 +62,10 @@ void zz_arm_writer_put_ldr_reg_reg_imm_A1(ZzArmWriter *self, ZzARMReg dst_reg, Z void zz_arm_writer_put_ldr_reg_address(ZzArmWriter *self, ZzARMReg reg, zaddr address); void zz_arm_writer_put_add_reg_reg_imm(ZzArmWriter *self, ZzARMReg dst_reg, ZzARMReg src_reg, zuint32 imm); void zz_arm_writer_put_sub_reg_reg_imm(ZzArmWriter *self, ZzARMReg dst_reg, ZzARMReg src_reg, zuint32 imm); -zpointer zz_arm_writer_put_push_reg(ZzArmWriter *self, zint32 regs); -zpointer zz_arm_writer_put_pop_reg(ZzArmWriter *self, zint32 regs); - +void zz_arm_writer_put_push_reg(ZzArmWriter *self, ZzARMReg reg); +void zz_arm_writer_put_pop_reg(ZzArmWriter *self, ZzARMReg reg); +ZzLiteralInstruction *zz_arm_writer_put_ldr_b_reg_relocate_address(ZzArmWriter *self, ZzARMReg reg, zaddr address, + ZzLiteralInstruction **literal_insn_ptr); +ZzLiteralInstruction *zz_arm_writer_put_ldr_reg_relocate_address(ZzArmWriter *self, ZzARMReg reg, zaddr address, + ZzLiteralInstruction **literal_insn_ptr); #endif \ No newline at end of file diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/writer-thumb.c b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/writer-thumb.c index a39a96c4f..c55db42fe 100644 --- a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/writer-thumb.c +++ b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/writer-thumb.c @@ -24,46 +24,60 @@ ZzThumbWriter *zz_thumb_writer_new(zpointer data_ptr) { ZzThumbWriter *writer = (ZzThumbWriter *)malloc(sizeof(ZzThumbWriter)); - int t = 4 - (zaddr)data_ptr % 4; + memset(writer, 0, sizeof(ZzThumbWriter)); - writer->codedata = data_ptr + t; - writer->base = data_ptr + t; - writer->pc = data_ptr + t; + zaddr align_address = (zaddr)data_ptr & ~(zaddr)3; + writer->codedata = (zpointer)align_address; + writer->base = (zpointer)align_address; + writer->pc = align_address; writer->size = 0; + + writer->literal_insn_size = 0; + memset(writer->literal_insns, 0, sizeof(ZzLiteralInstruction) * MAX_LITERAL_INSN_SIZE); + return writer; } void zz_thumb_writer_init(ZzThumbWriter *self, zpointer data_ptr) { zz_thumb_writer_reset(self, data_ptr); } void zz_thumb_writer_reset(ZzThumbWriter *self, zpointer data_ptr) { - int t = (zaddr)data_ptr % 4; + zaddr align_address = (zaddr)data_ptr & ~(zaddr)3; - self->codedata = data_ptr + t; - self->base = data_ptr + t; - self->pc = data_ptr + t + 4; + self->codedata = (zpointer)align_address; + self->base = (zpointer)align_address; + self->pc = align_address; self->size = 0; + + self->literal_insn_size = 0; + memset(self->literal_insns, 0, sizeof(ZzLiteralInstruction) * MAX_LITERAL_INSN_SIZE); } zsize zz_thumb_writer_near_jump_range_size() { return ((1 << 23) << 1); } -zpointer zz_thumb_writer_put_ldr_b_reg_address(ZzThumbWriter *self, ZzARMReg reg, zaddr address) { - ZzArmRegInfo ri; +// ------- relocator ------- - zz_arm_register_describe(reg, &ri); +ZzLiteralInstruction *zz_thumb_writer_put_ldr_b_reg_relocate_address(ZzThumbWriter *self, ZzARMReg reg, zaddr address, + ZzLiteralInstruction **literal_insn_ptr) { + zz_thumb_writer_put_ldr_b_reg_address(self, reg, address); + ZzLiteralInstruction *literal_insn = &(self->literal_insns[self->literal_insn_size - 1]); + *literal_insn_ptr = literal_insn; + return literal_insn; +} + +ZzLiteralInstruction *zz_thumb_writer_put_ldr_reg_relocate_address(ZzThumbWriter *self, ZzARMReg reg, zaddr address, + ZzLiteralInstruction **literal_insn_ptr) { + zz_thumb_writer_put_ldr_reg_address(self, reg, address); + ZzLiteralInstruction *literal_insn = &(self->literal_insns[self->literal_insn_size - 1]); + *literal_insn_ptr = literal_insn; + return literal_insn; +} - // if (((zaddr)self->pc) % 4) { - // zz_thumb_writer_put_ldr_reg_imm(self, reg, 0x4); - // if (ri.meta <= ZZ_ARM_REG_R7) { - // zz_thumb_writer_put_nop(self); - // } - // } else { - // if (ri.meta <= ZZ_ARM_REG_R7) { - // zz_thumb_writer_put_ldr_reg_imm(self, reg, 0x0); - // } else { - // zz_thumb_writer_put_ldr_reg_imm(self, reg, 0x4); - // zz_thumb_writer_put_nop(self); - // } - // } +// ------- custom ------- + +void zz_thumb_writer_put_ldr_b_reg_address(ZzThumbWriter *self, ZzARMReg reg, zaddr address) { + ZzArmRegInfo ri; + zz_arm_register_describe(reg, &ri); + self->literal_insns[self->literal_insn_size].literal_insn_ptr = self->codedata; if ((((zaddr)self->pc) % 4)) { if (ri.meta <= ZZ_ARM_REG_R7) { @@ -82,14 +96,17 @@ zpointer zz_thumb_writer_put_ldr_b_reg_address(ZzThumbWriter *self, ZzARMReg reg } zz_thumb_writer_put_b_imm(self, 0x2); + self->literal_insns[self->literal_insn_size++].literal_address_ptr = self->codedata; zz_thumb_writer_put_bytes(self, (zpointer)&address, sizeof(zpointer)); - return self->pc; + return; } -zpointer zz_thumb_writer_put_ldr_reg_address(ZzThumbWriter *self, ZzARMReg reg, zaddr address) { +void zz_thumb_writer_put_ldr_reg_address(ZzThumbWriter *self, ZzARMReg reg, zaddr address) { ZzArmRegInfo ri; - zz_arm_register_describe(reg, &ri); + + self->literal_insns[self->literal_insn_size].literal_insn_ptr = self->codedata; + if ((((zaddr)self->pc) % 4)) { if (ri.meta <= ZZ_ARM_REG_R7) { zz_thumb_writer_put_ldr_reg_imm(self, reg, 0x0); @@ -103,43 +120,40 @@ zpointer zz_thumb_writer_put_ldr_reg_address(ZzThumbWriter *self, ZzARMReg reg, zz_thumb_writer_put_nop(self); } - // if ((((zaddr)self->pc) % 4)) { - // zz_thumb_writer_put_nop(self); - // } + self->literal_insns[self->literal_insn_size++].literal_address_ptr = self->codedata; zz_thumb_writer_put_bytes(self, (zpointer)&address, sizeof(zpointer)); - return self->pc; + return; } -// ------- user custom ------- // ------- architecture default ------- -zpointer zz_thumb_writer_put_nop(ZzThumbWriter *self) { +void zz_thumb_writer_put_nop(ZzThumbWriter *self) { zz_thumb_writer_put_instruction(self, 0x46c0); - return self->pc; + return; } -zpointer zz_thumb_writer_put_bytes(ZzThumbWriter *self, zbyte *data, zuint data_size) { +void zz_thumb_writer_put_bytes(ZzThumbWriter *self, zbyte *data, zuint data_size) { memcpy(self->codedata, data, data_size); self->codedata = (zpointer)self->codedata + data_size; self->pc += data_size; self->size += data_size; - return self->pc; + return; } -zpointer zz_thumb_writer_put_instruction(ZzThumbWriter *self, uint16_t insn) { +void zz_thumb_writer_put_instruction(ZzThumbWriter *self, uint16_t insn) { *(uint16_t *)(self->codedata) = insn; self->codedata = (zpointer)self->codedata + sizeof(uint16_t); self->pc += 2; self->size += 2; - return self->pc; + return; } -zpointer zz_thumb_writer_put_b_imm(ZzThumbWriter *self, zuint32 imm) { +void zz_thumb_writer_put_b_imm(ZzThumbWriter *self, zuint32 imm) { zz_thumb_writer_put_instruction(self, 0xe000 | ((imm / 2) & ZZ_INT11_MASK)); - return self->pc; + return; } -zpointer zz_thumb_writer_put_bx_reg(ZzThumbWriter *self, ZzARMReg reg) { +void zz_thumb_writer_put_bx_reg(ZzThumbWriter *self, ZzARMReg reg) { ZzArmRegInfo ri; zz_arm_register_describe(reg, &ri); @@ -150,20 +164,20 @@ zpointer zz_thumb_writer_put_bx_reg(ZzThumbWriter *self, ZzARMReg reg) { zz_thumb_writer_put_instruction(self, 0x4700 | (ri.index << 3)); zz_thumb_writer_put_nop(self); - return self->pc; + return; } -zpointer zz_thumb_writer_put_blx_reg(ZzThumbWriter *self, ZzARMReg reg) { +void zz_thumb_writer_put_blx_reg(ZzThumbWriter *self, ZzARMReg reg) { ZzArmRegInfo ri; zz_arm_register_describe(reg, &ri); zz_thumb_writer_put_instruction(self, 0x4780 | (ri.index << 3)); - return self->pc; + return; } // A8.8.18 -zpointer zz_thumb_writer_put_branch_imm(ZzThumbWriter *self, zuint32 imm, zbool link, zbool thumb) { +void zz_thumb_writer_put_branch_imm(ZzThumbWriter *self, zuint32 imm, zbool link, zbool thumb) { union { zint32 i; zuint32 u; @@ -181,27 +195,27 @@ zpointer zz_thumb_writer_put_branch_imm(ZzThumbWriter *self, zuint32 imm, zbool zz_thumb_writer_put_instruction(self, 0xf000 | (s << 10) | imm10); zz_thumb_writer_put_instruction(self, 0x8000 | (link << 14) | (j1 << 13) | (thumb << 12) | (j2 << 11) | imm11); - return self->pc; + return; } -zpointer zz_thumb_writer_put_bl_imm(ZzThumbWriter *self, zuint32 imm) { +void zz_thumb_writer_put_bl_imm(ZzThumbWriter *self, zuint32 imm) { zz_thumb_writer_put_branch_imm(self, imm, TRUE, TRUE); - return self->pc; + return; } -zpointer zz_thumb_writer_put_blx_imm(ZzThumbWriter *self, zuint32 imm) { +void zz_thumb_writer_put_blx_imm(ZzThumbWriter *self, zuint32 imm) { zz_thumb_writer_put_branch_imm(self, imm, TRUE, FALSE); - return self->pc; + return; } -zpointer zz_thumb_writer_put_b_imm32(ZzThumbWriter *self, zuint32 imm) { +void zz_thumb_writer_put_b_imm32(ZzThumbWriter *self, zuint32 imm) { zz_thumb_writer_put_branch_imm(self, imm, FALSE, TRUE); - return self->pc; + return; } // PAGE: A8-410 // A8.8.64 LDR (literal) -zpointer zz_thumb_writer_put_ldr_reg_imm(ZzThumbWriter *self, ZzARMReg reg, zint32 imm) { +void zz_thumb_writer_put_ldr_reg_imm(ZzThumbWriter *self, ZzARMReg reg, zint32 imm) { ZzArmRegInfo ri; zz_arm_register_describe(reg, &ri); @@ -216,65 +230,11 @@ zpointer zz_thumb_writer_put_ldr_reg_imm(ZzThumbWriter *self, ZzARMReg reg, zint zz_thumb_writer_put_instruction(self, 0xf85f | (add << 7)); zz_thumb_writer_put_instruction(self, (ri.index << 12) | ABS(imm)); } - return self->pc; -} - -// static zpointer zz_thumb_writer_put_transfer_reg_reg_offset(ZzThumbWriter -// *self, -// ZzThumbMemoryOperation -// operation, -// ZzARMReg left_reg, -// ZzARMReg right_reg, -// zint32 right_offset) -// { -// zz_arm_register_describe(left_reg, &lr); -// zz_arm_register_describe(right_reg, &rr); - -// if (right_offset >= 0) { -// if (lr.meta <= ZZ_ARM_REG_R7 && (rr.meta <= ZZ_ARM_REG_R7 || rr.meta == -// ZZ_ARM_REG_SP) && -// ((rr.meta == ZZ_ARM_REG_SP && right_offset <= 1020) || -// (rr.meta != ZZ_ARM_REG_SP && right_offset <= 124)) && -// (right_offset % 4) == 0) { -// zuint16 insn; - -// if (rr.meta == ZZ_ARM_REG_SP) -// insn = 0x9000 | (lr.index << 8) | (right_offset / 4); -// else -// insn = 0x6000 | (right_offset / 4) << 6 | (rr.index << 3) | -// lr.index; - -// if (operation == ZZ_THUMB_MEMORY_LOAD) -// insn |= 0x0800; - -// zz_thumb_writer_put_instruction(self, insn); -// } else { -// if (right_offset > 4095) -// return; -// zz_thumb_writer_put_instruction( -// self, 0xf8c0 | ((operation == ZZ_THUMB_MEMORY_LOAD) ? 0x0010 -// : 0x0000) | -// rr.index); -// zz_thumb_writer_put_instruction(self, (lr.index << 12) | -// right_offset); -// } -// } else { -// if ((rr.index & 0xF) == 0xF) { -// zz_thumb_writer_put_ldr_reg_imm(self, left_reg, right_offset); -// } else { -// zz_thumb_writer_put_instruction( -// self, 0xf840 | ((operation == ZZ_THUMB_MEMORY_LOAD) ? 0x0010 -// : 0x0000) | -// rr.index); -// zz_thumb_writer_put_instruction(self, 0x0c00 | (lr.index << 12) | -// (ABS(right_offset) & -// ZZ_INT8_MASK)); -// } -// } -// } - -zpointer zz_thumb_writer_put_transfer_reg_reg_offset_T1(ZzThumbWriter *self, ZzThumbMemoryOperation operation, - ZzARMReg left_reg, ZzARMReg right_reg, zint32 right_offset) { + return; +} + +zbool zz_thumb_writer_put_transfer_reg_reg_offset_T1(ZzThumbWriter *self, ZzThumbMemoryOperation operation, + ZzARMReg left_reg, ZzARMReg right_reg, zint32 right_offset) { ZzArmRegInfo lr, rr; zz_arm_register_describe(left_reg, &lr); @@ -283,20 +243,20 @@ zpointer zz_thumb_writer_put_transfer_reg_reg_offset_T1(ZzThumbWriter *self, ZzT zuint16 insn; if (right_offset < 0) - return 0; + return FALSE; if (lr.meta <= ZZ_ARM_REG_R7 && rr.meta <= ZZ_ARM_REG_R7 && right_offset < ((1 << 5) << 2)) { insn = 0x6000 | (right_offset / 4) << 6 | (rr.index << 3) | lr.index; if (operation == ZZ_THUMB_MEMORY_LOAD) insn |= 0x0800; zz_thumb_writer_put_instruction(self, insn); - return self->pc; + return TRUE; } - return 0; + return FALSE; } -zpointer zz_thumb_writer_put_transfer_reg_reg_offset_T2(ZzThumbWriter *self, ZzThumbMemoryOperation operation, - ZzARMReg left_reg, ZzARMReg right_reg, zint32 right_offset) { +zbool zz_thumb_writer_put_transfer_reg_reg_offset_T2(ZzThumbWriter *self, ZzThumbMemoryOperation operation, + ZzARMReg left_reg, ZzARMReg right_reg, zint32 right_offset) { ZzArmRegInfo lr, rr; zz_arm_register_describe(left_reg, &lr); @@ -305,20 +265,20 @@ zpointer zz_thumb_writer_put_transfer_reg_reg_offset_T2(ZzThumbWriter *self, ZzT zuint16 insn; if (right_offset < 0) - return 0; + return FALSE; if (rr.meta == ZZ_ARM_REG_SP && lr.meta <= ZZ_ARM_REG_R7 && right_offset < ((1 << 8) << 2)) { insn = 0x9000 | (lr.index << 8) | (right_offset / 4); if (operation == ZZ_THUMB_MEMORY_LOAD) insn |= 0x0800; zz_thumb_writer_put_instruction(self, insn); - return self->pc; + return TRUE; } - return 0; + return FALSE; } -zpointer zz_thumb_writer_put_transfer_reg_reg_offset_T3(ZzThumbWriter *self, ZzThumbMemoryOperation operation, - ZzARMReg left_reg, ZzARMReg right_reg, zint32 right_offset) { +zbool zz_thumb_writer_put_transfer_reg_reg_offset_T3(ZzThumbWriter *self, ZzThumbMemoryOperation operation, + ZzARMReg left_reg, ZzARMReg right_reg, zint32 right_offset) { ZzArmRegInfo lr, rr; zz_arm_register_describe(left_reg, &lr); @@ -327,13 +287,9 @@ zpointer zz_thumb_writer_put_transfer_reg_reg_offset_T3(ZzThumbWriter *self, ZzT zuint16 insn; if (right_offset < 0) - return 0; + return FALSE; if (right_offset < (1 << 12)) { - // if (operation == ZZ_THUMB_MEMORY_LOAD && rr.meta == ZZ_ARM_REG_PC && - // (self->pc % 4)) { - // zz_thumb_writer_put_nop(self); - // } if (rr.meta == ZZ_ARM_REG_PC) { zz_thumb_writer_put_ldr_reg_imm(self, left_reg, right_offset); } @@ -341,14 +297,14 @@ zpointer zz_thumb_writer_put_transfer_reg_reg_offset_T3(ZzThumbWriter *self, ZzT 0xf8c0 | ((operation == ZZ_THUMB_MEMORY_LOAD) ? 0x0010 : 0x0000) | rr.index); zz_thumb_writer_put_instruction(self, (lr.index << 12) | right_offset); - return self->pc; + return TRUE; } - return 0; + return FALSE; } -zpointer zz_thumb_writer_put_transfer_reg_reg_offset_T4(ZzThumbWriter *self, ZzThumbMemoryOperation operation, - ZzARMReg left_reg, ZzARMReg right_reg, zint32 right_offset, - zbool index, zbool wback) { +zbool zz_thumb_writer_put_transfer_reg_reg_offset_T4(ZzThumbWriter *self, ZzThumbMemoryOperation operation, + ZzARMReg left_reg, ZzARMReg right_reg, zint32 right_offset, + zbool index, zbool wback) { ZzArmRegInfo lr, rr; zz_arm_register_describe(left_reg, &lr); @@ -367,65 +323,64 @@ zpointer zz_thumb_writer_put_transfer_reg_reg_offset_T4(ZzThumbWriter *self, ZzT rr.index); zz_thumb_writer_put_instruction(self, 0x0800 | (lr.index << 12) | (index << 10) | (add << 9) | (wback << 8) | (ABS(right_offset))); - return self->pc; + return TRUE; } } - return 0; + return FALSE; } // PAGE: A8-406 // PAGE: A8.8.203 STR (immediate, Thumb) -static zpointer zz_thumb_writer_put_transfer_reg_reg_offset(ZzThumbWriter *self, ZzThumbMemoryOperation operation, - ZzARMReg left_reg, ZzARMReg right_reg, - zint32 right_offset) { +static void zz_thumb_writer_put_transfer_reg_reg_offset(ZzThumbWriter *self, ZzThumbMemoryOperation operation, + ZzARMReg left_reg, ZzARMReg right_reg, zint32 right_offset) { if (zz_thumb_writer_put_transfer_reg_reg_offset_T1(self, operation, left_reg, right_reg, right_offset)) - return self->pc; + return; if (zz_thumb_writer_put_transfer_reg_reg_offset_T2(self, operation, left_reg, right_reg, right_offset)) - return self->pc; + return; if (zz_thumb_writer_put_transfer_reg_reg_offset_T3(self, operation, left_reg, right_reg, right_offset)) - return self->pc; + return; if (zz_thumb_writer_put_transfer_reg_reg_offset_T4(self, operation, left_reg, right_reg, right_offset, 1, 0)) - return self->pc; - return 0; + return; + return; } -zpointer zz_thumb_writer_put_ldr_reg_reg_offset(ZzThumbWriter *self, ZzARMReg dst_reg, ZzARMReg src_reg, - zint32 src_offset) { +void zz_thumb_writer_put_ldr_reg_reg_offset(ZzThumbWriter *self, ZzARMReg dst_reg, ZzARMReg src_reg, + zint32 src_offset) { zz_thumb_writer_put_transfer_reg_reg_offset(self, ZZ_THUMB_MEMORY_LOAD, dst_reg, src_reg, src_offset); - return self->pc; + return; } -zpointer zz_thumb_writer_put_str_reg_reg_offset(ZzThumbWriter *self, ZzARMReg src_reg, ZzARMReg dst_reg, - zint32 dst_offset) { +void zz_thumb_writer_put_str_reg_reg_offset(ZzThumbWriter *self, ZzARMReg src_reg, ZzARMReg dst_reg, + zint32 dst_offset) { zz_thumb_writer_put_transfer_reg_reg_offset(self, ZZ_THUMB_MEMORY_STORE, src_reg, dst_reg, dst_offset); - return self->pc; + return; } -zpointer zz_thumb_writer_put_ldr_index_reg_reg_offset(ZzThumbWriter *self, ZzARMReg dst_reg, ZzARMReg src_reg, - zint32 src_offset, zbool index) { +void zz_thumb_writer_put_ldr_index_reg_reg_offset(ZzThumbWriter *self, ZzARMReg dst_reg, ZzARMReg src_reg, + zint32 src_offset, zbool index) { zz_thumb_writer_put_transfer_reg_reg_offset_T4(self, ZZ_THUMB_MEMORY_LOAD, dst_reg, src_reg, src_offset, index, 1); - return self->pc; + return; } -zpointer zz_thumb_writer_put_str_index_reg_reg_offset(ZzThumbWriter *self, ZzARMReg src_reg, ZzARMReg dst_reg, - zint32 dst_offset, zbool index) { +void zz_thumb_writer_put_str_index_reg_reg_offset(ZzThumbWriter *self, ZzARMReg src_reg, ZzARMReg dst_reg, + zint32 dst_offset, zbool index) { zz_thumb_writer_put_transfer_reg_reg_offset_T4(self, ZZ_THUMB_MEMORY_STORE, src_reg, dst_reg, dst_offset, index, 1); - return self->pc; + return; } -zpointer zz_thumb_writer_put_str_reg_reg(ZzThumbWriter *self, ZzARMReg src_reg, ZzARMReg dst_reg) { +void zz_thumb_writer_put_str_reg_reg(ZzThumbWriter *self, ZzARMReg src_reg, ZzARMReg dst_reg) { zz_thumb_writer_put_str_reg_reg_offset(self, src_reg, dst_reg, 0); - return self->pc; + return; } -zpointer zz_thumb_writer_put_ldr_reg_reg(ZzThumbWriter *self, ZzARMReg dst_reg, ZzARMReg src_reg) { +void zz_thumb_writer_put_ldr_reg_reg(ZzThumbWriter *self, ZzARMReg dst_reg, ZzARMReg src_reg) { zz_thumb_writer_put_ldr_reg_reg_offset(self, dst_reg, src_reg, 0); - return self->pc; + return; } -zpointer zz_thumb_writer_put_add_reg_imm(ZzThumbWriter *self, ZzARMReg dst_reg, zint32 imm) { +void zz_thumb_writer_put_add_reg_imm(ZzThumbWriter *self, ZzARMReg dst_reg, zint32 imm) { ZzArmRegInfo dst; zuint16 sign_mask, insn; @@ -446,16 +401,15 @@ zpointer zz_thumb_writer_put_add_reg_imm(ZzThumbWriter *self, ZzARMReg dst_reg, } zz_thumb_writer_put_instruction(self, insn); - return self->pc; + return; } -zpointer zz_thumb_writer_put_sub_reg_imm(ZzThumbWriter *self, ZzARMReg dst_reg, zint32 imm) { +void zz_thumb_writer_put_sub_reg_imm(ZzThumbWriter *self, ZzARMReg dst_reg, zint32 imm) { zz_thumb_writer_put_add_reg_imm(self, dst_reg, -imm); - return self->pc; + return; } -zpointer zz_thumb_writer_put_add_reg_reg_imm(ZzThumbWriter *self, ZzARMReg dst_reg, ZzARMReg left_reg, - zint32 right_value) { +void zz_thumb_writer_put_add_reg_reg_imm(ZzThumbWriter *self, ZzARMReg dst_reg, ZzARMReg left_reg, zint32 right_value) { ZzArmRegInfo dst, left; zuint16 insn; @@ -466,11 +420,17 @@ zpointer zz_thumb_writer_put_add_reg_reg_imm(ZzThumbWriter *self, ZzARMReg dst_r return zz_thumb_writer_put_add_reg_imm(self, dst_reg, right_value); } - if (left.meta == ZZ_ARM_REG_SP || left.meta == ZZ_ARM_REG_PC) { - zuint16 base_mask; + if (dst.meta <= ZZ_ARM_REG_R7 && left.meta <= ZZ_ARM_REG_R7 && ABS(right_value) < (1 << 3)) { + zuint32 sign_mask = 0; + + if (right_value < 0) + sign_mask = 1 << 9; - if (right_value < 0 || right_value % 4 != 0) - return 0; + insn = 0x1c00 | sign_mask | (ABS(right_value) << 6) | (left.index << 3) | dst.index; + zz_thumb_writer_put_instruction(self, insn); + } else if ((left.meta == ZZ_ARM_REG_SP || left.meta == ZZ_ARM_REG_PC) && dst.meta <= ZZ_ARM_REG_R7 && + right_value > 0 && (right_value % 4 == 0) && right_value < (1 << 8)) { + zuint16 base_mask; if (left.meta == ZZ_ARM_REG_SP) base_mask = 0x0800; @@ -478,47 +438,54 @@ zpointer zz_thumb_writer_put_add_reg_reg_imm(ZzThumbWriter *self, ZzARMReg dst_r base_mask = 0x0000; insn = 0xa000 | base_mask | (dst.index << 8) | (right_value / 4); + zz_thumb_writer_put_instruction(self, insn); } else { - zuint16 sign_mask = 0x0000; - - if (ABS(right_value) > 7) - return 0; - + zuint16 insn1, insn2; + zuint i, imm3, imm8; + i = (ABS(right_value) >> (3 + 8)) & 0x1; + imm3 = (ABS(right_value) >> 8) & 0b111; + imm8 = ABS(right_value) & 0b11111111; + + // A8-708, sub + // A8-306 add if (right_value < 0) - sign_mask = 0x0200; - - insn = 0x1c00 | sign_mask | (ABS(right_value) << 6) | (left.index << 3) | dst.index; + zz_thumb_writer_put_instruction(self, 0b1111001010100000 | i << 10 | left.index); + else + zz_thumb_writer_put_instruction(self, 0b1111001000000000 | i << 10 | left.index); + zz_thumb_writer_put_instruction(self, 0b0 | imm3 << 12 | dst.index << 8 | imm8); } - zz_thumb_writer_put_instruction(self, insn); - - return self->pc; + return; } -zpointer zz_thumb_writer_put_sub_reg_reg_imm(ZzThumbWriter *self, ZzARMReg dst_reg, ZzARMReg left_reg, - zint32 right_value) { +void zz_thumb_writer_put_sub_reg_reg_imm(ZzThumbWriter *self, ZzARMReg dst_reg, ZzARMReg left_reg, zint32 right_value) { zz_thumb_writer_put_add_reg_reg_imm(self, dst_reg, left_reg, -right_value); - return self->pc; + return; } -zpointer zz_thumb_writer_put_push_reg(ZzThumbWriter *self, zint32 regs) { +void zz_thumb_writer_put_push_reg(ZzThumbWriter *self, ZzARMReg reg) { + ZzArmRegInfo ri; + zz_arm_register_describe(reg, &ri); + zuint16 M, register_list; M = 0; - register_list = regs & 0xFF; - zz_thumb_writer_put_instruction(self, 0b1011010000000000 | M << 8 | register_list); + zz_thumb_writer_put_instruction(self, 0b1011010000000000 | M << 8 | 1 << ri.index); + return; } -zpointer zz_thumb_writer_put_pop_reg(ZzThumbWriter *self, zint32 regs) { +void zz_thumb_writer_put_pop_reg(ZzThumbWriter *self, ZzARMReg reg) { + ZzArmRegInfo ri; + zz_arm_register_describe(reg, &ri); + zuint16 P, register_list; P = 0; - register_list = regs & 0xFF; - zz_thumb_writer_put_instruction(self, 0b1011110000000000 | P << 8 | register_list); + zz_thumb_writer_put_instruction(self, 0b1011110000000000 | P << 8 | 1 << ri.index); + return; } -zpointer zz_thumb_writer_put_add_reg_reg_reg(ZzThumbWriter *self, ZzARMReg dst_reg, ZzARMReg left_reg, - ZzARMReg right_reg) { +void zz_thumb_writer_put_add_reg_reg_reg(ZzThumbWriter *self, ZzARMReg dst_reg, ZzARMReg left_reg, ZzARMReg right_reg) { ZzArmRegInfo dst, left, right; zz_arm_register_describe(dst_reg, &dst); zz_arm_register_describe(left_reg, &left); @@ -530,4 +497,5 @@ zpointer zz_thumb_writer_put_add_reg_reg_reg(ZzThumbWriter *self, ZzARMReg dst_r Rn_ndx = left.index; zz_thumb_writer_put_instruction(self, 0b0001100000000000 | Rm_ndx << 6 | Rn_ndx << 3 | Rd_ndx); + return; } \ No newline at end of file diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/writer-thumb.h b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/writer-thumb.h index 5a277ba58..a05f03dec 100644 --- a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/writer-thumb.h +++ b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm/writer-thumb.h @@ -40,7 +40,7 @@ typedef enum _ZzThumbMemoryOperation { ZZ_THUMB_MEMORY_LOAD, ZZ_THUMB_MEMORY_STO // ------- user custom ------- -zpointer zz_thumb_writer_put_ldr_b_reg_address(ZzThumbWriter *self, ZzARMReg reg, zaddr address); +void zz_thumb_writer_put_ldr_b_reg_address(ZzThumbWriter *self, ZzARMReg reg, zaddr address); // ------- architecture default ------- @@ -48,40 +48,39 @@ ZzThumbWriter *zz_thumb_writer_new(zpointer data_ptr); void zz_thumb_writer_init(ZzThumbWriter *self, zpointer data_ptr); void zz_thumb_writer_reset(ZzThumbWriter *self, zpointer data_ptr); zsize zz_thumb_writer_near_jump_range_size(); -zpointer zz_thumb_writer_put_nop(ZzThumbWriter *self); -zpointer zz_thumb_writer_put_bytes(ZzThumbWriter *self, zbyte *data, zuint data_size); -zpointer zz_thumb_writer_put_instruction(ZzThumbWriter *self, uint16_t insn); -zpointer zz_thumb_writer_put_b_imm(ZzThumbWriter *self, zuint32 imm); -zpointer zz_thumb_writer_put_bx_reg(ZzThumbWriter *self, ZzARMReg reg); -zpointer zz_thumb_writer_put_blx_reg(ZzThumbWriter *self, ZzARMReg reg); -zpointer zz_thumb_writer_put_branch_imm(ZzThumbWriter *self, zuint32 imm, zbool link, zbool thumb); -zpointer zz_thumb_writer_put_bl_imm(ZzThumbWriter *self, zuint32 imm); -zpointer zz_thumb_writer_put_blx_imm(ZzThumbWriter *self, zuint32 imm); -zpointer zz_thumb_writer_put_b_imm32(ZzThumbWriter *self, zuint32 imm); +void zz_thumb_writer_put_nop(ZzThumbWriter *self); +void zz_thumb_writer_put_bytes(ZzThumbWriter *self, zbyte *data, zuint data_size); +void zz_thumb_writer_put_instruction(ZzThumbWriter *self, uint16_t insn); +void zz_thumb_writer_put_b_imm(ZzThumbWriter *self, zuint32 imm); +void zz_thumb_writer_put_bx_reg(ZzThumbWriter *self, ZzARMReg reg); +void zz_thumb_writer_put_blx_reg(ZzThumbWriter *self, ZzARMReg reg); +void zz_thumb_writer_put_branch_imm(ZzThumbWriter *self, zuint32 imm, zbool link, zbool thumb); +void zz_thumb_writer_put_bl_imm(ZzThumbWriter *self, zuint32 imm); +void zz_thumb_writer_put_blx_imm(ZzThumbWriter *self, zuint32 imm); +void zz_thumb_writer_put_b_imm32(ZzThumbWriter *self, zuint32 imm); -zpointer zz_thumb_writer_put_ldr_reg_imm(ZzThumbWriter *self, ZzARMReg reg, zint32 imm); -zpointer zz_thumb_writer_put_ldr_reg_address(ZzThumbWriter *self, ZzARMReg reg, zaddr address); +void zz_thumb_writer_put_ldr_reg_imm(ZzThumbWriter *self, ZzARMReg reg, zint32 imm); +void zz_thumb_writer_put_ldr_reg_address(ZzThumbWriter *self, ZzARMReg reg, zaddr address); -static zpointer zz_thumb_writer_put_transfer_reg_reg_offset(ZzThumbWriter *self, ZzThumbMemoryOperation operation, - ZzARMReg left_reg, ZzARMReg right_reg, zint32 right_offset); -zpointer zz_thumb_writer_put_ldr_reg_reg_offset(ZzThumbWriter *self, ZzARMReg dst_reg, ZzARMReg src_reg, - zint32 src_offset); -zpointer zz_thumb_writer_put_str_reg_reg_offset(ZzThumbWriter *self, ZzARMReg src_reg, ZzARMReg dst_reg, - zint32 dst_offset); -zpointer zz_thumb_writer_put_str_index_reg_reg_offset(ZzThumbWriter *self, ZzARMReg src_reg, ZzARMReg dst_reg, - zint32 dst_offset, zbool index); -zpointer zz_thumb_writer_put_ldr_index_reg_reg_offset(ZzThumbWriter *self, ZzARMReg dst_reg, ZzARMReg src_reg, - zint32 src_offset, zbool index); -zpointer zz_thumb_writer_put_str_reg_reg(ZzThumbWriter *self, ZzARMReg src_reg, ZzARMReg dst_reg); -zpointer zz_thumb_writer_put_ldr_reg_reg(ZzThumbWriter *self, ZzARMReg dst_reg, ZzARMReg src_reg); -zpointer zz_thumb_writer_put_add_reg_imm(ZzThumbWriter *self, ZzARMReg dst_reg, zint32 imm); -zpointer zz_thumb_writer_put_sub_reg_imm(ZzThumbWriter *self, ZzARMReg dst_reg, zint32 imm); -zpointer zz_thumb_writer_put_add_reg_reg_imm(ZzThumbWriter *self, ZzARMReg dst_reg, ZzARMReg left_reg, - zint32 right_value); -zpointer zz_thumb_writer_put_sub_reg_reg_imm(ZzThumbWriter *self, ZzARMReg dst_reg, ZzARMReg left_reg, - zint32 right_value); -zpointer zz_thumb_writer_put_push_reg(ZzThumbWriter *self, zint32 regs); -zpointer zz_thumb_writer_put_pop_reg(ZzThumbWriter *self, zint32 regs); -zpointer zz_thumb_writer_put_add_reg_reg_reg(ZzThumbWriter *self, ZzARMReg dst_reg, ZzARMReg left_reg, - ZzARMReg right_reg); +static void zz_thumb_writer_put_transfer_reg_reg_offset(ZzThumbWriter *self, ZzThumbMemoryOperation operation, + ZzARMReg left_reg, ZzARMReg right_reg, zint32 right_offset); +void zz_thumb_writer_put_ldr_reg_reg_offset(ZzThumbWriter *self, ZzARMReg dst_reg, ZzARMReg src_reg, zint32 src_offset); +void zz_thumb_writer_put_str_reg_reg_offset(ZzThumbWriter *self, ZzARMReg src_reg, ZzARMReg dst_reg, zint32 dst_offset); +void zz_thumb_writer_put_str_index_reg_reg_offset(ZzThumbWriter *self, ZzARMReg src_reg, ZzARMReg dst_reg, + zint32 dst_offset, zbool index); +void zz_thumb_writer_put_ldr_index_reg_reg_offset(ZzThumbWriter *self, ZzARMReg dst_reg, ZzARMReg src_reg, + zint32 src_offset, zbool index); +void zz_thumb_writer_put_str_reg_reg(ZzThumbWriter *self, ZzARMReg src_reg, ZzARMReg dst_reg); +void zz_thumb_writer_put_ldr_reg_reg(ZzThumbWriter *self, ZzARMReg dst_reg, ZzARMReg src_reg); +void zz_thumb_writer_put_add_reg_imm(ZzThumbWriter *self, ZzARMReg dst_reg, zint32 imm); +void zz_thumb_writer_put_sub_reg_imm(ZzThumbWriter *self, ZzARMReg dst_reg, zint32 imm); +void zz_thumb_writer_put_add_reg_reg_imm(ZzThumbWriter *self, ZzARMReg dst_reg, ZzARMReg left_reg, zint32 right_value); +void zz_thumb_writer_put_sub_reg_reg_imm(ZzThumbWriter *self, ZzARMReg dst_reg, ZzARMReg left_reg, zint32 right_value); +void zz_thumb_writer_put_push_reg(ZzThumbWriter *self, ZzARMReg reg); +void zz_thumb_writer_put_pop_reg(ZzThumbWriter *self, ZzARMReg reg); +void zz_thumb_writer_put_add_reg_reg_reg(ZzThumbWriter *self, ZzARMReg dst_reg, ZzARMReg left_reg, ZzARMReg right_reg); +ZzLiteralInstruction *zz_thumb_writer_put_ldr_reg_relocate_address(ZzThumbWriter *self, ZzARMReg reg, zaddr address, + ZzLiteralInstruction **literal_insn_ptr); +ZzLiteralInstruction *zz_thumb_writer_put_ldr_b_reg_relocate_address(ZzThumbWriter *self, ZzARMReg reg, zaddr address, + ZzLiteralInstruction **literal_insn_ptr); #endif \ No newline at end of file diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm64/instructions.c b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm64/instructions.c index e192e9055..00ec11d1c 100644 --- a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm64/instructions.c +++ b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm64/instructions.c @@ -6,7 +6,8 @@ zuint32 get_insn_sub(zuint32 insn, int start, int length) { return (insn >> star zbool insn_equal(zuint32 insn, char *opstr) { zuint32 mask = 0, value = 0; zsize length = strlen(opstr); - for (int i = length - 1, j = 0; i >= 0 && j < length; i--, j++) { + int i, j; + for (i = length - 1, j = 0; i >= 0 && j < length; i--, j++) { if (opstr[i] == 'x') { mask = mask | (0 << j); } else if (opstr[i] == '0') { diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm64/instructions.h b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm64/instructions.h index 78948cdcf..d16d377c5 100644 --- a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm64/instructions.h +++ b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm64/instructions.h @@ -26,6 +26,12 @@ typedef struct _ZzInstruction { zuint32 insn; } ZzInstruction; +typedef struct _ZzRelocateInstruction { + const ZzInstruction *insn_ctx; + zaddr relocated_offset; + zsize relocated_length; +} ZzRelocateInstruction; + zuint32 get_insn_sub(zuint32 insn, int start, int length); zbool insn_equal(zuint32 insn, char *opstr); diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm64/reader-arm64.c b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm64/reader-arm64.c index 28a548a83..37c3b4f9a 100644 --- a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm64/reader-arm64.c +++ b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm64/reader-arm64.c @@ -18,38 +18,7 @@ #include "zzdeps/common/debugbreak.h" #include "zzdeps/zz.h" -// static csh handle; - -// void zz_arm64_reader_capstone_init(void) { -// cs_err err = 0; - -// err = cs_open(CS_ARCH_ARM6464, CS_MODE_ARM64, &handle); -// if (err) { -// Xerror("Failed on cs_open() with error returned: %u\n", err); -// exit(-1); -// } - -// cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); -// } - -// cs_insn *zz_arm64_reader_disassemble_at(zpointer address) { -// if (!handle) -// zz_arm64_reader_capstone_init(); -// cs_insn *insn; -// size_t count; -// count = cs_disasm(handle, address, 16, (unsigned long)address, 0, &insn); -// if (!insn) { -// #if defined(DEBUG_MODE) -// debug_break(); -// #endif -// Xerror("zz_arm64_reader_disassemble_at error at %p", (zpointer)address); -// } -// return insn; -// } - zpointer zz_arm64_reader_read_one_instruction(ZzInstruction *insn_ctx, zpointer address) { - // ZzInstruction *insn = (ZzInstruction *)malloc(sizeof(ZzInstruction)); - insn_ctx->address = (zaddr)address; insn_ctx->size = 4; insn_ctx->pc = (zaddr)address; @@ -58,9 +27,6 @@ zpointer zz_arm64_reader_read_one_instruction(ZzInstruction *insn_ctx, zpointer } ARM64InsnType GetARM64InsnType(zuint32 insn) { - zuint32 op, op1; - op1 = get_insn_sub(insn, 20, 5); - // PAGE: C6-673 if (insn_equal(insn, "01011000xxxxxxxxxxxxxxxxxxxxxxxx")) { return ARM64_INS_LDR_literal; diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm64/relocator-arm64.c b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm64/relocator-arm64.c index ab97f45ce..b64dbd8db 100644 --- a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm64/relocator-arm64.c +++ b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm64/relocator-arm64.c @@ -23,75 +23,43 @@ void zz_arm64_relocator_init(ZzArm64Relocator *relocator, zpointer input_code, ZzArm64Writer *output) { relocator->inpos = 0; relocator->outpos = 0; - + relocator->output = output; relocator->input_start = input_code; relocator->input_cur = input_code; relocator->input_pc = (zaddr)input_code; - relocator->input_insns = (ZzInstruction *)malloc(MAX_RELOCATOR_INSTRUCIONS_SIZE * sizeof(ZzInstruction)); + relocator->relocate_literal_insns_size = 0; + relocator->try_relocated_length = 0; + relocator->input_insns = (ZzInstruction *)malloc(MAX_RELOCATOR_INSTRUCIONS_SIZE * sizeof(ZzInstruction)); memset(relocator->input_insns, 0, MAX_RELOCATOR_INSTRUCIONS_SIZE * sizeof(ZzInstruction)); - - relocator->output = output; + relocator->output_insns = + (ZzRelocateInstruction *)malloc(MAX_RELOCATOR_INSTRUCIONS_SIZE * sizeof(ZzRelocateInstruction)); + memset(relocator->output_insns, 0, MAX_RELOCATOR_INSTRUCIONS_SIZE * sizeof(ZzRelocateInstruction)); + relocator->relocate_literal_insns = + (ZzLiteralInstruction **)malloc(MAX_LITERAL_INSN_SIZE * sizeof(ZzLiteralInstruction *)); + memset(relocator->relocate_literal_insns, 0, MAX_LITERAL_INSN_SIZE * sizeof(ZzLiteralInstruction *)); } void zz_arm64_relocator_reset(ZzArm64Relocator *self, zpointer input_code, ZzArm64Writer *output) { self->input_cur = input_code; self->input_start = input_code; self->input_pc = (zaddr)input_code; - self->inpos = 0; self->outpos = 0; - self->output = output; -} + self->relocate_literal_insns_size = 0; + self->try_relocated_length = 0; -// zsize zz_arm64_relocator_read_one(ZzArm64Relocator *self, ZzInstruction *instruction) { -// insn_cs **insn_ctx_ptr, *insn_cs; -// ZzInstruction insn_ctx = self->input_insns[self->inpos]; -// insn_ctx_ptr = &insn_ctx.insn_cs; - -// if (cs_disasm(self->capstone, self->input_cur, 4, self->input_pc, 1, insn_ctx_ptr) != 1) { -// return 0; -// } - -// insn_cs = *insn_ctx_ptr; - -// // zbool flag = TRUE; -// // switch (insn_cs->id) { -// // case ARM64_INS_B: -// // if (branch_is_unconditional(ins)) -// // flag = relocator_rewrite_b(ins, relocate_writer); -// // else -// // flag = relocator_rewrite_b_cond(ins, relocate_writer); -// // break; -// // case ARM64_INS_LDR: -// // flag = relocator_rewrite_ldr(ins, relocate_writer); -// // break; -// // case ARM64_INS_ADR: -// // case ARM64_INS_ADRP: -// // flag = relocator_rewrite_adr(ins, relocate_writer); -// // break; -// // case ARM64_INS_BL: -// // flag = relocator_rewrite_bl(ins, relocate_writer); -// // break; -// // default: -// // zz_arm64_writer_put_bytes(relocate_writer, address, insn_cs->size); -// // } -// // if (!flag) -// // zz_arm64_writer_put_bytes(relocate_writer, address, insn_cs->size); - -// if (instruction != NULL) -// *instruction = insn_ctx; - -// self->input_cur += insn_cs->size; -// self->input_pc += insn_cs->size; - -// return self->input_cur - self->input_start; -// } + memset(self->input_insns, 0, MAX_RELOCATOR_INSTRUCIONS_SIZE * sizeof(ZzInstruction)); + memset(self->output_insns, 0, MAX_RELOCATOR_INSTRUCIONS_SIZE * sizeof(ZzRelocateInstruction)); + memset(self->relocate_literal_insns, 0, MAX_LITERAL_INSN_SIZE * sizeof(ZzLiteralInstruction *)); +} zsize zz_arm64_relocator_read_one(ZzArm64Relocator *self, ZzInstruction *instruction) { ZzInstruction *insn_ctx = &self->input_insns[self->inpos]; + ZzRelocateInstruction *re_insn_ctx = &self->output_insns[self->inpos]; + re_insn_ctx->insn_ctx = insn_ctx; zz_arm64_reader_read_one_instruction(insn_ctx, self->input_cur); // switch (0) {} @@ -99,7 +67,7 @@ zsize zz_arm64_relocator_read_one(ZzArm64Relocator *self, ZzInstruction *instruc self->inpos++; if (instruction != NULL) - instruction = insn_ctx; + *instruction = *insn_ctx; self->input_cur += insn_ctx->size; self->input_pc += insn_ctx->size; @@ -107,174 +75,76 @@ zsize zz_arm64_relocator_read_one(ZzArm64Relocator *self, ZzInstruction *instruc return self->input_cur - self->input_start; } +zaddr zz_arm64_relocator_get_insn_relocated_offset(ZzArm64Relocator *self, zaddr address) { + const ZzInstruction *insn_ctx; + const ZzRelocateInstruction *re_insn_ctx; + int i; + for (i = 0; i < self->inpos; i++) { + re_insn_ctx = &self->output_insns[i]; + insn_ctx = re_insn_ctx->insn_ctx; + if (insn_ctx->address == address && re_insn_ctx->relocated_offset) { + return re_insn_ctx->relocated_offset; + } + } + return 0; +} + +void zz_arm64_relocator_relocate_writer(ZzArm64Relocator *relocator, zaddr code_address) { + ZzArm64Writer *arm64_writer; + arm64_writer = relocator->output; + if (relocator->relocate_literal_insns_size) { + int i; + zaddr *rebase_ptr; + zaddr literal_address, relocated_offset, relocated_address, *literal_address_ptr; + for (i = 0; i < relocator->relocate_literal_insns_size; i++) { + literal_address_ptr = relocator->relocate_literal_insns[i]->literal_address_ptr; + literal_address = *literal_address_ptr; + relocated_offset = zz_arm64_relocator_get_insn_relocated_offset(relocator, literal_address); + if (relocated_offset) { + relocated_address = code_address + relocated_offset; + *literal_address_ptr = relocated_address; + } + } + } +} + void zz_arm64_relocator_write_all(ZzArm64Relocator *self) { zuint count = 0; + zuint outpos = self->outpos; + ZzArm64Writer arm64_writer = *self->output; + while (zz_arm64_relocator_write_one(self)) count++; } void zz_arm64_relocator_try_relocate(zpointer address, zuint min_bytes, zuint *max_bytes) { - *max_bytes = 16; + int tmp_size = 0; + zpointer target_addr; + ZzInstruction insn_ctx; + zbool early_end = FALSE; + target_addr = (zpointer)address; + + do { + zz_arm64_reader_read_one_instruction(&insn_ctx, target_addr); + switch (GetARM64InsnType(insn_ctx.insn)) { + case ARM64_INS_B: + early_end = TRUE; + break; + default:; + } + tmp_size += insn_ctx.size; + target_addr = target_addr + insn_ctx.size; + } while (tmp_size < min_bytes); + + if (early_end) { + *max_bytes = tmp_size; + } return; } -// static zbool zz_arm64_branch_is_unconditional(const cs_insn *insn) { -// switch (insn->detail->arm64.cc) { -// case ARM64_CC_INVALID: -// case ARM64_CC_AL: -// case ARM64_CC_NV: -// return TRUE; -// default: -// return FALSE; -// } -// } - -// static zbool zz_arm64_relocator_rewrite_ldr(ZzArm64Relocator *self, const ZzInstruction *insn_ctx) { -// const cs_arm64_op *dst = &insn_ctx->detail->operands[0]; -// const cs_arm64_op *src = &insn_ctx->detail->operands[1]; -// zbool dst_reg_is_fp_or_simd; -// ZzARM64Reg tmp_reg; - -// (void)self; - -// if (src->type != ARM64_OP_IMM) -// return FALSE; - -// dst_reg_is_fp_or_simd = (dst->reg >= ARM64_REG_S0 && dst->reg <= ARM64_REG_S31) || -// (dst->reg >= ARM64_REG_D0 && dst->reg <= ARM64_REG_D31) || -// (dst->reg >= ARM64_REG_Q0 && dst->reg <= ARM64_REG_Q31); -// if (dst_reg_is_fp_or_simd) { -// #if defined(DEBUG_MODE) -// debug_break(); -// #endif -// } else { -// if (dst->reg >= ARM64_REG_W0 && dst->reg <= ARM64_REG_W28) -// tmp_reg = ZZ_ARM64_REG_X0 + (dst->reg - ARM64_REG_W0); -// else if (dst->reg >= ARM64_REG_W29 && dst->reg <= ARM64_REG_W30) -// tmp_reg = ZZ_ARM64_REG_X29 + (dst->reg - ARM64_REG_W29); -// else -// tmp_reg = dst->reg; - -// zz_arm64_writer_put_ldr_b_reg_address(self->output, tmp_reg, src->imm); -// zz_arm64_writer_put_ldr_reg_reg_offset(self->output, dst->reg, tmp_reg, 0); -// } - -// return TRUE; -// } - -// static zbool zz_arm64_relocator_rewrite_adr(ZzArm64Relocator *self, const ZzInstruction *insn_ctx) { -// const cs_arm64_op *dst = &insn_ctx->detail->operands[0]; -// const cs_arm64_op *label = &insn_ctx->detail->operands[1]; - -// zz_arm64_writer_put_ldr_b_reg_address(self->output, dst->reg, label->imm); -// return TRUE; -// } - -// static zbool zz_arm64_relocator_rewrite_b(ZzArm64Relocator *self, const ZzInstruction *insn_ctx) { -// const cs_arm64_op *target = &insn_ctx->detail->operands[0]; - -// zz_arm64_writer_put_ldr_b_reg_address(self->output, ZZ_ARM64_REG_X17, target->imm); - -// return TRUE; -// } - -// static zbool zz_arm64_relocator_rewrite_b_cond(ZzArm64Relocator *self, const ZzInstruction *insn_ctx) { -// const cs_arm64_op *target = &insn_ctx->detail->operands[0]; - -// zz_arm64_writer_put_b_cond_imm(self->output, insn_ctx->detail->cc, 0x8); -// zz_arm64_writer_put_b_imm(self->output, 0x4 + 0x14); - -// zz_arm64_writer_put_ldr_br_reg_address(self->output, ZZ_ARM64_REG_X17, target->imm); - -// return TRUE; -// } - -// static zbool zz_arm64_relocator_rewrite_bl(ZzArm64Relocator *self, const ZzInstruction *insn_ctx) { -// const cs_arm64_op *target = &insn_ctx->detail->operands[0]; - -// zz_arm64_writer_put_ldr_br_reg_address(self->output, ZZ_ARM64_REG_LR, target->imm); - -// return TRUE; -// } - -// zbool relocator_rewrite_ldr(ZzInstruction *ins, ZzArm64Writer *relocate_writer) -// { -// cs_arm64 ins_csd = ins->insn_cs->detail->arm64; -// const cs_arm64_op *dst = &ins_csd.operands[0]; -// const cs_arm64_op *src = &ins_csd.operands[1]; -// if (src->type != ARM64_OP_IMM) -// return FALSE; -// return TRUE; -// } - -// zbool relocator_rewrite_b(ZzInstruction *ins, ZzArm64Writer *relocate_writer) { -// cs_arm64 ins_csd = ins->insn_cs->detail->arm64; -// zaddr target_addr = ins_csd.operands[0].imm; - -// // zz_arm64_writer_put_ldr_br_b_reg_address(relocate_writer, -// ZZ_ARM64_REG_X17, -// // target_addr); -// zz_arm64_writer_put_ldr_reg_address(relocate_writer, ZZ_ARM64_REG_X17, -// target_addr); -// zz_arm64_writer_put_br_reg(relocate_writer, ZZ_ARM64_REG_X17); -// return TRUE; -// } - -// zbool relocator_rewrite_bl(ZzInstruction *ins, ZzArm64Writer *relocate_writer) -// { -// cs_arm64 ins_csd = ins->insn_cs->detail->arm64; -// zaddr target_addr = ins_csd.operands[0].imm; - -// zz_arm64_writer_put_ldr_reg_address(relocate_writer, ZZ_ARM64_REG_X17, -// target_addr); -// zz_arm64_writer_put_blr_reg(relocate_writer, ZZ_ARM64_REG_X17); -// return TRUE; -// } - -// /* -// origin: -// 1. j.eq [3] - -// 2. [...] -// 3. [...] - -// rwrite: -// 1. j.eq [1.2] -// 1.1 b [2] -// 1.2 abs_jmp [3] - -// 2. [...] -// 3. [...] -// */ -// zbool relocator_rewrite_b_cond(ZzInstruction *ins, -// ZzArm64Writer *relocate_writer) { -// cs_arm64 ins_csd = ins->insn_cs->detail->arm64; -// zaddr target_addr = ins_csd.operands[0].imm; - -// zz_arm64_writer_put_b_cond_imm(relocate_writer, ins_csd.cc, 0x8); -// zz_arm64_writer_put_b_imm(relocate_writer, 0x4 + 0x14); - -// // zz_arm64_writer_put_ldr_br_b_reg_address(relocate_writer, -// ZZ_ARM64_REG_X17, -// // target_addr); -// zz_arm64_writer_put_ldr_reg_address(relocate_writer, ZZ_ARM64_REG_X17, -// target_addr); -// zz_arm64_writer_put_br_reg(relocate_writer, ZZ_ARM64_REG_X17); -// return TRUE; -// } - -// zbool relocator_rewrite_adr(ZzInstruction *ins, ZzArm64Writer *relocate_writer) -// { -// cs_arm64 ins_csd = ins->insn_cs->detail->arm64; - -// const cs_arm64_op dst = ins_csd.operands[0]; -// const cs_arm64_op label = ins_csd.operands[1]; -// zz_arm64_writer_put_ldr_reg_address(relocate_writer, dst.reg, label.imm); -// return TRUE; -// } - // PAGE: C6-673 -static zbool zz_arm64_relocator_rewrite_LDR_literal(ZzArm64Relocator *self, const ZzInstruction *insn_ctx) { +static zbool zz_arm64_relocator_rewrite_LDR_literal(ZzArm64Relocator *self, const ZzInstruction *insn_ctx, + ZzRelocateInstruction *re_insn_ctx) { zuint32 insn = insn_ctx->insn; // TODO: check opc == 10, with signed zuint32 imm19 = get_insn_sub(insn, 5, 19); @@ -286,11 +156,13 @@ static zbool zz_arm64_relocator_rewrite_LDR_literal(ZzArm64Relocator *self, cons zz_arm64_writer_put_ldr_b_reg_address(self->output, Rt_ndx, target_address); zz_arm64_writer_put_ldr_reg_reg_offset(self->output, Rt_ndx, Rt_ndx, 0); + return TRUE; } // PAGE: C6-535 -static zbool zz_arm64_relocator_rewrite_ADR(ZzArm64Relocator *self, const ZzInstruction *insn_ctx) { +static zbool zz_arm64_relocator_rewrite_ADR(ZzArm64Relocator *self, const ZzInstruction *insn_ctx, + ZzRelocateInstruction *re_insn_ctx) { zuint32 insn = insn_ctx->insn; zuint32 immhi = get_insn_sub(insn, 5, 19); zuint32 immlo = get_insn_sub(insn, 29, 2); @@ -301,11 +173,13 @@ static zbool zz_arm64_relocator_rewrite_ADR(ZzArm64Relocator *self, const ZzInst int Rt_ndx = get_insn_sub(insn, 0, 4); zz_arm64_writer_put_ldr_b_reg_address(self->output, Rt_ndx, target_address); + return TRUE; } // PAGE: C6-536 -static zbool zz_arm64_relocator_rewrite_ADRP(ZzArm64Relocator *self, const ZzInstruction *insn_ctx) { +static zbool zz_arm64_relocator_rewrite_ADRP(ZzArm64Relocator *self, const ZzInstruction *insn_ctx, + ZzRelocateInstruction *re_insn_ctx) { zuint32 insn = insn_ctx->insn; zuint32 immhi = get_insn_sub(insn, 5, 19); zuint32 immlo = get_insn_sub(insn, 29, 2); @@ -313,15 +187,17 @@ static zbool zz_arm64_relocator_rewrite_ADRP(ZzArm64Relocator *self, const ZzIns zuint64 imm = immhi << 2 << 12 | immlo << 12; zaddr target_address; - target_address = (insn_ctx->pc & (1 << 12)) + imm; + target_address = (insn_ctx->pc & 0xFFFFFFFFFFFFF000) + imm; int Rt_ndx = get_insn_sub(insn, 0, 4); zz_arm64_writer_put_ldr_b_reg_address(self->output, Rt_ndx, target_address); + return TRUE; } // PAGE: C6-550 -static zbool zz_arm64_relocator_rewrite_B(ZzArm64Relocator *self, const ZzInstruction *insn_ctx) { +static zbool zz_arm64_relocator_rewrite_B(ZzArm64Relocator *self, const ZzInstruction *insn_ctx, + ZzRelocateInstruction *re_insn_ctx) { zuint32 insn = insn_ctx->insn; zuint32 imm26 = get_insn_sub(insn, 0, 26); @@ -329,14 +205,15 @@ static zbool zz_arm64_relocator_rewrite_B(ZzArm64Relocator *self, const ZzInstru zaddr target_address; target_address = insn_ctx->pc + offset; - int Rt_ndx = get_insn_sub(insn, 0, 4); zz_arm64_writer_put_ldr_br_reg_address(self->output, ZZ_ARM64_REG_X17, target_address); + return TRUE; } // PAGE: C6-560 -static zbool zz_arm64_relocator_rewrite_BL(ZzArm64Relocator *self, const ZzInstruction *insn_ctx) { +static zbool zz_arm64_relocator_rewrite_BL(ZzArm64Relocator *self, const ZzInstruction *insn_ctx, + ZzRelocateInstruction *re_insn_ctx) { zuint32 insn = insn_ctx->insn; zuint32 imm26 = get_insn_sub(insn, 0, 26); @@ -344,30 +221,28 @@ static zbool zz_arm64_relocator_rewrite_BL(ZzArm64Relocator *self, const ZzInstr zaddr target_address; target_address = insn_ctx->pc + offset; - int Rt_ndx = get_insn_sub(insn, 0, 4); zz_arm64_writer_put_ldr_blr_b_reg_address(self->output, ZZ_ARM64_REG_X17, target_address); + ZzLiteralInstruction **literal_insn_ptr = &(self->relocate_literal_insns[self->relocate_literal_insns_size++]); + zz_arm64_writer_put_ldr_br_reg_relocate_address(self->output, ZZ_ARM64_REG_X17, insn_ctx->pc + 4, literal_insn_ptr); + return TRUE; } -/* - origin: - 1. j.eq [3] +// 0x000 : b.cond 0x8; - 2. [...] - 3. [...] +// 0x004 : b 0x14 - rwrite: - 1. j.eq [1.2] - 1.1 b [2] - 1.2 abs_jmp [3] +// 0x008 : ldr x17, [pc, #4] +// 0x00c : br x17 +// 0x010 : .long 0x0 +// 0x014 : .long 0x0 - 2. [...] - 3. [...] - */ +// 0x018 : remain code // PAGE: C6-549 -static zbool zz_arm64_relocator_rewrite_B_cond(ZzArm64Relocator *self, const ZzInstruction *insn_ctx) { +static zbool zz_arm64_relocator_rewrite_B_cond(ZzArm64Relocator *self, const ZzInstruction *insn_ctx, + ZzRelocateInstruction *re_insn_ctx) { zuint32 insn = insn_ctx->insn; zuint32 imm19 = get_insn_sub(insn, 5, 19); @@ -379,7 +254,7 @@ static zbool zz_arm64_relocator_rewrite_B_cond(ZzArm64Relocator *self, const ZzI zuint32 cond = get_insn_sub(insn, 0, 4); zz_arm64_writer_put_b_cond_imm(self->output, cond, 0x8); - zz_arm64_writer_put_b_imm(self->output, 0xc); + zz_arm64_writer_put_b_imm(self->output, 0x14); zz_arm64_writer_put_ldr_br_reg_address(self->output, ZZ_ARM64_REG_X17, target_address); return TRUE; @@ -387,32 +262,37 @@ static zbool zz_arm64_relocator_rewrite_B_cond(ZzArm64Relocator *self, const ZzI zbool zz_arm64_relocator_write_one(ZzArm64Relocator *self) { const ZzInstruction *insn_ctx; + ZzRelocateInstruction *re_insn_ctx; + zbool rewritten = FALSE; if (self->inpos != self->outpos) { insn_ctx = &self->input_insns[self->outpos]; + re_insn_ctx = &self->output_insns[self->outpos]; self->outpos++; } else return FALSE; + re_insn_ctx->relocated_offset = (zaddr)self->output->pc - (zaddr)self->output->base; + switch (GetARM64InsnType(insn_ctx->insn)) { case ARM64_INS_LDR_literal: - rewritten = zz_arm64_relocator_rewrite_LDR_literal(self, insn_ctx); + rewritten = zz_arm64_relocator_rewrite_LDR_literal(self, insn_ctx, re_insn_ctx); break; case ARM64_INS_ADR: - rewritten = zz_arm64_relocator_rewrite_ADR(self, insn_ctx); + rewritten = zz_arm64_relocator_rewrite_ADR(self, insn_ctx, re_insn_ctx); break; case ARM64_INS_ADRP: - rewritten = zz_arm64_relocator_rewrite_ADRP(self, insn_ctx); + rewritten = zz_arm64_relocator_rewrite_ADRP(self, insn_ctx, re_insn_ctx); break; case ARM64_INS_B: - rewritten = zz_arm64_relocator_rewrite_B(self, insn_ctx); + rewritten = zz_arm64_relocator_rewrite_B(self, insn_ctx, re_insn_ctx); break; case ARM64_INS_BL: - rewritten = zz_arm64_relocator_rewrite_BL(self, insn_ctx); + rewritten = zz_arm64_relocator_rewrite_BL(self, insn_ctx, re_insn_ctx); break; case ARM64_INS_B_cond: - rewritten = zz_arm64_relocator_rewrite_B_cond(self, insn_ctx); + rewritten = zz_arm64_relocator_rewrite_B_cond(self, insn_ctx, re_insn_ctx); break; default: rewritten = FALSE; @@ -420,5 +300,7 @@ zbool zz_arm64_relocator_write_one(ZzArm64Relocator *self) { } if (!rewritten) zz_arm64_writer_put_bytes(self->output, (zbyte *)&insn_ctx->insn, insn_ctx->size); + re_insn_ctx->relocated_length = + (zaddr)self->output->pc - (zaddr)self->output->base - (zaddr)re_insn_ctx->relocated_offset; return TRUE; } \ No newline at end of file diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm64/relocator-arm64.h b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm64/relocator-arm64.h index ae2db64bf..e0d8824e1 100644 --- a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm64/relocator-arm64.h +++ b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm64/relocator-arm64.h @@ -33,14 +33,18 @@ #include "zzdeps/zz.h" typedef struct _ZzArm64Relocator { + zbool try_relocated_again; + zsize try_relocated_length; zpointer input_start; zpointer input_cur; zaddr input_pc; - ZzInstruction *input_insns; - ZzArm64Writer *output; - zuint inpos; zuint outpos; + ZzInstruction *input_insns; + ZzRelocateInstruction *output_insns; + ZzArm64Writer *output; + ZzLiteralInstruction **relocate_literal_insns; + zsize relocate_literal_insns_size; } ZzArm64Relocator; void zz_arm64_relocator_init(ZzArm64Relocator *relocator, zpointer input_code, ZzArm64Writer *writer); @@ -52,9 +56,14 @@ void zz_arm64_relocator_write_all(ZzArm64Relocator *self); void zz_arm64_relocator_try_relocate(zpointer address, zuint min_bytes, zuint *max_bytes); /* rewrite */ -static zbool zz_arm64_relocator_rewrite_ldr(ZzArm64Relocator *self, const ZzInstruction *insn_ctx); -static zbool zz_arm64_relocator_rewrite_adr(ZzArm64Relocator *self, const ZzInstruction *insn_ctx); -static zbool zz_arm64_relocator_rewrite_b(ZzArm64Relocator *self, const ZzInstruction *insn_ctx); -static zbool zz_arm64_relocator_rewrite_b_cond(ZzArm64Relocator *self, const ZzInstruction *insn_ctx); -static zbool zz_arm64_relocator_rewrite_bl(ZzArm64Relocator *self, const ZzInstruction *insn_ctx); +static zbool zz_arm64_relocator_rewrite_ldr(ZzArm64Relocator *self, const ZzInstruction *insn_ctx, + ZzRelocateInstruction *re_insn_ctx); +static zbool zz_arm64_relocator_rewrite_adr(ZzArm64Relocator *self, const ZzInstruction *insn_ctx, + ZzRelocateInstruction *re_insn_ctx); +static zbool zz_arm64_relocator_rewrite_b(ZzArm64Relocator *self, const ZzInstruction *insn_ctx, + ZzRelocateInstruction *re_insn_ctx); +static zbool zz_arm64_relocator_rewrite_b_cond(ZzArm64Relocator *self, const ZzInstruction *insn_ctx, + ZzRelocateInstruction *re_insn_ctx); +static zbool zz_arm64_relocator_rewrite_bl(ZzArm64Relocator *self, const ZzInstruction *insn_ctx, + ZzRelocateInstruction *re_insn_ctx); #endif \ No newline at end of file diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm64/writer-arm64.c b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm64/writer-arm64.c index 35c4a898d..ae1ec1353 100644 --- a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm64/writer-arm64.c +++ b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm64/writer-arm64.c @@ -30,59 +30,86 @@ ZzArm64Writer *zz_arm64_writer_new(zpointer data_ptr) { ZzArm64Writer *writer = (ZzArm64Writer *)malloc(sizeof(ZzArm64Writer)); - int t = 4 - (zaddr)data_ptr % 4; + memset(writer, 0, sizeof(ZzArm64Writer)); - writer->codedata = data_ptr + t; - writer->base = data_ptr + t; - writer->pc = data_ptr + t; + zaddr align_address = (zaddr)data_ptr & ~(zaddr)3; + writer->codedata = (zpointer)align_address; + writer->base = (zpointer)align_address; + writer->pc = align_address; writer->size = 0; + + writer->literal_insn_size = 0; + memset(writer->literal_insns, 0, sizeof(ZzLiteralInstruction) * MAX_LITERAL_INSN_SIZE); + return writer; } void zz_arm64_writer_init(ZzArm64Writer *self, zpointer target_addr) { zz_arm64_writer_reset(self, target_addr); } void zz_arm64_writer_reset(ZzArm64Writer *self, zpointer data_ptr) { - int t = (zaddr)data_ptr % 4; + zaddr align_address = (zaddr)data_ptr & ~(zaddr)3; - self->codedata = data_ptr + t; - self->base = data_ptr + t; - self->pc = data_ptr + t; + self->codedata = (zpointer)align_address; + self->base = (zpointer)align_address; + self->pc = align_address; self->size = 0; + + self->literal_insn_size = 0; + memset(self->literal_insns, 0, sizeof(ZzLiteralInstruction) * MAX_LITERAL_INSN_SIZE); +} + +// ======= relocator ======= + +ZzLiteralInstruction *zz_arm64_writer_put_ldr_br_reg_relocate_address(ZzWriter *self, ZzARM64Reg reg, zaddr address, + ZzLiteralInstruction **literal_insn_ptr) { + + zz_arm64_writer_put_ldr_br_reg_address(self, reg, address); + ZzLiteralInstruction *literal_insn = &(self->literal_insns[self->literal_insn_size - 1]); + *literal_insn_ptr = literal_insn; + return literal_insn; } // ======= user custom ======= void zz_arm64_writer_put_ldr_br_reg_address(ZzWriter *self, ZzARM64Reg reg, zaddr address) { + self->literal_insns[self->literal_insn_size].literal_insn_ptr = self->codedata; zz_arm64_writer_put_ldr_reg_imm(self, reg, (zuint)0x8); zz_arm64_writer_put_br_reg(self, reg); + self->literal_insns[self->literal_insn_size++].literal_address_ptr = self->codedata; zz_arm64_writer_put_bytes(self, (zpointer)&address, sizeof(zpointer)); } void zz_arm64_writer_put_ldr_blr_b_reg_address(ZzWriter *self, ZzARM64Reg reg, zaddr address) { + self->literal_insns[self->literal_insn_size].literal_insn_ptr = self->codedata; zz_arm64_writer_put_ldr_reg_imm(self, reg, (zuint)0xc); zz_arm64_writer_put_blr_reg(self, reg); zz_arm64_writer_put_b_imm(self, 0xc); + self->literal_insns[self->literal_insn_size++].literal_address_ptr = self->codedata; zz_arm64_writer_put_bytes(self, (zpointer)&address, sizeof(zpointer)); } void zz_arm64_writer_put_ldr_b_reg_address(ZzWriter *self, ZzARM64Reg reg, zaddr address) { + self->literal_insns[self->literal_insn_size].literal_insn_ptr = self->codedata; zz_arm64_writer_put_ldr_reg_imm(self, reg, (zuint)0x8); zz_arm64_writer_put_b_imm(self, 0xc); + self->literal_insns[self->literal_insn_size++].literal_address_ptr = self->codedata; zz_arm64_writer_put_bytes(self, (zpointer)&address, sizeof(address)); } zsize zz_arm64_writer_near_jump_range_size() { return ((1 << 25) << 2); } void zz_arm64_writer_put_ldr_br_b_reg_address(ZzWriter *self, ZzARM64Reg reg, zaddr address) { + self->literal_insns[self->literal_insn_size].literal_insn_ptr = self->codedata; zz_arm64_writer_put_ldr_reg_imm(self, reg, (zuint)0xc); zz_arm64_writer_put_br_reg(self, reg); zz_arm64_writer_put_b_imm(self, 0xc); + self->literal_insns[self->literal_insn_size++].literal_address_ptr = self->codedata; zz_arm64_writer_put_bytes(self, (zpointer)&address, sizeof(address)); } // ======= default ======= -zpointer zz_arm64_writer_put_ldr_reg_imm(ZzWriter *self, ZzARM64Reg reg, zuint32 offset) { +void zz_arm64_writer_put_ldr_reg_imm(ZzWriter *self, ZzARM64Reg reg, zuint32 offset) { ZzArm64RegInfo ri; zz_arm64_register_describe(reg, &ri); @@ -92,12 +119,11 @@ zpointer zz_arm64_writer_put_ldr_reg_imm(ZzWriter *self, ZzARM64Reg reg, zuint32 Rt_ndx = ri.index; zz_arm64_writer_put_instruction(self, 0x58000000 | imm19 << 5 | Rt_ndx); - return self->pc; + return; } // PAGE: C6-871 -zpointer zz_arm64_writer_put_str_reg_reg_offset(ZzWriter *self, ZzARM64Reg src_reg, ZzARM64Reg dst_reg, - zuint64 offset) { +void zz_arm64_writer_put_str_reg_reg_offset(ZzWriter *self, ZzARM64Reg src_reg, ZzARM64Reg dst_reg, zuint64 offset) { ZzArm64RegInfo rs, rd; zz_arm64_register_describe(src_reg, &rs); @@ -114,11 +140,10 @@ zpointer zz_arm64_writer_put_str_reg_reg_offset(ZzWriter *self, ZzARM64Reg src_r zuint32 imm12 = offset >> size; zz_arm64_writer_put_instruction(self, 0x39000000 | size << 30 | opc << 22 | imm12 << 10 | Rn_ndx << 5 | Rt_ndx); - return self->pc; + return; } -zpointer zz_arm64_writer_put_ldr_reg_reg_offset(ZzWriter *self, ZzARM64Reg dst_reg, ZzARM64Reg src_reg, - zuint64 offset) { +void zz_arm64_writer_put_ldr_reg_reg_offset(ZzWriter *self, ZzARM64Reg dst_reg, ZzARM64Reg src_reg, zuint64 offset) { ZzArm64RegInfo rs, rd; zz_arm64_register_describe(src_reg, &rs); @@ -135,22 +160,22 @@ zpointer zz_arm64_writer_put_ldr_reg_reg_offset(ZzWriter *self, ZzARM64Reg dst_r zuint32 imm12 = offset >> size; zz_arm64_writer_put_instruction(self, 0x39000000 | size << 30 | opc << 22 | imm12 << 10 | Rn_ndx << 5 | Rt_ndx); - return self->pc; + return; } // C6-562 -zpointer zz_arm64_writer_put_br_reg(ZzWriter *self, ZzARM64Reg reg) { +void zz_arm64_writer_put_br_reg(ZzWriter *self, ZzARM64Reg reg) { ZzArm64RegInfo ri; zz_arm64_register_describe(reg, &ri); zuint32 op = 0, Rn_ndx; Rn_ndx = ri.index; zz_arm64_writer_put_instruction(self, 0xd61f0000 | op << 21 | Rn_ndx << 5); - return self->pc; + return; } // C6-561 -zpointer zz_arm64_writer_put_blr_reg(ZzWriter *self, ZzARM64Reg reg) { +void zz_arm64_writer_put_blr_reg(ZzWriter *self, ZzARM64Reg reg) { ZzArm64RegInfo ri; zz_arm64_register_describe(reg, &ri); @@ -159,29 +184,29 @@ zpointer zz_arm64_writer_put_blr_reg(ZzWriter *self, ZzARM64Reg reg) { Rn_ndx = ri.index; zz_arm64_writer_put_instruction(self, 0xd63f0000 | op << 21 | Rn_ndx << 5); - return self->pc; + return; } // C6-550 -zpointer zz_arm64_writer_put_b_imm(ZzWriter *self, zuint64 offset) { +void zz_arm64_writer_put_b_imm(ZzWriter *self, zuint64 offset) { zuint32 op = 0b0, imm26; imm26 = (offset >> 2) & 0x03ffffff; zz_arm64_writer_put_instruction(self, 0x14000000 | op << 31 | imm26); - return self->pc; + return; } // TODO: standard form, need fix others // PAGE: C6-549 -zpointer zz_arm64_writer_put_b_cond_imm(ZzWriter *self, zuint32 condition, zuint64 imm) { +void zz_arm64_writer_put_b_cond_imm(ZzWriter *self, zuint32 condition, zuint64 imm) { zuint32 imm19, cond; cond = condition; imm19 = (imm >> 2) & 0x7ffff; zz_arm64_writer_put_instruction(self, 0x54000000 | imm19 << 5 | cond); - return self->pc; + return; } // C6-525 -zpointer zz_arm64_writer_put_add_reg_reg_imm(ZzWriter *self, ZzARM64Reg dst_reg, ZzARM64Reg left_reg, zuint64 imm) { +void zz_arm64_writer_put_add_reg_reg_imm(ZzWriter *self, ZzARM64Reg dst_reg, ZzARM64Reg left_reg, zuint64 imm) { ZzArm64RegInfo rd, rl; zz_arm64_register_describe(dst_reg, &rd); @@ -195,11 +220,11 @@ zpointer zz_arm64_writer_put_add_reg_reg_imm(ZzWriter *self, ZzARM64Reg dst_reg, zz_arm64_writer_put_instruction(self, 0x11000000 | sf << 31 | op << 30 | S << 29 | shift << 22 | imm12 << 10 | Rn_ndx << 5 | Rd_ndx); - return self->pc; + return; } // C6-930 -zpointer zz_arm64_writer_put_sub_reg_reg_imm(ZzWriter *self, ZzARM64Reg dst_reg, ZzARM64Reg left_reg, zuint64 imm) { +void zz_arm64_writer_put_sub_reg_reg_imm(ZzWriter *self, ZzARM64Reg dst_reg, ZzARM64Reg left_reg, zuint64 imm) { ZzArm64RegInfo rd, rl; zz_arm64_register_describe(dst_reg, &rd); @@ -213,21 +238,21 @@ zpointer zz_arm64_writer_put_sub_reg_reg_imm(ZzWriter *self, ZzARM64Reg dst_reg, zz_arm64_writer_put_instruction(self, 0x11000000 | sf << 31 | op << 30 | S << 29 | shift << 22 | imm12 << 10 | Rn_ndx << 5 | Rd_ndx); - return self->pc; + return; } -zpointer zz_arm64_writer_put_bytes(ZzWriter *self, zbyte *data, zsize size) { +void zz_arm64_writer_put_bytes(ZzWriter *self, zbyte *data, zsize size) { memcpy(self->codedata, data, size); self->codedata = (zpointer)self->codedata + size; self->pc += size; self->size += size; - return self->pc; + return; } -zpointer zz_arm64_writer_put_instruction(ZzWriter *self, zuint32 insn) { +void zz_arm64_writer_put_instruction(ZzWriter *self, zuint32 insn) { *(zuint32 *)(self->codedata) = insn; self->codedata = (zpointer)self->codedata + sizeof(zuint32); self->pc += 4; self->size += 4; - return self->pc; + return; } diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm64/writer-arm64.h b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm64/writer-arm64.h index 009639f39..2b7370fbd 100644 --- a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm64/writer-arm64.h +++ b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-arm64/writer-arm64.h @@ -50,16 +50,21 @@ void zz_arm64_writer_put_ldr_br_b_reg_address(ZzArm64Writer *self, ZzARM64Reg re // ======= default ======= -zpointer zz_arm64_writer_put_ldr_reg_imm(ZzWriter *self, ZzARM64Reg reg, zuint32 offset); -zpointer zz_arm64_writer_put_str_reg_reg_offset(ZzWriter *self, ZzARM64Reg src_reg, ZzARM64Reg dst_reg, zuint64 offset); -zpointer zz_arm64_writer_put_ldr_reg_reg_offset(ZzWriter *self, ZzARM64Reg dst_reg, ZzARM64Reg src_reg, zuint64 offset); -zpointer zz_arm64_writer_put_br_reg(ZzWriter *self, ZzARM64Reg reg); -zpointer zz_arm64_writer_put_blr_reg(ZzWriter *self, ZzARM64Reg reg); -zpointer zz_arm64_writer_put_b_imm(ZzWriter *self, zuint64 offset); -zpointer zz_arm64_writer_put_b_cond_imm(ZzWriter *self, zuint32 condition, zuint64 imm); -zpointer zz_arm64_writer_put_add_reg_reg_imm(ZzWriter *self, ZzARM64Reg dst_reg, ZzARM64Reg left_reg, zuint64 imm); -zpointer zz_arm64_writer_put_sub_reg_reg_imm(ZzWriter *self, ZzARM64Reg dst_reg, ZzARM64Reg left_reg, zuint64 imm); -zpointer zz_arm64_writer_put_bytes(ZzWriter *self, zbyte *data, zsize size); -zpointer zz_arm64_writer_put_instruction(ZzWriter *self, zuint32 insn); +void zz_arm64_writer_put_ldr_reg_imm(ZzWriter *self, ZzARM64Reg reg, zuint32 offset); +void zz_arm64_writer_put_str_reg_reg_offset(ZzWriter *self, ZzARM64Reg src_reg, ZzARM64Reg dst_reg, zuint64 offset); +void zz_arm64_writer_put_ldr_reg_reg_offset(ZzWriter *self, ZzARM64Reg dst_reg, ZzARM64Reg src_reg, zuint64 offset); +void zz_arm64_writer_put_br_reg(ZzWriter *self, ZzARM64Reg reg); +void zz_arm64_writer_put_blr_reg(ZzWriter *self, ZzARM64Reg reg); +void zz_arm64_writer_put_b_imm(ZzWriter *self, zuint64 offset); +void zz_arm64_writer_put_b_cond_imm(ZzWriter *self, zuint32 condition, zuint64 imm); +void zz_arm64_writer_put_add_reg_reg_imm(ZzWriter *self, ZzARM64Reg dst_reg, ZzARM64Reg left_reg, zuint64 imm); +void zz_arm64_writer_put_sub_reg_reg_imm(ZzWriter *self, ZzARM64Reg dst_reg, ZzARM64Reg left_reg, zuint64 imm); +void zz_arm64_writer_put_bytes(ZzWriter *self, zbyte *data, zsize size); +void zz_arm64_writer_put_instruction(ZzWriter *self, zuint32 insn); + +// ======= relocator ======= + +ZzLiteralInstruction *zz_arm64_writer_put_ldr_br_reg_relocate_address(ZzWriter *self, ZzARM64Reg reg, zaddr address, + ZzLiteralInstruction **literal_insn_ptr); #endif \ No newline at end of file diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-x86/instructions.c b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-x86/instructions.c new file mode 100644 index 000000000..dc09a0d61 --- /dev/null +++ b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-x86/instructions.c @@ -0,0 +1,2 @@ +#include "instructions.h" +#include diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-x86/instructions.h b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-x86/instructions.h new file mode 100644 index 000000000..adc4675f8 --- /dev/null +++ b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-x86/instructions.h @@ -0,0 +1,31 @@ +/** + * Copyright 2017 jmpews + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef platforms_arch_x86_instructions_h +#define platforms_arch_x86_instructions_h + +#include "hookzz.h" + +typedef struct _ZzInstruction { +} ZzInstruction; + +typedef struct _ZzRelocateInstruction { + const ZzInstruction *insn_ctx; + zaddr relocated_offset; + zsize relocated_length; +} ZzRelocateInstruction; + +#endif \ No newline at end of file diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-x86/reader-x86.c b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-x86/reader-x86.c new file mode 100644 index 000000000..8185d3ed0 --- /dev/null +++ b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-x86/reader-x86.c @@ -0,0 +1,23 @@ +/** + * Copyright 2017 jmpews + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "reader-x86.h" +#include "zzdeps/common/debugbreak.h" +#include "zzdeps/zz.h" + +zpointer zz_x86_reader_read_one_instruction(ZzInstruction *insn_ctx, zpointer address) { return NULL; } + +X86InsnType GetX86InsnType(zuint32 insn) { return X86_UNDEF; } \ No newline at end of file diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-x86/reader-x86.h b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-x86/reader-x86.h new file mode 100644 index 000000000..864610be2 --- /dev/null +++ b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-x86/reader-x86.h @@ -0,0 +1,37 @@ +/** + * Copyright 2017 jmpews + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef platforms_arch_x86_reader_h +#define platforms_arch_x86_reader_h + +// platforms +#include "instructions.h" + +// hookzz + +// zzdeps +#include "hookzz.h" +#include "zzdefs.h" +#include "zzdeps/common/debugbreak.h" +#include "zzdeps/zz.h" + +typedef enum _X86InsnType { X86_UNDEF } X86InsnType; + +X86InsnType GetX86InsnType(zuint32 insn); + +zpointer zz_x86_reader_read_one_instruction(ZzInstruction *insn_ctx, zpointer address); + +#endif \ No newline at end of file diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/backend-arm/trampoline-arm.h b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-x86/regs-x86.c similarity index 86% rename from VirtualApp/lib/src/main/jni/HookZz/src/platforms/backend-arm/trampoline-arm.h rename to VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-x86/regs-x86.c index 6548be5b4..91af33c98 100644 --- a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/backend-arm/trampoline-arm.h +++ b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-x86/regs-x86.c @@ -12,4 +12,10 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - */ \ No newline at end of file + */ + +#include "regs-x86.h" + +void zz_x86_register_describe(ZzX86Reg reg, ZzX86RegInfo *ri) { + +} diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-x86/regs-x86.h b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-x86/regs-x86.h new file mode 100644 index 000000000..377ee37a7 --- /dev/null +++ b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-x86/regs-x86.h @@ -0,0 +1,39 @@ +/** + * Copyright 2017 jmpews + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef platforms_arch_x86_regs_h +#define platforms_arch_x86_regs_h + +// platforms +#include "instructions.h" + +// hookzz + +// zzdeps +#include "hookzz.h" +#include "zzdefs.h" +#include "zzdeps/common/debugbreak.h" +#include "zzdeps/zz.h" + +typedef enum _ZzX86Reg { X86_REG_UNDEF } ZzX86Reg; + +typedef struct _ZzX86RegInfo { + +} ZzX86RegInfo; + +void zz_x86_register_describe(ZzX86Reg reg, ZzX86RegInfo *ri); + +#endif \ No newline at end of file diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-x86/relocator-x86.c b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-x86/relocator-x86.c new file mode 100644 index 000000000..3380a97ae --- /dev/null +++ b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-x86/relocator-x86.c @@ -0,0 +1,48 @@ +/** + * Copyright 2017 jmpews + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "relocator-x86.h" +#include +#include + +#define MAX_RELOCATOR_INSTRUCIONS_SIZE 64 + +void zz_x86_relocator_init(ZzX86Relocator *relocator, zpointer input_code, ZzX86Writer *output) { +} + +void zz_x86_relocator_reset(ZzX86Relocator *self, zpointer input_code, ZzX86Writer *output) { +} + +zsize zz_x86_relocator_read_one(ZzX86Relocator *self, ZzInstruction *instruction) { + return 0; +} + +zaddr zz_x86_relocator_get_insn_relocated_offset(ZzX86Relocator *self, zaddr address) { + return 0; +} + +void zz_x86_relocator_relocate_writer(ZzX86Relocator *relocator, zaddr code_address) { +} + +void zz_x86_relocator_write_all(ZzX86Relocator *self) { +} + +void zz_x86_relocator_try_relocate(zpointer address, zuint min_bytes, zuint *max_bytes) { +} + +zbool zz_x86_relocator_write_one(ZzX86Relocator *self) { + return TRUE; +} \ No newline at end of file diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-x86/relocator-x86.h b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-x86/relocator-x86.h new file mode 100644 index 000000000..ed6a1efda --- /dev/null +++ b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-x86/relocator-x86.h @@ -0,0 +1,58 @@ +/** + * Copyright 2017 jmpews + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef platforms_arch_x86_relocator_h +#define platforms_arch_x86_relocator_h + +// platforms +#include "instructions.h" +#include "reader-x86.h" +#include "regs-x86.h" +#include "writer-x86.h" + +// hookzz +#include "writer.h" + +// zzdeps +#include "hookzz.h" +#include "zzdefs.h" +#include "zzdeps/common/debugbreak.h" +#include "zzdeps/zz.h" + +typedef struct _ZzX86Relocator { + zbool try_relocated_again; + zsize try_relocated_length; + zpointer input_start; + zpointer input_cur; + zaddr input_pc; + zuint inpos; + zuint outpos; + ZzInstruction *input_insns; + ZzRelocateInstruction *output_insns; + ZzX86Writer *output; + ZzLiteralInstruction **relocate_literal_insns; + zsize relocate_literal_insns_size; +} ZzX86Relocator; + +void zz_x86_relocator_init(ZzX86Relocator *relocator, zpointer input_code, ZzX86Writer *writer); +void zz_x86_relocator_reset(ZzX86Relocator *self, zpointer input_code, ZzX86Writer *output); + +zsize zz_x86_relocator_read_one(ZzX86Relocator *self, ZzInstruction *instruction); +zbool zz_x86_relocator_write_one(ZzX86Relocator *self); +void zz_x86_relocator_write_all(ZzX86Relocator *self); +void zz_x86_relocator_try_relocate(zpointer address, zuint min_bytes, zuint *max_bytes); + +#endif \ No newline at end of file diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-x86/writer-x86.c b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-x86/writer-x86.c new file mode 100644 index 000000000..eb6afe6c7 --- /dev/null +++ b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-x86/writer-x86.c @@ -0,0 +1,47 @@ +/** + * Copyright 2017 jmpews + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "writer-x86.h" + +ZzX86Writer *zz_x86_writer_new(zpointer data_ptr) { + return NULL; +} + +void zz_x86_writer_init(ZzX86Writer *self, zpointer target_addr) { zz_x86_writer_reset(self, target_addr); } + +void zz_x86_writer_reset(ZzX86Writer *self, zpointer data_ptr) { +} + +zsize zz_x86_writer_near_jump_range_size() { return 0; } + + +void zz_x86_writer_put_bytes(ZzWriter *self, zbyte *data, zsize size) { + +} + +void zz_x86_writer_put_instruction(ZzWriter *self, zuint32 insn) { + +} + + +// ======= relocator ======= + +// ======= user custom ======= + +// ======= default ======= diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-x86/writer-x86.h b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-x86/writer-x86.h new file mode 100644 index 000000000..602921036 --- /dev/null +++ b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/arch-x86/writer-x86.h @@ -0,0 +1,52 @@ +/** + * Copyright 2017 jmpews + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef platforms_arch_x86_writer_h +#define platforms_arch_x86_writer_h + +// platforms +#include "instructions.h" +#include "regs-x86.h" +#include "writer-x86.h" + +// hookzz +#include "writer.h" + +// zzdeps +#include "hookzz.h" +#include "zzdefs.h" +#include "zzdeps/common/debugbreak.h" +#include "zzdeps/zz.h" + +typedef ZzWriter ZzX86Writer; + +ZzX86Writer *zz_x86_writer_new(zpointer data_ptr); + +void zz_x86_writer_reset(ZzX86Writer *self, zpointer data_ptr); + +void zz_x86_writer_init(ZzX86Writer *self, zpointer target_addr); + +zsize zz_x86_writer_near_jump_range_size(); +void zz_x86_writer_put_bytes(ZzWriter *self, zbyte *data, zsize size); +void zz_x86_writer_put_instruction(ZzWriter *self, zuint32 insn); + +// ======= user custom ======= + +// ======= default ======= + +// ======= relocator ======= + +#endif \ No newline at end of file diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/backend-arm/interceptor-arm.c b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/backend-arm/interceptor-arm.c new file mode 100644 index 000000000..c37bb132f --- /dev/null +++ b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/backend-arm/interceptor-arm.c @@ -0,0 +1,563 @@ +/** + * Copyright 2017 jmpews + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "interceptor-arm.h" +#include "zzinfo.h" + +#include + +#define ZZ_THUMB_TINY_REDIRECT_SIZE 4 +#define ZZ_THUMB_FULL_REDIRECT_SIZE 8 +#define ZZ_ARM_TINY_REDIRECT_SIZE 4 +#define ZZ_ARM_FULL_REDIRECT_SIZE 8 + +ZzInterceptorBackend *ZzBuildInteceptorBackend(ZzAllocator *allocator) { + if (!ZzMemoryIsSupportAllocateRXPage()) { + return NULL; + } + ZZSTATUS status; + ZzInterceptorBackend *backend = (ZzInterceptorBackend *)malloc(sizeof(ZzInterceptorBackend)); + memset(backend, 0, sizeof(ZzInterceptorBackend)); + + zz_arm_writer_init(&backend->arm_writer, NULL); + zz_arm_relocator_init(&backend->arm_relocator, NULL, &backend->arm_writer); + zz_thumb_writer_init(&backend->thumb_writer, NULL); + zz_thumb_relocator_init(&backend->thumb_relocator, NULL, &backend->thumb_writer); + + backend->allocator = allocator; + backend->enter_thunk = NULL; + backend->half_thunk = NULL; + backend->leave_thunk = NULL; + + status = ZzThunkerBuildThunk(backend); + + if (status == ZZ_FAILED) { + ZzInfoLog("%s", "ZzThunkerBuildThunk return ZZ_FAILED\n"); + return NULL; + } + + return backend; +} + +ZzCodeSlice *zz_code_patch_thumb_writer(ZzThumbWriter *thumb_writer, ZzAllocator *allocator, zaddr target_addr, + zsize range_size) { + ZzCodeSlice *code_slice = NULL; + if (range_size > 0) { + code_slice = ZzNewNearCodeSlice(allocator, target_addr, range_size, thumb_writer->size); + } else { + code_slice = ZzNewCodeSlice(allocator, thumb_writer->size + 4); + } + if (!code_slice) + return NULL; + + if (!ZzMemoryPatchCode((zaddr)code_slice->data, thumb_writer->base, thumb_writer->size)) { + + free(code_slice); + return NULL; + } + return code_slice; +} + +ZzCodeSlice *zz_code_patch_thumb_relocate_writer(ZzThumbRelocator *thumb_relocator, ZzThumbWriter *thumb_writer, + ZzAllocator *allocator, zaddr target_addr, zsize range_size) { + ZzCodeSlice *code_slice = NULL; + if (range_size > 0) { + code_slice = ZzNewNearCodeSlice(allocator, target_addr, range_size, thumb_writer->size); + } else { + code_slice = ZzNewCodeSlice(allocator, thumb_writer->size + 4); + } + if (!code_slice) + return NULL; + + zz_thumb_relocator_relocate_writer(thumb_relocator, (zaddr)code_slice->data); + + if (!ZzMemoryPatchCode((zaddr)code_slice->data, thumb_writer->base, thumb_writer->size)) { + + free(code_slice); + return NULL; + } + return code_slice; +} + +ZzCodeSlice *zz_code_patch_arm_writer(ZzArmWriter *arm_writer, ZzAllocator *allocator, zaddr target_addr, + zsize range_size) { + ZzCodeSlice *code_slice = NULL; + if (range_size > 0) { + code_slice = ZzNewNearCodeSlice(allocator, target_addr, range_size, arm_writer->size); + } else { + code_slice = ZzNewCodeSlice(allocator, arm_writer->size + 4); + } + if (!code_slice) + return NULL; + + if (!ZzMemoryPatchCode((zaddr)code_slice->data, arm_writer->base, arm_writer->size)) { + free(code_slice); + return NULL; + } + return code_slice; +} + +ZzCodeSlice *zz_code_patch_arm_relocate_writer(ZzArmRelocator *arm_relocator, ZzArmWriter *arm_writer, + ZzAllocator *allocator, zaddr target_addr, zsize range_size) { + ZzCodeSlice *code_slice = NULL; + if (range_size > 0) { + code_slice = ZzNewNearCodeSlice(allocator, target_addr, range_size, arm_writer->size); + } else { + code_slice = ZzNewCodeSlice(allocator, arm_writer->size + 4); + } + if (!code_slice) + return NULL; + + zz_arm_relocator_relocate_writer(arm_relocator, (zaddr)code_slice->data); + + if (!ZzMemoryPatchCode((zaddr)code_slice->data, arm_writer->base, arm_writer->size)) { + free(code_slice); + return NULL; + } + return code_slice; +} + +ZZSTATUS ZzPrepareTrampoline(ZzInterceptorBackend *self, ZzHookFunctionEntry *entry) { + zbool is_thumb = FALSE; + zaddr target_addr = (zaddr)entry->target_ptr; + zuint redirect_limit = 0; + + ZzArmHookFunctionEntryBackend *entry_backend; + entry_backend = (ZzArmHookFunctionEntryBackend *)malloc(sizeof(ZzArmHookFunctionEntryBackend)); + memset(entry_backend, 0, sizeof(ZzArmHookFunctionEntryBackend)); + + entry->backend = (struct _ZzHookFunctionEntryBackend *)entry_backend; + + is_thumb = INSTRUCTION_IS_THUMB((zaddr)entry->target_ptr); + if (is_thumb) + target_addr = (zaddr)entry->target_ptr & ~(zaddr)1; + + if (is_thumb) { + if (entry->try_near_jump) { + entry_backend->redirect_code_size = ZZ_THUMB_TINY_REDIRECT_SIZE; + } else { + zz_thumb_relocator_try_relocate((zpointer)target_addr, ZZ_THUMB_FULL_REDIRECT_SIZE, &redirect_limit); + if (redirect_limit != 0 && redirect_limit > ZZ_THUMB_TINY_REDIRECT_SIZE && + redirect_limit < ZZ_THUMB_FULL_REDIRECT_SIZE) { + entry->try_near_jump = TRUE; + entry_backend->redirect_code_size = ZZ_THUMB_TINY_REDIRECT_SIZE; + } else if (redirect_limit != 0 && redirect_limit < ZZ_THUMB_TINY_REDIRECT_SIZE) { + return ZZ_FAILED; + } else { + entry_backend->redirect_code_size = ZZ_THUMB_FULL_REDIRECT_SIZE; + if (target_addr % 4) { + entry_backend->redirect_code_size += 2; + } + } + } + self->thumb_relocator.try_relocated_length = entry_backend->redirect_code_size; + } else { + if (entry->try_near_jump) { + entry_backend->redirect_code_size = ZZ_ARM_TINY_REDIRECT_SIZE; + } else { + zz_arm_relocator_try_relocate((zpointer)target_addr, ZZ_ARM_FULL_REDIRECT_SIZE, &redirect_limit); + if (redirect_limit != 0 && redirect_limit > ZZ_ARM_TINY_REDIRECT_SIZE && + redirect_limit < ZZ_ARM_FULL_REDIRECT_SIZE) { + entry->try_near_jump = TRUE; + entry_backend->redirect_code_size = ZZ_ARM_TINY_REDIRECT_SIZE; + } else if (redirect_limit != 0 && redirect_limit < ZZ_ARM_TINY_REDIRECT_SIZE) { + return ZZ_FAILED; + } else { + entry_backend->redirect_code_size = ZZ_ARM_FULL_REDIRECT_SIZE; + } + } + self->arm_relocator.try_relocated_length = entry_backend->redirect_code_size; + } + + zz_arm_relocator_init(&self->arm_relocator, (zpointer)target_addr, &self->arm_writer); + zz_thumb_relocator_init(&self->thumb_relocator, (zpointer)target_addr, &self->thumb_writer); + return ZZ_SUCCESS; +} + +ZZSTATUS ZzBuildEnterTransferTrampoline(ZzInterceptorBackend *self, ZzHookFunctionEntry *entry) { + zbyte temp_code_slice_data[256] = {0}; + ZzArmWriter *arm_writer = NULL; + ZzArmWriter *thumb_writer = NULL; + ZzCodeSlice *code_slice = NULL; + ZzArmHookFunctionEntryBackend *entry_backend = (ZzArmHookFunctionEntryBackend *)entry->backend; + ZZSTATUS status = ZZ_SUCCESS; + zbool is_thumb = TRUE; + zaddr target_addr = (zaddr)entry->target_ptr; + + is_thumb = INSTRUCTION_IS_THUMB((zaddr)entry->target_ptr); + if (is_thumb) + target_addr = (zaddr)entry->target_ptr & ~(zaddr)1; + + if (is_thumb) { + thumb_writer = &self->thumb_writer; + zz_thumb_writer_reset(thumb_writer, temp_code_slice_data); + + /* jump to on_enter_trampoline */ + zz_thumb_writer_put_ldr_reg_address(thumb_writer, ZZ_ARM_REG_PC, (zaddr)entry->on_enter_trampoline); + + /* code patch */ + code_slice = zz_code_patch_thumb_writer(thumb_writer, self->allocator, target_addr, + zz_thumb_writer_near_jump_range_size()); + if (code_slice) + entry->on_enter_transfer_trampoline = code_slice->data; + else + return ZZ_FAILED; + } else { + arm_writer = &self->arm_writer; + zz_arm_writer_reset(arm_writer, temp_code_slice_data); + + /* jump to on_enter_trampoline */ + zz_arm_writer_put_ldr_reg_address(arm_writer, ZZ_ARM_REG_PC, (zaddr)entry->on_enter_trampoline); + + /* code patch */ + code_slice = + zz_code_patch_arm_writer(arm_writer, self->allocator, target_addr, zz_arm_writer_near_jump_range_size()); + if (code_slice) + entry->on_enter_transfer_trampoline = code_slice->data; + else + return ZZ_FAILED; + } + + if (ZzIsEnableDebugMode()) { + char buffer[1024] = {}; + sprintf(buffer + strlen(buffer), "%s\n", "ZzBuildEnterTransferTrampoline:"); + sprintf(buffer + strlen(buffer), + "LogInfo: on_enter_transfer_trampoline at %p, length: %ld. and will jump to " + "on_enter_trampoline(%p).\n", + code_slice->data, code_slice->size, entry->on_enter_trampoline); + ZzInfoLog("%s", buffer); + } + + free(code_slice); + return status; +} + +ZZSTATUS ZzBuildEnterTrampoline(ZzInterceptorBackend *self, ZzHookFunctionEntry *entry) { + zbyte temp_code_slice_data[256] = {0}; + ZzArmWriter *arm_writer = NULL; + ZzArmWriter *thumb_writer = NULL; + ZzCodeSlice *code_slice = NULL; + ZzArmHookFunctionEntryBackend *entry_backend = (ZzArmHookFunctionEntryBackend *)entry->backend; + ZZSTATUS status = ZZ_SUCCESS; + zbool is_thumb; + + is_thumb = INSTRUCTION_IS_THUMB((zaddr)entry->target_ptr); + + thumb_writer = &self->thumb_writer; + zz_thumb_writer_reset(thumb_writer, temp_code_slice_data); + + /* prepare 2 stack space: 1. next_hop 2. entry arg */ + zz_thumb_writer_put_sub_reg_imm(thumb_writer, ZZ_ARM_REG_SP, 0xc); + zz_thumb_writer_put_str_reg_reg_offset(thumb_writer, ZZ_ARM_REG_R1, ZZ_ARM_REG_SP, 0x0); // push r7 + zz_thumb_writer_put_ldr_b_reg_address(thumb_writer, ZZ_ARM_REG_R1, (zaddr)entry); + zz_thumb_writer_put_str_reg_reg_offset(thumb_writer, ZZ_ARM_REG_R1, ZZ_ARM_REG_SP, 0x4); + zz_thumb_writer_put_ldr_reg_reg_offset(thumb_writer, ZZ_ARM_REG_R1, ZZ_ARM_REG_SP, 0x0); // pop r7 + zz_thumb_writer_put_add_reg_imm(thumb_writer, ZZ_ARM_REG_SP, 0x4); + + /* jump to enter thunk */ + zz_thumb_writer_put_ldr_reg_address(thumb_writer, ZZ_ARM_REG_PC, (zaddr)self->enter_thunk); + + /* code patch */ + code_slice = zz_code_patch_thumb_writer(thumb_writer, self->allocator, 0, 0); + if (code_slice) + entry->on_enter_trampoline = code_slice->data + 1; + else + return ZZ_FAILED; + + /* debug log */ + if (ZzIsEnableDebugMode()) { + char buffer[1024] = {}; + sprintf(buffer + strlen(buffer), "%s\n", "ZzBuildEnterTrampoline:"); + sprintf(buffer + strlen(buffer), + "LogInfo: on_enter_trampoline at %p, length: %ld. hook-entry: %p. and will jump to " + "enter_thunk(%p)\n", + code_slice->data, code_slice->size, (void *)entry, (void *)self->enter_thunk); + ZzInfoLog("%s", buffer); + } + + if ((is_thumb && entry_backend->redirect_code_size == ZZ_THUMB_TINY_REDIRECT_SIZE) || + (!is_thumb && entry_backend->redirect_code_size == ZZ_ARM_TINY_REDIRECT_SIZE)) { + ZzBuildEnterTransferTrampoline(self, entry); + } + + free(code_slice); + return status; +} + +ZZSTATUS ZzBuildInvokeTrampoline(ZzInterceptorBackend *self, ZzHookFunctionEntry *entry) { + zbyte temp_code_slice_data[256] = {0}; + ZzCodeSlice *code_slice = NULL; + ZzArmHookFunctionEntryBackend *entry_backend = (ZzArmHookFunctionEntryBackend *)entry->backend; + ZZSTATUS status = ZZ_SUCCESS; + zbool is_thumb = TRUE; + zaddr target_addr = (zaddr)entry->target_ptr; + zpointer target_end_addr = 0; + zpointer restore_target_addr; + + is_thumb = INSTRUCTION_IS_THUMB((zaddr)entry->target_ptr); + if (is_thumb) + target_addr = (zaddr)entry->target_ptr & ~(zaddr)1; + + if (is_thumb) { + target_end_addr = (zpointer)((zaddr)entry->target_end_ptr & ~(zaddr)1); + } + + if (is_thumb) { + ZzThumbRelocator *thumb_relocator; + ZzThumbWriter *thumb_writer; + thumb_relocator = &self->thumb_relocator; + thumb_writer = &self->thumb_writer; + + zz_thumb_writer_reset(thumb_writer, temp_code_slice_data); + zz_thumb_relocator_reset(thumb_relocator, (zpointer)target_addr, thumb_writer); + zsize tmp_relocator_insn_size = 0; + entry->target_half_ret_addr = 0; + + if (entry->hook_type == HOOK_FUNCTION_TYPE) { + do { + zz_thumb_relocator_read_one(thumb_relocator, NULL); + tmp_relocator_insn_size = thumb_relocator->input_cur - thumb_relocator->input_start; + } while (tmp_relocator_insn_size < entry_backend->redirect_code_size); + zz_thumb_relocator_write_all(thumb_relocator); + } else if (entry->hook_type == HOOK_ADDRESS_TYPE) { + do { + zz_thumb_relocator_read_one(thumb_relocator, NULL); + zz_thumb_relocator_write_one(thumb_relocator); + tmp_relocator_insn_size = thumb_relocator->input_cur - thumb_relocator->input_start; + if (thumb_relocator->input_cur >= target_end_addr && !entry->target_half_ret_addr) { + /* jump to rest target address */ + zz_thumb_writer_put_ldr_reg_address(thumb_writer, ZZ_ARM_REG_PC, (zaddr)entry->on_half_trampoline); + entry->target_half_ret_addr = (zpointer)(thumb_writer->size + 1); + } + } while (tmp_relocator_insn_size < entry_backend->redirect_code_size || + thumb_relocator->input_cur < target_end_addr); + } + + /* jump to rest target address */ + restore_target_addr = (zpointer)((zaddr)target_addr + tmp_relocator_insn_size); + zz_thumb_writer_put_ldr_reg_address(thumb_writer, ZZ_ARM_REG_PC, (zaddr)(restore_target_addr + 1)); + + /* code patch */ + code_slice = zz_code_patch_thumb_relocate_writer(thumb_relocator, thumb_writer, self->allocator, 0, 0); + if (code_slice) + entry->on_invoke_trampoline = code_slice->data + 1; + else + return ZZ_FAILED; + } else { + ZzArmRelocator *arm_relocator; + ZzArmWriter *arm_writer; + arm_relocator = &self->arm_relocator; + arm_writer = &self->arm_writer; + + zz_arm_writer_reset(arm_writer, temp_code_slice_data); + zz_arm_relocator_reset(arm_relocator, (zpointer)target_addr, arm_writer); + entry->target_half_ret_addr = 0; + zsize tmp_relocator_insn_size = 0; + + if (entry->hook_type == HOOK_FUNCTION_TYPE) { + do { + zz_arm_relocator_read_one(arm_relocator, NULL); + tmp_relocator_insn_size = arm_relocator->input_cur - arm_relocator->input_start; + } while (tmp_relocator_insn_size < entry_backend->redirect_code_size); + zz_arm_relocator_write_all(arm_relocator); + } else if (entry->hook_type == HOOK_ADDRESS_TYPE) { + do { + zz_arm_relocator_read_one(arm_relocator, NULL); + zz_arm_relocator_write_one(arm_relocator); + tmp_relocator_insn_size = arm_relocator->input_cur - arm_relocator->input_start; + if (arm_relocator->input_cur >= target_end_addr && !entry->target_half_ret_addr) { + /* jump to rest target address */ + zz_arm_writer_put_ldr_reg_address(arm_writer, ZZ_ARM_REG_PC, (zaddr)entry->on_half_trampoline); + entry->target_half_ret_addr = (zpointer)arm_writer->size; + } + } while (tmp_relocator_insn_size < entry_backend->redirect_code_size || + arm_relocator->input_cur < target_end_addr); + } + + /* jump to rest target address */ + restore_target_addr = (zpointer)((zaddr)target_addr + tmp_relocator_insn_size); + zz_arm_writer_put_ldr_reg_address(arm_writer, ZZ_ARM_REG_PC, (zaddr)restore_target_addr); + + /* code patch */ + code_slice = zz_code_patch_arm_relocate_writer(arm_relocator, arm_writer, self->allocator, 0, 0); + if (code_slice) + entry->on_invoke_trampoline = code_slice->data; + else + return ZZ_FAILED; + } + + /* update target_half_ret_addr */ + if (entry->hook_type == HOOK_ADDRESS_TYPE) { + entry->target_half_ret_addr += (zaddr)code_slice->data; + } + + /* debug log */ + if (ZzIsEnableDebugMode()) { + char buffer[1024] = {}; + sprintf(buffer + strlen(buffer), "%s\n", "ZzBuildInvokeTrampoline:"); + sprintf(buffer + strlen(buffer), + "LogInfo: on_invoke_trampoline at %p, length: %ld. and will jump to rest code(%p).\n", code_slice->data, + code_slice->size, restore_target_addr); + if (is_thumb) { + sprintf(buffer + strlen(buffer), + "ThumbInstructionFix: origin instruction at %p, end at %p, relocator instruction nums %ld\n", + (&self->thumb_relocator)->input_start, (&self->thumb_relocator)->input_cur, + (&self->thumb_relocator)->inpos); + } else { + sprintf(buffer + strlen(buffer), + "ArmInstructionFix: origin instruction at %p, end at %p, relocator instruction nums %ld\n", + (&self->arm_relocator)->input_start, (&self->arm_relocator)->input_cur, + (&self->arm_relocator)->inpos); + } + + char origin_prologue[256] = {0}; + int t = 0; + zpointer p; + if (is_thumb) { + for (p = (&self->thumb_relocator)->input_start; p < (&self->thumb_relocator)->input_cur; p++, t = t + 5) { + sprintf(origin_prologue + t, "0x%.2x ", *(unsigned char *)p); + } + } else { + for (p = (&self->arm_relocator)->input_start; p < (&self->arm_relocator)->input_cur; p++, t = t + 5) { + sprintf(origin_prologue + t, "0x%.2x ", *(unsigned char *)p); + } + } + sprintf(buffer + strlen(buffer), "origin_prologue: %s\n", origin_prologue); + + ZzInfoLog("%s", buffer); + } + + free(code_slice); + return status; +} + +ZZSTATUS ZzBuildHalfTrampoline(ZzInterceptorBackend *self, ZzHookFunctionEntry *entry) { + zbyte temp_code_slice_data[256] = {0}; + ZzArmWriter *arm_writer = NULL; + ZzArmWriter *thumb_writer = NULL; + ZzCodeSlice *code_slice = NULL; + ZZSTATUS status = ZZ_SUCCESS; + + thumb_writer = &self->thumb_writer; + zz_thumb_writer_reset(thumb_writer, temp_code_slice_data); + + /* prepare 2 stack space: 1. next_hop 2. entry arg */ + zz_thumb_writer_put_sub_reg_imm(thumb_writer, ZZ_ARM_REG_SP, 0xc); + zz_thumb_writer_put_str_reg_reg_offset(thumb_writer, ZZ_ARM_REG_R1, ZZ_ARM_REG_SP, 0x0); // push r7 + zz_thumb_writer_put_ldr_b_reg_address(thumb_writer, ZZ_ARM_REG_R1, (zaddr)entry); + zz_thumb_writer_put_str_reg_reg_offset(thumb_writer, ZZ_ARM_REG_R1, ZZ_ARM_REG_SP, 0x4); + zz_thumb_writer_put_ldr_reg_reg_offset(thumb_writer, ZZ_ARM_REG_R1, ZZ_ARM_REG_SP, 0x0); // pop r7 + zz_thumb_writer_put_add_reg_imm(thumb_writer, ZZ_ARM_REG_SP, 0x4); + + /* jump to half_thunk */ + zz_thumb_writer_put_ldr_reg_address(thumb_writer, ZZ_ARM_REG_PC, (zaddr)self->half_thunk); + + /* code patch */ + code_slice = zz_code_patch_thumb_writer(thumb_writer, self->allocator, 0, 0); + if (code_slice) + entry->on_half_trampoline = code_slice->data + 1; + else + return ZZ_FAILED; + + free(code_slice); + return status; +} + +ZZSTATUS ZzBuildLeaveTrampoline(ZzInterceptorBackend *self, ZzHookFunctionEntry *entry) { + zbyte temp_code_slice_data[256] = {0}; + ZzCodeSlice *code_slice = NULL; + ZZSTATUS status = ZZ_SUCCESS; + zbool is_thumb = TRUE; + ZzArmWriter *thumb_writer; + + thumb_writer = &self->thumb_writer; + zz_thumb_writer_reset(thumb_writer, temp_code_slice_data); + + /* prepare 2 stack space: 1. next_hop 2. entry arg */ + zz_thumb_writer_put_sub_reg_imm(thumb_writer, ZZ_ARM_REG_SP, 0xc); + zz_thumb_writer_put_str_reg_reg_offset(thumb_writer, ZZ_ARM_REG_R1, ZZ_ARM_REG_SP, 0x0); // push r7 + zz_thumb_writer_put_ldr_b_reg_address(thumb_writer, ZZ_ARM_REG_R1, (zaddr)entry); + zz_thumb_writer_put_str_reg_reg_offset(thumb_writer, ZZ_ARM_REG_R1, ZZ_ARM_REG_SP, 0x4); + zz_thumb_writer_put_ldr_reg_reg_offset(thumb_writer, ZZ_ARM_REG_R1, ZZ_ARM_REG_SP, 0x0); // pop r7 + zz_thumb_writer_put_add_reg_imm(thumb_writer, ZZ_ARM_REG_SP, 0x4); + + /* jump to leave_thunk */ + zz_thumb_writer_put_ldr_reg_address(thumb_writer, ZZ_ARM_REG_PC, (zaddr)self->leave_thunk); + + /* code patch */ + code_slice = zz_code_patch_thumb_writer(thumb_writer, self->allocator, 0, 0); + if (code_slice) + entry->on_leave_trampoline = code_slice->data + 1; + else + return ZZ_FAILED; + + /* debug log */ + if (ZzIsEnableDebugMode()) { + char buffer[1024] = {}; + sprintf(buffer + strlen(buffer), "%s\n", "ZzBuildLeaveTrampoline:"); + sprintf(buffer + strlen(buffer), + "LogInfo: on_leave_trampoline at %p, length: %ld. and will jump to leave_thunk(%p).\n", + code_slice->data, code_slice->size, self->leave_thunk); + ZzInfoLog("%s", buffer); + } + + free(code_slice); + return ZZ_DONE; +} + +ZZSTATUS ZzActivateTrampoline(ZzInterceptorBackend *self, ZzHookFunctionEntry *entry) { + zbyte temp_code_slice_data[256] = {0}; + ZzCodeSlice *code_slice = NULL; + ZzArmHookFunctionEntryBackend *entry_backend = (ZzArmHookFunctionEntryBackend *)entry->backend; + ZZSTATUS status = ZZ_SUCCESS; + zbool is_thumb = TRUE; + zaddr target_addr = (zaddr)entry->target_ptr; + + is_thumb = INSTRUCTION_IS_THUMB((zaddr)entry->target_ptr); + if (is_thumb) + target_addr = (zaddr)entry->target_ptr & ~(zaddr)1; + + if (is_thumb) { + ZzThumbWriter *thumb_writer; + thumb_writer = &self->thumb_writer; + zz_thumb_writer_reset(thumb_writer, temp_code_slice_data); + thumb_writer->pc = target_addr + 4; + + if (entry_backend->redirect_code_size == ZZ_THUMB_TINY_REDIRECT_SIZE) { + zz_thumb_writer_put_b_imm32(thumb_writer, + (zaddr)entry->on_enter_transfer_trampoline - (zaddr)thumb_writer->pc); + } else { + zz_thumb_writer_put_ldr_reg_address(thumb_writer, ZZ_ARM_REG_PC, (zaddr)entry->on_enter_trampoline); + } + if (!ZzMemoryPatchCode((zaddr)target_addr, thumb_writer->base, thumb_writer->size)) + return ZZ_FAILED; + } else { + ZzArmWriter *arm_writer; + arm_writer = &self->arm_writer; + zz_arm_writer_reset(arm_writer, temp_code_slice_data); + arm_writer->pc = target_addr + 8; + + if (entry_backend->redirect_code_size == ZZ_ARM_TINY_REDIRECT_SIZE) { + zz_arm_writer_put_b_imm(arm_writer, (zaddr)entry->on_enter_transfer_trampoline - (zaddr)arm_writer->pc); + } else { + zz_arm_writer_put_ldr_reg_address(arm_writer, ZZ_ARM_REG_PC, (zaddr)entry->on_enter_trampoline); + } + if (!ZzMemoryPatchCode((zaddr)target_addr, arm_writer->base, arm_writer->size)) + return ZZ_FAILED; + } + + return ZZ_DONE_HOOK; +} diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/backend-arm/interceptor-arm.h b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/backend-arm/interceptor-arm.h index 663b7fa40..5563dfb8d 100644 --- a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/backend-arm/interceptor-arm.h +++ b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/backend-arm/interceptor-arm.h @@ -55,4 +55,9 @@ typedef struct _ZzArmHookFuntionEntryBackend { zuint redirect_code_size; } ZzArmHookFunctionEntryBackend; +ZzCodeSlice *zz_code_patch_thumb_writer(ZzThumbWriter *thumb_writer, ZzAllocator *allocator, zaddr target_addr, + zsize range_size); +ZzCodeSlice *zz_code_patch_arm_writer(ZzArmWriter *arm_writer, ZzAllocator *allocator, zaddr target_addr, + zsize range_size); + #endif \ No newline at end of file diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/backend-arm/thunker-arm.c b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/backend-arm/thunker-arm.c index 2a0ee694e..51529186d 100644 --- a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/backend-arm/thunker-arm.c +++ b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/backend-arm/thunker-arm.c @@ -89,20 +89,22 @@ void function_context_begin_invocation(ZzHookFunctionEntry *entry, zpointer next zpointer caller_ret_addr) { Xdebug("target %p call begin-invocation", entry->target_ptr); + ZzThreadStack *threadstack = ZzGetCurrentThreadStack(entry->thread_local_key); if (!threadstack) { threadstack = ZzNewThreadStack(entry->thread_local_key); } - ZzCallStack *callstack = ZzNewCallStack(); ZzPushCallStack(threadstack, callstack); + /* call pre_call */ if (entry->pre_call) { PRECALL pre_call; pre_call = entry->pre_call; (*pre_call)(rs, (ThreadStack *)threadstack, (CallStack *)callstack); } + /* set next hop */ if (entry->replace_call) { *(zpointer *)next_hop = entry->replace_call; } else { @@ -118,6 +120,7 @@ void function_context_begin_invocation(ZzHookFunctionEntry *entry, zpointer next void function_context_half_invocation(ZzHookFunctionEntry *entry, zpointer next_hop, RegState *rs, zpointer caller_ret_addr) { Xdebug("target %p call half-invocation", entry->target_ptr); + ZzThreadStack *threadstack = ZzGetCurrentThreadStack(entry->thread_local_key); if (!threadstack) { #if defined(DEBUG_MODE) @@ -126,11 +129,14 @@ void function_context_half_invocation(ZzHookFunctionEntry *entry, zpointer next_ } ZzCallStack *callstack = ZzPopCallStack(threadstack); + /* call half_call */ if (entry->half_call) { HALFCALL half_call; half_call = entry->half_call; (*half_call)(rs, (ThreadStack *)threadstack, (CallStack *)callstack); } + + /* set next hop */ *(zpointer *)next_hop = (zpointer)entry->target_half_ret_addr; ZzFreeCallStack(callstack); @@ -139,6 +145,7 @@ void function_context_half_invocation(ZzHookFunctionEntry *entry, zpointer next_ // just like post_call, wow! void function_context_end_invocation(ZzHookFunctionEntry *entry, zpointer next_hop, RegState *rs) { Xdebug("%p call end-invocation", entry->target_ptr); + ZzThreadStack *threadstack = ZzGetCurrentThreadStack(entry->thread_local_key); if (!threadstack) { #if defined(DEBUG_MODE) @@ -147,21 +154,22 @@ void function_context_end_invocation(ZzHookFunctionEntry *entry, zpointer next_h } ZzCallStack *callstack = ZzPopCallStack(threadstack); + /* call post_call */ if (entry->post_call) { POSTCALL post_call; post_call = entry->post_call; (*post_call)(rs, (ThreadStack *)threadstack, (CallStack *)callstack); } + + /* set next hop */ *(zpointer *)next_hop = callstack->caller_ret_addr; ZzFreeCallStack(callstack); } -// A4.1.10 BX void zz_thumb_thunker_build_enter_thunk(ZzWriter *writer) { /* save general registers and sp */ - zz_thumb_writer_put_bx_reg(writer, ZZ_ARM_REG_PC); zz_arm_writer_put_bytes(writer, THUMB_FUNCTION_ADDRESS((void *)ctx_save), 15 * 4); zz_arm_writer_put_add_reg_reg_imm(writer, ZZ_ARM_REG_R1, ZZ_ARM_REG_PC, 1); @@ -187,7 +195,6 @@ void zz_thumb_thunker_build_enter_thunk(ZzWriter *writer) { /* restore general registers and sp */ zz_thumb_writer_put_add_reg_imm(writer, ZZ_ARM_REG_SP, 0x8); - zz_thumb_writer_put_bx_reg(writer, ZZ_ARM_REG_PC); zz_arm_writer_put_bytes(writer, THUMB_FUNCTION_ADDRESS((void *)ctx_restore), 14 * 4); zz_arm_writer_put_bx_to_thumb(writer); @@ -229,7 +236,6 @@ void zz_thumb_thunker_build_half_thunk(ZzWriter *writer) { /* restore general registers and sp */ zz_thumb_writer_put_add_reg_imm(writer, ZZ_ARM_REG_SP, 0x8); - zz_thumb_writer_put_bx_reg(writer, ZZ_ARM_REG_PC); zz_arm_writer_put_bytes(writer, THUMB_FUNCTION_ADDRESS((void *)ctx_restore), 14 * 4); zz_arm_writer_put_bx_to_thumb(writer); @@ -255,8 +261,11 @@ void zz_thumb_thunker_build_leave_thunk(ZzWriter *writer) { zz_thumb_writer_put_str_reg_reg_offset(writer, ZZ_ARM_REG_R1, ZZ_ARM_REG_SP, 0x4); /* pass enter func args */ + /* entry */ zz_thumb_writer_put_ldr_reg_reg_offset(writer, ZZ_ARM_REG_R0, ZZ_ARM_REG_SP, CTX_SAVE_STACK_OFFSET + 0x8); + /* next hop*/ zz_thumb_writer_put_add_reg_reg_imm(writer, ZZ_ARM_REG_R1, ZZ_ARM_REG_SP, CTX_SAVE_STACK_OFFSET + 0x8 + 0x4); + /* RegState */ zz_thumb_writer_put_add_reg_reg_imm(writer, ZZ_ARM_REG_R2, ZZ_ARM_REG_SP, 0x4); /* call function_context_begin_invocation */ @@ -265,7 +274,6 @@ void zz_thumb_thunker_build_leave_thunk(ZzWriter *writer) { /* restore general registers and sp */ zz_thumb_writer_put_add_reg_imm(writer, ZZ_ARM_REG_SP, 0x8); - zz_thumb_writer_put_bx_reg(writer, ZZ_ARM_REG_PC); zz_arm_writer_put_bytes(writer, THUMB_FUNCTION_ADDRESS((void *)ctx_restore), 14 * 4); zz_arm_writer_put_bx_to_thumb(writer); @@ -287,89 +295,99 @@ ZZSTATUS ZzThunkerBuildThunk(ZzInterceptorBackend *self) { thumb_writer = &self->thumb_writer; zz_thumb_writer_reset(thumb_writer, temp_code_slice_data); - code_slice = NULL; - do { - zz_thumb_thunker_build_enter_thunk(thumb_writer); - if (code_slice) { - if (!ZzMemoryPatchCode((zaddr)code_slice->data, thumb_writer->base, thumb_writer->size)) - return ZZ_FAILED; - break; - } - code_slice = ZzNewCodeSlice(self->allocator, thumb_writer->size + 4); - if (!code_slice) { -#if defined(DEBUG_MODE) - debug_break(); -#endif - return ZZ_FAILED; - } else { - zz_thumb_writer_reset(thumb_writer, temp_code_slice_data); - thumb_writer->pc = code_slice->data + 4; - } - } while (code_slice); + /* buid enter_thunk */ + zz_thumb_thunker_build_enter_thunk(thumb_writer); + + /* code patch */ + code_slice = zz_code_patch_thumb_writer(thumb_writer, self->allocator, 0, 0); + if (code_slice) + self->enter_thunk = code_slice->data + 1; + else + return ZZ_FAILED; + + /* debug log */ if (ZzIsEnableDebugMode()) { - char buffer[1024] = {}; + char buffer[2048] = {}; + char thunk_buffer[2048] = {}; + int t = 0; + zpointer p; sprintf(buffer + strlen(buffer), "%s\n", "ZzThunkerBuildThunk:"); + + for (p = thumb_writer->base; p < thumb_writer->base + thumb_writer->size; p++, t = t + 5) { + sprintf(thunk_buffer + t, "0x%.2x ", *(unsigned char *)p); + } + + ZzInfoLog("%s", thunk_buffer); + // sprintf(buffer + strlen(buffer), "enter_thunk: %s\n", thunk_buffer); + sprintf(buffer + strlen(buffer), "LogInfo: enter_thunk at %p, length: %ld.\n", code_slice->data, code_slice->size); ZzInfoLog("%s", buffer); } - /* set thumb enter_thunk */ - self->enter_thunk = code_slice->data + 1; - zz_thumb_writer_reset(thumb_writer, temp_code_slice_data); - code_slice = NULL; - do { - zz_thumb_thunker_build_leave_thunk(thumb_writer); - if (code_slice) { - if (!ZzMemoryPatchCode((zaddr)code_slice->data, thumb_writer->base, thumb_writer->size)) - return ZZ_FAILED; - break; - } - code_slice = ZzNewCodeSlice(self->allocator, thumb_writer->size + 4); - if (!code_slice) { -#if defined(DEBUG_MODE) - debug_break(); -#endif - return ZZ_FAILED; - } else { - zz_thumb_writer_reset(thumb_writer, temp_code_slice_data); - thumb_writer->pc = code_slice->data + 4; - } - } while (code_slice); + + /* build leave_thunk */ + zz_thumb_thunker_build_leave_thunk(thumb_writer); + + /* code patch */ + code_slice = zz_code_patch_thumb_writer(thumb_writer, self->allocator, 0, 0); + if (code_slice) + self->leave_thunk = code_slice->data + 1; + else + return ZZ_FAILED; + + /* debug log */ if (ZzIsEnableDebugMode()) { - char buffer[1024] = {}; + char buffer[2048] = {}; + char thunk_buffer[2048] = {}; + int t = 0; + zpointer p; sprintf(buffer + strlen(buffer), "%s\n", "ZzThunkerBuildThunk:"); + + for (p = thumb_writer->base; p < thumb_writer->base + thumb_writer->size; p++, t = t + 5) { + sprintf(thunk_buffer + t, "0x%.2x ", *(unsigned char *)p); + } + + ZzInfoLog("%s", thunk_buffer); + // sprintf(buffer + strlen(buffer), "enter_thunk: %s\n", thunk_buffer); + sprintf(buffer + strlen(buffer), "LogInfo: leave_thunk at %p, length: %ld.\n", code_slice->data, code_slice->size); ZzInfoLog("%s", buffer); } - /* set thumb leave_thunk */ - self->leave_thunk = code_slice->data + 1; - zz_thumb_writer_reset(thumb_writer, temp_code_slice_data); - code_slice = NULL; - do { - zz_thumb_thunker_build_half_thunk(thumb_writer); - if (code_slice) { - if (!ZzMemoryPatchCode((zaddr)code_slice->data, thumb_writer->base, thumb_writer->size)) - return ZZ_FAILED; - break; - } - code_slice = ZzNewCodeSlice(self->allocator, thumb_writer->size + 4); - if (!code_slice) { -#if defined(DEBUG_MODE) - debug_break(); -#endif - return ZZ_FAILED; - } else { - zz_thumb_writer_reset(thumb_writer, temp_code_slice_data); - thumb_writer->pc = code_slice->data + 4; + + /* build half_thunk */ + zz_thumb_thunker_build_half_thunk(thumb_writer); + + /* code patch */ + code_slice = zz_code_patch_thumb_writer(thumb_writer, self->allocator, 0, 0); + if (code_slice) + self->half_thunk = code_slice->data + 1; + else + return ZZ_FAILED; + + /* debug log */ + if (ZzIsEnableDebugMode()) { + char buffer[2048] = {}; + char thunk_buffer[2048] = {}; + int t = 0; + zpointer p; + sprintf(buffer + strlen(buffer), "%s\n", "ZzThunkerBuildThunk:"); + + for (p = thumb_writer->base; p < thumb_writer->base + thumb_writer->size; p++, t = t + 5) { + sprintf(thunk_buffer + t, "0x%.2x ", *(unsigned char *)p); } - } while (code_slice); - /* set thumb half_thunk */ - self->half_thunk = code_slice->data + 1; + ZzInfoLog("%s", thunk_buffer); + // sprintf(buffer + strlen(buffer), "half_thunk: %s\n", thunk_buffer); + + sprintf(buffer + strlen(buffer), "LogInfo: half_thunk at %p, length: %ld.\n", code_slice->data, + code_slice->size); + ZzInfoLog("%s", buffer); + } + return status; } diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/backend-arm/trampoline-arm.c b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/backend-arm/trampoline-arm.c deleted file mode 100644 index 33423c526..000000000 --- a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/backend-arm/trampoline-arm.c +++ /dev/null @@ -1,561 +0,0 @@ -/** - * Copyright 2017 jmpews - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "interceptor-arm.h" -#include "zzinfo.h" - -#include - -#define INSTRUCTION_IS_THUMB(insn_addr) ((insn_addr & 0x1) == 0x1) - -#define ZZ_THUMB_TINY_REDIRECT_SIZE 4 -#define ZZ_THUMB_FULL_REDIRECT_SIZE 8 -#define ZZ_ARM_TINY_REDIRECT_SIZE 4 -#define ZZ_ARM_FULL_REDIRECT_SIZE 8 - -ZzInterceptorBackend *ZzBuildInteceptorBackend(ZzAllocator *allocator) { - ZzInterceptorBackend *backend = (ZzInterceptorBackend *)malloc(sizeof(ZzInterceptorBackend)); - backend->allocator = allocator; - - zz_arm_writer_init(&backend->arm_writer, NULL); - zz_arm_relocator_init(&backend->arm_relocator, NULL, &backend->arm_writer); - zz_thumb_writer_init(&backend->thumb_writer, NULL); - zz_thumb_relocator_init(&backend->thumb_relocator, NULL, &backend->thumb_writer); - - backend->enter_thunk = NULL; - backend->half_thunk = NULL; - backend->leave_thunk = NULL; - - ZzThunkerBuildThunk(backend); - return backend; -} - -ZZSTATUS ZzPrepareTrampoline(ZzInterceptorBackend *self, ZzHookFunctionEntry *entry) { - zbool is_thumb = FALSE; - zpointer target_addr = entry->target_ptr; - zuint redirect_limit; - - ZzArmHookFunctionEntryBackend *entry_backend; - entry_backend = (ZzArmHookFunctionEntryBackend *)malloc(sizeof(ZzArmHookFunctionEntryBackend)); - entry->backend = (struct _ZzHookFunctionEntryBackend *)entry_backend; - - is_thumb = INSTRUCTION_IS_THUMB((zaddr)target_addr); - - if (is_thumb) { - if (entry->try_near_jump) { - entry_backend->redirect_code_size = ZZ_THUMB_TINY_REDIRECT_SIZE; - } else { - zz_thumb_relocator_try_relocate(target_addr, ZZ_THUMB_FULL_REDIRECT_SIZE, &redirect_limit); - entry_backend->redirect_code_size = ZZ_THUMB_FULL_REDIRECT_SIZE; - } - } else { - if (entry->try_near_jump) { - entry_backend->redirect_code_size = ZZ_ARM_TINY_REDIRECT_SIZE; - } else { - zz_arm_relocator_try_relocate(target_addr, ZZ_ARM_FULL_REDIRECT_SIZE, &redirect_limit); - entry_backend->redirect_code_size = ZZ_ARM_FULL_REDIRECT_SIZE; - } - } - - zz_arm_relocator_init(&self->arm_relocator, target_addr, &self->arm_writer); - zz_thumb_relocator_init(&self->thumb_relocator, target_addr, &self->thumb_writer); - return ZZ_SUCCESS; -} - -ZZSTATUS ZzBuildEnterTransferTrampoline(ZzInterceptorBackend *self, ZzHookFunctionEntry *entry) { - zbyte temp_code_slice_data[256] = {0}; - ZzArmWriter *arm_writer = NULL; - ZzArmWriter *thumb_writer = NULL; - ZzCodeSlice *code_slice = NULL; - ZzArmHookFunctionEntryBackend *entry_backend = (ZzArmHookFunctionEntryBackend *)entry->backend; - ZZSTATUS status = ZZ_SUCCESS; - zbool is_thumb = TRUE; - zpointer target_addr = entry->target_ptr; - - is_thumb = INSTRUCTION_IS_THUMB((zaddr)target_addr); - if (is_thumb) { - thumb_writer = &self->thumb_writer; - zz_thumb_writer_reset(thumb_writer, temp_code_slice_data); - - code_slice = NULL; - do { - zz_thumb_writer_put_ldr_reg_address(thumb_writer, ZZ_ARM_REG_PC, (zaddr)entry->on_enter_trampoline); - if (code_slice) { - if (!ZzMemoryPatchCode((zaddr)code_slice->data, thumb_writer->base, thumb_writer->size)) - return ZZ_FAILED; - break; - } - code_slice = ZzNewNearCodeSlice(self->allocator, (zaddr)entry->target_ptr, - zz_thumb_writer_near_jump_range_size(), thumb_writer->size); - if (!code_slice) { - return ZZ_FAILED; - } else { - zz_thumb_writer_reset(thumb_writer, temp_code_slice_data); - thumb_writer->pc = code_slice->data + 4; - } - } while (code_slice); - entry->on_enter_transfer_trampoline = code_slice->data; - } else { - arm_writer = &self->arm_writer; - zz_arm_writer_reset(arm_writer, temp_code_slice_data); - - code_slice = NULL; - do { - zz_arm_writer_put_ldr_reg_address(arm_writer, ZZ_ARM_REG_PC, (zaddr)entry->on_enter_trampoline); - - if (code_slice) { - if (!ZzMemoryPatchCode((zaddr)code_slice->data, arm_writer->base, arm_writer->size)) - return ZZ_FAILED; - break; - } - code_slice = ZzNewNearCodeSlice(self->allocator, (zaddr)entry->target_ptr, - zz_arm_writer_near_jump_range_size(), arm_writer->size); - if (!code_slice) { - return ZZ_FAILED; - } else { - zz_arm_writer_reset(arm_writer, temp_code_slice_data); - arm_writer->pc = code_slice->data + 8; - } - - } while (code_slice); - entry->on_enter_transfer_trampoline = code_slice->data; - } - - if (ZzIsEnableDebugMode()) { - char buffer[1024] = {}; - sprintf(buffer + strlen(buffer), "%s\n", "ZzBuildEnterTransferTrampoline:"); - sprintf(buffer + strlen(buffer), - "LogInfo: on_enter_transfer_trampoline at %p, length: %ld. and will jump to on_enter_trampoline(%p).\n", - code_slice->data, code_slice->size, entry->on_enter_trampoline); - ZzInfoLog("%s", buffer); - } - return status; -} - -ZZSTATUS ZzBuildEnterTrampoline(ZzInterceptorBackend *self, ZzHookFunctionEntry *entry) { - zbyte temp_code_slice_data[256] = {0}; - ZzArmWriter *arm_writer = NULL; - ZzArmWriter *thumb_writer = NULL; - ZzCodeSlice *code_slice = NULL; - ZzArmHookFunctionEntryBackend *entry_backend = (ZzArmHookFunctionEntryBackend *)entry->backend; - ZZSTATUS status = ZZ_SUCCESS; - zbool is_thumb = TRUE; - zpointer target_addr = entry->target_ptr; - - thumb_writer = &self->thumb_writer; - zz_thumb_writer_reset(thumb_writer, temp_code_slice_data); - - is_thumb = INSTRUCTION_IS_THUMB((zaddr)target_addr); - - code_slice = NULL; - do { - /* 2 stack space: 1. next_hop 2. entry arg */ - zz_thumb_writer_put_sub_reg_imm(thumb_writer, ZZ_ARM_REG_SP, 0xc); - /* push r7 */ - zz_thumb_writer_put_str_reg_reg_offset(thumb_writer, ZZ_ARM_REG_R1, ZZ_ARM_REG_SP, 0x0); - - zz_thumb_writer_put_ldr_b_reg_address(thumb_writer, ZZ_ARM_REG_R1, (zaddr)entry); - zz_thumb_writer_put_str_reg_reg_offset(thumb_writer, ZZ_ARM_REG_R1, ZZ_ARM_REG_SP, 0x4); - - /* pop r7 */ - zz_thumb_writer_put_ldr_reg_reg_offset(thumb_writer, ZZ_ARM_REG_R1, ZZ_ARM_REG_SP, 0x0); - zz_thumb_writer_put_add_reg_imm(thumb_writer, ZZ_ARM_REG_SP, 0x4); - - /* jump to enter thunk */ - zz_thumb_writer_put_ldr_reg_address(thumb_writer, ZZ_ARM_REG_PC, (zaddr)self->enter_thunk); - - if (code_slice) { - if (!ZzMemoryPatchCode((zaddr)code_slice->data, thumb_writer->base, thumb_writer->size)) - return ZZ_FAILED; - break; - } - - code_slice = ZzNewCodeSlice(self->allocator, thumb_writer->size + 4); - - if (!code_slice) { -#if defined(DEBUG_MODE) - debug_break(); -#endif - return ZZ_FAILED; - } else { - zz_thumb_writer_reset(thumb_writer, temp_code_slice_data); - thumb_writer->pc = code_slice->data + 4; - } - } while (code_slice); - - if (ZzIsEnableDebugMode()) { - char buffer[1024] = {}; - sprintf(buffer + strlen(buffer), "%s\n", "ZzBuildEnterTrampoline:"); - sprintf(buffer + strlen(buffer), - "LogInfo: on_enter_trampoline at %p, length: %ld. hook-entry: %p. and will jump to enter_thunk(%p)\n", - code_slice->data, code_slice->size, (void *)entry, (void *)self->enter_thunk); - ZzInfoLog("%s", buffer); - } - - entry->on_enter_trampoline = code_slice->data + 1; - if ((is_thumb && entry_backend->redirect_code_size == ZZ_THUMB_TINY_REDIRECT_SIZE) || - (!is_thumb && entry_backend->redirect_code_size == ZZ_ARM_TINY_REDIRECT_SIZE)) { - ZzBuildEnterTransferTrampoline(self, entry); - } - - return status; -} - -ZZSTATUS ZzBuildInvokeTrampoline(ZzInterceptorBackend *self, ZzHookFunctionEntry *entry) { - zbyte temp_code_slice_data[256] = {0}; - ZzCodeSlice *code_slice = NULL; - ZzArmHookFunctionEntryBackend *entry_backend = (ZzArmHookFunctionEntryBackend *)entry->backend; - ZZSTATUS status = ZZ_SUCCESS; - zbool is_thumb = TRUE; - zpointer target_addr = entry->target_ptr; - zpointer target_end_addr = 0; - zpointer restore_target_addr; - - is_thumb = INSTRUCTION_IS_THUMB((zaddr)target_addr); - - if (is_thumb) { - target_addr = (zpointer)((zaddr)target_addr & ~(zaddr)1); - target_end_addr = (zpointer)((zaddr)entry->target_end_ptr & ~(zaddr)1); - } - - if (is_thumb) { - ZzThumbRelocator *thumb_relocator; - ZzThumbWriter *thumb_writer; - thumb_relocator = &self->thumb_relocator; - thumb_writer = &self->thumb_writer; - - zz_thumb_writer_reset(thumb_writer, temp_code_slice_data); - - code_slice = NULL; - do { - zz_thumb_relocator_reset(thumb_relocator, target_addr, thumb_writer); - zsize tmp_relocator_insn_size = 0; - entry->target_half_ret_addr = 0; - - if (entry->hook_type == HOOK_FUNCTION_TYPE) { - do { - zz_thumb_relocator_read_one(thumb_relocator, NULL); - tmp_relocator_insn_size = thumb_relocator->input_cur - thumb_relocator->input_start; - } while (tmp_relocator_insn_size < entry_backend->redirect_code_size); - zz_thumb_relocator_write_all(thumb_relocator); - } else if (entry->hook_type == HOOK_ADDRESS_TYPE) { - do { - zz_thumb_relocator_read_one(thumb_relocator, NULL); - zz_thumb_relocator_write_one(thumb_relocator); - tmp_relocator_insn_size = thumb_relocator->input_cur - thumb_relocator->input_start; - if (thumb_relocator->input_cur >= target_end_addr && !entry->target_half_ret_addr) { - /* jump to rest target address */ - zz_thumb_writer_put_ldr_reg_address(thumb_writer, ZZ_ARM_REG_PC, - (zaddr)entry->on_half_trampoline); - - entry->target_half_ret_addr = (zpointer)(thumb_writer->size + 1); - } - } while (tmp_relocator_insn_size < entry_backend->redirect_code_size || - thumb_relocator->input_cur < target_end_addr); - } - - restore_target_addr = (zpointer)((zaddr)target_addr + tmp_relocator_insn_size); - - /* jump to rest target address */ - zz_thumb_writer_put_ldr_reg_address(thumb_writer, ZZ_ARM_REG_PC, (zaddr)(restore_target_addr + 1)); - - if (code_slice) { - if (!ZzMemoryPatchCode((zaddr)code_slice->data, thumb_writer->base, thumb_writer->size)) - return ZZ_FAILED; - break; - } - code_slice = ZzNewCodeSlice(self->allocator, thumb_writer->size + 4); - if (!code_slice) { -#if defined(DEBUG_MODE) - debug_break(); -#endif - return ZZ_FAILED; - } else { - zz_thumb_writer_reset(thumb_writer, temp_code_slice_data); - thumb_writer->pc = code_slice->data + 4; - } - } while (code_slice); - - /* set thumb on_invoke_trampoline */ - entry->on_invoke_trampoline = code_slice->data + 1; - } else { - ZzArmRelocator *arm_relocator; - ZzArmWriter *arm_writer; - arm_relocator = &self->arm_relocator; - arm_writer = &self->arm_writer; - - zz_arm_writer_reset(arm_writer, temp_code_slice_data); - code_slice = NULL; - - do { - zz_arm_relocator_reset(arm_relocator, target_addr, arm_writer); - entry->target_half_ret_addr = 0; - zsize tmp_relocator_insn_size = 0; - - if (entry->hook_type == HOOK_FUNCTION_TYPE) { - do { - zz_arm_relocator_read_one(arm_relocator, NULL); - tmp_relocator_insn_size = arm_relocator->input_cur - arm_relocator->input_start; - } while (tmp_relocator_insn_size < entry_backend->redirect_code_size); - zz_arm_relocator_write_all(arm_relocator); - } else if (entry->hook_type == HOOK_ADDRESS_TYPE) { - do { - zz_arm_relocator_read_one(arm_relocator, NULL); - zz_arm_relocator_write_one(arm_relocator); - tmp_relocator_insn_size = arm_relocator->input_cur - arm_relocator->input_start; - if (arm_relocator->input_cur >= target_end_addr && !entry->target_half_ret_addr) { - /* jump to rest target address */ - zz_arm_writer_put_ldr_reg_address(arm_writer, ZZ_ARM_REG_PC, (zaddr)entry->on_half_trampoline); - - entry->target_half_ret_addr = (zpointer)arm_writer->size; - } - } while (tmp_relocator_insn_size < entry_backend->redirect_code_size || - arm_relocator->input_cur < target_end_addr); - } - - restore_target_addr = (zpointer)((zaddr)target_addr + tmp_relocator_insn_size); - - /* jump to rest target address */ - zz_arm_writer_put_ldr_reg_address(arm_writer, ZZ_ARM_REG_PC, (zaddr)restore_target_addr); - - if (code_slice) { - if (!ZzMemoryPatchCode((zaddr)code_slice->data, arm_writer->base, arm_writer->size)) - return ZZ_FAILED; - break; - } - code_slice = ZzNewCodeSlice(self->allocator, arm_writer->size + 4); - if (!code_slice) { -#if defined(DEBUG_MODE) - debug_break(); -#endif - return ZZ_FAILED; - } else { - zz_arm_writer_reset(arm_writer, temp_code_slice_data); - arm_writer->pc = code_slice->data + 8; - } - - } while (code_slice); - - /* set arm on_invoke_trampoline */ - entry->on_invoke_trampoline = code_slice->data; - } - - if (entry->hook_type == HOOK_ADDRESS_TYPE) { - // update target_half_ret_addr - entry->target_half_ret_addr += (zaddr)code_slice->data; - } - - if (ZzIsEnableDebugMode()) { - char buffer[1024] = {}; - sprintf(buffer + strlen(buffer), "%s\n", "ZzBuildInvokeTrampoline:"); - sprintf(buffer + strlen(buffer), - "LogInfo: on_invoke_trampoline at %p, length: %ld. and will jump to rest code(%p).\n", code_slice->data, - code_slice->size, restore_target_addr); - if (is_thumb) { - sprintf(buffer + strlen(buffer), - "ThumbInstructionFix: origin instruction at %p, end at %p, relocator instruction nums %ld\n", - (&self->thumb_relocator)->input_start, (&self->thumb_relocator)->input_cur, - (&self->thumb_relocator)->inpos); - } else { - sprintf(buffer + strlen(buffer), - "ArmInstructionFix: origin instruction at %p, end at %p, relocator instruction nums %ld\n", - (&self->arm_relocator)->input_start, (&self->arm_relocator)->input_cur, - (&self->arm_relocator)->inpos); - } - - char origin_prologue[256] = {0}; - int t = 0; - if (is_thumb) { - for (zpointer p = (&self->thumb_relocator)->input_start; p < (&self->thumb_relocator)->input_cur; - p++, t = t + 5) { - sprintf(origin_prologue + t, "0x%.2x ", *(unsigned char *)p); - } - } else { - for (zpointer p = (&self->arm_relocator)->input_start; p < (&self->arm_relocator)->input_cur; - p++, t = t + 5) { - sprintf(origin_prologue + t, "0x%.2x ", *(unsigned char *)p); - } - } - sprintf(buffer + strlen(buffer), "origin_prologue: %s\n", origin_prologue); - - ZzInfoLog("%s", buffer); - } - - return status; -} - -ZZSTATUS ZzBuildHalfTrampoline(ZzInterceptorBackend *self, ZzHookFunctionEntry *entry) { - zbyte temp_code_slice_data[256] = {0}; - ZzArmWriter *arm_writer = NULL; - ZzArmWriter *thumb_writer = NULL; - ZzCodeSlice *code_slice = NULL; - ZzArmHookFunctionEntryBackend *entry_backend = (ZzArmHookFunctionEntryBackend *)entry->backend; - ZZSTATUS status = ZZ_SUCCESS; - zbool is_thumb = TRUE; - zpointer target_addr = entry->target_ptr; - - thumb_writer = &self->thumb_writer; - zz_thumb_writer_reset(thumb_writer, temp_code_slice_data); - - is_thumb = INSTRUCTION_IS_THUMB((zaddr)target_addr); - - code_slice = NULL; - do { - /* 2 stack space: 1. next_hop 2. entry arg */ - zz_thumb_writer_put_sub_reg_imm(thumb_writer, ZZ_ARM_REG_SP, 0xc); - /* push r7 */ - zz_thumb_writer_put_str_reg_reg_offset(thumb_writer, ZZ_ARM_REG_R1, ZZ_ARM_REG_SP, 0x0); - - zz_thumb_writer_put_ldr_b_reg_address(thumb_writer, ZZ_ARM_REG_R1, (zaddr)entry); - zz_thumb_writer_put_str_reg_reg_offset(thumb_writer, ZZ_ARM_REG_R1, ZZ_ARM_REG_SP, 0x4); - - /* pop r7 */ - zz_thumb_writer_put_ldr_reg_reg_offset(thumb_writer, ZZ_ARM_REG_R1, ZZ_ARM_REG_SP, 0x0); - zz_thumb_writer_put_add_reg_imm(thumb_writer, ZZ_ARM_REG_SP, 0x4); - - zz_thumb_writer_put_ldr_reg_address(thumb_writer, ZZ_ARM_REG_PC, (zaddr)self->half_thunk); - - if (code_slice) { - if (!ZzMemoryPatchCode((zaddr)code_slice->data, thumb_writer->base, thumb_writer->size)) - return ZZ_FAILED; - break; - } - code_slice = ZzNewCodeSlice(self->allocator, thumb_writer->size + 4); - - if (!code_slice) { -#if defined(DEBUG_MODE) - debug_break(); -#endif - return ZZ_FAILED; - } else { - zz_thumb_writer_reset(thumb_writer, temp_code_slice_data); - thumb_writer->pc = code_slice->data + 4; - } - } while (code_slice); - - /* set thumb on_half_trampoline */ - entry->on_half_trampoline = code_slice->data + 1; - - return status; -} - -ZZSTATUS ZzBuildLeaveTrampoline(ZzInterceptorBackend *self, ZzHookFunctionEntry *entry) { - zbyte temp_code_slice_data[256] = {0}; - ZzCodeSlice *code_slice = NULL; - ZZSTATUS status = ZZ_SUCCESS; - zbool is_thumb = TRUE; - ZzArmWriter *thumb_writer; - - ZzArmHookFunctionEntryBackend *entry_backend = (ZzArmHookFunctionEntryBackend *)entry->backend; - - zpointer target_addr = entry->target_ptr; - thumb_writer = &self->thumb_writer; - zz_thumb_writer_reset(thumb_writer, temp_code_slice_data); - - is_thumb = INSTRUCTION_IS_THUMB((zaddr)target_addr); - - code_slice = NULL; - do { - /* 2 stack space: 1. next_hop 2. entry arg */ - zz_thumb_writer_put_sub_reg_imm(thumb_writer, ZZ_ARM_REG_SP, 0xc); - /* push r7 */ - zz_thumb_writer_put_str_reg_reg_offset(thumb_writer, ZZ_ARM_REG_R1, ZZ_ARM_REG_SP, 0x0); - - zz_thumb_writer_put_ldr_b_reg_address(thumb_writer, ZZ_ARM_REG_R1, (zaddr)entry); - zz_thumb_writer_put_str_reg_reg_offset(thumb_writer, ZZ_ARM_REG_R1, ZZ_ARM_REG_SP, 0x4); - - /* pop r7 */ - zz_thumb_writer_put_ldr_reg_reg_offset(thumb_writer, ZZ_ARM_REG_R1, ZZ_ARM_REG_SP, 0x0); - zz_thumb_writer_put_add_reg_imm(thumb_writer, ZZ_ARM_REG_SP, 0x4); - - zz_thumb_writer_put_ldr_reg_address(thumb_writer, ZZ_ARM_REG_PC, (zaddr)self->leave_thunk); - - if (code_slice) { - - if (!ZzMemoryPatchCode((zaddr)code_slice->data, thumb_writer->base, thumb_writer->size)) - return ZZ_FAILED; - break; - } - code_slice = ZzNewCodeSlice(self->allocator, thumb_writer->size + 4); - if (!code_slice) { -#if defined(DEBUG_MODE) - debug_break(); -#endif - return ZZ_FAILED; - } else { - zz_thumb_writer_reset(thumb_writer, temp_code_slice_data); - thumb_writer->pc = code_slice->data + 4; - } - } while (code_slice); - - if (ZzIsEnableDebugMode()) { - char buffer[1024] = {}; - sprintf(buffer + strlen(buffer), "%s\n", "ZzBuildLeaveTrampoline:"); - sprintf(buffer + strlen(buffer), - "LogInfo: on_leave_trampoline at %p, length: %ld. and will jump to leave_thunk(%p).\n", - code_slice->data, code_slice->size, self->leave_thunk); - ZzInfoLog("%s", buffer); - } - - /* set thumb on_leave_trampoline */ - entry->on_leave_trampoline = code_slice->data + 1; - - return ZZ_DONE; -} - -ZZSTATUS ZzActivateTrampoline(ZzInterceptorBackend *self, ZzHookFunctionEntry *entry) { - zbyte temp_code_slice_data[256] = {0}; - ZzCodeSlice *code_slice = NULL; - ZzArmHookFunctionEntryBackend *entry_backend = (ZzArmHookFunctionEntryBackend *)entry->backend; - ZZSTATUS status = ZZ_SUCCESS; - zbool is_thumb = TRUE; - zpointer target_addr = entry->target_ptr; - - is_thumb = INSTRUCTION_IS_THUMB((zaddr)target_addr); - - if (is_thumb) { - target_addr = (zpointer)((zaddr)target_addr & ~(zaddr)1); - - ZzThumbWriter *thumb_writer; - thumb_writer = &self->thumb_writer; - zz_thumb_writer_reset(thumb_writer, temp_code_slice_data); - thumb_writer->pc = target_addr + 4; - - if (entry_backend->redirect_code_size == ZZ_THUMB_TINY_REDIRECT_SIZE) { - zz_thumb_writer_put_b_imm32(thumb_writer, - (zaddr)entry->on_enter_transfer_trampoline - (zaddr)thumb_writer->pc); - } else { - zz_thumb_writer_put_ldr_reg_address(thumb_writer, ZZ_ARM_REG_PC, (zaddr)entry->on_enter_trampoline); - } - if (!ZzMemoryPatchCode((zaddr)target_addr, thumb_writer->base, thumb_writer->size)) - return ZZ_FAILED; - } else { - ZzArmWriter *arm_writer; - arm_writer = &self->arm_writer; - zz_arm_writer_reset(arm_writer, temp_code_slice_data); - arm_writer->pc = target_addr + 8; - - if (entry_backend->redirect_code_size == ZZ_ARM_TINY_REDIRECT_SIZE) { - zz_arm_writer_put_b_imm(arm_writer, (zaddr)entry->on_enter_transfer_trampoline - (zaddr)arm_writer->pc); - } else { - zz_arm_writer_put_ldr_reg_address(arm_writer, ZZ_ARM_REG_PC, (zaddr)entry->on_enter_trampoline); - } - if (!ZzMemoryPatchCode((zaddr)target_addr, arm_writer->base, arm_writer->size)) - return ZZ_FAILED; - } - - return ZZ_DONE_HOOK; -} diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/backend-arm64/trampoline-arm64.c b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/backend-arm64/interceptor-arm64.c similarity index 51% rename from VirtualApp/lib/src/main/jni/HookZz/src/platforms/backend-arm64/trampoline-arm64.c rename to VirtualApp/lib/src/main/jni/HookZz/src/platforms/backend-arm64/interceptor-arm64.c index f69b277b5..3df307a8d 100644 --- a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/backend-arm64/trampoline-arm64.c +++ b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/backend-arm64/interceptor-arm64.c @@ -25,121 +25,112 @@ ZzInterceptorBackend *ZzBuildInteceptorBackend(ZzAllocator *allocator) { if (!ZzMemoryIsSupportAllocateRXPage()) { return NULL; - // return backend; } + ZZSTATUS status; + ZzInterceptorBackend *backend = (ZzInterceptorBackend *)malloc(sizeof(ZzInterceptorBackend)); - backend->allocator = allocator; + memset(backend, 0, sizeof(ZzInterceptorBackend)); zz_arm64_writer_init(&backend->arm64_writer, NULL); zz_arm64_relocator_init(&backend->arm64_relocator, NULL, &backend->arm64_writer); + backend->allocator = allocator; backend->enter_thunk = NULL; backend->half_thunk = NULL; backend->leave_thunk = NULL; - ZzThunkerBuildThunk(backend); + status = ZzThunkerBuildThunk(backend); + if (status == ZZ_FAILED) { + ZzInfoLog("%s", "ZzThunkerBuildThunk return ZZ_FAILED\n"); + return NULL; + } + return backend; } +ZzCodeSlice *zz_code_patch_arm64_writer(ZzArm64Writer *arm64_writer, ZzAllocator *allocator, zaddr target_addr, + zsize range_size) { + ZzCodeSlice *code_slice = NULL; + if (range_size > 0) { + code_slice = ZzNewNearCodeSlice(allocator, target_addr, range_size, arm64_writer->size); + } else { + code_slice = ZzNewCodeSlice(allocator, arm64_writer->size + 4); + } + if (!code_slice) + return NULL; + + if (!ZzMemoryPatchCode((zaddr)code_slice->data, arm64_writer->base, arm64_writer->size)) { + free(code_slice); + return NULL; + } + return code_slice; +} + +ZzCodeSlice *zz_code_patch_arm64_relocate_writer(ZzArm64Relocator *relocator, ZzArm64Writer *arm64_writer, + ZzAllocator *allocator, zaddr target_addr, zsize range_size) { + ZzCodeSlice *code_slice = NULL; + if (range_size > 0) { + code_slice = ZzNewNearCodeSlice(allocator, target_addr, range_size, arm64_writer->size); + } else { + code_slice = ZzNewCodeSlice(allocator, arm64_writer->size + 4); + } + if (!code_slice) + return NULL; + + if (!ZzMemoryPatchCode((zaddr)code_slice->data, arm64_writer->base, arm64_writer->size)) { + free(code_slice); + return NULL; + } + return code_slice; +} + ZZSTATUS ZzPrepareTrampoline(ZzInterceptorBackend *self, ZzHookFunctionEntry *entry) { - zpointer target_addr = entry->target_ptr; - zuint redirect_limit; + zaddr target_addr = (zaddr)entry->target_ptr; + zuint redirect_limit = 0; ZzArm64HookFunctionEntryBackend *entry_backend; entry_backend = (ZzArm64HookFunctionEntryBackend *)malloc(sizeof(ZzArm64HookFunctionEntryBackend)); + memset(entry_backend, 0, sizeof(ZzArm64HookFunctionEntryBackend)); + entry->backend = (struct _ZzHookFunctionEntryBackend *)entry_backend; if (entry->try_near_jump) { entry_backend->redirect_code_size = ZZ_ARM64_TINY_REDIRECT_SIZE; } else { - zz_arm64_relocator_try_relocate(target_addr, ZZ_ARM64_FULL_REDIRECT_SIZE, &redirect_limit); - entry_backend->redirect_code_size = ZZ_ARM64_FULL_REDIRECT_SIZE; + zz_arm64_relocator_try_relocate((zpointer)target_addr, ZZ_ARM64_FULL_REDIRECT_SIZE, &redirect_limit); + if (redirect_limit != 0 && redirect_limit > ZZ_ARM64_TINY_REDIRECT_SIZE && + redirect_limit < ZZ_ARM64_FULL_REDIRECT_SIZE) { + entry->try_near_jump = TRUE; + entry_backend->redirect_code_size = ZZ_ARM64_TINY_REDIRECT_SIZE; + } else if (redirect_limit != 0 && redirect_limit < ZZ_ARM64_TINY_REDIRECT_SIZE) { + return ZZ_FAILED; + } else { + entry_backend->redirect_code_size = ZZ_ARM64_FULL_REDIRECT_SIZE; + } } - zz_arm64_relocator_init(&self->arm64_relocator, target_addr, &self->arm64_writer); + self->arm64_relocator.try_relocated_length = entry_backend->redirect_code_size; + zz_arm64_relocator_init(&self->arm64_relocator, (zpointer)target_addr, &self->arm64_writer); return ZZ_SUCCESS; } -// __attribute__((__naked__)) void on_enter_trampoline_template() { -// __asm__ volatile( -// /* store entry address and reserve space for next hop */ -// "sub sp, sp, 0x10\n" -// "ldr x17, #0x8\n" -// "b #0xc\n" -// /* entry address */ -// ".long 0x0\n" -// ".long 0x0\n" -// "str x17, [sp]\n" -// "ldr x17, #0x8\n" -// "br x17\n" -// /* enter_thunk address */ -// ".long 0x0\n" -// ".long 0x0"); -// } - -// __attribute__((__naked__)) void on_inovke_trampoline_template() { -// __asm__ volatile( -// /* fixed instruction */ -// "nop\n" -// "nop\n" -// "nop\n" -// "nop\n" -// "nop\n" -// "nop\n" -// "nop\n" -// "nop\n" -// "ldr x17, #8\n" -// "br x17\n" -// /* rest of orgin function address */ -// ".long 0x0\n" -// ".long 0x0"); -// } - -// __attribute__((__naked__)) void on_leave_trampoline_template() { -// __asm__ volatile( -// /* store entry address and reserve space for next hop */ -// "sub sp, sp, 0x10\n" -// "ldr x17, #0x8\n" -// "b #0xc\n" -// /* entry address */ -// ".long 0x0\n" -// ".long 0x0\n" -// "str x17, [sp]\n" -// "ldr x17, #0x8\n" -// "br x17\n" -// /* leave_thunk address */ -// ".long 0x0\n" -// ".long 0x0"); -// } ZZSTATUS ZzBuildEnterTransferTrampoline(ZzInterceptorBackend *self, ZzHookFunctionEntry *entry) { zbyte temp_code_slice_data[256] = {0}; ZzArm64Writer *arm64_writer = NULL; ZzCodeSlice *code_slice = NULL; ZzArm64HookFunctionEntryBackend *entry_backend = (ZzArm64HookFunctionEntryBackend *)entry->backend; ZZSTATUS status = ZZ_SUCCESS; - zpointer target_addr = entry->target_ptr; + zaddr target_addr = (zaddr)entry->target_ptr; arm64_writer = &self->arm64_writer; zz_arm64_writer_reset(arm64_writer, temp_code_slice_data); - - code_slice = NULL; - do { - zz_arm64_writer_put_ldr_br_reg_address(arm64_writer, ZZ_ARM64_REG_X17, (zaddr)entry->on_enter_trampoline); - if (code_slice) { - if (!ZzMemoryPatchCode((zaddr)code_slice->data, arm64_writer->base, arm64_writer->size)) - return ZZ_FAILED; - break; - } - code_slice = ZzNewNearCodeSlice(self->allocator, (zaddr)entry->target_ptr, - zz_arm64_writer_near_jump_range_size(), arm64_writer->size + 4); - if (!code_slice) { - return ZZ_FAILED; - } else { - zz_arm64_writer_reset(arm64_writer, temp_code_slice_data); - arm64_writer->pc = code_slice->data; - } - } while (code_slice); - entry->on_enter_transfer_trampoline = code_slice->data; + zz_arm64_writer_put_ldr_br_reg_address(arm64_writer, ZZ_ARM64_REG_X17, (zaddr)entry->on_enter_trampoline); + code_slice = + zz_code_patch_arm64_writer(arm64_writer, self->allocator, target_addr, zz_arm64_writer_near_jump_range_size()); + if (code_slice) + entry->on_enter_transfer_trampoline = code_slice->data; + else + return ZZ_FAILED; if (ZzIsEnableDebugMode()) { char buffer[1024] = {}; @@ -149,6 +140,8 @@ ZZSTATUS ZzBuildEnterTransferTrampoline(ZzInterceptorBackend *self, ZzHookFuncti code_slice->data, code_slice->size, entry->on_enter_trampoline); ZzInfoLog("%s", buffer); } + + free(code_slice); return status; } ZZSTATUS ZzBuildEnterTrampoline(ZzInterceptorBackend *self, ZzHookFunctionEntry *entry) { @@ -157,41 +150,27 @@ ZZSTATUS ZzBuildEnterTrampoline(ZzInterceptorBackend *self, ZzHookFunctionEntry ZzCodeSlice *code_slice = NULL; ZzArm64HookFunctionEntryBackend *entry_backend = (ZzArm64HookFunctionEntryBackend *)entry->backend; ZZSTATUS status = ZZ_SUCCESS; - zpointer target_addr = entry->target_ptr; + zaddr target_addr = (zaddr)entry->target_ptr; arm64_writer = &self->arm64_writer; zz_arm64_writer_reset(arm64_writer, temp_code_slice_data); - code_slice = NULL; - do { - /* 2 stack space: 1. next_hop 2. entry arg */ - zz_arm64_writer_put_sub_reg_reg_imm(arm64_writer, ZZ_ARM64_REG_SP, ZZ_ARM64_REG_SP, 2 * 0x8); + /* prepare 2 stack space: 1. next_hop 2. entry arg */ + zz_arm64_writer_put_sub_reg_reg_imm(arm64_writer, ZZ_ARM64_REG_SP, ZZ_ARM64_REG_SP, 2 * 0x8); + zz_arm64_writer_put_ldr_b_reg_address(arm64_writer, ZZ_ARM64_REG_X17, (zaddr)entry); + zz_arm64_writer_put_str_reg_reg_offset(arm64_writer, ZZ_ARM64_REG_X17, ZZ_ARM64_REG_SP, 0x0); - zz_arm64_writer_put_ldr_b_reg_address(arm64_writer, ZZ_ARM64_REG_X17, (zaddr)entry); - zz_arm64_writer_put_str_reg_reg_offset(arm64_writer, ZZ_ARM64_REG_X17, ZZ_ARM64_REG_SP, 0x0); + /* jump to enter thunk */ + zz_arm64_writer_put_ldr_br_reg_address(arm64_writer, ZZ_ARM64_REG_X17, (zaddr)self->enter_thunk); - /* jump to enter thunk */ - zz_arm64_writer_put_ldr_br_reg_address(arm64_writer, ZZ_ARM64_REG_X17, (zaddr)self->enter_thunk); - - if (code_slice) { - if (!ZzMemoryPatchCode((zaddr)code_slice->data, arm64_writer->base, arm64_writer->size)) - return ZZ_FAILED; - break; - } + /* code patch */ + code_slice = zz_code_patch_arm64_writer(arm64_writer, self->allocator, 0, 0); + if (code_slice) + entry->on_enter_trampoline = code_slice->data; + else + return ZZ_FAILED; - if (!code_slice) - code_slice = ZzNewCodeSlice(self->allocator, arm64_writer->size + 4); - - if (!code_slice) { -#if defined(DEBUG_MODE) - debug_break(); -#endif - return ZZ_FAILED; - } else { - zz_arm64_writer_reset(arm64_writer, temp_code_slice_data); - arm64_writer->pc = code_slice->data; - } - } while (code_slice); + /* debug log */ if (ZzIsEnableDebugMode()) { char buffer[1024] = {}; sprintf(buffer + strlen(buffer), "%s\n", "ZzBuildEnterTrampoline:"); @@ -201,12 +180,11 @@ ZZSTATUS ZzBuildEnterTrampoline(ZzInterceptorBackend *self, ZzHookFunctionEntry ZzInfoLog("%s", buffer); } - entry->on_enter_trampoline = code_slice->data; - if (entry_backend->redirect_code_size == ZZ_ARM64_TINY_REDIRECT_SIZE) { ZzBuildEnterTransferTrampoline(self, entry); } + free(code_slice); return status; } @@ -215,7 +193,7 @@ ZZSTATUS ZzBuildInvokeTrampoline(ZzInterceptorBackend *self, ZzHookFunctionEntry ZzCodeSlice *code_slice = NULL; ZzArm64HookFunctionEntryBackend *entry_backend = (ZzArm64HookFunctionEntryBackend *)entry->backend; ZZSTATUS status = ZZ_SUCCESS; - zpointer target_addr = entry->target_ptr; + zaddr target_addr = (zaddr)entry->target_ptr; zpointer restore_target_addr; ZzArm64Relocator *arm64_relocator; @@ -224,56 +202,48 @@ ZZSTATUS ZzBuildInvokeTrampoline(ZzInterceptorBackend *self, ZzHookFunctionEntry arm64_writer = &self->arm64_writer; zz_arm64_writer_reset(arm64_writer, temp_code_slice_data); + zz_arm64_relocator_reset(arm64_relocator, (zpointer)target_addr, arm64_writer); + zsize tmp_relocator_insn_size = 0; + entry->target_half_ret_addr = 0; + + if (entry->hook_type == HOOK_FUNCTION_TYPE) { + do { + zz_arm64_relocator_read_one(arm64_relocator, NULL); + tmp_relocator_insn_size = arm64_relocator->input_cur - arm64_relocator->input_start; + } while (tmp_relocator_insn_size < entry_backend->redirect_code_size); + zz_arm64_relocator_write_all(arm64_relocator); + } else if (entry->hook_type == HOOK_ADDRESS_TYPE) { + do { + zz_arm64_relocator_read_one(arm64_relocator, NULL); + zz_arm64_relocator_write_one(arm64_relocator); + tmp_relocator_insn_size = arm64_relocator->input_cur - arm64_relocator->input_start; + if (arm64_relocator->input_cur >= entry->target_end_ptr && !entry->target_half_ret_addr) { + zz_arm64_writer_put_ldr_br_reg_address(arm64_writer, ZZ_ARM64_REG_X17, + (zaddr)entry->on_half_trampoline); + + entry->target_half_ret_addr = (zpointer)arm64_writer->size; + } + } while (tmp_relocator_insn_size < entry_backend->redirect_code_size || + arm64_relocator->input_cur < entry->target_end_ptr); + } - code_slice = NULL; - do { - zz_arm64_relocator_reset(arm64_relocator, target_addr, arm64_writer); - zsize tmp_relocator_insn_size = 0; - entry->target_half_ret_addr = 0; - - if (entry->hook_type == HOOK_FUNCTION_TYPE) { - do { - zz_arm64_relocator_read_one(arm64_relocator, NULL); - tmp_relocator_insn_size = arm64_relocator->input_cur - arm64_relocator->input_start; - } while (tmp_relocator_insn_size < entry_backend->redirect_code_size); - zz_arm64_relocator_write_all(arm64_relocator); - } else if (entry->hook_type == HOOK_ADDRESS_TYPE) { - do { - zz_arm64_relocator_read_one(arm64_relocator, NULL); - zz_arm64_relocator_write_one(arm64_relocator); - tmp_relocator_insn_size = arm64_relocator->input_cur - arm64_relocator->input_start; - if (arm64_relocator->input_cur >= entry->target_end_ptr && !entry->target_half_ret_addr) { - /* jump to rest target address */ - zz_arm64_writer_put_ldr_br_reg_address(arm64_writer, ZZ_ARM64_REG_X17, - (zaddr)entry->on_half_trampoline); - - entry->target_half_ret_addr = (zpointer)arm64_writer->size; - } - } while (tmp_relocator_insn_size < entry_backend->redirect_code_size || - arm64_relocator->input_cur < entry->target_end_ptr); - } + /* jump to rest target address */ + restore_target_addr = (zpointer)((zaddr)target_addr + tmp_relocator_insn_size); + zz_arm64_writer_put_ldr_br_reg_address(arm64_writer, ZZ_ARM64_REG_X17, (zaddr)restore_target_addr); - restore_target_addr = (zpointer)((zaddr)target_addr + tmp_relocator_insn_size); + /* code patch */ + code_slice = zz_code_patch_arm64_relocate_writer(arm64_relocator, arm64_writer, self->allocator, 0, 0); + if (code_slice) + entry->on_invoke_trampoline = code_slice->data; + else + return ZZ_FAILED; - /* jump to rest target address */ - zz_arm64_writer_put_ldr_br_reg_address(arm64_writer, ZZ_ARM64_REG_X17, (zaddr)restore_target_addr); + /* update target_half_ret_addr */ + if (entry->hook_type == HOOK_ADDRESS_TYPE) { + entry->target_half_ret_addr += (zaddr)code_slice->data; + } - if (code_slice) { - if (!ZzMemoryPatchCode((zaddr)code_slice->data, arm64_writer->base, arm64_writer->size)) - return ZZ_FAILED; - break; - } - code_slice = ZzNewCodeSlice(self->allocator, arm64_writer->size + 4); - if (!code_slice) { -#if defined(DEBUG_MODE) - debug_break(); -#endif - return ZZ_FAILED; - } else { - zz_arm64_writer_reset(arm64_writer, temp_code_slice_data); - arm64_writer->pc = code_slice->data; - } - } while (code_slice); + /* debug log */ if (ZzIsEnableDebugMode()) { char buffer[1024] = {0}; sprintf(buffer + strlen(buffer), "%s\n", "ZzBuildInvokeTrampoline:"); @@ -287,8 +257,8 @@ ZZSTATUS ZzBuildInvokeTrampoline(ZzInterceptorBackend *self, ZzHookFunctionEntry char origin_prologue[256] = {0}; int t = 0; - for (zpointer p = (&self->arm64_relocator)->input_start; p < (&self->arm64_relocator)->input_cur; - p++, t = t + 5) { + zpointer p; + for (p = (&self->arm64_relocator)->input_start; p < (&self->arm64_relocator)->input_cur; p++, t = t + 5) { sprintf(origin_prologue + t, "0x%.2x ", *(unsigned char *)p); } sprintf(buffer + strlen(buffer), "origin_prologue: %s\n", origin_prologue); @@ -296,11 +266,7 @@ ZZSTATUS ZzBuildInvokeTrampoline(ZzInterceptorBackend *self, ZzHookFunctionEntry ZzInfoLog("%s", buffer); } - if (entry->hook_type == HOOK_ADDRESS_TYPE) { - // update target_half_ret_addr - entry->target_half_ret_addr += (zaddr)code_slice->data; - } - entry->on_invoke_trampoline = code_slice->data; + free(code_slice); return status; } @@ -310,42 +276,25 @@ ZZSTATUS ZzBuildHalfTrampoline(ZzInterceptorBackend *self, ZzHookFunctionEntry * ZzCodeSlice *code_slice = NULL; ZzArm64HookFunctionEntryBackend *entry_backend = (ZzArm64HookFunctionEntryBackend *)entry->backend; ZZSTATUS status = ZZ_SUCCESS; - zpointer target_addr = entry->target_ptr; + zaddr target_addr = (zaddr)entry->target_ptr; arm64_writer = &self->arm64_writer; zz_arm64_writer_reset(arm64_writer, temp_code_slice_data); - code_slice = NULL; - do { - /* 2 stack space: 1. next_hop 2. entry arg */ - zz_arm64_writer_put_sub_reg_reg_imm(arm64_writer, ZZ_ARM64_REG_SP, ZZ_ARM64_REG_SP, 2 * 0x8); - - zz_arm64_writer_put_ldr_b_reg_address(arm64_writer, ZZ_ARM64_REG_X17, (zaddr)entry); - zz_arm64_writer_put_str_reg_reg_offset(arm64_writer, ZZ_ARM64_REG_X17, ZZ_ARM64_REG_SP, 0x0); - - zz_arm64_writer_put_ldr_br_reg_address(arm64_writer, ZZ_ARM64_REG_X17, (zaddr)self->half_thunk); - - if (code_slice) { - if (!ZzMemoryPatchCode((zaddr)code_slice->data, arm64_writer->base, arm64_writer->size)) - return ZZ_FAILED; - break; - } + /* prepare 2 stack space: 1. next_hop 2. entry arg */ + zz_arm64_writer_put_sub_reg_reg_imm(arm64_writer, ZZ_ARM64_REG_SP, ZZ_ARM64_REG_SP, 2 * 0x8); + zz_arm64_writer_put_ldr_b_reg_address(arm64_writer, ZZ_ARM64_REG_X17, (zaddr)entry); + zz_arm64_writer_put_str_reg_reg_offset(arm64_writer, ZZ_ARM64_REG_X17, ZZ_ARM64_REG_SP, 0x0); - if (!code_slice) - code_slice = ZzNewCodeSlice(self->allocator, arm64_writer->size + 4); - if (!code_slice) { -#if defined(DEBUG_MODE) - debug_break(); -#endif - return ZZ_FAILED; - } else { - zz_arm64_writer_reset(arm64_writer, temp_code_slice_data); - arm64_writer->pc = code_slice->data; - } - } while (code_slice); + /* jump to half thunk */ + zz_arm64_writer_put_ldr_br_reg_address(arm64_writer, ZZ_ARM64_REG_X17, (zaddr)self->half_thunk); - /* set arm64 on_half_trampoline */ - entry->on_half_trampoline = code_slice->data; + /* code patch */ + code_slice = zz_code_patch_arm64_writer(arm64_writer, self->allocator, 0, 0); + if (code_slice) + entry->on_half_trampoline = code_slice->data; + else + return ZZ_FAILED; return status; } @@ -354,38 +303,28 @@ ZZSTATUS ZzBuildLeaveTrampoline(ZzInterceptorBackend *self, ZzHookFunctionEntry zbyte temp_code_slice_data[256] = {0}; ZzCodeSlice *code_slice = NULL; ZzArm64HookFunctionEntryBackend *entry_backend = (ZzArm64HookFunctionEntryBackend *)entry->backend; - zpointer target_addr = entry->target_ptr; - ZzArm64Writer *arm64_writer; + zaddr target_addr = (zaddr)entry->target_ptr; + ZzArm64Writer *arm64_writer = NULL; arm64_writer = &self->arm64_writer; zz_arm64_writer_reset(arm64_writer, temp_code_slice_data); - do { - /* 2 stack space: 1. next_hop 2. entry arg */ - zz_arm64_writer_put_sub_reg_reg_imm(arm64_writer, ZZ_ARM64_REG_SP, ZZ_ARM64_REG_SP, 2 * 0x8); + /* prepare 2 stack space: 1. next_hop 2. entry arg */ + zz_arm64_writer_put_sub_reg_reg_imm(arm64_writer, ZZ_ARM64_REG_SP, ZZ_ARM64_REG_SP, 2 * 0x8); + zz_arm64_writer_put_ldr_b_reg_address(arm64_writer, ZZ_ARM64_REG_X17, (zaddr)entry); + zz_arm64_writer_put_str_reg_reg_offset(arm64_writer, ZZ_ARM64_REG_X17, ZZ_ARM64_REG_SP, 0x0); - zz_arm64_writer_put_ldr_b_reg_address(arm64_writer, ZZ_ARM64_REG_X17, (zaddr)entry); - zz_arm64_writer_put_str_reg_reg_offset(arm64_writer, ZZ_ARM64_REG_X17, ZZ_ARM64_REG_SP, 0x0); + /* jump to leave thunk */ + zz_arm64_writer_put_ldr_br_reg_address(arm64_writer, ZZ_ARM64_REG_X17, (zaddr)self->leave_thunk); - /* jump to leave thunk */ - zz_arm64_writer_put_ldr_br_reg_address(arm64_writer, ZZ_ARM64_REG_X17, (zaddr)self->leave_thunk); - if (code_slice) { - if (!ZzMemoryPatchCode((zaddr)code_slice->data, arm64_writer->base, arm64_writer->size)) - return ZZ_FAILED; - break; - } - code_slice = ZzNewCodeSlice(self->allocator, arm64_writer->size + 4); - if (!code_slice) { -#if defined(DEBUG_MODE) - debug_break(); -#endif - return ZZ_FAILED; - } else { - zz_arm64_writer_reset(arm64_writer, temp_code_slice_data); - arm64_writer->pc = code_slice->data; - } - } while (code_slice); + /* code patch */ + code_slice = zz_code_patch_arm64_writer(arm64_writer, self->allocator, 0, 0); + if (code_slice) + entry->on_leave_trampoline = code_slice->data; + else + return ZZ_FAILED; + /* debug log */ if (ZzIsEnableDebugMode()) { char buffer[1024] = {}; sprintf(buffer + strlen(buffer), "%s\n", "ZzBuildLeaveTrampoline:"); @@ -395,9 +334,7 @@ ZZSTATUS ZzBuildLeaveTrampoline(ZzInterceptorBackend *self, ZzHookFunctionEntry ZzInfoLog("%s", buffer); } - /* set arm64 on_leave_trampoline */ - entry->on_leave_trampoline = code_slice->data; - + free(code_slice); return ZZ_DONE; } @@ -406,7 +343,7 @@ ZZSTATUS ZzActivateTrampoline(ZzInterceptorBackend *self, ZzHookFunctionEntry *e ZzCodeSlice *code_slice = NULL; ZzArm64HookFunctionEntryBackend *entry_backend = (ZzArm64HookFunctionEntryBackend *)entry->backend; ZZSTATUS status = ZZ_SUCCESS; - zpointer target_addr = entry->target_ptr; + zaddr target_addr = (zaddr)entry->target_ptr; ZzArm64Writer *arm64_writer; arm64_writer = &self->arm64_writer; @@ -414,7 +351,7 @@ ZZSTATUS ZzActivateTrampoline(ZzInterceptorBackend *self, ZzHookFunctionEntry *e arm64_writer->pc = target_addr; if (entry_backend->redirect_code_size == ZZ_ARM64_TINY_REDIRECT_SIZE) { - zz_arm64_writer_put_b_imm(arm64_writer, (zaddr)entry->on_enter_transfer_trampoline - (zaddr)target_addr); + zz_arm64_writer_put_b_imm(arm64_writer, (zaddr)entry->on_enter_transfer_trampoline - (zaddr)arm64_writer->pc); } else { zz_arm64_writer_put_ldr_br_reg_address(arm64_writer, ZZ_ARM64_REG_X17, (zaddr)entry->on_enter_trampoline); } @@ -458,8 +395,8 @@ ZZSTATUS ZzActivateSolidifyTrampoline(ZzHookFunctionEntry *entry, zaddr target_f ZzHookFunctionEntryNoJB *nojb_entry = (ZzHookFunctionEntryNoJB *)(data_seg_cmd->vmaddr + sizeof(ZzHookFunctionEntryNoJB) + aslr_slide); - - for (unsigned long i = 0; i < nojb_backend->num_of_entry; i++) { + unsigned long i; + for (i = 0; i < nojb_backend->num_of_entry; i++) { nojb_entry = &nojb_entry[i]; if ((zaddr)nojb_entry->target_fileoff == target_fileoff) { nojb_entry->entry_address = entry; diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/backend-arm64/interceptor-arm64.h b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/backend-arm64/interceptor-arm64.h index 77eef0514..8001aca0b 100644 --- a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/backend-arm64/interceptor-arm64.h +++ b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/backend-arm64/interceptor-arm64.h @@ -57,4 +57,7 @@ void leave_thunk_template(); void on_enter_trampoline_template(); void on_invoke_trampoline_template(); void on_leave_trampoline_template(); + +ZzCodeSlice *zz_code_patch_arm64_writer(ZzArm64Writer *arm64_writer, ZzAllocator *allocator, zaddr target_addr, + zsize range_size); #endif \ No newline at end of file diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/backend-arm64/thunker-arm64.c b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/backend-arm64/thunker-arm64.c index b97921b01..a5b3dc648 100644 --- a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/backend-arm64/thunker-arm64.c +++ b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/backend-arm64/thunker-arm64.c @@ -104,22 +104,23 @@ // just like pre_call, wow! void function_context_begin_invocation(ZzHookFunctionEntry *entry, zpointer next_hop, RegState *rs, zpointer caller_ret_addr) { + Xinfo("target %p call begin-invocation", entry->target_ptr); - Xdebug("target %p call begin-invocation", entry->target_ptr); ZzThreadStack *stack = ZzGetCurrentThreadStack(entry->thread_local_key); if (!stack) { stack = ZzNewThreadStack(entry->thread_local_key); } - ZzCallStack *callstack = ZzNewCallStack(); ZzPushCallStack(stack, callstack); + /* call pre_call */ if (entry->pre_call) { PRECALL pre_call; pre_call = entry->pre_call; (*pre_call)(rs, (ThreadStack *)stack, (CallStack *)callstack); } + /* set next hop */ if (entry->replace_call) { *(zpointer *)next_hop = entry->replace_call; } else { @@ -136,6 +137,7 @@ void function_context_begin_invocation(ZzHookFunctionEntry *entry, zpointer next void function_context_half_invocation(ZzHookFunctionEntry *entry, zpointer next_hop, RegState *rs, zpointer caller_ret_addr) { Xdebug("target %p call half-invocation", entry->target_ptr); + ZzThreadStack *stack = ZzGetCurrentThreadStack(entry->thread_local_key); if (!stack) { #if defined(DEBUG_MODE) @@ -144,11 +146,14 @@ void function_context_half_invocation(ZzHookFunctionEntry *entry, zpointer next_ } ZzCallStack *callstack = ZzPopCallStack(stack); + /* call half_call */ if (entry->half_call) { HALFCALL half_call; half_call = entry->half_call; (*half_call)(rs, (ThreadStack *)stack, (CallStack *)callstack); } + + /* set next hop */ *(zpointer *)next_hop = (zpointer)entry->target_half_ret_addr; ZzFreeCallStack(callstack); @@ -157,6 +162,7 @@ void function_context_half_invocation(ZzHookFunctionEntry *entry, zpointer next_ // just like post_call, wow! void function_context_end_invocation(ZzHookFunctionEntry *entry, zpointer next_hop, RegState *rs) { Xdebug("%p call end-invocation", entry->target_ptr); + ZzThreadStack *stack = ZzGetCurrentThreadStack(entry->thread_local_key); if (!stack) { #if defined(DEBUG_MODE) @@ -165,13 +171,15 @@ void function_context_end_invocation(ZzHookFunctionEntry *entry, zpointer next_h } ZzCallStack *callstack = ZzPopCallStack(stack); + /* call post_call */ if (entry->post_call) { POSTCALL post_call; post_call = entry->post_call; (*post_call)(rs, (ThreadStack *)stack, (CallStack *)callstack); } - *(zpointer *)next_hop = callstack->caller_ret_addr; + /* set next hop */ + *(zpointer *)next_hop = callstack->caller_ret_addr; ZzFreeCallStack(callstack); } @@ -278,6 +286,7 @@ void zz_arm64_thunker_build_enter_thunk(ZzWriter *writer) { /* save general registers and sp */ zz_arm64_writer_put_bytes(writer, (void *)ctx_save, 23 * 4); zz_arm64_writer_put_add_reg_reg_imm(writer, ZZ_ARM64_REG_X1, ZZ_ARM64_REG_SP, 8 + CTX_SAVE_STACK_OFFSET + 2 * 8); + /* trick: use the `ctx_save` left [sp]*/ zz_arm64_writer_put_str_reg_reg_offset(writer, ZZ_ARM64_REG_X1, ZZ_ARM64_REG_SP, 0 * 8); @@ -290,7 +299,6 @@ void zz_arm64_thunker_build_enter_thunk(ZzWriter *writer) { /* next hop*/ zz_arm64_writer_put_add_reg_reg_imm(writer, ZZ_ARM64_REG_X1, ZZ_ARM64_REG_SP, 2 * 8 + 8 + CTX_SAVE_STACK_OFFSET + 0x8); - /* RegState */ zz_arm64_writer_put_add_reg_reg_imm(writer, ZZ_ARM64_REG_X2, ZZ_ARM64_REG_SP, 2 * 8); /* caller ret address */ @@ -298,6 +306,7 @@ void zz_arm64_thunker_build_enter_thunk(ZzWriter *writer) { /* call function_context_begin_invocation */ zz_arm64_writer_put_ldr_blr_b_reg_address(writer, ZZ_ARM64_REG_X17, (zaddr)function_context_begin_invocation); + /* alignment padding + dummy PC */ zz_arm64_writer_put_add_reg_reg_imm(writer, ZZ_ARM64_REG_SP, ZZ_ARM64_REG_SP, 2 * 8); @@ -318,6 +327,7 @@ void zz_arm64_thunker_build_half_thunk(ZzWriter *writer) { /* save general registers and sp */ zz_arm64_writer_put_bytes(writer, (void *)ctx_save, 23 * 4); zz_arm64_writer_put_add_reg_reg_imm(writer, ZZ_ARM64_REG_X1, ZZ_ARM64_REG_SP, 8 + CTX_SAVE_STACK_OFFSET + 2 * 8); + /* trick: use the `ctx_save` left [sp]*/ zz_arm64_writer_put_str_reg_reg_offset(writer, ZZ_ARM64_REG_X1, ZZ_ARM64_REG_SP, 0 * 8); @@ -338,6 +348,7 @@ void zz_arm64_thunker_build_half_thunk(ZzWriter *writer) { /* call function_context_half_invocation */ zz_arm64_writer_put_ldr_blr_b_reg_address(writer, ZZ_ARM64_REG_X17, (zaddr)function_context_half_invocation); + /* alignment padding + dummy PC */ zz_arm64_writer_put_add_reg_reg_imm(writer, ZZ_ARM64_REG_SP, ZZ_ARM64_REG_SP, 2 * 8); @@ -454,6 +465,7 @@ void zz_arm64_thunker_build_leave_thunk(ZzWriter *writer) { /* save general registers and sp */ zz_arm64_writer_put_bytes(writer, (void *)ctx_save, 23 * 4); zz_arm64_writer_put_add_reg_reg_imm(writer, ZZ_ARM64_REG_X1, ZZ_ARM64_REG_SP, 8 + CTX_SAVE_STACK_OFFSET + 2 * 8); + /* trick: use the `ctx_save` left [sp]*/ zz_arm64_writer_put_str_reg_reg_offset(writer, ZZ_ARM64_REG_X1, ZZ_ARM64_REG_SP, 0 * 8); @@ -472,6 +484,7 @@ void zz_arm64_thunker_build_leave_thunk(ZzWriter *writer) { /* call function_context_end_invocation */ zz_arm64_writer_put_ldr_blr_b_reg_address(writer, ZZ_ARM64_REG_X17, (zaddr)function_context_end_invocation); + /* alignment padding + dummy PC */ zz_arm64_writer_put_add_reg_reg_imm(writer, ZZ_ARM64_REG_SP, ZZ_ARM64_REG_SP, 2 * 8); @@ -489,7 +502,7 @@ void zz_arm64_thunker_build_leave_thunk(ZzWriter *writer) { } ZZSTATUS ZzThunkerBuildThunk(ZzInterceptorBackend *self) { - zbyte temp_code_slice_data[256] = {0}; + zbyte temp_code_slice_data[512] = {0}; ZzArm64Writer *arm64_writer = NULL; ZzCodeSlice *code_slice = NULL; ZZSTATUS status = ZZ_SUCCESS; @@ -497,29 +510,17 @@ ZZSTATUS ZzThunkerBuildThunk(ZzInterceptorBackend *self) { arm64_writer = &self->arm64_writer; zz_arm64_writer_reset(arm64_writer, temp_code_slice_data); - code_slice = NULL; - do { - zz_arm64_thunker_build_enter_thunk(arm64_writer); - if (code_slice) { - if (!ZzMemoryPatchCode((zaddr)code_slice->data, arm64_writer->base, arm64_writer->size)) - return ZZ_FAILED; - break; - } - code_slice = ZzNewCodeSlice(self->allocator, arm64_writer->size + 4); - if (!code_slice) { -#if defined(DEBUG_MODE) - debug_break(); -#endif - return ZZ_FAILED; - } else { - zz_arm64_writer_reset(arm64_writer, temp_code_slice_data); - arm64_writer->pc = code_slice->data; - } - } while (code_slice); - - /* set arm64 enter_thunk */ - // self->enter_thunk = code_slice->data; - self->enter_thunk = (void *)enter_thunk_template; + /* build enter_thunk */ + zz_arm64_thunker_build_enter_thunk(arm64_writer); + + /* code patch */ + code_slice = zz_code_patch_arm64_writer(arm64_writer, self->allocator, 0, 0); + if (code_slice) + self->enter_thunk = (void *)enter_thunk_template; + else + return ZZ_FAILED; + + /* debug log */ if (ZzIsEnableDebugMode()) { char buffer[1024] = {}; sprintf(buffer + strlen(buffer), "%s\n", "ZzThunkerBuildThunk:"); @@ -529,25 +530,18 @@ ZZSTATUS ZzThunkerBuildThunk(ZzInterceptorBackend *self) { } zz_arm64_writer_reset(arm64_writer, temp_code_slice_data); - code_slice = NULL; - do { - zz_arm64_thunker_build_leave_thunk(arm64_writer); - if (code_slice) { - if (!ZzMemoryPatchCode((zaddr)code_slice->data, arm64_writer->base, arm64_writer->size)) - return ZZ_FAILED; - break; - } - code_slice = ZzNewCodeSlice(self->allocator, arm64_writer->size + 4); - if (!code_slice) { -#if defined(DEBUG_MODE) - debug_break(); -#endif - return ZZ_FAILED; - } else { - zz_arm64_writer_reset(arm64_writer, temp_code_slice_data); - arm64_writer->pc = code_slice->data; - } - } while (code_slice); + + /* build leave_thunk */ + zz_arm64_thunker_build_leave_thunk(arm64_writer); + + /* code patch */ + code_slice = zz_code_patch_arm64_writer(arm64_writer, self->allocator, 0, 0); + if (code_slice) + self->leave_thunk = code_slice->data; + else + return ZZ_FAILED; + + /* debug log */ if (ZzIsEnableDebugMode()) { char buffer[1024] = {}; sprintf(buffer + strlen(buffer), "%s\n", "ZzThunkerBuildThunk:"); @@ -556,32 +550,26 @@ ZZSTATUS ZzThunkerBuildThunk(ZzInterceptorBackend *self) { ZzInfoLog("%s", buffer); } - /* set arm64 leave_thunk */ - self->leave_thunk = code_slice->data; - zz_arm64_writer_reset(arm64_writer, temp_code_slice_data); - code_slice = NULL; - do { - zz_arm64_thunker_build_half_thunk(arm64_writer); - if (code_slice) { - if (!ZzMemoryPatchCode((zaddr)code_slice->data, arm64_writer->base, arm64_writer->size)) - return ZZ_FAILED; - break; - } - code_slice = ZzNewCodeSlice(self->allocator, arm64_writer->size + 4); - if (!code_slice) { -#if defined(DEBUG_MODE) - debug_break(); -#endif - return ZZ_FAILED; - } else { - zz_arm64_writer_reset(arm64_writer, temp_code_slice_data); - arm64_writer->pc = code_slice->data; - } - } while (code_slice); - - /* set arm64 half_thunk */ - self->half_thunk = code_slice->data; + + /* build half_thunk */ + zz_arm64_thunker_build_half_thunk(arm64_writer); + + /* code patch */ + code_slice = zz_code_patch_arm64_writer(arm64_writer, self->allocator, 0, 0); + if (code_slice) + self->half_thunk = code_slice->data; + else + return ZZ_FAILED; + + /* debug log */ + if (ZzIsEnableDebugMode()) { + char buffer[1024] = {}; + sprintf(buffer + strlen(buffer), "%s\n", "ZzThunkerBuildThunk:"); + sprintf(buffer + strlen(buffer), "LogInfo: half_thunk at %p, length: %ld.\n", code_slice->data, + code_slice->size); + ZzInfoLog("%s", buffer); + } return status; } diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/backend-x86/interceptor-template-x86.s b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/backend-x86/interceptor-template-x86.s new file mode 100644 index 000000000..b690233d8 --- /dev/null +++ b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/backend-x86/interceptor-template-x86.s @@ -0,0 +1,10 @@ +// .section __TEXT,__text,regular,pure_instructions +// .ios_version_min 11, 0 +.align 4 +.globl _ctx_save +.globl _ctx_restore +.globl _enter_thunk_template +.globl _leave_thunk_template +.globl _on_enter_trampoline_template +.globl _on_invoke_trampoline_template +.globl _on_leave_trampoline_template diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/backend-x86/interceptor-x86.c b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/backend-x86/interceptor-x86.c new file mode 100644 index 000000000..0f1fdc1ed --- /dev/null +++ b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/backend-x86/interceptor-x86.c @@ -0,0 +1,48 @@ +/** + * Copyright 2017 jmpews + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "interceptor-x86.h" +#include "zzinfo.h" +#include +#include + +#define ZZ_X86_TINY_REDIRECT_SIZE 4 +#define ZZ_X86_FULL_REDIRECT_SIZE 16 + +ZzInterceptorBackend *ZzBuildInteceptorBackend(ZzAllocator *allocator) { return NULL; } + +ZzCodeSlice *zz_code_patch_x86_writer(ZzX86Writer *x86_writer, ZzAllocator *allocator, zaddr target_addr, + zsize range_size) { + return NULL; +} +ZzCodeSlice *zz_code_patch_x86_relocate_writer(ZzX86Relocator *relocator, ZzX86Writer *x86_writer, + ZzAllocator *allocator, zaddr target_addr, zsize range_size) { + return NULL; +} + +ZZSTATUS ZzPrepareTrampoline(ZzInterceptorBackend *self, ZzHookFunctionEntry *entry) { return ZZ_FAILED; } + +ZZSTATUS ZzBuildEnterTransferTrampoline(ZzInterceptorBackend *self, ZzHookFunctionEntry *entry) { return ZZ_FAILED; } + +ZZSTATUS ZzBuildEnterTrampoline(ZzInterceptorBackend *self, ZzHookFunctionEntry *entry) { return ZZ_FAILED; } + +ZZSTATUS ZzBuildInvokeTrampoline(ZzInterceptorBackend *self, ZzHookFunctionEntry *entry) { return ZZ_FAILED; } + +ZZSTATUS ZzBuildHalfTrampoline(ZzInterceptorBackend *self, ZzHookFunctionEntry *entry) { return ZZ_FAILED; } + +ZZSTATUS ZzBuildLeaveTrampoline(ZzInterceptorBackend *self, ZzHookFunctionEntry *entry) { return ZZ_FAILED; } + +ZZSTATUS ZzActivateTrampoline(ZzInterceptorBackend *self, ZzHookFunctionEntry *entry) { return ZZ_FAILED; } diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/backend-x86/interceptor-x86.h b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/backend-x86/interceptor-x86.h new file mode 100644 index 000000000..39848f888 --- /dev/null +++ b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/backend-x86/interceptor-x86.h @@ -0,0 +1,54 @@ +/** + * Copyright 2017 jmpews + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef platforms_backend_x86_intercetor_x86 +#define platforms_backend_x86_intercetor_x86 + +// platforms +#include "platforms/arch-x86/relocator-x86.h" +#include "platforms/arch-x86/writer-x86.h" + +// hookzz +#include "allocator.h" +#include "interceptor.h" +#include "thunker.h" + +// zzdeps +#include "hookzz.h" +#include "zzdefs.h" +#include "zzdeps/common/debugbreak.h" +#include "zzdeps/zz.h" + +#define CTX_SAVE_STACK_OFFSET (8 + 30 * 8 + 8 * 16) + +typedef struct _ZzInterceptorBackend { + +} ZzInterceptorBackend; + +typedef struct _ZzX86HookFuntionEntryBackend { +} ZzX86HookFunctionEntryBackend; + +void ctx_save(); +void ctx_restore(); +void enter_thunk_template(); +void leave_thunk_template(); +void on_enter_trampoline_template(); +void on_invoke_trampoline_template(); +void on_leave_trampoline_template(); + +ZzCodeSlice *zz_code_patch_x86_writer(ZzX86Writer *x86_writer, ZzAllocator *allocator, zaddr target_addr, + zsize range_size); +#endif \ No newline at end of file diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/backend-x86/thunker-x86.c b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/backend-x86/thunker-x86.c new file mode 100644 index 000000000..59278e206 --- /dev/null +++ b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/backend-x86/thunker-x86.c @@ -0,0 +1,115 @@ +/** + * Copyright 2017 jmpews + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "thunker-x86.h" +#include "zzinfo.h" +#include + + +// just like pre_call, wow! +void function_context_begin_invocation(ZzHookFunctionEntry *entry, zpointer next_hop, RegState *rs, + zpointer caller_ret_addr) { + Xinfo("target %p call begin-invocation", entry->target_ptr); + + ZzThreadStack *stack = ZzGetCurrentThreadStack(entry->thread_local_key); + if (!stack) { + stack = ZzNewThreadStack(entry->thread_local_key); + } + ZzCallStack *callstack = ZzNewCallStack(); + ZzPushCallStack(stack, callstack); + + /* call pre_call */ + if (entry->pre_call) { + PRECALL pre_call; + pre_call = entry->pre_call; + (*pre_call)(rs, (ThreadStack *)stack, (CallStack *)callstack); + } + + /* set next hop */ + if (entry->replace_call) { + *(zpointer *)next_hop = entry->replace_call; + } else { + *(zpointer *)next_hop = entry->on_invoke_trampoline; + } + + if (entry->hook_type == HOOK_FUNCTION_TYPE) { + callstack->caller_ret_addr = *(zpointer *)caller_ret_addr; + *(zpointer *)caller_ret_addr = entry->on_leave_trampoline; + } +} + +// just like post_call, wow! +void function_context_half_invocation(ZzHookFunctionEntry *entry, zpointer next_hop, RegState *rs, + zpointer caller_ret_addr) { + Xdebug("target %p call half-invocation", entry->target_ptr); + + ZzThreadStack *stack = ZzGetCurrentThreadStack(entry->thread_local_key); + if (!stack) { +#if defined(DEBUG_MODE) + debug_break(); +#endif + } + ZzCallStack *callstack = ZzPopCallStack(stack); + + /* call half_call */ + if (entry->half_call) { + HALFCALL half_call; + half_call = entry->half_call; + (*half_call)(rs, (ThreadStack *)stack, (CallStack *)callstack); + } + + /* set next hop */ + *(zpointer *)next_hop = (zpointer)entry->target_half_ret_addr; + + ZzFreeCallStack(callstack); +} + +// just like post_call, wow! +void function_context_end_invocation(ZzHookFunctionEntry *entry, zpointer next_hop, RegState *rs) { + Xdebug("%p call end-invocation", entry->target_ptr); + + ZzThreadStack *stack = ZzGetCurrentThreadStack(entry->thread_local_key); + if (!stack) { +#if defined(DEBUG_MODE) + debug_break(); +#endif + } + ZzCallStack *callstack = ZzPopCallStack(stack); + + /* call post_call */ + if (entry->post_call) { + POSTCALL post_call; + post_call = entry->post_call; + (*post_call)(rs, (ThreadStack *)stack, (CallStack *)callstack); + } + + /* set next hop */ + *(zpointer *)next_hop = callstack->caller_ret_addr; + ZzFreeCallStack(callstack); +} + +void zz_x86_thunker_build_enter_thunk(ZzWriter *writer) { +} + +void zz_x86_thunker_build_half_thunk(ZzWriter *writer) { +} + +void zz_x86_thunker_build_leave_thunk(ZzWriter *writer) { +} + +ZZSTATUS ZzThunkerBuildThunk(ZzInterceptorBackend *self) { + return ZZ_FAILED; +} diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/platforms/backend-x86/thunker-x86.h b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/backend-x86/thunker-x86.h new file mode 100644 index 000000000..554626c4a --- /dev/null +++ b/VirtualApp/lib/src/main/jni/HookZz/src/platforms/backend-x86/thunker-x86.h @@ -0,0 +1,35 @@ +/** + * Copyright 2017 jmpews + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef platforms_backend_x86_thunker_x86 +#define platforms_backend_x86_thunker_x86 + +// platforms +#include "platforms/arch-x86/relocator-x86.h" +#include "platforms/arch-x86/writer-x86.h" + +#include "interceptor-x86.h" + +// hookzz +#include "stack.h" +#include "thunker.h" + +// zzdeps +#include "hookzz.h" +#include "zzdeps/common/debugbreak.h" +#include "zzdeps/zz.h" + +#endif \ No newline at end of file diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/stack.c b/VirtualApp/lib/src/main/jni/HookZz/src/stack.c index 8637f4f27..6329b5e28 100644 --- a/VirtualApp/lib/src/main/jni/HookZz/src/stack.c +++ b/VirtualApp/lib/src/main/jni/HookZz/src/stack.c @@ -44,6 +44,7 @@ ZzThreadStack *ZzNewThreadStack(zpointer key_ptr) { ZzCallStack *ZzNewCallStack() { ZzCallStack *callstack; callstack = (ZzCallStack *)malloc(sizeof(ZzCallStack)); + callstack->capacity = 4; callstack->items = (ZzCallStackItem *)malloc(sizeof(ZzCallStackItem) * callstack->capacity); @@ -74,8 +75,8 @@ zbool ZzPushCallStack(ZzThreadStack *stack, ZzCallStack *callstack) { return FALSE; if (stack->size >= stack->capacity) { - ZzCallStack **callstacks = (ZzCallStack **)realloc( - stack->callstacks, sizeof(ZzCallStack *) * (stack->capacity) * 2); + ZzCallStack **callstacks = + (ZzCallStack **)realloc(stack->callstacks, sizeof(ZzCallStack *) * (stack->capacity) * 2); if (!callstacks) return FALSE; stack->callstacks = callstacks; @@ -93,7 +94,8 @@ zpointer ZzGetCallStackData(CallStack *callstack_ptr, char *key) { ZzCallStack *callstack = (ZzCallStack *)callstack_ptr; if (!callstack) return NULL; - for (int i = 0; i < callstack->size; ++i) { + int i; + for (i = 0; i < callstack->size; ++i) { if (!strcmp(callstack->items[i].key, key)) { return callstack->items[i].value; } @@ -105,8 +107,8 @@ ZzCallStackItem *ZzNewCallStackData(ZzCallStack *callstack) { if (!callstack) return NULL; if (callstack->size >= callstack->capacity) { - ZzCallStackItem *callstackitems = (ZzCallStackItem *)realloc( - callstack->items, sizeof(ZzCallStackItem) * callstack->capacity * 2); + ZzCallStackItem *callstackitems = + (ZzCallStackItem *)realloc(callstack->items, sizeof(ZzCallStackItem) * callstack->capacity * 2); if (!callstackitems) return NULL; callstack->items = callstackitems; @@ -115,8 +117,7 @@ ZzCallStackItem *ZzNewCallStackData(ZzCallStack *callstack) { return &(callstack->items[callstack->size++]); } -zbool ZzSetCallStackData(CallStack *callstack_ptr, char *key, zpointer value_ptr, - zsize value_size) { +zbool ZzSetCallStackData(CallStack *callstack_ptr, char *key, zpointer value_ptr, zsize value_size) { ZzCallStack *callstack = (ZzCallStack *)callstack_ptr; if (!callstack) return FALSE; diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/stack.h b/VirtualApp/lib/src/main/jni/HookZz/src/stack.h index 511de7d44..0c0f6ed82 100644 --- a/VirtualApp/lib/src/main/jni/HookZz/src/stack.h +++ b/VirtualApp/lib/src/main/jni/HookZz/src/stack.h @@ -52,15 +52,10 @@ typedef struct _ZzThreadStack { } ZzThreadStack; ZzThreadStack *ZzNewThreadStack(zpointer key_ptr); - -ZzThreadStack *ZzGetCurrentThreadStack(zpointer key_ptr); - ZzCallStack *ZzNewCallStack(); - -void ZzFreeCallStack(ZzCallStack *callstack); - -ZzCallStack *ZzPopCallStack(ZzThreadStack *stack); - +ZzThreadStack *ZzGetCurrentThreadStack(zpointer key_ptr); zbool ZzPushCallStack(ZzThreadStack *stack, ZzCallStack *callstack); +ZzCallStack *ZzPopCallStack(ZzThreadStack *stack); +void ZzFreeCallStack(ZzCallStack *callstack); #endif \ No newline at end of file diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/writer.h b/VirtualApp/lib/src/main/jni/HookZz/src/writer.h index 62cd18ae1..a1036f62c 100644 --- a/VirtualApp/lib/src/main/jni/HookZz/src/writer.h +++ b/VirtualApp/lib/src/main/jni/HookZz/src/writer.h @@ -19,11 +19,22 @@ #include "hookzz.h" +#define MAX_LITERAL_INSN_SIZE 128 + +typedef struct _ZzLiteralInstruction { + zpointer literal_insn_ptr; + zaddr *literal_address_ptr; +} ZzLiteralInstruction; + typedef struct _ZzWriter { - zpointer *codedata; + zpointer codedata; zpointer base; - zpointer pc; - zuint size; + zaddr pc; + zsize size; + + ZzLiteralInstruction literal_insns[MAX_LITERAL_INSN_SIZE]; + zsize literal_insn_size; + } ZzWriter; #endif diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/zzdefs.h b/VirtualApp/lib/src/main/jni/HookZz/src/zzdefs.h index 7135936fe..9630b0f89 100644 --- a/VirtualApp/lib/src/main/jni/HookZz/src/zzdefs.h +++ b/VirtualApp/lib/src/main/jni/HookZz/src/zzdefs.h @@ -38,4 +38,6 @@ #define ZZ_INT26_MASK 0x03ffffff #define ZZ_INT28_MASK 0x0fffffff -#define THUMB_FUNCTION_ADDRESS(target_addr) (void *)((unsigned long)target_addr & ~(unsigned long)1) \ No newline at end of file +#define THUMB_FUNCTION_ADDRESS(target_addr) (void *)((unsigned long)target_addr & ~(unsigned long)1) +#define INSTRUCTION_IS_THUMB(insn_addr) ((insn_addr & 0x1) == 0x1) +#define ALIGN_4(target_addr) ((unsigned long)target_addr & ~(unsigned long)3) \ No newline at end of file diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/zzdeps/darwin/macho-utils-darwin.c b/VirtualApp/lib/src/main/jni/HookZz/src/zzdeps/darwin/macho-utils-darwin.c index e1c25d7aa..1ab97a980 100644 --- a/VirtualApp/lib/src/main/jni/HookZz/src/zzdeps/darwin/macho-utils-darwin.c +++ b/VirtualApp/lib/src/main/jni/HookZz/src/zzdeps/darwin/macho-utils-darwin.c @@ -55,8 +55,7 @@ zpointer zz_macho_get_dyld_load_address_via_task(task_t task) { KR_ERROR(kr); return 0; } - struct dyld_all_image_infos *allImageInfos = - (struct dyld_all_image_infos *)infoData.all_image_info_addr; + struct dyld_all_image_infos *allImageInfos = (struct dyld_all_image_infos *)infoData.all_image_info_addr; allImageInfos = (struct dyld_all_image_infos *)malloc(sizeof(struct dyld_all_image_infos)); if (zz_vm_read_data_via_task(task, infoData.all_image_info_addr, allImageInfos, sizeof(struct dyld_all_image_infos))) { @@ -76,14 +75,14 @@ task_t zz_darwin_get_task_via_pid(int pid) { return t; } -struct segment_command_64 *zz_macho_get_segment_64_via_name(struct mach_header_64 *header, - char *segment_name) { +struct segment_command_64 *zz_macho_get_segment_64_via_name(struct mach_header_64 *header, char *segment_name) { struct load_command *load_cmd; struct segment_command_64 *seg_cmd_64; struct section_64 *sect_64; load_cmd = (zpointer)header + sizeof(struct mach_header_64); - for (zsize i = 0; i < header->ncmds; i++, load_cmd = (zpointer)load_cmd + load_cmd->cmdsize) { + zsize i; + for (i = 0; i < header->ncmds; i++, load_cmd = (zpointer)load_cmd + load_cmd->cmdsize) { if (load_cmd->cmd == LC_SEGMENT_64) { seg_cmd_64 = (struct segment_command_64 *)load_cmd; if (!strcmp(seg_cmd_64->segname, segment_name)) { @@ -94,20 +93,19 @@ struct segment_command_64 *zz_macho_get_segment_64_via_name(struct mach_header_6 return NULL; } -struct section_64 *zz_macho_get_section_64_via_name(struct mach_header_64 *header, - char *sect_name) { +struct section_64 *zz_macho_get_section_64_via_name(struct mach_header_64 *header, char *sect_name) { struct load_command *load_cmd; struct segment_command_64 *seg_cmd_64; struct section_64 *sect_64; load_cmd = (zpointer)header + sizeof(struct mach_header_64); - for (zsize i = 0; i < header->ncmds; i++, load_cmd = (zpointer)load_cmd + load_cmd->cmdsize) { + zsize i; + zsize j; + for (i = 0; i < header->ncmds; i++, load_cmd = (zpointer)load_cmd + load_cmd->cmdsize) { if (load_cmd->cmd == LC_SEGMENT_64) { seg_cmd_64 = (struct segment_command_64 *)load_cmd; - sect_64 = - (struct section_64 *)((zpointer)seg_cmd_64 + sizeof(struct segment_command_64)); - for (zsize j = 0; j < seg_cmd_64->nsects; - j++, sect_64 = (zpointer)sect_64 + sizeof(struct section_64)) { + sect_64 = (struct section_64 *)((zpointer)seg_cmd_64 + sizeof(struct segment_command_64)); + for (j = 0; j < seg_cmd_64->nsects; j++, sect_64 = (zpointer)sect_64 + sizeof(struct section_64)) { if (!strcmp(sect_64->sectname, sect_name)) { return sect_64; } @@ -121,9 +119,10 @@ struct load_command *zz_macho_get_load_command_via_cmd(struct mach_header_64 *he struct load_command *load_cmd; struct segment_command_64 *seg_cmd_64; struct section_64 *sect_64; + zsize i; load_cmd = (zpointer)header + sizeof(struct mach_header_64); - for (zsize i = 0; i < header->ncmds; i++, load_cmd = (zpointer)load_cmd + load_cmd->cmdsize) { + for (i = 0; i < header->ncmds; i++, load_cmd = (zpointer)load_cmd + load_cmd->cmdsize) { if (load_cmd->cmd == cmd) { return load_cmd; } @@ -139,13 +138,13 @@ zpointer zz_macho_get_symbol_via_name(struct mach_header_64 *header, const char zz_macho_get_segment_64_via_name((struct mach_header_64 *)header, (char *)"__LINKEDIT"); zsize slide = (zaddr)header - (zaddr)seg_cmd_64->vmaddr; zsize linkEditBase = seg_cmd_64_linkedit->vmaddr - seg_cmd_64_linkedit->fileoff + slide; - struct symtab_command *symtab = - (struct symtab_command *)zz_macho_get_load_command_via_cmd(header, LC_SYMTAB); + struct symtab_command *symtab = (struct symtab_command *)zz_macho_get_load_command_via_cmd(header, LC_SYMTAB); char *sym_str_table = (char *)linkEditBase + symtab->stroff; struct nlist_64 *sym_table = (struct nlist_64 *)(linkEditBase + symtab->symoff); - for (int i = 0; i < symtab->nsyms; i++) { + int i; + for (i = 0; i < symtab->nsyms; i++) { if (sym_table[i].n_value && !strcmp(name, &sym_str_table[sym_table[i].n_un.n_strx])) { return (void *)(uint64_t)(sym_table[i].n_value + slide); } @@ -158,9 +157,10 @@ zpointer zz_macho_get_section_64_address_via_name(struct mach_header_64 *header, struct segment_command_64 *seg_cmd_64; struct section_64 *sect_64; zsize slide, linkEditBase; + zsize i, j; load_cmd = (zpointer)header + sizeof(struct mach_header_64); - for (zsize i = 0; i < header->ncmds; i++, load_cmd = (zpointer)load_cmd + load_cmd->cmdsize) { + for (i = 0; i < header->ncmds; i++, load_cmd = (zpointer)load_cmd + load_cmd->cmdsize) { if (load_cmd->cmd == LC_SEGMENT_64) { seg_cmd_64 = (struct segment_command_64 *)load_cmd; if ((seg_cmd_64->fileoff == 0) && (seg_cmd_64->filesize != 0)) { @@ -169,10 +169,8 @@ zpointer zz_macho_get_section_64_address_via_name(struct mach_header_64 *header, if (strcmp(seg_cmd_64->segname, "__LINKEDIT") == 0) { linkEditBase = seg_cmd_64->vmaddr - seg_cmd_64->fileoff + slide; } - sect_64 = - (struct section_64 *)((zpointer)seg_cmd_64 + sizeof(struct segment_command_64)); - for (zsize j = 0; j < seg_cmd_64->nsects; - j++, sect_64 = (zpointer)sect_64 + sizeof(struct section_64)) { + sect_64 = (struct section_64 *)((zpointer)seg_cmd_64 + sizeof(struct segment_command_64)); + for (j = 0; j < seg_cmd_64->nsects; j++, sect_64 = (zpointer)sect_64 + sizeof(struct section_64)) { if (!strcmp(sect_64->sectname, sect_name)) { return (zpointer)(sect_64->addr + slide); } diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/zzdeps/darwin/memory-utils-darwin.c b/VirtualApp/lib/src/main/jni/HookZz/src/zzdeps/darwin/memory-utils-darwin.c index 75806fa4d..4ac4cbbba 100644 --- a/VirtualApp/lib/src/main/jni/HookZz/src/zzdeps/darwin/memory-utils-darwin.c +++ b/VirtualApp/lib/src/main/jni/HookZz/src/zzdeps/darwin/memory-utils-darwin.c @@ -332,8 +332,8 @@ zpointer zz_vm_search_code_cave(zaddr address, zsize range_size, zsize size) { MemoryLayout *mlayout = zz_vm_get_memory_layout_via_task(mach_task_self()); - for (int i = 0; i < mlayout->size; i++) { - + int i; + for (i = 0; i < mlayout->size; i++) { if (mlayout->mem[i].flags == (1 << 0 | 1 << 2)) { search_start = (zaddr)mlayout->mem[i].start; search_end = (zaddr)mlayout->mem[i].end; diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/zzdeps/linux/memory-utils-linux.c b/VirtualApp/lib/src/main/jni/HookZz/src/zzdeps/linux/memory-utils-linux.c index 9c5c60e2b..6ad056a23 100644 --- a/VirtualApp/lib/src/main/jni/HookZz/src/zzdeps/linux/memory-utils-linux.c +++ b/VirtualApp/lib/src/main/jni/HookZz/src/zzdeps/linux/memory-utils-linux.c @@ -80,8 +80,8 @@ zpointer zz_linux_vm_search_code_cave(zaddr address, zsize range_size, zsize siz MemoryLayout *mlayout = zz_linux_vm_get_memory_layout_via_pid(-1); - for (int i = 0; i < mlayout->size; i++) { - + int i; + for (i = 0; i < mlayout->size; i++) { if (mlayout->mem[i].flags == (1 << 0 | 1 << 2)) { search_start = (zaddr)mlayout->mem[i].start; search_end = (zaddr)mlayout->mem[i].end; diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/zzdeps/posix/thread-utils-posix.c b/VirtualApp/lib/src/main/jni/HookZz/src/zzdeps/posix/thread-utils-posix.c index 04c048eaa..151b22d62 100644 --- a/VirtualApp/lib/src/main/jni/HookZz/src/zzdeps/posix/thread-utils-posix.c +++ b/VirtualApp/lib/src/main/jni/HookZz/src/zzdeps/posix/thread-utils-posix.c @@ -35,8 +35,8 @@ zbool zz_posix_thread_add_thread_local_key(ThreadLocalKeyList *keylist, ThreadLo return FALSE; if (keylist->size >= keylist->capacity) { - ThreadLocalKey **keys_tmp = (ThreadLocalKey **)realloc( - keylist->keys, sizeof(ThreadLocalKey *) * keylist->capacity * 2); + ThreadLocalKey **keys_tmp = + (ThreadLocalKey **)realloc(keylist->keys, sizeof(ThreadLocalKey *) * keylist->capacity * 2); if (!keys_tmp) return FALSE; keylist->keys = keys_tmp; @@ -65,9 +65,11 @@ zpointer zz_posix_thread_new_thread_local_key_ptr() { zpointer zz_posix_thread_get_current_thread_data(zpointer key_ptr) { ThreadLocalKeyList *g_keys = g_thread_local_key_list; + zsize i; + if (!key_ptr) return NULL; - for (zsize i = 0; i < g_keys->size; i++) { + for (i = 0; i < g_keys->size; i++) { if (g_keys->keys[i] == key_ptr) return (zpointer)pthread_getspecific(g_keys->keys[i]->key); } @@ -76,8 +78,9 @@ zpointer zz_posix_thread_get_current_thread_data(zpointer key_ptr) { zbool zz_posix_thread_set_current_thread_data(zpointer key_ptr, zpointer data) { ThreadLocalKeyList *g_keys = g_thread_local_key_list; + zsize i; - for (zsize i = 0; i < g_keys->size; i++) { + for (i = 0; i < g_keys->size; i++) { if (g_keys->keys[i] == key_ptr) return pthread_setspecific(g_keys->keys[i]->key, data); } diff --git a/VirtualApp/lib/src/main/jni/HookZz/src/zzinfo.h b/VirtualApp/lib/src/main/jni/HookZz/src/zzinfo.h index 2b8a883d8..db9d37f17 100644 --- a/VirtualApp/lib/src/main/jni/HookZz/src/zzinfo.h +++ b/VirtualApp/lib/src/main/jni/HookZz/src/zzinfo.h @@ -27,20 +27,18 @@ typedef struct _ZzInfo { zbool g_enable_debug_flag; -// LOGFUNC g_log_func; } ZzInfo; ZzInfo *ZzInfoObtain(void); zbool ZzIsEnableDebugMode(); -#if TARGET_OS_IPHONE -#include -void NSLog(CFStringRef format, ...); -#define ZzInfoLog(fmt, ...) \ - { NSLog(CFSTR(fmt), ##__VA_ARGS__); } -#elif defined(__ANDROID__) +#if defined(__ANDROID__) #include #define ZzInfoLog(fmt, ...) \ { __android_log_print(ANDROID_LOG_INFO, "zzinfo", fmt, __VA_ARGS__); } +#else +#define ZzInfoLog(fmt, ...) \ + { Xinfo(fmt, __VA_ARGS__); } #endif + #endif \ No newline at end of file diff --git a/VirtualApp/lib/src/main/jni/HookZz/tests/arm-insn-fix/makefile b/VirtualApp/lib/src/main/jni/HookZz/tests/arm-insn-fix/makefile new file mode 100644 index 000000000..a4a8203f0 --- /dev/null +++ b/VirtualApp/lib/src/main/jni/HookZz/tests/arm-insn-fix/makefile @@ -0,0 +1,19 @@ +NO_COLOR=\x1b[0m +OK_COLOR=\x1b[32;01m +ERROR_COLOR=\x1b[31;01m +WARN_COLOR=\x1b[33;01m + + +HOOKZZ_INCLUDE_DIR := -I$(abspath ../../include) -I$(abspath ../../src) +HOOKZZ_LIB_DIR := -L$(abspath ../../build/ios-armv7) + +ZZ_GCC_TEST := $(shell xcrun --sdk iphoneos --find clang) -isysroot $(shell xcrun --sdk iphoneos --show-sdk-path) -arch armv7 -O0 -g + +# -undefined dynamic_lookup +test: + @$(ZZ_GCC_TEST) $(HOOKZZ_INCLUDE_DIR) -c test_insn_fix.c -o test_insn_fix.o + @$(ZZ_GCC_TEST) -dynamiclib $(HOOKZZ_LIB_DIR) -lhookzz.static test_insn_fix.o -o test_insn_fix.dylib + @echo "$(OK_COLOR)build [test_insn_fix.dylib] success for armv7! $(NO_COLOR)" +clean: + rm -rf test_insn_fix.o + rm -rf test_insn_fix.dylib diff --git a/VirtualApp/lib/src/main/jni/HookZz/tests/arm-insn-fix/test_insn_fix.c b/VirtualApp/lib/src/main/jni/HookZz/tests/arm-insn-fix/test_insn_fix.c new file mode 100644 index 000000000..26069eb60 --- /dev/null +++ b/VirtualApp/lib/src/main/jni/HookZz/tests/arm-insn-fix/test_insn_fix.c @@ -0,0 +1,106 @@ +#include "hookzz.h" +#include +#include + +static void thumb_insn_need_fix() { + __asm__ volatile(".code 16\n" + + "add r0, pc\n" + + "ldr r0, [pc, #8]\n" + "ldr.W r0, [pc, #8]\n" + + "adr r0, #8\n" + "adr.W r0, #8\n" + "adr.W r0, #-8\n" + + "beq #8\n" + "b #8\n" + "beq.W #8\n" + "b.W #8\n" + + "bl #8\n" + "blx #8\n" + "nop"); +} + +#include "platforms/backend-arm64/interceptor-arm64.h" +#include + +#if 1 +__attribute__((constructor)) void test_insn_fix_thumb() { + + ZzInterceptorBackend *backend = (ZzInterceptorBackend *)malloc(sizeof(ZzInterceptorBackend)); + zbyte temp_code_slice_data[256] = {0}; + + zz_arm_writer_init(&backend->arm_writer, NULL); + zz_arm_relocator_init(&backend->arm_relocator, NULL, &backend->arm_writer); + zz_thumb_writer_init(&backend->thumb_writer, NULL); + zz_thumb_relocator_init(&backend->thumb_relocator, NULL, &backend->thumb_writer); + + ZzThumbRelocator *thumb_relocator; + ZzThumbWriter *thumb_writer; + thumb_relocator = &backend->thumb_relocator; + thumb_writer = &backend->thumb_writer; + + zz_thumb_writer_reset(thumb_writer, temp_code_slice_data); + + zz_thumb_relocator_reset(thumb_relocator, (zpointer)((zaddr)thumb_insn_need_fix & ~(zaddr)1), thumb_writer); + zsize tmp_relocator_insn_size = 0; + + do { + zz_thumb_relocator_read_one(thumb_relocator, NULL); + zz_thumb_relocator_write_one(thumb_relocator); + tmp_relocator_insn_size = thumb_relocator->input_cur - thumb_relocator->input_start; + } while (tmp_relocator_insn_size < 36); +} +#endif + +#if 0 +__attribute__((__naked__)) void arm_insn_need_fix() { + __asm__ volatile(".arm\n" + "add r0, pc, r0\n" + + "ldr r0, [pc, #8]\n" + + "adr r0, #8\n" + "adr r0, #-8\n" + + "beq #8\n" + "b #8\n" + + "bl #8\n" + "blx #8\n" + "nop"); +} + +#include "platforms/backend-arm/interceptor-arm.h" +#include + +__attribute__((constructor)) void test_insn_fix_arm() { + + ZzInterceptorBackend *backend = (ZzInterceptorBackend *)malloc(sizeof(ZzInterceptorBackend)); + zbyte temp_code_slice_data[256] = {0}; + + zz_arm_writer_init(&backend->arm_writer, NULL); + zz_arm_relocator_init(&backend->arm_relocator, NULL, &backend->arm_writer); + zz_thumb_writer_init(&backend->thumb_writer, NULL); + zz_thumb_relocator_init(&backend->thumb_relocator, NULL, &backend->thumb_writer); + + ZzArmRelocator *arm_relocator; + ZzArmWriter *arm_writer; + arm_relocator = &backend->arm_relocator; + arm_writer = &backend->arm_writer; + + zz_arm_writer_reset(arm_writer, temp_code_slice_data); + + zz_arm_relocator_reset(arm_relocator, (zpointer)((zaddr)arm_insn_need_fix & ~(zaddr)1), arm_writer); + zsize tmp_relocator_insn_size = 0; + + do { + zz_arm_relocator_read_one(arm_relocator, NULL); + zz_arm_relocator_write_one(arm_relocator); + tmp_relocator_insn_size = arm_relocator->input_cur - arm_relocator->input_start; + } while (tmp_relocator_insn_size < 36); +} +#endif \ No newline at end of file diff --git a/VirtualApp/lib/src/main/jni/HookZz/tests/arm-ios/makefile b/VirtualApp/lib/src/main/jni/HookZz/tests/arm-ios/makefile index 381c389b5..ed1ac5305 100644 --- a/VirtualApp/lib/src/main/jni/HookZz/tests/arm-ios/makefile +++ b/VirtualApp/lib/src/main/jni/HookZz/tests/arm-ios/makefile @@ -27,6 +27,12 @@ test: @$(ZZ_GCC_TEST) -dynamiclib -Wl,-U,_func -framework Foundation -L$(HOOKZZ_LIB_DIR) -lhookzz.static test_hook_printf.o -o $(HOOKZZ_LIB_DIR)/test_hook_printf.dylib @echo "$(OK_COLOR)build [test_hook_printf.dylib] success for armv7-ios! $(NO_COLOR)" + + @$(ZZ_GCC_TEST) -I$(HOOKZZ_INCLUDE_DIR) -c test_hook_freeaddr.c -o test_hook_freeaddr.o + @$(ZZ_GCC_TEST) -dynamiclib -Wl,-U,_func -framework Foundation -L$(HOOKZZ_LIB_DIR) -lhookzz.static test_hook_freeaddr.o -o $(HOOKZZ_LIB_DIR)/test_hook_freeaddr.dylib + @echo "$(OK_COLOR)build [test_hook_freeaddr.dylib] success for armv7-ios! $(NO_COLOR)" + + @echo "$(OK_COLOR)build [test] success for armv7-ios-hookzz! $(NO_COLOR)" clean: diff --git a/VirtualApp/lib/src/main/jni/HookZz/tests/arm-ios/test_hook_freeaddr.c b/VirtualApp/lib/src/main/jni/HookZz/tests/arm-ios/test_hook_freeaddr.c new file mode 100644 index 000000000..e9a16ea1a --- /dev/null +++ b/VirtualApp/lib/src/main/jni/HookZz/tests/arm-ios/test_hook_freeaddr.c @@ -0,0 +1,70 @@ +/** + * Copyright 2017 jmpews + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "hookzz.h" +#include +#include +#include + +#include +#include +#include + +void (*orig_freeaddrinfo)(struct addrinfo *ai); +void fake_freeaddrinfo(struct addrinfo *ai) { orig_freeaddrinfo(ai); } + +__attribute__((constructor)) void test_hook_freeaddrinfo() { + ZzEnableDebugMode(); + ZzHook((void *)freeaddrinfo, (void *)fake_freeaddrinfo, &orig_freeaddrinfo, NULL, NULL, FALSE); + + int sockfd; + struct addrinfo hints, *servinfo, *p; + int rv; + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; // use AF_INET6 to force IPv6 + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; // use my IP address + + if ((rv = getaddrinfo(NULL, "3490", &hints, &servinfo)) != 0) { + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); + exit(1); + } + + // loop through all the results and bind to the first we can + for (p = servinfo; p != NULL; p = p->ai_next) { + if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) { + perror("socket"); + continue; + } + + if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) { + close(sockfd); + perror("bind"); + continue; + } + + break; // if we get here, we must have connected successfully + } + + if (p == NULL) { + // looped off the end of the list with no successful bind + fprintf(stderr, "failed to bind socket\n"); + exit(2); + } + + freeaddrinfo(servinfo); // all done with this structure +} diff --git a/VirtualApp/lib/src/main/jni/HookZz/tests/arm64-insn-fix/makefile b/VirtualApp/lib/src/main/jni/HookZz/tests/arm64-insn-fix/makefile new file mode 100644 index 000000000..5974da54e --- /dev/null +++ b/VirtualApp/lib/src/main/jni/HookZz/tests/arm64-insn-fix/makefile @@ -0,0 +1,19 @@ +NO_COLOR=\x1b[0m +OK_COLOR=\x1b[32;01m +ERROR_COLOR=\x1b[31;01m +WARN_COLOR=\x1b[33;01m + + +HOOKZZ_INCLUDE_DIR := -I$(abspath ../../include) -I$(abspath ../../src) +HOOKZZ_LIB_DIR := -L$(abspath ../../build/ios-arm64) + +ZZ_GCC_TEST := $(shell xcrun --sdk iphoneos --find clang) -isysroot $(shell xcrun --sdk iphoneos --show-sdk-path) -arch arm64 -O0 -g + +# -undefined dynamic_lookup +test: + @$(ZZ_GCC_TEST) $(HOOKZZ_INCLUDE_DIR) -c test_insn_fix.c -o test_insn_fix.o + @$(ZZ_GCC_TEST) -dynamiclib $(HOOKZZ_LIB_DIR) -lhookzz.static test_insn_fix.o -o test_insn_fix.dylib + @echo "$(OK_COLOR)build [test_insn_fix.dylib] success for arm64! $(NO_COLOR)" +clean: + rm -rf test_insn_fix.o + rm -rf test_insn_fix.dylib diff --git a/VirtualApp/lib/src/main/jni/HookZz/tests/arm64-insn-fix/test_insn_fix.c b/VirtualApp/lib/src/main/jni/HookZz/tests/arm64-insn-fix/test_insn_fix.c new file mode 100644 index 000000000..e2e793d9e --- /dev/null +++ b/VirtualApp/lib/src/main/jni/HookZz/tests/arm64-insn-fix/test_insn_fix.c @@ -0,0 +1,40 @@ +#include "hookzz.h" +#include +#include + +static void arm64_insn_need_fix() { + __asm__ volatile("bl #40\n" + "nop"); +} + +#include "platforms/backend-arm64/interceptor-arm64.h" +#include + +#if 1 +__attribute__((constructor)) void test_insn_fix_arm64() { + + ZzInterceptorBackend *backend = (ZzInterceptorBackend *)malloc(sizeof(ZzInterceptorBackend)); + zbyte temp_code_slice_data[256] = {0}; + + zz_arm64_writer_init(&backend->arm64_writer, NULL); + zz_arm64_relocator_init(&backend->arm64_relocator, NULL, &backend->arm64_writer); + zz_arm64_writer_init(&backend->arm64_writer, NULL); + zz_arm64_relocator_init(&backend->arm64_relocator, NULL, &backend->arm64_writer); + + ZzArm64Relocator *arm64_relocator; + ZzArm64Writer *arm64_writer; + arm64_relocator = &backend->arm64_relocator; + arm64_writer = &backend->arm64_writer; + + zz_arm64_writer_reset(arm64_writer, temp_code_slice_data); + + zz_arm64_relocator_reset(arm64_relocator, (zpointer)((zaddr)arm64_insn_need_fix & ~(zaddr)1), arm64_writer); + zsize tmp_relocator_insn_size = 0; + + do { + zz_arm64_relocator_read_one(arm64_relocator, NULL); + zz_arm64_relocator_write_one(arm64_relocator); + tmp_relocator_insn_size = arm64_relocator->input_cur - arm64_relocator->input_start; + } while (tmp_relocator_insn_size < 36); +} +#endif diff --git a/VirtualApp/lib/src/main/jni/Jni/Helper.h b/VirtualApp/lib/src/main/jni/Jni/Helper.h index 727e10a71..398fd7b91 100644 --- a/VirtualApp/lib/src/main/jni/Jni/Helper.h +++ b/VirtualApp/lib/src/main/jni/Jni/Helper.h @@ -5,9 +5,27 @@ #ifndef NDK_LOG_H #define NDK_LOG_H - -#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0]))) +#include #define NATIVE_METHOD(func_ptr, func_name, signature) { func_name, signature, reinterpret_cast(func_ptr) } +class ScopeUtfString { +public: + ScopeUtfString(jstring j_str) : _j_str(j_str), + _c_str(facebook::jni::Environment::current()->GetStringUTFChars(j_str, NULL)) { + } + + const char *c_str() { + return _c_str; + } + + ~ScopeUtfString() { + facebook::jni::Environment::current()->ReleaseStringUTFChars(_j_str, _c_str); + } + +private: + jstring _j_str; + const char *_c_str; +}; + #endif //NDK_LOG_H diff --git a/VirtualApp/lib/src/main/jni/Jni/VAJni.cpp b/VirtualApp/lib/src/main/jni/Jni/VAJni.cpp index 4bde8bd76..aa0db1170 100644 --- a/VirtualApp/lib/src/main/jni/Jni/VAJni.cpp +++ b/VirtualApp/lib/src/main/jni/Jni/VAJni.cpp @@ -10,61 +10,48 @@ using namespace facebook::jni; static void jni_nativeLaunchEngine(alias_ref clazz, JArrayClass javaMethods, - jstring packageName, - jboolean isArt, jint apiLevel, jint cameraMethodType) { + jstring packageName, + jboolean isArt, jint apiLevel, jint cameraMethodType) { hookAndroidVM(javaMethods, packageName, isArt, apiLevel, cameraMethodType); } static void jni_nativeEnableIORedirect(alias_ref, jstring selfSoPath, jint apiLevel, - jint preview_api_level) { - JNIEnv *env = Environment::current(); - const char *so_path = env->GetStringUTFChars(selfSoPath, NULL); - IOUniformer::startUniformer(so_path, apiLevel, preview_api_level); - env->ReleaseStringUTFChars(selfSoPath, so_path); + jint preview_api_level) { + ScopeUtfString so_path(selfSoPath); + IOUniformer::startUniformer(so_path.c_str(), apiLevel, preview_api_level); } static void jni_nativeIOWhitelist(alias_ref jclazz, jstring _path) { - JNIEnv *env = Environment::current(); - const char *path = Environment::current()->GetStringUTFChars(_path, NULL); - IOUniformer::whitelist(path); - env->ReleaseStringUTFChars(_path, path); + ScopeUtfString path(_path); + IOUniformer::whitelist(path.c_str()); } static void jni_nativeIOForbid(alias_ref jclazz, jstring _path) { - JNIEnv *env = Environment::current(); - const char *path = env->GetStringUTFChars(_path, NULL); - IOUniformer::forbid(path); - env->ReleaseStringUTFChars(_path, path); + ScopeUtfString path(_path); + IOUniformer::forbid(path.c_str()); } static void jni_nativeIORedirect(alias_ref jclazz, jstring origPath, jstring newPath) { - JNIEnv *env = Environment::current(); - const char *orig_path = env->GetStringUTFChars(origPath, NULL); - const char *new_path = env->GetStringUTFChars(newPath, NULL); - IOUniformer::redirect(orig_path, new_path); - env->ReleaseStringUTFChars(origPath, orig_path); - env->ReleaseStringUTFChars(newPath, new_path); + ScopeUtfString orig_path(origPath); + ScopeUtfString new_path(newPath); + IOUniformer::redirect(orig_path.c_str(), new_path.c_str()); } static jstring jni_nativeGetRedirectedPath(alias_ref jclazz, jstring origPath) { - JNIEnv *env = Environment::current(); - const char *orig_path = env->GetStringUTFChars(origPath, NULL); - const char *redirected_path = IOUniformer::query(orig_path); - env->ReleaseStringUTFChars(origPath, orig_path); + ScopeUtfString orig_path(origPath); + const char *redirected_path = IOUniformer::query(orig_path.c_str()); if (redirected_path != NULL) { - return env->NewStringUTF(redirected_path); + return Environment::current()->NewStringUTF(redirected_path); } return NULL; } static jstring jni_nativeReverseRedirectedPath(alias_ref jclazz, jstring redirectedPath) { - JNIEnv *env = Environment::current(); - const char *redirected_path = env->GetStringUTFChars(redirectedPath, NULL); - const char *orig_path = IOUniformer::reverse(redirected_path); - env->ReleaseStringUTFChars(redirectedPath, redirected_path); + ScopeUtfString redirected_path(redirectedPath); + const char *orig_path = IOUniformer::reverse(redirected_path.c_str()); return Environment::current()->NewStringUTF(orig_path); } @@ -76,14 +63,22 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { return initialize(vm, [] { nativeEngineClass = findClassStatic("com/lody/virtual/client/NativeEngine"); nativeEngineClass->registerNatives({ - makeNativeMethod("nativeEnableIORedirect", jni_nativeEnableIORedirect), - makeNativeMethod("nativeIOWhitelist", jni_nativeIOWhitelist), - makeNativeMethod("nativeIOForbid", jni_nativeIOForbid), - makeNativeMethod("nativeIORedirect", jni_nativeIORedirect), - makeNativeMethod("nativeGetRedirectedPath", jni_nativeGetRedirectedPath), - makeNativeMethod("nativeReverseRedirectedPath", jni_nativeReverseRedirectedPath), - makeNativeMethod("nativeLaunchEngine", jni_nativeLaunchEngine), - }); + makeNativeMethod("nativeEnableIORedirect", + jni_nativeEnableIORedirect), + makeNativeMethod("nativeIOWhitelist", + jni_nativeIOWhitelist), + makeNativeMethod("nativeIOForbid", + jni_nativeIOForbid), + makeNativeMethod("nativeIORedirect", + jni_nativeIORedirect), + makeNativeMethod("nativeGetRedirectedPath", + jni_nativeGetRedirectedPath), + makeNativeMethod("nativeReverseRedirectedPath", + jni_nativeReverseRedirectedPath), + makeNativeMethod("nativeLaunchEngine", + jni_nativeLaunchEngine), + } + ); }); } diff --git a/VirtualApp/lib/src/main/jni/Substrate/Buffer.hpp b/VirtualApp/lib/src/main/jni/Substrate/Buffer.hpp new file mode 100755 index 000000000..34d9df32e --- /dev/null +++ b/VirtualApp/lib/src/main/jni/Substrate/Buffer.hpp @@ -0,0 +1,38 @@ +/* Cydia Substrate - Powerful Code Insertion Platform + * Copyright (C) 2008-2011 Jay Freeman (saurik) +*/ + +/* GNU Lesser General Public License, Version 3 {{{ */ +/* + * Substrate is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Substrate is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Substrate. If not, see . +**/ +/* }}} */ + +#ifndef SUBSTRATE_BUFFER_HPP +#define SUBSTRATE_BUFFER_HPP + +#include + +template +_disused static _finline void MSWrite(uint8_t *&buffer, Type_ value) { + *reinterpret_cast(buffer) = value; + buffer += sizeof(Type_); +} + +_disused static _finline void MSWrite(uint8_t *&buffer, uint8_t *data, size_t size) { + memcpy(buffer, data, size); + buffer += size; +} + +#endif//SUBSTRATE_BUFFER_HPP diff --git a/VirtualApp/lib/src/main/jni/Substrate/CydiaSubstrate.h b/VirtualApp/lib/src/main/jni/Substrate/CydiaSubstrate.h new file mode 100755 index 000000000..bb806aa9f --- /dev/null +++ b/VirtualApp/lib/src/main/jni/Substrate/CydiaSubstrate.h @@ -0,0 +1,152 @@ +/* Cydia Substrate - Powerful Code Insertion Platform + * Copyright (C) 2008-2011 Jay Freeman (saurik) +*/ + +/* GNU Lesser General Public License, Version 3 {{{ */ +/* + * Substrate is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Substrate is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Substrate. If not, see . +**/ +/* }}} */ + +#ifndef SUBSTRATE_H_ +#define SUBSTRATE_H_ + +#ifdef __APPLE__ +#ifdef __cplusplus +extern "C" { +#endif +#include +#ifdef __cplusplus +} +#endif + +#include +#include +#endif + +#include +#include + +#define _finline \ + inline __attribute__((__always_inline__)) +#define _disused \ + __attribute__((__unused__)) + +#define _extern \ + extern "C" __attribute__((__visibility__("default"))) + +#ifdef __cplusplus +#define _default(value) = value +#else +#define _default(value) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +bool MSHookProcess(pid_t pid, const char *library); + +typedef const void *MSImageRef; + +MSImageRef MSGetImageByName(const char *file); +void *MSFindSymbol(MSImageRef image, const char *name); + +void MSHookFunction(void *symbol, void *replace, void **result); + +#ifdef __APPLE__ +#ifdef __arm__ +__attribute__((__deprecated__)) +IMP MSHookMessage(Class _class, SEL sel, IMP imp, const char *prefix _default(NULL)); +#endif +void MSHookMessageEx(Class _class, SEL sel, IMP imp, IMP *result); +#endif + +#ifdef SubstrateInternal +typedef void *SubstrateAllocatorRef; +typedef struct __SubstrateProcess *SubstrateProcessRef; +typedef struct __SubstrateMemory *SubstrateMemoryRef; + +SubstrateProcessRef SubstrateProcessCreate(SubstrateAllocatorRef allocator, pid_t pid); +void SubstrateProcessRelease(SubstrateProcessRef process); + +SubstrateMemoryRef SubstrateMemoryCreate(SubstrateAllocatorRef allocator, SubstrateProcessRef process, void *data, size_t size); +void SubstrateMemoryRelease(SubstrateMemoryRef memory); +#endif + +#ifdef __cplusplus +} +#endif + +#ifdef __cplusplus + +#ifdef SubstrateInternal +struct SubstrateHookMemory { + SubstrateMemoryRef handle_; + + SubstrateHookMemory(SubstrateProcessRef process, void *data, size_t size) : + handle_(SubstrateMemoryCreate(NULL, NULL, data, size)) + { + } + + ~SubstrateHookMemory() { + if (handle_ != NULL) + SubstrateMemoryRelease(handle_); + } +}; +#endif + + +template +static inline void MSHookFunction(Type_ *symbol, Type_ *replace, Type_ **result) { + MSHookFunction( + reinterpret_cast(symbol), + reinterpret_cast(replace), + reinterpret_cast(result) + ); +} + +template +static inline void MSHookFunction(Type_ *symbol, Type_ *replace) { + return MSHookFunction(symbol, replace, reinterpret_cast(NULL)); +} + +template +static inline void MSHookSymbol(Type_ *&value, const char *name, MSImageRef image = NULL) { + value = reinterpret_cast(MSFindSymbol(image, name)); +} + +template +static inline void MSHookFunction(const char *name, Type_ *replace, Type_ **result = NULL) { + Type_ *symbol; + MSHookSymbol(symbol, name); + return MSHookFunction(symbol, replace, result); +} + +#endif + +#define MSHook(type, name, args...) \ + _disused static type (*_ ## name)(args); \ + static type $ ## name(args) + +#ifdef __cplusplus +#define MSHake(name) \ + &$ ## name, &_ ## name +#else +#define MSHake(name) \ + &$ ## name, (void **) &_ ## name +#endif + + +#endif//SUBSTRATE_H_ diff --git a/VirtualApp/lib/src/main/jni/Substrate/SubstrateARM.hpp b/VirtualApp/lib/src/main/jni/Substrate/SubstrateARM.hpp new file mode 100755 index 000000000..7dd313900 --- /dev/null +++ b/VirtualApp/lib/src/main/jni/Substrate/SubstrateARM.hpp @@ -0,0 +1,65 @@ +/* Cydia Substrate - Powerful Code Insertion Platform + * Copyright (C) 2008-2011 Jay Freeman (saurik) +*/ + +/* GNU Lesser General Public License, Version 3 {{{ */ +/* + * Substrate is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Substrate is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Substrate. If not, see . +**/ +/* }}} */ + +#ifndef SUBSTRATE_ARM_HPP +#define SUBSTRATE_ARM_HPP + +enum A$r { + A$r0, A$r1, A$r2, A$r3, + A$r4, A$r5, A$r6, A$r7, + A$r8, A$r9, A$r10, A$r11, + A$r12, A$r13, A$r14, A$r15, + A$sp = A$r13, + A$lr = A$r14, + A$pc = A$r15 +}; + +enum A$c { + A$eq, A$ne, A$cs, A$cc, + A$mi, A$pl, A$vs, A$vc, + A$hi, A$ls, A$ge, A$lt, + A$gt, A$le, A$al, + A$hs = A$cs, + A$lo = A$cc +}; + +#define A$mrs_rm_cpsr(rd) /* mrs rd, cpsr */ \ + (0xe10f0000 | ((rd) << 12)) +#define A$msr_cpsr_f_rm(rm) /* msr cpsr_f, rm */ \ + (0xe128f000 | (rm)) +#define A$ldr_rd_$rn_im$(rd, rn, im) /* ldr rd, [rn, #im] */ \ + (0xe5100000 | ((im) < 0 ? 0 : 1 << 23) | ((rn) << 16) | ((rd) << 12) | abs(im)) +#define A$str_rd_$rn_im$(rd, rn, im) /* sr rd, [rn, #im] */ \ + (0xe5000000 | ((im) < 0 ? 0 : 1 << 23) | ((rn) << 16) | ((rd) << 12) | abs(im)) +#define A$sub_rd_rn_$im(rd, rn, im) /* sub, rd, rn, #im */ \ + (0xe2400000 | ((rn) << 16) | ((rd) << 12) | (im & 0xff)) +#define A$blx_rm(rm) /* blx rm */ \ + (0xe12fff30 | (rm)) +#define A$mov_rd_rm(rd, rm) /* mov rd, rm */ \ + (0xe1a00000 | ((rd) << 12) | (rm)) +#define A$ldmia_sp$_$rs$(rs) /* ldmia sp!, {rs} */ \ + (0xe8b00000 | (A$sp << 16) | (rs)) +#define A$stmdb_sp$_$rs$(rs) /* stmdb sp!, {rs} */ \ + (0xe9200000 | (A$sp << 16) | (rs)) +#define A$stmia_sp$_$r0$ 0xe8ad0001 /* stmia sp!, {r0} */ +#define A$bx_r0 0xe12fff10 /* bx r0 */ + +#endif//SUBSTRATE_ARM_HPP diff --git a/VirtualApp/lib/src/main/jni/Substrate/SubstrateDebug.cpp b/VirtualApp/lib/src/main/jni/Substrate/SubstrateDebug.cpp new file mode 100755 index 000000000..2df6ef487 --- /dev/null +++ b/VirtualApp/lib/src/main/jni/Substrate/SubstrateDebug.cpp @@ -0,0 +1,96 @@ +/* Cydia Substrate - Powerful Code Insertion Platform + * Copyright (C) 2008-2011 Jay Freeman (saurik) +*/ + +/* GNU Lesser General Public License, Version 3 {{{ */ +/* + * Substrate is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Substrate is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Substrate. If not, see . +**/ +/* }}} */ + +#include "SubstrateHook.h" +#include "SubstrateDebug.hpp" + +#include +#include +#include + +_extern bool MSDebug; +bool MSDebug = false; + +static char _MSHexChar(uint8_t value) { + return value < 0x20 || value >= 0x80 ? '.' : value; +} + +#define HexWidth_ 16 +#define HexDepth_ 4 + +void MSLogHexEx(const void *vdata, size_t size, size_t stride, const char *mark) { + const uint8_t *data((const uint8_t *) vdata); + + size_t i(0), j; + + char d[256]; + size_t b(0); + d[0] = '\0'; + + while (i != size) { + if (i % HexWidth_ == 0) { + if (mark != NULL) + b += sprintf(d + b, "\n[%s] ", mark); + b += sprintf(d + b, "0x%.3zx:", i); + } + + b += sprintf(d + b, " "); + + for (size_t q(0); q != stride; ++q) + b += sprintf(d + b, "%.2x", data[i + stride - q - 1]); + + i += stride; + + for (size_t q(1); q != stride; ++q) + b += sprintf(d + b, " "); + + if (i % HexDepth_ == 0) + b += sprintf(d + b, " "); + + if (i % HexWidth_ == 0) { + b += sprintf(d + b, " "); + for (j = i - HexWidth_; j != i; ++j) + b += sprintf(d + b, "%c", _MSHexChar(data[j])); + + lprintf("%s", d); + b = 0; + d[0] = '\0'; + } + } + + if (i % HexWidth_ != 0) { + for (j = i % HexWidth_; j != HexWidth_; ++j) + b += sprintf(d + b, " "); + for (j = 0; j != (HexWidth_ - i % HexWidth_ + HexDepth_ - 1) / HexDepth_; ++j) + b += sprintf(d + b, " "); + b += sprintf(d + b, " "); + for (j = i / HexWidth_ * HexWidth_; j != i; ++j) + b += sprintf(d + b, "%c", _MSHexChar(data[j])); + + lprintf("%s", d); + b = 0; + d[0] = '\0'; + } +} + +void MSLogHex(const void *vdata, size_t size, const char *mark) { + return MSLogHexEx(vdata, size, 1, mark); +} diff --git a/VirtualApp/lib/src/main/jni/Substrate/SubstrateDebug.hpp b/VirtualApp/lib/src/main/jni/Substrate/SubstrateDebug.hpp new file mode 100755 index 000000000..9c554c851 --- /dev/null +++ b/VirtualApp/lib/src/main/jni/Substrate/SubstrateDebug.hpp @@ -0,0 +1,33 @@ +/* Cydia Substrate - Powerful Code Insertion Platform + * Copyright (C) 2008-2011 Jay Freeman (saurik) +*/ + +/* GNU Lesser General Public License, Version 3 {{{ */ +/* + * Substrate is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Substrate is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Substrate. If not, see . +**/ +/* }}} */ + +#ifndef SUBSTRATE_DEBUG_HPP +#define SUBSTRATE_DEBUG_HPP + +#include "SubstrateLog.hpp" +#define lprintf(format, ...) \ + MSLog(MSLogLevelNotice, format, ## __VA_ARGS__) + +extern "C" bool MSDebug; +void MSLogHexEx(const void *vdata, size_t size, size_t stride, const char *mark = 0); +void MSLogHex(const void *vdata, size_t size, const char *mark = 0); + +#endif//SUBSTRATE_DEBUG_HPP diff --git a/VirtualApp/lib/src/main/jni/Substrate/SubstrateHook.cpp b/VirtualApp/lib/src/main/jni/Substrate/SubstrateHook.cpp new file mode 100755 index 000000000..34f2a26dd --- /dev/null +++ b/VirtualApp/lib/src/main/jni/Substrate/SubstrateHook.cpp @@ -0,0 +1,934 @@ +/* Cydia Substrate - Powerful Code Insertion Platform + * Copyright (C) 2008-2011 Jay Freeman (saurik) +*/ + +/* GNU Lesser General Public License, Version 3 {{{ */ +/* + * Substrate is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Substrate is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Substrate. If not, see . +**/ +/* }}} */ + +#define SubstrateInternal +#include "CydiaSubstrate.h" + +#include + +#define _trace() do { \ + MSLog(MSLogLevelNotice, "_trace(%u)", __LINE__); \ +} while (false) + +#if defined(__i386__) || defined(__x86_64__) +#include "hde64.h" +#endif + +#include "SubstrateDebug.hpp" + +#include +#include +#include + +#ifdef __arm__ +/* WebCore (ARM) PC-Relative: +X 1 ldr r*,[pc,r*] != + 2 fldd d*,[pc,#*] +X 5 str r*,[pc,r*] != + 8 flds s*,[pc,#*] + 400 ldr r*,[pc,r*] == + 515 add r*, pc,r* == +X 4790 ldr r*,[pc,#*] */ + +// x=0; while IFS= read -r line; do if [[ ${#line} -ne 0 && $line == +([^\;]): ]]; then x=2; elif [[ $line == ' +'* && $x -ne 0 ]]; then ((--x)); echo "$x${line}"; fi; done WebCore.pc +// grep pc WebCore.pc | cut -c 40- | sed -Ee 's/^ldr *(ip|r[0-9]*),\[pc,\#0x[0-9a-f]*\].*/ ldr r*,[pc,#*]/;s/^add *r[0-9]*,pc,r[0-9]*.*/ add r*, pc,r*/;s/^(st|ld)r *r([0-9]*),\[pc,r([0-9]*)\].*/ \1r r\2,[pc,r\3]/;s/^fld(s|d) *(s|d)[0-9]*,\[pc,#0x[0-9a-f]*].*/fld\1 \2*,[pc,#*]/' | sort | uniq -c | sort -n + +#include "SubstrateARM.hpp" + +#define T$Label(l, r) \ + (((r) - (l)) * 2 - 4 + ((l) % 2 == 0 ? 0 : 2)) + +#define T$pop_$r0$ 0xbc01 // pop {r0} +#define T$b(im) /* b im */ \ + (0xde00 | (im & 0xff)) +#define T$blx(rm) /* blx rm */ \ + (0x4780 | (rm << 3)) +#define T$bx(rm) /* bx rm */ \ + (0x4700 | (rm << 3)) +#define T$nop /* nop */ \ + (0x46c0) + +#define T$add_rd_rm(rd, rm) /* add rd, rm */ \ + (0x4400 | (((rd) & 0x8) >> 3 << 7) | (((rm) & 0x8) >> 3 << 6) | (((rm) & 0x7) << 3) | ((rd) & 0x7)) +#define T$push_r(r) /* push r... */ \ + (0xb400 | (((r) & (1 << A$lr)) >> A$lr << 8) | ((r) & 0xff)) +#define T$pop_r(r) /* pop r... */ \ + (0xbc00 | (((r) & (1 << A$pc)) >> A$pc << 8) | ((r) & 0xff)) +#define T$mov_rd_rm(rd, rm) /* mov rd, rm */ \ + (0x4600 | (((rd) & 0x8) >> 3 << 7) | (((rm) & 0x8) >> 3 << 6) | (((rm) & 0x7) << 3) | ((rd) & 0x7)) +#define T$ldr_rd_$rn_im_4$(rd, rn, im) /* ldr rd, [rn, #im * 4] */ \ + (0x6800 | (((im) & 0x1f) << 6) | ((rn) << 3) | (rd)) +#define T$ldr_rd_$pc_im_4$(rd, im) /* ldr rd, [PC, #im * 4] */ \ + (0x4800 | ((rd) << 8) | ((im) & 0xff)) +#define T$cmp_rn_$im(rn, im) /* cmp rn, #im */ \ + (0x2000 | ((rn) << 8) | ((im) & 0xff)) +#define T$it$_cd(cd, ms) /* it, cd */ \ + (0xbf00 | ((cd) << 4) | (ms)) +#define T$cbz$_rn_$im(op,rn,im) /* cbz rn, #im */ \ + (0xb100 | ((op) << 11) | (((im) & 0x40) >> 6 << 9) | (((im) & 0x3e) >> 1 << 3) | (rn)) +#define T$b$_$im(cond,im) /* b #im */ \ + (cond == A$al ? 0xe000 | (((im) >> 1) & 0x7ff) : 0xd000 | ((cond) << 8) | (((im) >> 1) & 0xff)) + +#define T1$ldr_rt_$rn_im$(rt, rn, im) /* ldr rt, [rn, #im] */ \ + (0xf850 | ((im < 0 ? 0 : 1) << 7) | (rn)) +#define T2$ldr_rt_$rn_im$(rt, rn, im) /* ldr rt, [rn, #im] */ \ + (((rt) << 12) | abs(im)) + +#define T1$mrs_rd_apsr(rd) /* mrs rd, apsr */ \ + (0xf3ef) +#define T2$mrs_rd_apsr(rd) /* mrs rd, apsr */ \ + (0x8000 | ((rd) << 8)) + +#define T1$msr_apsr_nzcvqg_rn(rn) /* msr apsr, rn */ \ + (0xf380 | (rn)) +#define T2$msr_apsr_nzcvqg_rn(rn) /* msr apsr, rn */ \ + (0x8c00) +#define T$msr_apsr_nzcvqg_rn(rn) /* msr apsr, rn */ \ + (T2$msr_apsr_nzcvqg_rn(rn) << 16 | T1$msr_apsr_nzcvqg_rn(rn)) + +static inline bool A$pcrel$r(uint32_t ic) { + return (ic & 0x0c000000) == 0x04000000 && (ic & 0xf0000000) != 0xf0000000 && (ic & 0x000f0000) == 0x000f0000; +} + +static inline bool T$32bit$i(uint16_t ic) { + return ((ic & 0xe000) == 0xe000 && (ic & 0x1800) != 0x0000); +} + +static inline bool T$pcrel$cbz(uint16_t ic) { + return (ic & 0xf500) == 0xb100; +} + +static inline bool T$pcrel$b(uint16_t ic) { + return (ic & 0xf000) == 0xd000 && (ic & 0x0e00) != 0x0e00; +} + +static inline bool T2$pcrel$b(uint16_t *ic) { + return (ic[0] & 0xf800) == 0xf000 && ((ic[1] & 0xd000) == 0x9000 || (ic[1] & 0xd000) == 0x8000 && (ic[0] & 0x0380) != 0x0380); +} + +static inline bool T$pcrel$bl(uint16_t *ic) { + return (ic[0] & 0xf800) == 0xf000 && ((ic[1] & 0xd000) == 0xd000 || (ic[1] & 0xd001) == 0xc000); +} + +static inline bool T$pcrel$ldr(uint16_t ic) { + return (ic & 0xf800) == 0x4800; +} + +static inline bool T$pcrel$add(uint16_t ic) { + return (ic & 0xff78) == 0x4478; +} + +static inline bool T$pcrel$ldrw(uint16_t ic) { + return (ic & 0xff7f) == 0xf85f; +} + +static size_t MSGetInstructionWidthThumb(void *start) { + uint16_t *thumb(reinterpret_cast(start)); + return T$32bit$i(thumb[0]) ? 4 : 2; +} + +static size_t MSGetInstructionWidthARM(void *start) { + return 4; +} + +extern "C" size_t MSGetInstructionWidth(void *start) { + if ((reinterpret_cast(start) & 0x1) == 0) + return MSGetInstructionWidthARM(start); + else + return MSGetInstructionWidthThumb(reinterpret_cast(reinterpret_cast(start) & ~0x1)); +} + +static size_t SubstrateHookFunctionThumb(SubstrateProcessRef process, void *symbol, void *replace, void **result) { + if (symbol == NULL) + return 0; +printf("SubstrateHookFunctionThumb\n"); + uint16_t *area(reinterpret_cast(symbol)); + + unsigned align((reinterpret_cast(area) & 0x2) == 0 ? 0 : 1); + uint16_t *thumb(area + align); + + uint32_t *arm(reinterpret_cast(thumb + 2)); + uint16_t *trail(reinterpret_cast(arm + 2)); + + if ( + (align == 0 || area[0] == T$nop) && + thumb[0] == T$bx(A$pc) && + thumb[1] == T$nop && + arm[0] == A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8) + ) { + if (result != NULL) + *result = reinterpret_cast(arm[1]); + + SubstrateHookMemory code(process, arm + 1, sizeof(uint32_t) * 1); + + arm[1] = reinterpret_cast(replace); + + return sizeof(arm[0]); + } + + size_t required((trail - area) * sizeof(uint16_t)); + + size_t used(0); + while (used < required) + used += MSGetInstructionWidthThumb(reinterpret_cast(area) + used); + used = (used + sizeof(uint16_t) - 1) / sizeof(uint16_t) * sizeof(uint16_t); + + size_t blank((used - required) / sizeof(uint16_t)); + + uint16_t backup[used / sizeof(uint16_t)]; + memcpy(backup, area, used); + + if (MSDebug) { + char name[16]; + sprintf(name, "%p", area); + MSLogHexEx(area, used + sizeof(uint16_t), 2, name); + } + + if (result != NULL) { + + size_t length(used); + for (unsigned offset(0); offset != used / sizeof(uint16_t); ++offset) + if (T$pcrel$ldr(backup[offset])) + length += 3 * sizeof(uint16_t); + else if (T$pcrel$b(backup[offset])) + length += 6 * sizeof(uint16_t); + else if (T2$pcrel$b(backup + offset)) { + length += 5 * sizeof(uint16_t); + ++offset; + } else if (T$pcrel$bl(backup + offset)) { + length += 5 * sizeof(uint16_t); + ++offset; + } else if (T$pcrel$cbz(backup[offset])) { + length += 16 * sizeof(uint16_t); + } else if (T$pcrel$ldrw(backup[offset])) { + length += 4 * sizeof(uint16_t); + ++offset; + } else if (T$pcrel$add(backup[offset])) + length += 6 * sizeof(uint16_t); + else if (T$32bit$i(backup[offset])) + ++offset; + + unsigned pad((length & 0x2) == 0 ? 0 : 1); + length += (pad + 2) * sizeof(uint16_t) + 2 * sizeof(uint32_t); + + uint16_t *buffer(reinterpret_cast(mmap( + NULL, length, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0 + ))); + + if (buffer == MAP_FAILED) { + MSLog(MSLogLevelError, "MS:Error:mmap() = %d", errno); + *result = NULL; + return 0; + } + + if (false) fail: { + munmap(buffer, length); + *result = NULL; + return 0; + } + + size_t start(pad), end(length / sizeof(uint16_t)); + uint32_t *trailer(reinterpret_cast(buffer + end)); + for (unsigned offset(0); offset != used / sizeof(uint16_t); ++offset) { + if (T$pcrel$ldr(backup[offset])) { + union { + uint16_t value; + + struct { + uint16_t immediate : 8; + uint16_t rd : 3; + uint16_t : 5; + }; + } bits = {backup[offset+0]}; + + buffer[start+0] = T$ldr_rd_$pc_im_4$(bits.rd, T$Label(start+0, end-2) / 4); + buffer[start+1] = T$ldr_rd_$rn_im_4$(bits.rd, bits.rd, 0); + + // XXX: this code "works", but is "wrong": the mechanism is more complex than this + *--trailer = ((reinterpret_cast(area + offset) + 4) & ~0x2) + bits.immediate * 4; + + start += 2; + end -= 2; + } else if (T$pcrel$b(backup[offset])) { + union { + uint16_t value; + + struct { + uint16_t imm8 : 8; + uint16_t cond : 4; + uint16_t /*1101*/ : 4; + }; + } bits = {backup[offset+0]}; + + intptr_t jump(bits.imm8 << 1); + jump |= 1; + jump <<= 23; + jump >>= 23; + + buffer[start+0] = T$b$_$im(bits.cond, (end-6 - (start+0)) * 2 - 4); + + *--trailer = reinterpret_cast(area + offset) + 4 + jump; + *--trailer = A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8); + *--trailer = T$nop << 16 | T$bx(A$pc); + + start += 1; + end -= 6; + } else if (T2$pcrel$b(backup + offset)) { + union { + uint16_t value; + + struct { + uint16_t imm6 : 6; + uint16_t cond : 4; + uint16_t s : 1; + uint16_t : 5; + }; + } bits = {backup[offset+0]}; + + union { + uint16_t value; + + struct { + uint16_t imm11 : 11; + uint16_t j2 : 1; + uint16_t a : 1; + uint16_t j1 : 1; + uint16_t : 2; + }; + } exts = {backup[offset+1]}; + + intptr_t jump(1); + jump |= exts.imm11 << 1; + jump |= bits.imm6 << 12; + + if (exts.a) { + jump |= bits.s << 24; + jump |= (~(bits.s ^ exts.j1) & 0x1) << 23; + jump |= (~(bits.s ^ exts.j2) & 0x1) << 22; + jump |= bits.cond << 18; + jump <<= 7; + jump >>= 7; + } else { + jump |= bits.s << 20; + jump |= exts.j2 << 19; + jump |= exts.j1 << 18; + jump <<= 11; + jump >>= 11; + } + + buffer[start+0] = T$b$_$im(exts.a ? A$al : bits.cond, (end-6 - (start+0)) * 2 - 4); + + *--trailer = reinterpret_cast(area + offset) + 4 + jump; + *--trailer = A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8); + *--trailer = T$nop << 16 | T$bx(A$pc); + + ++offset; + start += 1; + end -= 6; + } else if (T$pcrel$bl(backup + offset)) { + union { + uint16_t value; + + struct { + uint16_t immediate : 10; + uint16_t s : 1; + uint16_t : 5; + }; + } bits = {backup[offset+0]}; + + union { + uint16_t value; + + struct { + uint16_t immediate : 11; + uint16_t j2 : 1; + uint16_t x : 1; + uint16_t j1 : 1; + uint16_t : 2; + }; + } exts = {backup[offset+1]}; + + int32_t jump(0); + jump |= bits.s << 24; + jump |= (~(bits.s ^ exts.j1) & 0x1) << 23; + jump |= (~(bits.s ^ exts.j2) & 0x1) << 22; + jump |= bits.immediate << 12; + jump |= exts.immediate << 1; + jump |= exts.x; + jump <<= 7; + jump >>= 7; + + buffer[start+0] = T$push_r(1 << A$r7); + buffer[start+1] = T$ldr_rd_$pc_im_4$(A$r7, ((end-2 - (start+1)) * 2 - 4 + 2) / 4); + buffer[start+2] = T$mov_rd_rm(A$lr, A$r7); + buffer[start+3] = T$pop_r(1 << A$r7); + buffer[start+4] = T$blx(A$lr); + + *--trailer = reinterpret_cast(area + offset) + 4 + jump; + + ++offset; + start += 5; + end -= 2; + } else if (T$pcrel$cbz(backup[offset])) { + union { + uint16_t value; + + struct { + uint16_t rn : 3; + uint16_t immediate : 5; + uint16_t : 1; + uint16_t i : 1; + uint16_t : 1; + uint16_t op : 1; + uint16_t : 4; + }; + } bits = {backup[offset+0]}; + + intptr_t jump(1); + jump |= bits.i << 6; + jump |= bits.immediate << 1; + + //jump <<= 24; + //jump >>= 24; + + unsigned rn(bits.rn); + unsigned rt(rn == A$r7 ? A$r6 : A$r7); + + buffer[start+0] = T$push_r(1 << rt); + buffer[start+1] = T1$mrs_rd_apsr(rt); + buffer[start+2] = T2$mrs_rd_apsr(rt); + buffer[start+3] = T$cbz$_rn_$im(bits.op, rn, (end-10 - (start+3)) * 2 - 4); + buffer[start+4] = T1$msr_apsr_nzcvqg_rn(rt); + buffer[start+5] = T2$msr_apsr_nzcvqg_rn(rt); + buffer[start+6] = T$pop_r(1 << rt); + + *--trailer = reinterpret_cast(area + offset) + 4 + jump; + *--trailer = A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8); + *--trailer = T$nop << 16 | T$bx(A$pc); + *--trailer = T$nop << 16 | T$pop_r(1 << rt); + *--trailer = T$msr_apsr_nzcvqg_rn(rt); + +#if 0 + if ((start & 0x1) == 0) + buffer[start++] = T$nop; + buffer[start++] = T$bx(A$pc); + buffer[start++] = T$nop; + + uint32_t *arm(reinterpret_cast(buffer + start)); + arm[0] = A$add(A$lr, A$pc, 1); + arm[1] = A$ldr_rd_$rn_im$(A$pc, A$pc, (trailer - arm) * sizeof(uint32_t) - 8); +#endif + + start += 7; + end -= 10; + } else if (T$pcrel$ldrw(backup[offset])) { + union { + uint16_t value; + + struct { + uint16_t : 7; + uint16_t u : 1; + uint16_t : 8; + }; + } bits = {backup[offset+0]}; + + union { + uint16_t value; + + struct { + uint16_t immediate : 12; + uint16_t rt : 4; + }; + } exts = {backup[offset+1]}; + + buffer[start+0] = T1$ldr_rt_$rn_im$(exts.rt, A$pc, T$Label(start+0, end-2)); + buffer[start+1] = T2$ldr_rt_$rn_im$(exts.rt, A$pc, T$Label(start+0, end-2)); + + buffer[start+2] = T1$ldr_rt_$rn_im$(exts.rt, exts.rt, 0); + buffer[start+3] = T2$ldr_rt_$rn_im$(exts.rt, exts.rt, 0); + + // XXX: this code "works", but is "wrong": the mechanism is more complex than this + *--trailer = ((reinterpret_cast(area + offset) + 4) & ~0x2) + (bits.u == 0 ? -exts.immediate : exts.immediate); + + ++offset; + start += 4; + end -= 2; + } else if (T$pcrel$add(backup[offset])) { + union { + uint16_t value; + + struct { + uint16_t rd : 3; + uint16_t rm : 3; + uint16_t h2 : 1; + uint16_t h1 : 1; + uint16_t : 8; + }; + } bits = {backup[offset+0]}; + + if (bits.h1) { + MSLog(MSLogLevelError, "MS:Error:pcrel(%u):add (rd > r7)", offset); + goto fail; + } + + unsigned rt(bits.rd == A$r7 ? A$r6 : A$r7); + + buffer[start+0] = T$push_r(1 << rt); + buffer[start+1] = T$mov_rd_rm(rt, (bits.h1 << 3) | bits.rd); + buffer[start+2] = T$ldr_rd_$pc_im_4$(bits.rd, T$Label(start+2, end-2) / 4); + buffer[start+3] = T$add_rd_rm((bits.h1 << 3) | bits.rd, rt); + buffer[start+4] = T$pop_r(1 << rt); + *--trailer = reinterpret_cast(area + offset) + 4; + + start += 5; + end -= 2; + } else if (T$32bit$i(backup[offset])) { + buffer[start++] = backup[offset]; + buffer[start++] = backup[++offset]; + } else { + buffer[start++] = backup[offset]; + } + } + + buffer[start++] = T$bx(A$pc); + buffer[start++] = T$nop; + + uint32_t *transfer = reinterpret_cast(buffer + start); + transfer[0] = A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8); + transfer[1] = reinterpret_cast(area + used / sizeof(uint16_t)) + 1; + + if (mprotect(buffer, length, PROT_READ | PROT_EXEC) == -1) { + MSLog(MSLogLevelError, "MS:Error:mprotect():%d", errno); + return 0; + } + + *result = reinterpret_cast(buffer + pad) + 1; + + if (MSDebug) { + char name[16]; + sprintf(name, "%p", *result); + MSLogHexEx(buffer, length, 2, name); + } + + } + + { + SubstrateHookMemory code(process, area, used); + + if (align != 0) + area[0] = T$nop; + + thumb[0] = T$bx(A$pc); + thumb[1] = T$nop; + + arm[0] = A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8); + arm[1] = reinterpret_cast(replace); + + for (unsigned offset(0); offset != blank; ++offset) + trail[offset] = T$nop; + } + + if (MSDebug) { + char name[16]; + sprintf(name, "%p", area); + MSLogHexEx(area, used + sizeof(uint16_t), 2, name); + } + + return used; +} + +static size_t SubstrateHookFunctionARM(SubstrateProcessRef process, void *symbol, void *replace, void **result) { + if (symbol == NULL) + return 0; +printf("SubstrateHookFunctionARM\n"); + uint32_t *area(reinterpret_cast(symbol)); + uint32_t *arm(area); + + const size_t used(8); + + uint32_t backup[used / sizeof(uint32_t)] = {arm[0], arm[1]}; + + if (MSDebug) { + char name[16]; + sprintf(name, "%p", area); + MSLogHexEx(area, used + sizeof(uint32_t), 4, name); + } + + if (result != NULL) { + + if (backup[0] == A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8)) { + *result = reinterpret_cast(backup[1]); + + return sizeof(backup[0]); + } + + size_t length(used); + for (unsigned offset(0); offset != used / sizeof(uint32_t); ++offset) + if (A$pcrel$r(backup[offset])) { + if ((backup[offset] & 0x02000000) == 0 || (backup[offset] & 0x0000f000 >> 12) != (backup[offset] & 0x0000000f)) + length += 2 * sizeof(uint32_t); + else + length += 4 * sizeof(uint32_t); + } + + length += 2 * sizeof(uint32_t); + + uint32_t *buffer(reinterpret_cast(mmap( + NULL, length, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0 + ))); + + if (buffer == MAP_FAILED) { + MSLog(MSLogLevelError, "MS:Error:mmap() = %d", errno); + *result = NULL; + return 0; + } + + if (false) fail: { + munmap(buffer, length); + *result = NULL; + return 0; + } + + size_t start(0), end(length / sizeof(uint32_t)); + uint32_t *trailer(reinterpret_cast(buffer + end)); + for (unsigned offset(0); offset != used / sizeof(uint32_t); ++offset) + if (A$pcrel$r(backup[offset])) { + union { + uint32_t value; + + struct { + uint32_t rm : 4; + uint32_t : 1; + uint32_t shift : 2; + uint32_t shiftamount : 5; + uint32_t rd : 4; + uint32_t rn : 4; + uint32_t l : 1; + uint32_t w : 1; + uint32_t b : 1; + uint32_t u : 1; + uint32_t p : 1; + uint32_t mode : 1; + uint32_t type : 2; + uint32_t cond : 4; + }; + } bits = {backup[offset+0]}, copy(bits); + + bool guard; + if (bits.mode == 0 || bits.rd != bits.rm) { + copy.rn = bits.rd; + guard = false; + } else { + copy.rn = bits.rm != A$r0 ? A$r0 : A$r1; + guard = true; + } + + if (guard) + buffer[start++] = A$stmdb_sp$_$rs$((1 << copy.rn)); + + buffer[start+0] = A$ldr_rd_$rn_im$(copy.rn, A$pc, (end-1 - (start+0)) * 4 - 8); + buffer[start+1] = copy.value; + + start += 2; + + if (guard) + buffer[start++] = A$ldmia_sp$_$rs$((1 << copy.rn)); + + *--trailer = reinterpret_cast(area + offset) + 8; + end -= 1; + } else + buffer[start++] = backup[offset]; + + buffer[start+0] = A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8); + buffer[start+1] = reinterpret_cast(area + used / sizeof(uint32_t)); + + if (mprotect(buffer, length, PROT_READ | PROT_EXEC) == -1) { + MSLog(MSLogLevelError, "MS:Error:mprotect():%d", errno); + goto fail; + } + + *result = buffer; + + if (MSDebug) { + char name[16]; + sprintf(name, "%p", *result); + MSLogHexEx(buffer, length, 4, name); + } + + } + + { + SubstrateHookMemory code(process, symbol, used); + + arm[0] = A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8); + arm[1] = reinterpret_cast(replace); + } + + if (MSDebug) { + char name[16]; + sprintf(name, "%p", area); + MSLogHexEx(area, used + sizeof(uint32_t), 4, name); + } + + return used; +} + +static size_t SubstrateHookFunction(SubstrateProcessRef process, void *symbol, void *replace, void **result) { + if (MSDebug) + MSLog(MSLogLevelNotice, "SubstrateHookFunction(%p, %p, %p, %p)\n", process, symbol, replace, result); + if ((reinterpret_cast(symbol) & 0x1) == 0) + return SubstrateHookFunctionARM(process, symbol, replace, result); + else + return SubstrateHookFunctionThumb(process, reinterpret_cast(reinterpret_cast(symbol) & ~0x1), replace, result); +} +#endif + +#if defined(__i386__) || defined(__x86_64__) + +#include "SubstrateX86.hpp" + +static size_t MSGetInstructionWidthIntel(void *start) { + hde64s decode; + return hde64_disasm(start, &decode); +} + +static void SubstrateHookFunction(SubstrateProcessRef process, void *symbol, void *replace, void **result) { + if (MSDebug) + MSLog(MSLogLevelNotice, "MSHookFunction(%p, %p, %p)\n", symbol, replace, result); + if (symbol == NULL) + return; + + uintptr_t source(reinterpret_cast(symbol)); + uintptr_t target(reinterpret_cast(replace)); + + uint8_t *area(reinterpret_cast(symbol)); + + size_t required(MSSizeOfJump(target, source)); + + if (MSDebug) { + char name[16]; + sprintf(name, "%p", area); + MSLogHex(area, 32, name); + } + + size_t used(0); + while (used < required) { + size_t width(MSGetInstructionWidthIntel(area + used)); + if (width == 0) { + MSLog(MSLogLevelError, "MS:Error:MSGetInstructionWidthIntel(%p) == 0", area + used); + return; + } + + used += width; + } + + size_t blank(used - required); + + if (MSDebug) { + char name[16]; + sprintf(name, "%p", area); + MSLogHex(area, used + sizeof(uint16_t), name); + } + + uint8_t backup[used]; + memcpy(backup, area, used); + + if (result != NULL) { + + if (backup[0] == 0xe9) { + *result = reinterpret_cast(source + 5 + *reinterpret_cast(backup + 1)); + return; + } + + if (!ia32 && backup[0] == 0xff && backup[1] == 0x25) { + *result = *reinterpret_cast(source + 6 + *reinterpret_cast(backup + 2)); + return; + } + + size_t length(used + MSSizeOfJump(source + used)); + + for (size_t offset(0), width; offset != used; offset += width) { + hde64s decode; + hde64_disasm(backup + offset, &decode); + width = decode.len; + //_assert(width != 0 && offset + width <= used); + +#ifdef __LP64__ + if ((decode.modrm & 0xc7) == 0x05) { + if (decode.opcode == 0x8b) { + void *destiny(area + offset + width + int32_t(decode.disp.disp32)); + uint8_t reg(decode.rex_r << 3 | decode.modrm_reg); + length -= decode.len; + length += MSSizeOfPushPointer(destiny); + length += MSSizeOfPop(reg); + length += MSSizeOfMove64(); + } else { + MSLog(MSLogLevelError, "MS:Error: Unknown RIP-Relative (%.2x %.2x)", decode.opcode, decode.opcode2); + continue; + } + } else +#endif + + if (backup[offset] == 0xe8) { + int32_t relative(*reinterpret_cast(backup + offset + 1)); + void *destiny(area + offset + decode.len + relative); + + if (relative == 0) { + length -= decode.len; + length += MSSizeOfPushPointer(destiny); + } else { + length += MSSizeOfSkip(); + length += MSSizeOfJump(destiny); + } + } else if (backup[offset] == 0xeb) { + length -= decode.len; + length += MSSizeOfJump(area + offset + decode.len + *reinterpret_cast(backup + offset + 1)); + } else if (backup[offset] == 0xe9) { + length -= decode.len; + length += MSSizeOfJump(area + offset + decode.len + *reinterpret_cast(backup + offset + 1)); + } else if ( + backup[offset] == 0xe3 || + (backup[offset] & 0xf0) == 0x70 + // XXX: opcode2 & 0xf0 is 0x80? + ) { + length += decode.len; + length += MSSizeOfJump(area + offset + decode.len + *reinterpret_cast(backup + offset + 1)); + } + } + + uint8_t *buffer(reinterpret_cast(mmap( + NULL, length, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0 + ))); + + if (buffer == MAP_FAILED) { + MSLog(MSLogLevelError, "MS:Error:mmap() = %d", errno); + *result = NULL; + return; + } + + if (false) fail: { + munmap(buffer, length); + *result = NULL; + return; + } + + { + uint8_t *current(buffer); + + for (size_t offset(0), width; offset != used; offset += width) { + hde64s decode; + hde64_disasm(backup + offset, &decode); + width = decode.len; + //_assert(width != 0 && offset + width <= used); + +#ifdef __LP64__ + if ((decode.modrm & 0xc7) == 0x05) { + if (decode.opcode == 0x8b) { + void *destiny(area + offset + width + int32_t(decode.disp.disp32)); + uint8_t reg(decode.rex_r << 3 | decode.modrm_reg); + MSPushPointer(current, destiny); + MSWritePop(current, reg); + MSWriteMove64(current, reg, reg); + } else { + MSLog(MSLogLevelError, "MS:Error: Unknown RIP-Relative (%.2x %.2x)", decode.opcode, decode.opcode2); + goto copy; + } + } else +#endif + + if (backup[offset] == 0xe8) { + int32_t relative(*reinterpret_cast(backup + offset + 1)); + if (relative == 0) + MSPushPointer(current, area + offset + decode.len); + else { + MSWrite(current, 0xe8); + MSWrite(current, MSSizeOfSkip()); + void *destiny(area + offset + decode.len + relative); + MSWriteSkip(current, MSSizeOfJump(destiny, current + MSSizeOfSkip())); + MSWriteJump(current, destiny); + } + } else if (backup[offset] == 0xeb) + MSWriteJump(current, area + offset + decode.len + *reinterpret_cast(backup + offset + 1)); + else if (backup[offset] == 0xe9) + MSWriteJump(current, area + offset + decode.len + *reinterpret_cast(backup + offset + 1)); + else if ( + backup[offset] == 0xe3 || + (backup[offset] & 0xf0) == 0x70 + ) { + MSWrite(current, backup[offset]); + MSWrite(current, 2); + MSWrite(current, 0xeb); + void *destiny(area + offset + decode.len + *reinterpret_cast(backup + offset + 1)); + MSWrite(current, MSSizeOfJump(destiny, current + 1)); + MSWriteJump(current, destiny); + } else +#ifdef __LP64__ + copy: +#endif + { + MSWrite(current, backup + offset, width); + } + } + + MSWriteJump(current, area + used); + } + + if (mprotect(buffer, length, PROT_READ | PROT_EXEC) == -1) { + MSLog(MSLogLevelError, "MS:Error:mprotect():%d", errno); + goto fail; + } + + *result = buffer; + + if (MSDebug) { + char name[16]; + sprintf(name, "%p", *result); + MSLogHex(buffer, length, name); + } + + } + + { + SubstrateHookMemory code(process, area, used); + + uint8_t *current(area); + MSWriteJump(current, target); + for (unsigned offset(0); offset != blank; ++offset) + MSWrite(current, 0x90); + } + + if (MSDebug) { + char name[16]; + sprintf(name, "%p", area); + MSLogHex(area, used + sizeof(uint16_t), name); + } +} +#endif + +_extern void MSHookFunction(void *symbol, void *replace, void **result) { + SubstrateHookFunction(NULL, symbol, replace, result); +} + +#if defined(__APPLE__) && defined(__arm__) +_extern void _Z14MSHookFunctionPvS_PS_(void *symbol, void *replace, void **result) { + return MSHookFunction(symbol, replace, result); +} +#endif diff --git a/VirtualApp/lib/src/main/jni/Substrate/SubstrateHook.h b/VirtualApp/lib/src/main/jni/Substrate/SubstrateHook.h new file mode 100755 index 000000000..40a0296cb --- /dev/null +++ b/VirtualApp/lib/src/main/jni/Substrate/SubstrateHook.h @@ -0,0 +1,19 @@ +#ifndef __SUBSTRATEHOOK_H__ +#define __SUBSTRATEHOOK_H__ + + +#include + +#define _extern extern "C" __attribute__((__visibility__("default"))) + +#ifdef __cplusplus +extern "C" { +#endif + +void MSHookFunction(void *symbol, void *replace, void **result); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/VirtualApp/lib/src/main/jni/Substrate/SubstrateLog.hpp b/VirtualApp/lib/src/main/jni/Substrate/SubstrateLog.hpp new file mode 100755 index 000000000..3e5728014 --- /dev/null +++ b/VirtualApp/lib/src/main/jni/Substrate/SubstrateLog.hpp @@ -0,0 +1,40 @@ +/* Cydia Substrate - Powerful Code Insertion Platform + * Copyright (C) 2008-2011 Jay Freeman (saurik) +*/ + +/* GNU Lesser General Public License, Version 3 {{{ */ +/* + * Substrate is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Substrate is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Substrate. If not, see . +**/ +/* }}} */ + +#ifndef SUBSTRATE_LOG_HPP +#define SUBSTRATE_LOG_HPP + +#if 0 +#include + +#define MSLog(level, format, ...) ((void)__android_log_print(level, "NNNN", format, __VA_ARGS__)) + +#define MSLogLevelNotice ANDROID_LOG_INFO +#define MSLogLevelWarning ANDROID_LOG_WARN +#define MSLogLevelError ANDROID_LOG_ERROR + +#else + +#define MSLog(level, format, ...) printf(format, __VA_ARGS__) + +#endif + +#endif//SUBSTRATE_LOG_HPP diff --git a/VirtualApp/lib/src/main/jni/Substrate/SubstratePosixMemory.cpp b/VirtualApp/lib/src/main/jni/Substrate/SubstratePosixMemory.cpp new file mode 100755 index 000000000..709cb228e --- /dev/null +++ b/VirtualApp/lib/src/main/jni/Substrate/SubstratePosixMemory.cpp @@ -0,0 +1,75 @@ +/* Cydia Substrate - Powerful Code Insertion Platform + * Copyright (C) 2008-2011 Jay Freeman (saurik) +*/ + +/* GNU Lesser General Public License, Version 3 {{{ */ +/* + * Substrate is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Substrate is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Substrate. If not, see . +**/ +/* }}} */ + +#define SubstrateInternal +#include "CydiaSubstrate.h" +#include "SubstrateLog.hpp" + +#include + +#include +#include +#include + +extern "C" void __clear_cache (void *beg, void *end); + +struct __SubstrateMemory { + void *address_; + size_t width_; + + __SubstrateMemory(void *address, size_t width) : + address_(address), + width_(width) + { + } +}; + +extern "C" SubstrateMemoryRef SubstrateMemoryCreate(SubstrateAllocatorRef allocator, SubstrateProcessRef process, void *data, size_t size) { + if (allocator != NULL) { + MSLog(MSLogLevelError, "MS:Error:allocator != %d", 0); + return NULL; + } + + if (size == 0) + return NULL; + + long page(sysconf(_SC_PAGESIZE)); // Portable applications should employ sysconf(_SC_PAGESIZE) instead of getpagesize + + uintptr_t base(reinterpret_cast(data) / page * page); + size_t width(((reinterpret_cast(data) + size - 1) / page + 1) * page - base); + void *address(reinterpret_cast(base)); + + if (mprotect(address, width, PROT_READ | PROT_WRITE | PROT_EXEC) == -1) { + MSLog(MSLogLevelError, "MS:Error:mprotect() = %d", errno); + return NULL; + } + + return new __SubstrateMemory(address, width); +} + +extern "C" void SubstrateMemoryRelease(SubstrateMemoryRef memory) { + if (mprotect(memory->address_, memory->width_, PROT_READ | PROT_WRITE | PROT_EXEC) == -1) + MSLog(MSLogLevelError, "MS:Error:mprotect() = %d", errno); + + __clear_cache(reinterpret_cast(memory->address_), reinterpret_cast(memory->address_) + memory->width_); + + delete memory; +} diff --git a/VirtualApp/lib/src/main/jni/Substrate/SubstrateX86.hpp b/VirtualApp/lib/src/main/jni/Substrate/SubstrateX86.hpp new file mode 100755 index 000000000..ffe2b06e3 --- /dev/null +++ b/VirtualApp/lib/src/main/jni/Substrate/SubstrateX86.hpp @@ -0,0 +1,200 @@ +/* Cydia Substrate - Powerful Code Insertion Platform + * Copyright (C) 2008-2011 Jay Freeman (saurik) +*/ + +/* GNU Lesser General Public License, Version 3 {{{ */ +/* + * Substrate is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Substrate is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Substrate. If not, see . +**/ +/* }}} */ + +#ifndef SUBSTRATE_X86_HPP +#define SUBSTRATE_X86_HPP + +#include "Buffer.hpp" + +#ifdef __LP64__ +static const bool ia32 = false; +#else +static const bool ia32 = true; +#endif + +enum I$r { + I$rax, I$rcx, I$rdx, I$rbx, + I$rsp, I$rbp, I$rsi, I$rdi, + I$r8, I$r9, I$r10, I$r11, + I$r12, I$r13, I$r14, I$r15, +}; + +_disused static bool MSIs32BitOffset(uintptr_t target, uintptr_t source) { + intptr_t offset(target - source); + return int32_t(offset) == offset; +} + +_disused static size_t MSSizeOfSkip() { + return 5; +} + +_disused static size_t MSSizeOfPushPointer(uintptr_t target) { + return uint64_t(target) >> 32 == 0 ? 5 : 13; +} + +_disused static size_t MSSizeOfPushPointer(void *target) { + return MSSizeOfPushPointer(reinterpret_cast(target)); +} + +_disused static size_t MSSizeOfJump(bool blind, uintptr_t target, uintptr_t source = 0) { + if (ia32 || !blind && MSIs32BitOffset(target, source + 5)) + return MSSizeOfSkip(); + else + return MSSizeOfPushPointer(target) + 1; +} + +_disused static size_t MSSizeOfJump(uintptr_t target, uintptr_t source) { + return MSSizeOfJump(false, target, source); +} + +_disused static size_t MSSizeOfJump(uintptr_t target) { + return MSSizeOfJump(true, target); +} + +_disused static size_t MSSizeOfJump(void *target, void *source) { + return MSSizeOfJump(reinterpret_cast(target), reinterpret_cast(source)); +} + +_disused static size_t MSSizeOfJump(void *target) { + return MSSizeOfJump(reinterpret_cast(target)); +} + +_disused static void MSWriteSkip(uint8_t *¤t, ssize_t size) { + MSWrite(current, 0xe9); + MSWrite(current, size); +} + +_disused static void MSPushPointer(uint8_t *¤t, uintptr_t target) { + MSWrite(current, 0x68); + MSWrite(current, target); + + if (uint32_t high = uint64_t(target) >> 32) { + MSWrite(current, 0xc7); + MSWrite(current, 0x44); + MSWrite(current, 0x24); + MSWrite(current, 0x04); + MSWrite(current, high); + } +} + +_disused static void MSPushPointer(uint8_t *¤t, void *target) { + return MSPushPointer(current, reinterpret_cast(target)); +} + +_disused static void MSWriteCall(uint8_t *¤t, I$r target) { + if (target >> 3 != 0) + MSWrite(current, 0x40 | (target & 0x08) >> 3); + MSWrite(current, 0xff); + MSWrite(current, 0xd0 | target & 0x07); +} + +_disused static void MSWriteCall(uint8_t *¤t, uintptr_t target) { + uintptr_t source(reinterpret_cast(current)); + + if (ia32 || MSIs32BitOffset(target, source + 5)) { + MSWrite(current, 0xe8); + MSWrite(current, target - (source + 5)); + } else { + MSPushPointer(current, target); + + MSWrite(current, 0x83); + MSWrite(current, 0xc4); + MSWrite(current, 0x08); + + MSWrite(current, 0x67); + MSWrite(current, 0xff); + MSWrite(current, 0x54); + MSWrite(current, 0x24); + MSWrite(current, 0xf8); + } +} + +template +_disused static void MSWriteCall(uint8_t *¤t, Type_ *target) { + return MSWriteCall(current, reinterpret_cast(target)); +} + +_disused static void MSWriteJump(uint8_t *¤t, uintptr_t target) { + uintptr_t source(reinterpret_cast(current)); + + if (ia32 || MSIs32BitOffset(target, source + 5)) + MSWriteSkip(current, target - (source + 5)); + else { + MSPushPointer(current, target); + MSWrite(current, 0xc3); + } +} + +_disused static void MSWriteJump(uint8_t *¤t, void *target) { + return MSWriteJump(current, reinterpret_cast(target)); +} + +_disused static void MSWriteJump(uint8_t *¤t, I$r target) { + if (target >> 3 != 0) + MSWrite(current, 0x40 | (target & 0x08) >> 3); + MSWrite(current, 0xff); + MSWrite(current, 0xe0 | target & 0x07); +} + +_disused static void MSWritePop(uint8_t *¤t, uint8_t target) { + if (target >> 3 != 0) + MSWrite(current, 0x40 | (target & 0x08) >> 3); + MSWrite(current, 0x58 | target & 0x07); +} + +_disused static size_t MSSizeOfPop(uint8_t target) { + return target >> 3 != 0 ? 2 : 1; +} + +_disused static void MSWritePush(uint8_t *¤t, I$r target) { + if (target >> 3 != 0) + MSWrite(current, 0x40 | (target & 0x08) >> 3); + MSWrite(current, 0x50 | target & 0x07); +} + +_disused static void MSWriteAdd(uint8_t *¤t, I$r target, uint8_t source) { + MSWrite(current, 0x83); + MSWrite(current, 0xc4 | target & 0x07); + MSWrite(current, source); +} + +_disused static void MSWriteSet64(uint8_t *¤t, I$r target, uintptr_t source) { + MSWrite(current, 0x48 | (target & 0x08) >> 3 << 2); + MSWrite(current, 0xb8 | target & 0x7); + MSWrite(current, source); +} + +template +_disused static void MSWriteSet64(uint8_t *¤t, I$r target, Type_ *source) { + return MSWriteSet64(current, target, reinterpret_cast(source)); +} + +_disused static void MSWriteMove64(uint8_t *¤t, uint8_t source, uint8_t target) { + MSWrite(current, 0x48 | (target & 0x08) >> 3 << 2 | (source & 0x08) >> 3); + MSWrite(current, 0x8b); + MSWrite(current, (target & 0x07) << 3 | source & 0x07); +} + +_disused static size_t MSSizeOfMove64() { + return 3; +} + +#endif//SUBSTRATE_X86_HPP diff --git a/VirtualApp/lib/src/main/jni/Substrate/hde64.c b/VirtualApp/lib/src/main/jni/Substrate/hde64.c new file mode 100755 index 000000000..d69f0c68e --- /dev/null +++ b/VirtualApp/lib/src/main/jni/Substrate/hde64.c @@ -0,0 +1,332 @@ +/* + * Hacker Disassembler Engine 64 C + * Copyright (c) 2008-2009, Vyacheslav Patkov. + * All rights reserved. + * + */ + +#include +#include + +#include "hde64.h" +#include "table64.h" + +unsigned int hde64_disasm(const void *code, hde64s *hs) +{ + uint8_t x, c, *p = (uint8_t *)code, cflags, opcode, pref = 0; + uint8_t *ht = hde64_table, m_mod, m_reg, m_rm, disp_size = 0; + uint8_t op64 = 0; + + memset(hs,0,sizeof(hde64s)); + char *tmp=(char*)hs; + + for (x = 16; x; x--) + switch (c = *p++) { + case 0xf3: + hs->p_rep = c; + pref |= PRE_F3; + break; + case 0xf2: + hs->p_rep = c; + pref |= PRE_F2; + break; + case 0xf0: + hs->p_lock = c; + pref |= PRE_LOCK; + break; + case 0x26: case 0x2e: case 0x36: + case 0x3e: case 0x64: case 0x65: + hs->p_seg = c; + pref |= PRE_SEG; + break; + case 0x66: + hs->p_66 = c; + pref |= PRE_66; + break; + case 0x67: + hs->p_67 = c; + pref |= PRE_67; + break; + default: + goto pref_done; + } + pref_done: + + hs->flags = (uint32_t)pref << 23; + + if (!pref) + pref |= PRE_NONE; + + if ((c & 0xf0) == 0x40) { + hs->flags |= F_PREFIX_REX; + if ((hs->rex_w = (c & 0xf) >> 3) && (*p & 0xf8) == 0xb8) + op64++; + hs->rex_r = (c & 7) >> 2; + hs->rex_x = (c & 3) >> 1; + hs->rex_b = c & 1; + if (((c = *p++) & 0xf0) == 0x40) { + opcode = c; + goto error_opcode; + } + } + + if ((hs->opcode = c) == 0x0f) { + hs->opcode2 = c = *p++; + ht += DELTA_OPCODES; + } else if (c >= 0xa0 && c <= 0xa3) { + op64++; + if (pref & PRE_67) + pref |= PRE_66; + else + pref &= ~PRE_66; + } + + opcode = c; + cflags = ht[ht[opcode / 4] + (opcode % 4)]; + + if (cflags == C_ERROR) { + error_opcode: + hs->flags |= F_ERROR | F_ERROR_OPCODE; + cflags = 0; + if ((opcode & -3) == 0x24) + cflags++; + } + + x = 0; + if (cflags & C_GROUP) { + uint16_t t; + t = *(uint16_t *)(ht + (cflags & 0x7f)); + cflags = (uint8_t)t; + x = (uint8_t)(t >> 8); + } + + if (hs->opcode2) { + ht = hde64_table + DELTA_PREFIXES; + if (ht[ht[opcode / 4] + (opcode % 4)] & pref) + hs->flags |= F_ERROR | F_ERROR_OPCODE; + } + + if (cflags & C_MODRM) { + hs->flags |= F_MODRM; + hs->modrm = c = *p++; + hs->modrm_mod = m_mod = c >> 6; + hs->modrm_rm = m_rm = c & 7; + hs->modrm_reg = m_reg = (c & 0x3f) >> 3; + + if (x && ((x << m_reg) & 0x80)) + hs->flags |= F_ERROR | F_ERROR_OPCODE; + + if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) { + uint8_t t = opcode - 0xd9; + if (m_mod == 3) { + ht = hde64_table + DELTA_FPU_MODRM + t*8; + t = ht[m_reg] << m_rm; + } else { + ht = hde64_table + DELTA_FPU_REG; + t = ht[t] << m_reg; + } + if (t & 0x80) + hs->flags |= F_ERROR | F_ERROR_OPCODE; + } + + if (pref & PRE_LOCK) { + if (m_mod == 3) { + hs->flags |= F_ERROR | F_ERROR_LOCK; + } else { + uint8_t *table_end, op = opcode; + if (hs->opcode2) { + ht = hde64_table + DELTA_OP2_LOCK_OK; + table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK; + } else { + ht = hde64_table + DELTA_OP_LOCK_OK; + table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK; + op &= -2; + } + for (; ht != table_end; ht++) + if (*ht++ == op) { + if (!((*ht << m_reg) & 0x80)) + goto no_lock_error; + else + break; + } + hs->flags |= F_ERROR | F_ERROR_LOCK; + no_lock_error: + ; + } + } + + if (hs->opcode2) { + switch (opcode) { + case 0x20: case 0x22: + m_mod = 3; + if (m_reg > 4 || m_reg == 1) + goto error_operand; + else + goto no_error_operand; + case 0x21: case 0x23: + m_mod = 3; + if (m_reg == 4 || m_reg == 5) + goto error_operand; + else + goto no_error_operand; + } + } else { + switch (opcode) { + case 0x8c: + if (m_reg > 5) + goto error_operand; + else + goto no_error_operand; + case 0x8e: + if (m_reg == 1 || m_reg > 5) + goto error_operand; + else + goto no_error_operand; + } + } + + if (m_mod == 3) { + uint8_t *table_end; + if (hs->opcode2) { + ht = hde64_table + DELTA_OP2_ONLY_MEM; + table_end = ht + sizeof(hde64_table) - DELTA_OP2_ONLY_MEM; + } else { + ht = hde64_table + DELTA_OP_ONLY_MEM; + table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM; + } + for (; ht != table_end; ht += 2) + if (*ht++ == opcode) { + if (*ht++ & pref && !((*ht << m_reg) & 0x80)) + goto error_operand; + else + break; + } + goto no_error_operand; + } else if (hs->opcode2) { + switch (opcode) { + case 0x50: case 0xd7: case 0xf7: + if (pref & (PRE_NONE | PRE_66)) + goto error_operand; + break; + case 0xd6: + if (pref & (PRE_F2 | PRE_F3)) + goto error_operand; + break; + case 0xc5: + goto error_operand; + } + goto no_error_operand; + } else + goto no_error_operand; + + error_operand: + hs->flags |= F_ERROR | F_ERROR_OPERAND; + no_error_operand: + + c = *p++; + if (m_reg <= 1) { + if (opcode == 0xf6) + cflags |= C_IMM8; + else if (opcode == 0xf7) + cflags |= C_IMM_P66; + } + + switch (m_mod) { + case 0: + if (pref & PRE_67) { + if (m_rm == 6) + disp_size = 2; + } else + if (m_rm == 5) + disp_size = 4; + break; + case 1: + disp_size = 1; + break; + case 2: + disp_size = 2; + if (!(pref & PRE_67)) + disp_size <<= 1; + } + + if (m_mod != 3 && m_rm == 4) { + hs->flags |= F_SIB; + p++; + hs->sib = c; + hs->sib_scale = c >> 6; + hs->sib_index = (c & 0x3f) >> 3; + if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1)) + disp_size = 4; + } + + p--; + switch (disp_size) { + case 1: + hs->flags |= F_DISP8; + hs->disp.disp8 = *p; + break; + case 2: + hs->flags |= F_DISP16; + hs->disp.disp16 = *(uint16_t *)p; + break; + case 4: + hs->flags |= F_DISP32; + hs->disp.disp32 = *(uint32_t *)p; + } + p += disp_size; + } else if (pref & PRE_LOCK) + hs->flags |= F_ERROR | F_ERROR_LOCK; + + if (cflags & C_IMM_P66) { + if (cflags & C_REL32) { + if (pref & PRE_66) { + hs->flags |= F_IMM16 | F_RELATIVE; + hs->imm.imm16 = *(uint16_t *)p; + p += 2; + goto disasm_done; + } + goto rel32_ok; + } + if (op64) { + hs->flags |= F_IMM64; + hs->imm.imm64 = *(uint64_t *)p; + p += 8; + } else if (!(pref & PRE_66)) { + hs->flags |= F_IMM32; + hs->imm.imm32 = *(uint32_t *)p; + p += 4; + } else + goto imm16_ok; + } + + + if (cflags & C_IMM16) { + imm16_ok: + hs->flags |= F_IMM16; + hs->imm.imm16 = *(uint16_t *)p; + p += 2; + } + if (cflags & C_IMM8) { + hs->flags |= F_IMM8; + hs->imm.imm8 = *p++; + } + + if (cflags & C_REL32) { + rel32_ok: + hs->flags |= F_IMM32 | F_RELATIVE; + hs->imm.imm32 = *(uint32_t *)p; + p += 4; + } else if (cflags & C_REL8) { + hs->flags |= F_IMM8 | F_RELATIVE; + hs->imm.imm8 = *p++; + } + + disasm_done: + + if ((hs->len = (uint8_t)(p-(uint8_t *)code)) > 15) { + hs->flags |= F_ERROR | F_ERROR_LENGTH; + hs->len = 15; + } + + return (unsigned int)hs->len; +} diff --git a/VirtualApp/lib/src/main/jni/Substrate/hde64.h b/VirtualApp/lib/src/main/jni/Substrate/hde64.h new file mode 100755 index 000000000..2fcc4cb25 --- /dev/null +++ b/VirtualApp/lib/src/main/jni/Substrate/hde64.h @@ -0,0 +1,112 @@ +/* + * Hacker Disassembler Engine 64 + * Copyright (c) 2008-2009, Vyacheslav Patkov. + * All rights reserved. + * + * hde64.h: C/C++ header file + * + */ + +#ifndef _HDE64_H_ +#define _HDE64_H_ + +/* stdint.h - C99 standard header + * http://en.wikipedia.org/wiki/stdint.h + * + * if your compiler doesn't contain "stdint.h" header (for + * example, Microsoft Visual C++), you can download file: + * http://www.azillionmonkeys.com/qed/pstdint.h + * and change next line to: + * #include "pstdint.h" + */ +#include + +#define F_MODRM 0x00000001 +#define F_SIB 0x00000002 +#define F_IMM8 0x00000004 +#define F_IMM16 0x00000008 +#define F_IMM32 0x00000010 +#define F_IMM64 0x00000020 +#define F_DISP8 0x00000040 +#define F_DISP16 0x00000080 +#define F_DISP32 0x00000100 +#define F_RELATIVE 0x00000200 +#define F_ERROR 0x00001000 +#define F_ERROR_OPCODE 0x00002000 +#define F_ERROR_LENGTH 0x00004000 +#define F_ERROR_LOCK 0x00008000 +#define F_ERROR_OPERAND 0x00010000 +#define F_PREFIX_REPNZ 0x01000000 +#define F_PREFIX_REPX 0x02000000 +#define F_PREFIX_REP 0x03000000 +#define F_PREFIX_66 0x04000000 +#define F_PREFIX_67 0x08000000 +#define F_PREFIX_LOCK 0x10000000 +#define F_PREFIX_SEG 0x20000000 +#define F_PREFIX_REX 0x40000000 +#define F_PREFIX_ANY 0x7f000000 + +#define PREFIX_SEGMENT_CS 0x2e +#define PREFIX_SEGMENT_SS 0x36 +#define PREFIX_SEGMENT_DS 0x3e +#define PREFIX_SEGMENT_ES 0x26 +#define PREFIX_SEGMENT_FS 0x64 +#define PREFIX_SEGMENT_GS 0x65 +#define PREFIX_LOCK 0xf0 +#define PREFIX_REPNZ 0xf2 +#define PREFIX_REPX 0xf3 +#define PREFIX_OPERAND_SIZE 0x66 +#define PREFIX_ADDRESS_SIZE 0x67 + +#pragma pack(push,1) + +typedef struct { + uint8_t len; + uint8_t p_rep; + uint8_t p_lock; + uint8_t p_seg; + uint8_t p_66; + uint8_t p_67; + uint8_t rex; + uint8_t rex_w; + uint8_t rex_r; + uint8_t rex_x; + uint8_t rex_b; + uint8_t opcode; + uint8_t opcode2; + uint8_t modrm; + uint8_t modrm_mod; + uint8_t modrm_reg; + uint8_t modrm_rm; + uint8_t sib; + uint8_t sib_scale; + uint8_t sib_index; + uint8_t sib_base; + union { + uint8_t imm8; + uint16_t imm16; + uint32_t imm32; + uint64_t imm64; + } imm; + union { + uint8_t disp8; + uint16_t disp16; + uint32_t disp32; + } disp; + uint32_t flags; +} hde64s; + +#pragma pack(pop) + +#ifdef __cplusplus +extern "C" { +#endif + +/* __cdecl */ +unsigned int hde64_disasm(const void *code, hde64s *hs); + +#ifdef __cplusplus +} +#endif + +#endif /* _HDE64_H_ */ diff --git a/VirtualApp/lib/src/main/jni/Substrate/table64.h b/VirtualApp/lib/src/main/jni/Substrate/table64.h new file mode 100755 index 000000000..144f29076 --- /dev/null +++ b/VirtualApp/lib/src/main/jni/Substrate/table64.h @@ -0,0 +1,74 @@ +/* + * Hacker Disassembler Engine 64 C + * Copyright (c) 2008-2009, Vyacheslav Patkov. + * All rights reserved. + * + */ + +#define C_NONE 0x00 +#define C_MODRM 0x01 +#define C_IMM8 0x02 +#define C_IMM16 0x04 +#define C_IMM_P66 0x10 +#define C_REL8 0x20 +#define C_REL32 0x40 +#define C_GROUP 0x80 +#define C_ERROR 0xff + +#define PRE_ANY 0x00 +#define PRE_NONE 0x01 +#define PRE_F2 0x02 +#define PRE_F3 0x04 +#define PRE_66 0x08 +#define PRE_67 0x10 +#define PRE_LOCK 0x20 +#define PRE_SEG 0x40 +#define PRE_ALL 0xff + +#define DELTA_OPCODES 0x4a +#define DELTA_FPU_REG 0xfd +#define DELTA_FPU_MODRM 0x104 +#define DELTA_PREFIXES 0x13c +#define DELTA_OP_LOCK_OK 0x1ae +#define DELTA_OP2_LOCK_OK 0x1c6 +#define DELTA_OP_ONLY_MEM 0x1d8 +#define DELTA_OP2_ONLY_MEM 0x1e7 + +unsigned char hde64_table[] = { + 0xa5,0xaa,0xa5,0xb8,0xa5,0xaa,0xa5,0xaa,0xa5,0xb8,0xa5,0xb8,0xa5,0xb8,0xa5, + 0xb8,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xac,0xc0,0xcc,0xc0,0xa1,0xa1, + 0xa1,0xa1,0xb1,0xa5,0xa5,0xa6,0xc0,0xc0,0xd7,0xda,0xe0,0xc0,0xe4,0xc0,0xea, + 0xea,0xe0,0xe0,0x98,0xc8,0xee,0xf1,0xa5,0xd3,0xa5,0xa5,0xa1,0xea,0x9e,0xc0, + 0xc0,0xc2,0xc0,0xe6,0x03,0x7f,0x11,0x7f,0x01,0x7f,0x01,0x3f,0x01,0x01,0xab, + 0x8b,0x90,0x64,0x5b,0x5b,0x5b,0x5b,0x5b,0x92,0x5b,0x5b,0x76,0x90,0x92,0x92, + 0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x6a,0x73,0x90, + 0x5b,0x52,0x52,0x52,0x52,0x5b,0x5b,0x5b,0x5b,0x77,0x7c,0x77,0x85,0x5b,0x5b, + 0x70,0x5b,0x7a,0xaf,0x76,0x76,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b, + 0x5b,0x5b,0x86,0x01,0x03,0x01,0x04,0x03,0xd5,0x03,0xd5,0x03,0xcc,0x01,0xbc, + 0x03,0xf0,0x03,0x03,0x04,0x00,0x50,0x50,0x50,0x50,0xff,0x20,0x20,0x20,0x20, + 0x01,0x01,0x01,0x01,0xc4,0x02,0x10,0xff,0xff,0xff,0x01,0x00,0x03,0x11,0xff, + 0x03,0xc4,0xc6,0xc8,0x02,0x10,0x00,0xff,0xcc,0x01,0x01,0x01,0x00,0x00,0x00, + 0x00,0x01,0x01,0x03,0x01,0xff,0xff,0xc0,0xc2,0x10,0x11,0x02,0x03,0x01,0x01, + 0x01,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0x10, + 0x10,0x10,0x10,0x02,0x10,0x00,0x00,0xc6,0xc8,0x02,0x02,0x02,0x02,0x06,0x00, + 0x04,0x00,0x02,0xff,0x00,0xc0,0xc2,0x01,0x01,0x03,0x03,0x03,0xca,0x40,0x00, + 0x0a,0x00,0x04,0x00,0x00,0x00,0x00,0x7f,0x00,0x33,0x01,0x00,0x00,0x00,0x00, + 0x00,0x00,0xff,0xbf,0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0xff,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff, + 0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0x00,0x00, + 0xff,0x40,0x40,0x40,0x40,0x41,0x49,0x40,0x40,0x40,0x40,0x4c,0x42,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x40,0x4f,0x44,0x53,0x40,0x40,0x40,0x44,0x57,0x43, + 0x5c,0x40,0x60,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x40,0x40,0x64,0x66,0x6e,0x6b,0x40,0x40,0x6a,0x46,0x40,0x40,0x44,0x46,0x40, + 0x40,0x5b,0x44,0x40,0x40,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x06,0x01,0x06, + 0x06,0x02,0x06,0x06,0x00,0x06,0x00,0x0a,0x0a,0x00,0x00,0x00,0x02,0x07,0x07, + 0x06,0x02,0x0d,0x06,0x06,0x06,0x0e,0x05,0x05,0x02,0x02,0x00,0x00,0x04,0x04, + 0x04,0x04,0x05,0x06,0x06,0x06,0x00,0x00,0x00,0x0e,0x00,0x00,0x08,0x00,0x10, + 0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x80,0x01,0x82,0x01,0x86,0x00, + 0xf6,0xcf,0xfe,0x3f,0xab,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xba,0xf8,0xbb, + 0x00,0xc0,0x00,0xc1,0x00,0xc7,0xbf,0x62,0xff,0x00,0x8d,0xff,0x00,0xc4,0xff, + 0x00,0xc5,0xff,0x00,0xff,0xff,0xeb,0x01,0xff,0x0e,0x12,0x08,0x00,0x13,0x09, + 0x00,0x16,0x08,0x00,0x17,0x09,0x00,0x2b,0x09,0x00,0xae,0xff,0x07,0xb2,0xff, + 0x00,0xb4,0xff,0x00,0xb5,0xff,0x00,0xc3,0x01,0x00,0xc7,0xff,0xbf,0xe7,0x08, + 0x00,0xf0,0x02,0x00 +}; diff --git a/doc/1.png b/doc/1.png new file mode 100644 index 000000000..a4c7c303a Binary files /dev/null and b/doc/1.png differ diff --git a/doc/2_1.jpg b/doc/2_1.jpg new file mode 100644 index 000000000..e2d7cd5c2 Binary files /dev/null and b/doc/2_1.jpg differ diff --git a/doc/3_1.png b/doc/3_1.png new file mode 100644 index 000000000..70c597f13 Binary files /dev/null and b/doc/3_1.png differ diff --git a/doc/3_2.png b/doc/3_2.png new file mode 100644 index 000000000..d12e958b8 Binary files /dev/null and b/doc/3_2.png differ diff --git a/doc/3_3.png b/doc/3_3.png new file mode 100644 index 000000000..e3811ceb2 Binary files /dev/null and b/doc/3_3.png differ diff --git a/doc/3_4.png b/doc/3_4.png new file mode 100644 index 000000000..27302ad93 Binary files /dev/null and b/doc/3_4.png differ diff --git a/doc/3_5.png b/doc/3_5.png new file mode 100644 index 000000000..2e17bc056 Binary files /dev/null and b/doc/3_5.png differ diff --git a/doc/VADev.md b/doc/VADev.md new file mode 100644 index 000000000..35b920d42 --- /dev/null +++ b/doc/VADev.md @@ -0,0 +1,538 @@ +

VA基础开发文档

+ +本文档主要介绍2部分。 +第一部分是VA的源码结构介绍,这部分是为了让开发者能快速了解掌握VA源码框架。 +第二部分是VA的基础SDK使用说明。 +其他更多的开发文档见:[VA私有库Wiki](https://github.com/asLody/VirtualApp-Priv/wiki) +VA产品说明:[文档](../README.md) +
+ +**下面开始第一部分,VA源码结构介绍:** + +## 1. VA源码目录介绍 ## +下图是VA源码根目录: +![](https://cdn.jsdelivr.net/gh/xxxyanchenxxx/temp@1.0/doc/1.png) +可以看到VA一共有4个源码目录,各个目录介绍如下: + +目录名称 | 作用 +---- | --- +app | VA Demo主包源码所在目录 +app-ext | VA Demo插件包源码所在目录 +lib | VA库源码所在目录 +lib-ext | VA插件库源码所在目录 +
+ +## 2. VA编译配置文件介绍 ## +VA的编译配置文件是VAConfig.gradle: +![](https://cdn.jsdelivr.net/gh/xxxyanchenxxx/temp@1.0/doc/2_1.jpg) + +配置解释: + +配置名称 | 作用 +---- | --- +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处理 +![](https://cdn.jsdelivr.net/gh/xxxyanchenxxx/temp@1.0/doc/3_1.png) +2. `com.lody.virtual.server`包下的代码运行在VA Server进程中,代码主要用于VA Framework中的APP Server部分,实现处理APP安装以及其他不给Android系统处理的APP请求 +![](https://cdn.jsdelivr.net/gh/xxxyanchenxxx/temp@1.0/doc/3_2.png) +3. `mirror`包下的代码主要用于对系统隐藏类的引用,属于工具类,减少大量反射代码的编写 +![](https://cdn.jsdelivr.net/gh/xxxyanchenxxx/temp@1.0/doc/3_3.png) +4. `cpp`包下的代码进行在VAPP Client进程中,主要用于VA Native部分,实现IO重定向和jni函数HOOK。其中: + - `substrate`中实现了针对arm32和arm64的hook + - `vfs.cpp`中实现了VA的虚拟文件系统,用于控制APP文件访问限制 + - `syscall_hook.cpp`中实现了对IO的Hook +![](https://cdn.jsdelivr.net/gh/xxxyanchenxxx/temp@1.0/doc/3_4.png) +5. `DelegateApplicationExt.java`运行在VA Host Plugin进程中,用于VA插件包,实现了对主包代码的加载执行 +![](https://cdn.jsdelivr.net/gh/xxxyanchenxxx/temp@1.0/doc/3_5.png) + +

+**下面开始第二部分,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 + +``` +权限名称必须与**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 +```java +private SettingConfig mConfig = new SettingConfig() { + @Override + public String getMainPackageName() { + // 主包的包名 + return BuildConfig.APPLICATION_ID; + } + + @Override + public String getExtPackageName() { + // 扩展包包名 + return BuildConfig.EXT_PACKAGE_NAME; + } + + @Override + public boolean isEnableIORedirect() { + // 是否启用IO重定向,建议开启 + return true; + } + + @Override + public Intent onHandleLauncherIntent(Intent originIntent) { + // 回到桌面的 Intent 拦截操作,这里把回到桌面的动作改成回到主包的BackHomeActivity页面 + Intent intent = new Intent(); + ComponentName component = new ComponentName(getMainPackageName(), BackHomeActivity.class.getName()); + intent.setComponent(component); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + return intent; + } + + @Override + public boolean isUseRealDataDir(String packageName) { + // data路径模拟真实路径格式,需要启用IO重定向。部分加固会校该验路径格式 + return false; + } + + @Override + public boolean isOutsidePackage(String packageName) { + // 是否是外部app。 设置外部 app 对内部app看见 + return false; + } + + @Override + public boolean isAllowCreateShortcut() { + // 是否允许创建桌面快捷图标。建议关闭(false),自己实现桌面快捷方式 + return false; + } + + @Override + public boolean isHostIntent(Intent intent) { + // 是否由VirtualApp处理的Intent + return intent.getData() != null && "market".equals(intent.getData().getScheme()); + } + + @Override + public boolean isUseRealApkPath(String packageName) { + // 安装apk路径模拟真实路径,需要启用IO重定向。部分加固会校验该路径格式 + return false; + } + + @Override + public boolean isEnableVirtualSdcardAndroidData() { + // 启用外置存储下的 `Android/data` 目录的重定向 + // 需要重定向支持 + // Android 11 之后必须启用!! + return BuildCompat.isR(); + } + + @Override + public String getVirtualSdcardAndroidDataName() { + // 设置外置存储下的 `Android/data` 目录的重定向路径 + // /sdcard/Android/data/com.example.test/ ==>> /sdcard/{VirtualSdcardAndroidDataName}/{user_id}/Android/data/com.example.test/ + return "Android_va"; + } + + @Override + public FakeWifiStatus getFakeWifiStatus() { + // 修改wifi信息。 null 则不修改 + return null; + } + + @Override + public boolean isHideForegroundNotification() { + // 隐藏前台消息,不建议隐藏 + return false; + } + + @Override + public boolean isOutsideAction(String action) { + // 外部 Intent 的 action 事件响应 + return MediaStore.ACTION_IMAGE_CAPTURE.equals(action) + || MediaStore.ACTION_VIDEO_CAPTURE.equals(action) + || Intent.ACTION_PICK.equals(action); + } + + @Override + public boolean isDisableDrawOverlays(String packageName) { + // 禁用 VAPP 的顶层覆盖(浮窗)。 + return false; + } + }; +``` + +### 复写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 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进程说明`](VirualApp进程说明.md),可以知道, +我们只需要在`VAPP进程`回调里(`onVirtualProcess`) 设置App回调 `AppCallback` 就可以达到目的. + +> 宿主Application代码,参考[io/busniess/va/App.java](https://github.com/asLody/VirtualApp-Priv/blob/v2.1/VirtualApp/app/src/main/java/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](https://github.com/asLody/VirtualApp-Priv/blob/v2.1/VirtualApp/app/src/main/java/io/busniess/va/delegate/MyComponentDelegate.java)类代码 + +```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](https://github.com/asLody/VirtualApp-Priv/wiki) + +
+
+ diff --git a/doc/VADev_eng.md b/doc/VADev_eng.md new file mode 100644 index 000000000..c74efb718 --- /dev/null +++ b/doc/VADev_eng.md @@ -0,0 +1,534 @@ +

VA Basic Development Document

+ +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](https://github.com/asLody/VirtualApp-Priv/wiki) +VA Product Description:[Document](../README_eng.md) +
+ +**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: +![](https://cdn.jsdelivr.net/gh/xxxyanchenxxx/temp@1.0/doc/1.png) +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: +![](https://cdn.jsdelivr.net/gh/xxxyanchenxxx/temp@1.0/doc/2_1.jpg) + +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 the`com.lody.virtual.client`package 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. +![](https://cdn.jsdelivr.net/gh/xxxyanchenxxx/temp@1.0/doc/3_1.png) +2. The code under the`com.lody.virtual.server`package 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. +![](https://cdn.jsdelivr.net/gh/xxxyanchenxxx/temp@1.0/doc/3_2.png) +3.The code under the `mirror`package 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. +![](https://cdn.jsdelivr.net/gh/xxxyanchenxxx/temp@1.0/doc/3_3.png) +4.The code under the `cpp`package 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: + - `substrate`implements hook for arm32 and arm64 + - `vfs.cpp`implements VA's virtual file system for controlling APP file access restrictions + - `syscall_hook.cpp`implements Hook for IO +![](https://cdn.jsdelivr.net/gh/xxxyanchenxxx/temp@1.0/doc/3_4.png) +5.`DelegateApplicationExt.java`runs in the VA Host Plugin process,used in the VA plug-in package, implementing the loading and execution to the main package code. +![](https://cdn.jsdelivr.net/gh/xxxyanchenxxx/temp@1.0/doc/3_5.png) + +

+**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 VirtualApp`core library `and `extensions`,while **app** and **app-ext** belong to the`sample 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 + +``` +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 +```java +private SettingConfig mConfig = new SettingConfig() { + @Override + public String getMainPackageName() { + // Name of the main package + return BuildConfig.APPLICATION_ID; + } + + @Override + public String getExtPackageName() { + // Name of extension package + return BuildConfig.EXT_PACKAGE_NAME; + } + + @Override + public boolean isEnableIORedirect() { + // Whether to enable IO redirection, it is recommended to enable + return true; + } + + @Override + public Intent onHandleLauncherIntent(Intent originIntent) { + // Back to the desktop of the Intent interception operation. Here change the action that back to the desktop to return to BackHomeActivity page of the main package. + Intent intent = new Intent(); + ComponentName component = new ComponentName(getMainPackageName(), BackHomeActivity.class.getName()); + intent.setComponent(component); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + return intent; + } + + @Override + public boolean isUseRealDataDir(String packageName) { + // The data path simulates the real path format and requires IO redirection to be enabled. Some of the hardening will check the path format. + return false; + } + + @Override + public boolean isOutsidePackage(String packageName) { + // Whether is an external App. Set the external App to be visible to the internal App. + return false; + } + + @Override + public boolean isAllowCreateShortcut() { + // Whether allow to create desktop shortcut icons. It is recommended to turn off (false) and implement desktop shortcuts by yourself. + return false; + } + + @Override + public boolean isHostIntent(Intent intent) { + // Whether the Intent is handled by VirtualApp. + return intent.getData() != null && "market".equals(intent.getData().getScheme()); + } + + @Override + public boolean isUseRealApkPath(String packageName) { + // The installation apk path simulates the real path and requires IO redirection to be enabled. Some hardening will check the path format. + return false; + } + + @Override + public boolean isEnableVirtualSdcardAndroidData() { + // Enable redirection of `Android/data` directory under external storage. + // Require redirection support. + // Must be enabled after Android 11!! + return BuildCompat.isR(); + } + + @Override + public String getVirtualSdcardAndroidDataName() { + // Set the redirect path for `Android/data` directory under external storage. + // /sdcard/Android/data/com.example.test/ ==>> /sdcard/{VirtualSdcardAndroidDataName}/{user_id}/Android/data/com.example.test/ + return "Android_va"; + } + + @Override + public FakeWifiStatus getFakeWifiStatus() { + // Modify the wifi information. null is not modified. + return null; + } + + @Override + public boolean isHideForegroundNotification() { + // Hide foreground messages, not recommended to hide. + return false; + } + + @Override + public boolean isOutsideAction(String action) { + // Action event response of external Intent. + return MediaStore.ACTION_IMAGE_CAPTURE.equals(action) + || MediaStore.ACTION_VIDEO_CAPTURE.equals(action) + || Intent.ACTION_PICK.equals(action); + } + + @Override + public boolean isDisableDrawOverlays(String packageName) { + // Disable top-level overlay (floating window) for VAPP. + return false; + } + }; +``` + +### 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 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 that`Application`is 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 the`VAPP process`callback(`onVirtualProcess`) set App callback `AppCallback` and then achieve the purpose. + +> Host Application code, please refer [io/busniess/va/App.java](https://github.com/asLody/VirtualApp-Priv/blob/v2.1/VirtualApp/app/src/main/java/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()); + } + }); + } +``` + +> [MyComponentDelegate](https://github.com/asLody/VirtualApp-Priv/blob/v2.1/VirtualApp/app/src/main/java/io/busniess/va/delegate/MyComponentDelegate.java)Class 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.classsload`can use `context.getClassLoader()` or `application.getClassLoader()` both are ok. Afterwards `XposedHelpers`, the same way how to use`XposedBridge`, 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](https://github.com/asLody/VirtualApp-Priv/wiki) + +
+
diff --git a/doc/va_architecture.jpg b/doc/va_architecture.jpg new file mode 100644 index 000000000..aa5d08b15 Binary files /dev/null and b/doc/va_architecture.jpg differ diff --git a/doc/va_process.jpg b/doc/va_process.jpg new file mode 100644 index 000000000..540650418 Binary files /dev/null and b/doc/va_process.jpg differ