mirror of
https://github.com/pysunday/rs-reverse.git
synced 2025-04-20 22:00:07 +08:00
commit
8dd6fee860
21
CHANGELOG.md
21
CHANGELOG.md
@ -1,5 +1,26 @@
|
|||||||
|
|
||||||
|
|
||||||
|
## [1.7.1](https://github.com/pysunday/rs-reverse/compare/1.7.0...1.7.1) (2024-04-10)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 拷贝目录报错修复 ([b8702c0](https://github.com/pysunday/rs-reverse/commit/b8702c0eeee0a32c11775af523c5e0ecb42fc5bc))
|
||||||
|
|
||||||
|
## [1.7.0](https://github.com/pysunday/rs-reverse/compare/1.6.0...1.7.0) (2024-04-10)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* 1. 增加makecode-high子命令 2. 增加basearr子命令 ([7757ad5](https://github.com/pysunday/rs-reverse/commit/7757ad59341e1278f1f3ea37f2c09fe6374c9193))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 1. exec命令适配版本;2. 新版cookie位数逻辑更新(无法过检测) ([ae822c7](https://github.com/pysunday/rs-reverse/commit/ae822c7a4dc908fe483d622ff4b391719b447703))
|
||||||
|
* 文档更新、代码优化 ([36848f8](https://github.com/pysunday/rs-reverse/commit/36848f8527ab954723dccb886b2931047c3c35a6))
|
||||||
|
* 更新readme ([4caaf73](https://github.com/pysunday/rs-reverse/commit/4caaf73979105168ecfedcf0279fde2d279290cf))
|
||||||
|
|
||||||
## [1.6.0](https://github.com/pysunday/rs-reverse/compare/1.5.1...1.6.0) (2024-03-28)
|
## [1.6.0](https://github.com/pysunday/rs-reverse/compare/1.5.1...1.6.0) (2024-03-28)
|
||||||
|
|
||||||
|
|
||||||
|
76
README.md
76
README.md
@ -10,12 +10,6 @@
|
|||||||
|
|
||||||
该项目的研究网站仅做参考,项目不鼓励直接请求该研究网站,算法逆向研究请直接使用`example`目录下的样例文件,如:`node main.js makecookie`(默认为最新版本代码)。
|
该项目的研究网站仅做参考,项目不鼓励直接请求该研究网站,算法逆向研究请直接使用`example`目录下的样例文件,如:`node main.js makecookie`(默认为最新版本代码)。
|
||||||
|
|
||||||
该瑞数cookie生成过程中的算法逆向存在以下变量:
|
|
||||||
|
|
||||||
1. 预先设置好的配置项,参见:`代码中config的值`;
|
|
||||||
2. 代码中的数字`46228`为作者代码格式化且代码修改后计算出来的方法字符串摘要值;
|
|
||||||
3. 代码中中的`_random(500, 1000)`为作者电脑运行计算的大概值,此值与浏览器运行环境有关(如电脑配置等);
|
|
||||||
|
|
||||||
## 1. 博客文章
|
## 1. 博客文章
|
||||||
|
|
||||||
1. [瑞数vmp-代码格式化后无法正常运行原因分析](https://howduudu.tech/#/blog/article/1699807978000)
|
1. [瑞数vmp-代码格式化后无法正常运行原因分析](https://howduudu.tech/#/blog/article/1699807978000)
|
||||||
@ -115,7 +109,67 @@ 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子命令用于开发中或者演示时使用。命令示例:
|
exec子命令用于开发中或者演示时使用。命令示例:
|
||||||
|
|
||||||
@ -154,10 +208,10 @@ Examples:
|
|||||||
|
|
||||||
适配文件配置在目录`./src/adapt/`下,已完成兼容配置:
|
适配文件配置在目录`./src/adapt/`下,已完成兼容配置:
|
||||||
|
|
||||||
网站 | 名称 | makecode | makecookie | 适配版本 | 是否逆向验证
|
网站 | 名称 | makecode | makecookie | makecode-high | 适配版本 | 是否逆向验证
|
||||||
---- | ---- | -------- | ---------- | -------- | --------------
|
---- | ---- | -------- | ---------- | ------------- | -------- | --------------
|
||||||
商标网 | cnipa | 👌 | 👌 | - | Y
|
商标网 | cnipa | 👌 | 👌 | 👌 | - | Y
|
||||||
瑞数官网 | riversecurity | 👌 | 👌 | 版本1 | N
|
瑞数官网 | riversecurity | 👌 | 👌 | N | 版本1 | N
|
||||||
|
|
||||||
以瑞数官网实例如:`npx rs-reverse makecookie -u https://www.riversecurity.com/resources.shtml -a riversecurity`
|
以瑞数官网实例如:`npx rs-reverse makecookie -u https://www.riversecurity.com/resources.shtml -a riversecurity`
|
||||||
|
|
||||||
|
37
main.js
37
main.js
@ -7,6 +7,7 @@ const fs = require('fs');
|
|||||||
const makeCode = require('@src/makeCode');
|
const makeCode = require('@src/makeCode');
|
||||||
const makeCodeHigh = require('@src/makeCodeHigh');
|
const makeCodeHigh = require('@src/makeCodeHigh');
|
||||||
const makeCookie = require('@src/makeCookie');
|
const makeCookie = require('@src/makeCookie');
|
||||||
|
const basearrParse = require('@src/basearrParse');
|
||||||
const utils = require('@utils/');
|
const utils = require('@utils/');
|
||||||
const { logger, getCode } = utils;
|
const { logger, getCode } = utils;
|
||||||
const pkg = require(paths.package);
|
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`));
|
const ts = argv.url?.$_ts || argv.file || require(paths.exampleResolve('codes', `${gv.version}-\$_ts.json`));
|
||||||
logger.trace(`传入的$_ts.nsd: ${ts.nsd}`);
|
logger.trace(`传入的$_ts.nsd: ${ts.nsd}`);
|
||||||
logger.trace(`传入的$_ts.cd: ${ts.cd}`);
|
logger.trace(`传入的$_ts.cd: ${ts.cd}`);
|
||||||
|
gv._setAttr('argv', argv);
|
||||||
try {
|
try {
|
||||||
if (argv.url) {
|
if (argv.url) {
|
||||||
command(ts, adapt(argv.url, argv.adapt), argv.url);
|
command(ts, adapt(argv.url, argv.adapt), argv.url);
|
||||||
@ -88,8 +90,15 @@ module.exports = yargs
|
|||||||
})
|
})
|
||||||
.command({
|
.command({
|
||||||
command: 'makecode-high',
|
command: 'makecode-high',
|
||||||
describe: '生成动态代码-高级',
|
describe: '解码两次请求返回的网站代码(功能涵盖makecode子命令)',
|
||||||
builder: commandBuilder,
|
builder: {
|
||||||
|
...commandBuilder,
|
||||||
|
f: undefined,
|
||||||
|
u: {
|
||||||
|
...commandBuilder.u,
|
||||||
|
demandOption: true,
|
||||||
|
}
|
||||||
|
},
|
||||||
handler: commandHandler.bind(null, makeCodeHigh),
|
handler: commandHandler.bind(null, makeCodeHigh),
|
||||||
})
|
})
|
||||||
.command({
|
.command({
|
||||||
@ -120,7 +129,7 @@ module.exports = yargs
|
|||||||
coerce: (input) => {
|
coerce: (input) => {
|
||||||
if (['1', '2'].includes(input)) {
|
if (['1', '2'].includes(input)) {
|
||||||
gv._setAttr('version', Number(input));
|
gv._setAttr('version', Number(input));
|
||||||
return paths.exampleResolve('codes', `${input}-\$_ts-full.json`);
|
return paths.exampleResolve('codes', `${input}-\$_ts.json`);
|
||||||
}
|
}
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
@ -131,10 +140,32 @@ module.exports = yargs
|
|||||||
Math.random = () => 0.1253744220839037;
|
Math.random = () => 0.1253744220839037;
|
||||||
const gv = require('@utils/initGv')(argv.file);
|
const gv = require('@utils/initGv')(argv.file);
|
||||||
Object.assign(global, gv.utils);
|
Object.assign(global, gv.utils);
|
||||||
|
Object.assign(global, require('@src/handler/viewer/'));
|
||||||
const output = JSON.stringify(eval(argv.code));
|
const output = JSON.stringify(eval(argv.code));
|
||||||
console.log([`\n 输入:${argv.code}`, `输出:${output}\n`].join('\n '));
|
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({
|
.updateStrings({
|
||||||
'Show version number': '显示版本号',
|
'Show version number': '显示版本号',
|
||||||
'Show help': '显示帮助信息',
|
'Show help': '显示帮助信息',
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "rs-reverse",
|
"name": "rs-reverse",
|
||||||
"version": "1.6.0",
|
"version": "1.7.1",
|
||||||
"description": "瑞数算法逆向,website reverse engineering",
|
"description": "瑞数算法逆向,website reverse engineering",
|
||||||
"main": "main.js",
|
"main": "main.js",
|
||||||
"directories": {
|
"directories": {
|
||||||
@ -29,7 +29,6 @@
|
|||||||
"README.md",
|
"README.md",
|
||||||
"utils",
|
"utils",
|
||||||
"main.js",
|
"main.js",
|
||||||
"test",
|
|
||||||
"src",
|
"src",
|
||||||
"example"
|
"example"
|
||||||
],
|
],
|
||||||
@ -40,11 +39,11 @@
|
|||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cheerio": "^1.0.0-rc.12",
|
"cheerio": "^1.0.0-rc.12",
|
||||||
|
"fs-extra": "^11.2.0",
|
||||||
"jest": "^29.7.0",
|
"jest": "^29.7.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"log4js": "^6.9.1",
|
"log4js": "^6.9.1",
|
||||||
"module-alias": "^2.2.3",
|
"module-alias": "^2.2.3",
|
||||||
"random-useragent": "^0.5.0",
|
|
||||||
"request": "^2.88.2",
|
"request": "^2.88.2",
|
||||||
"request-promise": "^4.2.6",
|
"request-promise": "^4.2.6",
|
||||||
"yargs": "^17.7.2"
|
"yargs": "^17.7.2"
|
||||||
|
@ -21,10 +21,10 @@ module.exports = function({ jscode, url }, name) {
|
|||||||
gv._setAttr('version', val);
|
gv._setAttr('version', val);
|
||||||
return ans;
|
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 (idx === -1) throw new Error(`${key}值数据未找到,请查看文档:src/adapt/readme.md`);
|
||||||
if (jscode.indexOf(val, idx + val.length) > -1) throw new Error(`${key}对应的值${val}在代码中非唯一,请检查!`);
|
if (jscode.code.indexOf(val, idx + val.length) > -1) throw new Error(`${key}对应的值${val}在代码中非唯一,请检查!`);
|
||||||
const fullString = findFullString(jscode, val);
|
const fullString = findFullString(jscode.code, val);
|
||||||
return { ...ans, [key]: fullString };
|
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(' ')}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
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.opdata = dataOper();
|
||||||
this.r2mkaText = null;
|
this.r2mkaText = null;
|
||||||
this.immucfg = immucfg || gv.config.immucfg;
|
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() {
|
run() {
|
||||||
@ -88,6 +91,7 @@ module.exports = class {
|
|||||||
this.gren(i, codeArr);
|
this.gren(i, codeArr);
|
||||||
}
|
}
|
||||||
codeArr.push('}}}}}}}}}}'.substr(opmate.getMateOri('G_$gG') - 1));
|
codeArr.push('}}}}}}}}}}'.substr(opmate.getMateOri('G_$gG') - 1));
|
||||||
|
this.mainFunctionIdx.push(codeArr.join('').length);
|
||||||
return codeArr;
|
return codeArr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,15 +137,21 @@ module.exports = class {
|
|||||||
opmate.setMate('_$$c');
|
opmate.setMate('_$$c');
|
||||||
opdata.setData('_$$k', func2(opmate.getMateOri('_$$c')));
|
opdata.setData('_$$k', func2(opmate.getMateOri('_$$c')));
|
||||||
if (current) {
|
if (current) {
|
||||||
|
if (this.mainFunctionIdx === null) this.mainFunctionIdx = [codeArr.join('').length];
|
||||||
codeArr.push("function ", opmate.getMate('_$jw'), "(", opmate.getMate('_$$6'));
|
codeArr.push("function ", opmate.getMate('_$jw'), "(", opmate.getMate('_$$6'));
|
||||||
opdata.getData('_$_K').forEach(it => codeArr.push(",", keynames[it]));
|
opdata.getData('_$_K').forEach(it => codeArr.push(",", keynames[it]));
|
||||||
codeArr.push("){");
|
codeArr.push("){");
|
||||||
} else {
|
} else {
|
||||||
codeArr.push("(function(", opmate.getMate('G_$dK'), ",", opmate.getMate('G_$kv'), "){var ", opmate.getMate('_$$6'), "=0;");
|
codeArr.push("(function(", opmate.getMate('G_$dK'), ",", opmate.getMate('G_$kv'), "){var ", opmate.getMate('_$$6'), "=0;");
|
||||||
}
|
}
|
||||||
opdata.getData('_$$w').forEach(([key1, key2]) => {
|
const functionsNameMap = opdata.getData('_$$w').reduce((ans, [key1, key2], idx) => {
|
||||||
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 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 => {
|
opdata.getData('_$cS').forEach(item => {
|
||||||
for (let i = 0; i < item.length - 1; i += 2) {
|
for (let i = 0; i < item.length - 1; i += 2) {
|
||||||
codeArr.push(keycodes[item[i]], keynames[item[i + 1]])
|
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(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("while(1){", opmate.getMate('_$cu'), "=", opmate.getMate('_$aw'), "[", opmate.getMate('_$ku'), "++];");
|
||||||
codeArr.push("if(", opmate.getMate('_$cu'), "<", opmate.getMateOri('_$bf'), "){");
|
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'), []);
|
const codelist = this.grenIfelse(0, opmate.getMateOri('_$bf'), []);
|
||||||
codeArr.push(...codelist);
|
codeArr.push(...codelist);
|
||||||
codeArr.push("}else ", ';', '}');
|
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) {
|
grenIfelse(start, end, codeArr) {
|
||||||
const { opdata, opmate } = this
|
const { opdata, opmate } = this
|
||||||
const arr8 = opdata.getData('arr8')
|
const arr8 = opdata.getData('arr8')
|
||||||
|
@ -1 +0,0 @@
|
|||||||
// 整站代码还原
|
|
@ -2,7 +2,6 @@ const _random = require('lodash/random');
|
|||||||
const dataOper = require('./dataOper');
|
const dataOper = require('./dataOper');
|
||||||
const parser = require('./parser/');
|
const parser = require('./parser/');
|
||||||
const gv = require('./globalVarible');
|
const gv = require('./globalVarible');
|
||||||
const randomUseragent = require('random-useragent');
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
factorial,
|
factorial,
|
||||||
@ -13,6 +12,7 @@ const {
|
|||||||
uuid,
|
uuid,
|
||||||
string2ascii,
|
string2ascii,
|
||||||
execRandomByNumber,
|
execRandomByNumber,
|
||||||
|
execNumberByTime,
|
||||||
hexnum,
|
hexnum,
|
||||||
ascii2string,
|
ascii2string,
|
||||||
getFixedNumber,
|
getFixedNumber,
|
||||||
@ -28,13 +28,20 @@ const {
|
|||||||
runTask,
|
runTask,
|
||||||
} = parser;
|
} = parser;
|
||||||
|
|
||||||
|
const developConfig = {
|
||||||
|
// 开发时用的配置,比如时间值固定、随机数固定等
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = class {
|
module.exports = class {
|
||||||
constructor(ts, r2mkaText) {
|
constructor(ts, r2mkaText, coder, vmcode) {
|
||||||
|
this.coder = coder;
|
||||||
|
this.vmcode = vmcode;
|
||||||
parser.init(ts, r2mkaText)
|
parser.init(ts, r2mkaText)
|
||||||
|
const current = new Date().getTime() + 1000;
|
||||||
this.config = {
|
this.config = {
|
||||||
'window.navigator.maxTouchPoints': 0,
|
'window.navigator.maxTouchPoints': 0,
|
||||||
'window.eval.toString().length': 33,
|
'window.eval.toString().length': 33,
|
||||||
'window.navigator.userAgent': randomUseragent.getRandom(),
|
'window.navigator.userAgent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36',
|
||||||
'window.navigator.platform': 'MacIntel',
|
'window.navigator.platform': 'MacIntel',
|
||||||
'window.name': '$_YWTU=LjFNq_oZCsth6KJ9xHOin6RRhL4fQt7Vsn8YCz9dRjl&$_YVTX=Wa&vdFm=_$hh',
|
'window.name': '$_YWTU=LjFNq_oZCsth6KJ9xHOin6RRhL4fQt7Vsn8YCz9dRjl&$_YVTX=Wa&vdFm=_$hh',
|
||||||
'window.navigator.battery': {
|
'window.navigator.battery': {
|
||||||
@ -53,46 +60,53 @@ module.exports = class {
|
|||||||
'window.innerWidth': 1680,
|
'window.innerWidth': 1680,
|
||||||
'window.outerHeight': 1025,
|
'window.outerHeight': 1025,
|
||||||
'window.outerWidth': 1680,
|
'window.outerWidth': 1680,
|
||||||
|
'window.document.hidden': false,
|
||||||
|
formatUid: 46228, // 代码特征码
|
||||||
|
currentTime: current, // 完整的时间戳
|
||||||
|
runTime: Math.floor(current / 1000), // 运行时间
|
||||||
|
startTime: Math.floor(current / 1000) - 1, // 模拟浏览器启动时间
|
||||||
|
r2mkaTime: +ascii2string(gv.keys[21]), // r2mka文本解析出来的时间
|
||||||
|
random: null, // 代替Math.random方法返回值
|
||||||
|
// execNumberByTime: execNumberByTime(), // 固定时间内的循环运行次数
|
||||||
|
execNumberByTime: _random(1500, 2000), // 固定时间内的循环运行次数
|
||||||
|
...developConfig,
|
||||||
}
|
}
|
||||||
this.runTime = Math.floor(new Date().getTime() / 1000); // 运行时间
|
// console.log(this.config);
|
||||||
this.startTime = this.runTime - 1; // 模拟浏览器启动时间
|
|
||||||
this.r2mkaTime = +ascii2string(gv.keys[21]); // r2mka文本解析出来的时间
|
|
||||||
}
|
}
|
||||||
|
|
||||||
run() {
|
run() {
|
||||||
|
const basearr = this[`getBasearr_v${gv.version}`]();
|
||||||
|
const nextarr = numarrJoin(
|
||||||
|
numarrJoin(
|
||||||
|
2,
|
||||||
|
numToNumarr4([this.config.r2mkaTime, this.config.startTime]),
|
||||||
|
gv.keys[2]
|
||||||
|
),
|
||||||
|
encryptMode1(
|
||||||
|
xor(
|
||||||
|
numarrEncrypt(basearr),
|
||||||
|
gv.keys[2],
|
||||||
|
16
|
||||||
|
),
|
||||||
|
numarrAddTime(gv.keys[17], this.config.runTime, this.config.random)[0],
|
||||||
|
0
|
||||||
|
)
|
||||||
|
)
|
||||||
return '0' + numarr2string(
|
return '0' + numarr2string(
|
||||||
encryptMode1([
|
encryptMode1(
|
||||||
...numToNumarr4(this.r2mkaTime),
|
[
|
||||||
...numarrJoin(
|
...numToNumarr4(uuid(nextarr)),
|
||||||
numarrJoin(
|
...nextarr
|
||||||
gv.r2mka("0>one>32-126").taskarr[73],
|
],
|
||||||
numarrJoin(
|
numarrAddTime(gv.keys[16], this.config.runTime, this.config.random)[0],
|
||||||
numToNumarr4([this.r2mkaTime, this.startTime]),
|
1,
|
||||||
string2ascii(gv.cp0[399])
|
this.config.random
|
||||||
),
|
|
||||||
gv.keys[2]
|
|
||||||
),
|
|
||||||
encryptMode1(
|
|
||||||
xor(
|
|
||||||
numarrEncrypt(this[`getBasearr_v${gv.version}`]()),
|
|
||||||
gv.keys[2],
|
|
||||||
16
|
|
||||||
),
|
|
||||||
numarrAddTime(gv.keys[17], this.runTime)[0],
|
|
||||||
0
|
|
||||||
)
|
|
||||||
)],
|
|
||||||
numarrAddTime(gv.keys[16], this.runTime)[0]
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getBasearr_v2() {
|
getBasearr_v2() {
|
||||||
// 第2版计算cookie方法
|
// 第2版计算cookie基础数组,cookie位数257位(当gv.keys[22]存在值)
|
||||||
const name = this.config['window.name'].split('&').reduce((ans, it) => {
|
|
||||||
const [key, val] = it.split('=');
|
|
||||||
return { ...ans, [key]: val };
|
|
||||||
}, {});
|
|
||||||
return numarrJoin(
|
return numarrJoin(
|
||||||
3,
|
3,
|
||||||
numarrJoin(
|
numarrJoin(
|
||||||
@ -102,8 +116,8 @@ module.exports = class {
|
|||||||
128,
|
128,
|
||||||
...numToNumarr4(uuid(this.config['window.navigator.userAgent'])),
|
...numToNumarr4(uuid(this.config['window.navigator.userAgent'])),
|
||||||
string2ascii(this.config['window.navigator.platform']),
|
string2ascii(this.config['window.navigator.platform']),
|
||||||
...numToNumarr4(_random(500, 1000)),
|
...numToNumarr4(this.config.execNumberByTime),
|
||||||
...execRandomByNumber(),
|
...execRandomByNumber(98, this.config.random),
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
...numToNumarr4(Number(hexnum('3136373737323136'))),
|
...numToNumarr4(Number(hexnum('3136373737323136'))),
|
||||||
@ -114,50 +128,67 @@ module.exports = class {
|
|||||||
...numToNumarr2(this.config['window.outerWidth']),
|
...numToNumarr2(this.config['window.outerWidth']),
|
||||||
),
|
),
|
||||||
10, // 下标43
|
10, // 下标43
|
||||||
[
|
(() => {
|
||||||
0, // 运行时代码中传入的初始数组长度,由于传入的是空数组,因此为0
|
const flag = +ascii2string(gv.keys[24]);
|
||||||
1, // 任务编号0>one>36>one>2-131的任务列表取得
|
return [
|
||||||
...numToNumarr4(this.r2mkaTime + this.runTime - this.startTime), // ramka串返回的时间 + 当前时间 - 启动时间
|
flag > 0 && flag < 8 ? 1 : 0,
|
||||||
...numToNumarr4(+ascii2string(gv.keys[19])),
|
13,
|
||||||
...numToNumarr8(Math.floor(Math.random() * 1048575) * 4294967296 + (((this.runTime * 1000) & 4294967295) >>> 0)),
|
...numToNumarr4(this.config.r2mkaTime + this.config.runTime - this.config.startTime), // ramka串返回的时间 + 当前时间 - 启动时间
|
||||||
],
|
...numToNumarr4(+ascii2string(gv.keys[19])),
|
||||||
7, // 下标63
|
...numToNumarr8(Math.floor((this.config.random || Math.random()) * 1048575) * 4294967296 + (((this.config.currentTime + 1) & 4294967295) >>> 0)),
|
||||||
|
flag,
|
||||||
|
];
|
||||||
|
})(),
|
||||||
|
7, // 下标64
|
||||||
[
|
[
|
||||||
...numToNumarr4(16777216), // gv.cp2取得
|
...numToNumarr4(16777216), // gv.cp2取得
|
||||||
...numToNumarr4(0), // 任务编号0-0的任务列表取得
|
...numToNumarr4(0), // 任务编号0-0的任务列表取得
|
||||||
...numToNumarr2(getFixedNumber()), // 固定值5900
|
...numToNumarr2(getFixedNumber()), // 固定值5900
|
||||||
...numToNumarr2(46228), // 根据方法的toString()计算
|
...this.getCodeUid(),
|
||||||
],
|
],
|
||||||
0, // 任务编号0>one>63-287的任务列表取得
|
0, // 任务编号0>one>63-287的任务列表取得
|
||||||
[0], // 任务编号0>one>63>one>4-290的任务列表取得
|
[0], // 任务编号0>one>63>one>4-290的任务列表取得
|
||||||
6, // 下标80
|
6, // 下标81
|
||||||
[ // 编号510方法执行返回
|
[ // 编号510方法执行返回
|
||||||
1,
|
1,
|
||||||
...numToNumarr2(0),
|
...numToNumarr2(0),
|
||||||
...numToNumarr2(0),
|
...numToNumarr2(0),
|
||||||
0,
|
this.config['window.document.hidden'] ? 0 : 1,
|
||||||
...encryptMode2(decrypt(name.$_YWTU || ''), numarrAddTime(gv.keys[16])[0]),
|
...encryptMode2(decrypt(ascii2string(gv.keys[22])), numarrAddTime(gv.keys[16])[0]),
|
||||||
...numToNumarr2(+decode(decrypt(name.$_YVTX || ''))),
|
...numToNumarr2(+decode(decrypt(ascii2string(gv.keys[22])))),
|
||||||
],
|
|
||||||
2, // 下标98
|
|
||||||
[
|
|
||||||
factorial(5) - factorial(3) * 2 + 100, // 100是cp2里取出来的,可能随版本变动
|
|
||||||
203, // cp2[76],检测window.HTMLFormElement是否存在
|
|
||||||
102, // cp2[120],检测document.createElement('from')
|
|
||||||
103, // 检测window.top值是否为null
|
|
||||||
],
|
|
||||||
9, // 下标104
|
|
||||||
[
|
|
||||||
0 | 8, // 8为cp2中的值
|
|
||||||
['bluetooth', 'cellular', 'ethernet', 'wifi', 'wimax'].indexOf(this.config['window.navigator.connection'].type) + 1,
|
|
||||||
],
|
],
|
||||||
|
2, // 下标99
|
||||||
|
(() => {
|
||||||
|
const taskmap = {}
|
||||||
|
runTask('0>one>71>one>4-342', [taskmap]);
|
||||||
|
return [29, 30, 31, 32].map(it => {
|
||||||
|
return taskmap[ascii2string(gv.keys[it])]();
|
||||||
|
})
|
||||||
|
})(),
|
||||||
|
9, // 下标105
|
||||||
|
(() => { // 编号133方法
|
||||||
|
const { connType } = this.config['window.navigator.connection'];
|
||||||
|
const { charging, chargingTime, level } = this.config['window.navigator.battery']
|
||||||
|
const connTypeIdx = ['bluetooth', 'cellular', 'ethernet', 'wifi', 'wimax'].indexOf(connType) + 1;
|
||||||
|
let oper = 0;
|
||||||
|
if (level) oper |= 2;
|
||||||
|
if (charging) oper |= 1;
|
||||||
|
if (connTypeIdx !== undefined) oper |= 8
|
||||||
|
return [
|
||||||
|
oper,
|
||||||
|
level * 100,
|
||||||
|
chargingTime >> 8,
|
||||||
|
chargingTime & 255,
|
||||||
|
connTypeIdx,
|
||||||
|
]
|
||||||
|
})(),
|
||||||
13,
|
13,
|
||||||
[0],
|
[0],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
getBasearr_v1() {
|
getBasearr_v1() {
|
||||||
// 第1版计算cookie方法
|
// 第1版计算cookie基础数组,cookie位数236位
|
||||||
const { getTaskNumber: gtn } = this;
|
const { getTaskNumber: gtn } = this;
|
||||||
return numarrJoin(
|
return numarrJoin(
|
||||||
3,
|
3,
|
||||||
@ -239,4 +270,13 @@ module.exports = class {
|
|||||||
getTaskNumber(name, idx) {
|
getTaskNumber(name, idx) {
|
||||||
return gv.r2mka(name).taskarr[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;
|
return cache.keys;
|
||||||
}
|
}
|
||||||
|
get argv() {
|
||||||
|
// 命令调用参数
|
||||||
|
return cache.argv;
|
||||||
|
}
|
||||||
_getAttr(attr) {
|
_getAttr(attr) {
|
||||||
return cache[attr];
|
return cache[attr];
|
||||||
}
|
}
|
||||||
|
@ -1,72 +0,0 @@
|
|||||||
const gv = require('@src/handler/globalVarible');
|
|
||||||
const monitor = require('@utils/monitor');
|
|
||||||
const logger = require('@utils/logger');
|
|
||||||
|
|
||||||
module.exports = function(...params) {
|
|
||||||
logger.trace('执行开始!');
|
|
||||||
try {
|
|
||||||
return dynamicExec(...params);
|
|
||||||
} catch (err) {
|
|
||||||
logger.error(String(err));
|
|
||||||
throw err;
|
|
||||||
} finally {
|
|
||||||
logger.trace('执行结束!');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function dynamicExec(taskItem, start = 0, args = [], loop_res = {}, global_res = {}) {
|
|
||||||
const codemap = gv.config.codemap;
|
|
||||||
const { key, taskarr: task } = taskItem;
|
|
||||||
args = monitor(args, `${key}_args`, { getLog: true, setLog: true });
|
|
||||||
loop_res = monitor(loop_res, `${key}_loop_res`, { getLog: true, setLog: true });
|
|
||||||
global_res = monitor(global_res, `${key}_global_res`, { getLog: true, setLog: true });
|
|
||||||
logger.trace(`动态代码运行,任务列表:${key}, 起点:${start},长度:${task.length}`);
|
|
||||||
const data = [];
|
|
||||||
const ret = [];
|
|
||||||
ret[0] = args;
|
|
||||||
ret[2] = [ 'window', args ];
|
|
||||||
const vars = [
|
|
||||||
`${codemap.params[0]} = taskItem`,
|
|
||||||
`${codemap.params[1]} = start`,
|
|
||||||
`${codemap.params[2]} = task.length`,
|
|
||||||
`${codemap.params[3]} = ret`,
|
|
||||||
// 任务列表
|
|
||||||
`${codemap.taskarr} = taskItem.taskarr`,
|
|
||||||
// 数据数组
|
|
||||||
`${codemap.dataKey} = data`,
|
|
||||||
// 数据数组游标
|
|
||||||
`${codemap.dataIdx} = 0`,
|
|
||||||
`${codemap.ret0} = ret[0]`,
|
|
||||||
`${codemap.ret1} = ret[1]`,
|
|
||||||
`${codemap.ret2} = ret[2]`,
|
|
||||||
`${codemap.ret3} = ret[3]`,
|
|
||||||
// 全局资源
|
|
||||||
`${codemap.globalRes} = global_res`,
|
|
||||||
// 本地资源
|
|
||||||
`${codemap.loopRes} = loop_res`,
|
|
||||||
`${codemap.forcur} = start`,
|
|
||||||
`${codemap.formax} = task.length`,
|
|
||||||
...codemap.varible,
|
|
||||||
].join(', ');
|
|
||||||
eval(`var ${vars};${codemap.commonFunc}`)
|
|
||||||
for (let t_cursor = start, idx = 0; t_cursor < task.length; t_cursor++) {
|
|
||||||
idx ++;
|
|
||||||
if (typeof codemap[task[t_cursor]] !== 'string') {
|
|
||||||
logger.error(`codemap中下标${task[t_cursor]}不存在值!`)
|
|
||||||
} else {
|
|
||||||
eval(`${codemap.forcur}=t_cursor`);
|
|
||||||
codemap[task[t_cursor]].split(';').map(it => it.trim()).forEach(c => {
|
|
||||||
try {
|
|
||||||
eval(c);
|
|
||||||
} catch(err) {
|
|
||||||
logger.error(`代码: ${c} 执行失败,当前任务:${taskItem.key}`)
|
|
||||||
debugger;
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
eval(`t_cursor=${codemap.forcur}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret[5];
|
|
||||||
}
|
|
||||||
|
|
@ -21,7 +21,6 @@ module.exports = {
|
|||||||
numarrEncrypt: require('./numarrEncrypt'),
|
numarrEncrypt: require('./numarrEncrypt'),
|
||||||
numarr2string: require('./numarr2string'),
|
numarr2string: require('./numarr2string'),
|
||||||
numarrJoin: require('./numarrJoin'),
|
numarrJoin: require('./numarrJoin'),
|
||||||
dynamicExec: require('./dynamicExec'),
|
|
||||||
numarrAlterByNumber: require('./numarrAlterByNumber'),
|
numarrAlterByNumber: require('./numarrAlterByNumber'),
|
||||||
runTask: require('./runTask'),
|
runTask: require('./runTask'),
|
||||||
}
|
}
|
||||||
|
@ -56,14 +56,14 @@ function getCfg(numarr) {
|
|||||||
return [ret, arr];
|
return [ret, arr];
|
||||||
}
|
}
|
||||||
|
|
||||||
function encryptMode1(valarr, keyarr, flag = 1) {
|
function encryptMode1(valarr, keyarr, flag = 1, random) {
|
||||||
const cfg = getCfg(keyarr);
|
const cfg = getCfg(keyarr);
|
||||||
var _$iv, _$j7, _$kb, _$ka, _$dV, _$du, _$jb;
|
var _$iv, _$j7, _$kb, _$ka, _$dV, _$du, _$jb;
|
||||||
const max = Math.floor(valarr.length / 16) + 1;
|
const max = Math.floor(valarr.length / 16) + 1;
|
||||||
let ans = [], arr;
|
let ans = [], arr;
|
||||||
const fill = 16 - valarr.length % 16;
|
const fill = 16 - valarr.length % 16;
|
||||||
if (flag) {
|
if (flag) {
|
||||||
ans = arr = new Array(4).fill(4294967295).map(it => Math.floor(Math.random() * it));
|
ans = arr = new Array(4).fill(4294967295).map(it => Math.floor((random || Math.random()) * it));
|
||||||
}
|
}
|
||||||
const copyarr = numToNumarr4.reverse_sign([...valarr, ...new Array(fill).fill(fill)]);
|
const copyarr = numToNumarr4.reverse_sign([...valarr, ...new Array(fill).fill(fill)]);
|
||||||
for (let i = 0; i < max; ) {
|
for (let i = 0; i < max; ) {
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
const gv = require('@src/handler/globalVarible');
|
const gv = require('@src/handler/globalVarible');
|
||||||
const numToNumarr4 = require('./numToNumarr4');
|
const numToNumarr4 = require('./numToNumarr4');
|
||||||
|
|
||||||
module.exports = function(numarr, time) {
|
module.exports = function(numarr, time, random) {
|
||||||
// time为时间戳除以1000后向上取整,如果不传则取当前时间戳
|
// time为时间戳除以1000后向上取整,如果不传则取当前时间戳
|
||||||
const ele = Math.ceil(Math.random() * 256);
|
const ele = Math.ceil((random || Math.random()) * 256);
|
||||||
const now = time || Math.floor(new Date().getTime() / 1000);
|
const now = time || Math.floor(new Date().getTime() / 1000);
|
||||||
const arr = [...numarr, ...numToNumarr4(now)].map(it => it ^ ele);
|
const arr = [...numarr, ...numToNumarr4(now)].map(it => it ^ ele);
|
||||||
arr.push(ele);
|
arr.push(ele);
|
||||||
|
@ -10,11 +10,11 @@ exports.execNumberByTime = function (times = 3) {
|
|||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.execRandomByNumber = function (nums = 98) {
|
exports.execRandomByNumber = function (nums = 98, random) {
|
||||||
// 指定次数的随机数取平均值后四舍五入
|
// 指定次数的随机数取平均值后四舍五入
|
||||||
if (typeof nums !== 'number') return;
|
if (typeof nums !== 'number') return;
|
||||||
const arr = []
|
const arr = []
|
||||||
for (let i = 0; i < nums; i++) arr.push(Math.random());
|
for (let i = 0; i < nums; i++) arr.push(random || Math.random());
|
||||||
const avg = _sum(arr) / nums;
|
const avg = _sum(arr) / nums;
|
||||||
return [
|
return [
|
||||||
avg * 100,
|
avg * 100,
|
||||||
|
@ -1,45 +1,138 @@
|
|||||||
// 直接通过动态代码执行来运行任务
|
// 直接通过动态代码执行来运行任务
|
||||||
// 该方法并未完全还原,谨慎使用
|
// 该方法并未完全还原,谨慎使用
|
||||||
const gv = require('@src/handler/globalVarible');
|
const gv = require('@src/handler/globalVarible');
|
||||||
const dynamicExec = require('./dynamicExec');
|
const monitor = require('@utils/monitor');
|
||||||
|
const logger = require('@utils/logger');
|
||||||
const custask = require('../task');
|
const custask = require('../task');
|
||||||
const error = require('@utils/error');
|
const error = require('@utils/error');
|
||||||
const logger = require('@utils/logger');
|
|
||||||
|
|
||||||
module.exports = function(taskid, args, allowTask) {
|
module.exports = function(task, args, allowTask) {
|
||||||
// taskid为任务id,allowTask为允许执行的任务
|
if (typeof task === 'string') task = gv.r2mka(task);
|
||||||
const task = gv.r2mka(taskid);
|
if (!task) throw new Error('任务未找到');
|
||||||
if (!task) {
|
logger.debug(`${task.key}执行开始!`);
|
||||||
error(`任务未找到`, { taskid });
|
try {
|
||||||
}
|
const global_res = new Proxy({}, {
|
||||||
const global_res = new Proxy({}, {
|
get(target, property, receiver) {
|
||||||
get(target, property, receiver) {
|
// 由于每个版本下标都会变,在解析cd值生成8位偏移数的时候只用到了cp2数组,因此这里只返回cp2,需要注意!
|
||||||
// 由于每个版本下标都会变,在解析cd值生成8位偏移数的时候只用到了cp2数组,因此这里只返回cp2,需要注意!
|
logger.debug(`global_res 获取下标: ${property}`);
|
||||||
logger.debug(`global_res 获取下标: ${property}`);
|
return gv.cp2;
|
||||||
return gv.cp2;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
const loop_res = new Proxy([], {
|
|
||||||
get(target, key, receiver) {
|
|
||||||
const child = gv.r2mka().child_one;
|
|
||||||
if (Number(key) < child.length) {
|
|
||||||
const current = child[key];
|
|
||||||
if (!key) return current;
|
|
||||||
return (...params) => {
|
|
||||||
if (custask[current.key]) {
|
|
||||||
// 自定义任务
|
|
||||||
return custask[current.key](...params);
|
|
||||||
}
|
|
||||||
if (allowTask && !allowTask[key]) {
|
|
||||||
error('当前任务未在允许列表!', { key: current.key });
|
|
||||||
}
|
|
||||||
return dynamicExec(current, 0, params, loop_res, global_res);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (gv.config.offsetConst[key]) return gv.config.offsetConst[key];
|
})
|
||||||
error('loop_res取值未找到', { key });
|
const loop_res = new Proxy([], {
|
||||||
}
|
get(target, key, receiver) {
|
||||||
})
|
const child = gv.r2mka().child_one;
|
||||||
return dynamicExec(task, 0, args, loop_res, global_res);
|
if (Number(key) < child.length) {
|
||||||
|
const current = child[key];
|
||||||
|
if (!key) return current;
|
||||||
|
return (...params) => {
|
||||||
|
if (custask[current.key]) {
|
||||||
|
// 自定义任务
|
||||||
|
return custask[current.key](...params);
|
||||||
|
}
|
||||||
|
if (allowTask && !allowTask[key]) {
|
||||||
|
error('当前任务未在允许列表!', { key: current.key });
|
||||||
|
}
|
||||||
|
return dynamicExec(current, 0, params, loop_res, global_res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (gv.config.offsetConst[key]) return gv.config.offsetConst[key];
|
||||||
|
error('loop_res取值未找到', { key });
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return dynamicExec(task, 0, args, loop_res, global_res);
|
||||||
|
} catch (err) {
|
||||||
|
logger.error(String(err));
|
||||||
|
throw err;
|
||||||
|
} finally {
|
||||||
|
logger.debug(`${task.key}执行结束!`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function taskFactory(task, args) {
|
||||||
|
return (...params) => {
|
||||||
|
if (custask[task.key]) return custask[task.key](...params);
|
||||||
|
return module.exports(task, params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getParentSubTask(task, loopRes) {
|
||||||
|
const subTask = [];
|
||||||
|
if (!task) debugger;
|
||||||
|
while (task.isReset === 0 && task.key !== '0-0') {
|
||||||
|
subTask.push(['window', 'args', ...task.child_one.slice(2).map(it => taskFactory(it))]);
|
||||||
|
task = task.parent;
|
||||||
|
}
|
||||||
|
return [loopRes, ...subTask.reverse()];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function dynamicExec(taskItem, start = 0, args = [], loop_res = {}, global_res = {}) {
|
||||||
|
const codemap = gv.config.codemap;
|
||||||
|
const { key, taskarr: task } = taskItem;
|
||||||
|
args = monitor(args, `${key}_args`, { getLog: true, setLog: true });
|
||||||
|
loop_res = monitor(loop_res, `${key}_loop_res`, { getLog: true, setLog: true });
|
||||||
|
global_res = monitor(global_res, `${key}_global_res`, { getLog: true, setLog: true });
|
||||||
|
logger.debug(`动态代码运行,任务列表:${key}, 起点:${start},长度:${task.length}`);
|
||||||
|
const data = [];
|
||||||
|
const ret = [];
|
||||||
|
ret[0] = args;
|
||||||
|
ret[2] = [ 'window', args ];
|
||||||
|
ret[3] = getParentSubTask(taskItem.parent, loop_res);
|
||||||
|
const taskItemProxy = new Proxy({}, {
|
||||||
|
get(target, property, receiver) {
|
||||||
|
const idx = codemap.taskAttr.indexOf(property);
|
||||||
|
if (idx === -1) debugger;
|
||||||
|
const name = ['lens', 'isReset', 'taskarr', 'child_one', 'child_two'][idx];
|
||||||
|
if (!name) debugger;
|
||||||
|
return taskItem[name];
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const vars = [
|
||||||
|
`${codemap.params[0]} = taskItemProxy`,
|
||||||
|
`${codemap.params[1]} = start`,
|
||||||
|
`${codemap.params[2]} = task.length`,
|
||||||
|
`${codemap.params[3]} = ret`,
|
||||||
|
// 任务工厂函数
|
||||||
|
`${codemap.taskFactory} = taskFactory`,
|
||||||
|
`${codemap.keyname} = gv.ts.cp[1]`,
|
||||||
|
// 任务列表
|
||||||
|
`${codemap.taskarr} = task`,
|
||||||
|
// 数据数组
|
||||||
|
`${codemap.dataKey} = data`,
|
||||||
|
// 数据数组游标
|
||||||
|
`${codemap.dataIdx} = 0`,
|
||||||
|
`${codemap.ret0} = ret[0]`,
|
||||||
|
`${codemap.ret1} = ret[1]`,
|
||||||
|
`${codemap.ret2} = ret[2]`,
|
||||||
|
`${codemap.ret3} = ret[3]`,
|
||||||
|
// 全局资源
|
||||||
|
`${codemap.globalRes} = global_res`,
|
||||||
|
// 本地资源
|
||||||
|
`${codemap.loopRes} = loop_res`,
|
||||||
|
`${codemap.forcur} = start`,
|
||||||
|
`${codemap.formax} = task.length`,
|
||||||
|
...codemap.varible,
|
||||||
|
].join(', ');
|
||||||
|
eval(`var ${vars};${codemap.commonFunc}`)
|
||||||
|
for (let t_cursor = start, idx = 0; t_cursor < task.length; t_cursor++) {
|
||||||
|
idx ++;
|
||||||
|
if (typeof codemap[task[t_cursor]] !== 'string') {
|
||||||
|
logger.error(`codemap中下标${task[t_cursor]}不存在值!`)
|
||||||
|
} else {
|
||||||
|
logger.debug(`(${key}, ${idx})执行代码:${codemap[task[t_cursor]]}`);
|
||||||
|
eval(`${codemap.forcur}=t_cursor`);
|
||||||
|
codemap[task[t_cursor]].split(';').map(it => it.trim()).forEach(c => {
|
||||||
|
try {
|
||||||
|
eval(c);
|
||||||
|
} catch(err) {
|
||||||
|
logger.error(`代码: ${c} 执行失败,当前任务:${key}`)
|
||||||
|
debugger;
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
eval(`t_cursor=${codemap.forcur}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret[5];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -27,8 +27,9 @@ function gtHandler(str, curr) {
|
|||||||
const parse = (() => {
|
const parse = (() => {
|
||||||
let count = 0;
|
let count = 0;
|
||||||
const valMap = {};
|
const valMap = {};
|
||||||
return function(val, deep = 0, deeps = [0]) {
|
return function(val, deep = 0, deeps = [0], parent = null) {
|
||||||
const str = val.taskstr;
|
const str = val.taskstr;
|
||||||
|
val.parent = parent;
|
||||||
val.taskstr = str;
|
val.taskstr = str;
|
||||||
val.val = {};
|
val.val = {};
|
||||||
if (!str) {
|
if (!str) {
|
||||||
@ -41,12 +42,12 @@ const parse = (() => {
|
|||||||
valMap[val.key] = val;
|
valMap[val.key] = val;
|
||||||
val.child_one.map((it, idx) => {
|
val.child_one.map((it, idx) => {
|
||||||
if (it) {
|
if (it) {
|
||||||
parse(it, deep + 1, [...deeps, 'one', idx]);
|
parse(it, deep + 1, [...deeps, 'one', idx], val);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
val.child_two.map((it, idx) => {
|
val.child_two.map((it, idx) => {
|
||||||
if (it) {
|
if (it) {
|
||||||
parse(it, deep + 1, [...deeps, 'two', idx]);
|
parse(it, deep + 1, [...deeps, 'two', idx], val);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return (key) => {
|
return (key) => {
|
||||||
|
@ -1,12 +1,29 @@
|
|||||||
const gv = require('@src/handler/globalVarible');
|
const gv = require('@src/handler/globalVarible');
|
||||||
|
|
||||||
// 预期任务作用,实际还没有用到,需要多版本对比
|
/*
|
||||||
const expectTask = {
|
* 1. 0>one>71>one>4>two>2-348与0>one>71>one>4>two>12-358返回值来源一致
|
||||||
'0>one>71>one>4>one>3-344': '计算阶乘'
|
*/
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
'0>one>21-23': (num) => {
|
'0>one>21-23': (num) => {
|
||||||
return Math.abs(num) % 8;
|
return Math.abs(num) % 8;
|
||||||
},
|
},
|
||||||
|
'0>one>71>one>4>two>2-348': () => {
|
||||||
|
// 该任务首先检测document.createElement('a')是否能成功,成功则返回gv.cp2中的固定值
|
||||||
|
return 102;
|
||||||
|
},
|
||||||
|
'0>one>71>one>4>two>12-358': () => {
|
||||||
|
// 该任务首先检测document.createElement('form')是否能成功,成功则返回gv.cp2中的固定值
|
||||||
|
return 102;
|
||||||
|
},
|
||||||
|
'0>one>71>one>4>two>4-350': () => {
|
||||||
|
// 该任务首先检测window.navigator.userAgent是否为string格式,是的话进行计算后返回
|
||||||
|
// **需要注意是否返回同一值**
|
||||||
|
return 224;
|
||||||
|
},
|
||||||
|
'0>one>71>one>4>two>14-360': () => {
|
||||||
|
// 该任务首先检测window.navigator.userAgent是否为string格式,是的话进行计算后返回
|
||||||
|
// **需要注意是否返回同一值**
|
||||||
|
return 225;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
14
src/handler/viewer/dkeys.js
Normal file
14
src/handler/viewer/dkeys.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// 遇到的gv.keys使用放在这里方便归档查阅
|
||||||
|
const gv = require('@src/handler/globalVarible');
|
||||||
|
|
||||||
|
exports.dkeys = function () {
|
||||||
|
return {
|
||||||
|
7: gv.utils.ascii2string(gv.keys[7]).split(';'),
|
||||||
|
22: gv.utils.ascii2string(gv.keys[22]),
|
||||||
|
29: gv.utils.ascii2string(gv.keys[29]),
|
||||||
|
30: gv.utils.ascii2string(gv.keys[30]),
|
||||||
|
31: gv.utils.ascii2string(gv.keys[31]),
|
||||||
|
33: gv.utils.ascii2string(gv.keys[33]),
|
||||||
|
34: gv.utils.ascii2string(gv.keys[34]),
|
||||||
|
};
|
||||||
|
}
|
3
src/handler/viewer/index.js
Normal file
3
src/handler/viewer/index.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
module.exports = {
|
||||||
|
...require('./dkeys'),
|
||||||
|
}
|
@ -23,13 +23,13 @@ module.exports = function (ts, immucfg, mate = {}) {
|
|||||||
mate.jscode ? {
|
mate.jscode ? {
|
||||||
name: 'makecode_input_js',
|
name: 'makecode_input_js',
|
||||||
desc: 'url方式提取的javascript代码:',
|
desc: 'url方式提取的javascript代码:',
|
||||||
text: mate.jscode,
|
text: mate.jscode.code,
|
||||||
extend: 'js',
|
extend: 'js',
|
||||||
} : null,
|
} : null,
|
||||||
mate.html ? {
|
mate.html ? {
|
||||||
name: 'makecode_input_html',
|
name: 'makecode_input_html',
|
||||||
desc: 'url方式提取的html代码:',
|
desc: 'url方式提取的html代码:',
|
||||||
text: mate.html,
|
text: mate.html.code,
|
||||||
extend: 'html',
|
extend: 'html',
|
||||||
newLine: true,
|
newLine: true,
|
||||||
} : null,
|
} : null,
|
||||||
|
@ -1,11 +1,16 @@
|
|||||||
const CoderHigh = require('./handler/CoderHigh');
|
const AppCode = require('./handler/AppCode');
|
||||||
const paths = require('@utils/paths');
|
const paths = require('@utils/paths');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
const fse = require('fs-extra');
|
||||||
|
const path = require('path');
|
||||||
const logger = require('@utils/logger');
|
const logger = require('@utils/logger');
|
||||||
const Coder = require('./handler/Coder');
|
const Coder = require('./handler/Coder');
|
||||||
const Cookie = require('./handler/Cookie');
|
const Cookie = require('./handler/Cookie');
|
||||||
const unescape = require('@utils/unescape');
|
const unescape = require('@utils/unescape');
|
||||||
const gv = require('@src/handler/globalVarible');
|
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) {
|
function parseR2mka(text) {
|
||||||
const start = text.indexOf('"') + 1;
|
const start = text.indexOf('"') + 1;
|
||||||
@ -13,15 +18,93 @@ function parseR2mka(text) {
|
|||||||
return unescape(text.substr(start, end));
|
return unescape(text.substr(start, end));
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = function (ts, immucfg) {
|
function mkdirsSync(dirPath) {
|
||||||
console.log('还原更多加密文件,如app.js等,作者开发中,可关注微信订阅号`码功`获取项目更新推送!');
|
if (!fs.existsSync(dirPath)) {
|
||||||
return
|
mkdirsSync(path.dirname(dirPath));
|
||||||
gv._setAttr('_ts', ts);
|
fs.mkdirSync(dirPath);
|
||||||
const startTime = new Date().getTime();
|
}
|
||||||
const coder = new Coder(ts, immucfg);
|
}
|
||||||
const { code, $_ts } = coder.run();
|
|
||||||
const r2mkaText = parseR2mka(coder.r2mkaText);
|
function filenameAddDesc(name, desc) {
|
||||||
const cookie = new Cookie($_ts, r2mkaText).run();
|
const arr = name.split('.');
|
||||||
return cookie;
|
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) {
|
||||||
|
if (fs.existsSync(paths.outputResolve('makecode-high'))) {
|
||||||
|
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 coder = new Coder(ts, immucfg);
|
||||||
const { code, $_ts } = coder.run();
|
const { code, $_ts } = coder.run();
|
||||||
const r2mkaText = parseR2mka(coder.r2mkaText);
|
const r2mkaText = parseR2mka(coder.r2mkaText);
|
||||||
const cookie = new Cookie($_ts, r2mkaText).run();
|
const cookie = new Cookie($_ts, r2mkaText, coder, code).run();
|
||||||
if (gv.metaContent) {
|
if (gv.metaContent) {
|
||||||
logger.info(`存在meta-content值:${gv.metaContent.content} 解析结果:${gv.metaContent.value}`);
|
logger.info(`存在meta-content值:${gv.metaContent.content} 解析结果:${gv.metaContent.value}`);
|
||||||
}
|
}
|
||||||
|
BIN
static/error-makecode-high.png
Normal file
BIN
static/error-makecode-high.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 127 KiB |
@ -1,5 +1,5 @@
|
|||||||
// process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"
|
// process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"
|
||||||
const request = require('request-promise');
|
const { request, cookieJar } = require('./request');
|
||||||
const cheerio = require('cheerio');
|
const cheerio = require('cheerio');
|
||||||
const isValidUrl = require('./isValidUrl');
|
const isValidUrl = require('./isValidUrl');
|
||||||
const _get = require('lodash/get');
|
const _get = require('lodash/get');
|
||||||
@ -7,30 +7,68 @@ const urlresolve = require('url').resolve;
|
|||||||
|
|
||||||
function addRequestHead(uri) {
|
function addRequestHead(uri) {
|
||||||
return {
|
return {
|
||||||
// proxy: 'http://127.0.0.1:7777',
|
// proxy: 'http://127.0.0.1:8888',
|
||||||
// gzip: true
|
gzip: true,
|
||||||
uri,
|
uri,
|
||||||
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36",
|
|
||||||
resolveWithFullResponse: true,
|
resolveWithFullResponse: true,
|
||||||
simple: false,
|
simple: false,
|
||||||
|
headers: {
|
||||||
|
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36',
|
||||||
|
'Connection': 'keep-alive',
|
||||||
|
'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',
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = async function getCode(url) {
|
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);
|
||||||
|
}
|
||||||
if (!isValidUrl(url)) throw new Error('输入链接不正确');
|
if (!isValidUrl(url)) throw new Error('输入链接不正确');
|
||||||
const res = await request(addRequestHead(url));
|
const res = await request(addRequestHead(url));
|
||||||
const $ = cheerio.load(res.body);
|
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'));
|
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, 请检查!`);
|
if (!tsscript.length) throw new Error(`${res.body}\n错误:链接返回结果未找到cd或nsd, 请检查!`);
|
||||||
const $_ts = Function('window', tsscript[0] + 'return $_ts')({});
|
const $_ts = Function('window', tsscript[0] + 'return $_ts')({});
|
||||||
$_ts.metaContent = _get($('meta[r=m]'), '0.attribs.content');
|
$_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);
|
const remotes = scripts.map(it => checkSrc(it.attribs.src)).filter(Boolean);
|
||||||
if (!remotes.length) throw new Error('未找到js外链,无法提取配置文本请检查!');
|
if (!remotes.length) throw new Error('未找到js外链,无法提取配置文本请检查!');
|
||||||
for(let src of remotes) {
|
const ret = {
|
||||||
const jscode = await request(addRequestHead(urlresolve(url, src)));
|
$_ts,
|
||||||
if (jscode.body.includes('r2mKa')) return { $_ts, jscode: jscode.body, html: res.body, url };
|
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外链中没有瑞数的代码文件');
|
throw new Error('js外链中没有瑞数的代码文件');
|
||||||
}
|
}
|
||||||
|
@ -3,14 +3,17 @@ const fs = require('fs');
|
|||||||
const { init } = require('@src/handler/parser/');
|
const { init } = require('@src/handler/parser/');
|
||||||
const logger = require('./logger');
|
const logger = require('./logger');
|
||||||
const gv = require('@src/handler/globalVarible');
|
const gv = require('@src/handler/globalVarible');
|
||||||
|
const Coder = require('@src/handler/Coder');
|
||||||
|
|
||||||
module.exports = function(filepath) {
|
module.exports = function(filepath) {
|
||||||
if (typeof filepath !== 'string') {
|
if (typeof filepath !== 'string') {
|
||||||
if (typeof filepath === 'number') gv._setAttr('version', filepath);
|
if (typeof filepath === 'number') gv._setAttr('version', filepath);
|
||||||
filepath = paths.exampleResolve('codes', `${gv.version}-$_ts-full.json`)
|
filepath = paths.exampleResolve('codes', `${gv.version}-$_ts.json`)
|
||||||
}
|
}
|
||||||
if (!fs.existsSync(filepath)) throw new Error(`输入文件不存在: ${filepath}`);
|
if (!fs.existsSync(filepath)) throw new Error(`输入文件不存在: ${filepath}`);
|
||||||
logger.debug(`初始化GlobalVarible变量,$_ts配置文件:${filepath}`);
|
logger.debug(`初始化GlobalVarible变量,$_ts配置文件:${filepath}`);
|
||||||
init(JSON.parse(fs.readFileSync(filepath, 'utf8')));
|
const coder = new Coder(JSON.parse(fs.readFileSync(filepath, 'utf8')));
|
||||||
|
const { code, $_ts } = coder.run();
|
||||||
|
init($_ts);
|
||||||
return gv;
|
return gv;
|
||||||
};
|
};
|
||||||
|
8
utils/request.js
Normal file
8
utils/request.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
const rp = require('request-promise');
|
||||||
|
const cookieJar = rp.jar()
|
||||||
|
const request = rp.defaults({ jar: cookieJar })
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
request,
|
||||||
|
cookieJar,
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user