如何在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
相关产品推荐
相关产品推荐

