X27CN v1.4.3: 增强数字混淆 - 使用JS类型转换表达式

This commit is contained in:
violettools
2026-01-26 02:51:34 +08:00
parent c6cefdf04f
commit 508381cbeb
6 changed files with 279 additions and 120 deletions

View File

@@ -151,9 +151,9 @@ print(workers.custom_url) # 自定义域名 URL
---
## X27CN 加密库
## X27CN 加密库 (v1.4.3)
X27CN 是 CFspider 使用的代码混淆加密算法,现已作为独立 Python 库发布。支持文本加密和整个前端文件混淆
X27CN 是 CFspider 使用的代码混淆加密算法,现已作为独立 Python 库发布。支持文本加密、密码安全、代码混淆和反调试保护
### 安装
@@ -170,49 +170,67 @@ import x27cn
encrypted = x27cn.encrypt('Hello World')
decrypted = x27cn.decrypt(encrypted)
# 混淆整个 HTML 文件(生成自解密页面
# 密码加密(更安全
encrypted = x27cn.encrypt_with_password('敏感数据', 'mypassword')
decrypted = x27cn.decrypt_with_password(encrypted, 'mypassword')
# 混淆整个 HTML/JS/CSS 文件
x27cn.obfuscate_file('index.html') # 生成 index.obf.html
x27cn.obfuscate_file('app.js') # 生成 app.obf.js
# 混淆 JavaScript 文件
x27cn.obfuscate_file('app.js') # 生成 app.obf.js
# 一键完整保护(混淆 + 反爬)
protected = x27cn.full_obfuscate(js_code, level=3)
```
# 混淆 CSS 文件
x27cn.obfuscate_file('style.css') # 生成 style.obf.css
### 数字混淆v1.4.3 新增)
使用 JavaScript 类型转换表达式,极难直接阅读:
```python
import x27cn
code = 'var x = 5; var y = 100;'
obfuscated = x27cn.obfuscate_numbers(code)
# 输出: var x = (((-~[])+(+!+[]))+((+!![])+(~~+!![])+([]>[]|+!![])));
# var y = (((+!+[])+(+!![]))*(((-~[])+(+!![]))*(~~5)));
```
**表达式说明:**
- `(+[])` = 0, `(+!![])` = 1, `(-~[])` = 1
- 乘法分解、加法组合、位运算混合
### 反调试保护
```python
# 一键添加反调试
protected = x27cn.full_obfuscate(js_code, level=3)
# 包含:无限 debugger、禁用 F12、控制台清除
# 域名锁定
protected = x27cn.full_obfuscate(js_code, domain_lock=['example.com'])
```
### 命令行工具
```bash
# 混淆 HTML 文件
# 一键保护(推荐)
x27cn protect app.js --level=3
# 混淆文件
x27cn obfuscate index.html
# 混淆 JS 文件
x27cn obfuscate app.js dist/app.js
# 使用自定义密钥
x27cn obfuscate app.html --key=mySecretKey
# 加密/解密文本
x27cn encrypt -t "Hello World"
x27cn decrypt -t "<faee><38db>..."
```
### 混淆效果
### 在线工具
```html
<!-- 原始 HTML -->
<h1>Hello World</h1>
<script>alert('Secret!');</script>
<!-- 混淆后(自动解密) -->
<script>(function(){var _$='<9525>...';...})();</script>
```
浏览器加载混淆后的文件会自动解密并正常显示原始内容,源代码无法被直接查看。
访问 [X27CN 在线工具](https://cfspider.pages.dev) 可直接在浏览器中进行加密/解密和代码混淆。
### 安全说明
X27CN 设计用于**代码混淆**不是密码学安全的加密算法。适用于前端代码保护、API 响应混淆、防止代码被轻易复制等场景。
X27CN 设计用于**代码混淆**不是密码学安全的加密算法。适用于前端代码保护、API 响应混淆、防止代码被轻易复制等场景。密码加密功能使用 PBKDF2-SHA256 算法。
---

View File

@@ -459,9 +459,45 @@ var ⲙꓺαꓷlꓻ=[120,50,...];var ⲉOеꓷⲓꓵ=[[65,83,...]];
var ⲧIꓶоꓺl=function(){return ⲅаⲅꓲοꓵⲕ(0)};...
```
### 数字混淆示例
```python
import x27cn
code = 'var x = 5; var y = 100; var z = 0;'
obfuscated = x27cn.obfuscate_numbers(code)
print(obfuscated)
# 输出示例:
# var x = (((-~[])+(+!+[]))+((+!![])+(~~+!![])+([]>[]|+!![])));
# var y = (((+!+[])+(+!![]))*(((-~[])+(+!![]))*(~~5)));
# var z = (+!![]^+!![]);
```
**表达式说明:**
- `(+[])` = 0 (空数组转数字)
- `(+!![])` = 1 (true 转数字)
- `(-~[])` = 1 (按位取反)
- `((+!![])+(+!![])+...)` = 加法组合
- `(a*b)` = 乘法分解
### 字符串加密示例
```python
import x27cn
code = 'var secret = "password";'
encrypted = x27cn.encrypt_strings(code)
print(encrypted)
# 输出类似:
# var ⲙꓺαⲃꓲ=[0x78,0x32,...];
# var ⲉOеꓷⲓ=[[0x8,83,68,...]];
# var ⲧIꓶоꓺ=function(ⲓ){...};
# var secret = ⲧIꓶоꓺ(0);
```
### 迷惑性字符集
v1.4.1 使用高度迷惑性字符进行混淆:
v1.4.2 使用高度迷惑性字符进行混淆:
| 字符类型 | 示例 | 说明 |
|---------|------|------|
@@ -538,6 +574,38 @@ X27CN 提供两种安全级别:
| `generate_time_bomb(date)` | 生成时间限制代码 |
| `inject_protection(code, ...)` | 注入保护到代码 |
## 更新日志
### v1.4.3 (2026-01-25)
- 增强数字混淆:使用 JavaScript 类型转换表达式
- `(+!![])` = 1, `(+[])` = 0, `(-~[])` = 1
- 乘法分解、加法组合、位运算混合
- 更难直接阅读,需要理解 JS 类型转换才能解析
### v1.4.2 (2026-01-25)
- 修复数字混淆中的数学表达式计算错误
- 优化字符串加密的随机数生成逻辑
- 前端工具添加正常版本/压缩版本切换功能
### v1.4.1
- 新增科普特(埃及)和 Lisu 字母用于混淆
- 增强变量名迷惑性
### v1.4.0
- 新增反调试、反爬虫保护
- 新增域名锁定、时间限制功能
- 一键保护 `full_obfuscate()``quick_protect()`
### v1.3.0
- 新增密码哈希和验证功能
- 新增基于密码的加密 `encrypt_with_password()`
- 密码强度检测和随机密码生成
### v1.2.0
- 新增代码压缩功能 `minify_js()`, `minify_css()`
- 支持 Node.js 工具调用
- 命令行工具增强
## License
MIT

View File

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

View File

@@ -89,7 +89,7 @@ from .advanced import (
quick_protect,
)
__version__ = '1.4.1'
__version__ = '1.4.3'
__author__ = 'CFspider'
__all__ = [
# 核心加密

View File

@@ -53,45 +53,80 @@ def obfuscate_numbers(js_code: str) -> str:
"""
混淆 JavaScript 中的数字
将数字转换为复杂表达式。
将数字转换为复杂的 JavaScript 类型转换表达式。
Args:
js_code: JavaScript 代码
Returns:
数字混淆后的代码
Example:
>>> obfuscate_numbers('var x = 5;')
'var x = (((+!![])+(+!![]))+((+!![])+(+!![])+(+!![])));'
"""
def expr_zero():
opts = ['(+[])', '(+!+[]^+!+[])', '([]|[])', '(+!![]^+!![])', '(-~[]^-~[])']
return random.choice(opts)
def expr_one():
opts = ['(+!![])', '(-~[])', '([]>[]|+!![])', '(+!+[])', '(~~+!![])']
return random.choice(opts)
def expr_small(n):
if n == 0:
return expr_zero()
if n == 1:
return expr_one()
if n == 2:
return f'({expr_one()}+{expr_one()})'
if n == 3:
return f'({expr_one()}+{expr_one()}+{expr_one()})'
# 4-9
a = random.randint(1, n - 1)
b = n - a
if a <= 3 and b <= 3:
return f'({expr_small(a)}+{expr_small(b)})'
opts = [f'({n}|{expr_zero()})', f'(~~{n})', f'(-~{n-1})', f'(~-{n+1})']
return random.choice(opts)
def expr_number(n):
if n == 0:
return expr_zero()
if n == 1:
return expr_one()
if n < 10:
return expr_small(n)
# 10-99
if n < 100:
if random.random() > 0.5 and n > 10:
for i in range(2, 10):
if n % i == 0 and n // i <= 20:
return f'({expr_small(i)}*{expr_number(n // i)})'
a = random.randint(1, min(n - 1, 50))
return f'({expr_number(a)}+{expr_number(n - a)})'
# 100-999
if n < 1000:
for i in range(2, 21):
if n % i == 0:
return f'({expr_number(i)}*{expr_number(n // i)})'
a = random.randint(1, n // 2)
return f'({expr_number(a)}+{expr_number(n - a)})'
return f'(0x{n:x})'
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})'
return expr_number(num)
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)

View File

@@ -111,7 +111,7 @@ def minify_js(js: str, mangle: bool = True) -> str:
def _mangle_variables(js: str) -> str:
"""混淆局部变量名"""
"""混淆局部变量名 - 使用 o/O/l/I 等易混淆字符"""
# 保护字符串
strings = []
def save_string(match):
@@ -123,50 +123,72 @@ def _mangle_variables(js: str) -> str:
js = re.sub(r'"(?:[^"\\]|\\.)*"', save_string, js)
js = re.sub(r'`(?:[^`\\]|\\.)*`', save_string, js)
# 找到函数作用域内的变量声明
var_pattern = re.compile(r'\b(var|let|const)\s+([a-zA-Z_$][a-zA-Z0-9_$]*)')
# 迷惑性字符集 - 重点使用 o/O/l/I 等易混淆字符 (不使用数字)
CONFUSING_CHARS = [
# 核心混淆字符 (重复多次增加出现概率)
'o', 'O', 'o', 'O', 'o', 'O', 'o', 'O', # o/O 混淆
'l', 'I', 'l', 'I', 'l', 'I', 'l', 'I', # l/I 混淆
# 希腊/西里尔 (看起来像拉丁字母)
'α', 'ο', 'а', 'е', 'о', 'ο', 'о', 'ο', # 多个 o 变体
# 科普特(埃及) - 看起来像 o
'', '', '', '', '', '',
# Lisu
'', '', '', '',
]
# 生成迷惑性变量名
# 生成迷惑性变量名 - 始终使用 6-8 个字符的复杂名称
def gen_name(index):
# 迷惑性字符集:
# - 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]
length = 6 + (index % 3) # 6-8 字符
name = ''
# 使用更好的随机算法避免重复
primes = [7919, 104729, 15485863, 32452843, 49979687]
seed = index * 31337 + primes[index % len(primes)]
for i in range(length):
seed = ((seed * 48271) % 2147483647)
char_idx = (seed + i * 17) % len(CONFUSING_CHARS)
name += CONFUSING_CHARS[char_idx]
return name
# 找到变量和函数声明
var_pattern = re.compile(r'\b(var|let|const)\s+([a-zA-Z_$][a-zA-Z0-9_$]*)')
func_pattern = re.compile(r'\bfunction\s+([a-zA-Z_$][a-zA-Z0-9_$]*)')
reserved = {'undefined', 'null', 'true', 'false', 'NaN', 'Infinity', 'length', 'prototype',
'Object', 'Array', 'String', 'Number', 'Boolean', 'Function', 'Symbol', 'Math',
'Date', 'RegExp', 'Error', 'JSON', 'console', 'window', 'document', 'navigator',
'setTimeout', 'setInterval', 'clearTimeout', 'clearInterval', 'Promise'}
# 收集变量
var_map = {}
index = 0
for match in var_pattern.finditer(js):
name = match.group(2)
if name not in var_map and name not in ['undefined', 'null', 'true', 'false', 'NaN', 'Infinity']:
if name not in var_map and name not in reserved and len(name) > 1:
var_map[name] = gen_name(index)
index += 1
# 替换变量(从长到短排序避免部分替换)
for match in func_pattern.finditer(js):
name = match.group(1)
if name not in var_map and name not in reserved and len(name) > 1:
var_map[name] = gen_name(index)
index += 1
# 使用占位符替换,避免新名称被再次替换
placeholders = {}
p_idx = 0
# 第一步:替换为占位符
for old_name in sorted(var_map.keys(), key=len, reverse=True):
new_name = var_map[old_name]
# 只替换完整单词
js = re.sub(rf'\b{re.escape(old_name)}\b', new_name, js)
placeholder = f'__VAR_{p_idx}__'
placeholders[placeholder] = new_name
js = re.sub(rf'\b{re.escape(old_name)}\b', placeholder, js)
p_idx += 1
# 第二步:占位符替换为新名称
for placeholder, new_name in placeholders.items():
js = js.replace(placeholder, new_name)
# 恢复字符串
for i, s in enumerate(strings):
@@ -381,6 +403,7 @@ def minify_html_node(html: str) -> str:
def obfuscate_identifiers(js: str) -> str:
"""
混淆 JavaScript 标识符(变量名、函数名)
使用 o/O/l/I 等易混淆字符
Args:
js: JavaScript 源代码
@@ -389,10 +412,10 @@ def obfuscate_identifiers(js: str) -> str:
混淆后的代码
"""
# 保护字符串和正则
protected = []
prot_arr = []
def save_protected(match):
idx = len(protected)
protected.append(match.group(0))
idx = len(prot_arr)
prot_arr.append(match.group(0))
return f'__PROT_{idx}__'
# 保护字符串
@@ -403,40 +426,39 @@ def obfuscate_identifiers(js: str) -> str:
# 保护正则
js = re.sub(r'/(?![/*])(?:[^/\\]|\\.)+/[gimsuy]*', save_protected, js)
# 迷惑性字符集 - 重点使用 o/O/l/I 等易混淆字符
CONFUSING_CHARS = [
'o', 'O', 'o', 'O', 'o', 'O', 'o', 'O',
'l', 'I', 'l', 'I', 'l', 'I', 'l', 'I',
'α', 'ο', 'а', 'е', 'о', 'ο', 'о', 'ο',
'', '', '', '', '', '',
'', '', '', '',
]
def gen_name(index):
"""生成 6-8 个字符的复杂迷惑性名称"""
length = 6 + (index % 3)
name = ''
primes = [7919, 104729, 15485863, 32452843, 49979687]
seed = index * 31337 + primes[index % len(primes)]
for i in range(length):
seed = ((seed * 48271) % 2147483647)
char_idx = (seed + i * 17) % len(CONFUSING_CHARS)
name += CONFUSING_CHARS[char_idx]
return name
# 收集声明的变量和函数
declarations = set()
# var/let/const 声明
for match in re.finditer(r'\b(?:var|let|const)\s+([a-zA-Z_$][a-zA-Z0-9_$]*)', js):
declarations.add(match.group(1))
# function 声明
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):
# 迷惑性字符集:埃及科普特 + 希腊 + 西里尔 + 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 = {
'undefined', 'null', 'true', 'false', 'NaN', 'Infinity',
'undefined', 'null', 'true', 'false', 'NaN', 'Infinity', 'length', 'prototype',
'Object', 'Array', 'String', 'Number', 'Boolean', 'Function',
'Symbol', 'BigInt', 'Math', 'Date', 'RegExp', 'Error',
'JSON', 'console', 'window', 'document', 'navigator',
@@ -460,12 +482,20 @@ def obfuscate_identifiers(js: str) -> str:
name_map[name] = gen_name(idx)
idx += 1
# 替换
# 使用占位符替换
placeholders = {}
p_idx = 0
for old_name, new_name in name_map.items():
js = re.sub(rf'\b{re.escape(old_name)}\b', new_name, js)
placeholder = f'__VAR_{p_idx}__'
placeholders[placeholder] = new_name
js = re.sub(rf'\b{re.escape(old_name)}\b', placeholder, js)
p_idx += 1
for placeholder, new_name in placeholders.items():
js = js.replace(placeholder, new_name)
# 恢复保护的内容
for i, p in enumerate(protected):
for i, p in enumerate(prot_arr):
js = js.replace(f'__PROT_{i}__', p)
return js
@@ -474,6 +504,7 @@ def obfuscate_identifiers(js: str) -> str:
def add_dead_code(js: str, complexity: int = 2) -> str:
"""
添加无效代码增加逆向难度
使用迷惑性变量名
Args:
js: JavaScript 源代码
@@ -482,15 +513,22 @@ def add_dead_code(js: str, complexity: int = 2) -> str:
Returns:
添加死代码后的代码
"""
import random
# 迷惑性字符集
chars = ['o', 'O', 'l', 'I', 'α', 'ο', 'а', 'о', '', '', '', '', '']
def rand_name():
return ''.join(random.choices(chars, k=7))
dead_code_templates = [
'var _$d0=function(){return Math.random()>2};',
'var _$d1=(function(){var _=[];for(var i=0;i<0;i++)_.push(i);return _})();',
'if(typeof _$d2==="undefined")var _$d2=null;',
'try{if(false)throw new Error()}catch(_$e){}',
'var _$d3=Date.now()%1===2?1:0;',
f'var {rand_name()}=function(){{return Math.random()>(~~2)}};',
f'var {rand_name()}=(function(){{var {rand_name()}=[];for(var {rand_name()}=(+[]);{rand_name()}<(+[]);{rand_name()}++){rand_name()}.push({rand_name()});return {rand_name()}}})();',
f'if(typeof {rand_name()}===(+[])?null:undefined)var {rand_name()}=null;',
f'try{{if((+[]))throw new Error()}}catch({rand_name()}){{}}',
f'var {rand_name()}=Date.now()%(+!![])===((2|0))?((+!![])):((+[]));',
]
import random
dead_codes = random.sample(dead_code_templates, min(complexity, len(dead_code_templates)))
# 在代码开头添加