You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Python 3中获取argv的原始字节数据(含任意特殊字节)

获取Python 3中argv的原始字节序列

要解决这个问题,核心是绕开Python对sys.argv的自动编码/解码处理——因为sys.argv的字符串是Python根据系统文件编码解码后的结果,必然会破坏原始字节的完整性(比如非法UTF-8字节被替换,合法UTF-8字节被转成Unicode字符,导致无法还原原始字节)。

我们需要直接从底层C层面获取进程启动时传入的原始argv字节数组,下面是跨平台的实现方案:

跨平台解决方案(使用ctypes)

这个方法直接访问C运行时的argv数据,完全跳过Python的编码处理,能完整保留所有原始字节:

import ctypes
import sys

def get_raw_argv_bytes():
    if sys.platform.startswith('win'):
        # Windows平台:通过CRT函数获取原始ANSI命令行并解析为argv
        kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
        shell32 = ctypes.WinDLL('shell32', use_last_error=True)
        
        # 获取原始ANSI命令行字符串
        kernel32.GetCommandLineA.restype = ctypes.c_char_p
        cmd_line = kernel32.GetCommandLineA()
        
        # 将命令行解析为argv数组
        shell32.CommandLineToArgvA.restype = ctypes.POINTER(ctypes.c_char_p)
        argc = ctypes.c_int()
        argv = shell32.CommandLineToArgvA(cmd_line, ctypes.byref(argc))
        
        if not argv:
            raise ctypes.WinError(ctypes.get_last_error())
        
        try:
            # 提取第一个参数(跳过脚本路径)并读取原始字节
            raw_args = []
            for i in range(1, argc.value):
                arg_ptr = argv[i]
                if arg_ptr:
                    arg_bytes = b''
                    offset = 0
                    while True:
                        b = ctypes.c_char.from_address(ctypes.addressof(arg_ptr) + offset).value
                        if b == b'\x00':
                            break
                        arg_bytes += b
                        offset += 1
                    raw_args.append(arg_bytes)
            return raw_args[0] if len(raw_args) == 1 else raw_args
        finally:
            # 释放CRT分配的内存
            kernel32.LocalFree.argtypes = [ctypes.c_void_p]
            kernel32.LocalFree(argv)
    else:
        # Unix-like平台:直接访问libc的全局argc和argv变量
        libc = ctypes.CDLL(None)
        argc = ctypes.c_int.in_dll(libc, 'argc')
        argv = ctypes.POINTER(ctypes.c_char_p).in_dll(libc, 'argv')
        
        raw_args = []
        for i in range(1, argc.value):
            arg_ptr = argv[i]
            if arg_ptr:
                arg_bytes = b''
                offset = 0
                while True:
                    b = ctypes.c_char.from_address(ctypes.addressof(arg_ptr) + offset).value
                    if b == b'\x00':
                        break
                    arg_bytes += b
                    offset += 1
                raw_args.append(arg_bytes)
        return raw_args[0] if len(raw_args) == 1 else raw_args

# 验证你的断言
raw_argv = get_raw_argv_bytes()
assert raw_argv == b'123\xffABC\xe2\x98\xba\x20'

方案原理说明

  • Unix-like系统:直接通过ctypes访问C标准库的全局argc和argv变量,这些就是进程启动时内核传递的原始字节数组,没有经过任何Python层面的编码处理。
  • Windows系统:利用CRT的CommandLineToArgvA函数,将原始ANSI编码的命令行解析为argv数组,确保拿到的是和C程序传入一致的原始字节。

为什么这个方案能避免无效结果

  • 不会将\xff错误编码为\xc3\xbf:完全跳过了UTF-8解码步骤,直接保留原始字节。
  • 不会出现编码错误:不需要对Unicode字符进行反向编码,因为根本没有经过解码。
  • 不会丢失任何字节:无论是单个的非法UTF-8字节(如\xff),还是合法的多字节UTF-8序列(如\xe2\x98\xba),都会完整保留。

内容的提问来源于stack exchange,提问作者JamesTheAwesomeDude

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:41:29