Compare commits

...

7 Commits
1.0 ... master

@ -9,10 +9,10 @@ android {
defaultConfig {
applicationId "moe.tqlwsl.aicemu"
minSdk 24
minSdk 28
targetSdk 33
versionCode 4
versionName "1.0-Beta3"
versionCode 6
versionName "1.0-Beta4.1"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" >
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.NFC_TRANSACTION_EVENT" />
@ -8,52 +8,65 @@
<application
android:name=".GlobalVar"
android:allowBackup="true"
android:extractNativeLibs="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:extractNativeLibs="true"
android:fullBackupContent="@xml/backup_rules"
android:icon="@drawable/aic_fill"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.AICEmu"
tools:targetApi="31" >
<meta-data
android:name="xposedmodule"
android:value="true" />
<meta-data
android:name="xposedminversion"
android:value="30" />
<meta-data
android:name="xposeddescription"
android:value="Emulate Every AIC Card" />
<meta-data
android:name="xposedscope"
android:resource="@array/xposed_scope" />
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true"
android:theme="@style/Theme.AICEmu" >
android:theme="@style/Theme.AICEmu">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".ReadCard"
android:theme="@style/CardActivityTheme" />
<activity
android:name=".SettingActivity"
android:exported="false"
android:label="@string/title_activity_setting"
android:theme="@style/Theme.AICEmuActionBar" />
<meta-data
android:name="xposedscope"
android:resource="@array/xposed_scope" />
<meta-data
android:name="xposedmodule"
android:value="true" />
<meta-data
android:name="xposedminversion"
android:value="93" />
<meta-data
android:name="xposeddescription"
android:value="Emulate Every AIC Card" />
<meta-data
android:name="xposedsharedprefs"
android:value="true" />
<service
android:name=".ApduService"
android:exported="true"
android:permission="android.permission.BIND_NFC_SERVICE">
<intent-filter>
<action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE" />
</intent-filter>
<meta-data
android:name="android.nfc.cardemulation.host_apdu_service"
android:resource="@xml/apdu_service" />
</service>
<service
android:name=".EmuCard"
android:exported="true"
android:permission="android.permission.BIND_NFC_SERVICE" >
android:permission="android.permission.BIND_NFC_SERVICE">
<intent-filter>
<action android:name="android.nfc.cardemulation.action.HOST_NFCF_SERVICE" />
</intent-filter>
@ -61,6 +74,5 @@
android:name="android.nfc.cardemulation.host_nfcf_service"
android:resource="@xml/host_nfcf_service" />
</service>
</application>
</manifest>

@ -0,0 +1,16 @@
package moe.tqlwsl.aicemu
import android.nfc.cardemulation.HostApduService
import android.os.Bundle
class ApduService : HostApduService() {
override fun onDeactivated(reason: Int) {
// placeholder
}
override fun processCommandApdu(commandApdu: ByteArray, extras: Bundle): ByteArray {
// placeholder
return ByteArray(0)
}
}

@ -4,6 +4,7 @@ import android.app.AlertDialog
import android.app.PendingIntent
import android.content.*
import android.nfc.NfcAdapter
import android.nfc.cardemulation.CardEmulation
import android.nfc.cardemulation.NfcFCardEmulation
import android.os.Bundle
import android.util.Log
@ -12,16 +13,14 @@ import android.widget.*
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import androidx.cardview.widget.CardView
import androidx.core.content.edit
import androidx.core.view.WindowCompat
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.gson.Gson
import com.google.gson.JsonSyntaxException
import com.google.gson.reflect.TypeToken
import moe.tqlwsl.aicemu.databinding.ActivityMainBinding
import java.io.File
import java.io.IOException
import moe.tqlwsl.aicemu.databinding.ActivityMainBinding
internal data class Card(val name: String, val idm: String)
@ -73,16 +72,28 @@ class MainActivity : AppCompatActivity() {
if (nfcAdapter == null) {
Log.e(TAG, "NFC not supported")
AlertDialog.Builder(this)
.setTitle(R.string.error).setMessage(R.string.nfc_not_supported).setCancelable(false).show()
.setTitle(R.string.error).setMessage(R.string.nfc_not_supported).setCancelable(true).show()
return
}
if (!nfcAdapter!!.isEnabled) {
Log.e(TAG, "NFC is off")
AlertDialog.Builder(this)
.setTitle(R.string.error).setMessage(R.string.nfc_not_on).setCancelable(false).show()
.setTitle(R.string.error).setMessage(R.string.nfc_not_on).setCancelable(true).show()
return
}
// set default payment app
var cardEmulation = CardEmulation.getInstance(nfcAdapter)
val componentName = ComponentName(applicationContext, ApduService::class.java)
val isDefault =
cardEmulation.isDefaultServiceForCategory(componentName, CardEmulation.CATEGORY_PAYMENT)
if (!isDefault) {
val intent = Intent(CardEmulation.ACTION_CHANGE_DEFAULT)
intent.putExtra(CardEmulation.EXTRA_CATEGORY, CardEmulation.CATEGORY_PAYMENT)
intent.putExtra(CardEmulation.EXTRA_SERVICE_COMPONENT, componentName)
startActivity(intent)
}
// add pendingintent in order not to read tag at home
val intent = Intent(this, javaClass).apply {
addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
@ -98,7 +109,7 @@ class MainActivity : AppCompatActivity() {
)
// setting prefs
prefs = applicationContext.getSharedPreferences("AICEmu", MODE_PRIVATE)
prefs = applicationContext.getSharedPreferences("AICEmu", Context.MODE_WORLD_READABLE)
currentCardId = prefs.getInt("currentCardId", -1)
compatibleID = prefs.getBoolean("compatibleID", false)
val compatibleButton: Button = findViewById(R.id.button_compatible)
@ -176,7 +187,7 @@ class MainActivity : AppCompatActivity() {
true
}
R.id.toolbar_menu_settings -> {
Toast.makeText(applicationContext, "还没做完()\nUnder constuction...", Toast.LENGTH_LONG).show()
// Toast.makeText(applicationContext, "还没做完()\nUnder constuction...", Toast.LENGTH_LONG).show()
val settingIntent = Intent(this, SettingActivity::class.java)
startActivity(settingIntent)
true

@ -1,6 +1,9 @@
package moe.tqlwsl.aicemu
import android.annotation.SuppressLint
import android.content.Context
import android.content.SharedPreferences
import android.content.pm.PackageManager
import android.graphics.Color
import android.os.Build
@ -8,10 +11,13 @@ import android.os.Bundle
import android.util.Log
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.SwitchCompat
import org.lsposed.hiddenapibypass.HiddenApiBypass
import java.lang.reflect.Method
class SettingActivity : AppCompatActivity() {
private lateinit var prefs: SharedPreferences
private var isHCEFSupported: Boolean = false
private var isHCEFUnlocked: Boolean = false
private var pmmtoolStatus: String? = ""
@ -34,8 +40,8 @@ class SettingActivity : AppCompatActivity() {
textHCEF.setTextColor(Color.RED)
}
val textUnlocker = findViewById<TextView>(R.id.unlocker_work_text)
if (isHCEFSupported) {
val textUnlocker = findViewById<TextView>(R.id.unlocker_work_text)
try {
val globalVar = this.applicationContext as GlobalVar
isHCEFUnlocked = globalVar.isHCEFUnlocked
@ -52,21 +58,31 @@ class SettingActivity : AppCompatActivity() {
textUnlocker.setText(R.string.Unlocker_work_error)
}
val textPmmtool = findViewById<TextView>(R.id.pmmtool_work_text)
pmmtoolStatus = getProperty("tmp.AICEmu.pmmtool");
if (pmmtoolStatus == "") {
textPmmtool.setText(R.string.Pmmtool_work_false)
textPmmtool.setTextColor(Color.RED)
}
else if (pmmtoolStatus == "0") {
textPmmtool.setText(R.string.Pmmtool_work_hook_failed)
textPmmtool.setTextColor(Color.RED)
}
else if (pmmtoolStatus == "1") {
textPmmtool.setText(R.string.Pmmtool_work_true)
textPmmtool.setTextColor(Color.GREEN)
}
// val textPmmtool = findViewById<TextView>(R.id.pmmtool_work_text)
// pmmtoolStatus = getProperty("tmp.AICEmu.pmmtool");
// if (pmmtoolStatus == "") {
// textPmmtool.setText(R.string.Pmmtool_work_false)
// textPmmtool.setTextColor(Color.RED)
// }
// else if (pmmtoolStatus == "0") {
// textPmmtool.setText(R.string.Pmmtool_work_hook_failed)
// textPmmtool.setTextColor(Color.RED)
// }
// else if (pmmtoolStatus == "1") {
// textPmmtool.setText(R.string.Pmmtool_work_true)
// textPmmtool.setTextColor(Color.GREEN)
// }
prefs = applicationContext.getSharedPreferences("AICEmu", Context.MODE_WORLD_READABLE)
val loadPmmtool = prefs.getBoolean("loadPmmtool", false)
val pmmtoolSwitch = findViewById<SwitchCompat>(R.id.pmmtool_switch)
pmmtoolSwitch.isChecked = loadPmmtool
pmmtoolSwitch.setOnCheckedChangeListener { _, isChecked ->
val editor = prefs.edit()
editor.putBoolean("loadPmmtool", isChecked)
editor.apply()
Runtime.getRuntime().exec(arrayOf("su", "-c", "kill -9 $(su -c pidof com.android.nfc)"))
}
}
}

@ -1,9 +1,14 @@
package moe.tqlwsl.aicemu;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.Application;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
import java.util.List;
@ -11,6 +16,7 @@ import java.util.List;
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XC_MethodReplacement;
import de.robv.android.xposed.XSharedPreferences;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;
@ -24,7 +30,6 @@ public class xp implements IXposedHookLoadPackage {
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,
@ -36,45 +41,47 @@ 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("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");
// mclassloader = mcontext.getClassLoader();
// 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();
// }
mclassloader = mcontext.getClassLoader();
XposedBridge.log("Got classloader");
String path = getSoPath();
XposedBridge.log("So path = " + path);
try {
Boolean needLoadPmmtool = false;
XSharedPreferences pref = getPref();
if (pref != null) {
needLoadPmmtool = pref.getBoolean("loadPmmtool", false);
} else {
XposedBridge.log("Cannot load pref for AICEmu properly");
}
XposedBridge.log("loadPmmtool: " + needLoadPmmtool.toString());
if (needLoadPmmtool && !path.equals("")) {
XposedBridge.log("Start injecting libpmm.so");
XposedHelpers.callMethod(Runtime.getRuntime(), "nativeLoad", path, mclassloader);
XposedBridge.log("Injected libpmm.so");
}
} catch (Exception e) {
XposedBridge.log(e);
e.printStackTrace();
}
// Unlocker
param.setResult(true);
@ -84,7 +91,10 @@ public class xp implements IXposedHookLoadPackage {
XposedBridge.log("Hook succeeded!!!");
}
}
private static XSharedPreferences getPref() {
XSharedPreferences pref = new XSharedPreferences("moe.tqlwsl.aicemu", "AICEmu");
return pref.getFile().canRead() ? pref : null;
}
private String getSoPath() {
try {
String text = "";

@ -38,7 +38,7 @@ void *new_func(u_int8_t a1, u_int8_t *a2, int a3) {
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);
__system_property_set("tmp.AICEmu.pmmtool", "1");
//__system_property_set("tmp.AICEmu.pmmtool", "1");
}
}
@ -60,7 +60,7 @@ void *new_func(u_int8_t a1, u_int8_t *a2, int a3) {
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);
__system_property_set("tmp.AICEmu.pmmtool", "1");
//__system_property_set("tmp.AICEmu.pmmtool", "1");
}
}
//}
@ -72,7 +72,7 @@ void *new_func(u_int8_t a1, u_int8_t *a2, int a3) {
jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
__android_log_print(6, "AICEmu-pmmtool", "Inside JNI_OnLoad");
__system_property_set("tmp.AICEmu.pmmtool", "0");
//__system_property_set("tmp.AICEmu.pmmtool", "0");
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");

@ -37,7 +37,41 @@
android:text="@string/Pmmtool_work_false"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/unlocker_work_text" />
app:layout_constraintTop_toBottomOf="@+id/unlocker_work_text"
android:visibility="gone"/>
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/pmmtool_switch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="100dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/pmmtool_work_text"
android:text="@string/pmmtool_switch"/>
<TextView
android:id="@+id/version_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:textSize="20sp"
android:text="@string/version_info"
android:textAlignment="center"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toTopOf="@+id/author_text"/>
<TextView
android:id="@+id/author_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="32dp"
android:textSize="16sp"
android:text="@string/author_info"
android:textAlignment="center"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>

@ -25,4 +25,6 @@
<string name="mode_compatible">兼容模式</string>
<string name="mode_commmon">正常模式</string>
<string name="add_test_card">添加测试卡</string>
<string name="apdu_service_desc">模拟AIC卡</string>
<string name="pmmtool_switch">用 Pmmtool 修改 PMm</string>
</resources>

@ -31,4 +31,8 @@
<string name="mode_commmon">Common</string>
<string name="mode_compatible">Compatible</string>
<string name="add_test_card">Add test card</string>
<string name="apdu_service_desc">Emulate AIC Card</string>
<string name="pmmtool_switch">Change PMm with Pmmtool</string>
<string name="author_info" translatable="false">made by wlt233 with ❤\ntqlwsl.moe | 2709684396</string>
<string name="version_info" translatable="false">1.0-Beta4.1 (2023.09.01)</string>
</resources>

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
android:apduServiceBanner="@drawable/aic_fill"
android:description="@string/apdu_service_desc"
android:requireDeviceUnlock="false" >
<aid-group
android:category="payment"
android:description="@string/apdu_service_desc" >
<aid-filter android:name="F0010203040506" />
</aid-group>
</host-apdu-service>
Loading…
Cancel
Save