Table of Contents
Steps to read PEB
Conclusion
Home Backend Development Golang How to implement peb in golang

How to implement peb in golang

Apr 14, 2023 am 11:21 AM

PEB (Process Environment Block) is the environment block of a process, which stores a lot of system-level information, such as the base address of the process, the environment variables of the process, the command line parameters of the process, etc. In the Windows kernel, PEB is implemented as a structure, which can be read through Undocumented Native API (such as ZwQueryInformationProcess) in Kernel Mode.

In this article, we will introduce how to use golang language to implement a simple PEB viewer.

Steps to read PEB

  1. Get the handle of the current process.

    In golang, we can use the GetCurrentProcess function in the syscall package to get the handle of the current process.

    handle, err := syscall.GetCurrentProcess()
    if err != nil {
        fmt.Println("获取当前进程句柄失败:", err)
        return
    }
    defer syscall.CloseHandle(handle)
    Copy after login
  2. Query the information of the current process, including the address of the PEB.

    In Windows, we can use ZwQueryInformationProcess or NtQueryInformationProcess to read process information. However, these APIs are not directly exposed in golang, so we need to use the unsafe package to call system functions.

    var pbi PROCESS_BASIC_INFORMATION
    var returnLength uint32
    ntStatus := NtQueryInformationProcess(
        handle,
        PROCESS_BASIC_INFORMATION_CLASS,
        uintptr(unsafe.Pointer(&pbi)),
        uint32(unsafe.Sizeof(pbi)),
        uintptr(unsafe.Pointer(&returnLength)),
    )
    if ntStatus != STATUS_SUCCESS {
        fmt.Println("获取进程PEB信息失败:", ntStatus)
        return
    }
    Copy after login

    In the above code, we define a PROCESS_BASIC_INFORMATION structure to save the process information returned by the NtQueryInformationProcess function. We tell the system the information we need to read by specifying the PROCESS_BASIC_INFORMATION_CLASS enumeration value. What we need here is the PEB information. In addition, we also need to provide a buffer to save the returned information and the size of this buffer.

    For specific implementation, please refer to this project [https://github.com/processhacker/phnt](https://github.com/processhacker/phnt), which implements some system APIs and provides Some data structures, such as PROCESS_BASIC_INFORMATION.

  3. Read the information in the PEB structure.

    PEB is a very important structure that stores information about many processes. The following is the definition of PEB:

    typedef struct _PEB {
        BOOLEAN InheritedAddressSpace;
        BOOLEAN ReadImageFileExecOptions;
        BOOLEAN BeingDebugged;
        BOOLEAN SpareBool;
        HANDLE Mutant;
        PVOID ImageBaseAddress;
        PPEB_LDR_DATA Ldr;
        PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
        PVOID SubSystemData;
        PVOID ProcessHeap;
        PRTL_CRITICAL_SECTION FastPebLock;
        PVOID AtlThunkSListPtr;
        PVOID IFEOKey;
        PVOID CrossProcessFlags;
        PVOID UserSharedInfoPtr;
        ULONG SystemReserved[1];
        ULONG AtlThunkSListPtr32;
        PVOID ApiSetMap;
    } PEB, *PPEB;
    Copy after login

    We can use golang's unsafe package to read these data. For example, we can use the following code to read the ImageBaseAddress of PEB:

    type PEB struct {
        InheritedAddressSpace    bool
        ReadImageFileExecOptions bool
        BeingDebugged            bool
        SpareBool                bool
        Mutant                   syscall.Handle
        ImageBaseAddress         uintptr
        Ldr                      *PEB_LDR_DATA
        ProcessParameters        *RTL_USER_PROCESS_PARAMETERS
        SubSystemData            uintptr
        ProcessHeap              uintptr
        FastPebLock              *RTL_CRITICAL_SECTION
        AtlThunkSListPtr         uintptr
        IFEOKey                  uintptr
        CrossProcessFlags        uintptr
        UserSharedInfoPtr        uintptr
        SystemReserved           [1]uint32
        AtlThunkSListPtr32       uintptr
        ApiSetMap                uintptr
    }
    
    func (p *PEB) GetImageBaseAddress() uintptr {
        return p.ImageBaseAddress
    }
    
    peb := (*PEB)(unsafe.Pointer(pbi.PebBaseAddress))
    fmt.Printf("ImageBaseAddress: 0x%x\n", peb.GetImageBaseAddress())
    Copy after login

    In the above code, we first define a PEB structure and specify types for the fields in the structure. Next, we implemented a GetImageBaseAddress function to return the ImageBaseAddress field in the PEB. Finally, we read the information in the PEB by converting the base address of the PEB to the *PEB type.

  4. Read the module information of the process.

    After obtaining the ImageBaseAddress in PEB, we can traverse the InMemoryOrderModuleList in PEB_LDR_DATA to obtain all module information loaded in the process.

    typedef struct _LDR_DATA_TABLE_ENTRY {
        LIST_ENTRY InLoadOrderLinks;
        LIST_ENTRY InMemoryOrderLinks;
        LIST_ENTRY InInitializationOrderLinks;
        PVOID DllBase;
        PVOID EntryPoint;
        ULONG SizeOfImage;
        UNICODE_STRING FullDllName;
        UNICODE_STRING BaseDllName;
        ULONG Flags;
        USHORT LoadCount;
        USHORT TlsIndex;
        union {
            LIST_ENTRY HashLinks;
            struct {
                PVOID SectionPointer;
                ULONG CheckSum;
            };
        };
        union {
            ULONG TimeDateStamp;
            struct {
                PVOID LoadedImports;
                PVOID EntryPointActivationContext;
            };
        };
    } LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
    
    typedef struct _PEB_LDR_DATA {
        ULONG Length;
        BOOLEAN Initialized;
        HANDLE SsHandle;
        LIST_ENTRY InLoadOrderModuleList;
        LIST_ENTRY InMemoryOrderModuleList;
        LIST_ENTRY InInitializationOrderModuleList;
        PVOID EntryInProgress;
        BOOLEAN ShutdownInProgress;
        HANDLE ShutdownThreadId;
    } PEB_LDR_DATA, *PPEB_LDR_DATA;
    Copy after login

    We can use the following code to traverse module information:

    type LDR_DATA_TABLE_ENTRY struct {
        InLoadOrderLinks            LIST_ENTRY
        InMemoryOrderLinks          LIST_ENTRY
        InInitializationOrderLinks  LIST_ENTRY
        DllBase                     uintptr
        EntryPoint                  uintptr
        SizeOfImage                 uint32
        FullDllName                 UNICODE_STRING
        BaseDllName                 UNICODE_STRING
        Flags                       uint32
        LoadCount                   uint16
        TlsIndex                    uint16
        HashLinks                   LIST_ENTRY
        TimeDateStamp               uint32
    }
    
    type PEB_LDR_DATA struct {
        Length                             uint32
        Initialized                        bool
        SsHandle                           syscall.Handle
        InLoadOrderModuleList              LIST_ENTRY
        InMemoryOrderModuleList            LIST_ENTRY
        InInitializationOrderModuleList    LIST_ENTRY
    }
    
    pebLdrData := (*PEB_LDR_DATA)(unsafe.Pointer(peb.Ldr))
    moduleList := (*LIST_ENTRY)(unsafe.Pointer(&pebLdrData.InMemoryOrderModuleList))
    
    for moduleList.Flink != uintptr(unsafe.Pointer(&pebLdrData.InMemoryOrderModuleList)) {
        ldrDataTableEntry := (*LDR_DATA_TABLE_ENTRY)(unsafe.Pointer(moduleList.Flink))
        moduleName := WcharPtrToString(ldrDataTableEntry.BaseDllName.Buffer, uint32(ldrDataTableEntry.BaseDllName.Length/2))
        moduleBase := ldrDataTableEntry.DllBase
        moduleSize := ldrDataTableEntry.SizeOfImage
        moduleEntry := ldrDataTableEntry.EntryPoint
        moduleList = (*LIST_ENTRY)(unsafe.Pointer(moduleList.Flink))
        fmt.Printf("模块名称:%s,基地址:%x,大小:%x,入口点:%x\n", moduleName, moduleBase, moduleSize, moduleEntry)
    }
    Copy after login

    In the above code, we first define an LDR_DATA_TABLE_ENTRY structure to save module information. Then we define a PEB_LDR_DATA structure and convert the peb.Ldr pointer to this structure pointer. Finally, we traverse the InMemoryOrderModuleList list and read each module.

    After obtaining the base address of the module, we can use the ReadProcessMemory function to read the data in the module. For specific implementation, please refer to this project [https://github.com/AllenDang/w32/blob/master/process_windows.go](https://github.com/AllenDang/w32/blob/master/process_windows.go), It implements functions for reading data from the process.

    However, it should be noted that if the process we want to obtain is another process, then we need to specify the access permissions of the process when reading the process data. In golang, we can use the CreateToolhelp32Snapshot function to obtain a list of all processes and specify specific access permissions when obtaining the process handle.

    const (
        PROCESS_QUERY_INFORMATION     = 0x0400
        PROCESS_VM_READ               = 0x0010
        PROCESS_VM_WRITE              = 0x0020
        PROCESS_VM_OPERATION          = 0x0008
        PROCESS_CREATE_THREAD         = 0x0002
        PROCESS_CREATE_PROCESS        = 0x0080
        PROCESS_TERMINATE             = 0x0001
        PROCESS_ALL_ACCESS            = 0x1F0FFF
        TH32CS_SNAPPROCESS            = 0x00000002
    )
    
    func openProcess(pid uint32) (handle syscall.Handle, err error) {
        handle, err = syscall.OpenProcess(PROCESS_VM_READ|PROCESS_QUERY_INFORMATION|PROCESS_VM_WRITE, false, pid)
        return
    }
    
    func main() {
        snapshot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
        defer syscall.CloseHandle(snapshot)
    
        var procEntry PROCESSENTRY32
        procEntry.Size = uint32(unsafe.Sizeof(procEntry))
    
        var (
            handle syscall.Handle
            err error
        )
    
        if Process32First(snapshot, &procEntry) {
            for {
                if strings.EqualFold(strings.ToLower(WcharPtrToString(procEntry.ExeFile[:])), "notepad.exe") {
                    fmt.Printf("找到 notepad 进程,pid:%d\n", procEntry.ProcessID)
                    handle, err = openProcess(procEntry.ProcessID)
                    if err != nil {
                        fmt.Println("打开进程失败:", err)
                    }
                }
    
                if !Process32Next(snapshot, &procEntry) {
                    break
                }
            }
        }
    }
    Copy after login

Conclusion

This article introduces how to use golang language to implement a simple PEB viewer. PEB is a process environment block, which is implemented as a structure in the Windows kernel, which stores a lot of system-level information. By using golang's unsafe package, we can read the PEB information and module information of the process. However, it should be noted that when reading the PEB information and module information of another process, you need to specify access permissions.

The above is the detailed content of How to implement peb in golang. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Article

R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
2 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
Repo: How To Revive Teammates
4 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island Adventure: How To Get Giant Seeds
4 weeks ago By 尊渡假赌尊渡假赌尊渡假赌

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Go language pack import: What is the difference between underscore and without underscore? Go language pack import: What is the difference between underscore and without underscore? Mar 03, 2025 pm 05:17 PM

This article explains Go's package import mechanisms: named imports (e.g., import "fmt") and blank imports (e.g., import _ "fmt"). Named imports make package contents accessible, while blank imports only execute t

How to implement short-term information transfer between pages in the Beego framework? How to implement short-term information transfer between pages in the Beego framework? Mar 03, 2025 pm 05:22 PM

This article explains Beego's NewFlash() function for inter-page data transfer in web applications. It focuses on using NewFlash() to display temporary messages (success, error, warning) between controllers, leveraging the session mechanism. Limita

How to convert MySQL query result List into a custom structure slice in Go language? How to convert MySQL query result List into a custom structure slice in Go language? Mar 03, 2025 pm 05:18 PM

This article details efficient conversion of MySQL query results into Go struct slices. It emphasizes using database/sql's Scan method for optimal performance, avoiding manual parsing. Best practices for struct field mapping using db tags and robus

How do I write mock objects and stubs for testing in Go? How do I write mock objects and stubs for testing in Go? Mar 10, 2025 pm 05:38 PM

This article demonstrates creating mocks and stubs in Go for unit testing. It emphasizes using interfaces, provides examples of mock implementations, and discusses best practices like keeping mocks focused and using assertion libraries. The articl

How can I define custom type constraints for generics in Go? How can I define custom type constraints for generics in Go? Mar 10, 2025 pm 03:20 PM

This article explores Go's custom type constraints for generics. It details how interfaces define minimum type requirements for generic functions, improving type safety and code reusability. The article also discusses limitations and best practices

How to write files in Go language conveniently? How to write files in Go language conveniently? Mar 03, 2025 pm 05:15 PM

This article details efficient file writing in Go, comparing os.WriteFile (suitable for small files) with os.OpenFile and buffered writes (optimal for large files). It emphasizes robust error handling, using defer, and checking for specific errors.

How do you write unit tests in Go? How do you write unit tests in Go? Mar 21, 2025 pm 06:34 PM

The article discusses writing unit tests in Go, covering best practices, mocking techniques, and tools for efficient test management.

How can I use tracing tools to understand the execution flow of my Go applications? How can I use tracing tools to understand the execution flow of my Go applications? Mar 10, 2025 pm 05:36 PM

This article explores using tracing tools to analyze Go application execution flow. It discusses manual and automatic instrumentation techniques, comparing tools like Jaeger, Zipkin, and OpenTelemetry, and highlighting effective data visualization

See all articles