JavaScript代码混淆工具的实现及其使用
JavaScript代码可逆混淆工具
这里的实现使用简单的异或(XOR)加密方式进行混淆,并提供解混淆的功能。请注意,这种方法只是一种基本的混淆手段,作为一种思路和学习实践,并不能提供强大的安全性,适用于对安全性要求不高的场景。
JavaScript代码混淆工具的目的,保护代码,防止他人轻易窃取代码逻辑或进行恶意篡改。这个结果是可逆(即混淆后能恢复原始代码,以便修改源代码)的,并且混淆后的代码,能在其它HTML文件中正常使用。
下面给出两种实现。
一、HTML5实现JavaScript代码混淆工具
先看界面
实现源码
<!DOCTYPE html>
<html>
<head>
<title>简单的JavaScript 可逆混淆工具</title>
<style>
body {
font-family: sans-serif;
}
textarea {
width: 90%;
height: 200px;
margin-bottom: 10px;
}
button {
padding: 10px 20px;
background-color: #4CAF50;
color: white;
border: none;
cursor: pointer;
margin-right: 5px;
margin-bottom: 10px;
}
.small-button {
padding: 5px 10px;
font-size: 12px;
}
.button-group {
margin-bottom: 15px;
}
</style>
</head>
<body>
<h1>JavaScript 可逆混淆工具</h1>
<div>
<label for="originalCode">原始 JavaScript 代码:</label><br>
<textarea id="originalCode"></textarea>
<div class="button-group">
<button class="small-button" onclick="copyText('originalCode')">复制</button>
<button class="small-button" onclick="clearText('originalCode')">清除</button>
</div>
</div>
<div>
<button onclick="obfuscateCode()">混淆</button>
<button onclick="deobfuscateCode()">解混淆</button>
</div>
<div>
<label for="obfuscatedCode">混淆后的 JavaScript 代码:</label><br>
<textarea id="obfuscatedCode"></textarea>
<div class="button-group">
<button class="small-button" onclick="copyText('obfuscatedCode')">复制</button>
<button class="small-button" onclick="clearText('obfuscatedCode')">清除</button>
</div>
</div>
<script>
const key = 'MySecretKey'; // 密钥,用于异或加密
// 复制文本框内容
function copyText(elementId) {
const textArea = document.getElementById(elementId);
textArea.select();
document.execCommand('copy');
alert('已复制到剪贴板');
}
// 清除文本框内容
function clearText(elementId) {
document.getElementById(elementId).value = '';
}
function obfuscateCode() {
const originalCode = document.getElementById('originalCode').value;
let obfuscatedCode = xorEncrypt(originalCode, key);
// 添加eval和解混淆函数
obfuscatedCode = `eval(xorDecrypt("${obfuscatedCode}", '${key}')); //密钥'${key}'
function xorDecrypt(text, key) {
const decodedText = atob(text);
let result = '';
for (let i = 0; i < decodedText.length; i++) {
const charCode = decodedText.charCodeAt(i) ^ key.charCodeAt(i % key.length);
result += String.fromCharCode(charCode);
}
return decodeURIComponent(result);
}`;
document.getElementById('obfuscatedCode').value = obfuscatedCode;
}
function deobfuscateCode() {
let obfuscatedCode = document.getElementById('obfuscatedCode').value;
// 移除添加的eval和解混淆函数
if (obfuscatedCode.startsWith('eval(xorDecrypt(')) {
const startQuote = obfuscatedCode.indexOf('"') + 1;
const endQuote = obfuscatedCode.indexOf('"', startQuote);
obfuscatedCode = obfuscatedCode.substring(startQuote, endQuote);
}
const originalCode = xorDecrypt(obfuscatedCode, key);
document.getElementById('originalCode').value = originalCode;
}
function xorEncrypt(text, key) {
const encodedText = encodeURIComponent(text);
const keyBytes = new TextEncoder().encode(key);
const textBytes = new TextEncoder().encode(encodedText);
const resultBytes = Array.from(textBytes).map((byte, i) => byte ^ keyBytes[i % keyBytes.length]);
const resultString = String.fromCharCode(...resultBytes);
return btoa(resultString);
}
function xorDecrypt(text, key) {
const decodedText = atob(text);
const keyBytes = new TextEncoder().encode(key);
const decodedBytes = Array.from(decodedText).map(char => char.charCodeAt(0));
const resultBytes = decodedBytes.map((byte, i) => byte ^ keyBytes[i % keyBytes.length]);
const resultString = String.fromCharCode(...resultBytes);
try {
const decoded = decodeURIComponent(new TextDecoder().decode(new Uint8Array(resultBytes)));
return decoded;
} catch (e) {
console.error("解码错误:", e);
return ""; // 或者其他错误处理方式
}
}
</script>
</body>
</html>
二、Python实现JavaScript代码混淆工具
先看效果图
源码如下:
import tkinter as tk
from tkinter import ttk, messagebox, scrolledtext
import base64
import urllib.parse
class XorObfuscator:
def __init__(self, key='MySecretKey'):
self.key = key
def _xor_operation(self, text_bytes, key_bytes):
return bytes([text_bytes[i] ^ key_bytes[i % len(key_bytes)] for i in range(len(text_bytes))])
def encrypt(self, plaintext):
try:
encoded = urllib.parse.quote(plaintext).encode('utf-8')
key_bytes = self.key.encode('utf-8')
encrypted = self._xor_operation(encoded, key_bytes)
return base64.b64encode(encrypted).decode('utf-8')
except Exception as e:
return f"加密错误: {str(e)}"
def decrypt(self, ciphertext):
try:
key_bytes = self.key.encode('utf-8')
decoded = base64.b64decode(ciphertext)
decrypted = self._xor_operation(decoded, key_bytes)
return urllib.parse.unquote(decrypted.decode('utf-8'))
except:
return "解码错误 - 请检查密钥或输入内容"
class ObfuscationToolApp(tk.Tk):
def __init__(self):
super().__init__()
self.title("Python 可逆混淆工具")
self.geometry("800x600")
self.obfuscator = XorObfuscator()
self.create_widgets()
def create_widgets(self):
# 原始代码区域
ttk.Label(self, text="原始代码:").pack(pady=5)
self.original_text = scrolledtext.ScrolledText(self, height=10)
self.original_text.pack(fill=tk.X, padx=10)
# 原始代码操作按钮
btn_frame1 = ttk.Frame(self)
btn_frame1.pack(pady=5)
ttk.Button(btn_frame1, text="复制", command=self.copy_original).pack(side=tk.LEFT, padx=5)
ttk.Button(btn_frame1, text="清除", command=self.clear_original).pack(side=tk.LEFT)
# 操作按钮
btn_frame2 = ttk.Frame(self)
btn_frame2.pack(pady=10)
ttk.Button(btn_frame2, text="混淆", command=self.obfuscate).pack(side=tk.LEFT, padx=20)
ttk.Button(btn_frame2, text="解混淆", command=self.deobfuscate).pack(side=tk.LEFT, padx=20)
# 混淆后代码区域
ttk.Label(self, text="混淆后代码:").pack(pady=5)
self.obfuscated_text = scrolledtext.ScrolledText(self, height=10)
self.obfuscated_text.pack(fill=tk.X, padx=10)
# 混淆代码操作按钮
btn_frame3 = ttk.Frame(self)
btn_frame3.pack(pady=5)
ttk.Button(btn_frame3, text="复制", command=self.copy_obfuscated).pack(side=tk.LEFT, padx=5)
ttk.Button(btn_frame3, text="清除", command=self.clear_obfuscated).pack(side=tk.LEFT)
# 密钥设置
settings_frame = ttk.Frame(self)
settings_frame.pack(pady=10)
ttk.Label(settings_frame, text="密钥:").pack(side=tk.LEFT)
self.key_entry = ttk.Entry(settings_frame, width=20)
self.key_entry.insert(0, "MySecretKey")
self.key_entry.pack(side=tk.LEFT, padx=5)
ttk.Button(settings_frame, text="更新密钥", command=self.update_key).pack(side=tk.LEFT)
def update_key(self):
new_key = self.key_entry.get()
self.obfuscator.key = new_key
messagebox.showinfo("提示", "密钥已更新")
def get_text(self, text_widget):
return text_widget.get("1.0", tk.END).strip()
def set_text(self, text_widget, content):
text_widget.delete("1.0", tk.END)
text_widget.insert(tk.INSERT, content)
def copy_original(self):
self.clipboard_clear()
self.clipboard_append(self.get_text(self.original_text))
def clear_original(self):
self.original_text.delete("1.0", tk.END)
def copy_obfuscated(self):
self.clipboard_clear()
self.clipboard_append(self.get_text(self.obfuscated_text))
def clear_obfuscated(self):
self.obfuscated_text.delete("1.0", tk.END)
def obfuscate(self):
original_code = self.get_text(self.original_text)
encrypted = self.obfuscator.encrypt(original_code)
# 生成JavaScript版本的解密函数
obfuscated_code = f'''eval(xorDecrypt("{encrypted}", "{self.obfuscator.key}"));
function xorDecrypt(text, key) {{
const decodedText = atob(text);
let result = '';
for (let i = 0; i < decodedText.length; i++) {{
const charCode = decodedText.charCodeAt(i) ^ key.charCodeAt(i % key.length);
result += String.fromCharCode(charCode);
}}
return decodeURIComponent(result);
}}'''
self.set_text(self.obfuscated_text, obfuscated_code)
def deobfuscate(self):
code = self.get_text(self.obfuscated_text)
if code.startswith('eval(xorDecrypt("'):
start = code.find('"') + 1
end = code.find('"', start)
encrypted = code[start:end]
else:
encrypted = code
result = self.obfuscator.decrypt(encrypted)
self.set_text(self.original_text, result)
if __name__ == "__main__":
app = ObfuscationToolApp()
app.mainloop()
三、运用到一个简单的猜数字游戏
下面通过一个例子,演示如何使用
原来(未混淆JavaScript代码)的如下:
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>猜数字游戏</title>
<style>
body {
font-family: Arial, sans-serif;
text-align: center;
margin-top: 50px;
}
input {
margin: 10px;
padding: 5px;
}
button {
padding: 10px 20px;
cursor: pointer;
}
</style>
</head>
<body>
<h1>猜数字游戏</h1>
<p>我已经想好了一个1到100之间的数字,你能猜到它是什么吗?</p>
<input type="number" id="guess" placeholder="请输入你的猜测">
<button onclick="checkGuess()">提交</button>
<button onclick="restartGame()">重玩</button>
<p id="result"></p>
<script>
let randomNumber = Math.floor(Math.random() * 100) + 1; // 生成一个1到100的随机数
let attempts = 0;
function checkGuess() {
const userGuess = document.getElementById('guess').value;
attempts++;
if (userGuess == randomNumber) {
document.getElementById('result').innerText = `恭喜你!猜对了!数字是 ${randomNumber},你总共猜了 ${attempts} 次。`;
} else if (userGuess > randomNumber) {
document.getElementById('result').innerText = '太大了,再试一次!';
} else if (userGuess < randomNumber) {
document.getElementById('result').innerText = '太小了,再试一次!';
}
}
function restartGame() {
randomNumber = Math.floor(Math.random() * 100) + 1; // 重新生成随机数
attempts = 0; // 重置尝试次数
document.getElementById('guess').value = ''; // 清空输入框
document.getElementById('result').innerText = ''; // 清空结果提示
}
</script>
</body>
</html>
混淆后代码
将<script> </script>源代码复制到工具中混淆,将混淆后的代码替换源代码即可。混淆后代码为:
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>猜数字游戏</title>
<style>
body {
font-family: Arial, sans-serif;
text-align: center;
margin-top: 50px;
}
input {
margin: 10px;
padding: 5px;
}
button {
padding: 10px 20px;
cursor: pointer;
}
</style>
</head>
<body>
<h1>猜数字游戏</h1>
<p>我已经想好了一个1到100之间的数字,你能猜到它是什么吗?</p>
<input type="number" id="guess" placeholder="请输入你的猜测">
<button onclick="checkGuess()">提交</button>
<button onclick="restartGame()">重玩</button>
<p id="result"></p>
<script>
eval(xorDecrypt("aEtjQFFCQEZ7QEt9XGFVRkBVUXlVXH9JPwAXV1dEOQQXKRY+KxYfBxE5QEt9XGAhRkBVOSoREWMfPwoMAE05KhERYwsyCwcdCFxiQEt9U3ZXU0NVRGJAS31cYSdGQFVFblY7aEtjQFE0QEYNQEt9XBZSRktRUXIjXAhPdl1bV1xEbiBNaDtrQFtCQDF/QDt1XBIkUlcgQW5dQWg7Y1RTQkAxfEBADFxrUUY3XFFyJFx1P3YgVVdcN24nOGg8ZUBaR0A2e0BJDFxhVUZAVVF5VVx/SXZXU1dXRG5XSWhLYwkGBkBGewQNORw+FRcBQEZ7QEoJXGFVU1dWNm5VOGhJEkBRQkBGe0BLfVxhVUZAVVF5VVx/SXZXUxQQGigRECIXdldTEQ0RKA4+OBwgFktbQEZ7QE4PXGMkRkBVUXlVXH9JdldTV1dEbldJaEtjQFFCQEZ7QEt9XGFVRkBVFyQLCjlcYVUWAQAGDBAcPgp2V1NXVjBuV0kpFjAQDhcLAGUCHDk8PwAOFwsACRwwKVF0AhYXFgdsTFc7GD8QBldWNm5VOGhLY0BRQkBGe0BLfVxhVUZAVVF5VVx/SXZXU1dXRG5XSWhLYwQXBgAZOxEKaEsRQFEwQEcJQEkMXGFVRkBVUXlVXH9JdldTV1dEbldJaEtjQFFCQEZ7QEt9XGFVChRARntNDD4cISIWFxYHbldJaEoXQFA2QEZ7FxgjHTwILQcIFi4XUGhLY0BUMEBECkBLfVxhVUZAVVF5VVx/SXZXU1dXRG5XSWhLY0BRQkBGe0BLfVxhVUZAVVF5VVx/STcKAAcIESURVyocJyAPFwgRJRE7NDA3TUQAAAc+CQ1qUH0MDRwABh8AATlcYVVGQSFReVVce0l2IFVXXUVuJD1oPGZAWkRATQhAPHlcESFGM1VRDiNcDzp2XVJXIENuXTpoQBBAJkdANQ1AO3RcFlFGMCRRc1NcCD92JyBXXUVuIE9oQGZAIUJAMX5AOAlcalJGN1NRcl1cDD92V1NXV0BuUjs/GD0BDB8rASYHHD9cZCFGNyNRCSZcdTp2IFdXJzBuJEloPGVAW0JANglAPHhca1BGMFRRDlJcdTp2XCBXIEBuJzhoQWVAUUJARn9ATg8YJxEGHxUAOEBOCVxhVUY3U1EKJlwMSHYgUFddRG5dS2hPY0BQMEBECkBLfVxhVUZAVVF5VVx/SXZXU1dXRG5XSWhLY0BRQkBGe0BLfVxkIUZAVREnFhxoS2MMBVdXRGMQCigLFBAGARZReVVcfjx2V1MABBovChQDDD4HBgBMUXlVXHo7dlUiV1dEbldJaEtjQFFCQEZ7QEt9XGFVRkBVUXlVXH9JdldTV1dEbldJaEtjQFFCQEZ7ARYuDD4ADQZLEy4RPCEcPgANBicNAgFRags2FhYeEVNiSxAjFzYXNxcdAG5XSWhKF0BRQkJRDlBcDE12JCJXIEFuJE1oOGRAJkZANgpAQXtcFiNGMCZRcyZcCEx2XVVXXTBuIEFoOBVAWkdAMX9AO3Vca1VGN1NRCiZcDEh2ICVXJzduXUhqXGAnRkIkUXlVXH9JdldTV1dEbldJaEtjQFFCQEZ7QEt9XGFVRkBVUXlVXHo9dldTFwkHLkBLfRA1QFFCTQE4AAsKDDYWEFdXRG5WOmhLYxcCHAEbJisMIBs2F0pXV0RuUjtoSRJAUUJARntAS31cYVVGQFVReVVcf0l2V1NXV0RuV0loS2NAUUJARntAS31cYVVGQFUQJAYMIBw9EU0VAAAOCRwgHD0RIQssEGNCCygKJgkXVUxaIgsXKAsHABsGQEZ7QEoJXGFVRFcgQW4kTWg4EkAmR0A2e0BBC1wWUUYwJFFzU1wIP3YnIFddN24gTGhBZUBbNkAxc0A4C1xqUEY3UVEJXVx1SXYgVVckN24kSGg8FUAhMUBMekJcfjt2VSJXV0RuV0loS2NAUUJARntAS31cYVVGQFVReVVcf0l2V1NXV0RuUj1oSRJAUUJARntAS31cYVVGQFVReVVcf0l2V1NXUjBuVThoSRJAUUJARntAS31cYVVGQFVReVVcf0l2V1MUEBooERAiF3ZXUwAABz8ECzk+MggGWkxReVVcejt2VSJXV0RuV0loS2NAUUJARntAS31cYVVGQFVReVVcf0l2V1NXV0Q5BBcpFj4rFh8HETlAS31cYCFGQFU5KhERYx8/CgwATTkqERFjCzILBx0IXGJAS31TdldTQ1VEYkBLfVxhJ0ZAVUVuVjtoS2NAUTRARg1AS31cFlxGSlJRcyFcCE92XFVXJ0RuIE5oQGdAWjRAMX1AQXVcalVGN1xRciRcdT92IFVXXDduJzhoPGVAWkdANntASQxcYVVGQFVReVVcf0l2V1NXV0RuV0loS2NAUUJARntAS31cYVUCBhERJhUNPlxhVUZBIVF5VUloShFAUUJARg1ASwtcYVVGN1xRc1JcdT12IFRXJzBuJDxoPGZAIUJATQ9APHVcEiNGS1BRDlNcDDp2JFJXIEJuXExoO2NAUzNARntAS31cYVVGQFVReVVcf0l2V1NXV0RuV0loS2NAUUJARnsBFi4MPgANBksTLhE8IRw+AA0GJw0CAVFqHiYAEAFCXWUTGCEMNkBRQkBHD0BLfV50QFAwQEZ7QEsLXGEjRkBVUQ5TXA9Bdl1WVyBDbiRAaDsSQCZKQDYOQEB+XBZQRkpQUQpQXAhPdiRSV11CblU4aEtjQFFCQEZ7QEt9XGFVRkBVUXlVXH9JdldTV1dEbldJaEtjAQwREBkuCw1jHjYRJh4AGS4LDQ8AGgFLVRcROBAVOV56SwocCxE5MRw1DXZXU1dWMG5XSWpedlYhV1dEblc/aEsVQFFCQDF9QDt1XGtQRjdSUQpcXA84diBUVyc2blxKaDxlQFo3QE0IQDx7XGsjRktVUQ5SXAxNdiciV1U1bldJaEtjQFFCQEZ7QEt9XGFVRkBVUXlVXHo9", 'MySecretKey')); //密钥'MySecretKey'
function xorDecrypt(text, key) {
const decodedText = atob(text);
let result = '';
for (let i = 0; i < decodedText.length; i++) {
const charCode = decodedText.charCodeAt(i) ^ key.charCodeAt(i % key.length);
result += String.fromCharCode(charCode);
}
return decodeURIComponent(result);
}
</script>
</body>
</html>