现在我正在测试 Android 电话加密中的一些东西。我通过使用 Xposed 框架在 RIL.java 中挂钩了一些方法
if ( lpparam.packageName.contains("com.android.phone")){
XposedBridge.log("damowang Loaded app: " + lpparam.packageName);
findAndHookMethod("com.android.internal.telephony.RIL", lpparam.classLoader, "readRilMessage",InputStream.class,byte[].class,new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
int messageLenth = Integer.parseInt(param.getResult().toString());
XposedBridge.log("damowang : RILSender readRilMessage result==="+messageLenth);
byte[] arr = (byte[])param.args[1];
String byteStr = "";
for(int i=0;i<messageLenth;i++){
byteStr += arr[i];
byteStr += " ";
}
XposedBridge.log("damowang : RILSender readRilMessage byte[]==="+byteStr);
}
});
findAndHookMethod("com.android.internal.telephony.RIL", lpparam.classLoader, "invokeOemRilRequestRaw",byte[].class,Message.class,new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
XposedBridge.log("damowang : RIL invokeOemRilRequestRaw result===");
byte[] arr = (byte[])param.args[0];
String byteStr = "";
for(int i=0;i<arr.length;i++){
byteStr += arr[i];
byteStr += " ";
}
XposedBridge.log("damowang : RIL invokeOemRilRequestRaw byte[]==="+arr.length+"==="+"==="+byteStr);
}
});
}
然后我得到了一些日志,例如:
damowang : RIL invokeOemRilRequestRaw byte[]===5======11 24 0 5 1
damowang : RIL invokeOemRilRequestRaw byte[]===5======11 24 0 5 0
damowang : RILSender readRilMessage result===12
damowang : RILSender readRilMessage byte[]===0 0 0 0 -95 0 0 0 17 0 0 0
damowang : RILSender readRilMessage result===12
damowang : RILSender readRilMessage byte[]===0 0 0 0 -94 0 0 0 17 0 0 0
damowang : RILSender readRilMessage result===8
damowang : RILSender readRilMessage byte[]===1 0 0 0 -22 3 0 0
damowang : RILSender readRilMessage result===60
damowang : RILSender readRilMessage byte[]===1 0 0 0 -15 3 0 0 16 0 0 0 99 4 0 0 16 0 0 0 -56 0 0 0 16 0 0 0 -56 0 0 0 -1 -1 -1 -1 99 0 0 0 -1 -1 -1 127 -1 -1 -1 127 -1 -1 -1 127 -1 -1 -1 127 -1 -1 -1 127
但是这些字节不能通过强制转换为有意义的 String ,这些 byte[] 是什么意思?(可能包含一些 AT 命令?)如何使用 Xposed 挂钩 RIL.java 中的发送者和接收者线程?
class RILSender extends Handler implements Runnable {
public RILSender(Looper looper) {
super(looper);
}
// Only allocated once
byte[] dataLength = new byte[4];
//***** Runnable implementation
public void
run() {
//setup if needed
}
//***** Handler implementation
@Override public void
handleMessage(Message msg) {
RILRequest rr = (RILRequest)(msg.obj);
RILRequest req = null;
switch (msg.what) {
case EVENT_SEND:
/**
* mRequestMessagePending++ already happened for every
* EVENT_SEND, thus we must make sure
* mRequestMessagePending-- happens once and only once
*/
boolean alreadySubtracted = false;
try {
LocalSocket s;
s = mSocket;
if (s == null) {
rr.onError(RADIO_NOT_AVAILABLE, null);
rr.release();
if (mRequestMessagesPending > 0)
mRequestMessagesPending--;
alreadySubtracted = true;
return;
}
synchronized (mRequestList) {
mRequestList.add(rr);
mRequestMessagesWaiting++;
}
if (mRequestMessagesPending > 0)
mRequestMessagesPending--;
alreadySubtracted = true;
byte[] data;
data = rr.mp.marshall();
rr.mp.recycle();
rr.mp = null;
if (data.length > RIL_MAX_COMMAND_BYTES) {
throw new RuntimeException(
"Parcel larger than max bytes allowed! "
+ data.length);
}
// parcel length in big endian
dataLength[0] = dataLength[1] = 0;
dataLength[2] = (byte)((data.length >> 8) & 0xff);
dataLength[3] = (byte)((data.length) & 0xff);
//Rlog.v(LOG_TAG, "writing packet: " + data.length + " bytes");
s.getOutputStream().write(dataLength);
s.getOutputStream().write(data);
} catch (IOException ex) {
Rlog.e(LOG_TAG, "IOException", ex);
req = findAndRemoveRequestFromList(rr.mSerial);
// make sure this request has not already been handled,
// eg, if RILReceiver cleared the list.
if (req != null || !alreadySubtracted) {
rr.onError(RADIO_NOT_AVAILABLE, null);
rr.release();
}
} catch (RuntimeException exc) {
Rlog.e(LOG_TAG, "Uncaught exception ", exc);
req = findAndRemoveRequestFromList(rr.mSerial);
// make sure this request has not already been handled,
// eg, if RILReceiver cleared the list.
if (req != null || !alreadySubtracted) {
rr.onError(GENERIC_FAILURE, null);
rr.release();
}
} finally {
// Note: We are "Done" only if there are no outstanding
// requests or replies. Thus this code path will only release
// the wake lock on errors.
releaseWakeLockIfDone();
}
if (!alreadySubtracted && mRequestMessagesPending > 0) {
mRequestMessagesPending--;
}
break;
case EVENT_WAKE_LOCK_TIMEOUT:
// Haven't heard back from the last request. Assume we're
// not getting a response and release the wake lock.
synchronized (mWakeLock) {
if (mWakeLock.isHeld()) {
// The timer of WAKE_LOCK_TIMEOUT is reset with each
// new send request. So when WAKE_LOCK_TIMEOUT occurs
// all requests in mRequestList already waited at
// least DEFAULT_WAKE_LOCK_TIMEOUT but no response.
// Reset mRequestMessagesWaiting to enable
// releaseWakeLockIfDone().
//
// Note: Keep mRequestList so that delayed response
// can still be handled when response finally comes.
if (mRequestMessagesWaiting != 0) {
Rlog.d(LOG_TAG, "NOTE: mReqWaiting is NOT 0 but"
+ mRequestMessagesWaiting + " at TIMEOUT, reset!"
+ " There still msg waitng for response");
mRequestMessagesWaiting = 0;
if (RILJ_LOGD) {
synchronized (mRequestList) {
int count = mRequestList.size();
Rlog.d(LOG_TAG, "WAKE_LOCK_TIMEOUT " +
" mRequestList=" + count);
for (int i = 0; i < count; i++) {
rr = mRequestList.get(i);
Rlog.d(LOG_TAG, i + ": [" + rr.mSerial + "] "
+ requestToString(rr.mRequest));
}
}
}
}
// mRequestMessagesPending shows how many
// requests are waiting to be sent (and before
// to be added in request list) since star the
// WAKE_LOCK_TIMEOUT timer. Since WAKE_LOCK_TIMEOUT
// is the expected time to get response, all requests
// should already sent out (i.e.
// mRequestMessagesPending is 0 )while TIMEOUT occurs.
if (mRequestMessagesPending != 0) {
Rlog.e(LOG_TAG, "ERROR: mReqPending is NOT 0 but"
+ mRequestMessagesPending + " at TIMEOUT, reset!");
mRequestMessagesPending = 0;
}
mWakeLock.release();
}
}
break;
}
}
}
class RILReceiver implements Runnable {
byte[] buffer;
RILReceiver() {
buffer = new byte[RIL_MAX_COMMAND_BYTES];
}
public void
run() {
int retryCount = 0;
try {for (;;) {
LocalSocket s = null;
LocalSocketAddress l;
try {
s = new LocalSocket();
l = new LocalSocketAddress(SOCKET_NAME_RIL,
LocalSocketAddress.Namespace.RESERVED);
s.connect(l);
} catch (IOException ex){
try {
if (s != null) {
s.close();
}
} catch (IOException ex2) {
//ignore failure to close after failure to connect
}
// don't print an error message after the the first time
// or after the 8th time
if (retryCount == 8) {
Rlog.e (LOG_TAG,
"Couldn't find '" + SOCKET_NAME_RIL
+ "' socket after " + retryCount
+ " times, continuing to retry silently");
} else if (retryCount > 0 && retryCount < 8) {
Rlog.i (LOG_TAG,
"Couldn't find '" + SOCKET_NAME_RIL
+ "' socket; retrying after timeout");
}
try {
Thread.sleep(SOCKET_OPEN_RETRY_MILLIS);
} catch (InterruptedException er) {
}
retryCount++;
continue;
}
retryCount = 0;
mSocket = s;
Rlog.i(LOG_TAG, "Connected to '" + SOCKET_NAME_RIL + "' socket");
int length = 0;
try {
InputStream is = mSocket.getInputStream();
for (;;) {
Parcel p;
length = readRilMessage(is, buffer);
if (length < 0) {
// End-of-stream reached
break;
}
p = Parcel.obtain();
p.unmarshall(buffer, 0, length);
p.setDataPosition(0);
//Rlog.v(LOG_TAG, "Read packet: " + length + " bytes");
processResponse(p);
p.recycle();
}
} catch (java.io.IOException ex) {
Rlog.i(LOG_TAG, "'" + SOCKET_NAME_RIL + "' socket closed",
ex);
} catch (Throwable tr) {
Rlog.e(LOG_TAG, "Uncaught exception read length=" + length +
"Exception:" + tr.toString());
}
Rlog.i(LOG_TAG, "Disconnected from '" + SOCKET_NAME_RIL
+ "' socket");
setRadioState (RadioState.RADIO_UNAVAILABLE);
try {
mSocket.close();
} catch (IOException ex) {
}
mSocket = null;
RILRequest.resetSerial();
// Clear request list on close
clearRequestList(RADIO_NOT_AVAILABLE, false);
}} catch (Throwable tr) {
Rlog.e(LOG_TAG,"Uncaught exception", tr);
}
/* We're disconnected so we don't know the ril version */
notifyRegistrantsRilConnectionChanged(-1);
}
}