本文目的:将手机上的某音缓存数据提取成我们常用的json格式ck。
某音将部分数据缓存至本地,其中包含了ck(device信息、token、app版本信息等),可以通过安卓程序将数据提取出来用于平时测试。因为该数据是缓存在应用的独立数据目录 安卓默认是不允许app互相访问独立数据,这里需要手机root后才可以提取。
缓存文件目录:/data/data/com.ss.android.ugc.aweme/shared_prefs
我们主要提取这五个文件 缓存文件包含数据
ttnetCookieStore.xml cookie,涉及敏感数据,数据需解码(下方代码里的decode方法)
token_shared_preference.xml x-tt-token
wschannel_multi_process_config.xml 登录的设备信息,包含device_id install_id 应用版本 手机版本等查询通用参数。
applog_stats.xml mac_addr fingerprint_codes等
LoginSharePreferences.xml 最后登录的账号信息
ttnetCookieStore.xml 部分内容如下:
aced000573720031636f6d2e6279746564616e63652e6672616d65776f726b732e626173656c69622e6e6574776f726b2e687474702e622e6858765a0a7f563d0c0300014a00016378707400076f64696e5f74747400806162663762643132383666343137303631623636346364333664313662386635613232303532633739643464346662333563643361646561646337323037373135336335336532323036623437393530643836393566363162643764656630346337336636656466646633653336356530626235613666383164343433633163707074000b2e736e7373646b2e636f6d77080000000005265c007400012f70770f000000010000010000017a6585797578
提取到的内容部分需要解密。
解密python代码:
def decode_cookie(str):
length = len(str)
newData = ""
i = 0
while(i
解密java代码:
/**
* cookie解密
* @param str cookie密文
* @return
*/
public static String decodeCookie(String str){
String cookieStr = "";
int i = 0;
while(i < str.length()){
char c1 = str.charAt(i);
int num1 = Integer.parseInt(String.valueOf(c1),16);
char c2 = str.charAt(i+1);
int num2 = Integer.parseInt(String.valueOf(c2),16);
int newChar = (num1<<4) + num2;
cookieStr += (char) Integer.parseInt(String.valueOf(newChar));
i=i + 2;
}
return cookieStr;
}
解密结果:
’ sr 1com.bytedance.frameworks.baselib.network.http.b.hXvZ
V= J cxpt odin_ttt abf7bd1286f417061b664cd36d16b8f5a22052c79d4d4fb35cd3adeadc72077153c53e2206b47950d8695f61bd7def04c73f6edfdf3e365e0bb5a6f81d443c1cppt .snssdk.com &\ t /pw zeyux
但是我们发现他还是有些其它地方乱码了,但是蓝色方框是我们的结果,其实这是因为他解密之后是一个protobuf格式,我们只需要再次分割拿出来就可以了。具体完整代码都是读取文件和正则匹配或者分割下就好了,关键是ck这里加密,主要给出解密代码.
wschannel_multi_process_config.xml 部分内容如下:
其中ws_apps包含json数据,但是需要解析
[{"channel_id":1239108,"app_id":1128,"device_id":"61919431820","install_id":"3149472127268080","urls":["wss:\/\/frontier-aweme.snssdk.com\/ws\/v2"],"app_version":160501,"platform":0,"fpid":9,"app_kay":"e1bd35ec9db7b8d846de66ed140b1ad9","extra":"ws_connect_protocol=0&os_api=25&device_type=MI%206&manifest_version_code=160502&dpi=480&is_guest_mode=0&is_background=1&app_name=aweme&version_name=16.5.1&ts=1624900639&sid=&cpu_support64=true&ttnet_ignore_offline=1&app_type=normal&ac=wifi&appTheme=dark&channel=xiaomi_1128_64&update_version_code=16519900&host_abi=arm64-v8a&_rticket=1624900639691&device_platform=android&iid=3149472127268080&ttnet_heartbeat_interval=30&ne=1&version_code=160501&cdid=903a39a1-841c-4a7c-89d3-9337ec85eec9&openudid=f4135260f97231ac&device_id=61919431820&resolution=1080*1920&ping-interval=30&language=zh&device_brand=Xiaomi&os_version=7.1.1&aid=1128&minor_status=0"}]
java中通过方法可以解析
String str = "[{"channel_id":1239108,"app_id":1128,"device_id":"61919431820","install_id":"3149472127268080","urls":["wss:\\/\\/frontier-aweme.snssdk.com\\/ws\\/v2"],"app_version":160501,"platform":0,"fpid":9,"app_kay":"e1bd35ec9db7b8d846de66ed140b1ad9","extra":"ws_connect_protocol=0&os_api=25&device_type=MI%206&manifest_version_code=160502&dpi=480&is_guest_mode=0&is_background=1&app_name=aweme&version_name=16.5.1&ts=1624900639&sid=&cpu_support64=true&ttnet_ignore_offline=1&app_type=normal&ac=wifi&appTheme=dark&channel=xiaomi_1128_64&update_version_code=16519900&host_abi=arm64-v8a&_rticket=1624900639691&device_platform=android&iid=3149472127268080&ttnet_heartbeat_interval=30&ne=1&version_code=160501&cdid=903a39a1-841c-4a7c-89d3-9337ec85eec9&openudid=f4135260f97231ac&device_id=61919431820&resolution=1080*1920&ping-interval=30&language=zh&device_brand=Xiaomi&os_version=7.1.1&aid=1128&minor_status=0"}]";
String json = org.apache.commons.lang.StringEscapeUtils.unescapeHtml(str);
最后拿到参数数据:
[{"channel_id":1239108,"app_id":1128,"device_id":"61919431820","install_id":"3149472127268080","urls":["wss:\/\/frontier-aweme.snssdk.com\/ws\/v2"],"app_version":160501,"platform":0,"fpid":9,"app_kay":"e1bd35ec9db7b8d846de66ed140b1ad9","extra":"ws_connect_protocol=0&os_api=25&device_type=MI%206&manifest_version_code=160502&dpi=480&is_guest_mode=0&is_background=1&app_name=aweme&version_name=16.5.1&ts=1624900639&sid=&cpu_support64=true&ttnet_ignore_offline=1&app_type=normal&ac=wifi&appTheme=dark&channel=xiaomi_1128_64&update_version_code=16519900&host_abi=arm64-v8a&_rticket=1624900639691&device_platform=android&iid=3149472127268080&ttnet_heartbeat_interval=30&ne=1&version_code=160501&cdid=903a39a1-841c-4a7c-89d3-9337ec85eec9&openudid=f4135260f97231ac&device_id=61919431820&resolution=1080*1920&ping-interval=30&language=zh&device_brand=Xiaomi&os_version=7.1.1&aid=1128&minor_status=0"}]
或者使用完整的解析代码:
/**
* 解析某音xml参数
* @param douyinParamXml
* @return
* @throws DocumentException
*/
public static String parseParamsXml(String douyinParamXml) throws DocumentException {
//1.创建Reader对象
SAXReader reader = new SAXReader();
//2.加载xml
//读取XML文件,获得document对象
//Document document = reader.read(new File("C:\\Users\\Administrator\\Desktop\\wschannel_multi_process_config.xml"));
//解析XML形式的文本,得到document对象
Document document = DocumentHelper.parseText(douyinParamXml);
//3.获取根节点
Element rootElement = document.getRootElement();
Iterator iterator = rootElement.elementIterator();
while (iterator.hasNext()){
Element stu = (Element) iterator.next();
List attributes = stu.attributes();
for (Attribute attribute : attributes) {
if ("ws_apps".equalsIgnoreCase(attribute.getValue())){
String json = stu.getStringValue();
return json;
}
}
}
return null;
}