add pmmtool to project

master
wlt233 1 year ago
parent 60224d6613
commit 2186a78aba

@ -0,0 +1,32 @@
cmake_minimum_required(VERSION 3.10.2)
include_directories(
src/main/jni/dobby
)
enable_language(C ASM)
add_library(
pmm
SHARED
src/main/jni/main.cpp
)
include_directories(dobby)
add_library(local_dobby STATIC IMPORTED)
set_target_properties(local_dobby PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/libs/${ANDROID_ABI}/libdobby.a)
find_library(
log-lib
log
)
find_library(android-lib android)
target_link_libraries(
pmm
local_dobby
${log-lib}
${android-lib}
)

@ -27,6 +27,15 @@ android {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
externalNativeBuild {
defaultConfig.externalNativeBuild.cmake {
abiFilters 'arm64-v8a'
}
cmake {
path file('CMakeLists.txt')
version '3.22.1'
}
}
kotlinOptions {
jvmTarget = '1.8'
}

Binary file not shown.

Binary file not shown.

@ -8,6 +8,7 @@
<application
android:name=".GlobalVar"
android:allowBackup="true"
android:extractNativeLibs="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@drawable/aic_fill"
@ -24,7 +25,7 @@
android:value="30" />
<meta-data
android:name="xposeddescription"
android:value="Emulate every AIC Card" />
android:value="Emulate Every AIC Card" />
<meta-data
android:name="xposedscope"
android:resource="@array/xposed_scope" />

@ -1,7 +1,13 @@
package moe.tqlwsl.aicemu;
import android.app.Application;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.util.Log;
import java.util.List;
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XC_MethodReplacement;
@ -10,41 +16,45 @@ import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;
public class xp implements IXposedHookLoadPackage {
private final String TAG = "AICEmu";
private final String TAG = "AICEmu-Xposed";
ClassLoader mclassloader = null;
Context mcontext = null;
// from https://github.com/OLIET2357/HCEFUnlocker
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
XposedBridge.log("In " + lpparam.packageName);
if (lpparam.packageName.equals("com.android.nfc")) {
XposedHelpers.findAndHookMethod("android.nfc.cardemulation.NfcFCardEmulation", lpparam.classLoader,
"isValidSystemCode", String.class, new XC_MethodReplacement() {
@Override
protected Object replaceHookedMethod(XC_MethodHook.MethodHookParam param) throws Throwable {
String systemCode = (String) param.args[0];
if (systemCode == null) {
return false;
}
if (lpparam.packageName.equals("com.android.nfc")) {
if (systemCode.length() != 4) {
Log.e(TAG, "System Code " + systemCode + " is not a valid System Code.");
return false;
}
// check if the value is between "4000" and "4FFF" (excluding "4*FF")
if (!systemCode.startsWith("4") || systemCode.toUpperCase().endsWith("FF")) {
// Log.e(TAG, "System Code " + systemCode + " is not a valid System Code.");
// return false;
}
try {
Integer.parseInt(systemCode, 16);
} catch (NumberFormatException e) {
Log.e(TAG, "System Code " + systemCode + " is not a valid System Code.");
return false;
}
return true;
}
});
// XposedHelpers.findAndHookMethod("android.nfc.cardemulation.NfcFCardEmulation", lpparam.classLoader,
// "isValidSystemCode", String.class, new XC_MethodReplacement() {
// @Override
// protected Object replaceHookedMethod(XC_MethodHook.MethodHookParam param) throws Throwable {
// String systemCode = (String) param.args[0];
// if (systemCode == null) {
// return false;
// }
//
// if (systemCode.length() != 4) {
// Log.e(TAG, "System Code " + systemCode + " is not a valid System Code.");
// return false;
// }
// // check if the value is between "4000" and "4FFF" (excluding "4*FF")
// if (!systemCode.startsWith("4") || systemCode.toUpperCase().endsWith("FF")) {
// // Log.e(TAG, "System Code " + systemCode + " is not a valid System Code.");
// // return false;
// }
// try {
// Integer.parseInt(systemCode, 16);
// } catch (NumberFormatException e) {
// Log.e(TAG, "System Code " + systemCode + " is not a valid System Code.");
// return false;
// }
// return true;
// }
// });
XposedHelpers.findAndHookMethod("android.nfc.cardemulation.NfcFCardEmulation", lpparam.classLoader,
"isValidNfcid2", String.class, new XC_MethodReplacement() {
@ -73,7 +83,70 @@ public class xp implements IXposedHookLoadPackage {
}
});
XposedHelpers.findAndHookMethod("com.android.nfc.NfcApplication",
lpparam.classLoader, "onCreate", new XC_MethodHook() {
@Override
protected void beforeHookedMethod(XC_MethodHook.MethodHookParam param) throws Throwable {
XposedBridge.log("Inside com.android.nfc.NfcApplication#onCreate");
super.beforeHookedMethod(param);
Application application = (Application) param.thisObject;
mcontext = application.getApplicationContext();
XposedBridge.log("Got context");
}
});
XposedHelpers.findAndHookMethod("android.nfc.cardemulation.NfcFCardEmulation",
lpparam.classLoader, "isValidSystemCode", String.class, new XC_MethodHook() {
@Override
protected void afterHookedMethod(XC_MethodHook.MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
XposedBridge.log("Inside android.nfc.cardemulation.NfcFCardEmulation#isValidSystemCode");
XposedBridge.log("Got classloader");
String path = getSoPath();
XposedBridge.log("So path = " + path);
int version = android.os.Build.VERSION.SDK_INT;
try {
if (!path.equals("")) {
XposedBridge.log("Start injecting libpmm.so");
if (version >= 28) {
XposedHelpers.callMethod(Runtime.getRuntime(), "nativeLoad", path, mclassloader);
} else {
XposedHelpers.callMethod(Runtime.getRuntime(), "doLoad", path, mclassloader);
}
XposedBridge.log("Injected libpmm.so");
}
} catch (Exception e) {
XposedBridge.log(e);
e.printStackTrace();
}
// Unlocker
param.setResult(true);
}
});
XposedBridge.log("Hook succeeded!!!");
}
}
private String getSoPath() {
try {
String text = "";
PackageManager pm = mcontext.getPackageManager();
List<PackageInfo> pkgList = pm.getInstalledPackages(0);
if (pkgList.size() > 0) {
for (PackageInfo pi: pkgList) {
if (pi.applicationInfo.publicSourceDir.contains("moe.tqlwsl.aicemu")) {
text = pi.applicationInfo.publicSourceDir.replace("base.apk", "lib/arm64/libpmm.so");
return text;
}
}
}
} catch (Exception e) {
XposedBridge.log(e);
e.printStackTrace();
}
return "";
}
}

@ -0,0 +1,152 @@
#ifndef dobby_h
#define dobby_h
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include <stdint.h>
typedef uintptr_t addr_t;
typedef uint32_t addr32_t;
typedef uint64_t addr64_t;
typedef void *dobby_dummy_func_t;
typedef void *asm_func_t;
#if defined(__arm__)
typedef struct {
uint32_t dummy_0;
uint32_t dummy_1;
uint32_t dummy_2;
uint32_t sp;
union {
uint32_t r[13];
struct {
uint32_t r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12;
} regs;
} general;
uint32_t lr;
} DobbyRegisterContext;
#elif defined(__arm64__) || defined(__aarch64__)
#define ARM64_TMP_REG_NDX_0 17
typedef union _FPReg {
__int128_t q;
struct {
double d1;
double d2;
} d;
struct {
float f1;
float f2;
float f3;
float f4;
} f;
} FPReg;
// register context
typedef struct {
uint64_t dmmpy_0; // dummy placeholder
uint64_t sp;
uint64_t dmmpy_1; // dummy placeholder
union {
uint64_t x[29];
struct {
uint64_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22,
x23, x24, x25, x26, x27, x28;
} regs;
} general;
uint64_t fp;
uint64_t lr;
union {
FPReg q[32];
struct {
FPReg q0, q1, q2, q3, q4, q5, q6, q7;
// [!!! READ ME !!!]
// for Arm64, can't access q8 - q31, unless you enable full floating-point register pack
FPReg q8, q9, q10, q11, q12, q13, q14, q15, q16, q17, q18, q19, q20, q21, q22, q23, q24, q25, q26, q27, q28, q29,
q30, q31;
} regs;
} floating;
} DobbyRegisterContext;
#elif defined(_M_IX86) || defined(__i386__)
typedef struct _RegisterContext {
uint32_t dummy_0;
uint32_t esp;
uint32_t dummy_1;
uint32_t flags;
union {
struct {
uint32_t eax, ebx, ecx, edx, ebp, esp, edi, esi;
} regs;
} general;
} DobbyRegisterContext;
#elif defined(_M_X64) || defined(__x86_64__)
typedef struct {
uint64_t dummy_0;
uint64_t rsp;
union {
struct {
uint64_t rax, rbx, rcx, rdx, rbp, rsp, rdi, rsi, r8, r9, r10, r11, r12, r13, r14, r15;
} regs;
} general;
uint64_t dummy_1;
uint64_t flags;
} DobbyRegisterContext;
#endif
#define install_hook_name(name, fn_ret_t, fn_args_t...) \
static fn_ret_t fake_##name(fn_args_t); \
static fn_ret_t (*orig_##name)(fn_args_t); \
/* __attribute__((constructor)) */ static void install_hook_##name(void *sym_addr) { \
DobbyHook(sym_addr, (dobby_dummy_func_t)fake_##name, (dobby_dummy_func_t *)&orig_##name); \
return; \
} \
fn_ret_t fake_##name(fn_args_t)
// memory code patch
int DobbyCodePatch(void *address, uint8_t *buffer, uint32_t buffer_size);
// function inline hook
int DobbyHook(void *address, dobby_dummy_func_t replace_func, dobby_dummy_func_t *origin_func);
// dynamic binary instruction instrument
// for Arm64, can't access q8 - q31, unless enable full floating-point register pack
typedef void (*dobby_instrument_callback_t)(void *address, DobbyRegisterContext *ctx);
int DobbyInstrument(void *address, dobby_instrument_callback_t pre_handler);
// destroy and restore code patch
int DobbyDestroy(void *address);
const char *DobbyGetVersion();
// symbol resolver
void *DobbySymbolResolver(const char *image_name, const char *symbol_name);
// import table replace
int DobbyImportTableReplace(char *image_name, char *symbol_name, dobby_dummy_func_t fake_func,
dobby_dummy_func_t *orig_func);
// for arm, Arm64, try use b xxx instead of ldr absolute indirect branch
// for x86, x64, always use absolute indirect jump
void dobby_enable_near_branch_trampoline();
void dobby_disable_near_branch_trampoline();
#ifdef __cplusplus
}
#endif
#endif

@ -0,0 +1,83 @@
#include "main.h"
#include <dobby.h>
char buff[30];
char pmm_str[30];
char target_pmm[8] = {0x00, 0xf1, 0x00, 0x00, 0x00, 0x01, 0x43, 0x00};
void *new_func(u_int8_t a1, u_int8_t *a2, int a3) {
__android_log_print(6, "AICEmu-pmmtool", "hook _Z23nfa_dm_check_set_confighPhb arg0->%x arg1->%x", a1, a2);
// if (a1 == 0x1d) { // hardcoded arg pattern
// 40 0a [syscode] [IDm] 53 02 01 00 55 01 01 51 08 [PMm]
// if (a1 == 0x1b) { // another type hardcoded arg pattern
// 40 12 [syscode] [IDm] [PMm] 53 02 01 00 55 01 01
// handmade hexdump
for (int i = 0x0; i < 0x10; ++i)
sprintf(buff + i * 3, "%02x ", *(char *)(a2 + i));
__android_log_print(6, "AICEmu-pmmtool", "[%x]: %s", a2, buff);
for (int i = 0x0; i < 0x10; ++i)
sprintf(buff + i * 3, "%02x ", *(char *)(a2 + 0x10 + i));
__android_log_print(6, "AICEmu-pmmtool", "[%x]: %s", a2 + 0x10, buff);
// look for 51 08 (set pmm command) for type 0x1d
for (int i = 0x0; i < 0x20; ++i) {
if (*(char *)(a2 + i) == 0x51 && *(char *)(a2 + i + 1) == 0x08) {
for (int j = 0; j < 8; ++j)
sprintf(pmm_str + j * 3, "%02x ", *(char *)(a2 + i + 2 + j));
__android_log_print(6, "AICEmu-pmmtool", "[1] old PMm: %s", pmm_str);
// set
for (int j = 0; j < 8; ++j)
*(char *)(a2 + i + 2 + j) = target_pmm[j];
for (int j = 0; j < 8; ++j)
sprintf(pmm_str + j * 3, "%02x ", *(char *)(a2 + i + 2 + j));
__android_log_print(6, "AICEmu-pmmtool", "[1] new PMm: %s", pmm_str);
}
}
// look for FF FF FF FF FF FF FF FF (pmm itself)
for (int i = 0x0; i < 0x20; ++i) {
if (*(char *)(a2 + i) == 0xff && *(char *)(a2 + i + 1) == 0xff
&& *(char *)(a2 + i + 2) == 0xff && *(char *)(a2 + i + 3) == 0xff
&& *(char *)(a2 + i + 4) == 0xff && *(char *)(a2 + i + 5) == 0xff
&& *(char *)(a2 + i + 6) == 0xff && *(char *)(a2 + i + 7) == 0xff) {
for (int j = 0; j < 8; ++j)
sprintf(pmm_str + j * 3, "%02x ", *(char *)(a2 + i + j));
__android_log_print(6, "AICEmu-pmmtool", "[2] old PMm: %s", pmm_str);
// set
for (int j = 0; j < 8; ++j)
*(char *)(a2 + i + j) = target_pmm[j];
for (int j = 0; j < 8; ++j)
sprintf(pmm_str + j * 3, "%02x ", *(char *)(a2 + i + j));
__android_log_print(6, "AICEmu-pmmtool", "[2] new PMm: %s", pmm_str);
}
}
//}
//__android_log_print(6, "pmmtool", "load old func");
void *result = old_func(a1, a2, a3);
//__android_log_print(6, "pmmtool", "hook result -> %x", result);
return result;
}
jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
__android_log_print(6, "AICEmu-pmmtool", "Inside JNI_OnLoad");
JNIEnv *env = nullptr;
if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) == JNI_OK) {
//void *func_addr = DobbySymbolResolver("libnfc-nci.so", "_Z23nfa_dm_check_set_confighPhb");
void *func_addr = DobbySymbolResolver(NULL, "_Z23nfa_dm_check_set_confighPhb");
__android_log_print(6, "AICEmu-pmmtool", "_Z23nfa_dm_check_set_confighPhb addr->%x", func_addr);
DobbyHook(func_addr, (void *) new_func, (void **) &old_func);
__android_log_print(6, "AICEmu-pmmtool", "Dobby hooked");
return JNI_VERSION_1_6;
}
return 0;
}

@ -0,0 +1,18 @@
#ifndef MAIN_H
#define MAIN_H
#include <jni.h>
#include <android/log.h>
#include <string.h>
#include <malloc.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <dlfcn.h>
#include <link.h>
#include <inttypes.h>
#include <unistd.h>
void *(*old_func)(u_int8_t, u_int8_t *, int) = nullptr;
#endif //MAIN_H
Loading…
Cancel
Save