【猿人学】第五题 乱码增强 逆向分析

难点

代码混淆cookie 加密,还有有点难度

Tip:例子:https://pan.bigdataboy.cn/s/5DvCq?password=phm69t

猿人学该题官网:https://match.yuanrenxue.com/match/5

mark

分析参数

m f 疑似时间戳,但不一样,也是需要注意的

[mark]

mRM4hZBv0dDon443M 这两个确定是加密值

mark

分析 ‘m’ ‘f’

通过调用栈,发现 m f 是直接赋值,都是通过 window 获取的

mark

可以先上下翻翻,看看有什么需要注意的地方,这里用 Hook 来定位 window._$is

(function() {
    'use strict';
    var value_;
    Object.defineProperty(window, '_$is', {  // 修改_$ss为你需要查询的window属性
        get: function() {
            console.log('Window Hook捕获到->', value_);
            return value_;
        },
        set: function(value) {
            debugger;
            value_ = value;
            console.log('Window Hook捕获到->', value_);
            return value;
        },
    });
})();

最终定位此处

 _0x4e96b4['_$is'] = _$yw; // _0x4e96b4 就是 window

_$yw =  _0x2d5f5b()["toString"](); 

// _0x2d5f5b() 
function _0x2d5f5b() {
    return new _0x35bb1d()['valueOf'](); // _0x35bb1d 是 Date() 对象
}

// 综上分析
 _0x4e96b4['_$is'] = new Date()['valueOf']()['toString']()

mark

继续通过 Hook 的方式,定位 window.$_zw[23]

(function() {
    'use strict';
    var value_;
    Object.defineProperty(window, '$_zw', {  // 修改_$ss为你需要查询的window属性
        get: function() {
            console.log('Window Hook捕获到->', value_);
            debugger;
            return value_;
        },
        set: function(value) {
            value_ = value;
            console.log('Window Hook捕获到->', value_);
            debugger;
            return value;
        },
    });
})();

最终定位此处

//  $_aiding['$_zw'][7] ---> Date
window.$_zw[23] = $_aiding['$_zw'][7].parse(new $_aiding['$_zw'][7]()

// 所以

window.$_zw[23] = Date.parse(new Date())

mark

也是采用 Hook 的方式先定位赋值的地方

(function() {
    'use strict';
    var cookie_;
    Object.defineProperty(document, 'cookie', {  // 修改_$ss为你需要查询的window属性
        get: function() {
            console.log('Get Cookie Hook 捕获到 -->', cookie_);
            debugger;
            return cookie_;
        },
        set: function(cookie_) {
            cookie_ = cookie_;
            console.log('Set Cookie Hook 捕获到 -->', cookie_);
            debugger;
            return cookie_;
        },
    });
})();

Hook Cookie 加密 m

 _$Wa = _0x12eaf3();

// _0x12eaf3
function _0x12eaf3() {
    return _0x35bb1d[_$UH[0xff]](new _0x35bb1d()); // _0x35bb1d 是 Date _$UH[0xff] 是 parse
}
// 所以,但是还需要 加密把加密函数扒下来
 _$Wa = Date.parse(new Date())

mark

Hook Cookie 加密 RM4hZBv0dDon443M 值,就使用上面的 Hook 脚本就行

mark

继续使用 Hook window 方式,来 Hook _$ss,定位到此处,发现是AES 加密

mark

寻找 AESKey Mode padding

// CryptoJS.enc.Utf8.stringify(WordArray) -->  WordArray.init 对象转 Utf-8

_$UH[0x2e5]
"ECB"
_$UH[0x33c] + _$UH[0x33d]
"Pkcs7"
_0x4e96b4[_0xc77418('0x6', 'OCbs')]
WordArray.init {words: Array(4), sigBytes: 16}
_$Ww
WordArray.init {words: Array(41), sigBytes: 164}
CryptoJS.enc.Utf8.stringify(_0x4e96b4[_0xc77418('0x6', 'OCbs')]);
"MTY1MDE5ODgxNjUy"
CryptoJS.enc.Utf8.stringify(_$Ww);
"37cdb337788229c60faf0aaffb2d6e65,0df6d975c6b74ba95888b9ac8f0b335c,c333e16a0ae6031b2a1c7be404fdc3e8,61eed28470638021cb96fd084d2f1899,57b5c27e56210e05f2eea98b3bfb0cdb"

mark

经过几次的实验,发现这个 Key会变的,所以还需要分析 Key 是怎么来的,继续使用 Hook Window 脚本

window._$qF
WordArray.init {words: Array(4), sigBytes: 16}
_0x4e96b4[_0xc77418('0x6', 'OCbs')]
WordArray.init {words: Array(4), sigBytes: 16}

mark

Hook 到此处,是 Key 生成的地方,原来 Keym 值而来

mark

寻找原加密的值,继续使用Hook Window 脚本来定位

可以发现前 四 个是循环此处添加的,时间戳后面是三个零

_$Wa = _0x12eaf3();
_0x3d0f3f[_$Fe] = 'm=' + _0x474032(_$Wa) + ';\x20path=/';
_0x4e96b4['_$pr']['push'](_0x474032(_$Wa));

mark

第五个,在这里,时间戳后面不是三个零

try {
    _$yw = _0x2d5f5b()[_$UH[0x1f]]();
    _0x3d0f3f[_$Fe] = 'm=' + _0x474032(_$yw) + ';\x20path=/';
    _0x4e96b4['_$is'] = _$yw;
    _0x4e96b4['_$pr']['push'](_0x474032(_$yw));
} catch (_0x3c2e99) {}

mark

整理一下流程

参数 f 最先生成带三个 0 的时间戳

参数 m 是 加密时间戳数组 的 第五个未加密时的值

时间戳数组前四个使用 `Date.parse(new Date())` 方式获取,结尾有 三个零

时间戳数组前第五个使用 `new Date()['valueOf']()['toString']()`  方式获取

cookie 的 m 就是 参数的 m 加密而来
MTY1MDE5ODgxNjUy --> 由五个加密的时间戳 再进行 AES 加密而来

扒代码

用手撕的方式吧

定位到加密函数出 _0x474032

function _0x474032(_0x233f82, _0xe2ed33, _0x3229f9) {
    return _0xe2ed33 ? _0x3229f9 ? v(_0xe2ed33, _0x233f82) : y(_0xe2ed33, _0x233f82) : _0x3229f9 ? _0x41873d(_0x233f82) : _0x37614a(_0x233f82);
}
// 美化一下格式
function _0x474032(_0x233f82, _0xe2ed33, _0x3229f9) {
    return _0xe2ed33 ?  // undefined
    _0x3229f9 ?
        v(_0xe2ed33, _0x233f82) : y(_0xe2ed33, _0x233f82)
    : _0x3229f9 ?  // undefined
        _0x41873d(_0x233f82) : _0x37614a(_0x233f82); // 所以最终执行的是 `_0x37614a` 
}
// 所以只需要 
_0x37614a(时间戳)

mark

然后把 _0x37614a() 函数 复制到本地,然后把所有缺少的函数补齐

function _0x37614a(_0x32e7c1) {
    return _0x499969(_0x41873d(_0x32e7c1));
}

mark

这就是补完后的样子,然后运行,报错 提示 _$UH 未定义

mark

打断点查看是个大数组,所以只需要这样补充就好

_$UH = {
    15:'charCodeAt',
    108:'length',
    276:'fromCharCode',
}

接着运行,报_0x1badc3[_$UH[31]] is not a function错,然后源文件该行断点,发现没有断住,说明没有执行这里,然后有个 try catch ,断点看看

mark

接着就是报什么错,就到原文件看是什么,对比着来,这里有几个值 需要注意,不然就算出值了也不能过,_0x4e96b4['_$tT']_0x4e96b4['_$Jy'],需要该函数计算 cookie m 时才是正确的

mark

验证

现在整个过程都清楚了,验证一下

mark

发表评论 / Comment

用心评论~