From bd55606e2178e94c89e93edc64267b52b50ab03f Mon Sep 17 00:00:00 2001
From: chiteroman <98092901+chiteroman@users.noreply.github.com>
Date: Mon, 20 Nov 2023 00:42:21 +0100
Subject: [PATCH] v13.1
---
.gitignore | 15 +
.idea/.gitignore | 3 +
.idea/compiler.xml | 6 +
.idea/gradle.xml | 20 +
.idea/inspectionProfiles/Project_Default.xml | 20 +
.idea/misc.xml | 9 +
.idea/vcs.xml | 7 +
app/.gitignore | 1 +
app/build.gradle.kts | 45 +
app/proguard-rules.pro | 3 +
app/src/main/AndroidManifest.xml | 2 +
app/src/main/cpp/Android.mk | 33 +
app/src/main/cpp/Application.mk | 5 +
app/src/main/cpp/libcxx | 1 +
app/src/main/cpp/main.cpp | 211 +
app/src/main/cpp/shadowhook/arch/arm/sh_a32.c | 446 ++
app/src/main/cpp/shadowhook/arch/arm/sh_a32.h | 41 +
.../main/cpp/shadowhook/arch/arm/sh_inst.c | 523 ++
.../main/cpp/shadowhook/arch/arm/sh_inst.h | 41 +
app/src/main/cpp/shadowhook/arch/arm/sh_t16.c | 284 +
app/src/main/cpp/shadowhook/arch/arm/sh_t16.h | 46 +
app/src/main/cpp/shadowhook/arch/arm/sh_t32.c | 408 ++
app/src/main/cpp/shadowhook/arch/arm/sh_t32.h | 36 +
app/src/main/cpp/shadowhook/arch/arm/sh_txx.c | 60 +
app/src/main/cpp/shadowhook/arch/arm/sh_txx.h | 39 +
.../main/cpp/shadowhook/arch/arm64/sh_a64.c | 310 ++
.../main/cpp/shadowhook/arch/arm64/sh_a64.h | 44 +
.../main/cpp/shadowhook/arch/arm64/sh_inst.c | 203 +
.../main/cpp/shadowhook/arch/arm64/sh_inst.h | 42 +
app/src/main/cpp/shadowhook/common/bytesig.c | 291 +
app/src/main/cpp/shadowhook/common/bytesig.h | 157 +
.../main/cpp/shadowhook/common/sh_config.h | 55 +
app/src/main/cpp/shadowhook/common/sh_errno.c | 107 +
app/src/main/cpp/shadowhook/common/sh_errno.h | 40 +
app/src/main/cpp/shadowhook/common/sh_log.c | 53 +
app/src/main/cpp/shadowhook/common/sh_log.h | 70 +
app/src/main/cpp/shadowhook/common/sh_sig.h | 49 +
.../main/cpp/shadowhook/common/sh_trampo.c | 172 +
.../main/cpp/shadowhook/common/sh_trampo.h | 52 +
app/src/main/cpp/shadowhook/common/sh_util.c | 538 ++
app/src/main/cpp/shadowhook/common/sh_util.h | 96 +
.../main/cpp/shadowhook/include/shadowhook.h | 191 +
app/src/main/cpp/shadowhook/sh_enter.c | 47 +
app/src/main/cpp/shadowhook/sh_enter.h | 30 +
app/src/main/cpp/shadowhook/sh_exit.c | 420 ++
app/src/main/cpp/shadowhook/sh_exit.h | 34 +
app/src/main/cpp/shadowhook/sh_hub.c | 538 ++
app/src/main/cpp/shadowhook/sh_hub.h | 45 +
app/src/main/cpp/shadowhook/sh_jni.c | 139 +
app/src/main/cpp/shadowhook/sh_linker.c | 409 ++
app/src/main/cpp/shadowhook/sh_linker.h | 41 +
app/src/main/cpp/shadowhook/sh_recorder.c | 517 ++
app/src/main/cpp/shadowhook/sh_recorder.h | 37 +
app/src/main/cpp/shadowhook/sh_safe.c | 133 +
app/src/main/cpp/shadowhook/sh_safe.h | 37 +
app/src/main/cpp/shadowhook/sh_switch.c | 343 ++
app/src/main/cpp/shadowhook/sh_switch.h | 34 +
app/src/main/cpp/shadowhook/sh_task.c | 333 ++
app/src/main/cpp/shadowhook/sh_task.h | 40 +
app/src/main/cpp/shadowhook/shadowhook.c | 328 ++
.../cpp/shadowhook/third_party/bsd/queue.h | 551 ++
.../cpp/shadowhook/third_party/bsd/tree.h | 759 +++
.../cpp/shadowhook/third_party/lss/LICENSE | 28 +
.../third_party/lss/linux_syscall_support.h | 4867 +++++++++++++++++
.../cpp/shadowhook/third_party/xdl/LICENSE | 21 +
.../main/cpp/shadowhook/third_party/xdl/xdl.c | 910 +++
.../main/cpp/shadowhook/third_party/xdl/xdl.h | 92 +
.../shadowhook/third_party/xdl/xdl_iterate.c | 297 +
.../shadowhook/third_party/xdl/xdl_iterate.h | 43 +
.../shadowhook/third_party/xdl/xdl_linker.c | 234 +
.../shadowhook/third_party/xdl/xdl_linker.h | 40 +
.../cpp/shadowhook/third_party/xdl/xdl_lzma.c | 187 +
.../cpp/shadowhook/third_party/xdl/xdl_lzma.h | 40 +
.../cpp/shadowhook/third_party/xdl/xdl_util.c | 95 +
.../cpp/shadowhook/third_party/xdl/xdl_util.h | 71 +
app/src/main/cpp/zygisk.hpp | 384 ++
.../playintegrityfix/CustomKeyStoreSpi.java | 105 +
.../playintegrityfix/CustomProvider.java | 18 +
.../playintegrityfix/EntryPoint.java | 85 +
build.gradle.kts | 3 +
changelog.md | 12 +-
gradle.properties | 21 +
gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 59203 bytes
gradle/wrapper/gradle-wrapper.properties | 6 +
gradlew | 185 +
gradlew.bat | 89 +
settings.gradle.kts | 17 +
update.json | 6 +-
88 files changed, 17440 insertions(+), 6 deletions(-)
create mode 100644 .gitignore
create mode 100644 .idea/.gitignore
create mode 100644 .idea/compiler.xml
create mode 100644 .idea/gradle.xml
create mode 100644 .idea/inspectionProfiles/Project_Default.xml
create mode 100644 .idea/misc.xml
create mode 100644 .idea/vcs.xml
create mode 100644 app/.gitignore
create mode 100644 app/build.gradle.kts
create mode 100644 app/proguard-rules.pro
create mode 100644 app/src/main/AndroidManifest.xml
create mode 100644 app/src/main/cpp/Android.mk
create mode 100644 app/src/main/cpp/Application.mk
create mode 160000 app/src/main/cpp/libcxx
create mode 100644 app/src/main/cpp/main.cpp
create mode 100644 app/src/main/cpp/shadowhook/arch/arm/sh_a32.c
create mode 100644 app/src/main/cpp/shadowhook/arch/arm/sh_a32.h
create mode 100644 app/src/main/cpp/shadowhook/arch/arm/sh_inst.c
create mode 100644 app/src/main/cpp/shadowhook/arch/arm/sh_inst.h
create mode 100644 app/src/main/cpp/shadowhook/arch/arm/sh_t16.c
create mode 100644 app/src/main/cpp/shadowhook/arch/arm/sh_t16.h
create mode 100644 app/src/main/cpp/shadowhook/arch/arm/sh_t32.c
create mode 100644 app/src/main/cpp/shadowhook/arch/arm/sh_t32.h
create mode 100644 app/src/main/cpp/shadowhook/arch/arm/sh_txx.c
create mode 100644 app/src/main/cpp/shadowhook/arch/arm/sh_txx.h
create mode 100644 app/src/main/cpp/shadowhook/arch/arm64/sh_a64.c
create mode 100644 app/src/main/cpp/shadowhook/arch/arm64/sh_a64.h
create mode 100644 app/src/main/cpp/shadowhook/arch/arm64/sh_inst.c
create mode 100644 app/src/main/cpp/shadowhook/arch/arm64/sh_inst.h
create mode 100644 app/src/main/cpp/shadowhook/common/bytesig.c
create mode 100644 app/src/main/cpp/shadowhook/common/bytesig.h
create mode 100644 app/src/main/cpp/shadowhook/common/sh_config.h
create mode 100644 app/src/main/cpp/shadowhook/common/sh_errno.c
create mode 100644 app/src/main/cpp/shadowhook/common/sh_errno.h
create mode 100644 app/src/main/cpp/shadowhook/common/sh_log.c
create mode 100644 app/src/main/cpp/shadowhook/common/sh_log.h
create mode 100644 app/src/main/cpp/shadowhook/common/sh_sig.h
create mode 100644 app/src/main/cpp/shadowhook/common/sh_trampo.c
create mode 100644 app/src/main/cpp/shadowhook/common/sh_trampo.h
create mode 100644 app/src/main/cpp/shadowhook/common/sh_util.c
create mode 100644 app/src/main/cpp/shadowhook/common/sh_util.h
create mode 100644 app/src/main/cpp/shadowhook/include/shadowhook.h
create mode 100644 app/src/main/cpp/shadowhook/sh_enter.c
create mode 100644 app/src/main/cpp/shadowhook/sh_enter.h
create mode 100644 app/src/main/cpp/shadowhook/sh_exit.c
create mode 100644 app/src/main/cpp/shadowhook/sh_exit.h
create mode 100644 app/src/main/cpp/shadowhook/sh_hub.c
create mode 100644 app/src/main/cpp/shadowhook/sh_hub.h
create mode 100644 app/src/main/cpp/shadowhook/sh_jni.c
create mode 100644 app/src/main/cpp/shadowhook/sh_linker.c
create mode 100644 app/src/main/cpp/shadowhook/sh_linker.h
create mode 100644 app/src/main/cpp/shadowhook/sh_recorder.c
create mode 100644 app/src/main/cpp/shadowhook/sh_recorder.h
create mode 100644 app/src/main/cpp/shadowhook/sh_safe.c
create mode 100644 app/src/main/cpp/shadowhook/sh_safe.h
create mode 100644 app/src/main/cpp/shadowhook/sh_switch.c
create mode 100644 app/src/main/cpp/shadowhook/sh_switch.h
create mode 100644 app/src/main/cpp/shadowhook/sh_task.c
create mode 100644 app/src/main/cpp/shadowhook/sh_task.h
create mode 100644 app/src/main/cpp/shadowhook/shadowhook.c
create mode 100644 app/src/main/cpp/shadowhook/third_party/bsd/queue.h
create mode 100644 app/src/main/cpp/shadowhook/third_party/bsd/tree.h
create mode 100644 app/src/main/cpp/shadowhook/third_party/lss/LICENSE
create mode 100644 app/src/main/cpp/shadowhook/third_party/lss/linux_syscall_support.h
create mode 100644 app/src/main/cpp/shadowhook/third_party/xdl/LICENSE
create mode 100644 app/src/main/cpp/shadowhook/third_party/xdl/xdl.c
create mode 100644 app/src/main/cpp/shadowhook/third_party/xdl/xdl.h
create mode 100644 app/src/main/cpp/shadowhook/third_party/xdl/xdl_iterate.c
create mode 100644 app/src/main/cpp/shadowhook/third_party/xdl/xdl_iterate.h
create mode 100644 app/src/main/cpp/shadowhook/third_party/xdl/xdl_linker.c
create mode 100644 app/src/main/cpp/shadowhook/third_party/xdl/xdl_linker.h
create mode 100644 app/src/main/cpp/shadowhook/third_party/xdl/xdl_lzma.c
create mode 100644 app/src/main/cpp/shadowhook/third_party/xdl/xdl_lzma.h
create mode 100644 app/src/main/cpp/shadowhook/third_party/xdl/xdl_util.c
create mode 100644 app/src/main/cpp/shadowhook/third_party/xdl/xdl_util.h
create mode 100644 app/src/main/cpp/zygisk.hpp
create mode 100644 app/src/main/java/es/chiteroman/playintegrityfix/CustomKeyStoreSpi.java
create mode 100644 app/src/main/java/es/chiteroman/playintegrityfix/CustomProvider.java
create mode 100644 app/src/main/java/es/chiteroman/playintegrityfix/EntryPoint.java
create mode 100644 build.gradle.kts
create mode 100644 gradle.properties
create mode 100644 gradle/wrapper/gradle-wrapper.jar
create mode 100644 gradle/wrapper/gradle-wrapper.properties
create mode 100644 gradlew
create mode 100644 gradlew.bat
create mode 100644 settings.gradle.kts
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..aa724b7
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,15 @@
+*.iml
+.gradle
+/local.properties
+/.idea/caches
+/.idea/libraries
+/.idea/modules.xml
+/.idea/workspace.xml
+/.idea/navEditor.xml
+/.idea/assetWizardSettings.xml
+.DS_Store
+/build
+/captures
+.externalNativeBuild
+.cxx
+local.properties
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..26d3352
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
new file mode 100644
index 0000000..b589d56
--- /dev/null
+++ b/.idea/compiler.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
new file mode 100644
index 0000000..ae388c2
--- /dev/null
+++ b/.idea/gradle.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..c306bb0
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..8978d23
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..25dfc0f
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/.gitignore b/app/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/app/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
new file mode 100644
index 0000000..46510f1
--- /dev/null
+++ b/app/build.gradle.kts
@@ -0,0 +1,45 @@
+plugins {
+ id("com.android.application")
+}
+
+android {
+ namespace = "es.chiteroman.playintegrityfix"
+ compileSdk = 34
+ ndkVersion = "26.1.10909125"
+ buildToolsVersion = "34.0.0"
+
+ defaultConfig {
+ applicationId = "es.chiteroman.playintegrityfix"
+ minSdk = 26
+ targetSdk = 34
+ versionCode = 1
+ versionName = "1.0"
+
+ externalNativeBuild {
+ ndk {
+ //noinspection ChromeOsAbiSupport
+ abiFilters += setOf("armeabi-v7a", "arm64-v8a")
+ jobs = 4
+ }
+ }
+ }
+
+ buildTypes {
+ release {
+ isMinifyEnabled = true
+ isShrinkResources = true
+ proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
+ }
+ }
+
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_1_8
+ targetCompatibility = JavaVersion.VERSION_1_8
+ }
+
+ externalNativeBuild {
+ ndkBuild {
+ path = file("src/main/cpp/Android.mk")
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
new file mode 100644
index 0000000..c9e4d6a
--- /dev/null
+++ b/app/proguard-rules.pro
@@ -0,0 +1,3 @@
+-keep class es.chiteroman.playintegrityfix.EntryPoint {init();}
+-keep class es.chiteroman.playintegrityfix.CustomProvider
+-keep class es.chiteroman.playintegrityfix.CustomKeyStoreSpi
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..568741e
--- /dev/null
+++ b/app/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/cpp/Android.mk b/app/src/main/cpp/Android.mk
new file mode 100644
index 0000000..9622ccc
--- /dev/null
+++ b/app/src/main/cpp/Android.mk
@@ -0,0 +1,33 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := zygisk
+LOCAL_SRC_FILES := main.cpp
+LOCAL_C_INCLUDES := $(LOCAL_PATH)
+
+LOCAL_SRC_FILES += $(wildcard $(LOCAL_PATH)/shadowhook/*.c)
+LOCAL_SRC_FILES += $(wildcard $(LOCAL_PATH)/shadowhook/common/*.c)
+LOCAL_SRC_FILES += $(wildcard $(LOCAL_PATH)/shadowhook/third_party/xdl/*.c)
+
+ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
+ LOCAL_SRC_FILES += $(wildcard $(LOCAL_PATH)/shadowhook/arch/arm/*.c)
+ LOCAL_C_INCLUDES += $(LOCAL_PATH)/shadowhook/arch/arm
+endif
+
+ifeq ($(TARGET_ARCH_ABI),arm64-v8a)
+ LOCAL_SRC_FILES += $(wildcard $(LOCAL_PATH)/shadowhook/arch/arm64/*.c)
+ LOCAL_C_INCLUDES += $(LOCAL_PATH)/shadowhook/arch/arm64
+endif
+
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/shadowhook
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/shadowhook/common
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/shadowhook/include
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/shadowhook/third_party/bsd
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/shadowhook/third_party/lss
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/shadowhook/third_party/xdl
+
+LOCAL_STATIC_LIBRARIES := libcxx
+LOCAL_LDLIBS := -llog
+include $(BUILD_SHARED_LIBRARY)
+
+include $(LOCAL_PATH)/libcxx/Android.mk
\ No newline at end of file
diff --git a/app/src/main/cpp/Application.mk b/app/src/main/cpp/Application.mk
new file mode 100644
index 0000000..9804744
--- /dev/null
+++ b/app/src/main/cpp/Application.mk
@@ -0,0 +1,5 @@
+APP_ABI := armeabi-v7a arm64-v8a
+APP_CFLAGS := -DNDEBUG -Oz -fvisibility=hidden -fvisibility-inlines-hidden -ffunction-sections -fdata-sections
+APP_CPPFLAGS := -std=c++20 -fno-exceptions -fno-rtti
+APP_STL := none
+APP_PLATFORM := android-26
\ No newline at end of file
diff --git a/app/src/main/cpp/libcxx b/app/src/main/cpp/libcxx
new file mode 160000
index 0000000..12c8f4e
--- /dev/null
+++ b/app/src/main/cpp/libcxx
@@ -0,0 +1 @@
+Subproject commit 12c8f4e93f196a700137e983dcceeac43cf807f2
diff --git a/app/src/main/cpp/main.cpp b/app/src/main/cpp/main.cpp
new file mode 100644
index 0000000..35ffb4f
--- /dev/null
+++ b/app/src/main/cpp/main.cpp
@@ -0,0 +1,211 @@
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "zygisk.hpp"
+#include "shadowhook.h"
+
+#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, "PIF/Native", __VA_ARGS__)
+
+#define FIRST_API_LEVEL "32"
+
+#define DEX_FILE_PATH "/data/adb/modules/playintegrityfix/classes.dex"
+
+#define PROP_FILE_PATH "/data/adb/modules/playintegrityfix/pif.prop"
+
+typedef void (*T_Callback)(void *, const char *, const char *, uint32_t);
+
+static volatile T_Callback propCallback = nullptr;
+
+static void modify_callback(void *cookie, const char *name, const char *value, uint32_t serial) {
+
+ if (cookie == nullptr || name == nullptr || value == nullptr || propCallback == nullptr) return;
+
+ std::string_view prop(name);
+
+ if (prop.compare("ro.product.first_api_level") == 0) {
+ LOGD("Property '%s' with value '%s' is now spoofed to '%s'", name, value, FIRST_API_LEVEL);
+ value = FIRST_API_LEVEL;
+ }
+
+ if (!prop.starts_with("cache")) LOGD("[%s] -> %s", name, value);
+
+ return propCallback(cookie, name, value, serial);
+}
+
+static void (*o_system_property_read_callback)(const prop_info *, T_Callback, void *);
+
+static void
+my_system_property_read_callback(const prop_info *pi, T_Callback callback, void *cookie) {
+
+ if (pi == nullptr || callback == nullptr || cookie == nullptr) {
+ return o_system_property_read_callback(pi, callback, cookie);
+ }
+ propCallback = callback;
+ return o_system_property_read_callback(pi, modify_callback, cookie);
+}
+
+static void doHook() {
+ shadowhook_init(SHADOWHOOK_MODE_UNIQUE, true);
+ void *handle = shadowhook_hook_sym_name(
+ "libc.so",
+ "__system_property_read_callback",
+ reinterpret_cast(my_system_property_read_callback),
+ reinterpret_cast(&o_system_property_read_callback)
+ );
+ if (handle == nullptr) {
+ LOGD("Couldn't find '__system_property_read_callback' handle. Report to @chiteroman");
+ return;
+ }
+ LOGD("Found '__system_property_read_callback' handle at %p", handle);
+}
+
+static bool needHook() {
+ char rawApi[2];
+ if (__system_property_get("ro.product.first_api_level", rawApi) < 1) return true;
+ int api = std::stoi(rawApi);
+ return api > 32;
+}
+
+class PlayIntegrityFix : public zygisk::ModuleBase {
+public:
+ void onLoad(zygisk::Api *api, JNIEnv *env) override {
+ this->api = api;
+ this->env = env;
+ }
+
+ void preAppSpecialize(zygisk::AppSpecializeArgs *args) override {
+ auto rawProcess = env->GetStringUTFChars(args->nice_name, nullptr);
+
+ std::string_view process(rawProcess);
+
+ bool isGms = process.starts_with("com.google.android.gms");
+ isGmsUnstable = process.compare("com.google.android.gms.unstable") == 0;
+
+ env->ReleaseStringUTFChars(args->nice_name, rawProcess);
+
+ if (isGms) api->setOption(zygisk::FORCE_DENYLIST_UNMOUNT);
+
+ if (isGmsUnstable) {
+
+ auto rawDir = env->GetStringUTFChars(args->app_data_dir, nullptr);
+ std::string dir(rawDir);
+ env->ReleaseStringUTFChars(args->app_data_dir, rawDir);
+
+ LOGD("GMS data dir: %s", dir.c_str());
+
+ int fd = api->connectCompanion();
+
+ int strSize = static_cast(dir.size());
+
+ write(fd, &strSize, sizeof(strSize));
+ write(fd, dir.data(), dir.size());
+
+ dir.clear();
+ dir.shrink_to_fit();
+
+ long size;
+ read(fd, &size, sizeof(size));
+
+ moduleDex.resize(size);
+ read(fd, moduleDex.data(), size);
+
+ close(fd);
+
+ hook = needHook();
+
+ if (hook) return;
+ }
+
+ api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
+ }
+
+ void postAppSpecialize(const zygisk::AppSpecializeArgs *args) override {
+ if (!isGmsUnstable) return;
+ if (hook) doHook();
+ if (!moduleDex.empty()) injectDex();
+ }
+
+ void preServerSpecialize(zygisk::ServerSpecializeArgs *args) override {
+ api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
+ }
+
+private:
+ zygisk::Api *api = nullptr;
+ JNIEnv *env = nullptr;
+ bool isGmsUnstable = false;
+ bool hook = false;
+ std::vector moduleDex;
+
+ void injectDex() {
+ LOGD("get system classloader");
+ auto clClass = env->FindClass("java/lang/ClassLoader");
+ auto getSystemClassLoader = env->GetStaticMethodID(clClass, "getSystemClassLoader",
+ "()Ljava/lang/ClassLoader;");
+ auto systemClassLoader = env->CallStaticObjectMethod(clClass, getSystemClassLoader);
+
+ LOGD("create buffer");
+ auto buf = env->NewDirectByteBuffer(moduleDex.data(), static_cast(moduleDex.size()));
+ LOGD("create class loader");
+ auto dexClClass = env->FindClass("dalvik/system/InMemoryDexClassLoader");
+ auto dexClInit = env->GetMethodID(dexClClass, "",
+ "(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V");
+ auto dexCl = env->NewObject(dexClClass, dexClInit, buf, systemClassLoader);
+
+ LOGD("load class");
+ auto loadClass = env->GetMethodID(clClass, "loadClass",
+ "(Ljava/lang/String;)Ljava/lang/Class;");
+ auto entryClassName = env->NewStringUTF("es.chiteroman.playintegrityfix.EntryPoint");
+ auto entryClassObj = env->CallObjectMethod(dexCl, loadClass, entryClassName);
+
+ LOGD("call init");
+ auto entryClass = (jclass) entryClassObj;
+ auto entryInit = env->GetStaticMethodID(entryClass, "init", "()V");
+ env->CallStaticVoidMethod(entryClass, entryInit);
+
+ LOGD("Injected %d bytes to the process", static_cast(moduleDex.size()));
+ }
+};
+
+static void companion(int fd) {
+ int strSize;
+ read(fd, &strSize, sizeof(strSize));
+
+ std::string propFile;
+
+ propFile.resize(strSize);
+
+ read(fd, propFile.data(), strSize);
+
+ propFile = propFile + "/cache/pif.prop";
+
+ std::filesystem::copy_file(PROP_FILE_PATH, propFile,
+ std::filesystem::copy_options::overwrite_existing);
+
+ std::filesystem::permissions(propFile, std::filesystem::perms::owner_read |
+ std::filesystem::perms::group_read |
+ std::filesystem::perms::others_read);
+
+ propFile.clear();
+ propFile.shrink_to_fit();
+
+ FILE *file = fopen(DEX_FILE_PATH, "rb");
+
+ fseek(file, 0, SEEK_END);
+ long size = ftell(file);
+ fseek(file, 0, SEEK_SET);
+
+ char buffer[size];
+ fread(buffer, 1, size, file);
+ fclose(file);
+
+ write(fd, &size, sizeof(size));
+ write(fd, buffer, size);
+}
+
+REGISTER_ZYGISK_MODULE(PlayIntegrityFix)
+
+REGISTER_ZYGISK_COMPANION(companion)
\ No newline at end of file
diff --git a/app/src/main/cpp/shadowhook/arch/arm/sh_a32.c b/app/src/main/cpp/shadowhook/arch/arm/sh_a32.c
new file mode 100644
index 0000000..d71e4f8
--- /dev/null
+++ b/app/src/main/cpp/shadowhook/arch/arm/sh_a32.c
@@ -0,0 +1,446 @@
+// Copyright (c) 2021-2022 ByteDance Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+
+// Created by Kelun Cai (caikelun@bytedance.com) on 2021-04-11.
+
+#include "sh_a32.h"
+
+#include
+#include
+#include
+
+#include "sh_log.h"
+
+// https://developer.arm.com/documentation/ddi0406/latest
+// https://developer.arm.com/documentation/ddi0597/latest
+
+typedef enum {
+ IGNORED = 0,
+ B_A1,
+ BX_A1,
+ BL_IMM_A1,
+ BLX_IMM_A2,
+ ADD_REG_A1,
+ ADD_REG_PC_A1,
+ SUB_REG_A1,
+ SUB_REG_PC_A1,
+ ADR_A1,
+ ADR_A2,
+ MOV_REG_A1,
+ MOV_REG_PC_A1,
+ LDR_LIT_A1,
+ LDR_LIT_PC_A1,
+ LDRB_LIT_A1,
+ LDRD_LIT_A1,
+ LDRH_LIT_A1,
+ LDRSB_LIT_A1,
+ LDRSH_LIT_A1,
+ LDR_REG_A1,
+ LDR_REG_PC_A1,
+ LDRB_REG_A1,
+ LDRD_REG_A1,
+ LDRH_REG_A1,
+ LDRSB_REG_A1,
+ LDRSH_REG_A1
+} sh_a32_type_t;
+
+static sh_a32_type_t sh_a32_get_type(uint32_t inst) {
+ if (((inst & 0x0F000000u) == 0x0A000000) && ((inst & 0xF0000000) != 0xF0000000))
+ return B_A1;
+ else if (((inst & 0x0FFFFFFFu) == 0x012FFF1F) && ((inst & 0xF0000000) != 0xF0000000))
+ return BX_A1;
+ else if (((inst & 0x0F000000u) == 0x0B000000) && ((inst & 0xF0000000) != 0xF0000000))
+ return BL_IMM_A1;
+ else if ((inst & 0xFE000000) == 0xFA000000)
+ return BLX_IMM_A2;
+ else if (((inst & 0x0FE00010u) == 0x00800000) && ((inst & 0xF0000000) != 0xF0000000) &&
+ ((inst & 0x0010F000u) != 0x0010F000) && ((inst & 0x000F0000u) != 0x000D0000) &&
+ (((inst & 0x000F0000u) == 0x000F0000) || ((inst & 0x0000000Fu) == 0x0000000F)))
+ return ((inst & 0x0000F000u) == 0x0000F000) ? ADD_REG_PC_A1 : ADD_REG_A1;
+ else if (((inst & 0x0FE00010u) == 0x00400000) && ((inst & 0xF0000000) != 0xF0000000) &&
+ ((inst & 0x0010F000u) != 0x0010F000) && ((inst & 0x000F0000u) != 0x000D0000) &&
+ (((inst & 0x000F0000u) == 0x000F0000) || ((inst & 0x0000000Fu) == 0x0000000F)))
+ return ((inst & 0x0000F000u) == 0x0000F000) ? SUB_REG_PC_A1 : SUB_REG_A1;
+ else if (((inst & 0x0FFF0000u) == 0x028F0000) && ((inst & 0xF0000000) != 0xF0000000))
+ return ADR_A1;
+ else if (((inst & 0x0FFF0000u) == 0x024F0000) && ((inst & 0xF0000000) != 0xF0000000))
+ return ADR_A2;
+ else if (((inst & 0x0FEF001Fu) == 0x01A0000F) && ((inst & 0xF0000000) != 0xF0000000) &&
+ ((inst & 0x0010F000u) != 0x0010F000) &&
+ (!(((inst & 0x0000F000u) == 0x0000F000) && ((inst & 0x00000FF0u) != 0x00000000))))
+ return ((inst & 0x0000F000u) == 0x0000F000) ? MOV_REG_PC_A1 : MOV_REG_A1;
+ else if (((inst & 0x0F7F0000u) == 0x051F0000) && ((inst & 0xF0000000) != 0xF0000000))
+ return ((inst & 0x0000F000u) == 0x0000F000) ? LDR_LIT_PC_A1 : LDR_LIT_A1;
+ else if (((inst & 0x0F7F0000u) == 0x055F0000) && ((inst & 0xF0000000) != 0xF0000000))
+ return LDRB_LIT_A1;
+ else if (((inst & 0x0F7F00F0u) == 0x014F00D0) && ((inst & 0xF0000000) != 0xF0000000))
+ return LDRD_LIT_A1;
+ else if (((inst & 0x0F7F00F0u) == 0x015F00B0) && ((inst & 0xF0000000) != 0xF0000000))
+ return LDRH_LIT_A1;
+ else if (((inst & 0x0F7F00F0u) == 0x015F00D0) && ((inst & 0xF0000000) != 0xF0000000))
+ return LDRSB_LIT_A1;
+ else if (((inst & 0x0F7F00F0u) == 0x015F00F0) && ((inst & 0xF0000000) != 0xF0000000))
+ return LDRSH_LIT_A1;
+ else if (((inst & 0x0E5F0010u) == 0x061F0000) && ((inst & 0xF0000000) != 0xF0000000) &&
+ ((inst & 0x01200000u) != 0x00200000))
+ return ((inst & 0x0000F000u) == 0x0000F000) ? LDR_REG_PC_A1 : LDR_REG_A1;
+ else if (((inst & 0x0E5F0010u) == 0x065F0000) && ((inst & 0xF0000000) != 0xF0000000) &&
+ ((inst & 0x01200000u) != 0x00200000))
+ return LDRB_REG_A1;
+ else if (((inst & 0x0E5F0FF0u) == 0x000F00D0) && ((inst & 0xF0000000) != 0xF0000000) &&
+ ((inst & 0x01200000u) != 0x00200000))
+ return LDRD_REG_A1;
+ else if (((inst & 0x0E5F0FF0u) == 0x001F00B0) && ((inst & 0xF0000000) != 0xF0000000) &&
+ ((inst & 0x01200000u) != 0x00200000))
+ return LDRH_REG_A1;
+ else if (((inst & 0x0E5F0FF0u) == 0x001F00D0) && ((inst & 0xF0000000) != 0xF0000000) &&
+ ((inst & 0x01200000u) != 0x00200000))
+ return LDRSB_REG_A1;
+ else if (((inst & 0x0E5F0FF0u) == 0x001F00F0) && ((inst & 0xF0000000) != 0xF0000000) &&
+ ((inst & 0x01200000u) != 0x00200000))
+ return LDRSH_REG_A1;
+ else
+ return IGNORED;
+}
+
+size_t sh_a32_get_rewrite_inst_len(uint32_t inst) {
+ static uint8_t map[] = {
+ 4, // IGNORED
+ 12, // B_A1
+ 12, // BX_A1
+ 16, // BL_IMM_A1
+ 16, // BLX_IMM_A2
+ 32, // ADD_REG_A1
+ 32, // ADD_REG_PC_A1
+ 32, // SUB_REG_A1
+ 32, // SUB_REG_PC_A1
+ 12, // ADR_A1
+ 12, // ADR_A2
+ 32, // MOV_REG_A1
+ 12, // MOV_REG_PC_A1
+ 24, // LDR_LIT_A1
+ 36, // LDR_LIT_PC_A1
+ 24, // LDRB_LIT_A1
+ 24, // LDRD_LIT_A1
+ 24, // LDRH_LIT_A1
+ 24, // LDRSB_LIT_A1
+ 24, // LDRSH_LIT_A1
+ 32, // LDR_REG_A1
+ 36, // LDR_REG_PC_A1
+ 32, // LDRB_REG_A1
+ 32, // LDRD_REG_A1
+ 32, // LDRH_REG_A1
+ 32, // LDRSB_REG_A1
+ 32 // LDRSH_REG_A1
+ };
+
+ return (size_t)(map[sh_a32_get_type(inst)]);
+}
+
+static bool sh_a32_is_addr_need_fix(uintptr_t addr, sh_a32_rewrite_info_t *rinfo) {
+ return (rinfo->overwrite_start_addr <= addr && addr < rinfo->overwrite_end_addr);
+}
+
+static uintptr_t sh_a32_fix_addr(uintptr_t addr, sh_a32_rewrite_info_t *rinfo) {
+ if (rinfo->overwrite_start_addr <= addr && addr < rinfo->overwrite_end_addr) {
+ uintptr_t cursor_addr = rinfo->overwrite_start_addr;
+ size_t offset = 0;
+ for (size_t i = 0; i < rinfo->rewrite_inst_lens_cnt; i++) {
+ if (cursor_addr >= addr) break;
+ cursor_addr += 4;
+ offset += rinfo->rewrite_inst_lens[i];
+ }
+ uintptr_t fixed_addr = (uintptr_t)rinfo->rewrite_buf + offset;
+ SH_LOG_INFO("a32 rewrite: fix addr %" PRIxPTR " -> %" PRIxPTR, addr, fixed_addr);
+ return fixed_addr;
+ }
+
+ return addr;
+}
+
+static size_t sh_a32_rewrite_b(uint32_t *buf, uint32_t inst, uintptr_t pc, sh_a32_type_t type,
+ sh_a32_rewrite_info_t *rinfo) {
+ uint32_t cond;
+ if (type == B_A1 || type == BL_IMM_A1 || type == BX_A1)
+ cond = SH_UTIL_GET_BITS_32(inst, 31, 28);
+ else
+ // type == BLX_IMM_A2
+ cond = 0xE; // 1110 None (AL)
+
+ uint32_t addr;
+ if (type == B_A1 || type == BL_IMM_A1) {
+ uint32_t imm24 = SH_UTIL_GET_BITS_32(inst, 23, 0);
+ uint32_t imm32 = SH_UTIL_SIGN_EXTEND_32(imm24 << 2u, 26u);
+ addr = pc + imm32; // arm -> arm
+ } else if (type == BLX_IMM_A2) {
+ uint32_t h = SH_UTIL_GET_BIT_32(inst, 24);
+ uint32_t imm24 = SH_UTIL_GET_BITS_32(inst, 23, 0);
+ uint32_t imm32 = SH_UTIL_SIGN_EXTEND_32((imm24 << 2u) | (h << 1u), 26u);
+ addr = SH_UTIL_SET_BIT0(pc + imm32); // arm -> thumb
+ } else {
+ // type == BX_A1
+ // BX PC
+ // PC must be even, and the "arm" instruction must be at a 4-byte aligned address,
+ // so the instruction set must keep "arm" unchanged.
+ addr = pc; // arm -> arm
+ }
+ addr = sh_a32_fix_addr(addr, rinfo);
+
+ size_t idx = 0;
+ if (type == BL_IMM_A1 || type == BLX_IMM_A2) {
+ buf[idx++] = 0x028FE008u | (cond << 28u); // ADD LR, PC, #8
+ }
+ buf[idx++] = 0x059FF000u | (cond << 28u); // LDR PC, [PC, #0]
+ buf[idx++] = 0xEA000000; // B #0
+ buf[idx++] = addr;
+ return idx * 4; // 12 or 16
+}
+
+static size_t sh_a32_rewrite_add_or_sub(uint32_t *buf, uint32_t inst, uintptr_t pc) {
+ // ADD{S} , , PC{, } or ADD{S} , PC, {, }
+ // SUB{S} , , PC{, } or SUB{S} , PC, {, }
+ uint32_t cond = SH_UTIL_GET_BITS_32(inst, 31, 28);
+ uint32_t rn = SH_UTIL_GET_BITS_32(inst, 19, 16);
+ uint32_t rm = SH_UTIL_GET_BITS_32(inst, 3, 0);
+ uint32_t rd = SH_UTIL_GET_BITS_32(inst, 15, 12);
+
+ uint32_t rx; // r0 - r3
+ for (rx = 3;; --rx)
+ if (rx != rn && rx != rm && rx != rd) break;
+
+ if (rd == 0xF) // Rd == PC
+ {
+ uint32_t ry; // r0 - r4
+ for (ry = 4;; --ry)
+ if (ry != rn && ry != rm && ry != rd && ry != rx) break;
+
+ buf[0] = 0x0A000000u | (cond << 28u); // B #0
+ buf[1] = 0xEA000005; // B #20
+ buf[2] = 0xE92D8000 | (1u << rx) | (1u << ry); // PUSH {Rx, Ry, PC}
+ buf[3] = 0xE59F0008 | (rx << 12u); // LDR Rx, [PC, #8]
+ if (rn == 0xF)
+ // Rn == PC
+ buf[4] =
+ (inst & 0x0FF00FFFu) | 0xE0000000 | (ry << 12u) | (rx << 16u); // ADD/SUB Ry, Rx, Rm{, }
+ else
+ // Rm == PC
+ buf[4] = (inst & 0x0FFF0FF0u) | 0xE0000000 | (ry << 12u) | rx; // ADD/SUB Ry, Rn, Rx{, }
+ buf[5] = 0xE58D0008 | (ry << 12u); // STR Ry, [SP, #8]
+ buf[6] = 0xE8BD8000 | (1u << rx) | (1u << ry); // POP {Rx, Ry, PC}
+ buf[7] = pc;
+ return 32;
+ } else {
+ buf[0] = 0x0A000000u | (cond << 28u); // B #0
+ buf[1] = 0xEA000005; // B #20
+ buf[2] = 0xE52D0004 | (rx << 12u); // PUSH {Rx}
+ buf[3] = 0xE59F0008 | (rx << 12u); // LDR Rx, [PC, #8]
+ if (rn == 0xF)
+ // Rn == PC
+ buf[4] = (inst & 0x0FF0FFFFu) | 0xE0000000 | (rx << 16u); // ADD/SUB{S} Rd, Rx, Rm{, }
+ else
+ // Rm == PC
+ buf[4] = (inst & 0x0FFFFFF0u) | 0xE0000000 | rx; // ADD/SUB{S} Rd, Rn, Rx{, }
+ buf[5] = 0xE49D0004 | (rx << 12u); // POP {Rx}
+ buf[6] = 0xEA000000; // B #0
+ buf[7] = pc;
+ return 32;
+ }
+}
+
+static size_t sh_a32_rewrite_adr(uint32_t *buf, uint32_t inst, uintptr_t pc, sh_a32_type_t type,
+ sh_a32_rewrite_info_t *rinfo) {
+ uint32_t cond = SH_UTIL_GET_BITS_32(inst, 31, 28);
+ uint32_t rd = SH_UTIL_GET_BITS_32(inst, 15, 12); // r0 - r15
+ uint32_t imm12 = SH_UTIL_GET_BITS_32(inst, 11, 0);
+ uint32_t imm32 = sh_util_arm_expand_imm(imm12);
+ uint32_t addr = (type == ADR_A1 ? (SH_UTIL_ALIGN_4(pc) + imm32) : (SH_UTIL_ALIGN_4(pc) - imm32));
+ if (sh_a32_is_addr_need_fix(addr, rinfo)) return 0; // rewrite failed
+
+ buf[0] = 0x059F0000u | (cond << 28u) | (rd << 12u); // LDR Rd, [PC, #0]
+ buf[1] = 0xEA000000; // B #0
+ buf[2] = addr;
+ return 12;
+}
+
+static size_t sh_a32_rewrite_mov(uint32_t *buf, uint32_t inst, uintptr_t pc) {
+ // MOV{S} , PC
+ uint32_t cond = SH_UTIL_GET_BITS_32(inst, 31, 28);
+ uint32_t rd = SH_UTIL_GET_BITS_32(inst, 15, 12);
+ uint32_t rx = (rd == 0) ? 1 : 0;
+
+ if (rd == 0xF) // Rd == PC (MOV PC, PC)
+ {
+ buf[0] = 0x059FF000u | (cond << 28u); // LDR PC, [PC, #0]
+ buf[1] = 0xEA000000; // B #0
+ buf[2] = pc;
+ return 12;
+ } else {
+ buf[0] = 0x0A000000u | (cond << 28u); // B #0
+ buf[1] = 0xEA000005; // B #20
+ buf[2] = 0xE52D0004 | (rx << 12u); // PUSH {Rx}
+ buf[3] = 0xE59F0008 | (rx << 12u); // LDR Rx, [PC, #8]
+ buf[4] = (inst & 0x0FFFFFF0u) | 0xE0000000 | rx; // MOV{S} Rd, Rx{, #/RRX}
+ buf[5] = 0xE49D0004 | (rx << 12u); // POP {Rx}
+ buf[6] = 0xEA000000; // B #0
+ buf[7] = pc;
+ return 32;
+ }
+}
+
+static size_t sh_a32_rewrite_ldr_lit(uint32_t *buf, uint32_t inst, uintptr_t pc, sh_a32_type_t type,
+ sh_a32_rewrite_info_t *rinfo) {
+ uint32_t cond = SH_UTIL_GET_BITS_32(inst, 31, 28);
+ uint32_t u = SH_UTIL_GET_BIT_32(inst, 23);
+ uint32_t rt = SH_UTIL_GET_BITS_16(inst, 15, 12);
+
+ uint32_t imm32;
+ if (type == LDR_LIT_A1 || type == LDR_LIT_PC_A1 || type == LDRB_LIT_A1)
+ imm32 = SH_UTIL_GET_BITS_32(inst, 11, 0);
+ else
+ imm32 = (SH_UTIL_GET_BITS_32(inst, 11, 8) << 4u) + SH_UTIL_GET_BITS_32(inst, 3, 0);
+ uint32_t addr = (u ? (SH_UTIL_ALIGN_4(pc) + imm32) : (SH_UTIL_ALIGN_4(pc) - imm32));
+ if (sh_a32_is_addr_need_fix(addr, rinfo)) return 0; // rewrite failed
+
+ if (type == LDR_LIT_PC_A1 && rt == 0xF) {
+ // Rt == PC
+ buf[0] = 0x0A000000u | (cond << 28u); // B #0
+ buf[1] = 0xEA000006; // B #24
+ buf[2] = 0xE92D0003; // PUSH {R0, R1}
+ buf[3] = 0xE59F0000; // LDR R0, [PC, #0]
+ buf[4] = 0xEA000000; // B #0
+ buf[5] = addr; //
+ buf[6] = 0xE5900000; // LDR R0, [R0]
+ buf[7] = 0xE58D0004; // STR R0, [SP, #4]
+ buf[8] = 0xE8BD8001; // POP {R0, PC}
+ return 36;
+ } else {
+ buf[0] = 0x0A000000u | (cond << 28u); // B #0
+ buf[1] = 0xEA000003; // B #12
+ buf[2] = 0xE59F0000 | (rt << 12u); // LDR Rt, [PC, #0]
+ buf[3] = 0xEA000000; // B #0
+ buf[4] = addr; //
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wswitch"
+ switch (type) {
+ case LDR_LIT_A1:
+ buf[5] = 0xE5900000 | (rt << 16u) | (rt << 12u); // LDR Rt, [Rt]
+ break;
+ case LDRB_LIT_A1:
+ buf[5] = 0xE5D00000 | (rt << 16u) | (rt << 12u); // LDRB Rt, [Rt]
+ break;
+ case LDRD_LIT_A1:
+ buf[5] = 0xE1C000D0 | (rt << 16u) | (rt << 12u); // LDRD Rt, [Rt]
+ break;
+ case LDRH_LIT_A1:
+ buf[5] = 0xE1D000B0 | (rt << 16u) | (rt << 12u); // LDRH Rt, [Rt]
+ break;
+ case LDRSB_LIT_A1:
+ buf[5] = 0xE1D000D0 | (rt << 16u) | (rt << 12u); // LDRSB Rt, [Rt]
+ break;
+ case LDRSH_LIT_A1:
+ buf[5] = 0xE1D000F0 | (rt << 16u) | (rt << 12u); // LDRSH Rt, [Rt]
+ break;
+ }
+#pragma clang diagnostic pop
+ return 24;
+ }
+}
+
+static size_t sh_a32_rewrite_ldr_reg(uint32_t *buf, uint32_t inst, uintptr_t pc, sh_a32_type_t type) {
+ // LDR