PEB (プロセス環境ブロック) はプロセスの環境ブロックであり、プロセスのベース アドレス、プロセスの環境変数、プロセスのコマンド ライン パラメーターなど、多くのシステム レベルの情報が保存されます。 、など。 Windows カーネルでは、PEB は構造として実装されており、カーネル モードで文書化されていないネイティブ API (ZwQueryInformationProcess など) を通じて読み取ることができます。
この記事では、golang 言語を使用して簡単な PEB ビューアを実装する方法を紹介します。
現在のプロセスのハンドルを取得します。
golang では、syscall パッケージの GetCurrentProcess 関数を使用して、現在のプロセスのハンドルを取得できます。
handle, err := syscall.GetCurrentProcess() if err != nil { fmt.Println("获取当前进程句柄失败:", err) return } defer syscall.CloseHandle(handle)
PEB のアドレスを含む、現在のプロセスの情報をクエリします。
Windows では、ZwQueryInformationProcess または NtQueryInformationProcess を使用してプロセス情報を読み取ることができます。ただし、これらの API は golang で直接公開されていないため、システム関数を呼び出すには安全でないパッケージを使用する必要があります。
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 }
上記のコードでは、NtQueryInformationProcess 関数によって返されたプロセス情報を保存するための PROCESS_BASIC_INFORMATION 構造体を定義します。 PROCESS_BASIC_INFORMATION_CLASS 列挙値を指定して、読み取る必要がある情報をシステムに伝えます。ここで必要なのは PEB 情報です。さらに、返された情報を保存するためのバッファーとこのバッファーのサイズも提供する必要があります。
具体的な実装については、このプロジェクト [https://github.com/processhacker/phnt](https://github.com/processhacker/phnt) を参照してください。このプロジェクトは、いくつかのシステム API を実装し、いくつかの機能を提供します。 PROCESS_BASIC_INFORMATION などのデータ構造。
PEB 構造内の情報を読みます。
PEB は、多くのプロセスに関する情報を保存する非常に重要な構造です。以下は 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;
golang の安全でないパッケージを使用してこれらのデータを読み取ることができます。たとえば、次のコードを使用して PEB の ImageBaseAddress を読み取ることができます。
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())
上記のコードでは、最初に PEB 構造を定義し、構造内のフィールドの型を指定します。次に、PEB の ImageBaseAddress フィールドを返す GetImageBaseAddress 関数を実装しました。最後に、PEB のベース アドレスを *PEB タイプに変換することで、PEB 内の情報を読み取ります。
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;
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) }
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 } } } }
以上がgolangでpebを実装する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。