├── lib
└── .gitkeep
├── apk
└── Add the APK to modify here.txt
├── smali
├── MagiaNative
│ ├── app
│ │ ├── .gitignore
│ │ ├── src
│ │ │ ├── main
│ │ │ │ ├── res
│ │ │ │ │ ├── values
│ │ │ │ │ │ ├── strings.xml
│ │ │ │ │ │ ├── colors.xml
│ │ │ │ │ │ └── styles.xml
│ │ │ │ │ ├── mipmap-hdpi
│ │ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ │ └── ic_launcher_round.png
│ │ │ │ │ ├── mipmap-mdpi
│ │ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ │ └── ic_launcher_round.png
│ │ │ │ │ ├── mipmap-xhdpi
│ │ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ │ └── ic_launcher_round.png
│ │ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ │ └── ic_launcher_round.png
│ │ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ │ └── ic_launcher_round.png
│ │ │ │ │ ├── mipmap-anydpi-v26
│ │ │ │ │ │ ├── ic_launcher.xml
│ │ │ │ │ │ └── ic_launcher_round.xml
│ │ │ │ │ ├── drawable-v24
│ │ │ │ │ │ └── ic_launcher_foreground.xml
│ │ │ │ │ └── drawable
│ │ │ │ │ │ └── ic_launcher_background.xml
│ │ │ │ ├── AndroidManifest.xml
│ │ │ │ └── java
│ │ │ │ │ └── io
│ │ │ │ │ └── kamihama
│ │ │ │ │ └── magianative
│ │ │ │ │ ├── RestClient$2.smali
│ │ │ │ │ ├── RestClient$1.smali
│ │ │ │ │ ├── RestClient.java
│ │ │ │ │ └── RestClient.smali
│ │ │ ├── test
│ │ │ │ └── java
│ │ │ │ │ └── io
│ │ │ │ │ └── kamihama
│ │ │ │ │ └── magianative
│ │ │ │ │ └── ExampleUnitTest.java
│ │ │ └── androidTest
│ │ │ │ └── java
│ │ │ │ └── io
│ │ │ │ └── kamihama
│ │ │ │ └── magianative
│ │ │ │ └── ExampleInstrumentedTest.java
│ │ ├── proguard-rules.pro
│ │ └── build.gradle
│ ├── settings.gradle
│ ├── gradle
│ │ └── wrapper
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ ├── build.gradle
│ ├── gradle.properties
│ ├── .gitignore
│ ├── gradlew.bat
│ └── gradlew
└── loader
│ ├── libLoader.smali
│ └── libLoader$1.smali
├── armv7apk
└── Add the ARMv7 APK to modify here.txt
├── requirements.txt
├── patches
├── koruri-semibold.ttf
├── unknown
│ ├── okhttp3
│ │ └── internal
│ │ │ └── publicsuffix
│ │ │ └── publicsuffixes.gz
│ └── google-services.json
├── Hook.patch
├── Backtrace.patch
├── NativeBridge.patch
└── strings.xml
├── ci_versions
├── src_apk.sh
└── deps.sh
├── src
├── Config.h
├── rest
│ ├── MagiaRest.h
│ └── MagiaRest.cpp
├── Utils.h
├── libmadomagi.h
├── Utils.cpp
└── MagiaClient.cpp
├── convert_smali_eol.ps1
├── ci_check_for_update.sh
├── sign_example.bat
├── .gitmodules
├── ci_download_src_apk.sh
├── ci_install_deps.sh
├── LICENSE
├── sign_example.sh
├── ci_build.sh
├── README.md
├── CMakeLists.txt
└── .gitignore
/lib/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/apk/Add the APK to modify here.txt:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/smali/MagiaNative/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/armv7apk/Add the ARMv7 APK to modify here.txt:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | parse==1.18.0
2 | PyTexturePacker==1.1.0
3 |
--------------------------------------------------------------------------------
/smali/MagiaNative/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':magianativelib'
2 |
--------------------------------------------------------------------------------
/patches/koruri-semibold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rayshift/magiatranslate/HEAD/patches/koruri-semibold.ttf
--------------------------------------------------------------------------------
/ci_versions/src_apk.sh:
--------------------------------------------------------------------------------
1 | SRCAPK_CERT_SHA256="3dc9c8238c830ac58a6e705353eaa0dbe0f90e302f1259042bbcab6b4c3d8c6e"
2 | SRCAPK_VER="3.2.0"
--------------------------------------------------------------------------------
/smali/MagiaNative/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | MagiaNative
3 |
4 |
--------------------------------------------------------------------------------
/smali/MagiaNative/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rayshift/magiatranslate/HEAD/smali/MagiaNative/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/smali/MagiaNative/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rayshift/magiatranslate/HEAD/smali/MagiaNative/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/smali/MagiaNative/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rayshift/magiatranslate/HEAD/smali/MagiaNative/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/patches/unknown/okhttp3/internal/publicsuffix/publicsuffixes.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rayshift/magiatranslate/HEAD/patches/unknown/okhttp3/internal/publicsuffix/publicsuffixes.gz
--------------------------------------------------------------------------------
/smali/MagiaNative/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rayshift/magiatranslate/HEAD/smali/MagiaNative/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/smali/MagiaNative/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rayshift/magiatranslate/HEAD/smali/MagiaNative/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/smali/MagiaNative/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rayshift/magiatranslate/HEAD/smali/MagiaNative/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/smali/MagiaNative/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rayshift/magiatranslate/HEAD/smali/MagiaNative/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/smali/MagiaNative/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rayshift/magiatranslate/HEAD/smali/MagiaNative/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/smali/MagiaNative/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rayshift/magiatranslate/HEAD/smali/MagiaNative/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/smali/MagiaNative/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rayshift/magiatranslate/HEAD/smali/MagiaNative/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/smali/MagiaNative/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rayshift/magiatranslate/HEAD/smali/MagiaNative/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/smali/MagiaNative/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #008577
4 | #00574B
5 | #D81B60
6 |
7 |
--------------------------------------------------------------------------------
/src/Config.h:
--------------------------------------------------------------------------------
1 | #ifndef CONFIG_H
2 | #define CONFIG_H
3 | #include
4 | #include
5 | #include
6 | #include
7 | /**************************
8 | * Magia Translate Ver *
9 | **************************/
10 | #define MT_VERSION 123
11 |
12 | #endif
13 |
--------------------------------------------------------------------------------
/smali/MagiaNative/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Sep 21 21:15:19 BST 2020
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
7 |
--------------------------------------------------------------------------------
/convert_smali_eol.ps1:
--------------------------------------------------------------------------------
1 | $ErrorActionPreference = "Stop"
2 |
3 | Get-ChildItem -Recurse .\build\app\smali | ForEach-Object -Process {
4 | $filepath = $_.FullName
5 | if ($filepath.EndsWith(".smali")) {
6 | [IO.File]::WriteAllText($filepath, ([IO.File]::ReadAllText($filepath) -replace "`r`n", "`n"))
7 | }
8 | }
--------------------------------------------------------------------------------
/smali/MagiaNative/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/smali/MagiaNative/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/ci_versions/deps.sh:
--------------------------------------------------------------------------------
1 | COMMANDLINETOOLS_URL="https://dl.google.com/android/repository/commandlinetools-linux-9477386_latest.zip"
2 | COMMANDLINETOOLS_SHA256="bd1aa17c7ef10066949c88dc6c9c8d536be27f992a1f3b5a584f9bd2ba5646a0"
3 | CMAKE_VER="3.22.1"
4 | NDK_VER="25.2.9519653"
5 | BUILD_TOOLS_VER="33.0.2"
6 | APKTOOL_VER="2.8.1"
7 | APKTOOL_SHA256="7b4a8e1703e228d206db29644b71141687d8a111b55b039b08b02dfa443ab0f9"
--------------------------------------------------------------------------------
/smali/MagiaNative/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/smali/MagiaNative/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
11 |
12 |
--------------------------------------------------------------------------------
/smali/MagiaNative/app/src/test/java/io/kamihama/magianative/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package io.kamihama.magianative;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/patches/Hook.patch:
--------------------------------------------------------------------------------
1 | diff --git a/build/app/smali/jp/f4samurai/MyApplication.smali b/build/app/smali/jp/f4samurai/MyApplication.smali
2 | index 2a83c1d..c18fa78 100644
3 | --- "a/build/app/smali/jp/f4samurai/MyApplication.smali"
4 | +++ "b/build/app/smali/jp/f4samurai/MyApplication.smali"
5 | @@ -6,6 +6,7 @@
6 | # direct methods
7 | .method public constructor ()V
8 | .locals 0
9 | + invoke-static {}, Lcom/loadLib/libLoader;->loadLib()V
10 |
11 | .line 9
12 | invoke-direct {p0}, Landroid/app/Application;->()V
13 |
--------------------------------------------------------------------------------
/smali/MagiaNative/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | google()
6 | jcenter()
7 |
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:3.4.2'
11 |
12 | // NOTE: Do not place your application dependencies here; they belong
13 | // in the individual module build.gradle files
14 | }
15 | }
16 |
17 | allprojects {
18 | repositories {
19 | google()
20 | jcenter()
21 |
22 | }
23 | }
24 |
25 | task clean(type: Delete) {
26 | delete rootProject.buildDir
27 | }
28 |
--------------------------------------------------------------------------------
/ci_check_for_update.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 | set -o pipefail
4 |
5 | UA="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"
6 |
7 | CHECKSUM_URL="https://jp.rika.ren/apk/Origin/checksum.txt"
8 |
9 | . ci_versions/src_apk.sh
10 |
11 | LATEST_SRCAPK_VER=$(curl -s -A "${UA}" -L "${CHECKSUM_URL}" | grep -E -i "^Version\s+name:\s+" | tail -n1 | grep -P -o "(\\d+\\.)+\\d+$")
12 |
13 | if echo "${SRCAPK_VER}" | grep -q -P "^(\\d+\\.)+\\d+$" && echo "${LATEST_SRCAPK_VER}" | grep -q -P "^(\\d+\\.)+\\d+$"; then
14 | if [[ "${SRCAPK_VER}" != "${LATEST_SRCAPK_VER}" ]]; then
15 | echo "latest-src-apk-ver=${LATEST_SRCAPK_VER}"
16 | echo "new-version-available=true"
17 | fi
18 | fi
--------------------------------------------------------------------------------
/sign_example.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 |
3 | if not exist "%zipalign%" (
4 | echo zipalign not found
5 | goto errorexit
6 | )
7 | if not exist "%apksigner%" (
8 | echo apksigner not found
9 | goto errorexit
10 | )
11 |
12 | echo Doing zipalign...
13 | "%zipalign%" -f -p 4 "%~dp0\build\magia_patched.apk" "%~dp0\build\magia_patched_aligned.apk"
14 | if errorlevel 1 (
15 | echo Failed to zipalign!
16 | goto errorexit
17 | )
18 | echo Removing tmp file...
19 | del /f /q "%~dp0\build\magia_patched.apk"
20 | rename "%~dp0\build\magia_patched_aligned.apk" magia_patched.apk
21 |
22 | echo Doing apksign...
23 | call "%apksigner%" sign --ks "%~dp0\changeme.keystore" --ks-pass pass:changeme --ks-key-alias name "%~dp0\build\magia_patched.apk"
24 | if errorlevel 1 goto errorexit
25 |
26 | exit /b
27 |
28 | :errorexit
29 | exit /b 3
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "lib/Dobby"]
2 | path = lib/Dobby
3 | url = https://github.com/rayshift/Dobby
4 | branch = master
5 | [submodule "lib/cocos"]
6 | path = lib/cocos
7 | url = https://github.com/neobenedict/cocos2d-src-only/
8 | branch = master
9 | [submodule "smali/okhttp-smali"]
10 | path = smali/okhttp-smali
11 | url = https://github.com/neobenedict/okhttp-smali
12 | branch = master
13 | [submodule "lib/untp"]
14 | path = lib/untp
15 | url = https://github.com/neobenedict/untp
16 | branch = develop
17 | [submodule "patches/images"]
18 | path = patches/images
19 | url = https://git.rayshift.io/kamihama/magia-client-image-patches
20 | branch = master
21 | [submodule "patches/magia-en-apk-assets"]
22 | path = patches/magia-en-apk-assets
23 | url = https://git.rayshift.io/kamihama/magia-en-apk-assets
24 | branch = master
25 |
--------------------------------------------------------------------------------
/smali/MagiaNative/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/smali/loader/libLoader.smali:
--------------------------------------------------------------------------------
1 | .class public Lcom/loadLib/libLoader;
2 | .super Landroid/app/Activity;
3 | .source "libLoader.java"
4 |
5 |
6 | # direct methods
7 | .method public constructor ()V
8 | .locals 0
9 |
10 | .prologue
11 | .line 12
12 | invoke-direct {p0}, Landroid/app/Activity;->()V
13 |
14 | return-void
15 | .end method
16 |
17 | .method public static loadLib()V
18 | .locals 4
19 |
20 | .prologue
21 | .line 14
22 | new-instance v0, Landroid/os/Handler;
23 |
24 | invoke-direct {v0}, Landroid/os/Handler;->()V
25 |
26 | new-instance v1, Lcom/loadLib/libLoader$1;
27 |
28 | invoke-direct {v1}, Lcom/loadLib/libLoader$1;->()V
29 |
30 | const-wide/16 v2, 0x1
31 |
32 | invoke-virtual {v0, v1, v2, v3}, Landroid/os/Handler;->postDelayed(Ljava/lang/Runnable;J)Z
33 |
34 | .line 20
35 | return-void
36 | .end method
37 |
--------------------------------------------------------------------------------
/smali/MagiaNative/app/src/androidTest/java/io/kamihama/magianative/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package io.kamihama.magianative;
2 |
3 | import android.content.Context;
4 |
5 | import androidx.test.InstrumentationRegistry;
6 | import androidx.test.runner.AndroidJUnit4;
7 |
8 | import org.junit.Test;
9 | import org.junit.runner.RunWith;
10 |
11 | import static org.junit.Assert.*;
12 |
13 | /**
14 | * Instrumented test, which will execute on an Android device.
15 | *
16 | * @see Testing documentation
17 | */
18 | @RunWith(AndroidJUnit4.class)
19 | public class ExampleInstrumentedTest {
20 | @Test
21 | public void useAppContext() {
22 | // Context of the app under test.
23 | Context appContext = InstrumentationRegistry.getTargetContext();
24 |
25 | assertEquals("io.kamihama.magianative", appContext.getPackageName());
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/rest/MagiaRest.h:
--------------------------------------------------------------------------------
1 | #ifndef MAGIAREST_H
2 | #define MAGIAREST_H
3 | #include
4 | #include
5 | #include
6 |
7 | using json = nlohmann::json;
8 |
9 | #define MAGIAREST_EMPTY 0
10 | #define MAGIAREST_SUCCESS 1
11 | #define MAGIAREST_ERROR 2
12 |
13 | // Rest class using JNI
14 | class MagiaRest {
15 | public:
16 | MagiaRest(JavaVM* gJvm);
17 |
18 | int Endpoint();
19 |
20 | size_t EndpointStringLength();
21 |
22 | std::string GetEndpointUrl();
23 |
24 | std::string GetEndpointError();
25 | int GetEndpointVersion();
26 |
27 | int GetMaxThreads();
28 |
29 | ~MagiaRest();
30 | private:
31 | JNIEnv* env;
32 | jclass klass;
33 | jobject magiaRestObj;
34 |
35 | jstring endpointJString = NULL;
36 | const char *endpointChar = NULL;
37 |
38 | bool endpointValid = false;
39 | json endpointJson = NULL;
40 |
41 | };
42 |
43 | #endif
--------------------------------------------------------------------------------
/ci_download_src_apk.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | verify_apk() {
5 | . ci_versions/deps.sh
6 | "./deps/Android/Sdk/build-tools/${BUILD_TOOLS_VER}/apksigner" verify --print-certs "$1" > /tmp/result.txt || exit 1
7 | grep -q "$2" /tmp/result.txt && return 0
8 | echo "Cert SHA256 digest mismatch" >&2
9 | exit 2
10 | }
11 |
12 | UA="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"
13 |
14 | URL_PREFIX="https://jp.rika.ren/apk/Origin/com.aniplex.magireco"
15 | ARMV8_URL="${URL_PREFIX}.arm8.apk"
16 | ARMV7_URL="${URL_PREFIX}.arm7.apk"
17 |
18 | . ci_versions/src_apk.sh
19 |
20 | rm -fr apk armv7apk
21 | mkdir -p apk armv7apk
22 |
23 | curl -A "${UA}" -o out.apk -L "${ARMV8_URL}"
24 | verify_apk out.apk "${SRCAPK_CERT_SHA256}" && mv out.apk "./apk/src_${SRCAPK_VER}.apk"
25 |
26 | curl -A "${UA}" -o out.apk -L "${ARMV7_URL}"
27 | verify_apk out.apk "${SRCAPK_CERT_SHA256}" && mv out.apk "./armv7apk/armv7src_${SRCAPK_VER}.apk"
--------------------------------------------------------------------------------
/smali/loader/libLoader$1.smali:
--------------------------------------------------------------------------------
1 | .class final Lcom/loadLib/libLoader$1;
2 | .super Ljava/lang/Object;
3 | .source "libLoader.java"
4 |
5 | # interfaces
6 | .implements Ljava/lang/Runnable;
7 |
8 |
9 | # annotations
10 | .annotation system Ldalvik/annotation/EnclosingMethod;
11 | value = Lcom/JvRuit/Ldr;->loadLib()V
12 | .end annotation
13 |
14 | .annotation system Ldalvik/annotation/InnerClass;
15 | accessFlags = 0x8
16 | name = null
17 | .end annotation
18 |
19 |
20 | # direct methods
21 | .method constructor ()V
22 | .locals 0
23 |
24 | .prologue
25 | .line 14
26 | invoke-direct {p0}, Ljava/lang/Object;->()V
27 |
28 | return-void
29 | .end method
30 |
31 |
32 | # virtual methods
33 | .method public run()V
34 | .locals 1
35 |
36 | .prologue
37 | .line 17
38 | const-string/jumbo v0, "uwasa"
39 |
40 | invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V
41 |
42 | .line 18
43 | return-void
44 | .end method
45 |
--------------------------------------------------------------------------------
/ci_install_deps.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | UA="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"
5 |
6 | . ci_versions/deps.sh
7 |
8 | rm -fr deps
9 | mkdir deps
10 | cd deps
11 |
12 | mkdir -p Android/Sdk
13 | pushd Android/Sdk
14 | curl -A "${UA}" -o "commandlinetools-linux.zip" -L "${COMMANDLINETOOLS_URL}"
15 | sha256sum "commandlinetools-linux.zip" | grep -q "${COMMANDLINETOOLS_SHA256}"
16 | unzip "commandlinetools-linux.zip"
17 | rm "commandlinetools-linux.zip"
18 | yes | ./cmdline-tools/bin/sdkmanager --sdk_root="$(realpath .)" --licenses
19 | for PKG in "cmake;${CMAKE_VER}" "ndk;${NDK_VER}" "build-tools;${BUILD_TOOLS_VER}"; do
20 | ./cmdline-tools/bin/sdkmanager --sdk_root="$(realpath .)" --install "${PKG}"
21 | done
22 | popd
23 |
24 | # apktool
25 | APKTOOL="apktool_${APKTOOL_VER}.jar"
26 | curl -A "${UA}" -o "${APKTOOL}" -L "https://bitbucket.org/iBotPeaches/apktool/downloads/${APKTOOL}"
27 | sha256sum "${APKTOOL}" | grep -q "${APKTOOL_SHA256}"
--------------------------------------------------------------------------------
/smali/MagiaNative/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 29
5 | buildToolsVersion "29.0.2"
6 | defaultConfig {
7 | applicationId "io.kamihama.magianative"
8 | minSdkVersion 19
9 | targetSdkVersion 29
10 | versionCode 1
11 | versionName "1.0"
12 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | implementation fileTree(dir: 'libs', include: ['*.jar'])
24 | implementation 'androidx.appcompat:appcompat:1.2.0'
25 | testImplementation 'junit:junit:4.12'
26 | androidTestImplementation 'androidx.test:runner:1.3.0'
27 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
28 | implementation("com.squareup.okhttp3:okhttp:3.12.9")
29 | }
30 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020-2024 Rayshift
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/smali/MagiaNative/app/src/main/java/io/kamihama/magianative/RestClient$2.smali:
--------------------------------------------------------------------------------
1 | .class final Lio/kamihama/magianative/RestClient$2;
2 | .super Ljava/lang/Object;
3 | .source "RestClient.java"
4 |
5 | # interfaces
6 | .implements Ljavax/net/ssl/HostnameVerifier;
7 |
8 |
9 | # annotations
10 | .annotation system Ldalvik/annotation/EnclosingMethod;
11 | value = Lio/kamihama/magianative/RestClient;->getUnsafeOkHttpClient()Lokhttp3/OkHttpClient;
12 | .end annotation
13 |
14 | .annotation system Ldalvik/annotation/InnerClass;
15 | accessFlags = 0x8
16 | name = null
17 | .end annotation
18 |
19 |
20 | # direct methods
21 | .method constructor ()V
22 | .registers 1
23 |
24 | .prologue
25 | .line 110
26 | invoke-direct {p0}, Ljava/lang/Object;->()V
27 |
28 | return-void
29 | .end method
30 |
31 |
32 | # virtual methods
33 | .method public verify(Ljava/lang/String;Ljavax/net/ssl/SSLSession;)Z
34 | .registers 4
35 | .param p1, "hostname" # Ljava/lang/String;
36 | .param p2, "session" # Ljavax/net/ssl/SSLSession;
37 |
38 | .prologue
39 | .line 113
40 | const/4 v0, 0x1
41 |
42 | return v0
43 | .end method
44 |
--------------------------------------------------------------------------------
/smali/MagiaNative/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx1536m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app's APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=true
20 |
21 |
--------------------------------------------------------------------------------
/sign_example.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | BASEDIR="$(realpath "$(dirname "${0}")")"
3 |
4 | # env-based
5 | ZIPALIGN="${MT_ZIPALIGN:-zipalign}" # ~/android-sdk/build-tools/zipalign
6 | APKSIGNER="${MT_APKSIGNER:-apksigner}" # ~/android-sdk/build-tools/apksigner
7 |
8 | # hardcode-based
9 | #ZIPALIGN="${BASEDIR}/abt/zipalign"
10 | #APKSIGNER="${BASEDIR}/abt/apksigner"
11 |
12 | # arg-based
13 | APK="${1:-${BASEDIR}/build/io.kamihama.magiatranslate.v0.50.apk}"
14 | KEYSTORE="${2:-${BASEDIR}/changeme.keystore}"
15 |
16 | _errorexit() {
17 | [ -z "${2}" ] || echo "${2}"
18 | echo "Signing failed."
19 | exit ${1}
20 | }
21 |
22 | [ -f "${APK}" ] || _errorexit 1 "Missing apk to sign! Tried file: ${APK}"
23 | [ -f "${KEYSTORE}" ] || _errorexit 2 "Missing keystore! Tried file: ${KEYSTORE}"
24 |
25 | echo "Doing zipalign..."
26 | "${ZIPALIGN}" -f -p 4 "${APK}" "${APK}.tmp"
27 | [ "$?" -ne "0" ] && _errorexit 3 "Failed to zipalign!"
28 | echo "Removing tmp file..."
29 | mv "${APK}.tmp" "${APK}"
30 |
31 | echo "Doing apksign..."
32 | "${APKSIGNER}" sign --ks "${KEYSTORE}" --ks-pass pass:changeme --ks-key-alias name "${APK}"
33 | [ "$?" -ne "0" ] && _errorexit 4 "Failed to apksign!"
34 |
35 | exit 0
36 |
--------------------------------------------------------------------------------
/patches/unknown/google-services.json:
--------------------------------------------------------------------------------
1 | {
2 | "project_info": {
3 | "project_number": "48695978581",
4 | "firebase_url": "https://kamihama-io.firebaseio.com",
5 | "project_id": "kamihama-io",
6 | "storage_bucket": "kamihama-io.appspot.com"
7 | },
8 | "client": [
9 | {
10 | "client_info": {
11 | "mobilesdk_app_id": "1:48695978581:android:bc7cc007c2de2d0e79c2dc",
12 | "android_client_info": {
13 | "package_name": "io.kamihama.magiatranslate"
14 | }
15 | },
16 | "oauth_client": [
17 | {
18 | "client_id": "48695978581-l3g2vae3su7td5tilbunf8fpb1875np4.apps.googleusercontent.com",
19 | "client_type": 3
20 | }
21 | ],
22 | "api_key": [
23 | {
24 | "current_key": "AIzaSyBlHoCTAsEa1zsIhKfE8nvMVewd0ULYmkw"
25 | }
26 | ],
27 | "services": {
28 | "appinvite_service": {
29 | "other_platform_oauth_client": [
30 | {
31 | "client_id": "48695978581-l3g2vae3su7td5tilbunf8fpb1875np4.apps.googleusercontent.com",
32 | "client_type": 3
33 | }
34 | ]
35 | }
36 | }
37 | }
38 | ],
39 | "configuration_version": "1"
40 | }
--------------------------------------------------------------------------------
/patches/Backtrace.patch:
--------------------------------------------------------------------------------
1 | diff --git a/build/app/smali/jp/f4samurai/backtrace/BacktraceHandler.smali b/build/app/smali/jp/f4samurai/backtrace/BacktraceHandler.smali
2 | index 6bc2d4d..67e0489 100644
3 | --- a/build/app/smali/jp/f4samurai/backtrace/BacktraceHandler.smali
4 | +++ b/build/app/smali/jp/f4samurai/backtrace/BacktraceHandler.smali
5 | @@ -6,9 +6,9 @@
6 | # static fields
7 | .field private static final ANR_TIMEOUT:I = 0xbb8
8 |
9 | -.field private static final ENDPOINT_URL:Ljava/lang/String; = "https://f4samurai.sp.backtrace.io:6098"
10 | +.field private static final ENDPOINT_URL:Ljava/lang/String; = "https://walpurgisnacht.rayshift.io/backtrace"
11 |
12 | -.field private static final SUBMISSION_TOKEN:Ljava/lang/String; = "a798a9b785f35254cfee3086e38053e7597ba9a49cdcc8b0a90d64ef052786b6"
13 | +.field private static final SUBMISSION_TOKEN:Ljava/lang/String; = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
14 |
15 | .field private static sBacktraceClient:Lbacktraceio/library/BacktraceClient;
16 |
17 | @@ -90,9 +90,9 @@
18 | :cond_0
19 | new-instance v0, Lbacktraceio/library/BacktraceCredentials;
20 |
21 | - const-string v1, "https://f4samurai.sp.backtrace.io:6098"
22 | + const-string v1, "https://walpurgisnacht.rayshift.io/backtrace"
23 |
24 | - const-string v2, "a798a9b785f35254cfee3086e38053e7597ba9a49cdcc8b0a90d64ef052786b6"
25 | + const-string v2, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
26 |
27 | invoke-direct {v0, v1, v2}, Lbacktraceio/library/BacktraceCredentials;->(Ljava/lang/String;Ljava/lang/String;)V
28 |
29 |
--------------------------------------------------------------------------------
/smali/MagiaNative/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/smali/MagiaNative/app/src/main/java/io/kamihama/magianative/RestClient$1.smali:
--------------------------------------------------------------------------------
1 | .class final Lio/kamihama/magianative/RestClient$1;
2 | .super Ljava/lang/Object;
3 | .source "RestClient.java"
4 |
5 | # interfaces
6 | .implements Ljavax/net/ssl/X509TrustManager;
7 |
8 |
9 | # annotations
10 | .annotation system Ldalvik/annotation/EnclosingMethod;
11 | value = Lio/kamihama/magianative/RestClient;->getUnsafeOkHttpClient()Lokhttp3/OkHttpClient;
12 | .end annotation
13 |
14 | .annotation system Ldalvik/annotation/InnerClass;
15 | accessFlags = 0x8
16 | name = null
17 | .end annotation
18 |
19 |
20 | # direct methods
21 | .method constructor ()V
22 | .registers 1
23 |
24 | .prologue
25 | .line 86
26 | invoke-direct {p0}, Ljava/lang/Object;->()V
27 |
28 | return-void
29 | .end method
30 |
31 |
32 | # virtual methods
33 | .method public checkClientTrusted([Ljava/security/cert/X509Certificate;Ljava/lang/String;)V
34 | .registers 3
35 | .param p1, "chain" # [Ljava/security/cert/X509Certificate;
36 | .param p2, "authType" # Ljava/lang/String;
37 | .annotation system Ldalvik/annotation/Throws;
38 | value = {
39 | Ljava/security/cert/CertificateException;
40 | }
41 | .end annotation
42 |
43 | .prologue
44 | .line 89
45 | return-void
46 | .end method
47 |
48 | .method public checkServerTrusted([Ljava/security/cert/X509Certificate;Ljava/lang/String;)V
49 | .registers 3
50 | .param p1, "chain" # [Ljava/security/cert/X509Certificate;
51 | .param p2, "authType" # Ljava/lang/String;
52 | .annotation system Ldalvik/annotation/Throws;
53 | value = {
54 | Ljava/security/cert/CertificateException;
55 | }
56 | .end annotation
57 |
58 | .prologue
59 | .line 93
60 | return-void
61 | .end method
62 |
63 | .method public getAcceptedIssuers()[Ljava/security/cert/X509Certificate;
64 | .registers 2
65 |
66 | .prologue
67 | .line 97
68 | const/4 v0, 0x0
69 |
70 | new-array v0, v0, [Ljava/security/cert/X509Certificate;
71 |
72 | return-object v0
73 | .end method
74 |
--------------------------------------------------------------------------------
/smali/MagiaNative/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | /.idea/navEditor.xml
9 | /.idea/assetWizardSettings.xml
10 | .DS_Store
11 | /build
12 | /captures
13 | .externalNativeBuild
14 | # Built application files
15 | *.apk
16 | *.aar
17 | *.ap_
18 | *.aab
19 |
20 | # Files for the ART/Dalvik VM
21 | *.dex
22 |
23 | # Java class files
24 | *.class
25 |
26 | # Generated files
27 | bin/
28 | gen/
29 | out/
30 | # Uncomment the following line in case you need and you don't have the release build type files in your app
31 | # release/
32 |
33 | # Gradle files
34 | .gradle/
35 | build/
36 |
37 | # Local configuration file (sdk path, etc)
38 | local.properties
39 |
40 | # Proguard folder generated by Eclipse
41 | proguard/
42 |
43 | # Log Files
44 | *.log
45 |
46 | # Android Studio Navigation editor temp files
47 | .navigation/
48 |
49 | # Android Studio captures folder
50 | captures/
51 |
52 | # IntelliJ
53 | *.iml
54 | .idea/workspace.xml
55 | .idea/tasks.xml
56 | .idea/gradle.xml
57 | .idea/assetWizardSettings.xml
58 | .idea/dictionaries
59 | .idea/libraries
60 | # Android Studio 3 in .gitignore file.
61 | .idea/caches
62 | .idea/modules.xml
63 | # Comment next line if keeping position of elements in Navigation Editor is relevant for you
64 | .idea/navEditor.xml
65 |
66 | # Keystore files
67 | # Uncomment the following lines if you do not want to check your keystore files in.
68 | #*.jks
69 | #*.keystore
70 |
71 | # External native build folder generated in Android Studio 2.2 and later
72 | .externalNativeBuild
73 | .cxx/
74 |
75 | # Google Services (e.g. APIs or Firebase)
76 | # google-services.json
77 |
78 | # Freeline
79 | freeline.py
80 | freeline/
81 | freeline_project_description.json
82 |
83 | # fastlane
84 | fastlane/report.xml
85 | fastlane/Preview.html
86 | fastlane/screenshots
87 | fastlane/test_output
88 | fastlane/readme.md
89 |
90 | # Version control
91 | vcs.xml
92 |
93 | # lint
94 | lint/intermediates/
95 | lint/generated/
96 | lint/outputs/
97 | lint/tmp/
98 | # lint/reports/
99 |
100 | # Android Profiling
101 | *.hprof
102 |
--------------------------------------------------------------------------------
/smali/MagiaNative/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/ci_build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | BASEDIR="$(realpath "$(dirname "${0}")")"
5 |
6 | # prepare signing key
7 | [[ "${KEYSTORE_BASE64}" == "" ]] && echo "KEYSTORE_BASE64 is not set" >&2 && exit 1
8 | [[ "${KS_PASS}" == "" ]] && echo "KS_PASS is not set" >&2 && exit 1
9 | echo "${KEYSTORE_BASE64}" | base64 -d > "${BASEDIR}/builder.jks" 2> /dev/null
10 | KEYSTORE_ARGS="--ks \"${BASEDIR}/builder.jks\" --ks-pass \"pass:${KS_PASS}\""
11 | [[ "${KEY_PASS}" != "" ]] && echo "KEY_PASS is set!" >&2 && KEYSTORE_ARGS="${KEYSTORE_ARGS} --key-pass \"pass:${KEY_PASS}\""
12 | [[ "${KS_KEY_ALIAS}" != "" ]] && echo "KS_KEY_ALIAS is set!" >&2 && KEYSTORE_ARGS="${KEYSTORE_ARGS} --ks-key-alias \"${KS_KEY_ALIAS}\""
13 | unset KEYSTORE_BASE64
14 | unset KS_PASS
15 | unset KEY_PASS
16 | unset KS_KEY_ALIAS
17 | cp sign_example.sh sign.sh
18 | sed -E -i "s@^(\"\\\$\{APKSIGNER\}\" sign ).+( \"\\\$\{APK\}\")\$@\\1${KEYSTORE_ARGS}\\2@" sign.sh 2>&1 > /dev/null
19 | sed -i "s@^KEYSTORE=.*@KEYSTORE=\"${BASEDIR}/builder.jks\"@" sign.sh 2>&1 > /dev/null
20 | chmod +x sign.sh
21 |
22 | # prepare source APKs
23 | MT_VER=$(grep -P -o "(?<=^#define MT_VERSION )\d+$" src/Config.h)
24 | . ci_versions/src_apk.sh
25 | SRCAPK="${BASEDIR}/apk/src_${SRCAPK_VER}.apk"
26 | export ARMV7SRCAPK="${BASEDIR}/armv7apk/armv7src_${SRCAPK_VER}.apk"
27 | VERSION="v${SRCAPK_VER}_v${MT_VER}"
28 |
29 | # load deps versions
30 | . ci_versions/deps.sh
31 | DEPS_DIR="${BASEDIR}/deps"
32 | # prepare apktool
33 | export MT_APKTOOL="apktool_${APKTOOL_VER}.jar"
34 | mkdir -p "${BASEDIR}/build"
35 | cp "${DEPS_DIR}/${MT_APKTOOL}" "${BASEDIR}/build/${MT_APKTOOL}"
36 | # prepare Android SDK
37 | SDK_ROOT="${DEPS_DIR}/Android/Sdk"
38 | NDK="${SDK_ROOT}/ndk/${NDK_VER}"
39 | CMAKE_BIN_DIR="${SDK_ROOT}/cmake/${CMAKE_VER}/bin"
40 | BUILD_TOOLS_DIR="${SDK_ROOT}/build-tools/${BUILD_TOOLS_VER}"
41 | export MT_CMAKE="${CMAKE_BIN_DIR}/cmake"
42 | export MT_NINJA="${CMAKE_BIN_DIR}/ninja"
43 | export MT_ZIPALIGN="${BUILD_TOOLS_DIR}/zipalign"
44 | export MT_APKSIGNER="${BUILD_TOOLS_DIR}/apksigner"
45 |
46 | RESULT="${BASEDIR}/build/io.kamihama.magiatranslate.${VERSION}.apk"
47 |
48 | # build main APK which contains audiofix
49 | MT_AUDIOFIX_3_0_1=Y "${BASEDIR}/build_release.sh" "${SRCAPK}" "${VERSION}" "${NDK}"
50 | MAIN_APK="MagiaTranslate_${VERSION}.apk"
51 | mv "${RESULT}" "${BASEDIR}/${MAIN_APK}"
52 | echo "MAIN_APK=${MAIN_APK}" >> "$GITHUB_ENV"
53 |
54 | # build failsafe APK which does not contain audiofix
55 | MT_AUDIOFIX_3_0_1=N "${BASEDIR}/build_release.sh" "${SRCAPK}" "${VERSION}" "${NDK}"
56 | FAILSAFE_APK="MagiaTranslate_${VERSION}_failsafe.apk"
57 | mv "${RESULT}" "${BASEDIR}/${FAILSAFE_APK}"
58 | echo "FAILSAFE_APK=${FAILSAFE_APK}" >> "$GITHUB_ENV"
59 |
60 | rm "${BASEDIR}/builder.jks"
--------------------------------------------------------------------------------
/src/Utils.h:
--------------------------------------------------------------------------------
1 | #ifndef UTILS_H
2 | #define UTILS_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 |
16 | #ifdef NDEBUG
17 | #define RELEASE_BUILD
18 | #else
19 | #define DEBUG_BUILD
20 | #endif
21 |
22 | #ifdef DEBUG_BUILD
23 | #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, "MagiaHook", __VA_ARGS__)
24 | #else
25 | #define LOGD(...) do {} while(false)
26 | #endif
27 | #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, "MagiaHook", __VA_ARGS__)
28 | #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, "MagiaHook", __VA_ARGS__)
29 | #define LOGW(...) __android_log_print(ANDROID_LOG_WARN, "MagiaHook", __VA_ARGS__)
30 |
31 | typedef unsigned long DWORD;
32 |
33 | uintptr_t get_libBase(const char* libName);
34 |
35 | std::string get_libFoldername(const char* libName);
36 |
37 | void* lookup_symbol(const char* path, const char* symbolname);
38 |
39 | bool file_exists (const std::string& name);
40 |
41 | std::string getJNISignature();
42 | std::string getJNISignature(bool);
43 | std::string getJNISignature(char);
44 | std::string getJNISignature(short);
45 | std::string getJNISignature(int);
46 | std::string getJNISignature(long);
47 | std::string getJNISignature(float);
48 | std::string getJNISignature(double);
49 | std::string getJNISignature(const char*);
50 | std::string getJNISignature(const std::string&);
51 |
52 | template
53 | std::string getJNISignature(T x) {
54 | // This template should never be instantiated
55 | static_assert(sizeof(x) == 0, "Unsupported argument type");
56 | return "";
57 | }
58 |
59 | template
60 | std::string getJNISignature(T x, Ts... xs) {
61 | return getJNISignature(x) + getJNISignature(xs...);
62 | }
63 |
64 |
65 | JNIEnv* getEnv(JavaVM* gJvm);
66 | jclass findClass(JNIEnv* env, jobject gClassLoader, jmethodID gFindClassMethod, const char* name);
67 |
68 | // https://stackoverflow.com/a/26221725/9665729
69 | template
70 | std::string string_format( const std::string& format, Args ... args )
71 | {
72 | size_t size = snprintf( nullptr, 0, format.c_str(), args ... ) + 1; // Extra space for '\0'
73 | if( size <= 0 ){ throw std::runtime_error( "Error during formatting." ); }
74 | std::unique_ptr buf( new char[ size ] );
75 | snprintf( buf.get(), size, format.c_str(), args ... );
76 | return std::string( buf.get(), buf.get() + size - 1 ); // We don't want the '\0' inside
77 | }
78 |
79 | std::string longlong_to_string( unsigned long long value );
80 | #endif
81 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Magia Translate
2 | [](https://github.com/rayshift/magiatranslate/releases) [](https://github.com/rayshift/magiatranslate/releases) [](https://opensource.org/licenses/MIT) [](https://discord.gg/6vncnjj)
3 |
4 | This is the client source code for Magia Translate, an English translation modification for Magia Record JP. It is licensed under the MIT license.
5 |
6 | Magia Record JP has reached end of service as of the 31st July 2024. As such, this app has no further purpose, and has been retired. We thank you for your support over the last 4 years.
7 |
8 | ## How to build
9 | - Clone the repository including all submodules `git clone --recurse-submodules https://github.com/rayshift/magiatranslate`
10 | - If you don't have Android Studio installed, you may download [command line tools](https://developer.android.com/studio#command-tools) only.
11 | - Downlad `NDK` (`ndk;25.2.9519653`), `CMake` (`cmake;3.22.1`) and `Android SDK Build-Tools` (`build-tools;33.0.2`) with [sdkmanager](https://developer.android.com/studio/command-line/sdkmanager), or just use its GUI to install them if you have Android Studio installed.
12 | - Install the python requirements in requirements.txt.
13 | - Move `sign_example.bat` to `sign.bat` and add your jarsigner keystore, alias and password.
14 | - Place your magia record APKs in the `apk` and `armv7apk` directory.
15 | - Run `build_release.bat`.
16 |
17 | Notes:
18 | - Use `build_debug.bat` if you want a debug build with debug symbols.
19 | - If your apk has split ABIs (armeabi-v7a/arm64), you will need to move the other `libmadomagi_native.so` into `build/app/lib/{ARCH}`. For example, if the arm7 version of the game is placed in `apk/`, you need to move the `arm8` .so manually, and vice versa.
20 |
21 | ## Contributing
22 | Create a pull request with your contributions. Please do not submit any copyrighted content (images) to this repository.
23 |
24 | Ensure you test your changes on both armeabi-v7a and arm64-v8a. Also test an emulator such as Nox. To force install a specific ABI, use something like:
25 | `adb.exe -s device install --abi arm64-v8a -r -d .\MagiaTranslate_v2.2.6_v110.apk`
26 |
27 | ## Further reading
28 | - The server source code is now public at https://github.com/rayshift/kamihama-server - in order to change the server URL, edit the URLs in the smali file `smali/MagiaNative/app/src/main/java/io/kamihama/magianative/RestClient.smali`. You can also recompile the smali file by loading the MagiaNative project in Android Studio, editing `RestClient.java`, and compiling with this plugin: https://github.com/ollide/intellij-java2smali
29 | - The hooking library used is https://github.com/jmpews/Dobby.
30 |
--------------------------------------------------------------------------------
/patches/NativeBridge.patch:
--------------------------------------------------------------------------------
1 | diff --git a/build/app/smali/jp/f4samurai/bridge/NativeBridge.smali b/build/app/smali/jp/f4samurai/bridge/NativeBridge.smali
2 | index 6012fad..681a112 100644
3 | --- a/build/app/smali/jp/f4samurai/bridge/NativeBridge.smali
4 | +++ b/build/app/smali/jp/f4samurai/bridge/NativeBridge.smali
5 | @@ -8,8 +8,6 @@
6 |
7 | .field private static sAppActivity:Ljp/f4samurai/AppActivity;
8 |
9 | -.field private static sCheatHandler:Ljp/f4samurai/bridge/CheatHandler;
10 | -
11 | .field private static sClipboardManager:Landroid/content/ClipboardManager;
12 |
13 |
14 | @@ -43,15 +41,6 @@
15 |
16 | sput-object v0, Ljp/f4samurai/bridge/NativeBridge;->sAppActivity:Ljp/f4samurai/AppActivity;
17 |
18 | - .line 39
19 | - new-instance v0, Ljp/f4samurai/bridge/CheatHandler;
20 | -
21 | - sget-object v1, Ljp/f4samurai/bridge/NativeBridge;->sAppActivity:Ljp/f4samurai/AppActivity;
22 | -
23 | - invoke-direct {v0, v1}, Ljp/f4samurai/bridge/CheatHandler;->(Landroid/content/Context;)V
24 | -
25 | - sput-object v0, Ljp/f4samurai/bridge/NativeBridge;->sCheatHandler:Ljp/f4samurai/bridge/CheatHandler;
26 | -
27 | .line 40
28 | invoke-static {}, Ljp/f4samurai/AppActivity;->getContext()Landroid/content/Context;
29 |
30 | @@ -539,11 +528,7 @@
31 | .locals 1
32 |
33 | .line 195
34 | - sget-object v0, Ljp/f4samurai/bridge/NativeBridge;->sCheatHandler:Ljp/f4samurai/bridge/CheatHandler;
35 | -
36 | - invoke-virtual {v0}, Ljp/f4samurai/bridge/CheatHandler;->isUnauthorizedUser()Z
37 | -
38 | - move-result v0
39 | + const v0, 0
40 |
41 | return v0
42 | .end method
43 | @@ -649,13 +634,6 @@
44 | .locals 2
45 |
46 | .line 123
47 | - sget-object v0, Ljp/f4samurai/bridge/NativeBridge;->sAppActivity:Ljp/f4samurai/AppActivity;
48 | -
49 | - new-instance v1, Ljp/f4samurai/bridge/NativeBridge$2;
50 | -
51 | - invoke-direct {v1, p0}, Ljp/f4samurai/bridge/NativeBridge$2;->(Ljava/lang/String;)V
52 | -
53 | - invoke-virtual {v0, v1}, Ljp/f4samurai/AppActivity;->runOnUiThread(Ljava/lang/Runnable;)V
54 |
55 | return-void
56 | .end method
57 | @@ -664,13 +642,6 @@
58 | .locals 2
59 |
60 | .line 132
61 | - sget-object v0, Ljp/f4samurai/bridge/NativeBridge;->sAppActivity:Ljp/f4samurai/AppActivity;
62 | -
63 | - new-instance v1, Ljp/f4samurai/bridge/NativeBridge$3;
64 | -
65 | - invoke-direct {v1, p0, p1}, Ljp/f4samurai/bridge/NativeBridge$3;->(Ljava/lang/String;Ljava/lang/String;)V
66 | -
67 | - invoke-virtual {v0, v1}, Ljp/f4samurai/AppActivity;->runOnUiThread(Ljava/lang/Runnable;)V
68 |
69 | return-void
70 | .end method
71 | @@ -679,13 +650,6 @@
72 | .locals 2
73 |
74 | .line 114
75 | - sget-object v0, Ljp/f4samurai/bridge/NativeBridge;->sAppActivity:Ljp/f4samurai/AppActivity;
76 | -
77 | - new-instance v1, Ljp/f4samurai/bridge/NativeBridge$1;
78 | -
79 | - invoke-direct {v1, p0}, Ljp/f4samurai/bridge/NativeBridge$1;->(Ljava/lang/String;)V
80 | -
81 | - invoke-virtual {v0, v1}, Ljp/f4samurai/AppActivity;->runOnUiThread(Ljava/lang/Runnable;)V
82 |
83 | return-void
84 | .end method
85 |
--------------------------------------------------------------------------------
/src/libmadomagi.h:
--------------------------------------------------------------------------------
1 | enum BaseSceneLayerType {
2 | DebugMenuSceneLayer,
3 | DebugSelectQuestSceneLayer,
4 | DebugSelectStorySceneLayer,
5 | SoundViewerSceneLayer,
6 | DebugSelectMysteriesSceneLayer,
7 | AnimeViewerSceneLayer,
8 | CameraSceneLayer,
9 | WebSceneLayer,
10 | StartupSceneLayer,
11 | PrologueSceneLayer,
12 | AnotherQuestSceneLayer,
13 | TopSceneLayer,
14 | EventStoryRaidSceneLayer,
15 | EventBranchSceneLayer,
16 | EventSingleRaidSceneLayer,
17 | EventDungeonSceneLayer,
18 | EventRaidSceneLayer,
19 | EventPuellaHistoriaSceneLayer,
20 | QuestBattleSceneLayer,
21 | QuestUnitTestSceneLayer,
22 | EvolutionSceneLayer,
23 | MemoriaSceneLayer,
24 | GachaSceneLayer,
25 | StorySceneLayer,
26 | StoryViewerSceneLayer,
27 | Live2dViewerSceneLayer,
28 | MovieSceneLayer,
29 | DownloadSceneLayer,
30 | DebugSelectURLSceneLayer,
31 | QuestStoredDataSceneLayer,
32 | SendReplayDataSceneLayer,
33 | InputTextSceneLayer,
34 | SpfxViewerSceneLayer,
35 | LoadingSceneLayer,
36 | ErrorSceneLayer,
37 | NetworkErrorSceneLayer,
38 | TapSceneLayer,
39 | EmotionBoardSceneLayer,
40 | GlassTapSceneLayer,
41 | QuestViewerSceneLayer,
42 | BaseSceneLayerTypeMaxValue
43 | };
44 |
45 | char const* BaseSceneLayerTypeStrings[] {
46 | "DebugMenuSceneLayer",
47 | "DebugSelectQuestSceneLayer",
48 | "DebugSelectStorySceneLayer",
49 | "SoundViewerSceneLayer",
50 | "DebugSelectMysteriesSceneLayer",
51 | "AnimeViewerSceneLayer",
52 | "CameraSceneLayer",
53 | "WebSceneLayer",
54 | "StartupSceneLayer",
55 | "PrologueSceneLayer",
56 | "AnotherQuestSceneLayer",
57 | "TopSceneLayer",
58 | "EventStoryRaidSceneLayer",
59 | "EventBranchSceneLayer",
60 | "EventSingleRaidSceneLayer",
61 | "EventDungeonSceneLayer",
62 | "EventRaidSceneLayer",
63 | "EventPuellaHistoriaSceneLayer",
64 | "QuestBattleSceneLayer",
65 | "QuestUnitTestSceneLayer",
66 | "EvolutionSceneLayer",
67 | "MemoriaSceneLayer",
68 | "GachaSceneLayer",
69 | "StorySceneLayer",
70 | "StoryViewerSceneLayer",
71 | "Live2dViewerSceneLayer",
72 | "MovieSceneLayer",
73 | "DownloadSceneLayer",
74 | "DebugSelectURLSceneLayer",
75 | "QuestStoredDataSceneLayer",
76 | "SendReplayDataSceneLayer",
77 | "InputTextSceneLayer",
78 | "SpfxViewerSceneLayer",
79 | "LoadingSceneLayer",
80 | "ErrorSceneLayer",
81 | "NetworkErrorSceneLayer",
82 | "TapSceneLayer",
83 | "GlassTapSceneLayer",
84 | "QuestViewerSceneLayer",
85 | "EmotionBoardSceneLayer"
86 | };
87 |
88 | #if defined(__arm__)
89 | struct BaseSceneLayerInfo {
90 | char unk[24];
91 | BaseSceneLayerType layerType;
92 | };
93 | #elif defined(__aarch64__)
94 | struct BaseSceneLayerInfo {
95 | char unk[36];
96 | BaseSceneLayerType layerType;
97 | };
98 | #endif
99 |
100 | enum UrlConfigResourceType {
101 | BaseUrl,
102 | TrunkUrl,
103 | ScenarioUrl,
104 | UrlConfigResourceTypeMaxValue
105 | };
--------------------------------------------------------------------------------
/src/rest/MagiaRest.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include "../Utils.h"
3 | #include "../Config.h"
4 | #include
5 | #include
6 | #include
7 | #include "MagiaRest.h"
8 |
9 | const char* restClient = "io/kamihama/magianative/RestClient";
10 | using json = nlohmann::json;
11 |
12 | MagiaRest::MagiaRest(JavaVM* gJvm) {
13 | LOGD("Setting up MagiaRest.");
14 | env = getEnv(gJvm);
15 | klass = env->FindClass(restClient);
16 | jmethodID clientCtor = env->GetMethodID(klass, "", "()V");
17 | magiaRestObj = env->NewObject(klass, clientCtor);
18 | LOGD("Finished setting up MagiaRest.");
19 | }
20 |
21 | int MagiaRest::Endpoint() {
22 | const char* callHandshake = "GetEndpoint";
23 | std::string signature = "(I)Ljava/lang/String;";
24 | jmethodID messageid = env->GetMethodID(klass, callHandshake, signature.c_str());
25 |
26 | LOGD("Calling GetEndpoint via JNI.");
27 | endpointJString = (jstring)env->CallObjectMethod(magiaRestObj, messageid, MT_VERSION);
28 | endpointChar = env->GetStringUTFChars(endpointJString, 0);
29 |
30 | if (strcmp(endpointChar, "") == 0) {
31 | LOGW("Null response returned from endpoint, an error has occurred, or Kamihama is down.");
32 | return MAGIAREST_EMPTY;
33 | }
34 | LOGD("Successfully retrieved Endpoint JSON.");
35 |
36 | if (json::accept(endpointChar)) {
37 | endpointValid = true;
38 | endpointJson = json::parse(endpointChar);
39 |
40 | if (endpointJson["status"] != 200) {
41 | LOGW("Non-success result returned.");
42 | return MAGIAREST_ERROR;
43 | }
44 | }
45 | return endpointValid ? MAGIAREST_SUCCESS : MAGIAREST_EMPTY;
46 | }
47 |
48 | size_t MagiaRest::EndpointStringLength() {
49 | if (endpointChar == NULL) {
50 | return MAGIAREST_EMPTY;
51 | }
52 | else {
53 | auto size = std::strlen(endpointChar);
54 | return size;
55 | }
56 | }
57 |
58 | std::string MagiaRest::GetEndpointUrl() {
59 | if (endpointJson != NULL && endpointJson.contains("response") && endpointJson["response"].contains("endpoint")) {
60 | return endpointJson["response"]["endpoint"];
61 | }
62 | LOGW("No endpoint URL found in JSON response.");
63 | return "";
64 | }
65 |
66 | std::string MagiaRest::GetEndpointError() {
67 | if (endpointJson != NULL && endpointJson.contains("message")) {
68 | return endpointJson["message"];
69 | }
70 | LOGW("No message found in JSON response.");
71 | return "";
72 | }
73 | int MagiaRest::GetEndpointVersion() {
74 | if (endpointJson != NULL && endpointJson.contains("response") && endpointJson["response"].contains("version")) {
75 | return (int)endpointJson["response"]["version"];
76 | }
77 | LOGW("No version number found in JSON response.");
78 | return 0;
79 | }
80 |
81 | int MagiaRest::GetMaxThreads() {
82 | if (endpointJson != NULL && endpointJson.contains("response") && endpointJson["response"].contains("max_threads")) {
83 | return (int)endpointJson["response"]["max_threads"];
84 | }
85 | LOGW("No version number found in JSON response.");
86 | return 0;
87 | }
88 |
89 | MagiaRest::~MagiaRest() {
90 | if (endpointJString != NULL || endpointChar != NULL) {
91 | env->ReleaseStringUTFChars(endpointJString, endpointChar);
92 | }
93 | }
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # CMakeList.txt : CMake project for MagiaClient, include source and define
2 | # project specific logic here.
3 | #
4 | #set(CMAKE_CXX_STANDARD 11)
5 | cmake_minimum_required (VERSION 3.8)
6 |
7 | project ("MagiaClient")
8 | set(TARGET_NAME uwasa)
9 | #if (CMAKE_BUILD_TYPE STREQUAL "Debug")
10 | #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -stdlib=libc++ -fsanitize=address -fno-omit-frame-pointer")
11 | #else
12 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -stdlib=libc++")
13 | #endif(CMAKE_BUILD_TYPE STREQUAL "Debug")
14 |
15 |
16 | # Options
17 | set(compile_definitions "")
18 |
19 | option(MAGIA_TRANSLATE_AUDIOFIX_3_0_1 "Include audiofix for 3.0.1 and above" ON)
20 |
21 | if (MAGIA_TRANSLATE_AUDIOFIX_3_0_1)
22 | set(compile_definitions "${compile_definitions} -DMAGIA_TRANSLATE_AUDIOFIX_3_0_1")
23 | endif ()
24 |
25 | message(STATUS "[MagiaClient] MAGIA_TRANSLATE_AUDIOFIX_3_0_1: ${MAGIA_TRANSLATE_AUDIOFIX_3_0_1}")
26 |
27 |
28 | if(CMAKE_BUILD_TYPE STREQUAL "Release")
29 | set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -fvisibility=hidden -fvisibility-inlines-hidden -g0 -O3 -ffunction-sections -fdata-sections")
30 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fvisibility=hidden -fvisibility-inlines-hidden -g0 -O3 -ffunction-sections -fdata-sections")
31 | endif(CMAKE_BUILD_TYPE STREQUAL "Release")
32 |
33 | set(DobbyHome ${CMAKE_CURRENT_SOURCE_DIR}/lib/Dobby)
34 | include_directories(
35 | ${DobbyHome}/include
36 | ${DobbyHome}/builtin-plugin
37 | ${DobbyHome}/builtin-plugin/SymbolResolver
38 | ${DobbyHome}/external/logging
39 | ${DobbyHome}/source
40 | ${CMAKE_CURRENT_SOURCE_DIR}/lib
41 | ${CMAKE_CURRENT_SOURCE_DIR}/lib/cocos
42 | ${CMAKE_CURRENT_SOURCE_DIR}/abiproxy/src
43 | )
44 |
45 | include(FetchContent)
46 |
47 | FetchContent_Declare(json
48 | GIT_REPOSITORY https://github.com/ArthurSonzogni/nlohmann_json_cmake_fetchcontent
49 | GIT_TAG v3.9.1)
50 |
51 | FetchContent_GetProperties(json)
52 | if(NOT json_POPULATED)
53 | FetchContent_Populate(json)
54 | add_subdirectory(${json_SOURCE_DIR} ${json_BINARY_DIR} EXCLUDE_FROM_ALL)
55 | endif()
56 |
57 |
58 | if(CMAKE_BUILD_TYPE STREQUAL "Release")
59 | link_libraries("-Wl,--strip-all")
60 | endif(CMAKE_BUILD_TYPE STREQUAL "Release")
61 |
62 | add_library( # Sets the name of the library.
63 | ${TARGET_NAME}
64 | # Sets the library as a shared library.
65 | SHARED
66 |
67 | # Provides a relative path to your source file(s).
68 | "lib/cocos/math/CCGeometry.cpp"
69 | "lib/cocos/math/Vec2.cpp"
70 | "src/MagiaClient.cpp"
71 | "src/Utils.cpp"
72 | "src/rest/MagiaRest.cpp"
73 | )
74 |
75 | target_compile_definitions(${TARGET_NAME} PRIVATE "COMPILE_DEFINITIONS ${compile_definitions}")
76 |
77 | find_library(ANDROID_LOG_LIB log)
78 | target_link_libraries(${TARGET_NAME} PRIVATE ${ANDROID_LOG_LIB})
79 | target_link_libraries(${TARGET_NAME} PRIVATE dobby_static)
80 | target_link_libraries(${TARGET_NAME} PRIVATE nlohmann_json::nlohmann_json)
81 |
82 |
83 | macro(SET_OPTION option value)
84 | set(${option} ${value} CACHE INTERNAL "" FORCE)
85 | endmacro()
86 | if(CMAKE_BUILD_TYPE STREQUAL "Debug")
87 | SET_OPTION(DOBBY_DEBUG ON)
88 | endif(CMAKE_BUILD_TYPE STREQUAL "Debug")
89 | SET_OPTION(DOBBY_GENERATE_SHARED OFF)
90 | SET_OPTION(DynamicBinaryInstrument ON)
91 | SET_OPTION(NearBranch ON)
92 | SET_OPTION(Plugin.SymbolResolver ON)
93 |
94 | add_subdirectory(${DobbyHome} dobby)
95 |
--------------------------------------------------------------------------------
/src/Utils.cpp:
--------------------------------------------------------------------------------
1 | #include "Utils.h"
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 |
17 | typedef unsigned long DWORD;
18 |
19 | uintptr_t get_libBase(const char* libName) {
20 | FILE *fp;
21 | uintptr_t addr = 0;
22 | char filename[32], buffer[1024];
23 | snprintf(filename, sizeof(filename), "/proc/%d/maps", getpid());
24 | fp = fopen(filename, "rt");
25 | if (fp != NULL) {
26 | while (fgets(buffer, sizeof(buffer), fp)) {
27 | if (strstr(buffer, libName)) {
28 | addr = (uintptr_t) strtoul(buffer, NULL, 16);
29 | break;
30 | }
31 | }
32 | fclose(fp);
33 | }
34 | return addr;
35 | }
36 |
37 | std::string get_libFoldername(const char* libName) {
38 | FILE *fp;
39 | uintptr_t addr = 0;
40 | char filename[32], buffer[1024];
41 | snprintf(filename, sizeof(filename), "/proc/%d/maps", getpid());
42 | fp = fopen(filename, "rt");
43 | if (fp != NULL) {
44 | while (fgets(buffer, sizeof(buffer), fp)) {
45 | if (strstr(buffer, libName)) {
46 | std::string delimiter = "/";
47 | std::string strBuffer = buffer;
48 | std::string token = strBuffer.substr(strBuffer.find(delimiter), std::string::npos);
49 | return token;
50 | break;
51 | }
52 | }
53 | fclose(fp);
54 | }
55 | return "";
56 | }
57 |
58 | //uintptr_t getRealOffset(const char* libName, uintptr_t address) {
59 | //if (libBase == 0) {
60 | //libBase = get_libBase(libName);
61 | //}
62 | //return (libBase + address);
63 | //}
64 |
65 | void* lookup_symbol(const char* path, const char* symbolname)
66 | {
67 | void *imagehandle = dlopen(path, RTLD_GLOBAL | RTLD_NOW);
68 | if (imagehandle != NULL){
69 | void * sym = dlsym(imagehandle, symbolname);
70 | if (sym != NULL){
71 | dlclose(imagehandle);
72 | return sym;
73 | }
74 | else{
75 | LOGI("(lookup_symbol) dlsym didn't work: %s, %s\n", path, symbolname);
76 | dlclose(imagehandle);
77 | return NULL;
78 | }
79 | }
80 | else{
81 | LOGI("(lookup_symbol) dlerror: %s\n",dlerror());
82 | return NULL;
83 | }
84 | }
85 |
86 | bool file_exists (const std::string& name) {
87 | struct stat buffer;
88 | return (stat (name.c_str(), &buffer) == 0);
89 | }
90 |
91 | std::string getJNISignature() {
92 | return "";
93 | }
94 |
95 | std::string getJNISignature(bool) {
96 | return "Z";
97 | }
98 |
99 | std::string getJNISignature(char) {
100 | return "C";
101 | }
102 |
103 | std::string getJNISignature(short) {
104 | return "S";
105 | }
106 |
107 | std::string getJNISignature(int) {
108 | return "I";
109 | }
110 |
111 | std::string getJNISignature(long) {
112 | return "J";
113 | }
114 |
115 | std::string getJNISignature(float) {
116 | return "F";
117 | }
118 |
119 | std::string getJNISignature(double) {
120 | return "D";
121 | }
122 |
123 | std::string getJNISignature(const char*) {
124 | return "Ljava/lang/String;";
125 | }
126 |
127 | std::string getJNISignature(const std::string&) {
128 | return "Ljava/lang/String;";
129 | }
130 |
131 | JNIEnv* getEnv(JavaVM* gJvm) {
132 | JNIEnv *env;
133 | int status = gJvm->GetEnv((void**)&env, JNI_VERSION_1_6);
134 | if(status < 0) {
135 | status = gJvm->AttachCurrentThread(&env, NULL);
136 | if(status < 0) {
137 | LOGW("Null JNIEnv obtained!");
138 | return nullptr;
139 | }
140 | }
141 | return env;
142 | }
143 |
144 | jclass findClass(JNIEnv* env, jobject gClassLoader, jmethodID gFindClassMethod, const char* name) {
145 | return static_cast(env->CallObjectMethod(gClassLoader, gFindClassMethod, env->NewStringUTF(name)));
146 | }
147 |
148 | std::string longlong_to_string( unsigned long long value ){
149 | std::ostringstream os;
150 | os << value;
151 | return os.str();
152 | }
--------------------------------------------------------------------------------
/smali/MagiaNative/app/src/main/java/io/kamihama/magianative/RestClient.java:
--------------------------------------------------------------------------------
1 | package io.kamihama.magianative;
2 |
3 | import android.util.Log;
4 |
5 | import org.json.JSONException;
6 | import org.json.JSONObject;
7 |
8 | import java.io.IOException;
9 | import java.security.cert.CertificateException;
10 |
11 | import javax.net.ssl.HostnameVerifier;
12 | import javax.net.ssl.SSLContext;
13 | import javax.net.ssl.SSLSession;
14 | import javax.net.ssl.SSLSocketFactory;
15 | import javax.net.ssl.TrustManager;
16 | import javax.net.ssl.X509TrustManager;
17 |
18 | import okhttp3.MediaType;
19 | import okhttp3.OkHttpClient;
20 | import okhttp3.Request;
21 | import okhttp3.RequestBody;
22 | import okhttp3.Response;
23 |
24 | public class RestClient {
25 | private final String Endpoint = "https://walpurgisnacht.rayshift.io";
26 | private final String LogTag = "MagiaClientJNI";
27 | private String UserAgent = "okhttp3 " + System.getProperty("http.agent");
28 |
29 | public String GetEndpoint(int version) {
30 | JSONObject jsonString = new JSONObject();
31 |
32 | try {
33 | jsonString.put("version", version);
34 | } catch (JSONException e) {
35 | Log.e(LogTag, "Error adding version: " + e.toString());
36 | return "";
37 | }
38 |
39 | try {
40 | return postRequest(Endpoint + "/api/v1/endpoint", jsonString.toString());
41 | } catch (IOException e) {
42 | Log.e(LogTag, "Error with request: " + e.toString());
43 | return "";
44 | }
45 | }
46 |
47 | private static final MediaType JSON
48 | = MediaType.parse("application/json; charset=utf-8");
49 |
50 | private OkHttpClient client = getUnsafeOkHttpClient();
51 |
52 | private String postRequest (String url, String json) throws IOException {
53 | RequestBody body = RequestBody.create(JSON, json); // new
54 | // RequestBody body = RequestBody.create(JSON, json); // old
55 | Request request = new Request.Builder()
56 | .url(url)
57 | .post(body)
58 | .removeHeader("User-Agent")
59 | .addHeader("User-Agent", UserAgent)
60 | .build();
61 |
62 | Response response = client.newCall(request).execute();
63 |
64 | // Temporary workaround
65 | if ((response.code() == 307) || (response.code() == 308)) {
66 | String location = response.header("Location");
67 | if (location != null) {
68 | request = request.newBuilder()
69 | .url(location)
70 | .post(body)
71 | .removeHeader("User-Agent")
72 | .addHeader("User-Agent", UserAgent)
73 | .build();
74 |
75 | Response newResponse = client.newCall(request).execute();
76 | return newResponse.body() != null ? newResponse.body().string() : "";
77 | }
78 | }
79 | return response.body() != null ? response.body().string() : "";
80 | }
81 |
82 | private static OkHttpClient getUnsafeOkHttpClient() {
83 | try {
84 | // Create a trust manager that does not validate certificate chains
85 | final TrustManager[] trustAllCerts = new TrustManager[] {
86 | new X509TrustManager() {
87 | @Override
88 | public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
89 | }
90 |
91 | @Override
92 | public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
93 | }
94 |
95 | @Override
96 | public java.security.cert.X509Certificate[] getAcceptedIssuers() {
97 | return new java.security.cert.X509Certificate[]{};
98 | }
99 | }
100 | };
101 |
102 | // Install the all-trusting trust manager
103 | final SSLContext sslContext = SSLContext.getInstance("SSL");
104 | sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
105 | // Create an ssl socket factory with our all-trusting manager
106 | final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
107 |
108 | OkHttpClient.Builder builder = new OkHttpClient.Builder();
109 | builder.sslSocketFactory(sslSocketFactory, (X509TrustManager)trustAllCerts[0]);
110 | builder.hostnameVerifier(new HostnameVerifier() {
111 | @Override
112 | public boolean verify(String hostname, SSLSession session) {
113 | return true;
114 | }
115 | });
116 |
117 | OkHttpClient okHttpClient = builder.build();
118 | return okHttpClient;
119 | } catch (Exception e) {
120 | throw new RuntimeException(e);
121 | }
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/smali/MagiaNative/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/smali/MagiaNative/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | build/
2 | CMakeLists.txt.user
3 | CMakeCache.txt
4 | CMakeFiles
5 | CMakeScripts
6 | Testing
7 | Makefile
8 | cmake_install.cmake
9 | install_manifest.txt
10 | compile_commands.json
11 | CTestTestfile.cmake
12 | _deps
13 |
14 | .idea/
15 | apk/*.apk
16 | apk/*.old
17 | armv7apk/*.apk
18 | armv7apk/*.old
19 | *.keystore
20 | *.jks
21 |
22 | # Prerequisites
23 | *.d
24 |
25 | # Compiled Object files
26 | *.slo
27 | *.lo
28 | *.o
29 | *.obj
30 |
31 | # Precompiled Headers
32 | *.gch
33 | *.pch
34 |
35 | # Compiled Dynamic libraries
36 | *.so
37 | *.dylib
38 | *.dll
39 |
40 | # Fortran module files
41 | *.mod
42 | *.smod
43 |
44 | # Compiled Static libraries
45 | *.lai
46 | *.la
47 | *.a
48 | *.lib
49 |
50 | # Executables
51 | *.exe
52 | *.out
53 | *.app
54 |
55 | # Libs
56 | #lib/cocos
57 | #lib/Dobby
58 |
59 | ## Ignore Visual Studio temporary files, build results, and
60 | ## files generated by popular Visual Studio add-ons.
61 | ##
62 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
63 |
64 | # User-specific files
65 | *.rsuser
66 | *.suo
67 | *.user
68 | *.userosscache
69 | *.sln.docstates
70 |
71 | # User-specific files (MonoDevelop/Xamarin Studio)
72 | *.userprefs
73 |
74 | # Mono auto generated files
75 | mono_crash.*
76 |
77 | # Build results
78 | [Dd]ebug/
79 | [Dd]ebugPublic/
80 | [Rr]elease/
81 | [Rr]eleases/
82 | x64/
83 | x86/
84 | [Ww][Ii][Nn]32/
85 | [Aa][Rr][Mm]/
86 | [Aa][Rr][Mm]64/
87 | bld/
88 | [Bb]in/
89 | [Oo]bj/
90 | [Ll]og/
91 | [Ll]ogs/
92 |
93 | # Visual Studio 2015/2017 cache/options directory
94 | .vs/
95 | # Uncomment if you have tasks that create the project's static files in wwwroot
96 | #wwwroot/
97 |
98 | # Visual Studio 2017 auto generated files
99 | Generated\ Files/
100 |
101 | # MSTest test Results
102 | [Tt]est[Rr]esult*/
103 | [Bb]uild[Ll]og.*
104 |
105 | # NUnit
106 | *.VisualState.xml
107 | TestResult.xml
108 | nunit-*.xml
109 |
110 | # Build Results of an ATL Project
111 | [Dd]ebugPS/
112 | [Rr]eleasePS/
113 | dlldata.c
114 |
115 | # Benchmark Results
116 | BenchmarkDotNet.Artifacts/
117 |
118 | # .NET Core
119 | project.lock.json
120 | project.fragment.lock.json
121 | artifacts/
122 |
123 | # ASP.NET Scaffolding
124 | ScaffoldingReadMe.txt
125 |
126 | # StyleCop
127 | StyleCopReport.xml
128 |
129 | # Files built by Visual Studio
130 | *_i.c
131 | *_p.c
132 | *_h.h
133 | *.ilk
134 | *.meta
135 | *.obj
136 | *.iobj
137 | *.pch
138 | *.pdb
139 | *.ipdb
140 | *.pgc
141 | *.pgd
142 | *.rsp
143 | *.sbr
144 | *.tlb
145 | *.tli
146 | *.tlh
147 | *.tmp
148 | *.tmp_proj
149 | *_wpftmp.csproj
150 | *.log
151 | *.vspscc
152 | *.vssscc
153 | .builds
154 | *.pidb
155 | *.svclog
156 | *.scc
157 |
158 | # Chutzpah Test files
159 | _Chutzpah*
160 |
161 | # Visual C++ cache files
162 | ipch/
163 | *.aps
164 | *.ncb
165 | *.opendb
166 | *.opensdf
167 | *.sdf
168 | *.cachefile
169 | *.VC.db
170 | *.VC.VC.opendb
171 |
172 | # Visual Studio profiler
173 | *.psess
174 | *.vsp
175 | *.vspx
176 | *.sap
177 |
178 | # Visual Studio Trace Files
179 | *.e2e
180 |
181 | # TFS 2012 Local Workspace
182 | $tf/
183 |
184 | # Guidance Automation Toolkit
185 | *.gpState
186 |
187 | # ReSharper is a .NET coding add-in
188 | _ReSharper*/
189 | *.[Rr]e[Ss]harper
190 | *.DotSettings.user
191 |
192 | # TeamCity is a build add-in
193 | _TeamCity*
194 |
195 | # DotCover is a Code Coverage Tool
196 | *.dotCover
197 |
198 | # AxoCover is a Code Coverage Tool
199 | .axoCover/*
200 | !.axoCover/settings.json
201 |
202 | # Coverlet is a free, cross platform Code Coverage Tool
203 | coverage*.json
204 | coverage*.xml
205 | coverage*.info
206 |
207 | # Visual Studio code coverage results
208 | *.coverage
209 | *.coveragexml
210 |
211 | # NCrunch
212 | _NCrunch_*
213 | .*crunch*.local.xml
214 | nCrunchTemp_*
215 |
216 | # MightyMoose
217 | *.mm.*
218 | AutoTest.Net/
219 |
220 | # Web workbench (sass)
221 | .sass-cache/
222 |
223 | # Installshield output folder
224 | [Ee]xpress/
225 |
226 | # DocProject is a documentation generator add-in
227 | DocProject/buildhelp/
228 | DocProject/Help/*.HxT
229 | DocProject/Help/*.HxC
230 | DocProject/Help/*.hhc
231 | DocProject/Help/*.hhk
232 | DocProject/Help/*.hhp
233 | DocProject/Help/Html2
234 | DocProject/Help/html
235 |
236 | # Click-Once directory
237 | publish/
238 |
239 | # Publish Web Output
240 | *.[Pp]ublish.xml
241 | *.azurePubxml
242 | # Note: Comment the next line if you want to checkin your web deploy settings,
243 | # but database connection strings (with potential passwords) will be unencrypted
244 | *.pubxml
245 | *.publishproj
246 |
247 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
248 | # checkin your Azure Web App publish settings, but sensitive information contained
249 | # in these scripts will be unencrypted
250 | PublishScripts/
251 |
252 | # NuGet Packages
253 | *.nupkg
254 | # NuGet Symbol Packages
255 | *.snupkg
256 | # The packages folder can be ignored because of Package Restore
257 | **/[Pp]ackages/*
258 | # except build/, which is used as an MSBuild target.
259 | !**/[Pp]ackages/build/
260 | # Uncomment if necessary however generally it will be regenerated when needed
261 | #!**/[Pp]ackages/repositories.config
262 | # NuGet v3's project.json files produces more ignorable files
263 | *.nuget.props
264 | *.nuget.targets
265 |
266 | # Microsoft Azure Build Output
267 | csx/
268 | *.build.csdef
269 |
270 | # Microsoft Azure Emulator
271 | ecf/
272 | rcf/
273 |
274 | # Windows Store app package directories and files
275 | AppPackages/
276 | BundleArtifacts/
277 | Package.StoreAssociation.xml
278 | _pkginfo.txt
279 | *.appx
280 | *.appxbundle
281 | *.appxupload
282 |
283 | # Visual Studio cache files
284 | # files ending in .cache can be ignored
285 | *.[Cc]ache
286 | # but keep track of directories ending in .cache
287 | !?*.[Cc]ache/
288 |
289 | # Others
290 | ClientBin/
291 | ~$*
292 | *~
293 | *.dbmdl
294 | *.dbproj.schemaview
295 | *.jfm
296 | *.pfx
297 | *.publishsettings
298 | orleans.codegen.cs
299 |
300 | # Including strong name files can present a security risk
301 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
302 | #*.snk
303 |
304 | # Since there are multiple workflows, uncomment next line to ignore bower_components
305 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
306 | #bower_components/
307 |
308 | # RIA/Silverlight projects
309 | Generated_Code/
310 |
311 | # Backup & report files from converting an old project file
312 | # to a newer Visual Studio version. Backup files are not needed,
313 | # because we have git ;-)
314 | _UpgradeReport_Files/
315 | Backup*/
316 | UpgradeLog*.XML
317 | UpgradeLog*.htm
318 | ServiceFabricBackup/
319 | *.rptproj.bak
320 |
321 | # SQL Server files
322 | *.mdf
323 | *.ldf
324 | *.ndf
325 |
326 | # Business Intelligence projects
327 | *.rdl.data
328 | *.bim.layout
329 | *.bim_*.settings
330 | *.rptproj.rsuser
331 | *- [Bb]ackup.rdl
332 | *- [Bb]ackup ([0-9]).rdl
333 | *- [Bb]ackup ([0-9][0-9]).rdl
334 |
335 | # Microsoft Fakes
336 | FakesAssemblies/
337 |
338 | # GhostDoc plugin setting file
339 | *.GhostDoc.xml
340 |
341 | # Node.js Tools for Visual Studio
342 | .ntvs_analysis.dat
343 | node_modules/
344 |
345 | # Visual Studio 6 build log
346 | *.plg
347 |
348 | # Visual Studio 6 workspace options file
349 | *.opt
350 |
351 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
352 | *.vbw
353 |
354 | # Visual Studio LightSwitch build output
355 | **/*.HTMLClient/GeneratedArtifacts
356 | **/*.DesktopClient/GeneratedArtifacts
357 | **/*.DesktopClient/ModelManifest.xml
358 | **/*.Server/GeneratedArtifacts
359 | **/*.Server/ModelManifest.xml
360 | _Pvt_Extensions
361 |
362 | # Paket dependency manager
363 | .paket/paket.exe
364 | paket-files/
365 |
366 | # FAKE - F# Make
367 | .fake/
368 |
369 | # CodeRush personal settings
370 | .cr/personal
371 |
372 | # Python Tools for Visual Studio (PTVS)
373 | __pycache__/
374 | *.pyc
375 |
376 | # Cake - Uncomment if you are using it
377 | # tools/**
378 | # !tools/packages.config
379 |
380 | # Tabs Studio
381 | *.tss
382 |
383 | # Telerik's JustMock configuration file
384 | *.jmconfig
385 |
386 | # BizTalk build output
387 | *.btp.cs
388 | *.btm.cs
389 | *.odx.cs
390 | *.xsd.cs
391 |
392 | # OpenCover UI analysis results
393 | OpenCover/
394 |
395 | # Azure Stream Analytics local run output
396 | ASALocalRun/
397 |
398 | # MSBuild Binary and Structured Log
399 | *.binlog
400 |
401 | # NVidia Nsight GPU debugger configuration file
402 | *.nvuser
403 |
404 | # MFractors (Xamarin productivity tool) working folder
405 | .mfractor/
406 |
407 | # Local History for Visual Studio
408 | .localhistory/
409 |
410 | # BeatPulse healthcheck temp database
411 | healthchecksdb
412 |
413 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
414 | MigrationBackup/
415 |
416 | # Ionide (cross platform F# VS Code tools) working folder
417 | .ionide/
418 |
419 | # Fody - auto-generated XML schema
420 | FodyWeavers.xsd
421 |
422 | .vscode/
423 |
424 | abiproxy/build/
425 | abiproxy/.ninja_deps
426 | abiproxy/.ninja_log
427 | abiproxy/build.ninja
428 | lib/cocos_old/
429 | lib/Dobby_old/
430 | sign.bat
431 | sign.sh
432 | jarsign.sh
433 |
434 | # Android NDK, build-tools
435 | /ndk/
436 | /abt/
437 | com.aniplex.magireco.arm8.apk
438 | test/
439 |
--------------------------------------------------------------------------------
/patches/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Navigate home
4 | Navigate up
5 | More options
6 | Done
7 | See all
8 | Choose an app
9 | OFF
10 | ON
11 | sans-serif
12 | sans-serif-medium
13 | sans-serif-medium
14 | sans-serif
15 | sans-serif
16 | sans-serif
17 | sans-serif
18 | sans-serif-light
19 | sans-serif
20 | sans-serif
21 | sans-serif
22 | sans-serif-medium
23 | Alt+
24 | Ctrl+
25 | delete
26 | enter
27 | Function+
28 | Meta+
29 | Shift+
30 | space
31 | Sym+
32 | Menu+
33 | Search…
34 | Clear query
35 | Search query
36 | Search
37 | Submit query
38 | Voice search
39 | Share with
40 | Share with %s
41 | Collapse
42 | Magia Record JP
43 | APP
44 | RELEASE
45 | Ad
46 | Casting to %1$s
47 | Closed captions
48 | Closed captions unavailable
49 | Connecting to %1$s
50 | Disconnect
51 | Image displayed while the cast receiver is playing an ad
52 | Ad in progress…
53 | Album art
54 | Live stream
55 | Loading…
56 | Skip
57 | Forward
58 | Forward ten seconds
59 | Forward thirty seconds
60 | @android:string/ok
61 | --:--
62 | --:--
63 | Mute
64 | Connected to %1$s
65 | Connecting to %1$s
66 | Cast
67 | Disconnect
68 | Pause
69 | Play
70 | Rewind
71 | Rewind ten seconds
72 | Rewind thirty seconds
73 | Playback seek control
74 | Skip to next item
75 | Skip to previous item
76 | Stop
77 | Stop live stream
78 | Audio
79 | Cancel
80 | Closed Captions
81 | Track %1$d
82 | None
83 | OK
84 | Subtitles
85 | Unmute
86 | Enable
87 | "%1$s won't work unless you enable Google Play services."
88 | Enable Google Play services
89 | Install
90 | "%1$s won't run without Google Play services, which are missing from your device."
91 | Get Google Play services
92 | Google Play services availability
93 | Google Play services error
94 | %1$s is having trouble with Google Play services. Please try again.
95 | "%1$s won't run without Google Play services, which are not supported by your device."
96 | Update
97 | "%1$s won't run unless you update Google Play services."
98 | Update Google Play services
99 | "%1$s won't run without Google Play services, which are currently updating."
100 | New version of Google Play services needed. It will update itself shortly.
101 | Open on phone
102 | Sign in
103 | Sign in with Google
104 | 48695978581-l3g2vae3su7td5tilbunf8fpb1875np4.apps.googleusercontent.com
105 | android_channel_id
106 | Miscellaneous
107 | https://kamihama-io.firebaseio.com
108 | 48695978581
109 | Miscellaneous
110 | AIzaSyBlHoCTAsEa1zsIhKfE8nvMVewd0ULYmkw
111 | 1:48695978581:android:bc7cc007c2de2d0e79c2dc
112 | AIzaSyBlHoCTAsEa1zsIhKfE8nvMVewd0ULYmkw
113 | kamihama-io.appspot.com
114 | Cast button
115 | Cast button. Connected
116 | Cast button. Connecting
117 | Cast button. Disconnected
118 | Finding devices
119 | Cast to
120 | Album art
121 | Casting screen
122 | Close
123 | Collapse
124 | Disconnect
125 | Expand
126 | No info available
127 | No media selected
128 | Pause
129 | Play
130 | Stop
131 | Stop casting
132 | Volume slider
133 | System
134 | Devices
135 | Clear search
136 | Search
137 | magireco-754ac
138 | Save image
139 | Allow Ad to store image in Picture gallery?
140 | Accept
141 | Decline
142 | Create calendar event
143 | Allow Ad to create a calendar event?
144 | Test Ad
145 | Search
146 | PRODUCT
147 | 999+
148 | Continue
149 | Preview mode updated.
150 | Preview
151 | Buy with Google
152 | androidx.startup
153 |
154 |
--------------------------------------------------------------------------------
/smali/MagiaNative/app/src/main/java/io/kamihama/magianative/RestClient.smali:
--------------------------------------------------------------------------------
1 | .class public Lio/kamihama/magianative/RestClient;
2 | .super Ljava/lang/Object;
3 | .source "RestClient.java"
4 |
5 |
6 | # static fields
7 | .field private static final JSON:Lokhttp3/MediaType;
8 |
9 |
10 | # instance fields
11 | .field private final Endpoint:Ljava/lang/String;
12 |
13 | .field private final LogTag:Ljava/lang/String;
14 |
15 | .field private UserAgent:Ljava/lang/String;
16 |
17 | .field private client:Lokhttp3/OkHttpClient;
18 |
19 |
20 | # direct methods
21 | .method static constructor ()V
22 | .registers 1
23 |
24 | .prologue
25 | .line 47
26 | const-string v0, "application/json; charset=utf-8"
27 |
28 | .line 48
29 | invoke-static {v0}, Lokhttp3/MediaType;->parse(Ljava/lang/String;)Lokhttp3/MediaType;
30 |
31 | move-result-object v0
32 |
33 | sput-object v0, Lio/kamihama/magianative/RestClient;->JSON:Lokhttp3/MediaType;
34 |
35 | .line 47
36 | return-void
37 | .end method
38 |
39 | .method public constructor ()V
40 | .registers 3
41 |
42 | .prologue
43 | .line 24
44 | invoke-direct {p0}, Ljava/lang/Object;->()V
45 |
46 | .line 25
47 | const-string v0, "https://walpurgisnacht.rayshift.io"
48 |
49 | iput-object v0, p0, Lio/kamihama/magianative/RestClient;->Endpoint:Ljava/lang/String;
50 |
51 | .line 26
52 | const-string v0, "MagiaClientJNI"
53 |
54 | iput-object v0, p0, Lio/kamihama/magianative/RestClient;->LogTag:Ljava/lang/String;
55 |
56 | .line 27
57 | new-instance v0, Ljava/lang/StringBuilder;
58 |
59 | invoke-direct {v0}, Ljava/lang/StringBuilder;->()V
60 |
61 | const-string v1, "okhttp3 "
62 |
63 | invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
64 |
65 | move-result-object v0
66 |
67 | const-string v1, "http.agent"
68 |
69 | invoke-static {v1}, Ljava/lang/System;->getProperty(Ljava/lang/String;)Ljava/lang/String;
70 |
71 | move-result-object v1
72 |
73 | invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
74 |
75 | move-result-object v0
76 |
77 | invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
78 |
79 | move-result-object v0
80 |
81 | iput-object v0, p0, Lio/kamihama/magianative/RestClient;->UserAgent:Ljava/lang/String;
82 |
83 | .line 50
84 | invoke-static {}, Lio/kamihama/magianative/RestClient;->getUnsafeOkHttpClient()Lokhttp3/OkHttpClient;
85 |
86 | move-result-object v0
87 |
88 | iput-object v0, p0, Lio/kamihama/magianative/RestClient;->client:Lokhttp3/OkHttpClient;
89 |
90 | return-void
91 | .end method
92 |
93 | .method private static getUnsafeOkHttpClient()Lokhttp3/OkHttpClient;
94 | .registers 8
95 |
96 | .prologue
97 | .line 85
98 | const/4 v6, 0x1
99 |
100 | :try_start_1
101 | new-array v5, v6, [Ljavax/net/ssl/TrustManager;
102 |
103 | const/4 v6, 0x0
104 |
105 | new-instance v7, Lio/kamihama/magianative/RestClient$1;
106 |
107 | invoke-direct {v7}, Lio/kamihama/magianative/RestClient$1;->()V
108 |
109 | aput-object v7, v5, v6
110 |
111 | .line 103
112 | .local v5, "trustAllCerts":[Ljavax/net/ssl/TrustManager;
113 | const-string v6, "SSL"
114 |
115 | invoke-static {v6}, Ljavax/net/ssl/SSLContext;->getInstance(Ljava/lang/String;)Ljavax/net/ssl/SSLContext;
116 |
117 | move-result-object v3
118 |
119 | .line 104
120 | .local v3, "sslContext":Ljavax/net/ssl/SSLContext;
121 | const/4 v6, 0x0
122 |
123 | new-instance v7, Ljava/security/SecureRandom;
124 |
125 | invoke-direct {v7}, Ljava/security/SecureRandom;->()V
126 |
127 | invoke-virtual {v3, v6, v5, v7}, Ljavax/net/ssl/SSLContext;->init([Ljavax/net/ssl/KeyManager;[Ljavax/net/ssl/TrustManager;Ljava/security/SecureRandom;)V
128 |
129 | .line 106
130 | invoke-virtual {v3}, Ljavax/net/ssl/SSLContext;->getSocketFactory()Ljavax/net/ssl/SSLSocketFactory;
131 |
132 | move-result-object v4
133 |
134 | .line 108
135 | .local v4, "sslSocketFactory":Ljavax/net/ssl/SSLSocketFactory;
136 | new-instance v0, Lokhttp3/OkHttpClient$Builder;
137 |
138 | invoke-direct {v0}, Lokhttp3/OkHttpClient$Builder;->()V
139 |
140 | .line 109
141 | .local v0, "builder":Lokhttp3/OkHttpClient$Builder;
142 | const/4 v6, 0x0
143 |
144 | aget-object v6, v5, v6
145 |
146 | check-cast v6, Ljavax/net/ssl/X509TrustManager;
147 |
148 | invoke-virtual {v0, v4, v6}, Lokhttp3/OkHttpClient$Builder;->sslSocketFactory(Ljavax/net/ssl/SSLSocketFactory;Ljavax/net/ssl/X509TrustManager;)Lokhttp3/OkHttpClient$Builder;
149 |
150 | .line 110
151 | new-instance v6, Lio/kamihama/magianative/RestClient$2;
152 |
153 | invoke-direct {v6}, Lio/kamihama/magianative/RestClient$2;->()V
154 |
155 | invoke-virtual {v0, v6}, Lokhttp3/OkHttpClient$Builder;->hostnameVerifier(Ljavax/net/ssl/HostnameVerifier;)Lokhttp3/OkHttpClient$Builder;
156 |
157 | .line 117
158 | invoke-virtual {v0}, Lokhttp3/OkHttpClient$Builder;->build()Lokhttp3/OkHttpClient;
159 | :try_end_36
160 | .catch Ljava/lang/Exception; {:try_start_1 .. :try_end_36} :catch_38
161 |
162 | move-result-object v2
163 |
164 | .line 118
165 | .local v2, "okHttpClient":Lokhttp3/OkHttpClient;
166 | return-object v2
167 |
168 | .line 119
169 | .end local v0 # "builder":Lokhttp3/OkHttpClient$Builder;
170 | .end local v2 # "okHttpClient":Lokhttp3/OkHttpClient;
171 | .end local v3 # "sslContext":Ljavax/net/ssl/SSLContext;
172 | .end local v4 # "sslSocketFactory":Ljavax/net/ssl/SSLSocketFactory;
173 | :catch_38
174 | move-exception v1
175 |
176 | .line 120
177 | .local v1, "e":Ljava/lang/Exception;
178 | new-instance v6, Ljava/lang/RuntimeException;
179 |
180 | invoke-direct {v6, v1}, Ljava/lang/RuntimeException;->(Ljava/lang/Throwable;)V
181 |
182 | throw v6
183 | .end method
184 |
185 | .method private postRequest(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
186 | .registers 11
187 | .param p1, "url" # Ljava/lang/String;
188 | .param p2, "json" # Ljava/lang/String;
189 | .annotation system Ldalvik/annotation/Throws;
190 | value = {
191 | Ljava/io/IOException;
192 | }
193 | .end annotation
194 |
195 | .prologue
196 | .line 53
197 | sget-object v5, Lio/kamihama/magianative/RestClient;->JSON:Lokhttp3/MediaType;
198 |
199 | invoke-static {v5, p2}, Lokhttp3/RequestBody;->create(Lokhttp3/MediaType;Ljava/lang/String;)Lokhttp3/RequestBody;
200 |
201 | move-result-object v0
202 |
203 | .line 55
204 | .local v0, "body":Lokhttp3/RequestBody;
205 | new-instance v5, Lokhttp3/Request$Builder;
206 |
207 | invoke-direct {v5}, Lokhttp3/Request$Builder;->()V
208 |
209 | .line 56
210 | invoke-virtual {v5, p1}, Lokhttp3/Request$Builder;->url(Ljava/lang/String;)Lokhttp3/Request$Builder;
211 |
212 | move-result-object v5
213 |
214 | .line 57
215 | invoke-virtual {v5, v0}, Lokhttp3/Request$Builder;->post(Lokhttp3/RequestBody;)Lokhttp3/Request$Builder;
216 |
217 | move-result-object v5
218 |
219 | const-string v6, "User-Agent"
220 |
221 | .line 58
222 | invoke-virtual {v5, v6}, Lokhttp3/Request$Builder;->removeHeader(Ljava/lang/String;)Lokhttp3/Request$Builder;
223 |
224 | move-result-object v5
225 |
226 | const-string v6, "User-Agent"
227 |
228 | iget-object v7, p0, Lio/kamihama/magianative/RestClient;->UserAgent:Ljava/lang/String;
229 |
230 | .line 59
231 | invoke-virtual {v5, v6, v7}, Lokhttp3/Request$Builder;->addHeader(Ljava/lang/String;Ljava/lang/String;)Lokhttp3/Request$Builder;
232 |
233 | move-result-object v5
234 |
235 | .line 60
236 | invoke-virtual {v5}, Lokhttp3/Request$Builder;->build()Lokhttp3/Request;
237 |
238 | move-result-object v3
239 |
240 | .line 62
241 | .local v3, "request":Lokhttp3/Request;
242 | iget-object v5, p0, Lio/kamihama/magianative/RestClient;->client:Lokhttp3/OkHttpClient;
243 |
244 | invoke-virtual {v5, v3}, Lokhttp3/OkHttpClient;->newCall(Lokhttp3/Request;)Lokhttp3/Call;
245 |
246 | move-result-object v5
247 |
248 | invoke-interface {v5}, Lokhttp3/Call;->execute()Lokhttp3/Response;
249 |
250 | move-result-object v4
251 |
252 | .line 65
253 | .local v4, "response":Lokhttp3/Response;
254 | invoke-virtual {v4}, Lokhttp3/Response;->code()I
255 |
256 | move-result v5
257 |
258 | const/16 v6, 0x133
259 |
260 | if-eq v5, v6, :cond_3f
261 |
262 | invoke-virtual {v4}, Lokhttp3/Response;->code()I
263 |
264 | move-result v5
265 |
266 | const/16 v6, 0x134
267 |
268 | if-ne v5, v6, :cond_81
269 |
270 | .line 66
271 | :cond_3f
272 | const-string v5, "Location"
273 |
274 | invoke-virtual {v4, v5}, Lokhttp3/Response;->header(Ljava/lang/String;)Ljava/lang/String;
275 |
276 | move-result-object v1
277 |
278 | .line 67
279 | .local v1, "location":Ljava/lang/String;
280 | if-eqz v1, :cond_81
281 |
282 | .line 68
283 | invoke-virtual {v3}, Lokhttp3/Request;->newBuilder()Lokhttp3/Request$Builder;
284 |
285 | move-result-object v5
286 |
287 | .line 69
288 | invoke-virtual {v5, v1}, Lokhttp3/Request$Builder;->url(Ljava/lang/String;)Lokhttp3/Request$Builder;
289 |
290 | move-result-object v5
291 |
292 | .line 70
293 | invoke-virtual {v5, v0}, Lokhttp3/Request$Builder;->post(Lokhttp3/RequestBody;)Lokhttp3/Request$Builder;
294 |
295 | move-result-object v5
296 |
297 | const-string v6, "User-Agent"
298 |
299 | .line 71
300 | invoke-virtual {v5, v6}, Lokhttp3/Request$Builder;->removeHeader(Ljava/lang/String;)Lokhttp3/Request$Builder;
301 |
302 | move-result-object v5
303 |
304 | const-string v6, "User-Agent"
305 |
306 | iget-object v7, p0, Lio/kamihama/magianative/RestClient;->UserAgent:Ljava/lang/String;
307 |
308 | .line 72
309 | invoke-virtual {v5, v6, v7}, Lokhttp3/Request$Builder;->addHeader(Ljava/lang/String;Ljava/lang/String;)Lokhttp3/Request$Builder;
310 |
311 | move-result-object v5
312 |
313 | .line 73
314 | invoke-virtual {v5}, Lokhttp3/Request$Builder;->build()Lokhttp3/Request;
315 |
316 | move-result-object v3
317 |
318 | .line 75
319 | iget-object v5, p0, Lio/kamihama/magianative/RestClient;->client:Lokhttp3/OkHttpClient;
320 |
321 | invoke-virtual {v5, v3}, Lokhttp3/OkHttpClient;->newCall(Lokhttp3/Request;)Lokhttp3/Call;
322 |
323 | move-result-object v5
324 |
325 | invoke-interface {v5}, Lokhttp3/Call;->execute()Lokhttp3/Response;
326 |
327 | move-result-object v2
328 |
329 | .line 76
330 | .local v2, "newResponse":Lokhttp3/Response;
331 | invoke-virtual {v2}, Lokhttp3/Response;->body()Lokhttp3/ResponseBody;
332 |
333 | move-result-object v5
334 |
335 | if-eqz v5, :cond_7e
336 |
337 | invoke-virtual {v2}, Lokhttp3/Response;->body()Lokhttp3/ResponseBody;
338 |
339 | move-result-object v5
340 |
341 | invoke-virtual {v5}, Lokhttp3/ResponseBody;->string()Ljava/lang/String;
342 |
343 | move-result-object v5
344 |
345 | .line 79
346 | .end local v1 # "location":Ljava/lang/String;
347 | .end local v2 # "newResponse":Lokhttp3/Response;
348 | :goto_7d
349 | return-object v5
350 |
351 | .line 76
352 | .restart local v1 # "location":Ljava/lang/String;
353 | .restart local v2 # "newResponse":Lokhttp3/Response;
354 | :cond_7e
355 | const-string v5, ""
356 |
357 | goto :goto_7d
358 |
359 | .line 79
360 | .end local v1 # "location":Ljava/lang/String;
361 | .end local v2 # "newResponse":Lokhttp3/Response;
362 | :cond_81
363 | invoke-virtual {v4}, Lokhttp3/Response;->body()Lokhttp3/ResponseBody;
364 |
365 | move-result-object v5
366 |
367 | if-eqz v5, :cond_90
368 |
369 | invoke-virtual {v4}, Lokhttp3/Response;->body()Lokhttp3/ResponseBody;
370 |
371 | move-result-object v5
372 |
373 | invoke-virtual {v5}, Lokhttp3/ResponseBody;->string()Ljava/lang/String;
374 |
375 | move-result-object v5
376 |
377 | goto :goto_7d
378 |
379 | :cond_90
380 | const-string v5, ""
381 |
382 | goto :goto_7d
383 | .end method
384 |
385 |
386 | # virtual methods
387 | .method public GetEndpoint(I)Ljava/lang/String;
388 | .registers 7
389 | .param p1, "version" # I
390 |
391 | .prologue
392 | .line 30
393 | new-instance v1, Lorg/json/JSONObject;
394 |
395 | invoke-direct {v1}, Lorg/json/JSONObject;->()V
396 |
397 | .line 33
398 | .local v1, "jsonString":Lorg/json/JSONObject;
399 | :try_start_5
400 | const-string v2, "version"
401 |
402 | invoke-virtual {v1, v2, p1}, Lorg/json/JSONObject;->put(Ljava/lang/String;I)Lorg/json/JSONObject;
403 | :try_end_a
404 | .catch Lorg/json/JSONException; {:try_start_5 .. :try_end_a} :catch_15
405 |
406 | .line 40
407 | :try_start_a
408 | const-string v2, "https://walpurgisnacht.rayshift.io/api/v1/endpoint"
409 |
410 | invoke-virtual {v1}, Lorg/json/JSONObject;->toString()Ljava/lang/String;
411 |
412 | move-result-object v3
413 |
414 | invoke-direct {p0, v2, v3}, Lio/kamihama/magianative/RestClient;->postRequest(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
415 | :try_end_13
416 | .catch Ljava/io/IOException; {:try_start_a .. :try_end_13} :catch_35
417 |
418 | move-result-object v2
419 |
420 | .line 43
421 | :goto_14
422 | return-object v2
423 |
424 | .line 34
425 | :catch_15
426 | move-exception v0
427 |
428 | .line 35
429 | .local v0, "e":Lorg/json/JSONException;
430 | const-string v2, "MagiaClientJNI"
431 |
432 | new-instance v3, Ljava/lang/StringBuilder;
433 |
434 | invoke-direct {v3}, Ljava/lang/StringBuilder;->()V
435 |
436 | const-string v4, "Error adding version: "
437 |
438 | invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
439 |
440 | move-result-object v3
441 |
442 | invoke-virtual {v0}, Lorg/json/JSONException;->toString()Ljava/lang/String;
443 |
444 | move-result-object v4
445 |
446 | invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
447 |
448 | move-result-object v3
449 |
450 | invoke-virtual {v3}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
451 |
452 | move-result-object v3
453 |
454 | invoke-static {v2, v3}, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I
455 |
456 | .line 36
457 | const-string v2, ""
458 |
459 | goto :goto_14
460 |
461 | .line 41
462 | .end local v0 # "e":Lorg/json/JSONException;
463 | :catch_35
464 | move-exception v0
465 |
466 | .line 42
467 | .local v0, "e":Ljava/io/IOException;
468 | const-string v2, "MagiaClientJNI"
469 |
470 | new-instance v3, Ljava/lang/StringBuilder;
471 |
472 | invoke-direct {v3}, Ljava/lang/StringBuilder;->()V
473 |
474 | const-string v4, "Error with request: "
475 |
476 | invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
477 |
478 | move-result-object v3
479 |
480 | invoke-virtual {v0}, Ljava/io/IOException;->toString()Ljava/lang/String;
481 |
482 | move-result-object v4
483 |
484 | invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
485 |
486 | move-result-object v3
487 |
488 | invoke-virtual {v3}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
489 |
490 | move-result-object v3
491 |
492 | invoke-static {v2, v3}, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I
493 |
494 | .line 43
495 | const-string v2, ""
496 |
497 | goto :goto_14
498 | .end method
499 |
--------------------------------------------------------------------------------
/src/MagiaClient.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include "Utils.h"
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include "Config.h"
16 | #include
17 | #include "libmadomagi.h"
18 | #include "rest/MagiaRest.h"
19 |
20 | #define RT_FAILED -1
21 | #define RS_SUCCESS 0
22 |
23 | const char* libName = "libmadomagi_native.so";
24 | const char* hookName = "libuwasa.so";
25 |
26 | JavaVM* gJvm = nullptr;
27 | static jobject gClassLoader;
28 | static jmethodID gFindClassMethod;
29 | uintptr_t libBase = 0;
30 |
31 | //namespace fs = std::filesystem; ndk 22+ required
32 |
33 | struct hook_loop_args {
34 | std::string libso;
35 | };
36 |
37 | uintptr_t storyMessageUnitStartOffset = 0;
38 | uintptr_t storyMessageUnitCreateMessageAreaOffset = 0;
39 | uintptr_t storyLogUnitAddMessageOffset = 0;
40 | uintptr_t storyLogUnitAddNarrationOffset = 0;
41 | uintptr_t storyCharaUnitonTextHomeOffset = 0;
42 | uintptr_t storyNarrationUnitCreateLabelOffset = 0;
43 | uintptr_t initCenterWidthOutline = 0;
44 |
45 | int max_threads = 10;
46 |
47 | void* openMessageBoxPtr = nullptr;
48 | uintptr_t* resourceUrlPtr = nullptr;
49 |
50 | bool initialized = false;
51 |
52 | const std::string assetBase = "/magica/resource";
53 | const std::string assetTrunk = "/download/asset/master";
54 | const std::string assetScenario = "/resource/scenario";
55 | std::vector> urlEndpoints(3);
56 |
57 | const std::string koruriFont("fonts/koruri-semibold.ttf");
58 |
59 | typedef int *(*setUrlType)(int *);
60 | typedef int *(*setResourceType)(int *, unsigned int *);
61 | typedef uintptr_t *(*UrlConfigImplResourceType)(uintptr_t &a1, int a2, unsigned int a3, int a4);
62 |
63 | // Hooked functions
64 | void *(*setPositionHooked)(uintptr_t label, cocos2d::Vec2 const& position);
65 | void *(*setMaxLineWidthHooked)(uintptr_t label, float length);
66 | void *(*setDimensionsHooked)(uintptr_t label, float width, float a3);
67 |
68 | const std::string* (*urlConfigResourceHooked)(void* a1, UrlConfigResourceType type); // There is also api, chat, web, etc for other endpoints
69 |
70 | //void* urlConfig_ImplObj = nullptr;
71 |
72 | // Cocos functions
73 | typedef cocos2d::Director* (*director_type)(void* dummy);
74 | typedef const cocos2d::Size& (*get_win_size_type)(cocos2d::Director* director);
75 | typedef cocos2d::Vec2 (*get_visible_origin_type)(cocos2d::Director* director);
76 |
77 | director_type getDirector;
78 | get_win_size_type getWinSize;
79 | get_visible_origin_type getVisibleOrigin;
80 |
81 | /* BROKEN
82 | void testDialogue() {
83 | if (openMessageBoxPtr != nullptr) {
84 | auto x = DialogueBoxProxy();
85 | x.DialogueBox(openMessageBoxPtr);
86 | }
87 | }*/
88 | jclass findClass(JNIEnv* env, const char* name) {
89 | return static_cast(env->CallObjectMethod(gClassLoader, gFindClassMethod, env->NewStringUTF(name)));
90 | }
91 |
92 | void displayMessage(const std::string& title, const std::string& description) {
93 | auto env = getEnv(gJvm);
94 | const char* cocosHelper = "org/cocos2dx/lib/Cocos2dxHelper";
95 | const char* showDialogueBox = "showDialog";
96 | std::string signature = "(" + std::string(getJNISignature(title, description)) + ")V";
97 |
98 | jclass klass = findClass(env, cocosHelper);
99 | if (klass == nullptr) {
100 | LOGE("No Cocos2dxHelper found.");
101 | return;
102 | }
103 |
104 | jmethodID mid = env->GetStaticMethodID(klass, showDialogueBox, signature.c_str());
105 | if (mid == nullptr) {
106 | LOGE("No showDialog found.");
107 | return;
108 | }
109 | jstring str1 = env->NewStringUTF(title.c_str());
110 | jstring str2 = env->NewStringUTF(description.c_str());
111 | env->CallStaticObjectMethod(klass, mid, str1, str2);
112 | }
113 |
114 | int *(*sceneLayerManagerCreateSceneLayerOld)(uintptr_t *sceneLayerManager, BaseSceneLayerInfo* sceneLayerInfo);
115 |
116 | int *sceneLayerManagerCreateSceneLayer(uintptr_t *sceneLayerManager, BaseSceneLayerInfo* sceneLayerInfo) {
117 | auto sceneType = sceneLayerInfo->layerType;
118 | if (sceneType >= BaseSceneLayerType::BaseSceneLayerTypeMaxValue || sceneType < 0) {
119 | LOGW("Unknown scene triggered. %d", sceneType);
120 | }
121 | else {
122 | LOGI("Scene layer changed to: %s", BaseSceneLayerTypeStrings[sceneType]);
123 | }
124 |
125 | if (!initialized && sceneType == BaseSceneLayerType::WebSceneLayer) { // Set up everything here
126 | auto rest = MagiaRest(gJvm);
127 | switch(rest.Endpoint()) {
128 | case MAGIAREST_EMPTY:
129 | {
130 | auto emptyMessage = string_format("Unable to connect to the translation server. Restart the app to retry, or continue to play in Japanese. (Response length: %zu)",
131 | rest.EndpointStringLength());
132 |
133 | displayMessage("MagiaTranslate Error", emptyMessage.c_str());
134 | break;
135 | }
136 | case MAGIAREST_ERROR:
137 | {
138 | auto errorMessage = string_format("An error has occurred. Restart the app to retry, or continue to play in Japanese.\nError: %s", rest.GetEndpointError().c_str());
139 | displayMessage("MagiaTranslate Error", errorMessage.c_str());
140 | break;
141 | }
142 | case MAGIAREST_SUCCESS:
143 | {
144 | auto ver = rest.GetEndpointVersion();
145 | if (MT_VERSION < ver) {
146 | LOGI("Version update required.");
147 | auto updateMessage = string_format("A new version of MagiaTranslate is available, please update your app at kamihama.io. Continuing may result in crashes.\nApp version installed: %d\nApp version available: %d",
148 | MT_VERSION, ver);
149 | displayMessage("MagiaTranslate Update", updateMessage.c_str());
150 | }
151 | auto endpointUrl = rest.GetEndpointUrl();
152 | if (endpointUrl.empty()) {
153 | LOGW("Empty endpoint URL.");
154 | displayMessage("MagiaTranslate Error", "Error 115 has occurred, the returned translate endpoint URL is empty, please try again later.");
155 | break;
156 | }
157 |
158 | // Set max download threads
159 | auto mt = rest.GetMaxThreads();
160 | if (mt > 0) {
161 | LOGD("Set maximum threads from API, value %d.", mt);
162 | max_threads = mt;
163 | }
164 |
165 | const std::string assetNameBase = endpointUrl + assetBase;
166 | const std::string assetNameFull = endpointUrl + assetBase + assetTrunk;
167 | const std::string assetNameScript = endpointUrl + assetBase + assetTrunk + assetScenario;
168 |
169 | //std::string assetNameBaseProxy(assetNameBase.c_str());
170 | //std::string assetNameFullProxy(assetNameFull.c_str());
171 | //std::string assetNameScriptProxy(assetNameScript.c_str());
172 |
173 | LOGD("Setting endpoint URLs.");
174 | LOGD("%s", assetNameScript.c_str());
175 |
176 | urlEndpoints.at(UrlConfigResourceType::BaseUrl) = std::make_shared(assetNameBase);
177 | urlEndpoints.at(UrlConfigResourceType::TrunkUrl) = std::make_shared(assetNameFull);
178 | urlEndpoints.at(UrlConfigResourceType::ScenarioUrl) = std::make_shared(assetNameScript);
179 | LOGD("Finished setting endpoint URLs.");
180 | break;
181 | }
182 | }
183 |
184 | initialized = true;
185 | auto y = sceneLayerManagerCreateSceneLayerOld(sceneLayerManager, sceneLayerInfo);
186 | return y;
187 | }
188 |
189 | return sceneLayerManagerCreateSceneLayerOld(sceneLayerManager, sceneLayerInfo);
190 |
191 | }
192 |
193 | // Change function to fetch resource URLs
194 | const std::string* urlConfigResource(void* a1, UrlConfigResourceType type) {
195 | LOGD("Fetching URL config resource %d", (int)type);
196 | if (type < UrlConfigResourceType::UrlConfigResourceTypeMaxValue) {
197 | try {
198 | if (urlEndpoints.at(type) != nullptr && urlEndpoints.at(type).get() != nullptr) {
199 | auto url = (urlEndpoints.at(type)).get();
200 | LOGD("URL: %s", url->c_str());
201 | return url;
202 | }
203 | else {
204 | LOGW("Empty endpoint found for endpoint type %d!", (int)type);
205 | }
206 | }
207 | catch (std::out_of_range const& exc) {
208 | LOGW("Out of range for endpoint type %d!", (int)type);
209 | }
210 | }
211 | return urlConfigResourceHooked(a1, type);
212 | }
213 |
214 |
215 | void* (*cocosCreateLabelHooked)(const uintptr_t* textPtr, const std::string &fontPtr, float textSize, cocos2d::Size const& cocosSize, cocos2d::TextHAlignment hAlign, cocos2d::TextVAlignment vAlign);
216 | void* cocosCreateLabel(const uintptr_t* textPtr, const std::string &fontPtr, float textSize, cocos2d::Size const& cocosSize, cocos2d::TextHAlignment hAlign, cocos2d::TextVAlignment vAlign) {
217 | uintptr_t addr = reinterpret_cast(__builtin_extract_return_addr(__builtin_return_address(0)));
218 | LOGD("Label created at %p (%p), size %.1f.", (void*) addr, (void*)(addr - libBase), textSize);
219 | if (storyMessageUnitCreateMessageAreaOffset != 0 && addr >= storyMessageUnitCreateMessageAreaOffset) {
220 | uintptr_t difference = addr - storyMessageUnitCreateMessageAreaOffset;
221 | if (difference <= 0x200) {
222 | LOGD("Setting new text font for main story text.");
223 | if (textSize == 27.0) {
224 | textSize = 30.0;
225 | }
226 | return cocosCreateLabelHooked(textPtr, koruriFont, textSize, cocosSize, hAlign, vAlign);
227 | }
228 | }
229 | if (storyNarrationUnitCreateLabelOffset != 0 && addr >= storyNarrationUnitCreateLabelOffset) {
230 | uintptr_t difference = addr - storyNarrationUnitCreateLabelOffset;
231 |
232 | if (difference <= 0x200) { // 0x8e
233 | LOGD("Setting new narration text font. Difference: %p", (void*)difference);
234 | return cocosCreateLabelHooked(textPtr, koruriFont, textSize, cocosSize, hAlign, vAlign);
235 | }
236 | }
237 | if (initCenterWidthOutline != 0 && addr >= initCenterWidthOutline) {
238 | uintptr_t difference = addr - initCenterWidthOutline;
239 |
240 | if (difference <= 0x200) {
241 | LOGD("Setting new home text font and size.");
242 | textSize = textSize * 0.85;
243 | return cocosCreateLabelHooked(textPtr, koruriFont, textSize, cocosSize, hAlign, vAlign);
244 | }
245 | }
246 | if (storyLogUnitAddMessageOffset != 0 && addr >= storyLogUnitAddMessageOffset) {
247 | uintptr_t difference = addr - storyLogUnitAddMessageOffset;
248 |
249 | if (difference <= 0x640) { // 0xec, 0x54e
250 | LOGD("Setting new log text font. Difference: %p", (void*)difference);
251 | return cocosCreateLabelHooked(textPtr, koruriFont, textSize, cocosSize, hAlign, vAlign);
252 | }
253 | }
254 | if (storyLogUnitAddNarrationOffset != 0 && addr >= storyLogUnitAddNarrationOffset) {
255 | uintptr_t difference = addr - storyLogUnitAddNarrationOffset;
256 | if (difference <= 0x640) { // 0x43e, 0x5b0
257 | LOGD("Setting new log text font (narration). Difference: %p", (void*)difference);
258 | return cocosCreateLabelHooked(textPtr, koruriFont, textSize, cocosSize, hAlign, vAlign);
259 | }
260 | }
261 | return cocosCreateLabelHooked(textPtr, fontPtr, textSize, cocosSize, hAlign, vAlign);
262 |
263 | }
264 |
265 | // New functions
266 | void *setPositionNew(uintptr_t label, cocos2d::Vec2 const& position) {
267 | uintptr_t addr = reinterpret_cast(__builtin_extract_return_addr(__builtin_return_address(0)));
268 | //LOGI("Move at %p to x: %.2f, y: %.2f", (addr - libBase), position.x, position.y);
269 |
270 | // Story message boxes
271 | if (storyMessageUnitStartOffset != 0 && addr >= storyMessageUnitStartOffset) {
272 | uintptr_t difference = addr - storyMessageUnitStartOffset;
273 |
274 | // Alignment of main text in box
275 | if (difference <= 0x200) { // Offset = 0x76 as of 2.15
276 | LOGD("Moving story text.");
277 | //LOGI("Difference: %p", difference);
278 | //LOGD("old [message] x: %.2f, y: %.2f", position.x, position.y);
279 |
280 | // Move text to the left and up a bit
281 | if (position.x == -222.0 && position.y == 20.0) {
282 | cocos2d::Vec2 newPosition = cocos2d::Vec2(-368.0, 25.0);
283 | //LOGD("new 1 x: %.2f, y: %.2f", newPosition.x, newPosition.y);
284 | return setPositionHooked(label, newPosition);
285 | }
286 | else if (position.x == -207.0 && position.y == 30.0) {
287 | cocos2d::Vec2 newPosition = cocos2d::Vec2(-360.0, 40.0);
288 | //LOGD("new 2 x: %.2f, y: %.2f", newPosition.x, newPosition.y);
289 | return setPositionHooked(label, newPosition);
290 | }
291 | }
292 |
293 | }
294 |
295 |
296 | // Names alignment
297 | if (storyMessageUnitCreateMessageAreaOffset != 0 && addr >= storyMessageUnitCreateMessageAreaOffset) {
298 |
299 | uintptr_t difference = addr - storyMessageUnitCreateMessageAreaOffset;
300 | //LOGI("Difference: %p", difference);
301 |
302 | // Move names into the right place
303 | if (difference <= 0x600) { // Offset = 0x35e as of 2.15
304 | //LOGD("old [name] x: %.2f, y: %.2f", position.x, position.y);
305 | LOGD("Moving story name.");
306 | if (position.x == -215.0 && position.y == 57.0) { // Left names
307 | cocos2d::Vec2 newPosition = cocos2d::Vec2(-320.0, 55.0);
308 | //LOGD("new l-1 x: %.2f, y: %.2f", newPosition.x, newPosition.y);
309 | return setPositionHooked(label, newPosition);
310 | }
311 | else if (position.x == -55.0 && position.y == 57.0) { // Center names
312 | cocos2d::Vec2 newPosition = cocos2d::Vec2(30.0, 55.0);
313 | //LOGD("new m-1 x: %.2f, y: %.2f", newPosition.x, newPosition.y);
314 | return setPositionHooked(label, newPosition);
315 | }
316 | else if (position.x == 215.0 && position.y == 57.0) { // Right names
317 | cocos2d::Vec2 newPosition = cocos2d::Vec2(320.0, 55.0);
318 | //LOGD("new r-1 x: %.2f, y: %.2f", newPosition.x, newPosition.y);
319 | return setPositionHooked(label, newPosition);
320 | }
321 | }
322 |
323 | }
324 |
325 | // History
326 | if (storyLogUnitAddMessageOffset != 0 && addr >= storyLogUnitAddMessageOffset) {
327 | uintptr_t difference = addr - storyLogUnitAddMessageOffset;
328 | LOGD("LOG MESSAGE: %.2f %.2f", position.x, position.y);
329 | LOGD("Difference: %p", (void *)difference);
330 | //if (position.y >= 55.50 && position.y <= 56.50 && difference <= 0x1000) {
331 | if ((position.y >= 37.5 && position.y <= 39.5 && difference <= 0x1300)
332 | || (position.y >= 55.00 && position.y <= 56.00 && difference <= 0x1300)) {
333 | float newPosX = position.x + 125.0;
334 | LOGD("Moved log text from %.2f to %.2f", position.x, newPosX);
335 | cocos2d::Vec2 newPosition = cocos2d::Vec2(newPosX, 66.50);
336 | return setPositionHooked(label, newPosition);
337 | }
338 | else if (difference <= 0x400 && position.x == 70.00) {
339 | LOGD("Moving left-aligned name down in the log.");
340 | auto newY = position.y;
341 | cocos2d::Vec2 newPosition = cocos2d::Vec2(position.x, newY);
342 | return setPositionHooked(label, newPosition);
343 | }
344 | else if (difference <= 0x400 && position.x == 500.00) { // Names on the right
345 | LOGD("Moving name further to the right in log.");
346 | auto newX = position.x + 200;
347 | //auto newY = position.y - 15.0;
348 | auto newY = position.y;
349 | cocos2d::Vec2 newPosition = cocos2d::Vec2(newX, newY);
350 | return setPositionHooked(label, newPosition);
351 | }
352 | else if (difference <= 0x400 && position.x == 280.00) { // Names in the center, 280.00?
353 | LOGD("Moving center name to the left in the log.");
354 | auto newX = 71.50;
355 | auto newY = position.y;
356 | cocos2d::Vec2 newPosition = cocos2d::Vec2(newX, newY);
357 | return setPositionHooked(label, newPosition);
358 | }
359 | }
360 | return setPositionHooked(label, position);
361 | }
362 |
363 | void *setMaxLineWidthNew(uintptr_t label, float length) {
364 | //LOGI("Hook triggered - line length");
365 | uintptr_t addr = reinterpret_cast(__builtin_extract_return_addr(__builtin_return_address(0)));
366 | //LOGI("%p", (addr - libBase));
367 |
368 | if (storyMessageUnitCreateMessageAreaOffset != 0 && addr >= storyMessageUnitCreateMessageAreaOffset) {
369 | uintptr_t difference = addr - storyMessageUnitCreateMessageAreaOffset;
370 | //LOGI("Difference: %p", difference);
371 |
372 | // Make lines longer
373 | if (difference <= 0x244 && length == 410.0) { // Offset = 0x144 as of 2.15
374 | LOGD("Set line length from 410.0 to 810.0");
375 | length = 810.0;
376 | }
377 | }
378 | return setMaxLineWidthHooked(label, length);
379 | }
380 |
381 | void *setDimensionsNew(uintptr_t label, float width, float height) {
382 | uintptr_t addr = reinterpret_cast(__builtin_extract_return_addr(__builtin_return_address(0)));
383 | uintptr_t difference = addr - storyLogUnitAddMessageOffset;
384 | //LOGI("Difference [dimensions]: %p, addr: %p", difference, addr);
385 |
386 | if (storyLogUnitAddMessageOffset != 0 && addr >= storyLogUnitAddMessageOffset) {
387 | //LOGI("%p, %.2f, %.2f", label, width, a3);
388 | if (difference <= 0x900 && width == 410.0) { // Offset = 0x5ac as of 2.15
389 | LOGD("Set dimensions for log from 410.0 to 710.0.");
390 | return setDimensionsHooked(label, 710.0, height);
391 | }
392 | }
393 | //LOGD("Dimensions: %f, %f", width, height);
394 | return setDimensionsHooked(label, width, height);
395 | }
396 |
397 | // Fix the position of homeText under live2d girls
398 | cocos2d::Size (*lbGetViewPositionHooked)(float x, float y);
399 | cocos2d::Size lbGetViewPositionNew(float x, float y) {
400 | uintptr_t addr = reinterpret_cast(__builtin_extract_return_addr(__builtin_return_address(0)));
401 | uintptr_t difference = addr - storyCharaUnitonTextHomeOffset;
402 | //LOGD("Difference (viewPos): %p, addr: %p", (void*)difference, (void*)addr);
403 |
404 | if (storyCharaUnitonTextHomeOffset != 0 && addr >= storyCharaUnitonTextHomeOffset) {
405 | if (difference <= 0x1300) {
406 | auto oldx = x;
407 | auto oldy = y;
408 | if (x > -100.0) {
409 | x = -120.0;
410 | }
411 | if (x == -100.0) {
412 | x = -250.0;
413 | }
414 | x = x - 30.0;
415 | y = y - 30.0;
416 | LOGD("Set live2d subtitle dimensions from (%f, %f) to (%f, %f).", oldx, oldy, x, y);
417 | }
418 | }
419 |
420 | #if defined(__aarch64__)
421 | return lbGetViewPositionHooked(x, y);
422 | #endif
423 | //LOGI("Size 1: %f, size 2: %f", sizes.width, sizes.height);
424 |
425 | // Reimplement from scratch because arm is bugged (also this segfaults on arm64)
426 | auto director = getDirector((void *)0x00);
427 | //LOGI("Obtained director at %p.", (void*) director);
428 |
429 | auto dirSize = getWinSize(director);
430 | //LOGI("Obtained winsize, %f %f.", dirSize.width, dirSize.height);
431 | auto origin = getVisibleOrigin(director);
432 | //LOGI("Obtained visible origin, %f %f.", origin.x, origin.y);
433 | auto sizes = cocos2d::Size();
434 | sizes.width = origin.x + x + (float)dirSize.width * 0.5;
435 | sizes.height = origin.y + y + (float)dirSize.height * 0.5;
436 | //sizes.width = origin.x + x + (float)dirSize.width * 0.5;
437 | //sizes.height = origin.y + y + (float)dirSize.height * 0.5;
438 |
439 | //LOGI("NEW size 1: %f, size 2: %f", sizes.width, sizes.height);
440 | return sizes;
441 | }
442 |
443 |
444 | pthread_mutex_t *(*setUriDebugOld)(uintptr_t a1, const std::string &st);
445 | pthread_mutex_t *setUriDebug(uintptr_t a1, const std::string &stri) {
446 | auto mut = setUriDebugOld(a1, stri);
447 |
448 | auto outstr = stri.c_str();
449 | LOGI("Uri base set: %s", outstr);
450 | return mut;
451 | }
452 |
453 | pthread_mutex_t *(*http2SessionSetMaxConnectionNumOld)(uintptr_t *session, int max);
454 |
455 | pthread_mutex_t *http2SessionSetMaxConnectionNum(uintptr_t *session, int max) {
456 | if (max == 4) {
457 | max = max_threads;
458 | }
459 | LOGD("Set max number of connections to %d.", max);
460 | return http2SessionSetMaxConnectionNumOld(session, max);
461 | }
462 |
463 | #if defined(MAGIA_TRANSLATE_AUDIOFIX_3_0_1)
464 | uint32_t (*criNcv_GetHardwareSamplingRate_ANDROID_Hooked)();
465 |
466 | uint32_t criNcv_GetHardwareSamplingRate_ANDROID() {
467 | auto orig = criNcv_GetHardwareSamplingRate_ANDROID_Hooked();
468 | auto value = orig;
469 | value = 48000;
470 | LOGI("using hardware sample rate: %d (orig: %d)", value, orig);
471 | return value;
472 | }
473 |
474 | void *(*criNcv_SetHardwareSamplingRate_ANDROID_Hooked)(uint32_t value);
475 |
476 | void criNcv_SetHardwareSamplingRate_ANDROID(uint32_t value) {
477 | LOGI("set cached hardware sample rate to %d", value);
478 | criNcv_SetHardwareSamplingRate_ANDROID_Hooked(value);
479 | }
480 | #endif
481 |
482 | void initialization_error(const char* error) {
483 | LOGE("%s", error);
484 | auto errorMsg = string_format("A critical error has occurred, MagiaTranslate will not work properly and may crash. Please report this error on GitHub or Discord.\n%s", error);
485 | displayMessage("MagiaTranslate Error", errorMsg);
486 | }
487 |
488 | // Hook loop function. We run this in a separate thread so it doesn't block the main thread.
489 | void *hook_loop(void *arguments) {
490 | std::unique_ptr args((struct hook_loop_args *)arguments);
491 | auto libLocation = (args->libso).c_str();
492 |
493 | LOGI("Library location: %s", libLocation);
494 |
495 | while(libBase == 0) {
496 | libBase = get_libBase(libName);
497 | }
498 | LOGI("Base address: %p", (void*)libBase);
499 |
500 | // Hook resource endpoint
501 | void *resourceHook = lookup_symbol(libLocation, "_ZNK9UrlConfig8resourceENS_8Resource4TypeE"); // UrlConfig::resource(UrlConfig::Resource::Type)const
502 | if (DobbyHook(resourceHook, (void *)urlConfigResource, (void **)&urlConfigResourceHooked) == RS_SUCCESS) {
503 | LOGI("Successfully hooked UrlConfig::resource.");
504 | }
505 | else {
506 | initialization_error("Failed to hook UrlConfig::resource.");
507 | pthread_exit(NULL);
508 | }
509 |
510 |
511 | // Hook scene creator
512 | void *sceneHook = lookup_symbol(libLocation, "_ZN17SceneLayerManager16createSceneLayerEP18BaseSceneLayerInfo"); //_DWORD __fastcall SceneLayerManager::createSceneLayer(SceneLayerManager *__hidden this, BaseSceneLayerInfo *)
513 | if (DobbyHook(sceneHook, (void *)sceneLayerManagerCreateSceneLayer, (void **)&sceneLayerManagerCreateSceneLayerOld) == RS_SUCCESS) {
514 | LOGI("Successfully hooked SceneLayerManager::createSceneLayer.");
515 | }
516 | else {
517 | initialization_error("Failed to hook SceneLayerManager::createSceneLayer.");
518 | pthread_exit(NULL);
519 | }
520 |
521 | // Speed up downloads
522 | void *maxDlHook = lookup_symbol(libLocation, "_ZN5http212Http2Session19setMaxConnectionNumEi"); //_DWORD __fastcall http2::Http2Session::setMaxConnectionNum(http2::Http2Session *__hidden this, int)
523 | if (DobbyHook(maxDlHook, (void *)http2SessionSetMaxConnectionNum, (void **)&http2SessionSetMaxConnectionNumOld) == RS_SUCCESS) {
524 | LOGI("Successfully hooked http2::Http2Session::setMaxConnectionNum.");
525 | }
526 | else {
527 | LOGW("Failed to hook http2::Http2Session::setMaxConnectionNum.");
528 | }
529 |
530 |
531 | //openMessageBoxPtr = lookup_symbol(libLocation, "_ZN10MessageBox4openEPKcS1_S1_RKSt8functionIFvPN7cocos2d3RefEEEb");
532 | //LOGI("Set openMessageBox ptr to %p", openMessageBoxPtr);
533 |
534 | // For debugging
535 | //DobbyHook(lookup_symbol(libLocation, "_ZN5http212Http2Session6setURIERKSs"), (void *)setUriDebug, (void **)&setUriDebugOld); - crashes arm32 now.
536 |
537 | #if defined(MAGIA_TRANSLATE_AUDIOFIX_3_0_1)
538 | // audio pitch & speed fix
539 | void *getHWSampleRate = lookup_symbol(libLocation, "criNcv_GetHardwareSamplingRate_ANDROID");
540 |
541 | if (getHWSampleRate != nullptr) {
542 | LOGD("Found criNcv_GetHardwareSamplingRate_ANDROID at %p.", (void *)getHWSampleRate);
543 | if (DobbyHook(getHWSampleRate, (void *)criNcv_GetHardwareSamplingRate_ANDROID, (void **)&criNcv_GetHardwareSamplingRate_ANDROID_Hooked) == RS_SUCCESS) {
544 | LOGI("Successfully hooked criNcv_GetHardwareSamplingRate_ANDROID.");
545 | }
546 | else {
547 | initialization_error("Unable to hook criNcv_GetHardwareSamplingRate_ANDROID.");
548 | pthread_exit(NULL);
549 | }
550 | }
551 | else {
552 | initialization_error("Unable to hook criNcv_GetHardwareSamplingRate_ANDROID.");
553 | pthread_exit(NULL);
554 | }
555 |
556 | void *setHWSampleRate = lookup_symbol(libLocation, "criNcv_SetHardwareSamplingRate_ANDROID");
557 |
558 | if (setHWSampleRate != nullptr) {
559 | LOGD("Found criNcv_SetHardwareSamplingRate_ANDROID at %p.", (void *)setHWSampleRate);
560 | if (DobbyHook(setHWSampleRate, (void *)criNcv_SetHardwareSamplingRate_ANDROID, (void **)&criNcv_SetHardwareSamplingRate_ANDROID_Hooked) == RS_SUCCESS) {
561 | LOGI("Successfully hooked criNcv_SetHardwareSamplingRate_ANDROID.");
562 | }
563 | else {
564 | initialization_error("Unable to hook criNcv_SetHardwareSamplingRate_ANDROID.");
565 | pthread_exit(NULL);
566 | }
567 | }
568 | else {
569 | initialization_error("Unable to hook criNcv_SetHardwareSamplingRate_ANDROID.");
570 | pthread_exit(NULL);
571 | }
572 | #endif
573 |
574 | // Hooks
575 | void *cocos2dnodeSetPosition = lookup_symbol(libLocation, "_ZN7cocos2d4Node11setPositionERKNS_4Vec2E");
576 | // cocos2d::Node::setPosition(cocos2d::Vec2 const&)
577 | if (cocos2dnodeSetPosition != nullptr) {
578 | LOGD("Found cocos2d::Node::setPosition at %p.", (void *)cocos2dnodeSetPosition);
579 | if (DobbyHook(cocos2dnodeSetPosition, (void *)setPositionNew, (void **)&setPositionHooked) == RS_SUCCESS) {
580 | LOGI("Successfully hooked cocos2d::Node::setPosition.");
581 | }
582 | else {
583 | initialization_error("Unable to hook cocos2d::Node::setPosition.");
584 | pthread_exit(NULL);
585 | }
586 | }
587 | else {
588 | initialization_error("Unable to hook cocos2d::Node::setPosition.");
589 | pthread_exit(NULL);
590 | }
591 |
592 | void *cocos2dlineLength = lookup_symbol(libLocation, "_ZN7cocos2d5Label15setMaxLineWidthEf");
593 | // cocos2d::Label::setMaxLineWidth(float)
594 | if (cocos2dlineLength != nullptr) {
595 | LOGD("Found cocos2d::Label::setMaxLineWidth at %p.", (void *)cocos2dlineLength);
596 | if (DobbyHook(cocos2dlineLength, (void *)setMaxLineWidthNew, (void **)&setMaxLineWidthHooked) == RS_SUCCESS) {
597 | LOGI("Successfully hooked cocos2d::Label::setMaxLineWidth.");
598 | }
599 | else {
600 | initialization_error("Unable to hook cocos2d::Label::setMaxLineWidth.");
601 | pthread_exit(NULL);
602 | }
603 | }
604 | else {
605 | initialization_error("Unable to hook cocos2d::Label::setMaxLineWidth.");
606 | pthread_exit(NULL);
607 | }
608 |
609 | void *cocos2dsetDimensions = lookup_symbol(libLocation, "_ZN7cocos2d5Label13setDimensionsEff");
610 | //_DWORD __fastcall cocos2d::Label::setDimensions(cocos2d::Label *__hidden this, float, float)
611 | if (cocos2dsetDimensions != nullptr) {
612 | LOGD("Found cocos2d::Label::setDimensions at %p.", (void *)cocos2dsetDimensions);
613 | if (DobbyHook(cocos2dsetDimensions, (void *)setDimensionsNew, (void **)&setDimensionsHooked) == RS_SUCCESS) {
614 | LOGI("Successfully hooked cocos2d::Label::setDimensions.");
615 | }
616 | else {
617 | initialization_error("Unable to hook cocos2d::Label::setDimensions.");
618 | pthread_exit(NULL);
619 | }
620 | }
621 | else {
622 | initialization_error("Unable to hook cocos2d::Label::setDimensions.");
623 | pthread_exit(NULL);
624 | }
625 |
626 | // For moving live2d subtitles
627 | void *lbGetViewPosition = lookup_symbol(libLocation, "_ZN9LbUtility15getViewPositionEff");
628 | //_DWORD __fastcall LbUtility::getViewPosition(LbUtility *__hidden this, float, float)
629 | if (lbGetViewPosition != nullptr) {
630 | LOGD("Found LbUtility::getViewPosition at %p.", (void *)lbGetViewPosition);
631 | if (DobbyHook(lbGetViewPosition, (void *)lbGetViewPositionNew, (void **)&lbGetViewPositionHooked) == RS_SUCCESS) {
632 | LOGI("Successfully hooked LbUtility::getViewPosition.");
633 | }
634 | else {
635 | initialization_error("Unable to hook LbUtility::getViewPosition.");
636 | pthread_exit(NULL);
637 | }
638 | }
639 | else {
640 | initialization_error("Unable to hook LbUtility::getViewPosition.");
641 | pthread_exit(NULL);
642 | }
643 |
644 | // Change font
645 | void *cocosCreateLabelPtr = lookup_symbol(libLocation, "_ZN7cocos2d5Label13createWithTTFERKNSt6__ndk112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEES9_fRKNS_4SizeENS_14TextHAlignmentENS_14TextVAlignmentE");
646 |
647 | if (cocosCreateLabelPtr != nullptr) {
648 | LOGD("Found cocos2d::Label::createWithTTF at %p.", (void *)cocosCreateLabel);
649 | if (DobbyHook(cocosCreateLabelPtr, (void*) cocosCreateLabel, (void **)& cocosCreateLabelHooked) == RS_SUCCESS) {
650 | LOGI("Successfully hooked cocos2d::Label::createWithTTF.");
651 | }
652 | else {
653 | initialization_error("Unable to hook cocos2d::Label::createWithTTF.");
654 | pthread_exit(NULL);
655 | }
656 | }
657 | else {
658 | initialization_error("Unable to hook cocos2d::Label::createWithTTF.");
659 | pthread_exit(NULL);
660 | }
661 |
662 |
663 | // Find key functions, TODO: Tidy up into 1 nice loop
664 |
665 | void *storyMessageUnitTextStart = lookup_symbol(libLocation, "_ZN16StoryMessageUnit9textStartENS_11TextPosType13TextPosType__E");
666 | // StoryMessageUnit::textStart(StoryMessageUnit::TextPosType::TextPosType__)
667 | if (storyMessageUnitTextStart == nullptr) {
668 | initialization_error("Unable to find a pointer for StoryMessageUnit::textStart.");
669 | pthread_exit(NULL);
670 | }
671 | storyMessageUnitStartOffset = reinterpret_cast(storyMessageUnitTextStart);
672 |
673 | void *storyMessageUnitCreateMessageArea = lookup_symbol(libLocation, "_ZN16StoryMessageUnit17createMessageAreaENS_11TextPosType13TextPosType__E");
674 | // StoryMessageUnit::createMessageArea(StoryMessageUnit::TextPosType::TextPosType__)
675 | if (storyMessageUnitCreateMessageArea == nullptr) {
676 | initialization_error("Unable to find a pointer for StoryMessageUnit::createMessageArea.");
677 | pthread_exit(NULL);
678 | }
679 | storyMessageUnitCreateMessageAreaOffset = reinterpret_cast(storyMessageUnitCreateMessageArea);
680 |
681 | void *storyLogUnitAddMessage = lookup_symbol(libLocation, "_ZN12StoryLogUnit10addMessageENS_11MessageType13MessageType__ERKNSt6__ndk112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE");
682 |
683 | if (storyLogUnitAddMessage == nullptr) {
684 | initialization_error("Unable to find a pointer for StoryLogUnit::addMessage.");
685 | pthread_exit(NULL);
686 | }
687 | storyLogUnitAddMessageOffset = reinterpret_cast(storyLogUnitAddMessage);
688 |
689 | void *storyLogUnitAddNarrationOffsetPtr = lookup_symbol(libLocation, "_ZN12StoryLogUnit19addNarrationMessageERKNSt6__ndk112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE");
690 |
691 | if (storyLogUnitAddNarrationOffsetPtr == nullptr) {
692 | initialization_error("Unable to find a pointer for StoryLogUnit::addNarrationMessage.");
693 | pthread_exit(NULL);
694 | }
695 |
696 | storyLogUnitAddNarrationOffset = reinterpret_cast(storyLogUnitAddNarrationOffsetPtr);
697 |
698 | void *storyCharaUnitonTextHome = lookup_symbol(libLocation, "_ZN14StoryCharaUnit10onTextHomeENSt6__ndk110shared_ptrI16StoryTurnCommandEEb");
699 | // StoryCharaUnit::onTextHome(std::shared_ptr, bool)
700 |
701 | if (storyCharaUnitonTextHome == nullptr) {
702 | initialization_error("Unable to find a pointer for StoryCharaUnit::onTextHome.");
703 | pthread_exit(NULL);
704 | }
705 | storyCharaUnitonTextHomeOffset = reinterpret_cast(storyCharaUnitonTextHome);
706 |
707 | void *initLabelCWO = lookup_symbol(libLocation, "_ZN9LbUtility27initLabelCenterWidthOutlineEPN7cocos2d4NodeERPNS0_5LabelEPKcfNS0_4Vec2EiNS0_4SizeEiNS0_7Color4BEiSA_");
708 | // LbUtility::initLabelCenterWidthOutline(cocos2d::Node *, cocos2d::Label *&, char const*, float, cocos2d::Vec2, int, cocos2d::Size, int, cocos2d::Color4B, int, cocos2d::Color4B)
709 |
710 | if (initLabelCWO == nullptr) {
711 | initialization_error("Unable to find a pointer for LbUtility::initLabelCenterWidthOutline.");
712 | pthread_exit(NULL);
713 | }
714 | initCenterWidthOutline = reinterpret_cast(initLabelCWO);
715 |
716 | void* storyNarrationUnitCreateLabelPtr = lookup_symbol(libLocation, "_ZN18StoryNarrationUnit11createLabelEv");
717 |
718 | if (storyNarrationUnitCreateLabelPtr == nullptr) {
719 | initialization_error("Unable to find a pointer for StoryNarrationUnit::createLabel.");
720 | pthread_exit(NULL);
721 | }
722 |
723 | storyNarrationUnitCreateLabelOffset = reinterpret_cast(storyNarrationUnitCreateLabelPtr);
724 |
725 | // Cocos functions
726 | void *directorPtr = lookup_symbol(libLocation, "_ZN7cocos2d8Director11getInstanceEv");
727 | if (directorPtr == nullptr) {
728 | initialization_error("Unable to find a pointer for cocos2d::Director::getInstance()");
729 | pthread_exit(NULL);
730 | }
731 | getDirector = (director_type) directorPtr;
732 |
733 | void* getWinSizePtr = lookup_symbol(libLocation, "_ZNK7cocos2d8Director10getWinSizeEv");
734 | if (getWinSizePtr == nullptr) {
735 | initialization_error("Unable to find a pointer for cocos2d::Director::getWinSize()");
736 | pthread_exit(NULL);
737 | }
738 | getWinSize = (get_win_size_type) getWinSizePtr;
739 |
740 | void* getVisibleOriginPtr = lookup_symbol(libLocation, "_ZNK7cocos2d8Director16getVisibleOriginEv");
741 | if (getVisibleOriginPtr == nullptr) {
742 | initialization_error("Unable to find a pointer for cocos2d::Director::getVisibleOrigin()");
743 | pthread_exit(NULL);
744 | }
745 | getVisibleOrigin = (get_visible_origin_type) getVisibleOriginPtr;
746 |
747 |
748 |
749 | LOGI("Exiting hook thread.");
750 | pthread_exit(NULL);
751 | }
752 |
753 | __attribute__((constructor))
754 | void hook_main() {
755 |
756 | }
757 |
758 | extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved) {
759 | LOGI("Starting MagiaHook.");
760 |
761 | gJvm = vm; // cache the JavaVM pointer
762 | Dl_info dlInfo;
763 | JNIEnv* env;
764 | if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK)
765 | {
766 | return -1;
767 | }
768 |
769 | // https://stackoverflow.com/a/16302771/9665729
770 | // Cache ClassLoader object due to threading bug
771 | auto randomClass = env->FindClass("org/cocos2dx/lib/Cocos2dxHelper");
772 | jclass classClass = env->GetObjectClass(randomClass);
773 | auto classLoaderClass = env->FindClass("java/lang/ClassLoader");
774 | auto getClassLoaderMethod = env->GetMethodID(classClass, "getClassLoader",
775 | "()Ljava/lang/ClassLoader;");
776 | gClassLoader = env->NewGlobalRef(env->CallObjectMethod(randomClass, getClassLoaderMethod));
777 | gFindClassMethod = env->GetMethodID(classLoaderClass, "findClass",
778 | "(Ljava/lang/String;)Ljava/lang/Class;");
779 |
780 |
781 | if (dladdr((const void*) hook_main, &dlInfo))
782 | {
783 | //fs::path ilso = fs::path(dlInfo.dli_fname).remove_filename(); ndk 22+ required
784 | //ilso /= "il2cpp.so"; ndk 22+ required
785 | hook_loop_args* args = new hook_loop_args;
786 | auto ilso = (std::string) dirname((char *)dlInfo.dli_fname);
787 |
788 | ilso += "/";
789 | ilso += libName;
790 |
791 | //if (fs::exists(ilso)) { ndk 22+ required
792 | if (!file_exists(ilso)) {
793 | // Fix for some devices
794 | auto this_ilso = get_libFoldername(hookName);
795 | if (this_ilso.empty()) {
796 | LOGE("Failed to locate shared library %s. Checked: %s", libName, ilso.c_str());
797 | return JNI_VERSION_1_6;
798 | }
799 |
800 | auto ilso2 = this_ilso.substr(0, this_ilso.length() - strlen(hookName) - 1);
801 | ilso2 += libName;
802 | if (!file_exists(ilso2)) {
803 | LOGE("Failed to load shared library %s. Checked: %s", libName, ilso2.c_str());
804 | return JNI_VERSION_1_6;
805 | }
806 | args->libso = ilso2;
807 | }
808 | else {
809 | args->libso = ilso;
810 | }
811 | pthread_t ptid;
812 | if (pthread_create(&ptid, NULL, &hook_loop, args) != 0) {
813 | LOGE("Hooking thread failed to start.");
814 | return JNI_VERSION_1_6;
815 | }
816 | }
817 | return JNI_VERSION_1_6;
818 | }
--------------------------------------------------------------------------------