1

Тема: AHK: список модулей процесса

Доброй ночи. Помогите пожалуйста.
Пытаюсь узнать список модулей dll, которые подгружены в определенный процесс.
Я так понял что надо использовать функцию EnumProcessModules. Но как ее использовать без понятия.

2 (изменено: YMP, 2016-06-19 19:43:59)

Re: AHK: список модулей процесса

Можно так. Но учтите, что если скрипт запущен в 32-битном АНК, он не сможет работать с 64-битными процессами.


MsgBox, % PsListModules("explorer.exe")     ; Только имена модулей.
MsgBox, % PsListModules("explorer.exe", 1)  ; С полными путями. MsgBox может обрезать список, т.к. макс. объём её текста ограничен.

PsListModules(Process, ShowPath = 0)    ; Process = PID or Name.exe.
{
    static StructSize, NameOffset, PathOffset, MODULEENTRY32
    static FLAGS := 0x18        ; TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32
    static INVALID_HANDLE_VALUE := -1, ERROR_PARTIAL_COPY := 299
    If (!StructSize) {
        If (A_PtrSize = 8) {
            StructSize := 1080, NameOffset := 48, PathOffset := 560
        } Else {
            StructSize := 1064, NameOffset := 32, PathOffset := 544
        }
        VarSetCapacity(MODULEENTRY32, StructSize, 0)
        NumPut(StructSize, MODULEENTRY32, 0, "uint")
    }
    Process, Exist, %Process%
    If (ErrorLevel = 0) {
        MsgBox, Процесс не найден: %Process%
        Return 0
    }
    hSnapshot := DllCall("CreateToolhelp32Snapshot", "uint", FLAGS
                                                   , "uint", ErrorLevel
                                                   , "ptr")
    If (hSnapshot = INVALID_HANDLE_VALUE) {
        If (A_LastError = ERROR_PARTIAL_COPY) {
            MsgBox, Ошибка: битность процесса выше битности скрипта.
        } Else {
            MsgBox, Ошибка CreateToolhelp32Snapshot: %A_LastError%
        }
        Return 0
    }
    List := 0
    pszModule := ShowPath ? &MODULEENTRY32 + PathOffset : &MODULEENTRY32 + NameOffset
    If DllCall("Module32FirstW", "ptr", hSnapshot, "ptr", &MODULEENTRY32) {
        List := StrGet(pszModule, "utf-16")
        While DllCall("Module32NextW", "ptr", hSnapshot, "ptr", &MODULEENTRY32) {
            List .= " " . StrGet(pszModule, "utf-16")
        }
    }
    DllCall("CloseHandle", "ptr", hSnapshot)
    Return List
}

3

Re: AHK: список модулей процесса

Спасибо показывает.
Уже не в первый раз вижу подобный синтаксис. Объясните пожалуйста вот эту строчку:

List .= " " . StrGet(pszModule, "utf-16")

Что значит точка перед равно и точка после кавычек?

Все таки хотелось понять как использовать функцию EnumProcessModules. Эта функция используется в справочнике, но извлечь ее у меня не получалось.

4

Re: AHK: список модулей процесса

Точка означает соединение строк. Вместе с равно означает соединение и присвоение. Т.е. две строки ниже делают одно и то же. Одиночную точку указывать не обязательно.


a .= b
a := a . b

EnumProcessModules возвращает хэндлы модулей, а не имена. В каком справочнике она используется и как?

5

Re: AHK: список модулей процесса

YMP пишет:

EnumProcessModules возвращает хэндлы модулей, а не имена. В каком справочнике она используется и как?

В обычном справочнике autohotkey в разделе process в примере 4.
Вот ссылка: http://script-coding.com/AutoHotkey/Process.html

Здесь написано: "Для получения всех модулей для текущего процесса в системе можно воспользоваться функцией EnumProcessModules."
http://www.sources.ru/msdn/library/enum … cess.shtml

6

Re: AHK: список модулей процесса

Можно воспользоваться, но, по-моему, менее удобно. Так модули получаются с полными путями, которые надо ещё обрезать, если пути вам не нужны. А в моём варианте можно и то, и другое по выбору. Я там подправил код, добавив второй опциональный параметр для показа путей. А на основе EnumProcessModules, по вашей второй ссылке, см. код ниже. Список модулей Проводника с путями получается длинный, и MsgBox его обрезает. Похоже, у неё предел длины текста 8192 символов.


MsgBox, % PsListModules("explorer.exe")

PsListModules(Process)  ; Process = PID or Name.exe
{
    static ModulePath, cchModulePath = 260  ; MAX_PATH
    If (!ModulePath) {
        cbModulePath := A_IsUnicode ? cchModulePath * 2 : cchModulePath
        VarSetCapacity(ModulePath, cbModulePath, 0)
    }
    Process, Exist, %Process%
    If (ErrorLevel = 0) {
        MsgBox, Процесс не найден: %Process%
        Return
    }
    If !(hProcess := DllCall("OpenProcess"
            , "uint", 0x410     ; PROCESS_QUERY_INFORMATION | PROCESS_VM_READ
            , "int", 0
            , "uint", ErrorLevel
            , "ptr")) {
        MsgBox, Ошибка OpenProcess: %A_LastError%
        Return
    }
    cbHandles := 100 * A_PtrSize
HandleArraySize:
    VarSetCapacity(Handles, cbHandles, 0)
    If !DllCall("Psapi.dll\EnumProcessModulesEx"
            , "ptr", hProcess
            , "ptr", &Handles
            , "uint", cbHandles
            , "uint *", cbNeeded
            , "uint", 3) {          ; LIST_MODULES_ALL
        If (A_LastError = 299) {    ; ERROR_PARTIAL_COPY
            MsgBox, Ошибка: битность процесса выше битности скрипта.
        } Else {
            MsgBox, Ошибка EnumProcessModulesEx: %A_LastError%
        }
        DllCall("CloseHandle", "ptr", hProcess)
        Return
    }
    If (cbNeeded > cbHandles) {
        cbHandles += 50 * A_PtrSize
        Goto, HandleArraySize
    }
    Loop, % cbNeeded // A_PtrSize
    {
        If !DllCall("Psapi.dll\GetModuleFileNameEx"
                , "ptr", hProcess
                , "ptr", NumGet(Handles, (A_Index - 1) * A_PtrSize, "ptr")
                , "ptr", &ModulePath
                , "uint", cchModulePath) {
            MsgBox, Ошибка GetModuleFileNameEx: %A_LastError%
            DllCall("CloseHandle", "ptr", hProcess)
            Return
        }
        List .= StrGet(&ModulePath) . " "
    }
    DllCall("CloseHandle", "ptr", hProcess)
    Return List
}

7

Re: AHK: список модулей процесса

Спасибо огромное за два метода!

8

Re: AHK: список модулей процесса

Скажите пожалуйста почему если я инжектю длл скрипт не  видит этот модуль в процессе? Притом если я использую продвинутый диспетчер задач то он видит этот модуль.

9

Re: AHK: список модулей процесса

Не знаю, это надо смотреть. А как вы её инжектите?

10 (изменено: Dworkin, 2016-06-22 03:32:50)

Re: AHK: список модулей процесса

Взял 3 разных длл(например назовем их "а", "б" и "в"). Инжектил 3-мя инжекторами. Два инжектора взяты из интернета, третий использовал в 4иt инжiн. И каждый раз видело только два модуля(например "а" и "б"), а 3тий модуль не видело(модуль "в").
Продвинутый диспетчер задач "Process explorer" все модули видел.

11

Re: AHK: список модулей процесса

А как смотрели? Если список модулей большой и вы его смотрите в MsgBox, то конец списка может ею отрезаться. Попробуйте его помещать в буфер обмена и потом вставлять в текстовый редактор.

12

Re: AHK: список модулей процесса

YMP пишет:

А как смотрели? Если список модулей большой и вы его смотрите в MsgBox, то конец списка может ею отрезаться. Попробуйте его помещать в буфер обмена и потом вставлять в текстовый редактор.

я сразу в текстовый редактор помещал.

13

Re: AHK: список модулей процесса

Поскольку использованный вами метод инжектирования мне неизвестен, то и воспроизвести его у себя я не могу, а без этого никаких идей у меня нет.

14 (изменено: Dworkin, 2016-06-22 20:41:12)

Re: AHK: список модулей процесса

Помню у меня был рабочий инжектор на autoit. Вот нашел его. В конце функция инжекта:

#AutoIt3Wrapper_UseUpx=n
#AutoIt3Wrapper_UseX64=n

#RequireAdmin
#include <GUIConstants.au3>

GUICreate("Beispiel", 275, 100)
GUISetBkColor(0xFFFFFF)
GUICtrlCreateLabel("Prozess:", 10, 10, 50, 17)
$I_ProcessName = GUICtrlCreateInput("", 65, 10, 200, 21)
GUICtrlCreateLabel("DLL:", 10, 40, 50, 17)
$I_DllPath = GUICtrlCreateInput("", 65, 40, 150, 21)
$B_SearchDll = GUICtrlCreateButton("...", 225, 40, 40, 25)
$R_Auto = GUICtrlCreateRadio("Automatisch", 10, 75, 75, 17)
GUICtrlSetState(-1, $GUI_CHECKED)
$R_Man = GUICtrlCreateRadio("Manuell", 130, 75, 55, 17)
$B_Inject = GUICtrlCreateButton("Injizieren", 190, 70, 75, 25)
GUICtrlSetState(-1, $GUI_DISABLE)
GUISetState()

$Injected = False

Do
    $Msg = GUIGetMsg()
    Switch $Msg
        Case $B_SearchDll
            GUICtrlSetData($I_DllPath, FileOpenDialog("Dll", @HomeDrive, "Dynamic Link Library (*.dll)", 3))
        Case $R_Auto
            GUICtrlSetState($B_Inject, $GUI_DISABLE)
        Case $R_Man
            GUICtrlSetState($B_Inject, $GUI_ENABLE)
        Case $B_Inject
            _InjectDll(ProcessExists(GUICtrlRead($I_ProcessName)), GUICtrlRead($I_DllPath))
            _Message(@error)
    EndSwitch

    If BitAND(GUICtrlRead($R_Auto), $GUI_CHECKED) And Not $Injected Then
        $ProcessId = ProcessExists(GUICtrlRead($I_ProcessName))
        If $ProcessId > 0 Then
            _InjectDll($ProcessId, GUICtrlRead($I_DllPath))
            _Message(@error)
            $Injected = True
            ;Exit
        EndIf
    EndIf

    Sleep(10)
Until $Msg == $GUI_EVENT_CLOSE



Func _Message($ErrorCode)
    If $ErrorCode <> 0 Then
        MsgBox(48, "Fehler", "Es ist ein Fehler aufgetreten!" & @CRLF & "Fehlercode: " & @error)
    Else
        MsgBox(64, "Info", "Injektion erfolgreich!")
    EndIf
EndFunc


;=================================================================================================
; Function:            _InjectDll($ProcessId, $DllPath)
; Description:        Injects a .dll into a running program.
; Return Value(s):    On Success - Returns true
;                    On Failure - Returns false
;                    @Error - 0 = No error.
;                             1 = Invalid ProcessId.
;                             2 = File does not exist.
;                             3 = File is not a .dll (invalid file).
;                             4 = Failed to open 'Advapi32.dll'.
;                             5 = Failed to get the full path.
;                             6 = Failed to open the process.
;                             7 = Failed to call 'GetModuleHandle'.
;                             8 = Failed to call 'GetProcAddress'.
;                             9 = Failed to call 'VirtualAllocEx'.
;                             10 = Failed to write the memory.
;                             11 = Failed to create the 'RemoteThread'.
; Author(s):        KillerDeluxe
;=================================================================================================

Func _InjectDll($ProcessId, $DllPath)
    If $ProcessId == 0 Then Return SetError(1, "", False)
    If Not(FileExists($DllPath)) Then Return SetError(2, "", False)
    If Not(StringRight($DllPath, 4) == ".dll") Then Return SetError(3, "", False)

    $Kernel32 = DllOpen("kernel32.dll")
    If @error Then Return SetError(4, "", False)

    $DLL_Path = DllStructCreate("char[255]")
    DllCall($Kernel32, "DWORD", "GetFullPathNameA", "str", $DllPath, "DWORD", 255, "ptr", DllStructGetPtr($DLL_Path), "int", 0)
    If @error Then Return SetError(5, "", False)

    $hProcess = DllCall($Kernel32, "DWORD", "OpenProcess", "DWORD", 0x1F0FFF, "int", 0, "DWORD", $ProcessId)
    If @error Then Return SetError(6, "", False)

    $hModule = DllCall($Kernel32, "DWORD", "GetModuleHandleA", "str", "kernel32.dll")
    If @error Then Return SetError(7, "", False)

    $lpStartAddress = DllCall($Kernel32, "DWORD", "GetProcAddress", "DWORD", $hModule[0], "str", "LoadLibraryA")
    If @error Then Return SetError(8, "", False)

    $lpParameter = DllCall($Kernel32, "DWORD", "VirtualAllocEx", "int", $hProcess[0], "int", 0, "ULONG_PTR", DllStructGetSize($DLL_Path), "DWORD", 0x3000, "int", 4)
    If @error Then Return SetError(9, "", False)

    DllCall("kernel32.dll", "BOOL", "WriteProcessMemory", "int", $hProcess[0], "DWORD", $lpParameter[0], "str", DllStructGetData($DLL_Path, 1), "ULONG_PTR", DllStructGetSize($DLL_Path), "int", 0)
    If @error Then Return SetError(10, "", False)

    $hThread = DllCall($Kernel32, "int", "CreateRemoteThread", "DWORD", $hProcess[0], "int", 0, "int", 0, "DWORD", $lpStartAddress[0], "DWORD", $lpParameter[0], "int", 0, "int", 0)
    If @error Then Return SetError(11, "", False)

    DllCall($Kernel32, "BOOL", "CloseHandle", "DWORD", $hProcess[0])
    DllClose($Kernel32)

    Return SetError(0, "", True)
EndFunc

Проверил и тот же самый результат. Видит два модуля из трех. По моему в этом случаю тут зависит от самого модуля.
Кстати возможно ли создать подобное для AHK?

15 (изменено: YMP, 2016-06-23 15:42:57)

Re: AHK: список модулей процесса

Перевести код на АНК? Можно, конечно. Да, если упорно не видится только одна DLL, то причина в ней должна быть. По логике. Может, есть способ как-то замаскировать присутствие DLL в процессе, и она при загрузке это делает. А может, в чём другом дело.

16

Re: AHK: список модулей процесса

Если не сложно переведите функцию пожалуйста.
Просто странно что продвинутый диспетчер задач все видит.
Кстати есть программа процесс хакер она тоже может видеть модули и прочее. Она открыта.
Вот ее исходный код:
https://github.com/processhacker2/processhacker2
Могли бы вы пожалуйста глянуть и сказать возможно ли оттуда вытащить или сделать на подобии что бы так же показывало все модули?

17

Re: AHK: список модулей процесса

Логично, что продвинутый видит, на то он и продвинутый.

Попробовал перевести. На 32 битах работает, а на 64 целевой процесс вылетает с исключением. Видимо, это связано с тем, что адреса загрузки системных библиотек на 64 битах рандомизируются. Соответственно, адрес функции LoadLibrary, полученный в адресном пространстве скрипта, в целевом процессе указывает на какой-то случайный код, выполнение которого удалённым потоком и вызывает исключение.


PsInjectDll(Process, DllName)   ; Process — PID или Name.exe.
{
    static AccessRights = 0x43A     ; PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION
    ; | PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION
    Process, Exist, %Process%
    If !(PID := ErrorLevel) {
        MsgBox, Процесс не найден: %Process%
        Return 0
    }
    If !FileExist(DllName) {
        MsgBox, DLL не найдена: %DllName%
        Return 0
    }
    hKernel32 := DllCall("GetModuleHandleW", "wstr", "Kernel32.dll", "ptr")
    pLoadLibrary := DllCall("GetProcAddress", "ptr", hKernel32, "astr", "LoadLibraryW", "ptr")
    If !(hProcess := DllCall("OpenProcess", "uint", AccessRights, "int", 0, "uint", PID, "ptr")) {
        MsgBox, Ошибка OpenProcess: %A_LastError%
        Return 0
    }
    RetVal := 0
    cbDllName := (StrLen(DllName) + 1) * 2
    If !(pDllName := DllCall("VirtualAllocEx", "ptr", hProcess
                                             , "ptr", 0
                                             , "ptr", cbDllName
                                             , "uint", 0x3000   ; MEM_RESERVE | MEM_COMMIT
                                             , "uint", 4        ; PAGE_READWRITE
                                             , "ptr")) {
        MsgBox, Ошибка VirtualAllocEx: %A_LastError%
        Goto, Close
    }
    If !DllCall("WriteProcessMemory", "ptr", hProcess
                                    , "ptr", pDllName
                                    , "wstr", DllName
                                    , "ptr", cbDllName
                                    , "ptr *", cbWritten) {
        MsgBox, Ошибка WriteProcessMemory: %A_LastError%
        Goto, Free
    }
    If !(hThread := DllCall("CreateRemoteThread", "ptr", hProcess
                                                , "ptr", 0
                                                , "ptr", 0
                                                , "ptr", pLoadLibrary
                                                , "ptr", pDllName
                                                , "uint", 0
                                                , "ptr", 0
                                                , "ptr")) {
        MsgBox, Ошибка CreateRemoteThread: %A_LastError%
        Goto, Free
    }
    DllCall("CloseHandle", "ptr", hThread)
    RetVal := 1
    Goto, Close
Free:
    DllCall("VirtualFreeEx", "ptr", hProcess, "ptr", pDllName, "ptr", 0, "uint", 0x8000)
    ; 0x8000 = MEM_RELEASE
Close:
    DllCall("CloseHandle", "ptr", hProcess)
    Return RetVal
}

18

Re: AHK: список модулей процесса

Dworkin пишет:

Могли бы вы пожалуйста глянуть и сказать возможно ли оттуда вытащить или сделать на подобии что бы так же показывало все модули?

Возможно, дело в этом:

Process Hacker uses a kernel-mode driver, KProcessHacker, to assist with certain functionality.

На АНК драйвера писать точно не вариант.

19

Re: AHK: список модулей процесса

Спасибо большое!
Почему-то функция не работает.
Положил скрипт и модуль в одну папку
Писал так

PsInjectDll("test.exe", "test.dll")

и так

PsInjectDll(test.exe, "test.dll")

и не инжектит.
Так же перемещал на диск D и прописывал полный путь вот так:

PsInjectDll("test.exe", "D:\test.dll")

20

Re: AHK: список модулей процесса

Нужно, чтобы все три компонента — скрипт, процесс и DLL — были 32-битными. У вас так?

21

Re: AHK: список модулей процесса

YMP пишет:

Нужно, чтобы все три компонента — скрипт, процесс и DLL — были 32-битными. У вас так?

если у вас работает значит что-то у меня. Видимо что-то с длл. Во общем огромное спасибо)