html编写的app怎么逆向(保姆级)

556 阅读5分钟

学习的道路上渐行渐远,发现还没走到起跑线。

本篇文章仅供交流学习,侵权删(满满的求生欲)

本次app样本:57qi5rKz5YWs56S+MC4wLjE0

一.老连招 抓包+跟踪堆栈

抓包还是postern转发一下,就能抓到了。

跟踪堆栈到这里

image.png

图中红线方法的第二个参数有我们要的提交请求的加密参数,但是当我右键查找用例的时候一无所获,好吧,还是上frida,注意这个方法是在一个内部类里面,frida hook的时候要在这个类后面加上$a,但是也没hook到。邪门啊,这里就感觉有点不对劲了。

二.发现奇怪的地方

我看了一下这个内部类a继承的是APICallHandler,那我肯定是想点进去看看有没有有用的信息,毕竟已经走到了死胡同,但是发现点不进去,有古怪啊,我就看了一下最上面导包

image.png

apicloud,因为总听大佬们逆向小程序的时候说云函数,这里我第一时间以为这个也是云函数,毕竟有个cloud,逆向的时候经常会遇到不认识的包,这个时候就不要嫌麻烦,多去网上搜一搜

image.png

很明显就是有这么一个方便开发app的api存在啊,说明是方向找对了。

最终发现app是由html开发的,所以参数的生成以及方法的调用应该都是在js代码中,那么html开发的app有什么特征呢,如图,jadx反编译app(或者改app后缀为.zip,然后直接解压app也是可以的)

image.png

三.开始真正的html app逆向

看一下js文件,发现都是加密的

image.png

于是在这篇文章下面的评论中找到了一个项目

文章:bbs.pediy.com/thread-2494…

项目:github.com/newdive/uzm…

文章中是根据hook来获取解密后的js文件,这个项目可以直接获得所有解密后的文件,原理是libsec.so中获取静态密钥,rc4解密js等加密文件。

最终获得了解密后的js文件

image.png

但是现在又有个问题了,这一大堆js,又没办法hook,怎么逆向呢

image.png

有两个办法,第一个是使用谷歌浏览器的Webview 动态调试,相当于在网页上展示app,那么就可以用浏览器的调试工具去逆向js了,不过这个我初步了解,有几个小问题,有想了解可以看这篇文章,然后发散思考

www.cnblogs.com/wmhuang/p/7…

我这里使用第二种方法,硬看,有动态调试我不用,哎,就是玩

首先我抓到的包加密参数名字是这个

image.png

我是个老实人,他既然起名有aes,那我就信他,刚好js中也有个aes,ok,放到浏览器中看看

image.png

新建一个代码段,1格式化一下,2运行到当前环境

没有报错,很明显他定义了一个变量CryptoJS接受了什么东西,我们打印看看

image.png

就是定义了一些加密的方法,相当于在python中定义了一个加密通用类,那么其他地方要使用的话,肯定要用到CryptoJS,所以我在其他的js文件中中开始搜索有没有 CryptoJS,最终搜了快10个js文件的时候,让我给搜到了。

image.png

并且看到了这个方法,好家伙,密钥和IV都有了

看看这个方法在哪里有调用,入参是什么我们要知道,要不然怎么模拟请求啊。

然后发现入参第一个是不会变的,类似于deviceid,第二个是当前10位时间戳 + 本地缓存中的一个时间戳

image.png

不知道有没有用上缓存,希望没有吧,拿上其中一个抓到的加密参数去解密网站试试

www.mklab.cn/utils/aes

解密完就是我们看js中的did+当前10位时间戳,只不过后面有不可见字符

image.png

我们先不管后面不可见字符,直接用前面正常的字符,试试用它的js去使用加密看看能生成什么(涉及did,前几位隐掉了)

encodeURIComponent(CryptoJS.AES.encrypt("*******8091d066d6d3432641035311655777883",CryptoJS.enc.Latin1.parse('e8d5a8b98ea4947e3ba649a0bebd32d0'),{iv: CryptoJS.enc.Latin1.parse('faf0b82d67da14e9'),mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.ZeroPadding }))

控制台输出,但是报错了

image.png

然后想起了看静态资源的时候有一个pad-zeropadding.js的文件,他这个里也用到了CryptoJS.pad.ZeroPadding,那看来是缺少了这个,我们把这个js文件也运行到当前环境,然后就不报错了,结果一毛一样,那看来是没有加上什么缓存中的时间戳的

image.png

那么我们使用python试试呢。

from Crypto.Cipher import AES
import base64

def add_to_16(text):
    if len(text.encode('utf-8')) % 16:
        add = 16 - (len(text.encode('utf-8')) % 16)
    else:
        add = 0
    text = text + ('\0' * add)
    return text.encode('utf-8')

def encrypt(text):
    key = 'e8d5a8b98ea4947e3ba649a0bebd32d0'.encode('utf-8')
    mode = AES.MODE_CBC
    iv = b'faf0b82d67da14e9'
    text = add_to_16(text)
    cryptos = AES.new(key, mode, iv)
    cipher_text = cryptos.encrypt(text)
    return base64.b64encode(cipher_text).decode()

print(encrypt("*******066d6d3432641035311655777883"))

image.png

发现结果也一样(网站的问题,焯!)

ok,逆向成功!

================================分割线================================

后记

当我全部参数逆向结束,发起请求的时候,却还是不成功,才想起它对加密后的参数有一个操作,就是将+、/等字符进行了url转码,在python中可以使用quote进行转码

from urllib.parse import quote

print(quote("D+nVPSWxR")

然后请求到的结果

image.png

有Unicode编码

直接

response.text.encode('utf-8').decode('unicode_escape')

就能看到正常的文本了,这次是真的结束了,不容易啊,逆向+文章又是一下午过去了。