逆向某宝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个子编号共同编码了整棵树的路径。树中每一个节点都包含相应函数通过异或处理后的地址,秘钥位于父节点中。

最终结果

在这里插入图片描述

相关文章
相关标签/搜索