我正在开发 Go 库来访问一些内部 Windows 线程结构(线程环境 block ),这需要编写一些汇编代码。我一直试图理解为什么这在 Win32 C++ 应用程序上有效,但在我的 Go 库上却不起作用。
这段 Go 汇编代码访问 fs:[0x18] 以返回指向线程关联 TEB 的指针:
// func ReadFsDword(offset uint32) (dword uint32)
TEXT ·ReadFsDword(SB),$0-8
MOVL offset+0(FP), AX
// mov eax, dword ptr fs:[eax]
BYTE $0x64; BYTE $0x8B; BYTE $0x00
MOVL AX, ret+8(FP)
RET
这是等效的 MASM 代码,它可以在 MSVC 上正常编译和运行:
void* readfsdword(unsigned offset_)
{
unsigned dw;
__asm {
mov eax, offset_
mov eax, fs:[eax]
mov dw, eax
}
return (void*)dw;
}
当访问返回的 TEB 指针时,Go 程序会发生困惑。这是我收到的消息:
panic: runtime error: invalid memory address or nil pointer dereference [signal 0xc0000005 code=0x0 addr=0x0 pc=0x498d5b]
Go 汇编代码对我来说似乎是正确的,但我无法理解程序如何以及为什么会出现 panic 。非常感谢任何帮助!
以下是重现该问题的示例:
intrinsics.s
#include "textflag.h"
#include "funcdata.h"
// func ReadFsDword(offset uint32) (ret uint32)
TEXT ·ReadFsDword(SB),$0-8
MOVL offset+0(FP), AX
// mov eax, dword ptr fs:[eax]
BYTE $0x64; BYTE $0x8B; BYTE $0x00
MOVL AX, ret+8(FP)
RET
intrinsics.go
package nt
func ReadFsDword(offset uint32) (ret uint32)
test.go
package main
import "nt"
func main() {
GetProcAddress("LoadLibraryExW")
}
func GetProcAddress(proc string) unsafe.Pointer {
teb := nt.NtGetTeb()
fmt.Printf("%p", teb)
// todo: implement
return nil
}
最佳答案
问题已解决。显然,Windows 在 x64 上使用 gs
寄存器,偏移量为 0x30,而在 x86/WoW64 模式下使用 fs
和偏移量 0x18。
解决方案是使用 fs
或 gs
以及相应的偏移量,具体取决于 GOARCH
的值。
关于windows - Go程序访问线程环境 block 时出现panic,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51639548/