如何补丁Go二进制文件,将time.Sleep固定为仅等待1秒?
修改Go二进制文件中的time.Sleep行为及相关疑问解答
一、补丁time.Sleep使其固定等待1秒
- 明确参数传递逻辑:Go的
time.Sleep最终调用runtime.timeSleep,接收的time.Duration本质是int64类型(单位纳秒)。在x86_64架构下,该参数通常通过rdi寄存器传递;其他架构规则以你的gdb反汇编结果为准。 - 定位参数使用位置:在gdb中反汇编
runtime.timeSleep,找到使用传入参数的指令段——比如把寄存器值加载到等待时间计算逻辑里的指令。你需要在参数被使用前,强制将其替换为固定值(1秒=10^9纳秒,对应十六进制0x3B9ACA00)。 - 具体补丁操作:
- 若参数通过寄存器传递:在
timeSleep函数开头插入指令,覆盖原参数寄存器的值。比如x86_64下添加mov rdi, 0x3B9ACA00,对应的机器码是48 C7 C7 00 CA 9A 3B。 - 若参数通过栈传递:找到栈中存储参数的内存位置,将对应字节替换为固定值的十六进制表示。
- 若参数通过寄存器传递:在
- hexedit修改二进制的步骤:
- 用gdb获取
runtime.timeSleep的虚拟地址:执行info func runtime.timeSleep得到目标地址(比如0x45abc0)。 - 转换虚拟地址到文件偏移:用
objdump -h 你的二进制文件查看text段信息,比如text段虚拟起始地址为0x400000、文件偏移为0x1000,则目标地址的文件偏移为0x1000 + (0x45abc0 - 0x400000)。 - 打开hexedit跳转到该偏移,将原指令机器码替换为新指令的机器码,注意指令长度要匹配,避免破坏后续指令对齐。
- 用gdb获取
二、关于修改本地time.go文件的疑问
- 1)修改本地文件不会影响已预编译的二进制:已编译完成的二进制已将runtime的机器码打包在内,和本地源码完全独立。只有用修改后的Go源码重新编译Go工具链,再用新工具链编译目标程序时,修改才会生效。
- 2)gdb断点指向的是编译时使用的源码:你的二进制是用
/usr/local/go/src路径下的Go工具链编译的,所以gdb会加载该路径的源码作为调试符号的对应文件,但运行时二进制执行的是编译后的机器码,并非直接调用这个文件。
内容的提问来源于stack exchange,提问作者Chelinka
相关产品推荐
相关产品推荐

