简体   繁体   English

Android RIL套接字和电话加密?

[英]Android RIL socket and phone calls encryption?

Now I'm testing something in Android phone calls encryption. 现在,我正在测试Android电话加密中的某些功能。 I have Hook some method in RIL.java by using Xposed framework 我通过使用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);
            }
    });
}

Then I got some Logs like: 然后我得到一些日志,例如:

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

But these bytes can not by cast to meaningful String , what does these byte[] mean? 但是这些字节不能强制转换为有意义的String,这些byte []是什么意思? (maybe contains some AT command?) how can I use Xposed to Hook the sender and receiver threads in RIL.java? (也许包含一些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);
    }
}

So after working with RIL hooking for a while, I can answer the second part of your post. 因此,在使用RIL挂钩一段时间后,我可以回答您帖子的第二部分。

RIL messages can be of two types, SOLLICITED and UNSOLLICITED . RIL消息可以是两种类型, SOLLICITEDUNSOLLICITED
How these get handled can be seen in the java RIL class from the android sources RIL.java 可以从android源RIL.java的java RIL类中看到如何处理这些问题

But I'll explain briefly their structure and how they get parsed: 但是我将简要解释它们的结构以及如何解析它们:

UNSOLICITED messages are messages that RIL sends on its own and are usually events related to the radio. UNSOLICITED消息是RIL自己发送的消息,通常是与无线电有关的事件。 An example of an unsollicited message is: 一条不亲和的消息的示例是:

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 

The structure is simple: 结构很简单:

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

so 所以

  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 )

Response constants can be found in the RILConstants.java class from the sources. 可以从源代码的RILConstants.java类中找到响应常数。

SOLLICITED messages are responses to requests that android sends to the RIL layer. SOLLICITED消息是对android发送到RIL层的请求的响应。 These are done asynchronously and android keeps a wakelock waiting for a response for DEFAULT_WAKE_LOCK_TIMEOUT before releasing the wakelock ( even tough it will still process the response when it will eventually get it ). 这些都是异步完成的,Android会在释放唤醒锁之前保留一个唤醒锁,等待DEFAULT_WAKE_LOCK_TIMEOUT的响应(即使很难,它最终会得到响应时仍会处理该响应)。
SOLLICITED responses get handled a bit differently, when sending a request android gets a global serial for the request ( as seen here ), and saves it into an internal list. SOLLICITED响应的处理方式有所不同,当发送请求时,android获取该请求的全局序列( 如此处所示 ),并将其保存到内部列表中。 When it receives a response, it finds the response using the serial ( as seen here ). 收到响应后,它将使用序列号找到响应( 如此处所示 )。
An example of a sollicited message is: 提示信息的示例是:

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

The structure is as follows: 结构如下:

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

so 所以

  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 )

For the constants regarding error you should take a look at CommandException.java 有关错误的常量,请查看CommandException.java

If you want to parse the SOLLICITED responses you must hook RILRequest.obtain to be able to save a key-value copy of mSerial and mRequest to be able to parse it ( otherwise you CAN'T know the request ) 如果要解析SOLLICITED响应,则必须挂接RILRequest.obtain才能保存mSerial和mRequest的键值副本以能够解析它(否则,您将无法知道请求)

If you want to know more about the entire RIL layer there is an exaustive slide that covers pretty much everything android-radio-layer-interface . 如果您想了解整个RIL层的更多信息,可以浏览一张幻灯片,它涵盖了android-radio-layer-interface的几乎所有内容。
Also, shameless plug, but if you want you can take a look at an example module I did that basically just logs RIL messages. 同样,无耻的插件,但是如果您愿意,可以看一个示例模块,我基本上只是记录RIL消息。 xposed-ril-wrapper xposed-RIL-包装

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM