pwntools 读取程序输出的同时也记录在日志文件中

pwn_college

在使用 pwntools 的 pwnlib.tubes.process 模块时,遇到的问题是,既想要用 recvuntil() 在脚本中读取到程序的 stdout 输出,又想在终端 PTY 上同时看到程序的输入。

一般这是把程序 pipe 到 tee 来解决的,但得起个 shell 还得处理 buffer 的问题。
要么就只使用 recvline(),每次收到数据后自行转写文件。
或者直接开启 debug 日记级别,不过默认的输出格式和程序直接在终端上输出的样子大相径庭。

最后想了个简单的注入方式:

def tee(process, logfile='/tmp/challenge.log'):
    orig_send_raw = process.send_raw
    orig_recv_raw = process.recv_raw
    log_file = open(logfile, 'wb')
 
    def send_raw(data):
        log_file.write(data)
        log_file.flush()
        return orig_send_raw(data)
 
    def recv_raw(numb):
        data = orig_recv_raw(numb) or b''  # orig may return str('')
        log_file.write(data)
        log_file.flush()
        return data
 
    process.send_raw = send_raw
    process.recv_raw = recv_raw
    context.terminal = ['tmux', 'splitw', '-v']
    run_in_new_terminal('tail -s 0.1 -f ' + logfile, kill_at_exit=False)
 
 
p = process('/challenge/run')
tee(p, '/tmp/challenge.log')

把 process 类真正处理输入输出的 send_raw & recv_raw 封装起来。
纵向分屏避免 tail 窗口关闭后因终端宽度变更,终端上已有文字产生错位。

Pyright 将 while True 循环退出后的变量推断为 Never 类型

在最近的编程时发现 VSCode / Zed 基于的 pyright 静态类型检查工具,对 while True 中带有条件 break 的变量赋值,类型推断上存在不足。

a = b''
while True:
    if a and a:
        break
    a += b'0'
a.decode() # <- 此处 a 被推断为 Never 类型,方法无法识别
a = b''
while 1:
    if a and a:
        break
    a += b'0'
a.decode() # <- 此处 a 被推断为 bytes 类型,方法也正确解析并高亮

在编辑器里有很明显的高亮提示差异。使用 while 1 替代 while True 能让方法正确识别。或者保持 while True,用 if a 直白判断。

查了一圈最接近的算是这些,而且官方不认为是 bug,也不会修复。

JetBrains 家的 IDE 倒是没这问题,毕竟另起炉灶实现的。