1.抓包,经过多次抓包以后得到sDjcSign每次加密结果都不一样,初步怀疑RSA

某APP的sDjcSign加密插图
2.反编译搜索

这结果简单明了啊,就两个,那第一个remove肯定不是了,那就看看第二个。
3.正式开始逆向之旅

可以看到这个sb2是上面sb.toString得来的,那具体内容不知道是什么一会用frIDA看看,我们先看o.a(sb2, “se35d32s63r7m23m”)这个函数是干什么的。

好消息,这就是一个aes加密,那我们先翻译一下代码,现在的代码不就是这样的么

 

[Java] 纯文本查看 复制代码
1
tVar.a("sDjcSign", o.b(o.a(AES(sb2, "se35d32s63r7m23m"))));

那还有两个参数不知道干什么的对不对,重复刚才的操作,接着看o.a

这个o.a进来以后还调用了一个a,那就继续进这个a

 

 

[Java] 纯文本查看 复制代码
1
tVar.a("sDjcSign", o.b(RSA(AES(sb2, "se35d32s63r7m23m"))));

就剩一个o.b了。最后一个了,继续往下看

这个如果看不懂没关系,我们使用frida hook,正好这个sb2这个值也需要用frida去看一下对吧。

 

[JavaScript] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
function b() {
  Java.perform(function() {
    var i = Java.use("com.tencent.djcity.util.o");
    i.b.overload('[B').implementation = function (arg1) {
      console.log('b.arg1 = ' + ByteString.of(arg1).hex())
      // console.log('arg2 = ' + arg2)
      var ret = this.b(arg1)
      console.log('b.ret = ' + ret)
      return ret
    }
  });
}
function AES() {
  Java.perform(function() {
    var i = Java.use("com.tencent.djcity.util.o");
    i.a.overload('java.lang.String','java.lang.String').implementation = function (arg1,arg2) {
      console.log('AES.arg1 = ' + arg1)
      console.log('AES.arg2 = ' + arg2)
      var ret = this.a(arg1,arg2)
      console.log('AES.ret = ' + ByteString.of(ret).hex())
      return ret
    }
  });
}
function main() {
  AES()
  b()
}
main()
[Java] 纯文本查看 复制代码
1
2
3
4
5
AES.arg1 = 8C571443167953BCC67294D143B97FDA+5d73310d28a1a02929aea12667e64edb0dd356c592261249d47bf75e134efe2a+1709772579610+148
AES.arg2 = se35d32s63r7m23m
AES.ret = 778e7eb1fbad4a871b360bf31dbc5502b3d3c8fcfe60f34b6d7d6f7f1a91fabd04132463e13bc07364588f7a84118593bdb207adefd92823c81d0483319b8b88009c2905303978d2c8fa58480957eb005a73d5cb79a338b9c43fafe0de6c06bde254f1d3ce9d09a723d30c2337be860cb144864c4c69eeb190f1f19b4b6f3196
b.arg1 = 20b7bf49b0c8979e04a41474bc74d5acf6efa672a06fe78ea2e415bb929ea20e25a14316f7706e870664b95ba116b35448628b75c776188546b7291c27e05d7d963375c8a8a22e95ab6833a957e75a0f515f1b012f9e1ae6bf49c815c9b09afa1aabea8bb8df1651c073bec595cb235b6f3c6e0f385f291d242c6e2fd185af8d4336b33c2a5d24f7239a4a5d9587dc53acc686e0a2ede36c1d892d804f65d540474256902eca1fd7847fee066c5e2d70371b4e99015afb3c69b7dddfbeac87cc311654dd71ec220b54b84e76ccd46b08b16c71fce279f32a1d9cdb761a00383a8b17b6bb7b36602ffcc4fb2dd1b705530bdb379c3532d2cb22b6fbd89f0aabfa
b.ret = 20b7bf49b0c8979e04a41474bc74d5acf6efa672a06fe78ea2e415bb929ea20e25a14316f7706e870664b95ba116b35448628b75c776188546b7291c27e05d7d963375c8a8a22e95ab6833a957e75a0f515f1b012f9e1ae6bf49c815c9b09afa1aabea8bb8df1651c073bec595cb235b6f3c6e0f385f291d242c6e2fd185af8d4336b33c2a5d24f7239a4a5d9587dc53acc686e0a2ede36c1d892d804f65d540474256902eca1fd7847fee066c5e2d70371b4e99015afb3c69b7dddfbeac87cc311654dd71ec220b54b84e76ccd46b08b16c71fce279f32a1d9cdb761a00383a8b17b6bb7b36602ffcc4fb2dd1b705530bdb379c3532d2cb22b6fbd89f0aabfa

我们先看AES.arg1这个是什么意思。这个要结合抓包看,当时我研究了很久这个是啥意思
8C571443167953BCC67294D143B97FDA,这个意思是openid,自己无法生成,系统生成给你的
5d73310d28a1a02929aea12667e64edb0dd356c592261249d47bf75e134efe2a,这个是你的sDeviceID,都是固定的。
1709772579610,这个很明显吧,时间戳148,这个嘛,忘记当时怎么找的了,但是测试的时候感觉所有都可以,那干脆就当他是随机数了。
在看b.arg1和b.ret,注意在frida的js文件中写的脚本,arg1是'[B’,ret是string,那这个函数就是byte2string函数。4.复现加密我们从前面知道了这个参数的各个意思,因为他经过了一个读文件进行rsa加密嘛,所以我选择直接用java写。

[Java] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
public class test {
    private static PublicKey RSA() {
        String baseDir = System.getProperty("user.dir");
        byte[] bArr;
        Exception e;
        try {
            InputStream open = new FileInputStream(baseDir + "\\djc_rsa_public_key_new.der");
            try {
                bArr = new byte[open.available()];
                do {
                    try {
                    catch (Exception e2) {
                        e = e2;
                        System.out.println("Got exception while is -> bytearr conversion: " + e);
                        return KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(bArr));
                    }
                while (open.read(bArr) != -1);
            catch (Exception e3) {
                e = e3;
                bArr = null;
            }
            return KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(bArr));
        catch (Exception e4) {
            System.out.println("cuole");
            return null;
        }
    }
    public static byte[] AES(String str, String str2) throws Exception {
        if (str == null) {
            return null;
        }
        Cipher instance = Cipher.getInstance("AES/ECB/PKCS5Padding");
        instance.init(1new SecretKeySpec(str2.getBytes(StandardCharsets.UTF_8), "AES"));
        return instance.doFinal(str.getBytes(StandardCharsets.UTF_8));
    }
    public static byte[] toRSA(byte[] bArr) throws Exception {
        Cipher instance = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        instance.init(1, RSA());
        return instance.doFinal(bArr);
    }
    public static String bytesToHex(byte[] bytes) {
        StringBuilder buf = new StringBuilder(bytes.length * 2);
        for(byte b : bytes) { // 使用String的format方法进行转换
            buf.append(String.format("%02x", Integer.valueOf(b & 0xff)));
        }
        return buf.toString();
    }
    public static void main(){
         String time = String.valueOf(System.currentTimeMillis());
         System.out.println(bytesToHex3(toRSA(AES(openid + "+5d73310d28a1a02929aea12667e64edb0dd356c592261249d47bf75e134efe2a+" + time + "+" new Random().nextInt(1000),"se35d32s63r7m23m"))));
    }
}

 

这时候我们得到了一条加密因为存在RSA了,我们需要发包验证才行,先对比一下长度对不对吧。

 

本站资源来自互联网收集,仅提供信息发布
一旦您浏览本站,即表示您已接受以下条约:
1.使用辅助可能会违反游戏协议,甚至违法,用户有权决定使用,并自行承担风险;
2.本站辅助严禁用于任何形式的商业用途,若被恶意贩卖,利益与本站无关;
3.本站为非营利性网站,但为了分担服务器等运营费用,收费均为赞助,没有任何利益收益。
死神科技 » 某APP的sDjcSign加密

死神科技,因为专业,所以领先。

网站首页 24小时自动发卡
在线客服
24小时在线客服
阿里云自动发卡,购卡进群售后
12:01
您好,有任何疑问请与我们联系!

选择聊天工具: