欢迎光临
我们一直在努力

如何绕过 Python 导入系统:利用自定义 Import Hook 实现加密加载

作为资深开发者,我们有时需要保护部分核心代码不以明文形式部署。Python 强大的导入系统(Import System)为我们提供了实现此目的的手段:自定义导入钩子(Import Hook)。通过向 sys.meta_path 注入自定义的 Finder 和 Loader,我们可以拦截特定的模块导入请求,并在加载时对其进行解密。

本文将通过一个简单的 XOR 加密示例,展示如何构建一个自定义的导入机制,实现代码的加密加载。

核心概念

Python 3.3+ 的导入机制主要依赖两个抽象类:

  1. Meta Path Finder(查找器): 实现 find_spec(fullname, path, target=None) 方法。它负责在 sys.meta_path 中被调用,确定如何导入模块,并返回一个 ModuleSpec 对象。
  2. Loader(加载器):ModuleSpec 携带,负责实际执行代码。必须实现 exec_module(module) 方法,将模块的内容(此时应为解密后的代码)编译并执行到模块命名空间中。

第一步:准备加密模块文件

我们首先定义一个简单的 XOR 加密/解密函数,并使用它来加密我们的目标模块文件。

创建文件 secret_module_source.py

# secret_module_source.py - 原始代码
def get_secret_message():
    return "This message was successfully decrypted during import!"

print("--- Secret module loaded via custom hook ---")

创建加密工具 encrypt_tool.py 来生成加密文件 secret_module.enc

# encrypt_tool.py

# 统一使用的密钥
KEY = 42

def simple_xor_encrypt(data, key):
    return bytes([b ^ key for b in data])

# 读取明文代码
with open('secret_module_source.py', 'rb') as f:
    source_data = f.read()

# 加密并写入目标文件
encrypted_data = simple_xor_encrypt(source_data, KEY)
with open('secret_module.enc', 'wb') as f:
    f.write(encrypted_data)

print("Encryption complete: secret_module.enc created.")
# 注意:在实际部署中,你需要移除 secret_module_source.py 文件。

运行 python encrypt_tool.py

第二步:实现自定义 Finder 和 Loader

现在我们创建主程序文件 main.py,其中包含 Finder、Loader 的定义以及 Hook 的注册。

# main.py

import sys
import importlib.abc
import importlib.util

# 密钥必须与加密时一致
KEY = 42
TARGET_MODULE_NAME = "secret_module"
ENCRYPTED_FILE = "secret_module.enc"

def simple_xor_decrypt(data, key):
    return bytes([b ^ key for b in data])

class EncryptedLoader(importlib.abc.Loader):
    """负责解密并执行模块代码"""
    def __init__(self, data):
        self.encrypted_data = data

    def create_module(self, spec):
        # 允许系统默认创建模块对象
        return None

    def exec_module(self, module):
        # 1. 解密数据
        decrypted_code_bytes = simple_xor_decrypt(self.encrypted_data, KEY)
        # 2. 将字节转换为字符串
        decrypted_source = decrypted_code_bytes.decode('utf-8')

        # 3. 编译代码对象
        code = compile(
            decrypted_source, 
            module.__spec__.origin, 
            'exec'
        )

        # 4. 在模块的命名空间中执行编译后的代码
        exec(code, module.__dict__)


class EncryptedFinder(importlib.abc.MetaPathFinder):
    """负责查找特定模块文件,并提供定制化的 Loader"""
    def find_spec(self, fullname, path, target=None):
        if fullname != TARGET_MODULE_NAME:
            return None

        try:
            with open(ENCRYPTED_FILE, 'rb') as f:
                encrypted_data = f.read()

            # 创建加载器实例,传入加密数据
            loader = EncryptedLoader(encrypted_data)

            # 创建模块规范 (ModuleSpec)
            spec = importlib.util.spec_from_loader(fullname, loader)

            # 标记来源,方便调试 (可选)
            spec.origin = f'encrypted_source:{ENCRYPTED_FILE}'

            return spec

        except FileNotFoundError:
            print(f"Warning: Encrypted file {ENCRYPTED_FILE} not found.")
            return None

# --- 注册 Import Hook ---

# 插入到 sys.meta_path 的最前面,确保它优先于默认导入机制被检查
sys.meta_path.insert(0, EncryptedFinder())
print("Custom Encrypted Import Hook registered.")

# --- 导入测试 ---

# 尝试导入加密的模块
import secret_module

# 调用模块中的函数
message = secret_module.get_secret_message()
print(f"Received message: {message}")

第三步:运行验证

确保你已经运行了 encrypt_tool.py 生成了 secret_module.enc

运行 python main.py,你将看到如下输出:

Custom Encrypted Import Hook registered.
--- Secret module loaded via custom hook ---
Received message: This message was successfully decrypted during import!

这证明了在 Python 执行 import secret_module 时,系统成功调用了我们自定义的 EncryptedFinder,并由 EncryptedLoader 负责在内存中解密、编译和执行了代码,而硬盘上的文件始终保持加密状态。

【本站文章皆为原创,未经允许不得转载】:汤不热吧 » 如何绕过 Python 导入系统:利用自定义 Import Hook 实现加密加载
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址