n0elle 发表于 2017-2-26 00:06

APP签名算法提取之曲线救国

本帖最后由 n0elle 于 2017-2-26 00:17 编辑

现在,绝大多数apk在数据签名验证方面,采用了jni+so的方式增加安全性。

上次遇到一个app,360加固+native签名算法函数,这里不对脱壳做过多的描述。

用Charles对app进行抓包,多次抓包发现FuncTag是每个事件处理函数的一个标识,用于区分请求的模块功能。



发现有一个参数sv,应该是数据的签名字段,应该就是我们的目标。


在Android Killer打开工程,搜索40000020的16进制0x2625A14 定位到该处。



计算sv的区域,包名已经除去。
new-instance v0, Ljava/lang/StringBuilder;

    invoke-direct {v0}, Ljava/lang/StringBuilder;-><init>()V

    const-string v1, "a:"

    invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    move-result-object v0

    sget v1, Lcom/xxxx/xxxx/a/g;->d:I

    invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder;

    move-result-object v0

    const-string v1, "c"

    invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    move-result-object v0

    const-string v1, ":"

    invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    move-result-object v0

    .line 4636
    invoke-static {}, Lcom/xxxx/xxxx/y;->d()Lcom/xxxx/xxxx/y;

    move-result-object v1

    invoke-virtual {v1}, Lcom/xxxx/xxxx/y;->ap()Ljava/lang/String;

    move-result-object v1

    invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    move-result-object v0

    invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;

    move-result-object v0

    /*
    省略部分
    */
    .line 4643
    new-instance v1, Ljava/lang/StringBuilder;

    invoke-direct {v1}, Ljava/lang/StringBuilder;-><init>()V

    const-string v2, ""

    invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    move-result-object v1

    invoke-static {}, Lcom/xxxx/xxxx/y;->d()Lcom/xxxx/xxxx/y;

    move-result-object v2

    invoke-virtual {v2}, Lcom/xxxx/xxxx/y;->aB()J

    move-result-wide v2

    invoke-virtual {v1, v2, v3}, Ljava/lang/StringBuilder;->append(J)Ljava/lang/StringBuilder;

    move-result-object v1

    invoke-virtual {v1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;

    move-result-object v1

    invoke-static {v0, v1}, Lcom/xxxx/xxxx/utils/EncodeString;->EncodeMD5(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;

    move-result-object v1
在这里可以看出,sv的计算方法是把每个参数按照一定的顺序排列拼接起来,再进行EncodeMD5。


转换成java代码验证一下,没有错。       Object localObject = "a:" + com.xxxx.xxxx.a.g.d + "c" + ":" + com.xxxx.xxxx.y.d().ap();
    localObject = (String)localObject + "FuncTag" + ":" + 40000020;
    localObject = (String)localObject + "ir" + ":" + paramInt2;
    localObject = (String)localObject + "phoneNum" + ":" + paramString;
    localObject = (String)localObject + "platform" + ":" + 2;
    localObject = (String)localObject + "smsType" + ":" + paramInt1;
    String str = EncodeString.EncodeMD5((String)localObject + "userId" + ":", "" + com.xxxx.xxxx.y.d().aB());

str 就是我们要的sv值,他是通过EncodeString类里的EncodeMD5方法来加密的,跟过去看看。


发现都是static native的方法。
.method public static native EncodeMD5(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
.end method

.method public static native EncodeMD5ByByte([BLjava/lang/String;)Ljava/lang/String;
.end method

.method public static native EncodeUserNameAndPassword(Ljava/lang/String;)Ljava/lang/String;
.end method
继续找下,看下是加载哪个so库。


搜索关键字 loadLibrary ,发现在app初始化时加载了两个动态库,很明显,EncodeString类应该在encode这个动态库里面。
private static void b(Context paramContext)
{
    int i = Build.VERSION.SDK_INT;
    y.a(d, "loadSo , SDK Version: " + i);
    System.loadLibrary("encode");
    System.loadLibrary("game");
}


找到so文件拖入IDA,搜索 encode。

看了很久不是很明白他的算法到底是怎么实现的,他修改了MD5的算法,并不是一般的(数据+key)再进行原生的MD5加密。


在导出表里面发现这几个导出函数,想到了一个办法。



找到了函数注册到java里的包名,这里就跟上面在java代码里面看到的包名路径是一样的。



打开Android Studio,新建一个项目。



在main下新建jniLibs目录,把上面的so库放入armeabi中



在上面jni映射过来的方法在com.xxxx.engine.utils中,这里新建一个包,包名路径相同。



写一个EncodeString类,函数申明在上面反编译出来的代码里面已经有了,直接照搬过来。
在函数前装载so库
    static {
      System.loadLibrary("encode");
    }





在Oncreate下面调用EncodeMD5方法,debug打印出来。
运行一遍,看调试器里面,so已经加载成功。



String str = EncodeString.EncodeMD5((String)localObject + "userId" + ":", "" + com.xxxx.xxxx.y.d().aB());



最后按照原来的参数打印出来sv。其实这样相当于是曲线救国,可以把一台手机用于签名,连接电脑进行生产工作。
但是这样的效率相对来说低一点,对模拟器的兼容也不太好。
所以只能当做下下策来使用。

zxg1987 发表于 2017-3-3 12:39

n0elle 发表于 2017-2-27 13:23
其实,我发出来也是想学习下各位大神在处理相似问题时的应对方法,但是好像大神并不在:-(

大神都 是忙的,但是你我要想成大神只有不断摸索了

n0elle 发表于 2017-2-27 13:23

zxg1987 发表于 2017-2-27 13:04
希望可以有更好 的方法发出来

其实,我发出来也是想学习下各位大神在处理相似问题时的应对方法,但是好像大神并不在:-(

修罗本灭世 发表于 2017-2-26 00:22

不明觉厉!!!!!!!!!!!!!

邪恶博士 发表于 2017-2-26 00:33

谢谢分享

无名小银 发表于 2017-2-26 01:47

过来瞅瞅

daocao 发表于 2017-2-26 02:00

感谢分享,支持~

hobmg 发表于 2017-2-26 02:04

很是厉害 很是厉害

sdaza 发表于 2017-2-26 06:34

有意思。

Open 发表于 2017-2-26 07:54

感谢分享,长知识

夏雨微凉 发表于 2017-2-26 09:03

涨姿势啊

maomao1314 发表于 2017-2-26 12:05

谢谢分享
页: [1] 2 3 4 5 6
查看完整版本: APP签名算法提取之曲线救国