Xcubebase_Riru打包部署实践(过反调试、Frida持久化)
Xcubebase_Riru打包部署实践(过反调试、Frida持久化)
一、需求起因
在研究某加壳APP时,发现其做了反调试,无法直接使用frida。使用adb shell查看包名下的进行列表,并结合加固壳特征发现,此app的壳使用了双进程保护,主线程已经被子进程ptrace,并且检测到子进程关闭后,主进程也会自动关闭。由于需求是只需要对其做hook分析即可,经过搜索找到一个曲线救国的方案。
简单来说,此方案的原理即是利用Magisk模块Riru,将frida-gumjs注入到孵化器进程,以达到hook的目的,由于没有调试行为,所以也不会受到反调试的影响
二、打包Xcubebases_riru
此处先介绍xcubebase_riru模块的build,主要的坑都在这里
作者的git项目使用的是版本为10的Riru,而目前最新版本已经到了25,经过测试,直接将此项目clone下来是无法build的,我的做法是参照Riru Demo项目的设置,将Riru的版本升级到25
下面是需要改动的地方
1.gradle文件名
将项目根目录的module.example.gradle文件名修改为module.gradle
2.模块信息
在根目录中的module.gradle文件中,根据自己需要,修改模块的版本、名称、依赖的Riru版本等,根据上文描述,我们将依赖的Riru版本改为25,修改完成后如下图
ext {
moduleLibraryName = "xcube"
moduleMinRiruApiVersion = 10
moduleMinRiruVersionName = "v10.0"
//此处修改Riru依赖版本
moduleRiruApiVersion = 25
// FIXME replace with yours
moduleId = "xcube"
moduleName = "xcube"
moduleAuthor = "xcube"
moduleDescription = "xcube module ."
moduleVersion = "v1.0"
moduleVersionCode = 1
moduleProp = [
name : moduleName,
version : moduleVersion,
versionCode: moduleVersionCode.toString(),
author : moduleAuthor,
description: moduleDescription,
minApi : moduleMinRiruApiVersion
]
magiskModuleProp = [
id : "riru-${moduleId.replace('_', '-')}",
name : "Riru - ${moduleProp['name']}",
version : moduleProp['version'],
versionCode: moduleProp['versionCode'],
author : moduleProp['author'],
description: moduleProp['description']
]
}
3.其他配置信息
根目录build.gradle
module目录下的build.gradle
CMakeLists.txt
可能会有一些非必要修改,但是我们尽量和官方demo保持一致
4.添加frida-gumjs
在frida的Release页面找到frida-gumjs引擎库
这里我们把arm架构的32位和64位包都下载下来,解压缩,然后放到/main/cpp对应的ABI下,如下图
到这一步为止,项目执行Sync应该不会再报错了。
5.尝试build模块
如下图,执行gradle尝试build
正常情况下会报错,错误位置在main.cpp中,主要原因是我们升级了Riru到版本25,Riru版本25和9的写法有些差异,参照Riru Demo项目对main.cpp做一些修改,具体修改如下,将extern "C"里的代码全部用demo项目替换
extern "C" {
int riru_api_version;
const char *riru_magisk_module_path = nullptr;
int *riru_allow_unload = nullptr;
static auto module = RiruVersionedModuleInfo{
.moduleApiVersion = RIRU_MODULE_API_VERSION,
.moduleInfo= RiruModuleInfo{
.supportHide = true,
.version = RIRU_MODULE_VERSION,
.versionName = RIRU_MODULE_VERSION_NAME,
.onModuleLoaded = onModuleLoaded,
.forkAndSpecializePre = forkAndSpecializePre,
.forkAndSpecializePost = forkAndSpecializePost,
.forkSystemServerPre = forkSystemServerPre,
.forkSystemServerPost = forkSystemServerPost,
.specializeAppProcessPre = specializeAppProcessPre,
.specializeAppProcessPost = specializeAppProcessPost
}
};
#ifndef RIRU_MODULE_LEGACY_INIT
RiruVersionedModuleInfo *init(Riru *riru) {
auto core_max_api_version = riru->riruApiVersion;
riru_api_version = core_max_api_version <= RIRU_MODULE_API_VERSION ? core_max_api_version : RIRU_MODULE_API_VERSION;
module.moduleApiVersion = riru_api_version;
riru_magisk_module_path = strdup(riru->magiskModulePath);
if (riru_api_version >= 25) {
riru_allow_unload = riru->allowUnload;
}
return &module;
}
#else
RiruVersionedModuleInfo *init(Riru *riru) {
static int step = 0;
step += 1;
switch (step) {
case 1: {
auto core_max_api_version = riru->riruApiVersion;
riru_api_version = core_max_api_version <= RIRU_MODULE_API_VERSION ? core_max_api_version : RIRU_MODULE_API_VERSION;
if (riru_api_version < 25) {
module.moduleInfo.unused = (void *) shouldSkipUid;
} else {
riru_allow_unload = riru->allowUnload;
}
if (riru_api_version >= 24) {
module.moduleApiVersion = riru_api_version;
riru_magisk_module_path = strdup(riru->magiskModulePath);
return &module;
} else {
return (RiruVersionedModuleInfo *) &riru_api_version;
}
}
case 2: {
return (RiruVersionedModuleInfo *) &module.moduleInfo;
}
case 3:
default: {
return nullptr;
}
}
}
#endif
}
重新执行build,这时在out目录下应该有导出了
三、安装与测试
1.刷入
Magisk需要先刷入Riru-Core,版本为25以上,然后将导出的zip包推送到手机目录,通过Magisk刷入,以上操作完成后,重启手机。如果刷入出错,需要检查Riru版本是否正确。
2.准备测试app
我编写了一个简单的安卓app用于测试,功能是点击button,中间的textview控件文本会被修改为当前的系统时间戳,如下图
MainActivity代码
package com.xxy.testapp;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void clickbt(View v)
{
TextView tv = (TextView)findViewById(R.id.tv);
tv.setText(GetText());
}
public String GetText()
{
return String.valueOf(System.currentTimeMillis());
}
}
3.准备测试用frida脚本
console.log('attach!');
setTimeout(function(){
try {
Java.perform(function(){
Java.use('com.xxy.testapp.MainActivity').GetText.implementation = function(){
console.log('hooked!');
return "hooked!";
};
});
} catch (error) {
log(error);
}
},100);
上述测试代码的功能是hook目标app点击按钮的方法,将返回值由原来的时间戳替换为"hooked!"
4.推送和hook配置
Xcubebase_riru的hook目标包名和注入的js分别为/data/local/tmp下的pkg.conf和myscript.js,其中hook包名可以写多个,每行一个。修改pkg.conf,加入待测试的app包名,并推送我们的frida脚本到myscript.js,重新打开应用测试,测试效果如下图
5.logcat输出
在logcat可以看到frida的输出信息
四、资源下载
已经打包好的zip包,基于frida14.2.18
标题:Xcubebase_Riru打包部署实践(过反调试、Frida持久化)
作者:Cubeeeee
地址:http://blog.nps.fuguicun.com/articles/2021/07/14/1626252580981.html