Skip to content

Commit

Permalink
1.1.1
Browse files Browse the repository at this point in the history
  • Loading branch information
AXiX-official committed Jun 17, 2024
1 parent 970a4f3 commit 85a1553
Show file tree
Hide file tree
Showing 28 changed files with 842 additions and 86 deletions.
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2024 CrossCoreNightly

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
36 changes: 36 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# AssetSideLoader

[README_EN.md](README_EN.md)

## 介绍

一个LSPosed模块,通过hook UnityEngine的内部方法实现从自定义路径加载文件,来替换External Storage或者APK中的资源。

---

## 说明

- 需要先手动授予“获取应用列表”权限
- 请先在LSPosed中激活模块,并且至少选择一个目标应用,之后启动APP
- 启动APP后可以在`SELECT APPS`中选择目标应用,然后点击`DONE`返回
- 注意,即使在模块中选择了目标应用,也需要在LSPosed中为模块选择相应的目标应用
- `SELECT APPS`中只会显示`lib`目录下存在`libil2cpp.so`的应用
- 选择目标应用后,可以在主界面点击对应的应用进入具体设置
- 如果回到主界面后没有显示对应的应用,请重启APP
- 在具体设置中有三个路径需要手动填写
- `APK Patch`:APK文件中的资源相对于`/data/app/*/*/base.apk!/`的路径
- `Data Patch`:外部存储中的资源相对于`/storage/emulated/0/Android/com.example.www/files`的路径
- `Mod Patch`:自定义的mod文件夹路径,与Data Patch一样是外部存储中的相对路径
- APP期望在`Mod Patch`下有和`APK Patch``Data Patch`中要替换的文件相同的目录结构和文件名
- 选择好路径后,点击`SAVE`保存设置,点击`DELETE`删除设置,点击SWITCH切换是否启用
- 确定设定无误后,启动目标应用即可

## 示例

![example](doc/example.jpg)

## 致谢

- Perfare: [Zygisk-Il2CppDumper](https://github.com/Perfare/Zygisk-Il2CppDumper)
- jmpewsL [Dobby](https://github.com/jmpews/Dobby)
- LSPosed: [LSPosed](https://github.com/LSPosed/LSPosed)
33 changes: 33 additions & 0 deletions README_EN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# AssetSideLoader

## Introduction

A LSPosed module that replaces resources in External Storage or APK by hooking UnityEngine's internal methods to load files from a custom path.

---
## Description

- You need to grant "Get App List" permission manually.
- Please activate the module in LSPosed and select at least one target app, then launch the app.
- After launching the app, you can select the target app in `SELECT APPS`, then click `DONE` to return.
- Note that even if you have selected a target app in the module, you still need to select the corresponding target app for the module in LSPosed.
- The `SELECT APPS` will only show applications that have `libil2cpp.so` in the `lib` directory.
- After selecting the target application, you can click the corresponding application in the main interface to enter the specific settings.
- If the corresponding app is not displayed after returning to the main interface, please restart the app.
- There are three paths you need to fill in manually
- `APK Patch`: the path of resources in APK file relative to `/data/app/*/*/base.apk!/`.
- `Data Patch`: path to resources in external storage relative to `/storage/emulated/0/Android/com.example.www/files`.
- `Mod Patch`: the path to the customized mod folder, which is a relative path in the external storage like the Data Patch.
- APP expects the same directory structure and file names under `Mod Patch` as the files to be replaced in `APK Patch` and `Data Patch`.
- After selecting the path, click `SAVE` to save the settings, click `DELETE` to delete the settings, and click SWITCH to enable or disable the settings.
- After making sure the settings are correct, start the target application.

## Example

![example](doc/example.jpg)

## Credits

- Perfare: [Zygisk-Il2CppDumper](https://github.com/Perfare/Zygisk-Il2CppDumper)
- jmpewsL [Dobby](https://github.com/jmpews/Dobby)
- LSPosed: [LSPosed](https://github.com/LSPosed/LSPosed)
26 changes: 21 additions & 5 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
id("kotlin-parcelize")
}

android {
namespace = "com.axix.assetsideloader"
namespace = "top.axix.assetsideloader"
compileSdk = 34

defaultConfig {
applicationId = "com.axix.assetsideloader"
minSdk = 26
applicationId = "top.axix.assetsideloader"
minSdk = 24
targetSdk = 34
versionCode = 106
versionName = "1.0.6"
versionCode = 111
versionName = "1.1.1"

ndk {
}
Expand All @@ -34,10 +35,23 @@ android {
buildFeatures{
prefab = true
}

buildTypes {
debug {
isMinifyEnabled = false
}
}

compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}

lint {
abortOnError = true
checkReleaseBuilds = false
}

kotlinOptions {
jvmTarget = "1.8"
}
Expand All @@ -52,4 +66,6 @@ dependencies {
implementation("com.google.android.material:material:1.9.0")
testImplementation("junit:junit:4.13.2")
implementation("io.github.hexhacking:xdl:2.1.1")
implementation("androidx.recyclerview:recyclerview:1.2.1")
implementation("com.google.code.gson:gson:2.8.9")
}
28 changes: 19 additions & 9 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
xmlns:tools="http://schemas.android.com/tools"
package="top.axix.assetsideloader">

<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />

<application
android:allowBackup="true"
Expand All @@ -9,27 +12,34 @@
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.AppCompat.DayNight"
tools:targetApi="34">
android:theme="@style/Theme.AppCompat.DayNight">
<meta-data
android:name="xposedmodule"
android:value="true" />
<meta-data
android:name="xposedminversion"
android:value="93+" />
<meta-data
android:name="xposeddescription"
android:value="Asset Side Loader" />
android:value="SideLoad Unity Files" />
<meta-data
android:name="xposedminversion"
android:value="82" />
android:name="xposedsharedprefs"
android:value="true" />
<meta-data
android:name="xposedsharedprefs"
android:value="true" />
<meta-data
android:name="staticScope"
android:value="true" />
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".AppsListActivity" />
<activity android:name=".AppInfoActivity" />
</application>

</manifest>
2 changes: 1 addition & 1 deletion app/src/main/assets/xposed_init
Original file line number Diff line number Diff line change
@@ -1 +1 @@
com.axix.assetsideloader.MainHook
top.axix.assetsideloader.MainHook
71 changes: 40 additions & 31 deletions app/src/main/cpp/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
#include <string>
#include <unistd.h>
#include <fstream>
#include <iostream>
#include <filesystem>
#include <dobby.h>
#include "xdl.h"
#include "log.h"
#include "utf8.h"
#include "xdl.h"
#include "il2cpp-class.h"

//------------------------------------------------------------------------------------------------//
Expand All @@ -33,28 +35,30 @@ void init_il2cpp_api(void *handle) {

//------------------------------------------------------------------------------------------------//

void* Handle = nullptr;

std::string pakageName = "";
typedef struct {
void* handle;
const char* pakageName;
const char* dataDir;
const char* apkDir;
const char* modDir;
} AppInfo;

std::string modDir = "/storage/emulated/0/Android/data/";
AppInfo appInfo;

//------------------------------------------------------------------------------------------------//

void* ReplacePath(std::string path) {
if (path.find("AssetBundles") != std::string::npos) {
std::string modPath = modDir + path.substr(path.find("AssetBundles") + 12);
if (modPath.find(".ys") != std::string::npos) {
//去除.ys后缀
modPath = modPath.substr(0, modPath.find(".ys"));
}
// 判断文件是否存在
std::ifstream file(modPath);
if (file) {
LOG_I("Redirect from: %s", path.c_str());
LOG_I("To: %s", modPath.c_str());
return il2cpp_string_new(modPath.c_str());
}
std::string new_path;
if (path.find(appInfo.apkDir) == 0) {
new_path = appInfo.modDir + path.substr(strlen(appInfo.apkDir));
} else if (path.find(appInfo.dataDir) == 0) {
new_path = appInfo.modDir + path.substr(strlen(appInfo.dataDir));
} else {
new_path = path;
}
if (std::__fs::filesystem::exists(new_path)) {
LOG_D("Replace path: %s -> %s", path.c_str(), new_path.c_str());
return il2cpp_string_new(new_path.c_str());
}
return il2cpp_string_new(path.c_str());
}
Expand Down Expand Up @@ -98,16 +102,12 @@ void* Hook_LoadFromFileAsync_Internal(void* path, uint32_t crc, uint64_t offset)

void hook_funcs(){
LOG_I("Init Il2cpp api...");
init_il2cpp_api(Handle);
init_il2cpp_api(appInfo.handle);
LOG_I("hooking...");

modDir += pakageName;
modDir += "/files/mods";
LOG_I("modDir: %s", modDir.c_str());

uint64_t LoadFromFile_Internal_addr = (uint64_t)il2cpp_resolve_icall("UnityEngine.AssetBundle::LoadFromFile_Internal(System.String,System.UInt32,System.UInt64)");
if (LoadFromFile_Internal_addr) {
LOG_I("LoadFromFile_Internal_addr: %" PRIx64"", LoadFromFile_Internal_addr);
LOG_D("LoadFromFile_Internal_addr: %" PRIx64"", LoadFromFile_Internal_addr);
DobbyHook(
(void *)LoadFromFile_Internal_addr,
(void *)Hook_LoadFromFile_Internal,
Expand All @@ -117,7 +117,7 @@ void hook_funcs(){

uint64_t LoadFromFileAsync_Internal_addr = (uint64_t)il2cpp_resolve_icall("UnityEngine.AssetBundle::LoadFromFileAsync_Internal(System.String,System.UInt32,System.UInt64)");
if (LoadFromFileAsync_Internal_addr) {
LOG_I("LoadFromFileAsync_Internal_addr: %" PRIx64"", LoadFromFileAsync_Internal_addr);
LOG_D("LoadFromFileAsync_Internal_addr: %" PRIx64"", LoadFromFileAsync_Internal_addr);
DobbyHook(
(void *)LoadFromFileAsync_Internal_addr,
(void *)Hook_LoadFromFileAsync_Internal,
Expand All @@ -135,11 +135,11 @@ il2cpp_init_func il2cpp_init_origin = nullptr;
int hook_il2cpp_init(const char *domain_name) {
int result = il2cpp_init_origin(domain_name);
DobbyDestroy((void*)hook_il2cpp_init);
LOG_I("il2cpp_init finished with result: %d", result);
LOG_D("il2cpp_init finished with result: %d", result);
if (result == 1){
DobbyDestroy((void*)hook_il2cpp_init);
Handle = xdl_open("libil2cpp.so", 0);
LOG_I("libil2cpp.so handle: %p", Handle);
appInfo.handle = xdl_open("libil2cpp.so", 0);
LOG_D("libil2cpp.so handle: %p", appInfo.handle);
hook_funcs();
}
return result;
Expand All @@ -154,7 +154,7 @@ static dlsym_t orig_dlsym = nullptr;
void* my_dlsym(void* handle, const char* symbol){
void* addr = orig_dlsym(handle, symbol);
if (strcmp(symbol, "il2cpp_init") == 0) {
LOG_I("symbol il2cpp_init found at: %p", addr);
LOG_D("symbol il2cpp_init found at: %p", addr);
DobbyDestroy((void*)my_dlsym);
DobbyHook(
(void*)addr,
Expand All @@ -169,8 +169,17 @@ void* my_dlsym(void* handle, const char* symbol){

extern "C"
JNIEXPORT void JNICALL
Java_com_axix_assetsideloader_AssetSideLoader_InitHook(JNIEnv *env, jobject thiz, jstring str) {
pakageName = env->GetStringUTFChars(str, NULL);
Java_top_axix_assetsideloader_AssetSideLoader_InitHook(JNIEnv *env, jobject thiz, jstring pgn, jstring dataPath, jstring apkPath, jstring modPath) {
LOG_D("Native hook init...");
appInfo.pakageName = env->GetStringUTFChars(pgn, NULL);
LOG_D("Package name: %s", appInfo.pakageName);
appInfo.dataDir = env->GetStringUTFChars(dataPath, NULL);
LOG_D("Data dir: %s", appInfo.dataDir);
appInfo.apkDir = env->GetStringUTFChars(apkPath, NULL);
LOG_D("Apk dir: %s", appInfo.apkDir);
appInfo.modDir = env->GetStringUTFChars(modPath, NULL);
LOG_D("Mod dir: %s", appInfo.modDir);
LOG_D("Hooking dlsym...");

DobbyHook((void*) dlsym, (void*)my_dlsym, (void**)&orig_dlsym);
}
11 changes: 0 additions & 11 deletions app/src/main/java/com/axix/assetsideloader/AssetSideLoader.kt

This file was deleted.

12 changes: 0 additions & 12 deletions app/src/main/java/com/axix/assetsideloader/MainActivity.kt

This file was deleted.

14 changes: 0 additions & 14 deletions app/src/main/java/com/axix/assetsideloader/MainHook.kt

This file was deleted.

Loading

0 comments on commit 85a1553

Please sign in to comment.