2015-12-03 45 views
1

現在我正在測試一些Android手機通話加密。 我必須使用Xposed框架Android RIL套接字和電話加密?

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); 
      } 
    }); 
} 

然後勾在RIL.java一些方法,我得到了一些日誌,如:

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 

但這些字節不能被強制轉換爲有意義的字符串,是什麼做這些字節[] 意思? (可能包含一些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); 
    } 
} 

回答

1

因此,使用RIL掛鉤一段時間後,我可以回答您的文章的第二部分。

RIL消息可以有兩種類型,SOLLICITEDUNSOLLICITED
這些得到如何處理可以在java類RIL可以看到從Android源RIL.java

但我會簡單介紹一下它們的結構以及它們如何得到解析:

不請自來的消息是RIL發送消息並且通常是與收音機有關的事件。 一個unsollicited消息的一個例子是:

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類中找到。

SOLLICITED消息是對android發送到RIL層的請求的響應。這些都是異步完成的,並且在釋放wakelock之前,android會保持wakelock等待DEFAULT_WAKE_LOCK_TIMEOUT的響應(即使是強硬的它仍然會在最終得到它時處理響應)。
SOLLICITED響應得到處理有點不同,發送請求時android獲取請求的全局序列(as seen here),並將其保存到內部列表中。當它收到響應時,它使用串行(as seen here)查找響應。
一個sollicited信息的例子是:

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