|
Компьютерный форум OSzone.net » Программирование, базы данных и автоматизация действий » Программирование и базы данных » Delphi - Delphi | Работа с памятью чужого процесса, перехват API |
|
Delphi - Delphi | Работа с памятью чужого процесса, перехват API
|
![]() Старожил Сообщения: 300 |
Вопрос в PM пришел:
Цитата DillerInc:
Цитата:
|
|||
Отправлено: 20:15, 21-07-2005 |
![]() Старожил Сообщения: 300
|
Профиль | Сайт | Отправить PM | Цитировать hasherfrog
Темы разбил... DillerInc Цитата:
Цитата:
Цитата:
Кстати говоря, а Вы не из под 9x/Me случайно работаете?! Там область применения VirtualProtectEx() ограничена 2 Гб, а область загрузки системных DLL как раз идет дальше (т.н. shared virtual address space). p.s.: получать адрес из числа (Integer->Pointer) в Delphi лучше функцией ptr(), например ptr($4FFF). |
|||
Отправлено: 11:58, 27-07-2005 | #11 |
Для отключения данного рекламного блока вам необходимо зарегистрироваться или войти с учетной записью социальной сети. Если же вы забыли свой пароль на форуме, то воспользуйтесь данной ссылкой для восстановления пароля. |
![]() Обратный инженер Сообщения: 644
|
Профиль | Отправить PM | Цитировать Savant
Цитата:
Цитата:
![]() Цитата:
...возможна ли тут какая-то заковырка ? |
|||
------- Отправлено: 15:53, 27-07-2005 | #12 |
![]() Обратный инженер Сообщения: 644
|
Профиль | Отправить PM | Цитировать В общем,почитав всякого и наковырявшись с кодом "по полной программе",я к сожалению так конкретно и не понял почему возникает вышеописанная ошибка - ну,да бог с ним...
Во большинстве материалов,которые я читал,преподавалась следующая техника т.н. "сплайсинга" системных функций: в адресном пространстве чужого процесса создаётся удалённый поток с помощью CreateRemoteThread,в который потом подгружается библиотека,ответственная за перехват системных функций (размещение своих команд в начале таких функций,перенаправление управления на свой код-перехватчик)... Причём такой вариант трактуется именно как наиболее предпочтительный и эффективный. Но теперь я здесь по иному вопросу. Функция GetModuleHandle возвращает дескриптор указанного модуля,который,как я понял,является ни чем иным как базовым адрестом загрузки этого самого модуля.Проблема заключается походу в следующем: Цитата MSDN:
А как можно получить такой дескриптор какого-нибудь модуля в чужом процессе ? |
|
------- Отправлено: 23:56, 01-08-2005 | #13 |
![]() Обратный инженер Сообщения: 644
|
Профиль | Отправить PM | Цитировать Я почти достиг того,чего я хотел,а именно:
var sInfo : TStartupInfo; pInfo : TProcessInformation; dEvent : _DEBUG_EVENT; Base : Cardinal; dll_Name : array [0..MAX_PATH - 1] of Char; begin if CreateProcess(OpenFileName.lpstrFile, NIL, NIL, NIL, False, DEBUG_ONLY_THIS_PROCESS, NIL, NIL, sInfo, pInfo) then begin repeat // начинаем бесконечный цикл ожидания отладочного события WaitForDebugEvent(dEvent, INFINITE); if dEvent.dwDebugEventCode = LOAD_DLL_DEBUG_EVENT then // если отладочное событие - загрузка библиотеки,то... begin PPointer(Base) := dEvent.LoadDll.lpBaseOfDll; // ...получаем базовый адрес загруженной библиотеки if GetModuleFileNameEx(pInfo.hProcess, Base, @dll_Name, SizeOf(dll_Name)) <> 0 then // Пытаемся получить имя библиотеки по её модулю... begin Break; // Если предыдущая функция удалась,то выходим из бесконечного цикла end else MessageBox(Handle, 'Function failed', NIL, MB_OK); DoExit; // Типа убиваем всё наповал :] end; ContinueDebugEvent(dEvent.dwProcessId, dEvent.dwThreadId, DBG_CONTINUE); until False; Соответственно,кто-нибудь может сказать в чём могут быть причины ? Можно,конечно,пытаться использовать поле dEvent.LoadDll.lpImageName структуры _DEBUG_EVENT, которое,как я понял,должно содержать указатель на имя загруженной библиотеки,но там какие-то трудности,о которых как-то размыто пишут на MSDN...и сколько я не пробЫвал использовать эту возможность - ничего путного не выходило.Хотя это был бы наверное самый идеальный вариант получения имени загруженной библиотеки. |
------- Последний раз редактировалось DillerInc, 05-08-2005 в 00:08. Отправлено: 00:19, 04-08-2005 | #14 |
![]() Обратный инженер Сообщения: 644
|
Профиль | Отправить PM | Цитировать хм...неужели я задаю такие сложные вопросы,что никто не хочет на них отвечать...
![]() Иными словами,либо я чего-то не допонимаю,либо библиотека psapi.dll, в которой объявлены такие функции как GetModuleFileNameEx, GetModuleBaseName, криво написана... Тем не менее мне удалось создать работающий код(точнее взять его основу на MSDN),который будет динамически получать имя загружаемой в чужом процессе библиотеки,хотя,по-моему,всё это скорее напоминает какие-то танцы с бубном. function GetFileNameFromHandle(hFile : Cardinal) : Boolean; { Параметр hFile мы получаем из dEvent.LoadDll.hFile (см. выше) - кстати,одно из значений,которое в отличии от остальных значений реально возвращается отладочным событием LOAD_DLL_DEBUG_EVENT } const wantedLibName = 'XXX.dll'; var hFileMap : Cardinal; pMem : Pointer; FilePath : array [0..MAX_PATH - 1] of Char; sFilePath : String; sFileName : String; begin Result := False; try hFileMap := CreateFileMapping(hFile, NIL, PAGE_READONLY, 0, 0, NIL); if hFileMap <> 0 then begin pMem := MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 1); if pMem <> NIL then begin if GetMappedFileName(GetCurrentProcess(), pMem, @FilePath, SizeOf(FilePath)) <> 0 then // тут мы наконец-то получаем полный путь к нашему файлу begin sFilePath := StrPas(FilePath); sFileName := ExtractFileName(sFilePath); // здесь мы убираем путь,оставляя только само имя файла... if AnsiSameText(wantedLibName, sFileName) then // и сравниваем его с именем искомого файла begin Result := True; end; end else MessageBox(Handle, 'GetMappedFileName failed', NIL, MB_OK); end else MessageBox(Handle, 'pMem = NIL', NIL, MB_OK); end else MessageBox(Handle, 'hFileMap = 0', NIL, MB_OK); finally UnMapViewOfFile(pMem); CloseHandle(hFileMap); end; // try...finally end; // GetFileNameFromHandle ![]() |
------- Отправлено: 01:30, 09-08-2005 | #15 |
![]() Обратный инженер Сообщения: 644
|
Профиль | Отправить PM | Цитировать В общем,подумал,что может кому-то будет интересно,каким образом можно всё-таки поймать вызов какой-нибудь API-функции,заменив первые команды последней банальным EB FE,то есть попросту зациклив эту функцию.
Случай относится к тому варианту,когда вы запускаете подопытный процесс в режиме CREATE_SUSPENDED. Причина,из-за которой у меня в своё время не получалось поймать функцию,заключалась в следующем. При подобной технике необходимо,чтобы процесс был разморожен и как бы начал физически выполняться,если так можно выразиться. Достигается это с помощью предварительного зацикливания процесса на точке входа,а именно: var OpenDlgBox : TOpenFileName; sInfo : TStartupInfo; pInfo : TProcessInformation; EntryPoint : Cardinal; RestoreEP : WORD; // Функция для зацикливания адреса,которая возвращает два оригинальных байта,заменённых нашим опкодом function EndlessLoopRVA(RVA : DWORD) : WORD; const Code : WORD = $FEEB; // наш магический опкод error : LPCTSTR = 'Произошла ошибка во время зацикливания RVA'; var OriginalData : WORD; Temp_Protect : Cardinal; nBytesRead, nBytesWritten : Cardinal; begin try VirtualProtectEx(pInfo.hProcess, PPointer(RVA), 2, PAGE_EXECUTE_READWRITE, Temp_Protect); ReadProcessMemory(pInfo.hProcess, PPointer(RVA), @OriginalData, 2, nBytesRead); WriteProcessMemory(pInfo.hProcess, PPointer(RVA), @Code, SizeOf(WORD), nBytesWritten); VirtualProtectEx(pInfo.hProcess, PPointer(RVA), 2, Temp_Protect, Temp_Protect); Result := OriginalData; except MessageBox(Handle, error, NIL, MB_OK); end; // try...except end; // EndlessLoopRVA // Процедура,которая восстанавливает оригинальные байты procedure RestoreData(RVAs : DWORD; RestoreCode : WORD); var Trash : WORD; // это просто для размещения мусора Temp_Protect : Cardinal; nBytesRead, nBytesWritten : Cardinal; begin try VirtualProtectEx(pInfo.hProcess, PPointer(RVAs), 2, PAGE_EXECUTE_READWRITE, Temp_Protect); ReadProcessMemory(pInfo.hProcess, PPointer(RVAs), @Trash, 2, nBytesRead); WriteProcessMemory(pInfo.hProcess, PPointer(RVAs), @RestoreCode, SizeOf(WORD), nBytesWritten); VirtualProtectEx(pInfo.hProcess, PPointer(RVAs), 2, Temp_Protect, Temp_Protect); except MessageBox(Handle, 'Произошла ошибка при восстановлении кода', NIL, MB_OK); end; // try...except end; // RestoreData begin if CreateProcess(OpenDlgBox.lpstrFile, nil, nil, nil, False, CREATE_SUSPENDED, nil, nil, sInfo, pInfo) then begin RestoreEP := EndlessLoopRVA(EntryPoint); // Помещаем наш опкод на точку входа ResumeThread(pInfo.hThread); // Размораживаем процесс Sleep(300); // Даём ему немножко времени очухаться SuspendThread(pInfo.hThread); // Снова замораживаем его RestoreData(EntryPoint, RestoreEP); // И восстанавливаем оригинальные байты end; end; Под конец стоит заметить,что зацикливание библиотечных функций не будет работать на 9х-ой линейке Windows,т.к. если я не ошибаюсь,библиотеки там отображаются в некую общую область памяти,а не в каждый процесс отдельно. |
------- Отправлено: 16:53, 21-04-2006 | #16 |
Новый участник Сообщения: 2
|
Профиль | Отправить PM | Цитировать Вижу тема давнишняя, но наверняка сюда заходят.
Была аналогичная проблема с получением хендла длл в чужом процессе. Честно говоря был удивлен не найдя простой функции для этого. Пришлось делать через тулхелп32. В юзес подключаем Tlhelp32 и перечисляем модули в конкретном процессе(или если не ошибаюсь во всех когда вместо PId передаётся 0): {Code} // HLibrary := GetModuleHandle(PWideChar('ИмяМодуля.Dll')); Вот так разумеется не проканывает // HLibrary разумеется глобальная переменная procedure TForm1.Button2Click(Sender: TObject); var SnapModule: CARDINAL; ModuleEntry: ModuleEntry32; NextModule: BOOL; begin HLibrary := 0; SnapModule := CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, PId); // Не забываем предварительно получить пид ModuleEntry.dwSize := SizeOf(ModuleEntry); NextModule := Module32First(SnapModule, ModuleEntry); while NextModule do begin if ModuleEntry.szModule = 'ИмяМодуля.Dll' then begin HLibrary := ModuleEntry.hModule; Exit; end; NextModule := Module32Next(SnapModule, ModuleEntry); end; CloseHandle(SnapModule); end; {/Code} Ну там можно поиграть структурой ModuleEntry под свои потребности. Там много интересных полей. |
Отправлено: 16:08, 08-04-2012 | #17 |
Новый участник Сообщения: 2
|
Профиль | Отправить PM | Цитировать DillerInc
"var ProcAddress : LPDWORD; Temp_Protect : Cardinal; begin ProcAddress := LPDWORD(GetProcAddress(GetModuleHandle('Kernel32.dll'), 'LoadLibraryA'));" Зачем ProcAddress какого то непонятного типа? var ProcAddress: POINTER; begin ProcAddress := GetProcAddress(GetModuleHandle('Kernel32.dll'), 'LoadLibraryA');" Функция VirtualProtectEx судя из описания в моей студии требует lpAddress (System.Pointer), так надо понимать lp перед переменной означает что нам нужен LONG POINTER, т.е. указатель на функцию, а не указатель на параметр DWORD. Зачем там все эти выкрутасы? Поймать то вызов легко. Создаётся удалённый поток в процессе "жертве", и поток загружает нашу длл в адресное пространство. А в длл разумеется код который выполняет перехват(затирает первые 5 байт перехватываемой функции и записывает адрес нашей функции), и в зависимости от задачи можно восстановить искомую функцию, вызвать её, и опять переписать 5 байт до следующего вызова. А вот самому вызвать свою функцию из своей же длл(закинутой в сторонний процесс) не понятно пока как. Я понимаю что моя длл теперь в виртуальном пространстве стороннего процесса. Непонятно почему .modBaseAddr(как я понимаю адрес загрузки) совпадает с хендлом модуля. Допустим можно вычислить адрес функции, но ведь это виртуальный адрес в том процессе, и как вызвать функцию по виртуальному адресу? |
Последний раз редактировалось QWERYTY, 12-04-2012 в 19:44. Отправлено: 13:06, 11-04-2012 | #18 |
![]() |
Участник сейчас на форуме |
![]() |
Участник вне форума |
![]() |
Автор темы |
![]() |
Сообщение прикреплено |
| |||||
Название темы | Автор | Информация о форуме | Ответов | Последнее сообщение | |
Перехват API функций | ники | Лечение систем от вредоносных программ | 23 | 09-04-2009 11:21 | |
Перехват API на выключение компьютера | __sa__nya | Программное обеспечение Windows | 3 | 11-06-2008 13:54 | |
Delphi - Delphi | перехват проводника | Crowner | Программирование и базы данных | 5 | 06-02-2007 18:30 | |
Win32 API | Граббинг контента чужого TreeView | Scorpion666 | Программирование и базы данных | 1 | 26-01-2006 11:03 | |
WinAPI | Изменение контекстного меню чужого процесса | megad | Программирование и базы данных | 8 | 17-08-2005 21:42 |
|