逆向某寶x-sign算法


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

找到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方法。

混淆機器碼

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

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

在這里插入圖片描述
然后再次在IDA中打開該文件。

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

在這里插入圖片描述
這里代碼執行了哪些邏輯?初步分析時,函數頭以及函數尾都是典型的ARM架構。第一條指令會將函數需要使用的寄存器值push到棧中(這里為R0、R1、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(這里我們對應的是1、4以及1)。這3個子編號、指向JNIEnv的指針以及傳給該函數的其他參數共同組成一個結構體,以便后續使用。
這棵樹會在JNI_OnLoad中動態創建,其中3個子編號共同編碼了整棵樹的路徑。樹中每個節點都包含相應函數經過異或處理后的地址,秘鑰位於父節點中。

最終結果

在這里插入圖片描述


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM