接着上次的写,这次跟一下响应数据的解密
响应看过这么多广告sdk,他们的流量数据,基本都是放在 JSonObject 中,所以直接从 JSonObject 中下手hook就稳稳的
其调用栈为如下:
根据上面的调用栈对 com.bytedance.sdk.openadsdk.core.q 的 g 函数 hook
其参数如下:
发现该函数的参数还是密文,说明密文就是在 g 函数内部进行解密的,其解密函数就是下面的 b 函数:
在 b 函数中先对密文进行切割,然后将切割的字符串传入 a.b 函数中
其中参数三还被函数a处理过
由上面可知 a.b 函数的三个参数依次为:
参数一为:密文的第50位到结尾
参数二为:密文第34位到49位
参数三为:密文第2位到33位,前16位与后16位对换
a.b 函数为如下:
函数具体解密逻辑为:
1 对参数一先用base64解密
2 由参数三生成密钥
3 设置解密模式为 "AES/CBC/PKCS5Padding"
4 初始化解密参数,写入参数三生成的密钥,并由参数二生成初始化向量
5 对参数一base64解密后的数据进行解密
到这里穿山甲流量的解密就完成了,直接copy代码写了一个解密的jar包
CSJDcrypt.java
package com.yooha; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.io.FileReader; import java.io.IOException; public class CSJDcrypt { public static void main(String[] args) throws IOException { String s = readfile(args[0]); System.out.println(decrypt(s)); } public static String readfile(String filename) throws IOException { FileReader fileReader=new FileReader(filename); int length=0; char[] cfile = new char[0x1000 * 100]; int index = 0; while((length=fileReader.read())!=-1) { cfile[index++] = (char)length; } char[] newstr = new char[index + 1]; for(int i = 0; i < index; i++){ newstr[i] = cfile[i]; } newstr[index] = 0; fileReader.close(); return new String(newstr); } public static String a(String str, int i2) { if (str == null || str.length() != i2) { return null; } int i3 = i2 / 2; return str.substring(i3, i2) + str.substring(0, i3); } public static String decrypt(String str) { if (isEmpty(str) || str.length() < 49) { return str; } String a = a(str.substring(1, 33), 32); String substring = str.substring(33, 49); return (substring == null || a == null) ? str: _decrypt(str.substring(49), substring, a); } public static String _decrypt(String str, String str2, String str3) { if (isEmpty(str)) { return null; } try { byte[] decode = Mybase64.decode(str.getBytes()); System.out.println("str3 = " + str3); SecretKeySpec secretKeySpec = new SecretKeySpec(str3.getBytes(), "AES"); System.out.println("str3 = " + secretKeySpec.getEncoded()); Cipher instance = Cipher.getInstance("AES/CBC/PKCS5Padding"); instance.init(2, secretKeySpec, new IvParameterSpec(str2.getBytes())); String ret = new String(instance.doFinal(decode), "utf-8"); return ret; } catch (Exception e2) { System.out.println("_decrypt -> error = " + e2.getMessage()); return null; } } public static boolean isEmpty(String str){ if (str.length() == 0){ return true; } return false; } }
Mybase64.java
这个是网上找的一个base64,你们自己找个能跑起来就行
后来想想,之前有个沙箱当时就是用python调用jar包解密,搞的有点麻烦,沙箱越轻越好,还是直接用python解算了,然后了解了一下Crypto,挺好用的,写了个python的解密脚本
# -*- coding: utf-8 -*- import base64 from Crypto.Cipher import AES class AES_CIPHER(object): #解密函数 ("AES/CBC/PKCS5Padding"); @classmethod def _decrypt(cls, str1, str2, str3): cryptor = AES.new(str3.encode("utf8"), AES.MODE_CBC, str2.encode("utf8")) plain_text = cryptor.decrypt(base64.b64decode(str1)) unpad = lambda s: s[0:-ord(s[-1:])] return unpad(plain_text) @classmethod def decrypt(cls, info): if len(info) < 49: return info else: return cls._decrypt(info[49:], info[33:49], info[1:33][16:32] + info[1:33][0:16]).decode('utf-8') if __name__ == '__main__': with open("flow.txt", "r", encoding='utf-8') as out: info = out.readline() print(AES_CIPHER.decrypt(info))
没错,用python写代码就是这么少。下面是解密内容
后面我写了一个广告sdk自渲染广告的监控工具,链接:https://github.com/YoooHaaa/renderAd
有兴趣可以去看看,工具拿来把js脚本改改,就能复用到其他业务上
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)