领导:有个需求啊,基座代码要加密啊,不能让甲方看到,看到就GG了呀,把我们技术全学去了呀。
我:en......😬。
之前了解过JShaman,有20多项混淆加密功能,官网提供免登录在线加密。复制进去,再复制出来,覆盖原代码,代码照样能跑,贼厉害。关键是提供了Web API,有开发接口,这可玩性就高了。
截取一段加密后的代码
function get_copyright(){var _0x55bf5e="moc.namahsj".split("").reverse().join("");var _0x403775=0xe56f9^0xe5118;var _0x17cff7="\u0028\u0063\u0029"+_0x403775+"\u002d"+new Date()["\u0067\u0065\u0074\u0046\u0075\u006c\u006c\u0059\u0065\u0061\u0072"]()+"\u002c"+_0x55bf5e;return _0x17cff7;}console["\u006c\u006f\u0067"](get_copyright());
是吧,完全没有读代码的欲望。
ok,目标鼠标右键菜单加密代码,走起。
我的开发环境
node V16.x npm V7.x
首先创建文件夹JShaman
根目录运行 npm install readline request --save
创建两个js文件,一个是右键js文件执行、一个是右键文件夹执行;
分别是:JShaman.js、JShamans.js
添加注册表
. 能在右键菜单中执行js代码,这里是关键
- 创建一个txt文件,放入以下脚本,这是往鼠标右键添加菜单选项
Windows Registry Editor Version 5.00
[HKEY_CLASSES_ROOT\Directory\shell\JShaman加密]
"Icon"="D:\\JShaman\\encyt.ico"
[HKEY_CLASSES_ROOT\Directory\shell\JShaman加密\command]
@="\"C:\\Program Files\\nodejs\\node.exe\" \"D:\\JShaman\\JShamans.js\" \"%1\""
[HKEY_CLASSES_ROOT\SystemFileAssociations\.js\Shell\JShaman加密]
"Icon"="D:\\JShaman\\encyt.ico"
[HKEY_CLASSES_ROOT\SystemFileAssociations\.js\Shell\JShaman加密\command]
@="\"C:\\Program Files\\nodejs\\node.exe\" \"D:\\JShaman\\JShaman.js\" \"%1\""
D:\\JShaman\\encyt.ico
是右键菜单的图标,去iconfont随便找一个,修改后缀为ico即可。
- 将txt后缀修改为reg
- 执行该设置,一路确定。建议备份一下自己注册表哈,搞砸了,还有回头路。
4. 随后就可以右键菜单看到这个选项了,只有文件夹和js才有哦。
右键执行JS脚本
const vip_code = "free";
const config = {
compact: "true",//压缩代码
renameGlobalFunctionVariable: "false",//混淆全局变量名和函数名
controlFlowFlattening: "true",//平展控制流
deadCodeInjection: "false",//僵尸代码植入
stringArray: "true",//字符串阵列化
stringArrayEncoding: "false",//阵列字符串加密
disableConsoleOutput: "false",//禁用命令行输出
debugProtection: "false",//反浏览器调试
time_range: "false",//时间限定
time_start: "20240118",//时间限定起始时间、结束时间,时间限定启用时此2参数生效
time_end: "20240118",
domainLock: [],//域名锁定
reservedNames: [],//保留关键字
}
const fs = require("fs");
const readline = require("readline");
const request = require("request");
const filePath = process.argv[2];
if (!filePath) {
console.error("未选中文件");
process.exit(1);
}
if (!fs.existsSync(filePath)) {
console.error(`文件 ${filePath} 不存在`);
process.exit(1);
}
console.log(`正在处理文件:${filePath}`);
var javascript_code = fs.readFileSync(filePath, "utf8").toString();
var options = {
url: "https://www.jshaman.com:4430/submit_js_code/",
method: "POST",
json: true,
body: {
"js_code": javascript_code, //JavaScript代码
"vip_code": vip_code,//JShaman VIP码
}
};
if (options.body.vip_code != "free") {
options.body.config = config;//混淆加密参数
}
console.log("正在向JShaman.com提交混淆加密请求...")
request(options, function (error, response, body) {
if (!error && response.statusCode === 200) {
if (body?.message.indexOf("保护代码时发生错误") > -1) {
console.log("JShaman服务器拒绝加密,需要启用以下语法分析器:jsx", "flow", "typescript");
} else {
console.log(body.message);
}
if (body.status == 0) {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question("是否覆盖原文件?y为是,n则在同目录下另存。(y/n) ", (answer) => {
if (answer.toLowerCase() === "y") {
fs.writeFileSync(filePath, body.content.toString());
console.log("文件已覆盖。");
} else {
function getFileName(name) { return name.substring(0, name.lastIndexOf(".")) }
var obfuscated_file = getFileName(filePath) + "-JShaman.js";
fs.writeFileSync(obfuscated_file, body.content.toString());
console.log("混淆加密后的Js文件:", obfuscated_file);
}
rl.close();
});
}
} else {
console.error("向JShaman.com发送请求时出现错误:", error);
}
});
process.on("beforeExit", (code) => {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
console.log("按下任意键退出程序...");
rl.on("line", (input) => {
rl.close();
process.exit(0);
});
});
这时候就可以把js文件加密了,有两个选项,一个是覆盖文件加密,一个是加密到新文件。
以上操作借鉴了这位网友的分享
到这里已经很不错了,可是我的js代码多啊,又在多个文件夹中。每次更新我还是要花时间一个一个加密,这不行啊,影响我摸鱼时间啊,基于上述操作,我拓展了文件夹加密。
核心代码上述已经交代清楚了,如果没有其他需求可以移步了哈。
对文件夹加密
1. 获取文件夹中所有js文件
async function getFilesInDirectory(dirPath) {
const files = [];
try {
const entries = await fs.promises.readdir(dirPath, { withFileTypes: true });
for (const entry of entries) {
const fullPath = path.join(dirPath, entry.name);
if (entry.isDirectory()) {
const subFiles = await getFilesInDirectory(fullPath);
files.push(...subFiles);
} else {
if (path.extname(fullPath).toLowerCase() === ".js") {// 过滤文件
files.push(fullPath);
}
}
}
} catch (error) {
console.error(`读取目录时出错 ${dirPath}:`, error);
}
return files;
}
2. 将代码交换的方法包装一下
async function getEncryption(file) {
return new Promise((resolve, reject) => {
if (!fs.existsSync(file)) {
resolve({ success: false, state: "201", message: "待加密文件不存在!" })
}
var codeJS = fs.readFileSync(file, "utf8").toString();
var options = {
url: "https://www.jshaman.com:4430/submit_js_code/",
method: "POST",
json: true,
body: {
"js_code": codeJS, //JavaScript代码
"vip_code": vip_code,//JShaman VIP码
}
};
if (options.body.vip_code != "free") {
options.body.config = config;//混淆加密参数
}
request(options, (error, response, body) => {
if (error) {
console.error("向JShaman.com发送请求时出现错误:", error);
reject({ success: false, message: error });
} else {
if (response.statusCode === 200 && body.status == 0) {
resolve({ code: body.content.toString(), success: true });
} else {
if (body?.message.indexOf("保护代码时发生错误") > -1) {
resolve({ success: false, state: "201", message: "JShaman服务器拒绝加密,需要启用以下语法分析器:jsx flow typescript" })
} else {
resolve({ success: false, message: "加密失败!" })
}
}
}
});
});
}
3. 加密后写入新文件
async function createFile(pathFile) {
return new Promise((resolve, reject) => {
console.log("进行中:", pathFile)
const result = { success: true, data: {} };
function nextStep() {
index += 1;
if (pathList[index]) {
console.log("进行中:", pathList[index])
setTimeout(() => {
carryOut(pathList[index])
}, 5000);
} else {
resolve(result)
}
}
async function carryOut(file) {
if (file) {
const res = await getEncryption(file);
if (res.code) {
result.data[file] = "成功";
function getFileName(name) { return name.substring(0, name.lastIndexOf(".")) }
var newFile = getFileName(file) + "-JShaman.js";
fs.writeFileSync(newFile, res.code);
console.log("加密成功", file)
nextStep()
} else {
result.data[file] = res.message || "失败"
if (res.state === "201") {
result.data[file] = res.message;
console.log("加密失败", res.message)
nextStep()
} else {
console.log("失败了,3秒后重试", file);
setTimeout(() => {
carryOut(file)
}, 3000);
}
}
} else {
if (pathList[index]) {
nextStep();
} else {
result.success = false;
reject("非法路径");
}
}
}
carryOut(pathFile);
});
}
4. 加密后覆盖源文件
function overwriteFile(pathFile) {
return new Promise((resolve, reject) => {
console.log("进行中:", pathFile)
const result = { success: true, data: {} };
function nextStep() {
index += 1;
if (pathList[index]) {
console.log("进行中:", pathList[index])
setTimeout(() => {
carryOut(pathList[index])
}, 5000);
} else {
resolve(result)
}
}
async function carryOut(file) {
if (file) {
const res = await getEncryption(file);
if (res.code) {
result.data[file] = "成功";
fs.writeFileSync(file, res.code);
console.log("加密成功", file)
nextStep()
} else {
result.data[file] = res.message || "失败"
if (res.state === "201") {
result.data[file] = res.message;
console.log("加密失败", res.message)
nextStep()
} else {
console.log("失败了,3秒后重试", file);
setTimeout(() => {
carryOut(file)
}, 3000);
}
}
} else {
if (pathList[index]) {
nextStep();
} else {
result.success = false;
reject("非法路径");
}
}
}
carryOut(pathFile)
});
}
5. 收到指令后执行
getFilesInDirectory(filePath)
.then(files => {
index = 0;
pathList = files;
console.log('即将对这些文件进行加密:', files);
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question("受API限制,多文件每5秒进行一次加密,是否继续? (y/n) ", (answer) => {
if (answer.toLowerCase() === 'y') {
rl.question("是否覆盖原文件? (y/n) ,按 t 退出! ", async (reply) => {
if (reply.toLowerCase() === 't') {
rl.close();// 结束对话
} else if (reply.toLowerCase() === 'y') {
const res = await overwriteFile(pathList[index]);
console.log("覆盖源文件,加密结束!")
console.log(res.data)
process.exit(0);
} else {
const res = await createFile(pathList[index]);
console.log("创建新文件,加密结束!")
console.log(res.data)
process.exit(0);
}
});
} else {
process.exit(0);// 终止程序
}
});
})
.catch(error => {
console.error('出现错误:', error);
});
看看效果
右键文件夹时
加密前
执行中
加密效果
ok可以交差啦