访问线程环境块时进入程序恐慌状态

时间:2018-08-01 17:57:45

标签: windows go assembly

我正在使用Go库进行开发,以访问某些内部Windows线程结构(线程环境块),这需要编写一些汇编代码。我一直在试图理解为什么它可以在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程序会出现紧急情况。这是我收到的消息:

  

紧急:运行时错误:无效的内存地址或nil指针   取消引用[信号0xc0000005代码= 0x0 addr = 0x0 pc = 0x498d5b]

Go汇编代码对我来说似乎是正确的,但我不明白该程序如何以及为什么会慌乱。任何帮助深表感谢!

以下是重现此问题的示例:

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
}

1 个答案:

答案 0 :(得分:5)

问题已解决。显然,Windows使用gs寄存器在x64上的偏移量为0x30,而fs和0x18的偏移量在x86 / WoW64模式下使用。 解决方案是使用fsgs并根据GOARCH的值使用各自的偏移量。