From 508381cbebd74e0b5d7e3862a470312c593c4845 Mon Sep 17 00:00:00 2001 From: violettools Date: Mon, 26 Jan 2026 02:51:34 +0800 Subject: [PATCH] =?UTF-8?q?X27CN=20v1.4.3:=20=E5=A2=9E=E5=BC=BA=E6=95=B0?= =?UTF-8?q?=E5=AD=97=E6=B7=B7=E6=B7=86=20-=20=E4=BD=BF=E7=94=A8JS=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E8=BD=AC=E6=8D=A2=E8=A1=A8=E8=BE=BE=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 70 ++++++++++------ x27cn/README.md | 70 +++++++++++++++- x27cn/pyproject.toml | 2 +- x27cn/x27cn/__init__.py | 2 +- x27cn/x27cn/advanced.py | 81 +++++++++++++------ x27cn/x27cn/minify.py | 174 ++++++++++++++++++++++++---------------- 6 files changed, 279 insertions(+), 120 deletions(-) diff --git a/README.md b/README.md index bb051fb..b64c301 100644 --- a/README.md +++ b/README.md @@ -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 "<38db>..." ``` -### 混淆效果 +### 在线工具 -```html - -

Hello World

- - - - -``` - -浏览器加载混淆后的文件会自动解密并正常显示原始内容,源代码无法被直接查看。 +访问 [X27CN 在线工具](https://cfspider.pages.dev) 可直接在浏览器中进行加密/解密和代码混淆。 ### 安全说明 -X27CN 设计用于**代码混淆**,不是密码学安全的加密算法。适用于前端代码保护、API 响应混淆、防止代码被轻易复制等场景。 +X27CN 设计用于**代码混淆**,不是密码学安全的加密算法。适用于前端代码保护、API 响应混淆、防止代码被轻易复制等场景。密码加密功能使用 PBKDF2-SHA256 算法。 --- diff --git a/x27cn/README.md b/x27cn/README.md index fc1b866..a2c50db 100644 --- a/x27cn/README.md +++ b/x27cn/README.md @@ -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 diff --git a/x27cn/pyproject.toml b/x27cn/pyproject.toml index a0a18ef..6d1d81f 100644 --- a/x27cn/pyproject.toml +++ b/x27cn/pyproject.toml @@ -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" diff --git a/x27cn/x27cn/__init__.py b/x27cn/x27cn/__init__.py index b8a971f..9e0fae5 100644 --- a/x27cn/x27cn/__init__.py +++ b/x27cn/x27cn/__init__.py @@ -89,7 +89,7 @@ from .advanced import ( quick_protect, ) -__version__ = '1.4.1' +__version__ = '1.4.3' __author__ = 'CFspider' __all__ = [ # 核心加密 diff --git a/x27cn/x27cn/advanced.py b/x27cn/x27cn/advanced.py index 134639d..b0d63e5 100644 --- a/x27cn/x27cn/advanced.py +++ b/x27cn/x27cn/advanced.py @@ -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'(? 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))) # 在代码开头添加