-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add Xposed hook for android nfc service
update AGP version
- Loading branch information
Showing
9 changed files
with
249 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
cc.ioctl.nfcdevicehost.xposed.HookEntry |
30 changes: 30 additions & 0 deletions
30
app/src/main/java/cc/ioctl/nfcdevicehost/xposed/HookEntry.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package cc.ioctl.nfcdevicehost.xposed; | ||
|
||
import de.robv.android.xposed.IXposedHookLoadPackage; | ||
import de.robv.android.xposed.XC_MethodHook; | ||
import de.robv.android.xposed.XposedHelpers; | ||
import de.robv.android.xposed.callbacks.XC_LoadPackage; | ||
|
||
public class HookEntry implements IXposedHookLoadPackage { | ||
|
||
private static void initNfcServiceHook(ClassLoader classLoader) { | ||
XposedHelpers.findAndHookMethod("com.android.nfc.NfcService", classLoader, "playSound", int.class, new XC_MethodHook() { | ||
@Override | ||
protected void beforeHookedMethod(MethodHookParam param) { | ||
if (SysNfcSvcPatch.sDisableNfcDiscoverySound) { | ||
param.setResult(null); | ||
} | ||
} | ||
}); | ||
SysNfcSvcPatch.startMainThread(); | ||
} | ||
|
||
@Override | ||
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) { | ||
if ("com.android.nfc".equals(lpparam.packageName)) { | ||
if (lpparam.isFirstApplication) { | ||
initNfcServiceHook(lpparam.classLoader); | ||
} | ||
} | ||
} | ||
} |
194 changes: 194 additions & 0 deletions
194
app/src/main/java/cc/ioctl/nfcdevicehost/xposed/SysNfcSvcPatch.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,194 @@ | ||
package cc.ioctl.nfcdevicehost.xposed; | ||
|
||
import android.net.Credentials; | ||
import android.net.LocalServerSocket; | ||
import android.net.LocalSocket; | ||
|
||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.io.OutputStream; | ||
|
||
import de.robv.android.xposed.XposedBridge; | ||
|
||
public class SysNfcSvcPatch { | ||
|
||
private static Thread sWorkingThread = null; | ||
public static boolean sDisableNfcDiscoverySound = false; | ||
private static boolean sShouldRunning = true; | ||
|
||
static void run() { | ||
try { | ||
int myPid = android.os.Process.myPid(); | ||
while (sShouldRunning) { | ||
LocalServerSocket localServerSocket; | ||
try { | ||
localServerSocket = new LocalServerSocket("com.android.nfc/cc.ioctl.nfcdevicehost.xposed.SysNfcSvcPatch@" + myPid); | ||
while (sShouldRunning) { | ||
LocalSocket localSocket = localServerSocket.accept(); | ||
Credentials cred = null; | ||
try { | ||
cred = localSocket.getPeerCredentials(); | ||
} catch (IOException ignored) { | ||
} | ||
if (cred != null && cred.getUid() == 0) { | ||
localServerSocket.close(); | ||
handleTransaction(localSocket); | ||
// socket is closed in handleTransaction | ||
break; | ||
} else { | ||
try { | ||
localSocket.close(); | ||
} catch (IOException ignored) { | ||
} | ||
} | ||
} | ||
} catch (IOException e) { | ||
XposedBridge.log("SysNfcSvcPatch: " + e.getMessage()); | ||
XposedBridge.log(e); | ||
return; | ||
} | ||
} | ||
} catch (RuntimeException e) { | ||
XposedBridge.log(e); | ||
} | ||
} | ||
|
||
static final int TYPE_REQUEST = 1; | ||
static final int TYPE_RESPONSE = 2; | ||
static final int TYPE_EVENT = 3; | ||
static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; | ||
|
||
static final int REQUEST_SET_NFC_SOUND_DISABLE = 0x30; | ||
static final int REQUEST_GET_NFC_SOUND_DISABLE = 0x31; | ||
|
||
static void handleTransaction(LocalSocket socket) { | ||
try { | ||
byte[] buffer = new byte[65536]; | ||
InputStream is = socket.getInputStream(); | ||
while (sShouldRunning) { | ||
// read 4 bytes length | ||
readFully(is, buffer, 0, 4); | ||
int length = getInt32Le(buffer, 0); | ||
if (length < 16 || length > 65535) { | ||
break; | ||
} | ||
// read length bytes | ||
readFully(is, buffer, 0, length); | ||
// uint32_t type | ||
int type = getInt32Le(buffer, 0); | ||
// uint32_t sequence | ||
int sequence = getInt32Le(buffer, 4); | ||
// uint32_t requestCode | ||
int requestCode = getInt32Le(buffer, 8); | ||
// uint32_t arg0 | ||
int arg0 = getInt32Le(buffer, 12); | ||
byte[] data; | ||
if (length > 16) { | ||
data = new byte[length - 16]; | ||
System.arraycopy(buffer, 16, data, 0, length - 16); | ||
} else { | ||
data = EMPTY_BYTE_ARRAY; | ||
} | ||
switch (type) { | ||
case TYPE_REQUEST: | ||
handleRequest(socket, sequence, requestCode, arg0, data); | ||
break; | ||
case TYPE_RESPONSE: | ||
case TYPE_EVENT: | ||
default: | ||
break; | ||
} | ||
} | ||
} catch (IOException e) { | ||
XposedBridge.log("SysNfcSvcPatch: " + e.getMessage()); | ||
} | ||
try { | ||
socket.close(); | ||
} catch (IOException ignored) { | ||
} | ||
} | ||
|
||
private static void handleRequest(LocalSocket socket, int sequence, int requestCode, int arg0, byte[] data) { | ||
switch (requestCode) { | ||
case REQUEST_SET_NFC_SOUND_DISABLE: { | ||
sDisableNfcDiscoverySound = (arg0 != 0); | ||
sendResponse(socket, sequence, 0, 0, null); | ||
break; | ||
} | ||
case REQUEST_GET_NFC_SOUND_DISABLE: { | ||
sendResponse(socket, sequence, sDisableNfcDiscoverySound ? 1 : 0, 0, null); | ||
break; | ||
} | ||
default: { | ||
sendResponse(socket, sequence, -1, -1, null); | ||
} | ||
} | ||
} | ||
|
||
static void sendResponse(LocalSocket socket, int sequence, int resultCode, int errCode, byte[] data) { | ||
if (data == null) { | ||
data = EMPTY_BYTE_ARRAY; | ||
} | ||
byte[] bufferLen4 = new byte[4]; | ||
putInt32Le(bufferLen4, 0, data.length + 16); | ||
byte[] buffer = new byte[16 + data.length]; | ||
putInt32Le(buffer, 0, TYPE_RESPONSE); | ||
putInt32Le(buffer, 4, sequence); | ||
putInt32Le(buffer, 8, resultCode); | ||
putInt32Le(buffer, 12, errCode); | ||
System.arraycopy(data, 0, buffer, 16, data.length); | ||
try { | ||
OutputStream os = socket.getOutputStream(); | ||
os.write(bufferLen4); | ||
os.write(buffer); | ||
os.flush(); | ||
} catch (IOException e) { | ||
XposedBridge.log("SysNfcSvcPatch: " + e.getMessage()); | ||
} | ||
} | ||
|
||
public static synchronized void startMainThread() { | ||
if (sWorkingThread == null || !sWorkingThread.isAlive()) { | ||
sWorkingThread = new Thread(SysNfcSvcPatch::run); | ||
sWorkingThread.start(); | ||
} | ||
} | ||
|
||
static void readFully(InputStream is, byte[] buffer, int offset, int length) throws IOException { | ||
int remaining = length; | ||
while (remaining > 0) { | ||
int read = is.read(buffer, offset, remaining); | ||
if (read < 0) { | ||
throw new IOException("Unexpected EOF"); | ||
} | ||
remaining -= read; | ||
offset += read; | ||
} | ||
} | ||
|
||
/** | ||
* Read a little-endian 32-bit integer from the given byte array. | ||
* | ||
* @param buffer The byte array to read from. | ||
* @param offset The offset to start reading from. | ||
* @return The 32-bit integer read. | ||
*/ | ||
static int getInt32Le(byte[] buffer, int offset) { | ||
return (buffer[offset] & 0xFF) | ((buffer[offset + 1] & 0xFF) << 8) | ||
| ((buffer[offset + 2] & 0xFF) << 16) | ((buffer[offset + 3] & 0xFF) << 24); | ||
} | ||
|
||
/** | ||
* Put a little-endian 32-bit integer to the given byte array. | ||
* | ||
* @param buffer The byte array to write to. | ||
* @param offset The offset to start writing to. | ||
* @param value the value to put | ||
*/ | ||
static void putInt32Le(byte[] buffer, int offset, int value) { | ||
buffer[offset] = (byte) (value & 0xFF); | ||
buffer[offset + 1] = (byte) ((value >> 8) & 0xFF); | ||
buffer[offset + 2] = (byte) ((value >> 16) & 0xFF); | ||
buffer[offset + 3] = (byte) ((value >> 24) & 0xFF); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters