mirror of
https://github.com/pysunday/rs-reverse.git
synced 2025-04-12 03:46:56 +08:00
feat: 1. 增加makecode-high子命令 2. 增加basearr子命令
This commit is contained in:
parent
ae822c7a4d
commit
7757ad5934
66
README.md
66
README.md
@ -115,7 +115,63 @@ Examples:
|
||||
|
||||
```
|
||||
|
||||
### 2.3. exec子命令
|
||||
### 2.3. makecode-high子命令
|
||||
|
||||
执行子命令`makecode-high`生成cookie,解码两次请求返回的网站代码(功能涵盖makecode子命令),调用示例:
|
||||
|
||||
1. npx方式:`npx rs-reverse makecode-high -u url`
|
||||
2. 文件方式:`node main.js makecode-high -u url`
|
||||
|
||||
该命令第一次请求生成cookie带入第二次请求,将两次请求返回的加密代码及动态代码解码后保存到`output/makecode-high`目录中,和makecode命令区别为该命令只提供-u方式执行!
|
||||
|
||||
```console
|
||||
$ npx rs-reverse makecode-high -h
|
||||
rs-reverse makecode-high
|
||||
|
||||
解码两次请求返回的网站代码(功能涵盖makecode子命令)
|
||||
|
||||
Options:
|
||||
-h 显示帮助信息 [boolean]
|
||||
-f
|
||||
-l, --level 日志打印等级,参考log4js,默认为info [string]
|
||||
-u, --url 瑞数返回204状态码的请求地址 [string] [required]
|
||||
-a, --adapt 已经做了适配的网站名称,不传则为cnipa [string]
|
||||
-v, --version 显示版本号 [boolean]
|
||||
|
||||
Examples:
|
||||
rs-reverse makecode-high -u http://url/path
|
||||
```
|
||||
|
||||
调用示例:
|
||||
|
||||
```bash
|
||||
$ npx rs-reverse makecode-high -u https://wcjs.sbj.cnipa.gov.cn/sgtmi
|
||||
|
||||
第1次请求:
|
||||
|
||||
url方式提取的ts:/path/to/output/makecode-high/first/ts.json
|
||||
url方式提取的静态文本:/path/to/output/makecode-high/first/immucfg.json
|
||||
程序生成的ts:/path/to/output/makecode-high/first/ts-full.json
|
||||
url方式提取的javascript代码:/path/to/output/makecode-high/first/cCdzB9ZjDFks.a728b22.js
|
||||
url方式提取的html代码:/path/to/output/makecode-high/first/sgtmi.html
|
||||
cCdzB9ZjDFks.a728b22.js生成的动态代码:/path/to/output/makecode-high/first/cCdzB9ZjDFks.a728b22-dynamic.js
|
||||
|
||||
第2次请求:
|
||||
|
||||
url方式提取的ts:/path/to/output/makecode-high/second/ts.json
|
||||
url方式提取的静态文本:/path/to/output/makecode-high/second/immucfg.json
|
||||
程序生成的ts:/path/to/output/makecode-high/second/ts-full.json
|
||||
url方式提取的javascript代码:/path/to/output/makecode-high/second/cCdzB9ZjDFks.a728b22.js
|
||||
url方式提取的html代码:/path/to/output/makecode-high/second/sgtmi.html
|
||||
cCdzB9ZjDFks.a728b22.js生成的动态代码:/path/to/output/makecode-high/second/cCdzB9ZjDFks.a728b22-dynamic.js
|
||||
url方式提取的javascript代码:/path/to/output/makecode-high/second/chunk-vendors.66e24864.js
|
||||
url方式提取的javascript代码:/path/to/output/makecode-high/second/app.9f7a91c9.js
|
||||
chunk-vendors.66e24864.js生成的解密代码:/path/to/output/makecode-high/second/chunk-vendors.66e24864-decrypt.js
|
||||
app.9f7a91c9.js生成的解密代码:/path/to/output/makecode-high/second/app.9f7a91c9-decrypt.js
|
||||
|
||||
```
|
||||
|
||||
### 2.4. exec子命令
|
||||
|
||||
exec子命令用于开发中或者演示时使用。命令示例:
|
||||
|
||||
@ -154,10 +210,10 @@ Examples:
|
||||
|
||||
适配文件配置在目录`./src/adapt/`下,已完成兼容配置:
|
||||
|
||||
网站 | 名称 | makecode | makecookie | 适配版本 | 是否逆向验证
|
||||
---- | ---- | -------- | ---------- | -------- | --------------
|
||||
商标网 | cnipa | 👌 | 👌 | - | Y
|
||||
瑞数官网 | riversecurity | 👌 | 👌 | 版本1 | N
|
||||
网站 | 名称 | makecode | makecookie | makecode-high | 适配版本 | 是否逆向验证
|
||||
---- | ---- | -------- | ---------- | ------------- | -------- | --------------
|
||||
商标网 | cnipa | 👌 | 👌 | 👌 | - | Y
|
||||
瑞数官网 | riversecurity | 👌 | 👌 | N | 版本1 | N
|
||||
|
||||
以瑞数官网实例如:`npx rs-reverse makecookie -u https://www.riversecurity.com/resources.shtml -a riversecurity`
|
||||
|
||||
|
34
main.js
34
main.js
@ -7,6 +7,7 @@ const fs = require('fs');
|
||||
const makeCode = require('@src/makeCode');
|
||||
const makeCodeHigh = require('@src/makeCodeHigh');
|
||||
const makeCookie = require('@src/makeCookie');
|
||||
const basearrParse = require('@src/basearrParse');
|
||||
const utils = require('@utils/');
|
||||
const { logger, getCode } = utils;
|
||||
const pkg = require(paths.package);
|
||||
@ -64,6 +65,7 @@ const commandHandler = (command, argv) => {
|
||||
const ts = argv.url?.$_ts || argv.file || require(paths.exampleResolve('codes', `${gv.version}-\$_ts.json`));
|
||||
logger.trace(`传入的$_ts.nsd: ${ts.nsd}`);
|
||||
logger.trace(`传入的$_ts.cd: ${ts.cd}`);
|
||||
gv._setAttr('argv', argv);
|
||||
try {
|
||||
if (argv.url) {
|
||||
command(ts, adapt(argv.url, argv.adapt), argv.url);
|
||||
@ -88,8 +90,15 @@ module.exports = yargs
|
||||
})
|
||||
.command({
|
||||
command: 'makecode-high',
|
||||
describe: '生成动态代码-高级',
|
||||
builder: commandBuilder,
|
||||
describe: '解码两次请求返回的网站代码(功能涵盖makecode子命令)',
|
||||
builder: {
|
||||
...commandBuilder,
|
||||
f: undefined,
|
||||
u: {
|
||||
...commandBuilder.u,
|
||||
demandOption: true,
|
||||
}
|
||||
},
|
||||
handler: commandHandler.bind(null, makeCodeHigh),
|
||||
})
|
||||
.command({
|
||||
@ -136,6 +145,27 @@ module.exports = yargs
|
||||
console.log([`\n 输入:${argv.code}`, `输出:${output}\n`].join('\n '));
|
||||
}
|
||||
})
|
||||
.command({
|
||||
command: 'basearr',
|
||||
describe: '接收压缩前数字数组的序列化文本并格式化解析',
|
||||
builder: {
|
||||
l: {
|
||||
alias: 'level',
|
||||
describe: '日志打印等级,参考log4js,默认为info',
|
||||
type: 'string',
|
||||
},
|
||||
b: {
|
||||
alias: 'basearr',
|
||||
describe: '压缩前数字数组的序列化文本',
|
||||
type: 'array',
|
||||
demandOption: true,
|
||||
}
|
||||
},
|
||||
handler: (argv) => {
|
||||
debugLog(argv.level);
|
||||
basearrParse(argv.basearr);
|
||||
}
|
||||
})
|
||||
.updateStrings({
|
||||
'Show version number': '显示版本号',
|
||||
'Show help': '显示帮助信息',
|
||||
|
@ -39,6 +39,7 @@
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"cheerio": "^1.0.0-rc.12",
|
||||
"fs-extra": "^11.2.0",
|
||||
"jest": "^29.7.0",
|
||||
"lodash": "^4.17.21",
|
||||
"log4js": "^6.9.1",
|
||||
|
@ -21,10 +21,10 @@ module.exports = function({ jscode, url }, name) {
|
||||
gv._setAttr('version', val);
|
||||
return ans;
|
||||
}
|
||||
const idx = jscode.indexOf(val);
|
||||
const idx = jscode.code.indexOf(val);
|
||||
if (idx === -1) throw new Error(`${key}值数据未找到,请查看文档:src/adapt/readme.md`);
|
||||
if (jscode.indexOf(val, idx + val.length) > -1) throw new Error(`${key}对应的值${val}在代码中非唯一,请检查!`);
|
||||
const fullString = findFullString(jscode, val);
|
||||
if (jscode.code.indexOf(val, idx + val.length) > -1) throw new Error(`${key}对应的值${val}在代码中非唯一,请检查!`);
|
||||
const fullString = findFullString(jscode.code, val);
|
||||
return { ...ans, [key]: fullString };
|
||||
}, {});
|
||||
}
|
||||
|
165
src/basearrParse.js
Normal file
165
src/basearrParse.js
Normal file
@ -0,0 +1,165 @@
|
||||
const logger = require('@utils/logger');
|
||||
const error = require('@utils/error');
|
||||
|
||||
const parseBlock = (item, id) => {
|
||||
if (typeof id !== 'number') return { ...item, show: id };
|
||||
const val = item.val;
|
||||
let oper = 0;
|
||||
const next = (val) => {
|
||||
switch(val.type) {
|
||||
case 'div':
|
||||
oper += 1;
|
||||
break;
|
||||
case 'val':
|
||||
case 'arr':
|
||||
oper = val.idx + val.len;
|
||||
break;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
switch(id) {
|
||||
case 0:
|
||||
item.child = [
|
||||
next(div(val, oper)),
|
||||
next(value(val, oper, 1, 'window.navigator.maxTouchPoints')),
|
||||
next(value(val, oper, 1, 'window.eval.toString().length')),
|
||||
next(div(val, oper)),
|
||||
next(value(val, oper, 4, 'window.navigator.userAgent')),
|
||||
value(val, oper, 1, 'length'),
|
||||
next(block(val, oper, 'window.navigator.platform')),
|
||||
next(value(val, oper, 4, 'execNumberByTime')),
|
||||
next(value(val, oper, 2, 'execRandomByNumber')),
|
||||
next(div(val, oper)),
|
||||
next(div(val, oper)),
|
||||
next(value(val, oper, 4, '3136373737323136')),
|
||||
next(value(val, oper, 4, '0')),
|
||||
next(value(val, oper, 2, 'window.innerHeight')),
|
||||
next(value(val, oper, 2, 'window.innerWidth')),
|
||||
next(value(val, oper, 2, 'window.outerHeight')),
|
||||
next(value(val, oper, 2, 'window.outerWidth')),
|
||||
];
|
||||
break;
|
||||
case 1:
|
||||
item.child = [
|
||||
next(value(val, oper, 1, '0 < +ascii2string(gv.keys[24]) < 8')),
|
||||
next(div(val, oper)),
|
||||
next(value(val, oper, 4, 'r2mkaTime + runTime - startTime')),
|
||||
next(value(val, oper, 4, '+ascii2string(gv.keys[19])')),
|
||||
next(value(val, oper, 8, 'Math.floor(Math.random() * 1048575) * 4294967296 + (((currentTime + 1) & 4294967295) >>> 0)')),
|
||||
next(value(val, oper, 1, '+ascii2string(gv.keys[24])')),
|
||||
];
|
||||
break;
|
||||
case 2:
|
||||
item.child = [
|
||||
next(value(val, oper, 4, '16777216')),
|
||||
next(value(val, oper, 4, '0')),
|
||||
next(value(val, oper, 2, '5900')),
|
||||
next(value(val, oper, 2, 'codeToStringUid')),
|
||||
];
|
||||
break;
|
||||
case 4:
|
||||
item.child = [ // 编号510方法执行返回
|
||||
next(value(val, oper, 1, '1')),
|
||||
next(value(val, oper, 2, '0')),
|
||||
next(value(val, oper, 2, '0')),
|
||||
next(value(val, oper, 1, 'window.document.hidden')),
|
||||
next(value(val, oper, 8, 'encryptMode2(decrypt(ascii2string(gv.keys[22])), numarrAddTime(gv.keys[16])[0])')),
|
||||
next(value(val, oper, 2, '+decode(decrypt(ascii2string(gv.keys[22])))')),
|
||||
];
|
||||
break;
|
||||
case 5:
|
||||
item.child = [
|
||||
next(value(val, oper, 1, 'taskmap[ascii2string(gv.keys[29])]();')),
|
||||
next(value(val, oper, 1, 'taskmap[ascii2string(gv.keys[30])]();')),
|
||||
next(value(val, oper, 1, 'taskmap[ascii2string(gv.keys[31])]();')),
|
||||
next(value(val, oper, 1, 'taskmap[ascii2string(gv.keys[32])]();')),
|
||||
]
|
||||
break;
|
||||
case 6:
|
||||
item.child = [
|
||||
next(value(val, oper, 1, 'battery and connection operator')),
|
||||
next(value(val, oper, 1, 'window.navigator.battery.level * 100')),
|
||||
next(value(val, oper, 1, 'window.navigator.battery.chargingTime >> 8')),
|
||||
next(value(val, oper, 1, 'window.navigator.battery.chargingTime & 255')),
|
||||
next(value(val, oper, 1, 'window.navigator.connection')),
|
||||
];
|
||||
break;
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
function value(arr, oper, len, show) {
|
||||
return {
|
||||
show,
|
||||
val: arr.slice(oper, oper + len),
|
||||
idx: oper,
|
||||
type: 'val',
|
||||
len,
|
||||
}
|
||||
}
|
||||
|
||||
function block(arr, oper, id) {
|
||||
const num = arr[oper++]
|
||||
return parseBlock({ val: arr.slice(oper, num + oper), len: num, idx: oper, type: 'arr' }, id);
|
||||
}
|
||||
|
||||
function div(arr, oper, show = '-------') {
|
||||
return { show, val: arr[oper], idx: oper, type: 'div' };
|
||||
}
|
||||
|
||||
function print(divarr, deep = 0, parentIdx = 0) {
|
||||
divarr.forEach((it) => {
|
||||
const idx = deep ? `(${it.idx},${it.idx + parentIdx})` : `(${it.idx})`;
|
||||
console.log([new Array(deep * 4).fill(' ').join(''), idx, `[${it.val || '0'}]`, it.show].filter(Boolean).join(' '));
|
||||
if (it.child) print(it.child, deep + 1, it.idx);
|
||||
})
|
||||
}
|
||||
|
||||
function parse(basearr) {
|
||||
let oper = 0;
|
||||
console.log('\n');
|
||||
const next = (val) => {
|
||||
if (!val) debugger;
|
||||
switch(val.type) {
|
||||
case 'div':
|
||||
oper += 1;
|
||||
break;
|
||||
case 'val':
|
||||
case 'arr':
|
||||
oper = val.idx + val.len;
|
||||
break;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
print(new Array(8).fill('').reduce((ans, it, idx) => {
|
||||
return [
|
||||
...ans,
|
||||
next(div(basearr, oper)),
|
||||
value(basearr, oper, 1, 'length'),
|
||||
next(block(basearr, oper, idx)),
|
||||
];
|
||||
}, []));
|
||||
}
|
||||
|
||||
module.exports = function (basearrs) {
|
||||
try {
|
||||
basearrs = basearrs.map(it => {
|
||||
basearr = JSON.parse(it);
|
||||
if (!Array.isArray(basearr)) {
|
||||
throw new Error('');
|
||||
}
|
||||
return basearr;
|
||||
})
|
||||
} catch (err) {
|
||||
error('请传入序列化后的数字数组!');
|
||||
}
|
||||
basearrs.forEach(parse);
|
||||
if (basearrs.length > 1) {
|
||||
console.log('\n');
|
||||
for (let i = 0, j = new Set(); i < Math.max(...basearrs.map(it => it.length)); i++) {
|
||||
j.clear();
|
||||
basearrs.forEach(it => j.add(it[i]));
|
||||
if (j.size !== 1) console.log(`不同点下标${i}:${basearrs.map(it => it[i]).join(' ')}`);
|
||||
}
|
||||
}
|
||||
}
|
94
src/handler/AppCode.js
Normal file
94
src/handler/AppCode.js
Normal file
@ -0,0 +1,94 @@
|
||||
const gv = require('@src/handler/globalVarible');
|
||||
|
||||
module.exports = class {
|
||||
constructor(params, idx) {
|
||||
this.oper = 0;
|
||||
this.params = params;
|
||||
this.idx = idx;
|
||||
}
|
||||
|
||||
getLength() {
|
||||
let one, two, three, four, dkey = gv.decryptKeys[5];
|
||||
const text = this.params[0];
|
||||
const flag = dkey[text.charCodeAt(this.oper++)];
|
||||
if (flag <= 80) return flag;
|
||||
if (flag == 81) {
|
||||
return dkey[text.charCodeAt(this.oper++)] + 80;
|
||||
}
|
||||
if (flag == 82) {
|
||||
one = dkey[text.charCodeAt(this.oper++)];
|
||||
two = dkey[text.charCodeAt(this.oper++)];
|
||||
return one + two * 86 + 165;
|
||||
}
|
||||
if (flag == 83) {
|
||||
one = dkey[text.charCodeAt(this.oper++)];
|
||||
two = dkey[text.charCodeAt(this.oper++)];
|
||||
three = dkey[text.charCodeAt(this.oper++)];
|
||||
return one + two * 86 + three * 86 * 86 + 7560;
|
||||
}
|
||||
if (flag == 84) {
|
||||
one = dkey[text.charCodeAt(this.oper++)];
|
||||
two = dkey[text.charCodeAt(this.oper++)];
|
||||
three = dkey[text.charCodeAt(this.oper++)];
|
||||
four = dkey[text.charCodeAt(this.oper++)];
|
||||
return one + two * 86 + three * 86 * 86 + four * 86 * 86 * 86 + 643615;
|
||||
}
|
||||
}
|
||||
|
||||
getKeys(len) {
|
||||
const keys = [];
|
||||
for(let i = 0; i <= len; i++) {
|
||||
const j = Math.floor((this.random || Math.random()) * 4294967295) % len + 0;
|
||||
keys[i] = keys[j] || `$_${j}`;
|
||||
keys[j] = `$_${i}`;
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
decrypt() {
|
||||
const keys = this.getKeys(this.getLength());
|
||||
const name = `$$_${this.idx}`;
|
||||
const num = this.getLength();
|
||||
const ret = new Array(num), res = [];
|
||||
const staticText = this.params[1].split('~');
|
||||
for(let i = 0, j; i < num; i++) {
|
||||
i % 2 == 0 ? j = this.getLength() : j >>= 3;
|
||||
const next = this.getLength();
|
||||
switch(j & 7) {
|
||||
case 0:
|
||||
ret[i] = res[next];
|
||||
break;
|
||||
case 1:
|
||||
ret[i] = keys[next];
|
||||
break;
|
||||
case 2:
|
||||
ret[i] = gv.ts.cp[1][next];
|
||||
break;
|
||||
case 3:
|
||||
const val = this.params[0].substr(this.oper, next);
|
||||
this.oper += next;
|
||||
res.push(val);
|
||||
ret[i] = val;
|
||||
break;
|
||||
case 4:
|
||||
// ret[i] = `${name}[${next}]`;
|
||||
ret[i] = `"${staticText[next]}"`;
|
||||
break;
|
||||
case 5:
|
||||
ret[i] = this.params[2][next]
|
||||
break;
|
||||
}
|
||||
}
|
||||
// return `window[${name}]=${JSON.stringify(staticText)};${ret.join('')}`;
|
||||
return ret.join('');
|
||||
}
|
||||
|
||||
run() {
|
||||
const code = this.decrypt();
|
||||
if (this.getLength() !== 0) {
|
||||
debugger;
|
||||
throw new Error('预期值不符,需要增加额外代码适配!');
|
||||
};
|
||||
return code;
|
||||
}
|
||||
}
|
@ -18,6 +18,9 @@ module.exports = class {
|
||||
this.opdata = dataOper();
|
||||
this.r2mkaText = null;
|
||||
this.immucfg = immucfg || gv.config.immucfg;
|
||||
this.functionsPushStart = { 1: 938, 2: 0, 3: 0, 4: 0 }; // 生成方法排序数据的开始下标, 938为键值为348所命中的代码中获得
|
||||
this.functionsNameSort = []; // 存放vm代码中定义的方法,用于计算代码特征码使用
|
||||
this.mainFunctionIdx = null; // 主函数(编号为1)在代码中的开始与结束下标
|
||||
}
|
||||
|
||||
run() {
|
||||
@ -88,6 +91,7 @@ module.exports = class {
|
||||
this.gren(i, codeArr);
|
||||
}
|
||||
codeArr.push('}}}}}}}}}}'.substr(opmate.getMateOri('G_$gG') - 1));
|
||||
this.mainFunctionIdx.push(codeArr.join('').length);
|
||||
return codeArr;
|
||||
}
|
||||
|
||||
@ -133,15 +137,21 @@ module.exports = class {
|
||||
opmate.setMate('_$$c');
|
||||
opdata.setData('_$$k', func2(opmate.getMateOri('_$$c')));
|
||||
if (current) {
|
||||
if (this.mainFunctionIdx === null) this.mainFunctionIdx = [codeArr.join('').length];
|
||||
codeArr.push("function ", opmate.getMate('_$jw'), "(", opmate.getMate('_$$6'));
|
||||
opdata.getData('_$_K').forEach(it => codeArr.push(",", keynames[it]));
|
||||
codeArr.push("){");
|
||||
} else {
|
||||
codeArr.push("(function(", opmate.getMate('G_$dK'), ",", opmate.getMate('G_$kv'), "){var ", opmate.getMate('_$$6'), "=0;");
|
||||
}
|
||||
opdata.getData('_$$w').forEach(([key1, key2]) => {
|
||||
codeArr.push("function ", keynames[key1], "(){var ", opmate.getMate('_$$q'), "=[", key2, "];Array.prototype.push.apply(", opmate.getMate('_$$q'), ",arguments);return ", opmate.getMate('_$$g'), ".apply(this,", opmate.getMate('_$$q'), ");}");
|
||||
});
|
||||
const functionsNameMap = opdata.getData('_$$w').reduce((ans, [key1, key2], idx) => {
|
||||
const arr = ["function ", keynames[key1], "(){var ", opmate.getMate('_$$q'), "=[", key2, "];Array.prototype.push.apply(", opmate.getMate('_$$q'), ",arguments);return ", opmate.getMate('_$$g'), ".apply(this,", opmate.getMate('_$$q'), ");}"]
|
||||
codeArr.push(...arr);
|
||||
return {
|
||||
...ans,
|
||||
[keynames[key1]]: arr.join(''),
|
||||
}
|
||||
}, {});
|
||||
opdata.getData('_$cS').forEach(item => {
|
||||
for (let i = 0; i < item.length - 1; i += 2) {
|
||||
codeArr.push(keycodes[item[i]], keynames[item[i + 1]])
|
||||
@ -157,11 +167,29 @@ module.exports = class {
|
||||
codeArr.push(opmate.getMate('_$$6'), ",", opmate.getMate('_$aw'), "=", opmate.getMate('G_$kv'), "[", current, "];");
|
||||
codeArr.push("while(1){", opmate.getMate('_$cu'), "=", opmate.getMate('_$aw'), "[", opmate.getMate('_$ku'), "++];");
|
||||
codeArr.push("if(", opmate.getMate('_$cu'), "<", opmate.getMateOri('_$bf'), "){");
|
||||
if ([1, 2, 3, 4].includes(current)) {
|
||||
this.functionsSort(current, functionsNameMap);
|
||||
}
|
||||
const codelist = this.grenIfelse(0, opmate.getMateOri('_$bf'), []);
|
||||
codeArr.push(...codelist);
|
||||
codeArr.push("}else ", ';', '}');
|
||||
}
|
||||
|
||||
functionsSort(current, functionsNameMap) {
|
||||
const start = this.functionsPushStart[current];
|
||||
const { opdata, opmate } = this
|
||||
this.$_ts.aebi[current].slice(start, start + opdata.getData('_$$w').length).forEach(idx => {
|
||||
const numarr = opdata.getData('_$$k')[idx];
|
||||
if (!numarr || numarr.length !== 5) throw new Error('');
|
||||
const name = this.keynames[numarr[3]];
|
||||
this.functionsNameSort.push({
|
||||
name,
|
||||
current,
|
||||
code: functionsNameMap[name],
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
grenIfelse(start, end, codeArr) {
|
||||
const { opdata, opmate } = this
|
||||
const arr8 = opdata.getData('arr8')
|
||||
|
@ -1 +0,0 @@
|
||||
// 整站代码还原
|
@ -43,7 +43,9 @@ const developConfig = {
|
||||
}
|
||||
|
||||
module.exports = class {
|
||||
constructor(ts, r2mkaText) {
|
||||
constructor(ts, r2mkaText, coder, vmcode) {
|
||||
this.coder = coder;
|
||||
this.vmcode = vmcode;
|
||||
parser.init(ts, r2mkaText)
|
||||
const current = new Date().getTime() + 1000;
|
||||
this.config = {
|
||||
@ -151,7 +153,7 @@ module.exports = class {
|
||||
...numToNumarr4(16777216), // gv.cp2取得
|
||||
...numToNumarr4(0), // 任务编号0-0的任务列表取得
|
||||
...numToNumarr2(getFixedNumber()), // 固定值5900
|
||||
...numToNumarr2(this.config.formatUid), // 根据方法的toString()计算, 使用了$_ts.aebi[1]作为任务的方法,
|
||||
...this.getCodeUid(),
|
||||
],
|
||||
0, // 任务编号0>one>63-287的任务列表取得
|
||||
[0], // 任务编号0>one>63>one>4-290的任务列表取得
|
||||
@ -277,4 +279,13 @@ module.exports = class {
|
||||
getTaskNumber(name, idx) {
|
||||
return gv.r2mka(name).taskarr[idx];
|
||||
}
|
||||
|
||||
getCodeUid() {
|
||||
const mainFunctionCode = this.vmcode.slice(...this.coder.mainFunctionIdx);
|
||||
const one = uuid(this.coder.functionsNameSort[ascii2string(gv.keys[33])].code);
|
||||
const len = parseInt(mainFunctionCode.length / 100);
|
||||
const start = len * ascii2string(gv.keys[34]);
|
||||
const two = uuid(mainFunctionCode.substr(start, len))
|
||||
return numToNumarr2((one ^ two) & 65535);
|
||||
}
|
||||
}
|
||||
|
@ -66,6 +66,10 @@ class GlobalVarible {
|
||||
// 返回密钥集合
|
||||
return cache.keys;
|
||||
}
|
||||
get argv() {
|
||||
// 命令调用参数
|
||||
return cache.argv;
|
||||
}
|
||||
_getAttr(attr) {
|
||||
return cache[attr];
|
||||
}
|
||||
|
@ -1,28 +0,0 @@
|
||||
const gv = require('@src/handler/globalVarible');
|
||||
|
||||
function (text) {
|
||||
let one, two, three, four, idx = 0, dkey = gv.decryptKeys[5];
|
||||
const flag = dkey[text.charCodeAt(idx++)];
|
||||
if (flag <= 80) return flag;
|
||||
if (flag == 81) {
|
||||
return dkey[text.charCodeAt(idx++)] + 80;
|
||||
}
|
||||
if (flag == 82) {
|
||||
one = dkey[text.charCodeAt(idx++)];
|
||||
two = dkey[text.charCodeAt(idx++)];
|
||||
return one + two * 86 + 165;
|
||||
}
|
||||
if (flag == 83) {
|
||||
one = dkey[text.charCodeAt(idx++)];
|
||||
two = dkey[text.charCodeAt(idx++)];
|
||||
three = dkey[text.charCodeAt(idx++)];
|
||||
return one + two * 86 + three * 86 * 86 + 7560;
|
||||
}
|
||||
if (flag == 84) {
|
||||
one = dkey[text.charCodeAt(idx++)];
|
||||
two = dkey[text.charCodeAt(idx++)];
|
||||
three = dkey[text.charCodeAt(idx++)];
|
||||
four = dkey[text.charCodeAt(idx++)];
|
||||
return one + two * 86 + three * 86 * 86 + four * 86 * 86 * 86 + 643615;
|
||||
}
|
||||
}
|
@ -23,13 +23,13 @@ module.exports = function (ts, immucfg, mate = {}) {
|
||||
mate.jscode ? {
|
||||
name: 'makecode_input_js',
|
||||
desc: 'url方式提取的javascript代码:',
|
||||
text: mate.jscode,
|
||||
text: mate.jscode.code,
|
||||
extend: 'js',
|
||||
} : null,
|
||||
mate.html ? {
|
||||
name: 'makecode_input_html',
|
||||
desc: 'url方式提取的html代码:',
|
||||
text: mate.html,
|
||||
text: mate.html.code,
|
||||
extend: 'html',
|
||||
newLine: true,
|
||||
} : null,
|
||||
|
@ -1,12 +1,16 @@
|
||||
const CoderHigh = require('./handler/CoderHigh');
|
||||
const AppCode = require('./handler/AppCode');
|
||||
const paths = require('@utils/paths');
|
||||
const fs = require('fs');
|
||||
const fse = require('fs-extra');
|
||||
const path = require('path');
|
||||
const logger = require('@utils/logger');
|
||||
const Coder = require('./handler/Coder');
|
||||
const Cookie = require('./handler/Cookie');
|
||||
const unescape = require('@utils/unescape');
|
||||
const gv = require('@src/handler/globalVarible');
|
||||
const getCode = require('@utils/getCode');
|
||||
const adapt = require('@src/adapt');
|
||||
const { getLength } = require('@src/handler/parser/common');
|
||||
|
||||
function parseR2mka(text) {
|
||||
const start = text.indexOf('"') + 1;
|
||||
@ -14,15 +18,91 @@ function parseR2mka(text) {
|
||||
return unescape(text.substr(start, end));
|
||||
}
|
||||
|
||||
module.exports = function (ts, immucfg, mate) {
|
||||
gv._setAttr('_ts', ts);
|
||||
const startTime = new Date().getTime();
|
||||
const coder = new Coder(ts, immucfg);
|
||||
const { code, $_ts } = coder.run();
|
||||
const r2mkaText = parseR2mka(coder.r2mkaText);
|
||||
const cookieVal = new Cookie($_ts, r2mkaText).run();
|
||||
const cookieKey = gv.utils.ascii2string(gv.keys[7]).split(';')[5] + 'P';
|
||||
debugger;
|
||||
getCode(mate.url, `${cookieKey}=${cookieVal}`);
|
||||
function mkdirsSync(dirPath) {
|
||||
if (!fs.existsSync(dirPath)) {
|
||||
mkdirsSync(path.dirname(dirPath));
|
||||
fs.mkdirSync(dirPath);
|
||||
}
|
||||
}
|
||||
|
||||
function filenameAddDesc(name, desc) {
|
||||
const arr = name.split('.');
|
||||
if (arr.length < 2) throw new Error(`文件名不正确: ${name}`);
|
||||
arr[arr.length - 2] += desc;
|
||||
return arr.join('.');
|
||||
}
|
||||
|
||||
function writeFile(step, ts, immucfg, { jscode, html, appcode = [] }, $_ts, code) {
|
||||
const files = [
|
||||
{
|
||||
name: 'ts.json',
|
||||
desc: 'url方式提取的ts:',
|
||||
text: JSON.stringify(ts),
|
||||
},
|
||||
{
|
||||
name: 'immucfg.json',
|
||||
desc: 'url方式提取的静态文本:',
|
||||
text: JSON.stringify(immucfg),
|
||||
},
|
||||
{
|
||||
name: 'ts-full.json',
|
||||
desc: '程序生成的ts:',
|
||||
text: JSON.stringify($_ts),
|
||||
},
|
||||
jscode,
|
||||
html,
|
||||
{
|
||||
name: filenameAddDesc(jscode.name, '-dynamic'),
|
||||
desc: `${jscode.name}生成的动态代码:`,
|
||||
text: '// 该行标记来源,非动态代码生成: ' + JSON.stringify(ts) + '\n\n' + code,
|
||||
},
|
||||
...appcode,
|
||||
...appcode.filter(it => it.decryptCode).map(it => ({
|
||||
name: filenameAddDesc(it.name, '-decrypt'),
|
||||
desc: `${it.name}生成的解密代码:`,
|
||||
text: it.decryptCode,
|
||||
}))
|
||||
].filter(Boolean).map(it => ({ ...it, filepath: paths.outputResolve('makecode-high', step, it.name) }))
|
||||
if (!fs.existsSync(paths.outputResolve('makecode-high', step))) mkdirsSync(paths.outputResolve('makecode-high', step));
|
||||
return files;
|
||||
}
|
||||
|
||||
function decryptAppCode(appcode, idx) {
|
||||
const $_ts = { l__: (...params) => params };
|
||||
const codeParams = eval(appcode.code);
|
||||
appcode.decryptCode = new AppCode(codeParams, idx + 1).run();
|
||||
}
|
||||
|
||||
function firstStep(ts, immucfg, mate) {
|
||||
gv._setAttr('_ts', ts);
|
||||
const coder = new Coder(ts, immucfg);
|
||||
const { code, $_ts } = coder.run();
|
||||
const files = writeFile('first', ts, immucfg, mate, $_ts, code);
|
||||
const r2mkaText = parseR2mka(coder.r2mkaText);
|
||||
const cookieVal = new Cookie($_ts, r2mkaText, coder, code).run();
|
||||
const cookieKey = gv.utils.ascii2string(gv.keys[7]).split(';')[5] + 'P';
|
||||
return [files, `${cookieKey}=${cookieVal}`];
|
||||
}
|
||||
|
||||
function secondStep(ts, immucfg, mate) {
|
||||
gv._setAttr('_ts', ts);
|
||||
const coder = new Coder(ts, immucfg);
|
||||
const { code, $_ts } = coder.run();
|
||||
mate.appcode.map(decryptAppCode);
|
||||
return writeFile('second', ts, immucfg, mate, $_ts, code);
|
||||
}
|
||||
|
||||
module.exports = async function (ts, immucfg, mate) {
|
||||
fse.moveSync(paths.outputResolve('makecode-high'), paths.outputResolve('makecode-high-old'), { overwrite: true });
|
||||
const startTime = new Date().getTime();
|
||||
const [files, cookieStr] = firstStep(ts, immucfg, mate);
|
||||
files.unshift('\n第1次请求:\n');
|
||||
const result = await getCode(mate.url, cookieStr);
|
||||
files.push('\n第2次请求:\n', ...secondStep(result.$_ts, adapt(result, gv.argv.adapt), result));
|
||||
files.forEach(({ filepath, text, code }) => filepath && fs.writeFileSync(filepath, text || code));
|
||||
logger.info([
|
||||
`代码还原成功!用时:${new Date().getTime() - startTime}ms\n`,
|
||||
...files.reduce((ans, it, idx) => ([...ans, typeof it === 'string' ? it : `${it.desc}${it.filepath}${idx === files.length - 1 || it.newLine ? '\n' : ''}`]), []),
|
||||
].join('\n '));
|
||||
}
|
||||
|
||||
|
@ -39,7 +39,7 @@ module.exports = function (ts, immucfg) {
|
||||
const coder = new Coder(ts, immucfg);
|
||||
const { code, $_ts } = coder.run();
|
||||
const r2mkaText = parseR2mka(coder.r2mkaText);
|
||||
const cookie = new Cookie($_ts, r2mkaText).run();
|
||||
const cookie = new Cookie($_ts, r2mkaText, coder, code).run();
|
||||
if (gv.metaContent) {
|
||||
logger.info(`存在meta-content值:${gv.metaContent.content} 解析结果:${gv.metaContent.value}`);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"
|
||||
// process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"
|
||||
const { request, cookieJar } = require('./request');
|
||||
const cheerio = require('cheerio');
|
||||
const isValidUrl = require('./isValidUrl');
|
||||
@ -7,7 +7,7 @@ const urlresolve = require('url').resolve;
|
||||
|
||||
function addRequestHead(uri) {
|
||||
return {
|
||||
proxy: 'http://127.0.0.1:8888',
|
||||
// proxy: 'http://127.0.0.1:8888',
|
||||
gzip: true,
|
||||
uri,
|
||||
resolveWithFullResponse: true,
|
||||
@ -22,45 +22,53 @@ function addRequestHead(uri) {
|
||||
}
|
||||
}
|
||||
|
||||
function nameHandle(name, extend) {
|
||||
return name.split('.').pop() === extend ? name : `${name}.${extend}`;
|
||||
}
|
||||
|
||||
module.exports = async function getCode(url, cookieStr) {
|
||||
if (cookieStr) {
|
||||
cookieJar.setCookie(request.cookie(cookieStr), url);
|
||||
console.log(`当前cookie:${cookieJar.getCookieString(url)}`);
|
||||
}
|
||||
if (!isValidUrl(url)) throw new Error('输入链接不正确');
|
||||
const res = await request(addRequestHead(url));
|
||||
const $ = cheerio.load(res.body);
|
||||
const scripts = [...$('script[r=m]')]
|
||||
const scripts = [...$('script')]
|
||||
const tsscript = scripts.map(ele => $(ele).text()).filter(text => text.includes('$_ts.nsd') && text.includes('$_ts.cd'));
|
||||
if (!tsscript.length) throw new Error(`${res.body}\n错误:链接返回结果未找到cd或nsd, 请检查!`);
|
||||
const $_ts = Function('window', tsscript[0] + 'return $_ts')({});
|
||||
$_ts.metaContent = _get($('meta[r=m]'), '0.attribs.content');
|
||||
const checkSrc = (src) => src?.split('.').pop() === 'js' ? src : undefined;
|
||||
const checkSrc = (src) => src?.split('.').pop().split('?')[0] === 'js' ? src : undefined;
|
||||
const remotes = scripts.map(it => checkSrc(it.attribs.src)).filter(Boolean);
|
||||
if (!remotes.length) throw new Error('未找到js外链,无法提取配置文本请检查!');
|
||||
for(let src of remotes) {
|
||||
const jscode = await request(addRequestHead(urlresolve(url, src)));
|
||||
if (jscode.body.includes('r2mKa')) return { $_ts, jscode: jscode.body, html: res.body, url };
|
||||
const ret = {
|
||||
$_ts,
|
||||
jscode: null,
|
||||
html: {
|
||||
code: res.body,
|
||||
url,
|
||||
name: nameHandle(url.split('?')[0].split('/').pop(), 'html'),
|
||||
desc: 'url方式提取的html代码:'
|
||||
},
|
||||
appcode: [],
|
||||
url,
|
||||
}
|
||||
for(let src of remotes) {
|
||||
const jsurl = urlresolve(url, src);
|
||||
const name = jsurl.split('?')[0].split('/').pop();
|
||||
const jscode = await request(addRequestHead(jsurl));
|
||||
const data = {
|
||||
code: jscode.body,
|
||||
url: jsurl,
|
||||
name: nameHandle(name, 'js'),
|
||||
desc: 'url方式提取的javascript代码:'
|
||||
};
|
||||
if (jscode.body.indexOf('$_ts.l__(') === 0) {
|
||||
ret.appcode.push(data);
|
||||
} else if (jscode.body.includes('r2mKa')) {
|
||||
ret.jscode = data;
|
||||
}
|
||||
}
|
||||
if (ret.jscode) return ret;
|
||||
throw new Error('js外链中没有瑞数的代码文件');
|
||||
}
|
||||
|
||||
// Host: wcjs.sbj.cnipa.gov.cn
|
||||
// Connection: keep-alive
|
||||
// Upgrade-Insecure-Requests: 1
|
||||
// sec-ch-ua: "Google Chrome";v="123", "Not:A-Brand";v="8", "Chromium";v="123"
|
||||
// sec-ch-ua-mobile: ?0
|
||||
// sec-ch-ua-platform: "macOS"
|
||||
// User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36
|
||||
// Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
|
||||
// Accept-Encoding: gzip, deflate, br, zstd
|
||||
// Accept-Language: zh-CN,zh;q=0.9
|
||||
// Sec-Fetch-Dest: document
|
||||
// Sec-Fetch-Mode: navigate
|
||||
//
|
||||
// Sec-Fetch-Site: none
|
||||
// Sec-Fetch-User: ?1
|
||||
//
|
||||
//
|
||||
// Sec-Fetch-Site: same-origin
|
||||
// Referer: https://wcjs.sbj.cnipa.gov.cn/sgtmi
|
||||
|
Loading…
x
Reference in New Issue
Block a user