feat(x27cn): v1.4.1 迷惑性字符混淆 + 数字/运算符混淆

This commit is contained in:
violettools
2026-01-26 00:58:50 +08:00
parent 9401a98384
commit c6cefdf04f
7 changed files with 222 additions and 29 deletions

View File

@@ -454,11 +454,28 @@ function getSecret() {
**level=3 保护后:**
```javascript
(function(){var _$a=function(){var _$b=new Date().getTime();debugger;...})();
var _$k=[120,50,...];var _$a=[[65,83,...]];var _$s=function(i){...};
var _$0=function(){return _$s(0)};...
(function(){var IOа=function(){var ꓵⲛꓳⲣео=new Date().getTime();debugger;...})();
var ⲙꓺαꓷlꓻ=[120,50,...];var ⲉOеꓷⲓꓵ=[[65,83,...]];
var ⲧIꓶоꓺl=function(){return ⲅаⲅꓲοꓵⲕ(0)};...
```
### 迷惑性字符集
v1.4.1 使用高度迷惑性字符进行混淆:
| 字符类型 | 示例 | 说明 |
|---------|------|------|
| 拉丁迷惑 | `l`, `I`, `O` | 小写L/大写i/大写O 难以区分 |
| 希腊字母 | `α`, `ο` | 像 a, o 但 Unicode 不同 |
| 西里尔字母 | `а`, `е`, `о` | 外观与拉丁相同但编码不同 |
| 科普特(埃及) | `ⲁ`, `ⲃ`, ``, `ⲇ`... | 古埃及科普特字母 |
| Lisu 字母 | ``, ``, ``, `ꓵ`... | 缅甸傈僳族文字 |
混淆效果:
- 变量名:`ⲉOеꓷⲓꓵ`, `ⲙꓺαꓷlꓻ`
- 函数名:`IOа`, `ⲅаⲅꓲοꓵⲕ`
- 极难阅读和复制
反调试特性:
- 无限 debugger 断点
- 检测 DevTools 打开

View File

@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "x27cn"
version = "1.4.0"
version = "1.4.1"
description = "X27CN - Advanced code obfuscation, encryption and anti-crawl protection"
readme = "README.md"
license = "MIT"

View File

@@ -81,13 +81,15 @@ from .anti_crawl import (
from .advanced import (
encrypt_strings,
obfuscate_numbers,
obfuscate_operators,
advanced_obfuscate,
full_obfuscate,
obfuscate_file_full,
quick_protect,
)
__version__ = '1.4.0'
__version__ = '1.4.1'
__author__ = 'CFspider'
__all__ = [
# 核心加密
@@ -141,6 +143,8 @@ __all__ = [
'inject_protection',
# 高级混淆(一键式)
'encrypt_strings',
'obfuscate_numbers',
'obfuscate_operators',
'advanced_obfuscate',
'full_obfuscate',
'obfuscate_file_full',

View File

@@ -18,11 +18,118 @@ from .minify import minify_js, obfuscate_identifiers, add_dead_code
from .anti_crawl import generate_full_protection, inject_protection
def _get_confusing_chars():
"""获取迷惑性字符集"""
return [
'l', 'I', 'O', # l/I, O/0 迷惑
'α', 'ο', 'а', 'е', 'о', # 希腊/西里尔
'', '', '', '', '', '', '', '', '', '', '', '', '', '', # 科普特
'', '', '', '', '', '', '', '', '', '', # Lisu
]
def _gen_confusing_name(index: int) -> str:
"""生成迷惑性变量名"""
chars = _get_confusing_chars()
base = len(chars)
if index < base:
return chars[index]
first = index // base
second = index % base
if first < base:
return chars[first] + chars[second]
third = first // base
first = first % base
return chars[third % base] + chars[first] + chars[second]
def _random_confusing_name(length: int = 6) -> str:
"""生成随机迷惑性变量名"""
chars = _get_confusing_chars()
return ''.join(random.choice(chars) for _ in range(length))
def obfuscate_numbers(js_code: str) -> str:
"""
混淆 JavaScript 中的数字
将数字转换为复杂表达式。
Args:
js_code: JavaScript 代码
Returns:
数字混淆后的代码
"""
def obfuscate_number(match):
num_str = match.group(0)
# 跳过小数和科学计数法
if '.' in num_str or 'e' in num_str.lower():
return num_str
try:
num = int(num_str)
if num == 0:
return '(+[])' # 0
elif num == 1:
return '(+!![])' # 1
elif num < 10:
# 使用位运算混淆
options = [
f'({num + random.randint(1, 100)}-{random.randint(1, 100) + num - num})',
f'({num}|0)',
f'(~~{num})',
]
return random.choice(options)
elif num < 1000:
# 拆分为加法
a = random.randint(1, num - 1)
b = num - a
return f'({a}+{b})'
else:
# 使用十六进制
return f'(0x{num:x})'
except:
return num_str
# 匹配独立的数字(不是变量名的一部分)
pattern = r'(?<![a-zA-Z_$0-9])(\d+)(?![a-zA-Z_$0-9])'
return re.sub(pattern, obfuscate_number, js_code)
def obfuscate_operators(js_code: str) -> str:
"""
混淆 JavaScript 中的运算符和比较
将简单运算转换为函数调用。
Args:
js_code: JavaScript 代码
Returns:
运算符混淆后的代码
"""
# 生成迷惑性函数名
fn_eq = _random_confusing_name(7)
fn_neq = _random_confusing_name(7)
fn_add = _random_confusing_name(7)
fn_sub = _random_confusing_name(7)
# 运算符函数定义
ops_funcs = f'''var {fn_eq}=function(ⲁ,ⲃ){{return ⲁ===ⲃ}};
var {fn_neq}=function(ⲁ,ⲃ){{return ⲁ!==ⲃ}};
var {fn_add}=function(ⲁ,ⲃ){{return ⲁ+ⲃ}};
var {fn_sub}=function(ⲁ,ⲃ){{return ⲁ-ⲃ}};
'''
return ops_funcs + js_code
def encrypt_strings(js_code: str, key: str = DEFAULT_KEY) -> str:
"""
加密 JavaScript 代码中的字符串
将所有字符串字面量替换为运行时解密调用。
使用迷惑性字符作为变量名。
Args:
js_code: JavaScript 代码
@@ -31,6 +138,14 @@ def encrypt_strings(js_code: str, key: str = DEFAULT_KEY) -> str:
Returns:
字符串加密后的代码
"""
# 生成迷惑性变量名
var_key = _random_confusing_name(8)
var_arr = _random_confusing_name(8)
var_dec = _random_confusing_name(8)
var_a = _random_confusing_name(6)
var_r = _random_confusing_name(6)
var_j = _random_confusing_name(6)
# 收集所有字符串
strings = []
@@ -40,34 +155,40 @@ def encrypt_strings(js_code: str, key: str = DEFAULT_KEY) -> str:
if content and len(content) > 2: # 只加密较长的字符串
idx = len(strings)
strings.append(content)
return f'_$s({idx})'
return f'{var_dec}({idx})'
return match.group(0)
# 匹配字符串(简化版,可能有边缘情况)
# 匹配字符串
pattern = r'(["\'])([^"\'\\]*(?:\\.[^"\'\\]*)*)\1'
processed = re.sub(pattern, collect_string, js_code)
if not strings:
return js_code
# 生成解密器和字符串数组
# 生成解密器
key_bytes = key.encode('utf-8')
key_array = ','.join(str(b) for b in key_bytes)
# 用十六进制混淆密钥
key_array = ','.join(f'0x{b:x}' for b in key_bytes)
# 简单的 XOR 加密
# XOR 加密字符串
encrypted_strings = []
for s in strings:
encrypted = []
for i, c in enumerate(s):
encrypted.append(ord(c) ^ key_bytes[i % len(key_bytes)])
encrypted_strings.append(','.join(str(b) for b in encrypted))
val = ord(c) ^ key_bytes[i % len(key_bytes)]
# 随机使用十进制或十六进制
if random.random() > 0.5:
encrypted.append(f'0x{val:x}')
else:
encrypted.append(str(val))
encrypted_strings.append(','.join(encrypted))
strings_array = ';'.join(f'[{s}]' for s in encrypted_strings)
decoder = f'''
var _$k=[{key_array}];
var _$a=[{strings_array}];
var _$s=function(i){{var a=_$a[i],r='';for(var j=0;j<a.length;j++)r+=String.fromCharCode(a[j]^_$k[j%_$k.length]);return r}};
# 使用迷惑性字符的解密器
decoder = f'''var {var_key}=[{key_array}];
var {var_arr}=[{strings_array}];
var {var_dec}=function(){{var {var_a}={var_arr}[ⲓ],{var_r}='';for(var {var_j}=(+[]);{var_j}<{var_a}.length;{var_j}++){var_r}+=String.fromCharCode({var_a}[{var_j}]^{var_key}[{var_j}%{var_key}.length]);return {var_r}}};
'''
return decoder + processed
@@ -79,6 +200,7 @@ def advanced_obfuscate(
encrypt_strings_: bool = True,
rename_vars: bool = True,
dead_code: bool = True,
obfuscate_nums: bool = True,
anti_debug: bool = False,
disable_shortcuts: bool = False,
domain_lock: list = None,
@@ -95,6 +217,7 @@ def advanced_obfuscate(
encrypt_strings_: 加密字符串
rename_vars: 重命名变量
dead_code: 添加死代码
obfuscate_nums: 混淆数字
anti_debug: 添加反调试
disable_shortcuts: 禁用快捷键
domain_lock: 域名锁定
@@ -117,7 +240,11 @@ def advanced_obfuscate(
if encrypt_strings_:
result = encrypt_strings(result, key)
# 4. 添加保护代码
# 4. 数字混淆
if obfuscate_nums:
result = obfuscate_numbers(result)
# 5. 添加保护代码
if anti_debug or disable_shortcuts or domain_lock or expire_date:
result = inject_protection(
result,
@@ -174,9 +301,11 @@ def _obfuscate_js_full(code: str, key: str, level: int, anti_crawl: bool) -> str
# Level 2: 中等
result = encrypt_strings(result, key)
result = add_dead_code(result)
result = obfuscate_numbers(result)
if level >= 3:
# Level 3: 高级
result = obfuscate_operators(result)
result = inject_protection(
result,
anti_debug=True,

View File

@@ -288,11 +288,19 @@ def inject_protection(js_code: str, **kwargs) -> str:
def _random_vars(count: int) -> list:
"""生成随机变量名"""
chars = string.ascii_letters
"""生成迷惑性随机变量名"""
# 迷惑性字符集:埃及科普特 + 希腊 + 西里尔 + l/I/O
confusing = [
'l', 'I', 'O', # l/I, O/0 迷惑
'α', 'ο', 'а', 'е', 'о', # 希腊/西里尔 (像 a, o, e)
'', '', '', '', '', '', '', '', '', '', '', '', '', '', # 科普特(埃及)
'', '', '', '', '', '', '', '', '', '', # Lisu
]
vars = []
for _ in range(count):
name = '_$' + ''.join(random.choice(chars) for _ in range(6))
# 生成 6-8 个迷惑字符
length = random.randint(6, 8)
name = ''.join(random.choice(confusing) for _ in range(length))
vars.append(name)
return vars

View File

@@ -33,7 +33,7 @@ def main():
prog='x27cn',
description='X27CN 代码混淆加密工具'
)
parser.add_argument('--version', action='version', version='x27cn 1.4.0')
parser.add_argument('--version', action='version', version='x27cn 1.4.1')
subparsers = parser.add_subparsers(dest='command', help='命令')

View File

@@ -126,12 +126,32 @@ def _mangle_variables(js: str) -> str:
# 找到函数作用域内的变量声明
var_pattern = re.compile(r'\b(var|let|const)\s+([a-zA-Z_$][a-zA-Z0-9_$]*)')
# 生成变量名
# 生成迷惑性变量名
def gen_name(index):
chars = 'abcdefghijklmnopqrstuvwxyz'
if index < 26:
return '_' + chars[index]
return '_' + chars[index // 26 - 1] + chars[index % 26]
# 迷惑性字符集:
# - l, I, 1 (小写L, 大写i, 数字1)
# - O, 0 (大写O, 数字0)
# - α, а (希腊alpha, 西里尔a)
# - ⲁ, ⲃ, (科普特/埃及字母)
# - , , (Lisu字母像数字)
confusing = [
'l', 'I', 'O', # 基础迷惑
'α', 'ο', 'а', 'е', 'о', # 希腊/西里尔 (像 a, o, e)
'', '', '', '', '', '', '', '', '', '', '', '', '', '', # 科普特(埃及)
'', '', '', '', '', '', '', '', '', '', # Lisu
]
base = len(confusing)
if index < base:
return confusing[index]
# 组合生成更多
first = index // base
second = index % base
if first < base:
return confusing[first] + confusing[second]
# 三字符
third = first // base
first = first % base
return confusing[third % base] + confusing[first] + confusing[second]
# 收集变量
var_map = {}
@@ -394,10 +414,25 @@ def obfuscate_identifiers(js: str) -> str:
for match in re.finditer(r'\bfunction\s+([a-zA-Z_$][a-zA-Z0-9_$]*)', js):
declarations.add(match.group(1))
# 生成混淆名
# 生成迷惑性混淆名
def gen_name(index):
# 使用 _$0, _$1, ... 格式
return f'_${index:x}'
# 迷惑性字符集:埃及科普特 + 希腊 + 西里尔 + l/I/O/0
confusing = [
'l', 'I', 'O', # l/I, O/0 迷惑
'α', 'ο', 'а', 'е', 'о', # 希腊/西里尔 (像 a, o, e)
'', '', '', '', '', '', '', '', '', '', '', '', '', '', # 科普特(埃及)
'', '', '', '', '', '', '', '', '', '', # Lisu
]
base = len(confusing)
if index < base:
return confusing[index]
first = index // base
second = index % base
if first < base:
return confusing[first] + confusing[second]
third = first // base
first = first % base
return confusing[third % base] + confusing[first] + confusing[second]
# 过滤保留字和内置对象
reserved = {