Тема: AHK: список модулей процесса
Доброй ночи. Помогите пожалуйста.
Пытаюсь узнать список модулей dll, которые подгружены в определенный процесс.
Я так понял что надо использовать функцию EnumProcessModules. Но как ее использовать без понятия.
Вы не вошли. Пожалуйста, войдите или зарегистрируйтесь.
Страницы 1
Чтобы отправить ответ, вы должны войти или зарегистрироваться
Доброй ночи. Помогите пожалуйста.
Пытаюсь узнать список модулей dll, которые подгружены в определенный процесс.
Я так понял что надо использовать функцию EnumProcessModules. Но как ее использовать без понятия.
Можно так. Но учтите, что если скрипт запущен в 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
}
Спасибо показывает.
Уже не в первый раз вижу подобный синтаксис. Объясните пожалуйста вот эту строчку:
List .= " " . StrGet(pszModule, "utf-16")Что значит точка перед равно и точка после кавычек?
Все таки хотелось понять как использовать функцию EnumProcessModules. Эта функция используется в справочнике, но извлечь ее у меня не получалось.
Точка означает соединение строк. Вместе с равно означает соединение и присвоение. Т.е. две строки ниже делают одно и то же. Одиночную точку указывать не обязательно.
a .= b
a := a . b
EnumProcessModules возвращает хэндлы модулей, а не имена. В каком справочнике она используется и как?
EnumProcessModules возвращает хэндлы модулей, а не имена. В каком справочнике она используется и как?
В обычном справочнике autohotkey в разделе process в примере 4.
Вот ссылка: http://script-coding.com/AutoHotkey/Process.html
Здесь написано: "Для получения всех модулей для текущего процесса в системе можно воспользоваться функцией EnumProcessModules."
http://www.sources.ru/msdn/library/enum … cess.shtml
Можно воспользоваться, но, по-моему, менее удобно. Так модули получаются с полными путями, которые надо ещё обрезать, если пути вам не нужны. А в моём варианте можно и то, и другое по выбору. Я там подправил код, добавив второй опциональный параметр для показа путей. А на основе 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
}
Спасибо огромное за два метода!
Скажите пожалуйста почему если я инжектю длл скрипт не видит этот модуль в процессе? Притом если я использую продвинутый диспетчер задач то он видит этот модуль.
Не знаю, это надо смотреть. А как вы её инжектите?
Взял 3 разных длл(например назовем их "а", "б" и "в"). Инжектил 3-мя инжекторами. Два инжектора взяты из интернета, третий использовал в 4иt инжiн. И каждый раз видело только два модуля(например "а" и "б"), а 3тий модуль не видело(модуль "в").
Продвинутый диспетчер задач "Process explorer" все модули видел.
А как смотрели? Если список модулей большой и вы его смотрите в MsgBox, то конец списка может ею отрезаться. Попробуйте его помещать в буфер обмена и потом вставлять в текстовый редактор.
А как смотрели? Если список модулей большой и вы его смотрите в MsgBox, то конец списка может ею отрезаться. Попробуйте его помещать в буфер обмена и потом вставлять в текстовый редактор.
я сразу в текстовый редактор помещал.
Поскольку использованный вами метод инжектирования мне неизвестен, то и воспроизвести его у себя я не могу, а без этого никаких идей у меня нет.
Помню у меня был рабочий инжектор на 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?
Перевести код на АНК? Можно, конечно. Да, если упорно не видится только одна DLL, то причина в ней должна быть. По логике. Может, есть способ как-то замаскировать присутствие DLL в процессе, и она при загрузке это делает. А может, в чём другом дело.
Если не сложно переведите функцию пожалуйста.
Просто странно что продвинутый диспетчер задач все видит.
Кстати есть программа процесс хакер она тоже может видеть модули и прочее. Она открыта.
Вот ее исходный код:
https://github.com/processhacker2/processhacker2
Могли бы вы пожалуйста глянуть и сказать возможно ли оттуда вытащить или сделать на подобии что бы так же показывало все модули?
Логично, что продвинутый видит, на то он и продвинутый.
Попробовал перевести. На 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
}
Могли бы вы пожалуйста глянуть и сказать возможно ли оттуда вытащить или сделать на подобии что бы так же показывало все модули?
Возможно, дело в этом:
Process Hacker uses a kernel-mode driver, KProcessHacker, to assist with certain functionality.
На АНК драйвера писать точно не вариант. ![]()
Спасибо большое!
Почему-то функция не работает.
Положил скрипт и модуль в одну папку
Писал так
PsInjectDll("test.exe", "test.dll")и так
PsInjectDll(test.exe, "test.dll")и не инжектит.
Так же перемещал на диск D и прописывал полный путь вот так:
PsInjectDll("test.exe", "D:\test.dll")Нужно, чтобы все три компонента — скрипт, процесс и DLL — были 32-битными. У вас так?
Нужно, чтобы все три компонента — скрипт, процесс и DLL — были 32-битными. У вас так?
если у вас работает значит что-то у меня. Видимо что-то с длл. Во общем огромное спасибо)
Страницы 1
Чтобы отправить ответ, вы должны войти или зарегистрироваться