feat: 成功加载了so 并且调用了riru hide等逻辑
准备增加自定义linker
This commit is contained in:
@@ -23,8 +23,8 @@ android {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility JavaVersion.VERSION_1_8
|
sourceCompatibility JavaVersion.VERSION_11
|
||||||
targetCompatibility JavaVersion.VERSION_1_8
|
targetCompatibility JavaVersion.VERSION_11
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,6 +56,8 @@ public class AppListFragment extends Fragment implements AppListAdapter.OnAppTog
|
|||||||
super.onViewCreated(view, savedInstanceState);
|
super.onViewCreated(view, savedInstanceState);
|
||||||
|
|
||||||
configManager = new ConfigManager(requireContext());
|
configManager = new ConfigManager(requireContext());
|
||||||
|
// Ensure module directories exist
|
||||||
|
configManager.ensureModuleDirectories();
|
||||||
|
|
||||||
initViews(view);
|
initViews(view);
|
||||||
setupRecyclerView();
|
setupRecyclerView();
|
||||||
|
|||||||
@@ -27,13 +27,17 @@ public class ConfigManager {
|
|||||||
// Configure Shell to use root
|
// Configure Shell to use root
|
||||||
Shell.enableVerboseLogging = BuildConfig.DEBUG;
|
Shell.enableVerboseLogging = BuildConfig.DEBUG;
|
||||||
Shell.setDefaultBuilder(Shell.Builder.create()
|
Shell.setDefaultBuilder(Shell.Builder.create()
|
||||||
.setFlags(Shell.FLAG_REDIRECT_STDERR)
|
.setFlags(Shell.FLAG_REDIRECT_STDERR | Shell.FLAG_MOUNT_MASTER)
|
||||||
.setTimeout(10));
|
.setTimeout(30));
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConfigManager(Context context) {
|
public ConfigManager(Context context) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.gson = new GsonBuilder().setPrettyPrinting().create();
|
this.gson = new GsonBuilder().setPrettyPrinting().create();
|
||||||
|
|
||||||
|
// Ensure we get root shell on creation
|
||||||
|
Shell.getShell();
|
||||||
|
|
||||||
loadConfig();
|
loadConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,8 +46,32 @@ public class ConfigManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void ensureModuleDirectories() {
|
public void ensureModuleDirectories() {
|
||||||
Shell.cmd("mkdir -p " + MODULE_PATH).exec();
|
// Check root access first
|
||||||
Shell.cmd("mkdir -p " + SO_STORAGE_DIR).exec();
|
if (!isRootAvailable()) {
|
||||||
|
Log.e(TAG, "Root access not available!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create module directories
|
||||||
|
Shell.Result result1 = Shell.cmd("mkdir -p " + MODULE_PATH).exec();
|
||||||
|
if (!result1.isSuccess()) {
|
||||||
|
Log.e(TAG, "Failed to create module directory: " + MODULE_PATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
Shell.Result result2 = Shell.cmd("mkdir -p " + SO_STORAGE_DIR).exec();
|
||||||
|
if (!result2.isSuccess()) {
|
||||||
|
Log.e(TAG, "Failed to create SO storage directory: " + SO_STORAGE_DIR);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set permissions
|
||||||
|
Shell.cmd("chmod 755 " + MODULE_PATH).exec();
|
||||||
|
Shell.cmd("chmod 755 " + SO_STORAGE_DIR).exec();
|
||||||
|
|
||||||
|
// Verify directories exist
|
||||||
|
Shell.Result verify = Shell.cmd("ls -la " + MODULE_PATH).exec();
|
||||||
|
if (verify.isSuccess()) {
|
||||||
|
Log.i(TAG, "Module directory ready: " + String.join("\n", verify.getOut()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadConfig() {
|
private void loadConfig() {
|
||||||
@@ -94,6 +122,13 @@ public class ConfigManager {
|
|||||||
}
|
}
|
||||||
appConfig.enabled = enabled;
|
appConfig.enabled = enabled;
|
||||||
saveConfig();
|
saveConfig();
|
||||||
|
|
||||||
|
// 自动部署或清理 SO 文件
|
||||||
|
if (enabled) {
|
||||||
|
deploySoFilesToApp(packageName);
|
||||||
|
} else {
|
||||||
|
cleanupAppSoFiles(packageName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<SoFile> getAppSoFiles(String packageName) {
|
public List<SoFile> getAppSoFiles(String packageName) {
|
||||||
@@ -163,6 +198,11 @@ public class ConfigManager {
|
|||||||
// Add reference to the global SO file
|
// Add reference to the global SO file
|
||||||
appConfig.soFiles.add(globalSoFile);
|
appConfig.soFiles.add(globalSoFile);
|
||||||
saveConfig();
|
saveConfig();
|
||||||
|
|
||||||
|
// If app is enabled, deploy the new SO file
|
||||||
|
if (appConfig.enabled) {
|
||||||
|
deploySoFilesToApp(packageName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeSoFileFromApp(String packageName, SoFile soFile) {
|
public void removeSoFileFromApp(String packageName, SoFile soFile) {
|
||||||
@@ -171,6 +211,11 @@ public class ConfigManager {
|
|||||||
|
|
||||||
appConfig.soFiles.removeIf(s -> s.storedPath.equals(soFile.storedPath));
|
appConfig.soFiles.removeIf(s -> s.storedPath.equals(soFile.storedPath));
|
||||||
saveConfig();
|
saveConfig();
|
||||||
|
|
||||||
|
// If app is enabled, re-deploy to update SO files
|
||||||
|
if (appConfig.enabled) {
|
||||||
|
deploySoFilesToApp(packageName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean getHideInjection() {
|
public boolean getHideInjection() {
|
||||||
@@ -182,6 +227,152 @@ public class ConfigManager {
|
|||||||
saveConfig();
|
saveConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Copy SO files directly to app's data directory
|
||||||
|
private void deploySoFilesToApp(String packageName) {
|
||||||
|
AppConfig appConfig = config.perAppConfig.get(packageName);
|
||||||
|
if (appConfig == null || appConfig.soFiles.isEmpty()) {
|
||||||
|
Log.w(TAG, "No SO files to deploy for: " + packageName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// First check if we have root access
|
||||||
|
if (!Shell.getShell().isRoot()) {
|
||||||
|
Log.e(TAG, "No root access available!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create files directory in app's data dir
|
||||||
|
String filesDir = "/data/data/" + packageName + "/files";
|
||||||
|
|
||||||
|
// Use su -c for better compatibility
|
||||||
|
Shell.Result mkdirResult = Shell.cmd("su -c 'mkdir -p " + filesDir + "'").exec();
|
||||||
|
if (!mkdirResult.isSuccess()) {
|
||||||
|
Log.e(TAG, "Failed to create directory: " + filesDir);
|
||||||
|
Log.e(TAG, "Error: " + String.join("\n", mkdirResult.getErr()));
|
||||||
|
// Try without su -c
|
||||||
|
mkdirResult = Shell.cmd("mkdir -p " + filesDir).exec();
|
||||||
|
if (!mkdirResult.isSuccess()) {
|
||||||
|
Log.e(TAG, "Also failed without su -c");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set proper permissions and ownership
|
||||||
|
Shell.cmd("chmod 755 " + filesDir).exec();
|
||||||
|
|
||||||
|
// Get UID for the package
|
||||||
|
Shell.Result uidResult = Shell.cmd("stat -c %u /data/data/" + packageName).exec();
|
||||||
|
String uid = "";
|
||||||
|
if (uidResult.isSuccess() && !uidResult.getOut().isEmpty()) {
|
||||||
|
uid = uidResult.getOut().get(0).trim();
|
||||||
|
Log.i(TAG, "Package UID: " + uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy each SO file configured for this app
|
||||||
|
for (SoFile soFile : appConfig.soFiles) {
|
||||||
|
// Extract mapped filename
|
||||||
|
String mappedName = new File(soFile.storedPath).getName();
|
||||||
|
String destPath = filesDir + "/" + mappedName;
|
||||||
|
|
||||||
|
// Check if source file exists
|
||||||
|
Shell.Result checkResult = Shell.cmd("test -f \"" + soFile.storedPath + "\" && echo 'exists'").exec();
|
||||||
|
if (!checkResult.isSuccess() || checkResult.getOut().isEmpty()) {
|
||||||
|
Log.e(TAG, "Source SO file not found: " + soFile.storedPath);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.i(TAG, "Copying: " + soFile.storedPath + " to " + destPath);
|
||||||
|
|
||||||
|
// Copy file using cat to avoid permission issues
|
||||||
|
String copyCmd = "cat \"" + soFile.storedPath + "\" > \"" + destPath + "\"";
|
||||||
|
Shell.Result result = Shell.cmd(copyCmd).exec();
|
||||||
|
|
||||||
|
if (!result.isSuccess()) {
|
||||||
|
Log.e(TAG, "Failed with cat, trying cp");
|
||||||
|
// Fallback to cp
|
||||||
|
result = Shell.cmd("cp -f \"" + soFile.storedPath + "\" \"" + destPath + "\"").exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set permissions
|
||||||
|
Shell.cmd("chmod 755 \"" + destPath + "\"").exec();
|
||||||
|
|
||||||
|
// Set ownership if we have the UID
|
||||||
|
if (!uid.isEmpty()) {
|
||||||
|
Shell.cmd("chown " + uid + ":" + uid + " \"" + destPath + "\"").exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify the file was copied
|
||||||
|
Shell.Result verifyResult = Shell.cmd("ls -la \"" + destPath + "\" 2>/dev/null").exec();
|
||||||
|
if (verifyResult.isSuccess() && !verifyResult.getOut().isEmpty()) {
|
||||||
|
Log.i(TAG, "Successfully deployed: " + String.join(" ", verifyResult.getOut()));
|
||||||
|
} else {
|
||||||
|
Log.e(TAG, "Failed to verify SO file copy: " + destPath);
|
||||||
|
// Try another verification method
|
||||||
|
Shell.Result sizeResult = Shell.cmd("stat -c %s \"" + destPath + "\" 2>/dev/null").exec();
|
||||||
|
if (sizeResult.isSuccess() && !sizeResult.getOut().isEmpty()) {
|
||||||
|
Log.i(TAG, "File exists with size: " + sizeResult.getOut().get(0) + " bytes");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.i(TAG, "Deployment complete for: " + packageName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up deployed SO files when app is disabled
|
||||||
|
private void cleanupAppSoFiles(String packageName) {
|
||||||
|
AppConfig appConfig = config.perAppConfig.get(packageName);
|
||||||
|
if (appConfig == null || appConfig.soFiles.isEmpty()) {
|
||||||
|
Log.w(TAG, "No SO files to clean up for: " + packageName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// First check if we have root access
|
||||||
|
if (!Shell.getShell().isRoot()) {
|
||||||
|
Log.e(TAG, "No root access available!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String filesDir = "/data/data/" + packageName + "/files";
|
||||||
|
|
||||||
|
// Only delete the SO files we deployed, not the entire directory
|
||||||
|
for (SoFile soFile : appConfig.soFiles) {
|
||||||
|
String mappedName = new File(soFile.storedPath).getName();
|
||||||
|
String filePath = filesDir + "/" + mappedName;
|
||||||
|
|
||||||
|
Log.i(TAG, "Cleaning up: " + filePath);
|
||||||
|
|
||||||
|
// Check if file exists before trying to delete
|
||||||
|
Shell.Result checkResult = Shell.cmd("test -f \"" + filePath + "\" && echo 'exists'").exec();
|
||||||
|
if (checkResult.isSuccess() && !checkResult.getOut().isEmpty()) {
|
||||||
|
// Try to remove the file
|
||||||
|
Shell.Result result = Shell.cmd("rm -f \"" + filePath + "\"").exec();
|
||||||
|
|
||||||
|
// Verify deletion
|
||||||
|
Shell.Result verifyResult = Shell.cmd("test -f \"" + filePath + "\" && echo 'still_exists'").exec();
|
||||||
|
if (!verifyResult.isSuccess() || verifyResult.getOut().isEmpty()) {
|
||||||
|
Log.i(TAG, "Successfully deleted SO file: " + filePath);
|
||||||
|
} else {
|
||||||
|
Log.e(TAG, "Failed to delete SO file: " + filePath);
|
||||||
|
// Try with su -c
|
||||||
|
Shell.cmd("su -c 'rm -f \"" + filePath + "\"'").exec();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.w(TAG, "SO file not found for cleanup: " + filePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.i(TAG, "Cleanup complete for: " + packageName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deploy SO files for all enabled apps
|
||||||
|
public void deployAllSoFiles() {
|
||||||
|
for (Map.Entry<String, AppConfig> entry : config.perAppConfig.entrySet()) {
|
||||||
|
if (entry.getValue().enabled) {
|
||||||
|
deploySoFilesToApp(entry.getKey());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Data classes
|
// Data classes
|
||||||
public static class ModuleConfig {
|
public static class ModuleConfig {
|
||||||
public boolean enabled = true;
|
public boolean enabled = true;
|
||||||
|
|||||||
@@ -43,6 +43,8 @@ public class SoManagerFragment extends Fragment {
|
|||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
configManager = new ConfigManager(requireContext());
|
configManager = new ConfigManager(requireContext());
|
||||||
|
// Ensure module directories exist
|
||||||
|
configManager.ensureModuleDirectories();
|
||||||
|
|
||||||
// Initialize file picker
|
// Initialize file picker
|
||||||
filePickerLauncher = registerForActivityResult(
|
filePickerLauncher = registerForActivityResult(
|
||||||
|
|||||||
@@ -175,8 +175,10 @@ namespace Config {
|
|||||||
|
|
||||||
auto it = g_config.perAppConfig.find(packageName);
|
auto it = g_config.perAppConfig.find(packageName);
|
||||||
if (it != g_config.perAppConfig.end()) {
|
if (it != g_config.perAppConfig.end()) {
|
||||||
|
LOGD("Found app config for %s with %zu SO files", packageName.c_str(), it->second.soFiles.size());
|
||||||
return it->second.soFiles;
|
return it->second.soFiles;
|
||||||
}
|
}
|
||||||
|
LOGD("No app config found for %s", packageName.c_str());
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,6 @@
|
|||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
void hack_prepare(const char *game_data_dir, void *data, size_t length);
|
void hack_prepare(const char *game_data_dir, const char *package_name, void *data, size_t length);
|
||||||
|
|
||||||
#endif //ZYGISK_IL2CPPDUMPER_HACK_H
|
#endif //ZYGISK_IL2CPPDUMPER_HACK_H
|
||||||
|
|||||||
@@ -7,63 +7,51 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
// External function from newriruhide.cpp
|
||||||
|
extern "C" void riru_hide(const char *name);
|
||||||
|
|
||||||
void load_so_file(const char *game_data_dir, const Config::SoFile &soFile) {
|
void load_so_file(const char *game_data_dir, const Config::SoFile &soFile) {
|
||||||
char dest_path[512];
|
// Extract the mapped filename from storedPath (e.g., "1750851324251_libmylib.so")
|
||||||
snprintf(dest_path, sizeof(dest_path), "%s/files/%s", game_data_dir, soFile.name.c_str());
|
const char *mapped_name = strrchr(soFile.storedPath.c_str(), '/');
|
||||||
|
if (!mapped_name) {
|
||||||
|
mapped_name = soFile.storedPath.c_str();
|
||||||
|
} else {
|
||||||
|
mapped_name++; // Skip the '/'
|
||||||
|
}
|
||||||
|
|
||||||
// Copy SO file from storage to app directory
|
// The file should already be in app's files directory
|
||||||
int src_fd = open(soFile.storedPath.c_str(), O_RDONLY);
|
char so_path[512];
|
||||||
if (src_fd < 0) {
|
snprintf(so_path, sizeof(so_path), "%s/files/%s", game_data_dir, mapped_name);
|
||||||
LOGE("Failed to open source SO: %s", soFile.storedPath.c_str());
|
|
||||||
|
// Check if file exists
|
||||||
|
if (access(so_path, F_OK) != 0) {
|
||||||
|
LOGE("SO file not found: %s", so_path);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int dest_fd = open(dest_path, O_WRONLY | O_CREAT | O_TRUNC, 0755);
|
|
||||||
if (dest_fd < 0) {
|
|
||||||
LOGE("Failed to create dest SO: %s", dest_path);
|
|
||||||
close(src_fd);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
char buffer[4096];
|
|
||||||
ssize_t bytes;
|
|
||||||
while ((bytes = read(src_fd, buffer, sizeof(buffer))) > 0) {
|
|
||||||
if (write(dest_fd, buffer, bytes) != bytes) {
|
|
||||||
LOGE("Failed to write SO file");
|
|
||||||
close(src_fd);
|
|
||||||
close(dest_fd);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
close(src_fd);
|
|
||||||
close(dest_fd);
|
|
||||||
chmod(dest_path, 0755);
|
|
||||||
|
|
||||||
// Load the SO file
|
// Load the SO file
|
||||||
void *handle = dlopen(dest_path, RTLD_NOW | RTLD_LOCAL);
|
void *handle = dlopen(so_path, RTLD_NOW | RTLD_LOCAL);
|
||||||
if (handle) {
|
if (handle) {
|
||||||
LOGI("Successfully loaded SO: %s", soFile.name.c_str());
|
LOGI("Successfully loaded SO: %s (mapped: %s)", soFile.name.c_str(), mapped_name);
|
||||||
|
|
||||||
// Hide if configured
|
// Hide if configured
|
||||||
if (Config::shouldHideInjection()) {
|
if (Config::shouldHideInjection()) {
|
||||||
// Call hide function if available
|
// Hide using the mapped name since that's what we loaded
|
||||||
void (*hide_func)(const char*) = (void(*)(const char*))dlsym(handle, "riru_hide");
|
riru_hide(mapped_name);
|
||||||
if (hide_func) {
|
LOGI("Applied riru_hide to: %s", mapped_name);
|
||||||
hide_func(soFile.name.c_str());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LOGE("Failed to load SO: %s - %s", dest_path, dlerror());
|
LOGE("Failed to load SO: %s - %s", so_path, dlerror());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void hack_thread_func(const char *game_data_dir, const char *package_name) {
|
void hack_thread_func(const char *game_data_dir, const char *package_name) {
|
||||||
LOGI("Hack thread started for package: %s", package_name);
|
LOGI("Hack thread started for package: %s", package_name);
|
||||||
|
|
||||||
// Wait a bit for app to initialize
|
// Wait a bit for app to initialize and files to be copied
|
||||||
sleep(1);
|
sleep(2);
|
||||||
|
|
||||||
// Get SO files for this app
|
// Get SO files for this app
|
||||||
auto soFiles = Config::getAppSoFiles(package_name);
|
auto soFiles = Config::getAppSoFiles(package_name);
|
||||||
@@ -71,26 +59,13 @@ void hack_thread_func(const char *game_data_dir, const char *package_name) {
|
|||||||
|
|
||||||
// Load each SO file
|
// Load each SO file
|
||||||
for (const auto &soFile : soFiles) {
|
for (const auto &soFile : soFiles) {
|
||||||
LOGI("Loading SO: %s", soFile.name.c_str());
|
LOGI("Loading SO: %s (stored as: %s)", soFile.name.c_str(), soFile.storedPath.c_str());
|
||||||
load_so_file(game_data_dir, soFile);
|
load_so_file(game_data_dir, soFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void hack_prepare(const char *game_data_dir, void *data, size_t length) {
|
void hack_prepare(const char *game_data_dir, const char *package_name, void *data, size_t length) {
|
||||||
// Get package name from game_data_dir
|
LOGI("hack_prepare called for package: %s, dir: %s", package_name, game_data_dir);
|
||||||
// Format: /data/user/0/com.example.app or /data/data/com.example.app
|
|
||||||
const char *package_name = nullptr;
|
|
||||||
if (strstr(game_data_dir, "/data/user/")) {
|
|
||||||
package_name = strrchr(game_data_dir, '/');
|
|
||||||
if (package_name) package_name++;
|
|
||||||
} else if (strstr(game_data_dir, "/data/data/")) {
|
|
||||||
package_name = game_data_dir + strlen("/data/data/");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!package_name) {
|
|
||||||
LOGE("Failed to extract package name from: %s", game_data_dir);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::thread hack_thread(hack_thread_func, game_data_dir, package_name);
|
std::thread hack_thread(hack_thread_func, game_data_dir, package_name);
|
||||||
hack_thread.detach();
|
hack_thread.detach();
|
||||||
|
|||||||
@@ -6,6 +6,9 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <time.h>
|
||||||
#include "hack.h"
|
#include "hack.h"
|
||||||
#include "zygisk.hpp"
|
#include "zygisk.hpp"
|
||||||
#include "game.h"
|
#include "game.h"
|
||||||
@@ -21,6 +24,7 @@ public:
|
|||||||
void onLoad(Api *api, JNIEnv *env) override {
|
void onLoad(Api *api, JNIEnv *env) override {
|
||||||
this->api = api;
|
this->api = api;
|
||||||
this->env = env;
|
this->env = env;
|
||||||
|
enable_hack = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void preAppSpecialize(AppSpecializeArgs *args) override {
|
void preAppSpecialize(AppSpecializeArgs *args) override {
|
||||||
@@ -38,7 +42,8 @@ public:
|
|||||||
|
|
||||||
void postAppSpecialize(const AppSpecializeArgs *) override {
|
void postAppSpecialize(const AppSpecializeArgs *) override {
|
||||||
if (enable_hack) {
|
if (enable_hack) {
|
||||||
std::thread hack_thread(hack_prepare, _data_dir, data, length);
|
// Then start hack thread
|
||||||
|
std::thread hack_thread(hack_prepare, _data_dir, _package_name, data, length);
|
||||||
hack_thread.detach();
|
hack_thread.detach();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -48,9 +53,10 @@ private:
|
|||||||
JNIEnv *env;
|
JNIEnv *env;
|
||||||
bool enable_hack;
|
bool enable_hack;
|
||||||
char *_data_dir;
|
char *_data_dir;
|
||||||
|
char *_package_name;
|
||||||
void *data;
|
void *data;
|
||||||
size_t length;
|
size_t length;
|
||||||
|
|
||||||
void preSpecialize(const char *package_name, const char *app_data_dir) {
|
void preSpecialize(const char *package_name, const char *app_data_dir) {
|
||||||
// Read configuration
|
// Read configuration
|
||||||
Config::readConfig();
|
Config::readConfig();
|
||||||
@@ -61,6 +67,11 @@ private:
|
|||||||
enable_hack = true;
|
enable_hack = true;
|
||||||
_data_dir = new char[strlen(app_data_dir) + 1];
|
_data_dir = new char[strlen(app_data_dir) + 1];
|
||||||
strcpy(_data_dir, app_data_dir);
|
strcpy(_data_dir, app_data_dir);
|
||||||
|
_package_name = new char[strlen(package_name) + 1];
|
||||||
|
strcpy(_package_name, package_name);
|
||||||
|
|
||||||
|
// ConfigApp is responsible for copying SO files
|
||||||
|
// We just need to load them
|
||||||
|
|
||||||
#if defined(__i386__)
|
#if defined(__i386__)
|
||||||
auto path = "zygisk/armeabi-v7a.so";
|
auto path = "zygisk/armeabi-v7a.so";
|
||||||
|
|||||||
Reference in New Issue
Block a user