app:4.74.5
接口:https://app.dewu.com/sns-itr/v1/reply/content-reply-list
解析流程 该app不走系统代理,所以需要sockes转发,而且有frida反调试,需要删除libmsaoaidsec.so文件
正常抓包,找到接口,发现请求参数有个newSign 和请求头中有个X-Auth-Token需要获取到
直接搜索newSign关键字,发现它进入得是一个拦截器,最终是m37139c方法对newSign参数做了处理,我们看一下m37139c方法
看上去好像是一个aes加密,传入了一个map参数,我们可以hook一下,传入了哪些参数
传入得字典也是请求头中得其它参数,我们在回过头来看一下m37139c方法做了哪些处理,传入得map后又添加了下面几个参数,然后字符串拼接,直接hook encode方法就可以得到拼接后的字符串,其它的几个参数都可以固定,但是uuid需要我们去获取
1 2 3 4 5 6 7 8 v=4.84.0 timestamp=1660649735904 uuid=0d9686a78e2aa975 -> ? platform=android loginToken= 最后得参数,直接hook encode方法就可以得到 anchorReplyId0contentId85347120contentType0lastIdlimit20loginTokenplatformandroidsourcetimestamp1660649735904uuid0d9686a78e2aa975v4.84.0
发现只有获取,而没有生成uuid,我们可以先不管,先搜索X-Auth-Token
发现在这里出现了uuid的生成,我们进去看一下,发现uuid可能是一个设备id,这个id我们可以直接伪造
1 2 3 4 5 6 def create_android_id (): data_list = [] for i in range (1 , 9 ): part = "" .join(random.sample("0123456789ABCDEF" , 2 )) data_list.append(part) return "" .join(data_list).lower()
我们再看一下encode方法,发现最终会调用一个叫encodeByte的native方法,并且传入一个字节数组,这个字节数组就是我们上面讲到的sb字符数组转成的字节数组,直接hook这个方法
找到了最终的加密位置,但由于是在native层进行加密,我们还需要获取到对应的so文件,在jadx中也可以看到对应的so文件叫做JNIEncrypt
我们用ida打开对应的so文件,去寻找encode方法传入的第一参数,经过确认,第29行的 AES_128_ECB_PKCS5Padding_Encrypt应该就是传入的对应方法,也就是对应的AES加密,那我们直接用frida hook native层的加密
想要hook native层的方法,需要指定对应so文件和对应的方法,并且需要设置对应的进入和出去方法,发现传入的第一个参数,就是我们上面拼接的参数,第二个参数始终固定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 Java .perform (function ( ) { var addr_func = Module .findExportByName ("libJNIEncrypt.so" , "AES_128_ECB_PKCS5Padding_Encrypt" ); Interceptor .attach (addr_func, { onEnter : function (args ){ console .log ("-------------执行函数-------------" ); console .log ("-------------参数 1-------------" ); console .log (args[0 ].readUtf8String ()) console .log ("-------------参数 2-------------" ); console .log (args[1 ].readUtf8String ()); }, onLeave : function (retValue ){ console .log ("-------------返回-------------" ); console .log (retValue.readUtf8String ()); } }) });
最后剩下一个X-Auth-Token,在我们抓包的时候,可以去看一个包,这个包的响应头就是我们要的X-Auth-Token,而newSign我们已经获取到了,所以我们可以直接获取到newSign后,拼接请求,获取X-Auth-Token,在拼接请求,获取我们想要的评论
直接上代码
1 2 3 4 5 6 7 8 9 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 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 import timeimport requestsimport hashlibfrom Crypto.Cipher import AESfrom Crypto.Util.Padding import padfrom urllib.parse import quote_plusimport base64import jsonimport randomdef create_android_id (): data_list = [] for i in range (1 , 9 ): part = "" .join(random.sample("0123456789ABCDEF" , 2 )) data_list.append(part) return "" .join(data_list).lower()def md5 (data_bytes ): hash_object = hashlib.md5() hash_object.update(data_bytes) return hash_object.hexdigest()def aes_encrypt (data_string ): key = "d245a0ba8d678a61" aes = AES.new( key=key.encode('utf-8' ), mode=AES.MODE_ECB, ) raw = pad(data_string.encode('utf-8' ), 16 ) return aes.encrypt(raw) uid = create_android_id() ctime = str (int (time.time() * 1000 )) param_dict = {"loginToken" : "" , "platform" : "android" , "timestamp" : ctime, "uuid" : uid, "v" : "5.0.6" } ordered_string = "" .join(["{}{}" .format (key, param_dict[key]) for key in sorted (param_dict.keys())]) aes_string = aes_encrypt(ordered_string) aes_string = base64.encodebytes(aes_string) aes_string = aes_string.replace(b"\n" , b"" ) sign = md5(aes_string) param_dict['newSign' ] = sign res = requests.post( url="https://app.dewu.com/api/v1/app/user_core/users/getVisitorUserId" , headers={ "duuuid" : uid, "duimei" : "" , "duplatform" : "android" , "appId" : "duapp" , "duchannel" : "pp" , "humeChannel" : "" , "duv" : "5.0.6" , "duloginToken" : "" , "dudeviceTrait" : "MI+6+Plus" , "dudeviceBrand" : "Xiaomi" , "timestamp" : ctime, "shumeiid" : "20210807163758afabf6d66401eb2e4f234dbe68af5705014c79067d50b114" , "oaid" : "" , "User-Agent" : "duapp/5.0.6(android;6.0.1)" , "X-Auth-Token" : "" , "isRoot" : "0" , "emu" : "1" , "isProxy" : "0" , "Content-Type" : "application/json; charset=utf-8" }, json=param_dict, ) x_auth_token = res.headers['X-Auth-Token' ] reply_param_dict = { "contentId" : "91820099" , "contentType" : "0" , "anchorReplyId" : "0" , "lastId" : "" , "source" : "" , "limit" : "20" , }import copy new_dict = copy.deepcopy(reply_param_dict) new_dict.update( {"loginToken" : "" , "platform" : "android" , "timestamp" : str (int (time.time() * 1000 )), "uuid" : uid, "v" : "5.0.6" }) ordered_string = "" .join(["{}{}" .format (key, new_dict[key]) for key in sorted (new_dict.keys())]) aes_string = aes_encrypt(ordered_string) aes_string = base64.encodebytes(aes_string) aes_string = aes_string.replace(b"\n" , b"" ) sign_string = md5(aes_string) reply_param_dict['newSign' ] = sign_string res = requests.get( url="https://app.dewu.com/sns-itr/v1/reply/content-reply-list" , params=reply_param_dict, headers={ "X-Auth-Token" : x_auth_token, "User-Agent" : "duapp/5.0.6(android;10)" }, )print (res.text)
返回结果:成功拿到数据