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我们可以生成,其他的明显是加密后数据和签名。


一点都不高能的预警

先说一下思路:

  1. 捞出核心JS文件
  2. 读懂加密过程,捞出关键参数
  3. 用其他语言实现涉及到的加密函数
  4. 对比加密结果是否一致,尝试去伪造请求

捞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