Jadual Kandungan
Langkah-langkah membaca PEB
Kesimpulan
Rumah pembangunan bahagian belakang Golang Cara melaksanakan peb dalam golang

Cara melaksanakan peb dalam golang

Apr 14, 2023 am 11:21 AM

PEB (Blok Persekitaran Proses) ialah blok persekitaran proses, yang menyimpan banyak maklumat peringkat sistem, seperti alamat asas proses, pembolehubah persekitaran proses, parameter baris arahan proses , dsb. Dalam kernel Windows, PEB dilaksanakan sebagai struktur, yang boleh dibaca melalui API Asli Tidak Berdokumen (seperti ZwQueryInformationProcess) dalam Mod Kernel.

Dalam artikel ini, kami akan memperkenalkan cara melaksanakan pemapar PEB yang mudah menggunakan bahasa golang.

Langkah-langkah membaca PEB

  1. Dapatkan pengendalian proses semasa.

    Dalam golang, kita boleh menggunakan fungsi GetCurrentProcess dalam pakej syscall untuk mendapatkan pengendalian proses semasa.

    1

    2

    3

    4

    5

    6

    handle, err := syscall.GetCurrentProcess()

    if err != nil {

        fmt.Println("获取当前进程句柄失败:", err)

        return

    }

    defer syscall.CloseHandle(handle)

    Salin selepas log masuk
  2. Soal maklumat proses semasa, termasuk alamat PEB.

    Dalam Windows, kami boleh menggunakan ZwQueryInformationProcess atau NtQueryInformationProcess untuk membaca maklumat proses. Walau bagaimanapun, API ini tidak didedahkan secara langsung dalam golang, jadi kami perlu menggunakan pakej yang tidak selamat untuk memanggil fungsi sistem.

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    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

    }

    Salin selepas log masuk

    Dalam kod di atas, kami mentakrifkan struktur PROCESS_BASIC_INFORMATION untuk menyimpan maklumat proses yang dikembalikan oleh fungsi NtQueryInformationProcess. Kami memberitahu sistem maklumat yang perlu kami baca dengan menyatakan nilai penghitungan PROCESS_BASIC_INFORMATION_CLASS Apa yang kami perlukan di sini ialah maklumat PEB. Selain itu, kami juga perlu menyediakan penimbal untuk menyimpan maklumat yang dikembalikan dan saiz penimbal ini.

    Untuk pelaksanaan khusus, sila rujuk projek ini [https://github.com/processhacker/phnt](https://github.com/processhacker/phnt), yang melaksanakan beberapa API sistem dan menyediakan Beberapa struktur data, seperti PROCESS_BASIC_INFORMATION.

  3. Baca maklumat dalam struktur PEB.

    PEB ialah struktur yang sangat penting yang menyimpan maklumat tentang banyak proses. Berikut ialah definisi PEB:

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    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;

    Salin selepas log masuk

    Kita boleh menggunakan pakej tidak selamat golang untuk membaca data ini. Sebagai contoh, kita boleh menggunakan kod berikut untuk membaca ImageBaseAddress PEB:

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    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())

    Salin selepas log masuk

    Dalam kod di atas, kita mula-mula mentakrifkan struktur PEB dan menentukan jenis untuk medan dalam struktur . Seterusnya, kami melaksanakan fungsi GetImageBaseAddress untuk mengembalikan medan ImageBaseAddress dalam PEB. Akhir sekali, kami membaca maklumat dalam PEB dengan menukar alamat asas PEB kepada jenis *PEB.

  4. Baca maklumat modul proses.

    Selepas mendapatkan ImageBaseAddress dalam PEB, kami boleh melintasi InMemoryOrderModuleList dalam PEB_LDR_DATA untuk mendapatkan semua maklumat modul yang dimuatkan dalam proses.

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    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;

    Salin selepas log masuk

    Kami boleh menggunakan kod berikut untuk merentasi maklumat modul:

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    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)

    }

    Salin selepas log masuk

    Dalam kod di atas, kami mula-mula mentakrifkan struktur LDR_DATA_TABLE_ENTRY untuk menyimpan maklumat modul . Kemudian kami mentakrifkan struktur PEB_LDR_DATA dan menukar penunjuk peb.Ldr kepada penunjuk struktur ini. Akhir sekali, kami melintasi senarai InMemoryOrderModuleList dan membaca setiap modul.

    Selepas mendapatkan alamat asas modul, kita boleh menggunakan fungsi ReadProcessMemory untuk membaca data dalam modul. Untuk pelaksanaan khusus, sila rujuk projek ini [https://github.com/AllenDang/w32/blob/master/process_windows.go](https://github.com/AllenDang/w32/blob/master/process_windows.go ), Ia melaksanakan fungsi untuk membaca data daripada proses.

    Namun, perlu diingatkan bahawa jika proses yang ingin kita perolehi adalah proses lain, maka kita perlu menentukan kebenaran capaian proses tersebut apabila membaca data proses. Dalam golang, kita boleh menggunakan fungsi CreateToolhelp32Snapshot untuk mendapatkan senarai semua proses dan menentukan kebenaran akses tertentu apabila mendapatkan pemegang proses.

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    40

    41

    42

    43

    44

    45

    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

                }

            }

        }

    }

    Salin selepas log masuk

Kesimpulan

Artikel ini memperkenalkan cara menggunakan bahasa golang untuk melaksanakan pemapar PEB yang mudah. PEB ialah blok persekitaran proses, yang dilaksanakan sebagai struktur dalam kernel Windows, yang menyimpan banyak maklumat peringkat sistem. Dengan menggunakan pakej golang yang tidak selamat, kita boleh membaca maklumat PEB dan maklumat modul proses tersebut. Walau bagaimanapun, perlu diingat bahawa apabila membaca maklumat PEB dan maklumat modul proses lain, anda perlu menentukan kebenaran akses.

Atas ialah kandungan terperinci Cara melaksanakan peb dalam golang. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn

Tag artikel panas

Notepad++7.3.1

Notepad++7.3.1

Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina

SublimeText3 versi Cina

Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1

Hantar Studio 13.0.1

Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6

Dreamweaver CS6

Alat pembangunan web visual

SublimeText3 versi Mac

SublimeText3 versi Mac

Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

GO Language Pack Import: Apakah perbezaan antara garis bawah dan tanpa garis bawah? GO Language Pack Import: Apakah perbezaan antara garis bawah dan tanpa garis bawah? Mar 03, 2025 pm 05:17 PM

GO Language Pack Import: Apakah perbezaan antara garis bawah dan tanpa garis bawah?

Bagaimana saya menulis objek dan stub untuk ujian di GO? Bagaimana saya menulis objek dan stub untuk ujian di GO? Mar 10, 2025 pm 05:38 PM

Bagaimana saya menulis objek dan stub untuk ujian di GO?

Bagaimana untuk melaksanakan pemindahan maklumat jangka pendek antara halaman dalam kerangka beego? Bagaimana untuk melaksanakan pemindahan maklumat jangka pendek antara halaman dalam kerangka beego? Mar 03, 2025 pm 05:22 PM

Bagaimana untuk melaksanakan pemindahan maklumat jangka pendek antara halaman dalam kerangka beego?

Bagaimana saya boleh menggunakan alat pengesanan untuk memahami aliran pelaksanaan aplikasi saya? Bagaimana saya boleh menggunakan alat pengesanan untuk memahami aliran pelaksanaan aplikasi saya? Mar 10, 2025 pm 05:36 PM

Bagaimana saya boleh menggunakan alat pengesanan untuk memahami aliran pelaksanaan aplikasi saya?

Bagaimana saya boleh menentukan kekangan jenis tersuai untuk generik di GO? Bagaimana saya boleh menentukan kekangan jenis tersuai untuk generik di GO? Mar 10, 2025 pm 03:20 PM

Bagaimana saya boleh menentukan kekangan jenis tersuai untuk generik di GO?

Bagaimana cara menukar senarai hasil pertanyaan mysql ke dalam slice struktur tersuai dalam bahasa Go? Bagaimana cara menukar senarai hasil pertanyaan mysql ke dalam slice struktur tersuai dalam bahasa Go? Mar 03, 2025 pm 05:18 PM

Bagaimana cara menukar senarai hasil pertanyaan mysql ke dalam slice struktur tersuai dalam bahasa Go?

Bagaimana cara menulis fail dalam bahasa Go dengan mudah? Bagaimana cara menulis fail dalam bahasa Go dengan mudah? Mar 03, 2025 pm 05:15 PM

Bagaimana cara menulis fail dalam bahasa Go dengan mudah?

Bagaimanakah saya boleh menggunakan alat linter dan analisis statik untuk meningkatkan kualiti dan pemeliharaan kod pergi saya? Bagaimanakah saya boleh menggunakan alat linter dan analisis statik untuk meningkatkan kualiti dan pemeliharaan kod pergi saya? Mar 10, 2025 pm 05:38 PM

Bagaimanakah saya boleh menggunakan alat linter dan analisis statik untuk meningkatkan kualiti dan pemeliharaan kod pergi saya?

See all articles