创建: 2024-09-01 14:26
纯粹是好奇心,无其他意图,如有侵权,删之即可。
逆向目标
RC4密文: 54f7d1b1123e55cd0b4347a7e6c696d57d531c818c891f930cbb5f3bbdc1bc7b999a9cfbbbae76eaeb5628e1230cba
RC4KEY: V0hBVCBUSEUgRlVDSw==
访问目标,有18页试读。F12注意到chunk-6699a887.e1b613e3.js,Babel反混淆。有几个函数太扎眼:
//
// _0x57ce6e即
// https://path/some.xxxx
//
// 从此函数看出,有种情况会出现some.zip,而非some.xxxx
//
async 'openURL'(_0x57ce6e) {
const _0x3f7d43 = _0x377d3e;
this.lazyAble ? this.loadDecrypt(this.lazyUrl + '0.xxxx') : _0x57ce6e.endsWith(".zip") ? this.loadHash(_0x57ce6e) : _0x57ce6e.endsWith(".xxxx") ? this.loadDecrypt(_0x57ce6e) : this._openURL(_0x57ce6e);
},
//
// _0x21407d即some.xxxx
//
// _0x2815a9对象有两个属性
// "password": "9YsNbnJtxoeFu1MbGnH8cP7qWUHwEsNg",
// "spassword": "xSeZw1dY2HKAj3yk",
//
// Object(_0x4710a0.a)即function _0x3f2c74
//
async 'loadDecrypt'(_0x21407d) {
const _0x1ff5be = _0x377d3e;
let _0x415c9c = await fetch(_0x21407d);
if (_0x415c9c.ok) {
//
// AES-CBC解密,得到PDF数据,放在_0x1c4379中
//
const _0x1c4379 = await Object(_0x4710a0.a)(_0x415c9c, _0x2815a9.spassword);
try {
await this.initDocument(_0x1c4379.buffer, 'aaa.pdf'),
this.loading = false,
this.updateView();
} catch (_0x7c47b4) {
console.log(_0x7c47b4);
}
}
},
//
// loadDecrypt会调用此函数
//
// _0x1f65fe对应some.xxxx
// _0x3c635f是"xSeZw1dY2HKAj3yk"
//
async function _0x3f2c74(_0x1f65fe, _0x3c635f) {
const _0x5241fb = _0x49a261,
//
// _0x178a1b即some.xxxx的数据
//
_0x178a1b = await _0x1f65fe.arrayBuffer(),
//
// salt
//
_0x1633f3 = _0x178a1b.slice(0x0, 0x8),
//
// iv
//
_0x26ccd9 = _0x178a1b.slice(0x8, 0x18),
_0x24e12e = _0x178a1b.slice(0x18),
//
// Derive PBKDF2 key
// password="xSeZw1dY2HKAj3yk"
// salt
//
_0x1404e3 = await _0x4b76a1(_0x3c635f, _0x1633f3),
_0x1a9ab4 = await window.crypto.subtle.decrypt({
'name': "AES-CBC",
'iv': _0x26ccd9
}, _0x1404e3, _0x24e12e);
return new Uint8Array(_0x1a9ab4);
}
//
// loadDecrypt会间接调用此函数
// _0xb02836是"xSeZw1dY2HKAj3yk",_0x1d6150即0.xxxx前8字节,充作
// PBKDF2的salt
//
// CyberChef/Derive PBKDF2 key
// Passphrase="xSeZw1dY2HKAj3yk" (UTF8)
// Key size=128
// Iterations=65536
// Hashing functioin=SHA256
// Salt=d6 dc bf d0 0e c1 81 f1 (HEX)
// Output=1f67c8caec75e3069c52e43e29555904
//
async function _0x4b76a1(_0xb02836, _0x1d6150) {
const _0x5a76ae = _0x49a261,
_0x31b848 = {
'name': 'PBKDF2',
'salt': _0x1d6150,
'iterations': 0x10000,
'hash': 'SHA-256'
},
_0x42ed5e = await window.crypto.subtle.importKey("raw", new TextEncoder().encode(_0xb02836), {
'name': "PBKDF2"
}, false, ["deriveKey"]),
_0x11cb7a = await window.crypto.subtle.deriveKey(_0x31b848, _0x42ed5e, {
'name': "AES-CBC",
'length': 0x80
//
// false改成true,表示extractable,方便查看结果
// }, false, ["encrypt", "decrypt"]);
//
}, true, ["encrypt", "decrypt"]);
return _0x11cb7a;
}
先反混淆,再Overrides,设断,单步几下,就是上面那堆注释,无需其他奇技淫巧。
整理一下框架流程:
let buf = get_binary_from_file( ifile );
let salt = buf.slice( 0, 8 );
let iv = buf.slice( 0x8, 0x18 );
let ebuf = buf.slice( 0x18 );
let keysize = 128;
let password = "xSeZw1dY2HKAj3yk";
let iterations = 0x10000;
let hasher = CryptoJS.algo.SHA256;
let key = PrivateDeriveKey( keysize, password, salt, iterations, hasher );
let dbuf = aes_decrypt( key, iv, ebuf );
save_binary( dbuf, ofile );