From c6cefdf04f435361f923edaf7e2013e27967f897 Mon Sep 17 00:00:00 2001 From: violettools Date: Mon, 26 Jan 2026 00:58:50 +0800 Subject: [PATCH] =?UTF-8?q?feat(x27cn):=20v1.4.1=20=E8=BF=B7=E6=83=91?= =?UTF-8?q?=E6=80=A7=E5=AD=97=E7=AC=A6=E6=B7=B7=E6=B7=86=20+=20=E6=95=B0?= =?UTF-8?q?=E5=AD=97/=E8=BF=90=E7=AE=97=E7=AC=A6=E6=B7=B7=E6=B7=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- x27cn/README.md | 23 +++++- x27cn/pyproject.toml | 2 +- x27cn/x27cn/__init__.py | 6 +- x27cn/x27cn/advanced.py | 153 +++++++++++++++++++++++++++++++++++--- x27cn/x27cn/anti_crawl.py | 14 +++- x27cn/x27cn/cli.py | 2 +- x27cn/x27cn/minify.py | 51 +++++++++++-- 7 files changed, 222 insertions(+), 29 deletions(-) diff --git a/x27cn/README.md b/x27cn/README.md index cf93b8e..fc1b866 100644 --- a/x27cn/README.md +++ b/x27cn/README.md @@ -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 打开 diff --git a/x27cn/pyproject.toml b/x27cn/pyproject.toml index 070c7fb..a0a18ef 100644 --- a/x27cn/pyproject.toml +++ b/x27cn/pyproject.toml @@ -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" diff --git a/x27cn/x27cn/__init__.py b/x27cn/x27cn/__init__.py index f792d54..b8a971f 100644 --- a/x27cn/x27cn/__init__.py +++ b/x27cn/x27cn/__init__.py @@ -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', diff --git a/x27cn/x27cn/advanced.py b/x27cn/x27cn/advanced.py index dad531b..134639d 100644 --- a/x27cn/x27cn/advanced.py +++ b/x27cn/x27cn/advanced.py @@ -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'(? 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 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, diff --git a/x27cn/x27cn/anti_crawl.py b/x27cn/x27cn/anti_crawl.py index 8c9e8f0..cf09f09 100644 --- a/x27cn/x27cn/anti_crawl.py +++ b/x27cn/x27cn/anti_crawl.py @@ -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 diff --git a/x27cn/x27cn/cli.py b/x27cn/x27cn/cli.py index 7fac7ca..12c7ad9 100644 --- a/x27cn/x27cn/cli.py +++ b/x27cn/x27cn/cli.py @@ -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='命令') diff --git a/x27cn/x27cn/minify.py b/x27cn/x27cn/minify.py index 07983e4..6d4f50a 100644 --- a/x27cn/x27cn/minify.py +++ b/x27cn/x27cn/minify.py @@ -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 = {