1

Тема: AHK: Чтение переменных окружения из другого процесса

Функция PsGetEnv позволяет получить список переменных окружения указанного процесса или одну из переменных. Сочетание битностей (32/64) скрипта и процесса может быть любым.

Использована информация отсюда, отсюда и отсюда.


MsgBox, % PsGetEnv("AutoHotkey.exe", "Temp")    ; Переменная.
MsgBox, % PsGetEnv("AutoHotkey.exe")            ; Весь список.

; Переменная процесса активного окна.
F10::
    WinGet, PID, PID, A
    MsgBox, % PsGetEnv(PID, "Path")
Return


; ============================= Функция ===================================

PsGetEnv(Process, Var = 0)
{
    Static PBI  ; PROCESS_BASIC_INFORMATION
    Static MBI, pMBI, cbMBI := 48  ; MEMORY_BASIC_INFORMATION
    Static PROCESS_VM_READ := 0x10, PROCESS_QUERY_INFORMATION := 0x400
    Static STATUS_SUCCESS := 0, cbPES_max := 0x4000 ; Макс. размер блока переменных.
    If (!PBI) {
        VarSetCapacity(PBI, 48), VarSetCapacity(MBI, cbMBI + 16)
        ; Выравнять по границе 16 байт для NtWow64QueryVirtualMemory64.
        pMBI := ((&MBI + 16) >> 4) << 4
    }
    Process, Exist, %Process%
    If !(PID := ErrorLevel)
        Return Error("Процесс не найден")
    If !(hProcess := DllCall("OpenProcess", "uint", PROCESS_VM_READ | PROCESS_QUERY_INFORMATION
                                          , "int", 0, "uint", PID, "ptr"))
        Return Error("Ошибка OpenProcess")
    If (A_Is64bitOS)
        DllCall("IsWow64Process", "ptr", hProcess, "int *", Wow64Process)
    If (!A_Is64bitOS || Wow64Process)   ; Процесс 32-битный.
        PsPtrSize := 4, pptr := "uint *", OffsetRUPP := 16, OffsetPES := 0x48
    Else                                ; Процесс 64-битный.
        PsPtrSize := 8, pptr := "int64 *", OffsetRUPP := 32, OffsetPES := 0x80
    If (A_PtrSize < PsPtrSize) {    ; Скрипт х32, процесс х64.
        InfoClass := 0, cbPBI := 48, OffsetPEB := 8
        ;;; PROCESS_BASIC_INFORMATION (PBI)
        If (DllCall("ntdll.dll\NtWow64QueryInformationProcess64"
                , "ptr", hProcess, "int", InfoClass, "ptr", &PBI, "uint", cbPBI
                , "int64 *", ReturnLength) <> STATUS_SUCCESS)
            Return Error("Ошибка NtWow64QueryInformationProcess64", hProcess)
        ;;; Process Environment Block (PEB)
        pPEB := NumGet(PBI, OffsetPEB, "int64")
        ;;; RTL_USER_PROCESS_PARAMETERS (RUPP)
        If (DllCall("ntdll.dll\NtWow64ReadVirtualMemory64"
                , "ptr", hProcess, "int64", pPEB + OffsetRUPP, "int64 *", pRUPP
                , "int64", 8, "int64 *", BytesRead) <> STATUS_SUCCESS)
            Return Error("Ошибка NtWow64ReadVirtualMemory64: pRUPP", hProcess)
        ;;; Process Environment Strings (PES)
        If (DllCall("ntdll.dll\NtWow64ReadVirtualMemory64"
                , "ptr", hProcess, "int64", pRUPP + OffsetPES, "int64 *", pPES
                , "int64", 8, "int64 *", BytesRead) <> STATUS_SUCCESS)
            Return Error("Ошибка NtWow64ReadVirtualMemory64: pPES", hProcess)
        ;;; Размер региона памяти, где находится PES.
        If (DllCall("ntdll.dll\NtWow64QueryVirtualMemory64"
                , "ptr", hProcess, "int64", pPES, "uint", 0, "ptr", pMBI
                , "int64", cbMBI, "int64 *", ReturnLength) <> STATUS_SUCCESS)
            Return Error("Ошибка NtWow64QueryVirtualMemory64", hProcess)
        cbRegion := NumGet(pMBI+0, 24, "int64")
    }
    Else {
        If (A_PtrSize > PsPtrSize)  ; Скрипт х64, процесс х32.
            InfoClass := 26, cbPBI := 8, OffsetPEB := 0
        Else
            InfoClass := 0, cbPBI := A_PtrSize * 6, OffsetPEB := A_PtrSize
        ;;; PROCESS_BASIC_INFORMATION (PEB)
        If (DllCall("ntdll.dll\NtQueryInformationProcess"
                , "ptr", hProcess, "int", InfoClass, "ptr", &PBI, "uint", cbPBI
                , "uint *", ReturnLength) <> STATUS_SUCCESS)
        Return Error("Ошибка NtQueryInformationProcess", hProcess)
        ;;; Process Environment Block (PEB)
        pPEB := NumGet(PBI, OffsetPEB, "ptr")
        ;;; RTL_USER_PROCESS_PARAMETERS (RUPP)
        If !DllCall("ReadProcessMemory", "ptr", hProcess, "ptr", pPEB + OffsetRUPP
                                       , pptr, pRUPP, "ptr", PsPtrSize, "ptr *", BytesRead)
            Return Error("Ошибка ReadProcessMemory: pRUPP", hProcess)
        ;;; Process Environment Strings (PES)
        If !DllCall("ReadProcessMemory", "ptr", hProcess, "ptr", pRUPP + OffsetPES
                                       , pptr, pPES, "ptr", PsPtrSize, "ptr *", BytesRead)
            Return Error("Ошибка ReadProcessMemory: pPES", hProcess)
        ;;; Размер региона памяти, где находится PES.
        If !DllCall("VirtualQueryEx", "ptr", hProcess, "ptr", pPES, "ptr", pMBI
                                    , "ptr", cbMBI, "int64")
            Return Error("Ошибка VirtualQueryEx", hProcess)
        cbRegion := NumGet(pMBI+0, A_PtrSize * 3, "ptr")
    }
    ;;; Размер от начала блока PES до конца региона.
    cbPES := (((pPES + cbRegion) >> 12) << 12) - pPES
    If (cbPES > cbPES_max) ; Если размер большой, ограничить разумной величиной.
        cbPES := cbPES_max
    VarSetCapacity(PES, cbPES, 0)
    If (A_PtrSize < PsPtrSize) {
        If (DllCall("ntdll.dll\NtWow64ReadVirtualMemory64"
                , "ptr", hProcess, "int64", pPES, "ptr", &PES
                , "int64", cbPES, "int64 *", ReturnLength, "uint") <> STATUS_SUCCESS)
            Return Error("Ошибка NtWow64ReadVirtualMemory64: PES", hProcess)
    }
    Else {
        If !DllCall("ReadProcessMemory"
                , "ptr", hProcess, "ptr", pPES, "ptr", &PES
                , "ptr", cbPES, "ptr *", BytesRead)
            Return Error("Ошибка ReadProcessMemory: PES", hProcess)
    }
    DllCall("CloseHandle", "ptr", hProcess)

    Loop, % cbPES // 2  ; Строки в блоке разделены нулями, на конце два нуля.
    {                   ; Заменяем нули на переводы строки, кроме последних.
        If ((char := NumGet(PES, (A_Index - 1) * 2, "uchar")) = 0) {
            If (prev = 0)
                Break
            NumPut(0xA, PES, (A_Index - 1) * 2, "uchar")
        }
        prev := char
    }
    EnvList := StrGet(&PES, "utf-16")
    If (!Var)
        Return EnvList
    RegExMatch(EnvList, "im`n)^" Var "=([^\n]+)$", Found)
    Return Found1
}

Error(Msg, hProcess = 0)
{
    If (hProcess)
        DllCall("CloseHandle", "ptr", hProcess)
    MsgBox, %Msg%
    Return False
}