Compare commits
4 Commits
addJavaInj
...
update-rea
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
14ad58ec74 | ||
|
|
7d5a626750 | ||
|
|
be5208409d | ||
|
|
fd5799cc95 |
61
README.md
61
README.md
@@ -1,21 +1,48 @@
|
|||||||
# Zygisk-Il2CppDumper
|
# [Zygisk-MyInjector](https://github.com/jiqiu2022/Zygisk-MyInjector)
|
||||||
Il2CppDumper with Zygisk, dump il2cpp data at runtime, can bypass protection, encryption and obfuscation.
|
|
||||||
|
|
||||||
中文说明请戳[这里](README.zh-CN.md)
|
|
||||||
|
|
||||||
## How to use
|
|
||||||
1. Install [Magisk](https://github.com/topjohnwu/Magisk) v24 or later and enable Zygisk
|
原项目https://github.com/Perfare/Zygisk-Il2CppDumper
|
||||||
2. Build module
|
|
||||||
|
本项目在原项目基础上做局部更改,请支持原项目作者劳动成果
|
||||||
|
|
||||||
|
1. 安装[Magisk](https://github.com/topjohnwu/Magisk) v24以上版本并开启Zygisk
|
||||||
|
2. 生成模块
|
||||||
- GitHub Actions
|
- GitHub Actions
|
||||||
1. Fork this repo
|
1. Fork这个项目
|
||||||
2. Go to the **Actions** tab in your forked repo
|
2. 在你fork的项目中选择**Actions**选项卡
|
||||||
3. In the left sidebar, click the **Build** workflow.
|
3. 在左边的侧边栏中,单击**Build**
|
||||||
4. Above the list of workflow runs, select **Run workflow**
|
4. 选择**Run workflow**
|
||||||
5. Input the game package name and click **Run workflow**
|
5. 输入游戏包名并点击**Run workflow**
|
||||||
6. Wait for the action to complete and download the artifact
|
6. 等待操作完成并下载
|
||||||
- Android Studio
|
- Android Studio
|
||||||
1. Download the source code
|
1. 下载源码
|
||||||
2. Edit `game.h`, modify `AimPackageName` to the game package name
|
2. 编辑`game.h`, 修改`GamePackageName`为游戏包名
|
||||||
3. Use Android Studio to run the gradle task `:module:assembleRelease` to compile, the zip package will be generated in the `out` folder
|
3. 使用Android Studio运行gradle任务`:module:assembleRelease`编译,zip包会生成在`out`文件夹下
|
||||||
3. Install module in Magisk
|
3. 在Magisk里安装模块
|
||||||
4. Start the game, `dump.cs` will be generated in the `/data/data/AimPackageName/files/` directory
|
|
||||||
|
4. 将要注入的so放入到/data/local/tmp下修改为test.so
|
||||||
|
|
||||||
|
(部分手机第一次注入不会成功,请重启,再之后的注入会成功)
|
||||||
|
|
||||||
|
目前正在开发的分支:
|
||||||
|
|
||||||
|
1. 使用Java的System.load加载so
|
||||||
|
|
||||||
|
2. 注入多个so的分支
|
||||||
|
|
||||||
|
计划开发:
|
||||||
|
|
||||||
|
1. 第一步,仿照Riru,将注入的so进行内存上的初步隐藏(可以对抗部分业务检测,游戏安全相关已经补齐,建议不要尝试)
|
||||||
|
2. 第二步,实现一个自定义的linker,进行更深层次的注入隐藏
|
||||||
|
3. 第三步,搭配对应配套手机的内核模块对注入的模块进行进一步完美擦除,达到完美注入的目的
|
||||||
|
|
||||||
|
以此项目为脚手架的计划开发:
|
||||||
|
|
||||||
|
1. 一个全新的Frida框架,保留大部分原生api,并可以过任何相关注入检测
|
||||||
|
|
||||||
|
2. 一个全新的Trace框架,高性能Trace,速度是Stallker的60倍,并且支持更全面的信息打印。(具体效果可以参考看雪帖子)
|
||||||
|
|
||||||
|
3. 一个全新的无痕调试框架,支持像GDB一样调试,没有ptrace痕迹,两种思路进行无痕调试(基于硬件断点以及基于VM)
|
||||||
|
|
||||||
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
# Zygisk-Il2CppDumper
|
|
||||||
Zygisk版Il2CppDumper,在游戏运行时dump il2cpp数据,可以绕过保护,加密以及混淆。
|
|
||||||
|
|
||||||
## 如何食用
|
|
||||||
1. 安装[Magisk](https://github.com/topjohnwu/Magisk) v24以上版本并开启Zygisk
|
|
||||||
2. 生成模块
|
|
||||||
- GitHub Actions
|
|
||||||
1. Fork这个项目
|
|
||||||
2. 在你fork的项目中选择**Actions**选项卡
|
|
||||||
3. 在左边的侧边栏中,单击**Build**
|
|
||||||
4. 选择**Run workflow**
|
|
||||||
5. 输入游戏包名并点击**Run workflow**
|
|
||||||
6. 等待操作完成并下载
|
|
||||||
- Android Studio
|
|
||||||
1. 下载源码
|
|
||||||
2. 编辑`game.h`, 修改`AimPackageName`为游戏包名
|
|
||||||
3. 使用Android Studio运行gradle任务`:module:assembleRelease`编译,zip包会生成在`out`文件夹下
|
|
||||||
3. 在Magisk里安装模块
|
|
||||||
4. 启动游戏,会在`/data/data/AimPackageName/files/`目录下生成`dump.cs`
|
|
||||||
@@ -4,6 +4,6 @@ ext {
|
|||||||
moduleName = "myinjector"
|
moduleName = "myinjector"
|
||||||
moduleAuthor = "jiqiu2021"
|
moduleAuthor = "jiqiu2021"
|
||||||
moduleDescription = "注入任意SO到指定APP内"
|
moduleDescription = "注入任意SO到指定APP内"
|
||||||
moduleVersion = "v0.02"
|
moduleVersion = "v0.01"
|
||||||
moduleVersionCode = 1
|
moduleVersionCode = 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,6 @@
|
|||||||
#ifndef ZYGISK_IL2CPPDUMPER_GAME_H
|
#ifndef ZYGISK_IL2CPPDUMPER_GAME_H
|
||||||
#define ZYGISK_IL2CPPDUMPER_GAME_H
|
#define ZYGISK_IL2CPPDUMPER_GAME_H
|
||||||
|
|
||||||
#define AimPackageName "re.pwnme"
|
#define AimPackageName "com.tencent.mobileqq"
|
||||||
|
|
||||||
#endif //ZYGISK_IL2CPPDUMPER_GAME_H
|
#endif //ZYGISK_IL2CPPDUMPER_GAME_H
|
||||||
|
|||||||
@@ -18,48 +18,33 @@
|
|||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
//#include <asm-generic/fcntl.h>
|
//#include <asm-generic/fcntl.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
void load_so(const char *game_data_dir, JavaVM *vm, const char *soname) {
|
||||||
void hack_start(const char *game_data_dir) {
|
|
||||||
bool load = false;
|
bool load = false;
|
||||||
LOGI("hack_start %s", game_data_dir);
|
LOGI("hack_start %s", game_data_dir);
|
||||||
// 构建 files 目录路径
|
|
||||||
char files_dir[256];
|
|
||||||
snprintf(files_dir, sizeof(files_dir), "%s/files", game_data_dir);
|
|
||||||
|
|
||||||
// 检查 files 目录是否存在
|
// 构建新文件路径,使用传入的 soname 参数
|
||||||
struct stat st = {0};
|
|
||||||
if (stat(files_dir, &st) == -1) {
|
|
||||||
LOGI("%s directory does not exist, creating...", files_dir);
|
|
||||||
|
|
||||||
// 创建目录并赋予 0755 权限
|
|
||||||
if (mkdir(files_dir, 0755) != 0) {
|
|
||||||
LOGE("Failed to create directory %s: %s (errno: %d)", files_dir, strerror(errno), errno);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
LOGI("Successfully created directory %s with 0755 permissions", files_dir);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
LOGI("Directory %s already exists", files_dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 构建新文件路径
|
|
||||||
char new_so_path[256];
|
char new_so_path[256];
|
||||||
snprintf(new_so_path, sizeof(new_so_path), "%s/test.so", files_dir);
|
snprintf(new_so_path, sizeof(new_so_path), "%s/files/%s.so", game_data_dir, soname);
|
||||||
|
|
||||||
// 复制 /sdcard/test.so 到 game_data_dir 并重命名
|
// 构建源文件路径
|
||||||
const char *src_path = "/data/local/tmp/test.so";
|
char src_path[256];
|
||||||
|
snprintf(src_path, sizeof(src_path), "/data/local/tmp/%s.so", soname);
|
||||||
|
|
||||||
|
// 打开源文件
|
||||||
int src_fd = open(src_path, O_RDONLY);
|
int src_fd = open(src_path, O_RDONLY);
|
||||||
if (src_fd < 0) {
|
if (src_fd < 0) {
|
||||||
LOGE("Failed to open %s: %s (errno: %d)", src_path, strerror(errno), errno);
|
LOGE("Failed to open %s: %s (errno: %d)", src_path, strerror(errno), errno);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 打开目标文件
|
||||||
int dest_fd = open(new_so_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
int dest_fd = open(new_so_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||||
if (dest_fd < 0) {
|
if (dest_fd < 0) {
|
||||||
LOGE("Failed to open %s", new_so_path);
|
LOGE("Failed to open %s", new_so_path);
|
||||||
close(src_fd);
|
close(src_fd);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 复制文件内容
|
// 复制文件内容
|
||||||
char buffer[4096];
|
char buffer[4096];
|
||||||
ssize_t bytes;
|
ssize_t bytes;
|
||||||
@@ -72,104 +57,51 @@ void hack_start(const char *game_data_dir) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 关闭文件描述符
|
||||||
close(src_fd);
|
close(src_fd);
|
||||||
close(dest_fd);
|
close(dest_fd);
|
||||||
|
|
||||||
|
// 修改文件权限
|
||||||
if (chmod(new_so_path, 0755) != 0) {
|
if (chmod(new_so_path, 0755) != 0) {
|
||||||
LOGE("Failed to change permissions on %s: %s (errno: %d)", new_so_path, strerror(errno), errno);
|
LOGE("Failed to change permissions on %s: %s (errno: %d)", new_so_path, strerror(errno), errno);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
LOGI("Successfully changed permissions to 755 on %s", new_so_path);
|
LOGI("Successfully changed permissions to 755 on %s", new_so_path);
|
||||||
}
|
}
|
||||||
JavaVM* vm;
|
|
||||||
auto libart = dlopen("libart.so", RTLD_NOW);
|
|
||||||
auto JNI_GetCreatedJavaVMs = (jint (*)(JavaVM **, jsize, jsize *)) dlsym(libart,
|
|
||||||
"JNI_GetCreatedJavaVMs");
|
|
||||||
LOGI("JNI_GetCreatedJavaVMs %p", JNI_GetCreatedJavaVMs);
|
|
||||||
JavaVM *vms_buf[1];
|
|
||||||
jsize num_vms;
|
|
||||||
jint status = JNI_GetCreatedJavaVMs(vms_buf, 1, &num_vms);
|
|
||||||
if (status == JNI_OK && num_vms > 0) {
|
|
||||||
vm = vms_buf[0];
|
|
||||||
} else {
|
|
||||||
LOGE("GetCreatedJavaVMs error");
|
|
||||||
return ;
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEnv *env = nullptr;
|
// 加载 .so 文件
|
||||||
bool needDetach = false;
|
void *handle;
|
||||||
jint getEnvStat = vm->GetEnv((void **)&env, JNI_VERSION_1_6);
|
|
||||||
if (getEnvStat == JNI_EDETACHED) {
|
|
||||||
LOGI("Thread not attached, attaching...");
|
|
||||||
if (vm->AttachCurrentThread(&env, NULL) != 0) {
|
|
||||||
LOGE("Failed to attach current thread");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
needDetach = true;
|
|
||||||
} else if (getEnvStat == JNI_OK) {
|
|
||||||
LOGI("Thread already attached");
|
|
||||||
} else if (getEnvStat == JNI_EVERSION) {
|
|
||||||
LOGE("JNI version not supported");
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
LOGE("Failed to get the environment using GetEnv, error code: %d", getEnvStat);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (env != nullptr) {
|
|
||||||
jclass systemClass = env->FindClass("java/lang/System");
|
|
||||||
if (systemClass == NULL) {
|
|
||||||
LOGE("Failed to find java/lang/System class");
|
|
||||||
} else {
|
|
||||||
jmethodID loadMethod = env->GetStaticMethodID(systemClass, "load", "(Ljava/lang/String;)V");
|
|
||||||
if (loadMethod == NULL) {
|
|
||||||
LOGE("Failed to find System.load method");
|
|
||||||
} else {
|
|
||||||
jstring jLibPath = env->NewStringUTF(new_so_path);
|
|
||||||
env->CallStaticVoidMethod(systemClass, loadMethod, jLibPath);
|
|
||||||
if (env->ExceptionCheck()) {
|
|
||||||
env->ExceptionDescribe();
|
|
||||||
LOGE("Exception occurred while calling System.load %s",new_so_path);
|
|
||||||
env->ExceptionClear();
|
|
||||||
} else {
|
|
||||||
LOGI("Successfully loaded %s using System.load", new_so_path);
|
|
||||||
load = true;
|
|
||||||
}
|
|
||||||
env->DeleteLocalRef(jLibPath);
|
|
||||||
}
|
|
||||||
env->DeleteLocalRef(systemClass);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!load) {
|
|
||||||
LOGI("Attempting to load %s using dlopen", new_so_path);
|
|
||||||
void * handle;
|
|
||||||
for (int i = 0; i < 10; i++) {
|
for (int i = 0; i < 10; i++) {
|
||||||
handle = dlopen(new_so_path, RTLD_NOW | RTLD_LOCAL);
|
handle = dlopen(new_so_path, RTLD_NOW | RTLD_LOCAL);
|
||||||
if (handle) {
|
if (handle) {
|
||||||
LOGI("Successfully loaded %s using dlopen", new_so_path);
|
LOGI("Successfully loaded %s", new_so_path);
|
||||||
load = true;
|
load = true;
|
||||||
void (*JNI_OnLoad)(JavaVM *, void *);
|
|
||||||
*(void **) (&JNI_OnLoad) = dlsym(handle, "JNI_OnLoad");
|
|
||||||
if (JNI_OnLoad) {
|
|
||||||
LOGI("JNI_OnLoad symbol found, calling JNI_OnLoad.");
|
|
||||||
JNI_OnLoad(vm, NULL);
|
|
||||||
} else {
|
|
||||||
LOGE("JNI_OnLoad symbol not found in %s", new_so_path);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
LOGE("Failed to load %s: %s", new_so_path, dlerror());
|
LOGE("Failed to load %s: %s", new_so_path, dlerror());
|
||||||
sleep(1);
|
sleep(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// 如果加载失败
|
||||||
if (!load) {
|
if (!load) {
|
||||||
LOGI("Failed to load test.so in thread %d", gettid());
|
LOGI("%s.so not found in thread %d", soname, gettid());
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 查找 JNI_OnLoad 并调用
|
||||||
|
// void (*setupSignalHandler)();
|
||||||
|
// *(void **) (&setupSignalHandler) = dlsym(handle, "setupSignalHandler");
|
||||||
|
//
|
||||||
|
// if (setupSignalHandler) {
|
||||||
|
// LOGI("setupSignalHandler symbol found, calling setupSignalHandler.");
|
||||||
|
// setupSignalHandler(); // 调用找到的函数
|
||||||
|
// } else {
|
||||||
|
// LOGE("setupSignalHandler symbol not found in %s", new_so_path);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
void hack_start(const char *game_data_dir,JavaVM *vm) {
|
||||||
|
load_so(game_data_dir,vm,"test");
|
||||||
|
//如果要注入多个so,那么就在这里不断的添加load_so函数即可
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GetLibDir(JavaVM *vms) {
|
std::string GetLibDir(JavaVM *vms) {
|
||||||
@@ -330,7 +262,7 @@ void hack_prepare(const char *_data_dir, void *data, size_t length) {
|
|||||||
#if defined(__i386__) || defined(__x86_64__)
|
#if defined(__i386__) || defined(__x86_64__)
|
||||||
if (!NativeBridgeLoad(_data_dir, api_level, data, length)) {
|
if (!NativeBridgeLoad(_data_dir, api_level, data, length)) {
|
||||||
#endif
|
#endif
|
||||||
hack_start(_data_dir);
|
hack_start(_data_dir, nullptr);
|
||||||
#if defined(__i386__) || defined(__x86_64__)
|
#if defined(__i386__) || defined(__x86_64__)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -340,7 +272,7 @@ void hack_prepare(const char *_data_dir, void *data, size_t length) {
|
|||||||
|
|
||||||
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
|
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
|
||||||
auto game_data_dir = (const char *) reserved;
|
auto game_data_dir = (const char *) reserved;
|
||||||
std::thread hack_thread(hack_start, game_data_dir);
|
std::thread hack_thread(hack_start, game_data_dir,vm);
|
||||||
hack_thread.detach();
|
hack_thread.detach();
|
||||||
return JNI_VERSION_1_6;
|
return JNI_VERSION_1_6;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,11 @@ public:
|
|||||||
void preAppSpecialize(AppSpecializeArgs *args) override {
|
void preAppSpecialize(AppSpecializeArgs *args) override {
|
||||||
auto package_name = env->GetStringUTFChars(args->nice_name, nullptr);
|
auto package_name = env->GetStringUTFChars(args->nice_name, nullptr);
|
||||||
auto app_data_dir = env->GetStringUTFChars(args->app_data_dir, nullptr);
|
auto app_data_dir = env->GetStringUTFChars(args->app_data_dir, nullptr);
|
||||||
LOGI("preAppSpecialize %s %s", package_name, app_data_dir);
|
// if (strcmp(package_name, AimPackageName) == 0){
|
||||||
|
// args->runtime_flags=8451;
|
||||||
|
// }
|
||||||
|
LOGI("preAppSpecialize %s %s %d", package_name, app_data_dir,args->runtime_flags);
|
||||||
|
|
||||||
preSpecialize(package_name, app_data_dir);
|
preSpecialize(package_name, app_data_dir);
|
||||||
env->ReleaseStringUTFChars(args->nice_name, package_name);
|
env->ReleaseStringUTFChars(args->nice_name, package_name);
|
||||||
env->ReleaseStringUTFChars(args->app_data_dir, app_data_dir);
|
env->ReleaseStringUTFChars(args->app_data_dir, app_data_dir);
|
||||||
|
|||||||
Reference in New Issue
Block a user