首页
社区
课程
招聘
[原创]记一次简单的sign分析
发表于: 2020-11-5 21:09 10701

[原创]记一次简单的sign分析

2020-11-5 21:09
10701

前因:没有别的,就是群里有老哥发的文件,初学逆向,为自己记录顺带分享给和我一样刚开始起步学习的人,作为第一次在看雪上发帖子,有点小激动!

这里定位很简单,直接全局搜索关键词:"a" 就可以了,因为可以看到POST数据包中只有一个字段就是a,但是这里需要带上双引号,来到如下
图片描述

可以看到最关键的加密代码就是:

initFromXML.getAppKey则正常返回一个定值

图片描述

跟进m3385a函数可以发现,定义如下:

注意:这里发现JSONObject是处于org.json.JSONObject,系统自带的库中的类,这里也能作为一种hook的方法定位

对JSONObejct的hook效果如下,虽然是可以进行hook,但是我这里会发现程序会崩溃,可能代码有瑕疵,自己猜想就是因为第二个参数为java.lang.String类型的,但是你接收的时候如果要包含java.lang.String类型就必须指明java.lang.Object,然后再进行强转java.cast(),但是在接收的时候java.lang.Object不一定总是java.lang.String,可能是一个List或者Map等,这时候强转为java.lang.String就会造成程序结束
图片描述

这里可以直接对m3385a这个函数进行观察,流程就是将传入的数据先进行一个url编码,然后拼接initFromXML.getAppKey作为参数,调用EncryptUtil.encryptString

图片描述

继续跟到encryptString中去,代码如下,那么也就需要进libgavesec.so中的nativeEncrypt函数进行分析

图片描述

这里遇到了一个问题,比如下面的两个函数和注入代码,一个函数会调用native中的函数,但是如果我hook encryptString这个函数,返回值写的是调用native层的nativeEncrypt函数,这样的写法就会导致程序结束,具体原因不知道

因为上面那样写就导致程序结束,所以这里就直接hook nativeEncrypt,发现这样子就不会导致程序结束了

这里可以对EncryptUtil.encryptString(encode + str),java层进行一次hook来获取对应的参数先

那么的initFromXML.getAppKey值就为:

然后接着继续跟native层进行分析,将libgavesec.so拖入到IDA中,并且找到对应的函数,该函数是静态注册的,所以特征很明显,如果是动态注册的话 可以通过jni_onload中一些偏移变量来进行寻找对应的静态注册的函数

图片描述

主要进行了encrypt函数的调用

图片描述

接着就是来到加密函数encrypt中进行分析
图片描述

先是进行一次sha1加密
图片描述

所以这里要hook两个地方

encrypt:Base + 0x1C8C ,获取第一个参数

SHA1::Result:Base + 0x2AA4,获取该函数调用完之后的第二个参数的结果

hook的结果如下显示:
图片描述

接着打印了sha1加密过后的数据v12变量和最终的Sign值(这里也就是nativeEncrypt的返回值),但是你会发现结果是不一样的
图片描述

接着继续往下面看,会发现存在循环的操作,所以sha1加密的结果应该被二次修改了,这里有两个大循环的操作
图片描述

首先第一段循环:

你会发现hexDigits是data段的一段数据:

图片描述

最后分析,其实就是将其原封不动的转换为16进制的字符,然后一起拼接起来,分析注释如下

图片描述

然后就是第二段循环了,循环次数也可以看出来会对每个16进制字符进行处理,循环次数为40次

图片描述

hook了char2hexInt处理过后的数据会发现,char2hexInt这个函数才是二次处理的函数

图片描述

还需要char2hexInt的参数来观察,该地址为0x1B34,HOOK结果如下

图片描述

其实就是两个返回值进行异或处理,比如0x2^0x2就为0,最后还会通过hexDigits数组转成对应的16进制在内存中保存为0x30,因为字符 '0' 对应的ASCII 十六进制就是 0x30 是相等的!

图片描述

最终的sign值分析的注释:

图片描述

sign这里也分析完了,还有个整体加密的分析,发现整体会进行一次Base64.encode,但是nativeAES可以跟进去观察

图片描述

发现该函数依旧是native层的函数,所以这里继续去看分析

图片描述

来到如下进行分析,看到名字就知道是AES算法加密了,这里的话用findcrypt插件通过特征码也可以进行识别

图片描述

图片描述

然后接着就是先对传入的数据进行字符串复制

图片描述

然后就是AES对象和密钥的初始化,这里的AES需要hook,来确认v19的值,还有该函数最终的返回值dest_array_bytes的地址来进行打印

图片描述

AES::AES:0x3274,Cipher:0x397C,然后hook到的数据如下,一个是AES密钥,最终要进行AES字符串加密的字符串

图片描述

到这里就分析结束了

最终hook的代码:

简单的加密代码的实现:

结果对比:

hook:
图片描述

python:
图片描述
初学逆向,写的不好请见谅!

请求包:
 
POST /api/adult/check_guest HTTP/1.1
Content-Type: application/x-www-form-urlencoded
User-Agent: Dalvik/2.1.0 (Linux; U; Android 8.1.0; Pixel Build/OPM1.171019.011)
Host: service.kuyangsh.cn
Connection: Keep-Alive
Accept-Encoding: gzip
Content-Length: 1108
 
 
a=6ih0KN8TFL5%2FQT%2FN3JY63ZovsWQyeIxHjBLHp1GGwjUNYVaGJLC%2FYZenRFKbeqsgIoI4rD1atROr%0Ajkl1p7eobNMARMel19oiGkl5hRD72vOn9zyNbERMe8Cj3b24Ru4wc2mWbbnamKVKPepkaa2mqpJl%0Akp4%2Fa5udSz0UbDR6cTwLCRWeKb60H%2Fir4vzZv1OfwQF%2FXJQsuBmxH2F6wp9CJkk9WYchx4LQU%2FS3%0AjQfpQY2iZWwsmHAiyZGVsfZIgXTvhJygpT8vH268Py5JspYZoho0RRrx4BjUfs5boif6rEMpd5PC%0AiZTLhIPovbPpoZQJC7d%2BWPFtwjPT7Ljyzgz5QxtctnZqa4qMMkfFwAIeA7lj2wJZeZBD%2F%2BoU5R45%0AMEFK6OMrMXB1M%2BC4dBt7Rd384SYhe%2BAEp0gKNHGkrpxWImFcPAaalajyijs6V4Wl4res9CWuEE5W%0Ayj5ehtmPc6uZGuo5ns6THfDwnho8BiFOnH0QoqJEeyVdTsCzOiMwfBJJldB7qbsTfUlLbSnpq4tf%0AurPbVMVKQbk4ui1XgDH5v%2FptUHirNK0IHT%2BBms8wQ%2BSX3BcMLKFiWI0OBAjUydqcJpIi0sPSWpfh%0A2k1nmMlvPnljfc7P12iF8nFHoFWRYQPVie46K%2Bhd4%2FttkyrZ4Gy3WM6zWdmnED3h6CCgZ4rEe0DB%0AN5Dj8lJJbsOAE%2FxWcYDguyj8WkUET3yLB%2FBZQx%2BsOn9otWzjwROdhfi6V7OObXZ5XoGUIDffKaFu%0ADnvTinsAh%2FvjcSDVq%2BHyD%2FzUeRceMf6uQruBhHRzikSb2Oz0Zfxld7rqmWYZ8aIBe1DMRJuXecB%2F%0AAsBu4VVuVVfQf4hlCpVNmKnX6huuMkHtCptCLaD0pkmuY7X7OEfCsudtFIco%2F7gXaQ5aXgfCs7GJ%0AzAMxfpCRm4vnF0kc8nQ4OWlexOV5t65k%2B4eDt8wY91%2BIFHcq%2BIwZPR3e41oeKriHlbsPdocNOkeg%0AeyUw%2FXlAY97IpZA%3D%0A
 
返回包:
 
{
  "ret": 0,
  "msg": "没有错误",
  "data": {
    "needs_check": "0",
    "needs_bind": "0",
    "needs_guest_bind": 0,
    "user_is_guest": -1
  }
}
请求包:
 
POST /api/adult/check_guest HTTP/1.1
Content-Type: application/x-www-form-urlencoded
User-Agent: Dalvik/2.1.0 (Linux; U; Android 8.1.0; Pixel Build/OPM1.171019.011)
Host: service.kuyangsh.cn
Connection: Keep-Alive
Accept-Encoding: gzip
Content-Length: 1108
 
 
a=6ih0KN8TFL5%2FQT%2FN3JY63ZovsWQyeIxHjBLHp1GGwjUNYVaGJLC%2FYZenRFKbeqsgIoI4rD1atROr%0Ajkl1p7eobNMARMel19oiGkl5hRD72vOn9zyNbERMe8Cj3b24Ru4wc2mWbbnamKVKPepkaa2mqpJl%0Akp4%2Fa5udSz0UbDR6cTwLCRWeKb60H%2Fir4vzZv1OfwQF%2FXJQsuBmxH2F6wp9CJkk9WYchx4LQU%2FS3%0AjQfpQY2iZWwsmHAiyZGVsfZIgXTvhJygpT8vH268Py5JspYZoho0RRrx4BjUfs5boif6rEMpd5PC%0AiZTLhIPovbPpoZQJC7d%2BWPFtwjPT7Ljyzgz5QxtctnZqa4qMMkfFwAIeA7lj2wJZeZBD%2F%2BoU5R45%0AMEFK6OMrMXB1M%2BC4dBt7Rd384SYhe%2BAEp0gKNHGkrpxWImFcPAaalajyijs6V4Wl4res9CWuEE5W%0Ayj5ehtmPc6uZGuo5ns6THfDwnho8BiFOnH0QoqJEeyVdTsCzOiMwfBJJldB7qbsTfUlLbSnpq4tf%0AurPbVMVKQbk4ui1XgDH5v%2FptUHirNK0IHT%2BBms8wQ%2BSX3BcMLKFiWI0OBAjUydqcJpIi0sPSWpfh%0A2k1nmMlvPnljfc7P12iF8nFHoFWRYQPVie46K%2Bhd4%2FttkyrZ4Gy3WM6zWdmnED3h6CCgZ4rEe0DB%0AN5Dj8lJJbsOAE%2FxWcYDguyj8WkUET3yLB%2FBZQx%2BsOn9otWzjwROdhfi6V7OObXZ5XoGUIDffKaFu%0ADnvTinsAh%2FvjcSDVq%2BHyD%2FzUeRceMf6uQruBhHRzikSb2Oz0Zfxld7rqmWYZ8aIBe1DMRJuXecB%2F%0AAsBu4VVuVVfQf4hlCpVNmKnX6huuMkHtCptCLaD0pkmuY7X7OEfCsudtFIco%2F7gXaQ5aXgfCs7GJ%0AzAMxfpCRm4vnF0kc8nQ4OWlexOV5t65k%2B4eDt8wY91%2BIFHcq%2BIwZPR3e41oeKriHlbsPdocNOkeg%0AeyUw%2FXlAY97IpZA%3D%0A
 
返回包:
 
{
  "ret": 0,
  "msg": "没有错误",
  "data": {
    "needs_check": "0",
    "needs_bind": "0",
    "needs_guest_bind": 0,
    "user_is_guest": -1
  }
}
 
String a = m3385a((Map<String, String>) hashMap, initFromXML.getAppKey());
String a = m3385a((Map<String, String>) hashMap, initFromXML.getAppKey());
 
 
 
public static String m3385a(Map<String, String> map, String str) {
    if (C1074a.f2394c || TivicloudController.f2343a) {
        map.put("testing", "1");
    }
    try {
        JSONObject jSONObject = new JSONObject(map);
        Debug.m3346d("params : " + jSONObject.toString());
        String encode = URLEncoder.encode(jSONObject.toString(), "UTF-8");
        String encryptString = EncryptUtil.encryptString(encode + str);
        JSONObject jSONObject2 = new JSONObject();
        try {
            jSONObject2.put("sign", encryptString);
            jSONObject2.put(C0882di.C0883a.DATA, encode);
        } catch (JSONException e) {
            Debug.m3354w((Exception) e);
        }
        return new String(Base64.encode(EncryptUtil.nativeAES(jSONObject2.toString()), 0), "UTF-8");
    } catch (UnsupportedEncodingException e2) {
        Debug.m3354w((Exception) e2);
        return null;
    }
}
public static String m3385a(Map<String, String> map, String str) {
    if (C1074a.f2394c || TivicloudController.f2343a) {
        map.put("testing", "1");
    }
    try {
        JSONObject jSONObject = new JSONObject(map);
        Debug.m3346d("params : " + jSONObject.toString());
        String encode = URLEncoder.encode(jSONObject.toString(), "UTF-8");
        String encryptString = EncryptUtil.encryptString(encode + str);
        JSONObject jSONObject2 = new JSONObject();
        try {
            jSONObject2.put("sign", encryptString);
            jSONObject2.put(C0882di.C0883a.DATA, encode);
        } catch (JSONException e) {
            Debug.m3354w((Exception) e);
        }
        return new String(Base64.encode(EncryptUtil.nativeAES(jSONObject2.toString()), 0), "UTF-8");
    } catch (UnsupportedEncodingException e2) {
        Debug.m3354w((Exception) e2);
        return null;
    }
}
 
 
 
 
 
public static String encryptString(String str) {
    return nativeEncrypt(str);
}
 
private static native String nativeEncrypt(String str);
 
 
Java.perform(function () {
    var EncryptUtil = Java.use("com.tivicloud.utils.EncryptUtil");
    EncryptUtil.encryptString.implementation = function (a) {
        send("EncryptUtil.encryptString args[0]: " + a);
        var result = this.nativeEncrypt(a);
        return result;
    }
});
public static String encryptString(String str) {
    return nativeEncrypt(str);
}
 
private static native String nativeEncrypt(String str);
 
 
Java.perform(function () {
    var EncryptUtil = Java.use("com.tivicloud.utils.EncryptUtil");
    EncryptUtil.encryptString.implementation = function (a) {
        send("EncryptUtil.encryptString args[0]: " + a);
        var result = this.nativeEncrypt(a);
        return result;
    }
});
setImmediate(function(){
    Java.perform(function () {
        var EncryptUtil = Java.use("com.tivicloud.utils.EncryptUtil");
        EncryptUtil.nativeEncrypt.implementation = function (a) {
            send("EncryptUtil.nativeEncrypt args[0]: " + a);
            var result = this.nativeEncrypt(a);
            return result;
        }
    });
});
setImmediate(function(){
    Java.perform(function () {
        var EncryptUtil = Java.use("com.tivicloud.utils.EncryptUtil");
        EncryptUtil.nativeEncrypt.implementation = function (a) {
            send("EncryptUtil.nativeEncrypt args[0]: " + a);
            var result = this.nativeEncrypt(a);
            return result;
        }
    });
});
[*] EncryptUtil.encryptString args[0]: {"mobile_operator":"","app_versioncode":"4","app_version":"2.1.0.22277","connection_type":"WIFI","os_version":"8.1.0","version_code":"4","version_name":"2.1.0.22277","os_lang":"zh","sdk_version":"3.1.4","package_name":"com.lm.lm","imei":"359906070277673","os_name":"Android","lang":"zh","udid":"10e1ef4509a2340eb0276bb99d186506","nudid":"155c2b70-fc97-4005-abc7-6d6c4329ed23","app_id":"10054","channel_id":"10006","tdid":"39fb282a761c17e80c069332fc6a2ffa9"}fff18b83431fa3a83b9de80c1e413bde
[*] EncryptUtil.encryptString args[0]: {"mobile_operator":"","app_versioncode":"4","app_version":"2.1.0.22277","connection_type":"WIFI","os_version":"8.1.0","version_code":"4","version_name":"2.1.0.22277","os_lang":"zh","sdk_version":"3.1.4","package_name":"com.lm.lm","imei":"359906070277673","os_name":"Android","lang":"zh","udid":"10e1ef4509a2340eb0276bb99d186506","nudid":"155c2b70-fc97-4005-abc7-6d6c4329ed23","app_id":"10054","channel_id":"10006","tdid":"39fb282a761c17e80c069332fc6a2ffa9"}fff18b83431fa3a83b9de80c1e413bde
fff18b83431fa3a83b9de80c1e413bde
fff18b83431fa3a83b9de80c1e413bde
 
 
 
 
 
 
 
 
 
 
 
 
SHA1::Result((SHA1 *)&v13, (unsigned int *)v12);// sha1加密的结果
v4 = 0LL; // long long
v5 = 7;
 
do    // 进行循环操作
  {
    v6 = *(_DWORD *)&v12[v4]; // 0X0C
    v7 = &dest_cstr_1[v5];
    while ( 1 )
    {
      v8 = v6 & 0xF; // 0X0C
      v6 >>= 4; // 0X00
      *v7-- = hexDigits[v8]; //
      if ( !(v5 & 7) )
        break;
      --v5;
    }
    *(_DWORD *)&v12[v4] = v6;    // 赋值操作
    v4 += 4LL;
    v5 += 15;
  }
  while ( v4 != 20 );
SHA1::Result((SHA1 *)&v13, (unsigned int *)v12);// sha1加密的结果
v4 = 0LL; // long long
v5 = 7;
 
do    // 进行循环操作
  {
    v6 = *(_DWORD *)&v12[v4]; // 0X0C
    v7 = &dest_cstr_1[v5];
    while ( 1 )
    {
      v8 = v6 & 0xF; // 0X0C
      v6 >>= 4; // 0X00
      *v7-- = hexDigits[v8]; //
      if ( !(v5 & 7) )
        break;
      --v5;
    }
    *(_DWORD *)&v12[v4] = v6;    // 赋值操作
    v4 += 4LL;
    v5 += 15;
  }
  while ( v4 != 20 );
 
 
 
 
 
 
 
do
{
  v10 = char2hexInt(dest_cstr_1[v9]);
  dest_cstr_1[v9] = hexDigits[(signed int)((unsigned __int64)char2hexInt(a211034f8af4e6b[v9]) ^ v10)]; //异或的值为v10
  ++v9;
}
do
{
  v10 = char2hexInt(dest_cstr_1[v9]);
  dest_cstr_1[v9] = hexDigits[(signed int)((unsigned __int64)char2hexInt(a211034f8af4e6b[v9]) ^ v10)]; //异或的值为v10

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2020-11-5 22:06 被初学逆向编辑 ,原因:
收藏
免费 11
支持
分享
最新回复 (19)
雪    币: 17
活跃值: (891)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
初学就这么牛逼,值得回帖鼓励下,可惜看雪小学生太少,没人扣666
2020-11-5 21:22
0
雪    币: 477
活跃值: (1412)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
谢谢分享,ida分析的符号是你加的还是so保留了符号呢
2020-11-5 22:17
0
雪    币: 6573
活跃值: (3873)
能力值: (RANK:200 )
在线值:
发帖
回帖
粉丝
4
谢谢分享! 
2020-11-6 09:57
0
雪    币: 6112
活跃值: (1212)
能力值: (RANK:30 )
在线值:
发帖
回帖
粉丝
5
感谢分享,再接再厉!
2020-11-6 10:43
0
雪    币: 197
活跃值: (939)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
小学生来了,666
2020-11-6 20:51
0
雪    币: 343
活跃值: (533)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
小学生表示很赞666
2020-11-9 20:00
0
雪    币: 337
活跃值: (97)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
666666666666666
2020-11-10 15:32
0
雪    币: 21
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
10
66666666666666666
2020-11-11 17:55
0
雪    币: 212
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
11
LZ 上下样本 学习下
2020-11-12 02:07
0
雪    币: 35
活跃值: (136)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
6666
2020-11-27 17:09
0
雪    币: 4468
活跃值: (1884)
能力值: ( LV12,RANK:209 )
在线值:
发帖
回帖
粉丝
13
一年级刚下课,我来喊666了。
2020-11-27 17:16
0
雪    币: 5
活跃值: (94)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
lz 方便上个样本学习一下吗
2020-12-2 18:42
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
15
求样本
2020-12-2 22:45
0
雪    币: 178
活跃值: (1306)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
厉害了,赞
2020-12-3 09:44
0
雪    币: 230
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
17
lz 方便上个样本学习一下吗
2020-12-4 16:31
0
雪    币: 4
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
18
楼主方便上传个样本学习一下吗!!!!!
2021-1-13 14:13
0
雪    币: 615
活跃值: (1424)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
19
老学生来了,666
2021-1-13 14:19
0
雪    币: 77
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
20
666666666
2022-5-19 11:14
0
游客
登录 | 注册 方可回帖
返回
//