逆向某寶x-sign算法

上篇博文中淺析了從手機淘寶中提煉出商品搜索接口,不少人有個疑惑,x-sign怎麼來的?目前不少網友表示是經過xposed hook用模擬器做服務器中轉的方式。下面咱們經過逆向so文件的方式取得這個x-sign的算法。java

##找到x-sign的計算點 通過一系列跳轉後,咱們看到了com.taobao.wireless.security.adapter.a接口的a方法。算法

private String a(String[] arg4, String arg5, int arg6, String arg7) {
        return this.a.getRouter().doCommand(10401, new Object[]{arg4, arg5, Integer.valueOf(arg6), arg7});
    }

在接下來的跳轉鏈以後,咱們又找到了實現RouterComponent接口以及doCommand方法的一個類:服務器

package com.alibaba.wireless.security.mainplugin;

import com.alibaba.wireless.security.framework.IRouterComponent;
import com.taobao.wireless.security.adapter.JNICLibrary;

public class a implements IRouterComponent {
    public a() {
        super();
    }
    public Object doCommand(int arg2, Object[] arg3) {
        return JNICLibrary.doCommandNative(arg2, arg3);
    }
}

還有一個JNICLibrary類,其中聲明瞭doCommandNative方法:架構

package com.taobao.wireless.security.adapter;

public class JNICLibrary {
    public static native Object doCommandNative(int arg0, Object[] arg1);
}

所以,咱們須要在原生代碼中找到doCommandNative方法。less

混淆機器碼

在libsgmain.so文件中包含一個原生庫(libsgmain.so其實是一個.JAR文件,其中實現了與加密有關的接口):libsgmainso-6.xx.x。在IDA中加載該庫後,咱們看到了一堆錯誤消息提示框,問題在於section頭表無效。函數

經過elf查看工具咱們能夠看到 在這裏插入圖片描述 但咱們並不須要這個信息,程序頭表對咱們而言已經足夠,能夠正確加載並分析ELF文件。所以咱們能夠簡單刪除section頭表,將頭部中對應的字段置空。工具

在這裏插入圖片描述 而後再次在IDA中打開該文件。this

咱們有兩種方法能告訴Java虛擬機哪一個原生庫包含代碼中聲明的原生代碼的具體實現。第一種方法就是採用Java_package_name_ClassName_methodName之類的名字,第二種方法是調用RegisterNatives函數,在加載庫的時候進行註冊(在JNI_OnLoad函數中)。對於這個案例,若是咱們使用第一種方法,那麼函數名應該相似於Java_com_taobao_wireless_security_adapter_JNICLibrary_doCommandNative。在導出函數中咱們找不到這個名字,這意味着咱們須要查找RegisterNatives。所以,咱們轉到JNI_OnLoad函數,看到以下代碼:編碼

在這裏插入圖片描述 這裏代碼執行了哪些邏輯?初步分析時,函數頭以及函數尾都是典型的ARM架構。第一條指令會將函數須要使用的寄存器值push到棧中(這裏爲R0、R一、R2以及LR,用來保存函數返回地址)。最後一條指令恢復已保存的寄存器值,將返回地址存到PC寄存器中,而後返回函數。但若是咱們仔細分析,可能會注意到倒數第二條指令改變了返回地址。來計算一下代碼執行後返回地址的值。該地址加載自R1(0xB130),減去5,而後被mov到R0,再加上0x10,最後這個值等於0xB13B。所以,IDA認爲最終指令執行的是正常的函數返回操做,然而實際上會跳轉到0xB13B這個地址。加密

這裏須要注意的是,ARM處理器有兩個型號以及兩組指令:ARM以及Thumb。地址的低位用來決定處理器會使用哪一組指令集。這裏地址爲0xB13A,所以對應的是Thumb模式。

在這個庫中,每一個函數開頭處都添加了相似的語句以及某些垃圾代碼,這裏咱們不會詳細分析這些內容,只要記住幾乎全部函數的實際代碼都離函數開頭有一段距離。

因爲已有代碼中沒有顯式轉換到0xB13A,所以IDA沒法識別該地址處的代碼。一樣,IDA也沒有將庫中的大部分數據識別爲代碼,這樣咱們分析起來須要稍微用點技巧 所以,咱們手動告訴IDA代碼位置,而後獲得以下結果: 在這裏插入圖片描述 接下來咱們採用腳原本patch代碼。(鑑於篇幅 腳本內容略) patch完成後,咱們能夠指引IDA找到函數的真實代碼。IDA會逐一收集全部函數代碼,而後咱們就可使用HexRays來反編譯代碼。 咱們已經找到加密算法和密鑰,如今讓咱們嘗試解密類名。咱們獲得的結果爲com/taobao/wireless/security/adapter/JNICLibrary

命令結構樹

如今咱們須要找到哪裏調用了RegisterNatives,這將咱們指引到doCommandNative函數。通過一系列分析還原得出具體邏輯:

int __fastcall doCommandNative(JNIEnv *env, jobject obj, int command, jarray args)
{
  int v5; // r5
  struc_2 *a5; // r6
  int v9; // r1
  int v11; // [sp+Ch] [bp-14h]
  int v12; // [sp+10h] [bp-10h]
  v5 = 0;
  v12 = *(_DWORD *)off_8AC00;
  v11 = 0;
  a5 = (struc_2 *)malloc(0x14u);
  if ( a5 )
  {
    a5->field_0 = 0;
    a5->field_4 = 0;
    a5->field_8 = 0;
    a5->field_C = 0;
    v9 = command % 10000 / 100;
    a5->field_0 = command / 10000;
    a5->field_4 = v9;
    a5->field_8 = command % 100;
    a5->field_C = env;
    a5->field_10 = args;
    v5 = sub_9D60(command / 10000, v9, command % 100, 1, (int)a5, &v11);
  }
  free(a5);
  if ( !v5 && v11 )
    sub_7CF34(env, v11, &byte_83ED7);
  return v5;
}

函數名錶示這是開發者將全部函數轉到原生庫的統一入口點,咱們的目標函數編號爲10401。 從代碼中咱們能夠經過命令編號生成3個子編號:command / 10000、command % 10000 / 100以及command % 10(這裏咱們對應的是一、4以及1)。這3個子編號、指向JNIEnv的指針以及傳給該函數的其餘參數共同組成一個結構體,以便後續使用。 這棵樹會在JNI_OnLoad中動態建立,其中3個子編號共同編碼了整棵樹的路徑。樹中每一個節點都包含相應函數通過異或處理後的地址,祕鑰位於父節點中。

最終結果

在這裏插入圖片描述

相關文章
相關標籤/搜索