2

现在我正在测试 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);
    }
}
4

1 回答 1

3

因此,在使用 RIL hooking 一段时间后,我可以回答您帖子的第二部分。

RIL 消息可以有两种类型,SOLLICITEDUNSOLLICITED
这些如何处理可以在来自a​​ndroid源RIL.java的java RIL类中看到

但我将简要解释它们的结构以及它们是如何被解析的:

UNSOLICITED消息是 RIL 自行发送的消息,通常是与无线电相关的事件。未经请求的消息的示例是:

1 0 0 0 -15 3 0 0 15 0 0 0 0 0 0 0 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -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 

结构很简单:

[type uint32 little endian][response uint32 little endian][data]

所以

  1 0 0 0 = 1 is the type of the request, which means unsollicited message( notice the endianess )
-15 3 0 0 = 1009 is the response , which matches RIL_UNSOL_SIGNAL_STRENGTH
[15 0 . .]= data structure regarding signal strenght ( in this case an array of strings )

响应常量可以在源代码的RILConstants.java类中找到。

SOLICITED消息是对 android 发送到 RIL 层的请求的响应。这些是异步完成的,android 在释放唤醒锁之前保持唤醒锁等待 DEFAULT_WAKE_LOCK_TIMEOUT 的响应(即使很难,它仍然会在最终获得响应时处理响应)。
SOLLICITED 响应的处理方式略有不同,当发送请求时,android 会获取请求的全局序列(如此处所示),并将其保存到内部列表中。当它收到响应时,它会使用序列号找到响应(如此处所示)。
请求消息的示例是:

0 0 0 0 -94 0 0 0 17 0 0 0

结构如下:

[type uint32 little endian][serial uint32 little endian][error uint32 little endian][data]

所以

  0 0 0 0 = 0 is the type, UNSOLICITED
-94 0 0 0 = 162 is the serial
 17 0 0 0 = 17 is the error ( NO_SUCH_ELEMENT )

对于有关错误的常量,您应该查看CommandException.java

如果要解析 SOLLICITED 响应,则必须挂钩RILRequest.obtain才能保存 mSerial 和 mRequest 的键值副本才能解析它(否则您无法知道请求)

如果你想了解更多关于整个 RIL 层的信息,这里有一张详尽的幻灯片,它几乎涵盖了android-radio-layer-interface的所有内容。
另外,无耻的插件,但是如果您愿意,可以查看我所做的示例模块,它基本上只是记录 RIL 消息。xposed-ril-wrapper

于 2016-04-27T09:07:17.223 回答