我之前是这么做的,编写一个riru插件:
#include <jni.h>
#include <sys/types.h>
#include <riru.h>
#include <malloc.h>
#include <cstring>
#include <config.h>
#include <unistd.h>
#include <pthread.h>
#include <android/log.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <dlfcn.h>
//#include <stdio.h>
#define LOGTAG "test_fridahook"
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOGTAG , __VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG , LOGTAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO , LOGTAG, __VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN , LOGTAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR , LOGTAG, __VA_ARGS__)
#if defined(__arm__)
//#include "includes/armeabi-v7a/frida-gumjs.h"
#elif defined(__aarch64__)
//#include "includes/arm64-v8a/frida-gumjs.h"
#endif
int mysystem(char *cmdstring, char *buf, int len);
static int enable_hack;
static jstring *_appDataDir;
static char package_name[256];
const char *sopath = "/data/local/tmp/libfg1502.so";
// 仅在测试app生效
int rirutest(JNIEnv *env, jstring appDataDir) {
if (!appDataDir) {
LOGD("forkAndSpecializePre appDataDir null");
return 0;
}
const char *app_data_dir = env->GetStringUTFChars(appDataDir, NULL);
int user = 0;
if (sscanf(app_data_dir, "/data/%*[^/]/%d/%s", &user, package_name) != 2) {
if (sscanf(app_data_dir, "/data/%*[^/]/%s", package_name) != 1) {
package_name[0] = '\0';
LOGW("can't parse %s", app_data_dir);
env->ReleaseStringUTFChars(appDataDir, app_data_dir);
return 0;
}
}
env->ReleaseStringUTFChars(appDataDir, app_data_dir);
// LOGD("package [ %s ] starting...", package_name);
char cmd_string[1024];
const char *filepath = "/data/local/tmp/pkg.conf";
sprintf(cmd_string, "cat %s", filepath);
int bufsize = 1024 * 10;
char buf[bufsize];
mysystem(cmd_string, buf, bufsize);
int ret = 0;
char *item = NULL;
char *delims = "\r\n";
item = strtok(buf, delims);
while (item != NULL) {
// LOGD("package item: %s", item);
if (strcmp(item, package_name) == 0) {
ret = 1;
LOGD("package item: %s", item);
break;
} else {
ret = 0;
}
item = strtok(NULL, delims);
}
return ret;
}
// 用readjs方法中的方式比较简单,但是由于尝试在zygote进程中读取文件,才试到这里的方法
// 这个方法作为一个通用方法就不改回去了
int mysystem(char *cmdstring, char *buf, int len) {
int fd[2];
pid_t pid;
int n, count;
memset(buf, 0, len);
if (pipe(fd) < 0)
return -1;
if ((pid = fork()) < 0){
LOGE("fork faild");
return -1;
}
else if (pid > 0) {
close(fd[1]);
count = 0;
while ((n = read(fd[0], buf + count, len)) > 0 && count > len)
count += n;
close(fd[0]);
if (waitpid(pid, NULL, 0) > 0)
return -1;
} else {
close(fd[0]);
if (fd[1] != STDOUT_FILENO) {
if (dup2(fd[1], STDOUT_FILENO) != STDOUT_FILENO) {
return -1;
}
close(fd[1]);
}
if (execl("/system/bin/sh", "sh", "-c", cmdstring, (char *) 0) == -1){
LOGE("execl (%s) faild", cmdstring);
return -1;
}
}
return 0;
}
static void forkAndSpecializePre(
JNIEnv *env, jclass clazz, jint *uid, jint *gid, jintArray *gids, jint *runtimeFlags,
jobjectArray *rlimits, jint *mountExternal, jstring *seInfo, jstring *niceName,
jintArray *fdsToClose, jintArray *fdsToIgnore, jboolean *is_child_zygote,
jstring *instructionSet, jstring *appDataDir, jboolean *isTopApp, jobjectArray *pkgDataInfoList,
jobjectArray *whitelistedDataInfoList, jboolean *bindMountAppDataDirs, jboolean *bindMountAppStorageDirs) {
// Called "before" com_android_internal_os_Zygote_nativeForkAndSpecialize in frameworks/base/core/jni/com_android_internal_os_Zygote.cpp
// Parameters are pointers, you can change the value of them if you want
// Some parameters are not exist is older Android versions, in this case, they are null or 0
_appDataDir = appDataDir;
}
static void forkAndSpecializePost(JNIEnv *env, jclass clazz, jint res) {
// Called "after" com_android_internal_os_Zygote_nativeForkAndSpecialize in frameworks/base/core/jni/com_android_internal_os_Zygote.cpp
// "res" is the return value of com_android_internal_os_Zygote_nativeForkAndSpecialize
if (res == 0) {
// In app process
enable_hack = rirutest(env, *_appDataDir);
if (enable_hack) {
char cmd_string[1024];
const char *filepath = "/data/local/tmp/";
sprintf(cmd_string, "%s%s/libtest.so", filepath, package_name);
LOGE("Start Load Library");
void* handle = dlopen( cmd_string, RTLD_LAZY );
if( handle != 0) {
LOGE("Load %s success!", cmd_string);
}
else {
LOGE("Load %s failed! dlopen failed: %s\n", cmd_string, dlerror());
}
}
// When unload allowed is true, the module will be unloaded (dlclose) by Riru
// If this modules has hooks installed, DONOT set it to true, or there will be SIGSEGV
// This value will be automatically reset to false before the "pre" function is called
riru_set_unload_allowed(true);
} else {
// In zygote process
}
}
static void specializeAppProcessPre(
JNIEnv *env, jclass clazz, jint *uid, jint *gid, jintArray *gids, jint *runtimeFlags,
jobjectArray *rlimits, jint *mountExternal, jstring *seInfo, jstring *niceName,
jboolean *startChildZygote, jstring *instructionSet, jstring *appDataDir,
jboolean *isTopApp, jobjectArray *pkgDataInfoList, jobjectArray *whitelistedDataInfoList,
jboolean *bindMountAppDataDirs, jboolean *bindMountAppStorageDirs) {
// Called "before" com_android_internal_os_Zygote_nativeSpecializeAppProcess in frameworks/base/core/jni/com_android_internal_os_Zygote.cpp
// Parameters are pointers, you can change the value of them if you want
// Some parameters are not exist is older Android versions, in this case, they are null or 0
}
static void specializeAppProcessPost(
JNIEnv *env, jclass clazz) {
// Called "after" com_android_internal_os_Zygote_nativeSpecializeAppProcess in frameworks/base/core/jni/com_android_internal_os_Zygote.cpp
// When unload allowed is true, the module will be unloaded (dlclose) by Riru
// If this modules has hooks installed, DONOT set it to true, or there will be SIGSEGV
// This value will be automatically reset to false before the "pre" function is called
riru_set_unload_allowed(true);
}
static void forkSystemServerPre(
JNIEnv *env, jclass clazz, uid_t *uid, gid_t *gid, jintArray *gids, jint *runtimeFlags,
jobjectArray *rlimits, jlong *permittedCapabilities, jlong *effectiveCapabilities) {
// Called "before" com_android_internal_os_Zygote_forkSystemServer in frameworks/base/core/jni/com_android_internal_os_Zygote.cpp
// Parameters are pointers, you can change the value of them if you want
// Some parameters are not exist is older Android versions, in this case, they are null or 0
}
static void forkSystemServerPost(JNIEnv *env, jclass clazz, jint res) {
// Called "after" com_android_internal_os_Zygote_forkSystemServer in frameworks/base/core/jni/com_android_internal_os_Zygote.cpp
if (res == 0) {
// In system server process
} else {
// In zygote process
}
}
static void onModuleLoaded() {
// Called when this library is loaded and "hidden" by Riru (see Riru's hide.cpp)
// If you want to use threads, start them here rather than the constructors
// __attribute__((constructor)) or constructors of static variables,
// or the "hide" will cause SIGSEGV
}
extern "C" {
int riru_api_version;
const char *riru_magisk_module_path = nullptr;
int *riru_allow_unload = nullptr;
static auto module = RiruVersionedModuleInfo{
.moduleApiVersion = riru::moduleApiVersion,
.moduleInfo= RiruModuleInfo{
.supportHide = true,
.version = riru::moduleVersionCode,
.versionName = riru::moduleVersionName,
.onModuleLoaded = onModuleLoaded,
.forkAndSpecializePre = forkAndSpecializePre,
.forkAndSpecializePost = forkAndSpecializePost,
.forkSystemServerPre = forkSystemServerPre,
.forkSystemServerPost = forkSystemServerPost,
.specializeAppProcessPre = specializeAppProcessPre,
.specializeAppProcessPost = specializeAppProcessPost
}
};
RiruVersionedModuleInfo *init(Riru *riru) {
auto core_max_api_version = riru->riruApiVersion;
riru_api_version = core_max_api_version <= riru::moduleApiVersion ? core_max_api_version : riru::moduleApiVersion;
module.moduleApiVersion = riru_api_version;
riru_magisk_module_path = strdup(riru->magiskModulePath);
if (riru_api_version >= 25) {
riru_allow_unload = riru->allowUnload;
}
return &module;
}
}
看gadget源码,加载conf的规则:
https://github.com/frida/frida-core/blob/0120cf59bc6f623bb842c93bc8870ce2a704453c/lib/gadget/gadget.vala
private string derive_config_path_from_file_path (string path) {
var dirname = Path.get_dirname (path);
var filename = Path.get_basename (path);
string stem;
var ext_index = filename.last_index_of_char ('.');
if (ext_index != -1)
stem = filename[0:ext_index];
else
stem = filename;
return Path.build_filename (dirname, stem + ".config");
}
private Config load_config (Location location) throws Error {
unowned string? gadget_path = location.path;
if (gadget_path == null)
return new Config ();
var config_path = derive_config_path_from_file_path (gadget_path);
#if IOS
if (!FileUtils.test (config_path, FileTest.EXISTS)) {
var config_dir = Path.get_dirname (config_path);
if (Path.get_basename (config_dir) == "Frameworks") {
var app_dir = Path.get_dirname (config_dir);
config_path = Path.build_filename (app_dir, Path.get_basename (config_path));
}
}
#endif
#if ANDROID
if (!FileUtils.test (config_path, FileTest.EXISTS)) {
var ext_index = config_path.last_index_of_char ('.');
if (ext_index != -1) {
config_path = config_path[0:ext_index] + ".config.so";
} else {
config_path = config_path + ".config.so";
}
}
#endif
简单的说,如果能找到当前so所在的路径下的xxx.config。如果找不到,又是安卓环境下,那么就就在/data/app/xxxx.xxx.xxx-xxxx(对应包名)/lib目录下,加载xxx.config.so(需要提前将config.so文件放到apk下,这就需要重打包了)。
所以可以直接将frida-gadget重命名为libtest.so 丢到目录(/data/local/tmp/xxxx.xxx.xxx-xxxx/),也就是需要注入的目标的包下,然后同级目录下放入:libtest.config,这个config名字必须与修改frida-gadget重命名libtest相同。
config中就可以指定加载的js了:
{
"interaction": {
"type": "script",
"path": "/data/local/tmp/test.js"
}
}
frida-gadget支持4种模式,默认是监听127.0.0.1:27012,会卡死app,所以这里采用的是script模式,指定加载的脚本路径。
也可以:
{
"interaction": {
"type": "listen",
"address": "127.0.0.1",
"port": 27042,
"on_load": "wait"
}
}
然后objection可以连接了:
objection -h 192.168.0.x -p 27042 explore
到这里就可以指定app加载frida-gadget,然后执行你的脚本,无需重打包。
综上,使用方法是:
1. 安装上面编译好的riru插件。
2. 在/data/local/tmp目录下,新建文件pkg.conf 一行写一个需要hook的apk包名。
3. 将frida-gadget下载下来重命名为libtest.so,对应的config为libtest.conf,丢到/data/local/tmp/xxxx.xxx.xxx-xxxx/。
4. 在配置文件中写入需要注入的js路径即可。
这样麻烦的一点就是每一个app都要到对应的包目录下放一个gadget...
最后于 2021-8-16 21:08
被batstying编辑
,原因: