Получение информации о другом процессе
Возможность получения информации о стороннем процессе раскрывает перед программистами и пользователями широкие возможности. Это могут быть продвинутые менеджеры процессов, антивирусные и антитроянские программы, утилиты для реверсной инженерии и многое другое. У меня, к примеру, подобные функции используются в программе Quick Task Terminator. Давайте посмотрим, как это делается. Для начала надо описать структуры, необходимые для работы с процессами. В стандартном комплекте FASM их, естественно, нет, но это и неудивительно.Code (Assembler) : Убрать нумерацию
- ; Структура для получения данных о процессе под Win32
- struct PROCESS_BASIC_INFORMATION
- ExitStatus dd ?
- PebBaseAddress dd ?
- AffinityMask dd ?
- BasePriority dd ?
- uUniqueProcessId dd ?
- uInheritedFromUniqueProcessId dd ?
- ends
- ; Структура PEB процесса под Win32
- ; Process Enviroment Block или блок окружения процесса
- ; Содержит все параметры пользовательского режима, ассоциированные
- ; системой с текущим процессом
- struct PEB
- InheritedAddressSpace db ?
- ReadImageFileExecOptions db ?
- BeingDebugged db ?
- b003 db ?
- Mutant dd ?
- ImageBaseAddress dd ?
- Ldr dd ?
- ProcessParameters dd ?
- ends
- ; Юникодная строка в Win32
- struct UNICODE_STRING
- Length dw ?
- MaximumLength dw ?
- Buffer dd ?
- ends
- ; Структура RTL_USER_PROCESS_PARAMETERS под Win32
- struct RTL_USER_PROCESS_PARAMETERS
- MaximumLength dd ?
- Length dd ?
- Flags dd ?
- DebugFlags dd ?
- ConsoleHandle dd ?
- ConsoleFlags dd ?
- StdInputHandle dd ?
- StdOutputHandle dd ?
- StdErrorHandle dd ?
- CurrentDirectoryPath UNICODE_STRING
- CurrentDirectoryHandle dd ?
- DllPath UNICODE_STRING
- ImagePathName UNICODE_STRING
- CommandLine UNICODE_STRING
- ends
Code (Assembler) : Убрать нумерацию
- section '.data' data readable writeable
- ...
- ; Данные о 32-битных процессах
- Info PROCESS_BASIC_INFORMATION
- peb PEB
- pparam RTL_USER_PROCESS_PARAMETERS
Оформим все вышесказанное в программный код. Подразумевается, что вы уже получили значение pID нужного вам процесса. Удобнее всего сделать это через перечисление процессов при помощи CreateToolhelp32Snapshot. И да, в MSDN про RTL_USER_PROCESS_PARAMETERS читать бесполезно, лучше обратиться к альтернативным источникам информации.
Code (Assembler) : Убрать нумерацию
- ; Открыть процесс для получения информации
- invoke OpenProcess,PROCESS_QUERY_INFORMATION+PROCESS_VM_READ,0,[pID]
- ; Сохранить хэндл процесса
- mov ebx,eax
- ; Прочитать PROCESS_BASIC_INFORMATION
- invoke NtQueryInformationProcess,ebx,0,Info,\
- sizeof.PROCESS_BASIC_INFORMATION,tmp
- ; Прочитать PEB
- mov eax,[Info.PebBaseAddress]
- invoke ReadProcessMemory,ebx,eax,peb,sizeof.PEB,tmp
- ; Прочитать RTL_USER_PROCESS_PARAMETERS
- invoke ReadProcessMemory,ebx,[peb.ProcessParameters],pparam,\
- sizeof.RTL_USER_PROCESS_PARAMETERS,tmp
- ; Получить путь запуска с параметрами (CommandLine)
- movzx eax, word [pparam.CommandLine.Length]
- invoke ReadProcessMemory,ebx,\
- [pparam.CommandLine.Buffer],buff1,eax,tmp
- ; Получить рабочую директорию (CurrentDirectoryPath)
- movzx eax, word [pparam.CurrentDirectoryPath.Length]
- invoke ReadProcessMemory,ebx,\
- [pparam.CurrentDirectoryPath.Buffer],buff2,eax,tmp
- ; Получить путь запуска (ImagePathName)
- movzx eax, word [pparam.ImagePathName.Length]
- invoke ReadProcessMemory,ebx,\
- [pparam.ImagePathName.Buffer],buff3,eax,tmp
С 32-битными системами ничего сложного, но теперь, к сожалению, все чаще появляются операционные системы с 64-битной разрядностью. Для 64-битных процессов создаются свои структуры PEB, PROCESS_BASIC_INFORMATION и т.д. Причем получить доступ к ним описанными выше функциями Win32 невозможно, так как эта память находится в другом адресном пространстве с 64-битной адресацией. Однако, совмещение в одной программе возможностей полноценной работы без особых ограничений как под Win32, так и под Win64, на мой взгляд, будет большим плюсом. К примеру, сейчас лишь единицы таскменеджеров могут похвастаться такой универсальностью, остальные или не работают с 64-битными процессами, или же выпускаются в виде двух самостоятельных версий для систем с различной разрядностью.
Я являюсь приверженцем 32-битных операционных систем, и поддержку 64-битных систем расцениваю не иначе как вынужденное и неизбежное зло. Конечно, пришлось провести не один час в отладчике и потратить уйму времени, чтобы собрать по крупицам информацию, зато теперь результат моей работы перед вами. Для начала опишем необходимые структуры для работы с 64-битными процессами. В чем-то они похожи на свои 32-битные аналоги, в чем-то отличаются.
Code (Assembler) : Убрать нумерацию
- ; Структура для получения данных о процессе под Win64
- struct PROCESS_BASIC_INFORMATION_WOW64
- ExitStatus dd ?
- Reserved0 dd ?
- PebBaseAddress dq ? ; ULONG64
- AffinityMask dq ? ; ULONG64
- BasePriority dd ?
- Reserved1 dd ?
- uUniqueProcessId dq ? ; ULONG64
- uInheritedFromUniqueProcessId dq ? ; ULONG64
- ends
- ; Структура PEB процесса под Win64
- struct PEB64
- InheritedAddressSpace db ?
- ReadImageFileExecOptions db ?
- BeingDebugged db ?
- b003 db ?
- Reserved0 dd ?
- Mutant dq ?
- ImageBaseAddress dq ?
- Ldr dq ?
- ProcessParameters dq ?
- ends
- ; Юникодная строка в Win64
- struct UNICODE_STRING64
- Length dw ?
- MaximumLength dw ?
- Fill dd ?
- Buffer dq ? ; ULONG64
- ends
- ; Структура RTL_USER_PROCESS_PARAMETERS64 под Win64
- struct RTL_USER_PROCESS_PARAMETERS64
- MaximumLength dd ?
- Length dd ?
- Flags dd ?
- DebugFlags dd ?
- ConsoleHandle dq ? ; ULONG64
- ConsoleFlags dd ?
- Reserved dd ?
- StdInputHandle dq ? ; ULONG64
- StdOutputHandle dq ? ; ULONG64
- StdErrorHandle dq ? ; ULONG64
- CurrentDirectoryPath UNICODE_STRING64
- CurrentDirectoryHandle dq ?
- DllPath UNICODE_STRING64
- ImagePathName UNICODE_STRING64
- CommandLine UNICODE_STRING64
- ends
Code (Assembler) : Убрать нумерацию
- section '.data' data readable writeable
- ...
- ; Данные о 64-битных процессах
- Info64 PROCESS_BASIC_INFORMATION_WOW64
- peb64 PEB64
- pparam64 RTL_USER_PROCESS_PARAMETERS64
Code (Assembler) : Убрать нумерацию
- section '.data' data readable writeable
- ...
- ; Импортируемые функции
- ntdll db 'ntdll.dll',0
- nwiname db 'NtWow64QueryInformationProcess64',0
- nwmname db 'NtWow64ReadVirtualMemory64',0
- ; Прототипы функций
- ; NtWow64QueryInformationProcess64 (
- ; IN HANDLE DWORD ProcessHandle,
- ; IN PROCESSINFOCLASS DWORD ProcessInformationClass,
- ; OUT PVOID DWORD ProcessInformation,
- ; IN ULONG DWORD ProcessInformationLength,
- ; OUT PULONG DWORD ReturnLength OPTIONAL
- ; )
- ;
- ; NtWow64ReadVirtualMemory64(
- ; IN HANDLE DWORD ProcessHandle,
- ; IN ULONG64 QWORD BaseAddress,
- ; OUT PVOID DWORD Buffer,
- ; IN ULONG64 QWORD BufferLength,
- ; OUT PULONG64 DWORD ReturnLength OPTIONAL
- ; )
Code (Assembler) : Убрать нумерацию
- ; Получить информацию о процессе
- invoke OpenProcess,PROCESS_QUERY_INFORMATION+PROCESS_VM_READ,0,[pID]
- ; Сохранить хэндл процесса
- mov ebx,eax
- ; Получить адрес функции NtWow64QueryInformationProcess64
- invoke GetModuleHandle,ntdll
- invoke GetProcAddress,eax,nwiname
- ; NtWow64QueryInformationProcess64
- stdcall eax,ebx,0,Info64,sizeof.PROCESS_BASIC_INFORMATION_WOW64,tmp
- ; Получить адрес функции NtWow64ReadVirtualMemory64
- invoke GetModuleHandle,ntdll
- invoke GetProcAddress,eax,nwmname
- ; Сохранить адрес функции NtWow64ReadVirtualMemory64
- mov esi,eax
- ; Прочитать из памяти PEB64 процесса
- push 0
- push 0
- push sizeof.PEB64
- push peb64
- mov eax,Info64.PebBaseAddress
- push dword [eax+4]
- push dword [eax]
- ; NtWow64ReadVirtualMemory64
- stdcall esi,ebx
- ; Прочитать из памяти ProcessParameters процесса
- push 0
- push 0
- push sizeof.RTL_USER_PROCESS_PARAMETERS64
- push pparam64
- mov eax,peb64.ProcessParameters
- push dword [eax+4]
- push dword [eax]
- ; NtWow64ReadVirtualMemory64
- stdcall esi,ebx
- ; Прочитать из памяти командную строку процесса (CommandLine)
- push 0
- push 0
- movzx eax,[pparam64.CommandLine.Length]
- push eax
- push buff1
- push dword [pparam64.CommandLine.Buffer+4]
- push dword [pparam64.CommandLine.Buffer]
- ; NtWow64ReadVirtualMemory64
- stdcall esi,ebx
- ; Прочитать из памяти рабочий каталог процесса (CurrentDirectoryPath)
- push 0
- push 0
- movzx eax,[pparam64.CurrentDirectoryPath.Length]
- push eax
- push buff2
- push dword [pparam64.CurrentDirectoryPath.Buffer+4]
- push dword [pparam64.CurrentDirectoryPath.Buffer]
- ; NtWow64ReadVirtualMemory64
- stdcall esi,ebx
- ; Прочитать из памяти путь процесса (ImagePathName)
- push 0
- push 0
- movzx eax,[pparam64.ImagePathName.Length]
- push eax
- push buff3
- push dword [pparam64.ImagePathName.Buffer+4]
- push dword [pparam64.ImagePathName.Buffer]
- ; NtWow64ReadVirtualMemory64
- stdcall esi,ebx
Остался последний важный момент. Как узнать разрядность процесса? Ведь для разной разрядности нам придется использовать различные методы получения информации. Нам на помощь приходит функция IsWow64Process. Логика ее работы следующая. Если такая функция отсутствует в системе, или присутствует, но при этом для нашего процесса возвращает FALSE, то это значит, что операционная система 32-битная и никаких 64-битных процессов на ней быть не может. А если она для нашего процесса возвращает TRUE, то система 64-битная и требуется дополнительная проверка. Естественно, подразумевается, что сами мы находимся в контексте 32-битного процесса. Если под 64-битной системой для проверяемого процесса функция IsWow64Process возвращает FALSE, то это 64-битный процесс, иначе 32-битный. Для выполнения всех этих проверок я написал вот такую вспомогательную функцию.
Code (Assembler) : Убрать нумерацию
- section '.data' data readable writeable
- ...
- ; Импортируемые функции
- kernel db 'kernel32.dll',0
- iwname db 'IsWow64Process',0
Code (Assembler) : Убрать нумерацию
- ;---------------------------------------------------
- ; Процедура проверки разрядности процесса
- ;---------------------------------------------------
- ; Параметры:
- ; pID = идентификатор проверяемого процесса
- ; На выходе:
- ; EAX = 0 если процесс 32-битный
- ; EAX = 1 если процесс 64-битный
- ;---------------------------------------------------
- proc IsProcess64 pID:DWORD
- local result:DWORD
- local temp:DWORD
- pusha
- ; По умолчанию результат FALSE
- mov [result],0
- ; Определить запуск под Win64
- invoke GetModuleHandle,kernel
- invoke GetProcAddress,eax,iwname
- or eax,eax
- ; Мы под Win32, тут все процессы 32-битные
- jz .loc_ret
- ; Сохранить адрес IsWow64Process
- mov esi,eax
- ; Наш процесс запущен под Win64?
- invoke GetCurrentProcess
- ; IsWow64Process
- lea edi,[temp]
- stdcall esi,eax,edi
- cmp [temp],FALSE
- je .loc_ret
- ; Получить информацию о процессе
- invoke OpenProcess,PROCESS_QUERY_INFORMATION+PROCESS_VM_READ,0,[pID]
- or eax,eax
- jz .loc_ret
- mov ebx,eax
- ; IsWow64Process
- stdcall esi,ebx,edi
- ; Прибраться за собой
- invoke CloseHandle,ebx
- ; 32-битный процесс под Win64?
- cmp [temp],TRUE
- je .loc_ret
- mov [result],1
- .loc_ret:
- popa
- mov eax,[result]
- ret
- endp
Просмотров: 10069 | Комментариев: 6
Внимание! Статья опубликована больше года назад, информация могла устареть!
Комментарии
Отзывы посетителей сайта о статье
ManHunter
(20.09.2018 в 10:38):
Вот еще хорошее описание структуры PEB вплоть до современных систем: http://bytepointer.com/resources/tebpeb32.htm
NoName
(08.11.2014 в 17:19):
Спасибо за статью, есть всё что мне надо =)
Марат
(09.06.2013 в 22:48):
Огромное спасибо и низкий поклон за Ваши труды
ManHunter
(18.05.2013 в 21:31):
К парсеру прикручена экспериментальная фича - подсветка WinAPI в ассемблерных листингах.
ManHunter
(17.05.2013 в 18:39):
А я пробовал по аналогии qword [var], нифига не получилось. Спасибо!
disciple27
(17.05.2013 в 15:13):
ManHunter вы прям мысли читаете, как раз такое искал)))
в стек dq можно так загонять, win32ax/wx только надо:
var dq 0
invoke proc, double [var]
в стек dq можно так загонять, win32ax/wx только надо:
var dq 0
invoke proc, double [var]
Добавить комментарий
Заполните форму для добавления комментария