分析工具 雷电模拟器9.0.77 JADX Reqable frida
分析思路 参数加密分析
使用Reqable对登陆抓包看请求参数发现有sign值,那么想要对app登陆进行渗透测试肯定是需要sign值的,分析一下sign值是怎么得来的。
jadx反编译app进行代码审计: 快速定位到登陆接口发包函数技巧:直接在jadx搜索该请求的后缀
类似于这样的,这样就能快速定位到关键函数了
搜到了有这样一个函数getRequestMethod 返回了这个接口,跟进去分析一下
直接查看一下这个函数的交叉引用,
就4个地方调用了该函数,根据经验和运气,直接看第二个函数
太棒了孩子们,一下子就看到了sign=这么明显的特征,那么d2就是sign了,分析一下d2怎么来的
调用了d函数,传递的参数也是通过其他函数得来的,但是不重要,直接分析d函数看看传进来的参数是什么就好了。
第一个参数使用了map,应该是请求参数列表了,第二个参数是key,看到最后的key=和一个sb的数据类型,猜测这个函数是对请求参数最后加一个元素key=????后再调用e函数对请求参数进行加密,这里的操作可以称为对原始字符串加一个盐值,盐值是特殊的,这样别人想直接对请求参数进行加密爆破的话就永远拿不到一样的值。
使用frida去hook这个函数输出一下参数拿到key
1 2 3 4 5 6 7 8 let b = Java .use ("com...b" ); b["d" ].implementation = function (params, appkey ) { console .log ("*********************com...b************************" ); console .log (`b.d is called: params=${params} , appkey=${appkey} ` ); let result = this ["d" ](params, appkey); console .log (`b.d result=${result} ` ); return result; };
太棒了,直接拿到key和加密的对象。
再分析e函数看看是怎么对参数就行加密的
其实就是md5加密,对请求参数列表的字节形式md5加密,加密完成之后在进行字符的替换,相等于是有了两层加密。
使用frida去hook e这个函数获取到返回值,
1 2 3 4 5 6 7 let b1 = Java .use ("com...b" ); b1["e" ].implementation = function (buffer ) { console .log (`b.e is called: buffer=${buffer} ` ); let result = this ["e" ](buffer); console .log (`b.e result=${result} ` ); return result; };
拿到加密的结果,与抓包结果对比发现是一致的。
使用Java模拟的话就把这两个函数给扣下来就行了
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 public static String d (TreeMap<String, String> params, String appkey) { StringBuilder sb = new StringBuilder (); for (Map.Entry<String, String> entry : params.entrySet()) { sb.append(entry.getKey()); sb.append("=" ); sb.append(entry.getValue()); sb.append("&" ); } sb.append("key=" ); sb.append(appkey); return e(sb.toString().getBytes()).toUpperCase(); } public static String e (byte [] buffer) { char [] cArr = {'0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' , 'a' , 'b' , 'c' , 'd' , 'e' , 'f' }; try { MessageDigest messageDigest = MessageDigest.getInstance("MD5" ); messageDigest.update(buffer); byte [] digest = messageDigest.digest(); char [] cArr2 = new char [digest.length * 2 ]; int i2 = 0 ; for (byte b2 : digest) { int i3 = i2 + 1 ; cArr2[i2] = cArr[(b2 >>> 4 ) & 15 ]; i2 = i3 + 1 ; cArr2[i3] = cArr[b2 & 15 ]; } return new String (cArr2); } catch (Exception unused) { return "unknown" ; } }
创建一个TreeMap 和key:mibook_123456 传递给d函数就好了。
会员&用户名分析 尝试搜索关键代码:isVip
当我搜索完毕之后,鼠标不听使唤使劲往这个函数上方,无奈我只能选这个函数了进行分析了(经验和运气)
直接使用frida使得这个函数返回1
1 2 3 4 5 6 7 8 let MartianRPAccount = Java.use("com....MartianRPAccount" ); MartianRPAccount["getIsVip" ].implementation = function () { console.log(`MartianRPAccount.getIsVip is called`); let result = this ["getIsVip" ](); result = 1 ; console.log(`MartianRPAccount.getIsVip result=${result}`); return result; };
拿到会员了,嘻嘻嘻。
但是我发现用户名竟然是游客123123,这使得我浑身刺挠,我必须要在此App上留下我的名字,借此对用户名进行分析,搜索关键字:游客
感觉就是这个了,后面跟着UID参数
跟进去分析这个函数
分析e这个函数
分析b这个函数
很明显,用户类了,进去看看有没有与用户名相关的函数
找到了,太棒了,我直接使用frida让他返回我的名字,
现在他已经是我的形状了。