PS:这是一个系列,坐等我缓缓填坑。

PS:不太会间接能跑的代码,抛砖引玉。

PS:那些我也不太纯熟的就不搞了,包含(破滑块、验证码..)

PS: 反编译搞Apk会有很长的几个文章,稍后缓缓更。

最近,和某XX单位的网站gang上了。

他们家的网页只容许在微信客户端关上,抓包就跟蛋疼了。

不过,手上有Root后的Google Nexus5X,也有 whistle 跨平台抓包工具,

这个倒没太折腾,抓包工具证书往手机零碎根证书一扔,完事。

安卓7.0及以上用户证书导入的问题 - entr0py - 博客园


抓到了包,上面蛋疼的事件开始了。


前言: body 加密
嗯?申请Body是这一串货色?

嗯?时隔三年,神奇海螺又呈现了?

// json
{

"encryKey": "14a625eb2ec957f9b53412b01de37044e7e2aa6b4b911111c75091cba2a0315b","data": "44bc0dab8db8017603586f40554742d14a0c23dd009e35cae5b5ac87dbf7962a311fae30070763d2b48b564d72191fd07a881ebcccfb7c0fdd33e4067bc5119cee5e2fa5eaac10da995c86c8a092dcc3","sign": "cc3f924bbb6d57a15bd3e130230f51e55a04fa9e459d177440fbd10bce4b02d0","timestamp": 1627224237000

}
很显著,每个单词咱们都晓得,每个字母和数值咱们也懂。

然而....

除了timestamp咱们能够生成,其余的显著是加密后数据和签名。

一点都不高能的预警
先说一下思路:

捞出外围JS文件
读懂加密过程,捞出要害参数
用其余语言实现波及到的加密函数
比照加密后果是否统一,尝试去伪造申请
捞JS

首先这货的微信浏览器的,所以没方法应用浏览器开发者工具。

不过,抓包下面不是搞掂了么?间接从抓包后果看HTML就完事。

乖乖一个个申请看,找到第一个返回HTML的响应体。

于是,找到了这个...

哦, 看到了....

<script src="/umi.a029b1fd.js"></script>

看到这货,本宝宝小心脏有点乱跳了。

拜访一看。

害,看起来没的那么简略啊,显著这货是被webpack打包后的JS文件。

先下载回来再说...

umi.a029b1fd.js 下载到本地,一看1.5M。

关上一看,毫无疑问没有格式化...

得嘞,大JS文件格式化,先关上我的Ubuntu机器再说。

哦,VS Code format崩;加大内存,持续崩。

搜了一波,找到了神器 Online JavaScript beautifier

文件扔上去,再下载下来...

完事。

毫无疑问,这就是webpack打包后的货色了。

没得事,全局搜一波下面的参数。

完满,看到这个,是不是答案曾经进去了。

看看,每个参数怎么算的都通知我了,还能做撒?还须要做撒?

于是,我午睡去了。

........

其实,最头疼的货色就在这里了。

这时候,很多人会说,上AST 还原JS嘛。

AST形象语法树--最根底的javascript重点常识,99%的人基本不理解 - SegmentFault 思否

啧啧啧。

情理是这个情理,不过还有其余的思路吗?

间接写个index.html 引入这个JS也成的啊。

<html><body>    <h1>test</h1></body><script src="./app.js"></script></html>

开始解JS

 var O = Date.parse(new Date), Y = Object(h["e"])(!1, 16), j = Object(h["a"])(JSON.stringify({ data: b, timestamp: O                        }), Y), P = Object(h["f"])(j, Y); T = { encryKey: Object(h["a"])(Y, h["b"]), data: j, sign: P, timestamp: O}

在代码外面看到了一堆这种 h["a"] h["e"],而后跟着参数(j, Y)。

咱们显著晓得,这是JavaScript的一个函数调用,h看起来是一个map或者是对象,

这里是在调用它的a办法,传入了(j, Y)

在这里,咱们最想晓得的就是h["a"]的定义是什么样的,

因为晓得定义实现,也就能还原残缺代码逻辑。

跟一点代码(VS Code跳转定义性能),咱们能看到h是什么?

h = n("jNxd"),

看到这里其实是很头疼的,n是个什么玩意咱们齐全无从得悉。

不过这里也能失去点信息,各种各样的函数或者对象都是绑定在”n“上的,

咱们只有拿到n,咱们须要的h,h[a], h[b] 都晓得是什么了。

怎么拿到n呢? 情谊提醒,善用debugger。

开始寻找n
刚刚咱们曾经残缺把app.js(umi.a029b1fd.js格式化之后的文档)导入咱们的index.html

用浏览器关上看看页面。

页面没什么问题,咱们尝试在app.js下面加点debugger吧。

加在哪呢?(目标只有一个,能获取的到n)

....h左近后面能够吗?

浏览器控制台关上,刷新页面,切换到Console页面。

试试这里能不能有n对象。

咦,看起来有戏。

试试 h = n("jNxd")

很好,很好,看起来这里是OK的,

h["a"]也是一个函数,合乎咱们下面看到的。

点击一下下面h["a"]输入的内容,能够跳转到函数定义。

于是,咱们来到了重头戏。

       s = (e, t) => {            var n = i.a.enc.Utf8.parse(t),                r = i.a.enc.Utf8.parse(t),                o = i.a.enc.Utf8.parse(e),                a = i.a.AES.encrypt(o, n, {                    iv: r,                    mode: i.a.mode.CBC,                    padding: i.a.pad.Pkcs7                });            return i.a.enc.Hex.stringify(a.ciphertext)        },        u = (e, t) => {            var n = i.a.enc.Utf8.parse(t),                r = i.a.enc.Utf8.parse(t),                o = i.a.enc.Hex.parse(e),                a = i.a.enc.Base64.stringify(o),                s = i.a.AES.decrypt(a, n, {                    iv: r,                    mode: i.a.mode.CBC,                    padding: i.a.pad.Pkcs7                });            return s.toString(i.a.enc.Utf8).toString()        },        c = (e, t) => i.a.enc.Hex.stringify(i.a.HmacSHA256(e, t)),        l = (e, t, n) => {            var r = "",                i = t,                o = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "-", ".", "~", "!", "@", "#", "$", "%", "^", "*", "(", ")", "_", ":", "<", ">", "?"];            e && (i = Math.round(Math.random() * (n - t)) + t);            for (var a = 0; a < i; a += 1) {                var s = Math.round(Math.random() * (o.length - 1));                r += o[s]            }            return r        }

看看,代码都进去了,还须要撒?

明天的教程完结,早点睡....


微微一笑,如同没那么简略。

宝哥微微一笑,发现事件没那么简略。

已知,下面这一堆货色,

要不是 i.a.AES,要不是 HmacSHA256

没什么花色。

那么最大的问题就是,

这个加密过程是怎么搞的。

加密向量是什么?秘钥在哪?

SHA256用的是什么参数?参加加密的数据是怎么拼接的?

PS:还在写....

重头戏上场
回到下面的代码

if (p["d"] && "get" !== u.toLowerCase() && !g) {

                var O = Date.parse(new Date),                    Y = Object(h["e"])(!1, 16),                    j = Object(h["a"])(JSON.stringify({                        data: b,                        timestamp: O                    }), Y),                    P = Object(h["f"])(j, Y);                T = {                    encryKey: Object(h["a"])(Y, h["b"]),                    data: j,                    sign: P,                    timestamp: O                }

}
这里能够看出每个变量是怎么来的。

encryKey = Object(h["a"])(Y, h["b"]) // 调用了a办法

O= Date.parse(newDate) // 生成了工夫戳

Y=Object(h["e"])(!1,16) // 调用了e办法

P=Object(h["f"])(j,Y) 调用了f办法

于是咱们执行一下看看。

Y看起来是个随机字符串,j,p看起来都是字母+数字组合起来的字符串。

别离到定义出看看是撒。

h["e"]

l = (e, t, n) => {

            var r = "",                i = t,                o = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "-", ".", "~", "!", "@", "#", "$", "%", "^", "*", "(", ")", "_", ":", "<", ">", "?"];            e && (i = Math.round(Math.random() * (n - t)) + t);            for (var a = 0; a < i; a += 1) {                var s = Math.round(Math.random() * (o.length - 1));                r += o[s]            }            return r        }

哦,生成了随机字符串。

h["a"]

        // n("jNxd")["a"] encryKey        s = (e, t) => {            var n = i.a.enc.Utf8.parse(t),                r = i.a.enc.Utf8.parse(t),                o = i.a.enc.Utf8.parse(e),                a = i.a.AES.encrypt(o, n, {                    iv: r,                    mode: i.a.mode.CBC,                    padding: i.a.pad.Pkcs7                });            return i.a.enc.Hex.stringify(a.ciphertext)        },

哦, AES.encrypt 加密,应用的是CBC/Pkcs7对齐

h["f"] HmacSHA256

(e, t) => i.a.enc.Hex.stringify(i.a.HmacSHA256(e, t))
h["b"] 间接返回了一个固定的字符串。(毫无疑问是IV向量和加密Key)

看看,没了啊。

外围的加密代码就这点。

                    var O = Date.parse(new Date),                    Y = Object(h["e"])(!1, 16),                    j = Object(h["a"])(JSON.stringify({                        data: b,                        timestamp: O                    }), Y),                    P = Object(h["f"])(j, Y);                T = {                    encryKey: Object(h["a"])(Y, h["b"]),                    data: j,                    sign: P,                    timestamp: O                }

所以重点代码又回到这里了,看懂这里就是所有的逻辑了。

读一下,也就这样。

获取以后工夫戳 O
生成随机字符串 Y
把传入的b(body)和工夫戳组合到一起,设定IV向量为Y,应用AES 加密
把密文 j 和 Y进行SHA256签名
最用把Y也用AES 加密,这个时候加密IV向量为h["b"]

换集体话

写死了一个iv向量,随机生成一个16位的key,从iv向量对这个Key加密,

用这个Key作为另一个iv变量对申请体Body加密,

而后把下面一堆货色做一个sha256的签名。

哦,说好的前端参数签名加密。

到这里,其实破解过程曾经实现了。

这根本也是我睡醒之后,看了台风吃了晚饭回来之后,

开始抄Python 把下面逻辑实现一波的前置思路了。

这个时候,咱们也要晓得一些货色。

JS加密库 CryptoJS

Python对应的加密库 pycrypto

最初用Python实现这个残缺逻辑还是折腾了好一会的,

也抄了不少别的代码,最初贴一下。

from Crypto.Cipher import AESimport base64import timeimport binasciiclass AesEncrypt:    def __init__(self, key, iv):        self.key = key.encode('utf-8')        self.iv = iv.encode('utf-8')    # @staticmethod    def pkcs7padding(self, text):        """明文应用PKCS7填充 """        bs = 16        length = len(text)        bytes_length = len(text.encode('utf-8'))        padding_size = length if (bytes_length == length) else bytes_length        padding = bs - padding_size % bs        padding_text = chr(padding) * padding        self.coding = chr(padding)        return text + padding_text    def aes_encrypt(self, content):        """ AES加密 """        cipher = AES.new(self.key, AES.MODE_CBC, self.iv)        # 解决明文        content_padding = self.pkcs7padding(content)        # 加密        encrypt_bytes = cipher.encrypt(content_padding.encode('utf-8'))        # 从新编码        result = str(base64.b64encode(encrypt_bytes), encoding='utf-8')        print("加密hex:", str(binascii.hexlify(encrypt_bytes),encoding='utf-8'))        return result    def aes_encrypt_to_hex(self, content):        """ AES加密 """        cipher = AES.new(self.key, AES.MODE_CBC, self.iv)        # 解决明文        content_padding = self.pkcs7padding(content)        # 加密        encrypt_bytes = cipher.encrypt(content_padding.encode('utf-8'))        # 从新编码        # result = str(base64.b64encode(encrypt_bytes), encoding='utf-8')        return str(binascii.hexlify(encrypt_bytes),encoding='utf-8')    def aes_decrypt(self, content):        """AES解密 """        cipher = AES.new(self.key, AES.MODE_CBC, self.iv)        content = base64.b64decode(content)        text = cipher.decrypt(content).decode('utf-8')        return text.rstrip(self.coding)if __name__ == '__main__':    key = '123'    iv = '123'    ts = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())    p_json = {        "CompanyName": "testmall",              "UserId": "test",              "Password": "grasp@101",              "TimeStamp": "2019-05-05 10:59:26"    }    a = AesEncrypt(key=key, iv=iv)    e = a.aes_encrypt("123")    d = a.aes_decrypt(e)    print("加密:", e)    print("解密:", d)

好了,

真完了,

睡觉睡觉。