Имя пользователя:
Пароль:  
Помощь | Регистрация | Забыли пароль?  | Правила  

Компьютерный форум OSzone.net » Программирование, базы данных и автоматизация действий » Программирование и базы данных » Delphi - Delphi | Работа с памятью чужого процесса, перехват API

Ответить
Настройки темы
Delphi - Delphi | Работа с памятью чужого процесса, перехват API

Аватара для Savant

Старожил


Сообщения: 300
Благодарности: 6

Профиль | Сайт | Отправить PM | Цитировать


Вопрос в PM пришел:
Цитата DillerInc:
Привет!
Как не трудно догадаться,данная функция возвращает False,и я не уверен,всё ли правильно я делаю.
Итак:

var
eax : Pointer;
OldProtect : DWORD;
begin
VirtualProtectEx(processInfo.hProcess, eax, 2, PAGE_EXECUTE_READWRITE, @OldProtect);
end;

Указатель eax получен от GetProcAddress и имеет значение 7C5901D5 (адрес загрузки функции LoadLibraryA).
В общем,в отладчике можно наблюдать следующие ошибки :
C0000018 - STATUS_CONFLICTING_ADDRESSES
ERROR_INVALID_ADDRESS (GetLastError)
Что делать ?!
Вторым парметром должен идти адрес в памяти, зарезервированной функциями VirtualAlloc(Ex) c параметром MEM_RESERVE, а не указатель, полученный "от GetProcAddress и имеющий значение 7C5901D5 (адрес загрузки функции LoadLibraryA)".
Цитата:
lpAddress
[in] Pointer to the base address of the region of pages whose access protection attributes are to be changed.
All pages in the specified region must be within the same reserved region allocated when calling the VirtualAlloc or VirtualAllocEx function using MEM_RESERVE. The pages cannot span adjacent reserved regions that were allocated by separate calls to VirtualAlloc or VirtualAllocEx using MEM_RESERVE.

Отправлено: 20:15, 21-07-2005

 

Аватара для Savant

Старожил


Сообщения: 300
Благодарности: 6

Профиль | Сайт | Отправить PM | Цитировать


hasherfrog
Темы разбил...

DillerInc
Цитата:
Ну,неужели ни у кого нету никаких соображений по этому поводу,никаких советов ?
Конкретно я могу посоветовать прочитать еще три статьи, добавленные чуть выше. Там на Delphi, но довольно муторно расписано (по крайней мере я первую статью съел только со второго прочтения, вторая статья получше ушла, до третьей еще не дошел).
Цитата:
беру любое смещение из адресного простанства чужого процесса,вставляю его как второй параметр в функцию VirtualProtectEx - всё работает без каких-либо проблем!
Этого не может быть. Могу представить программу, которая это подтвердит.
Цитата:
... применяется функция ReadProcessMemory,что кстати странно, т.к. кто гарантирует,что у нас есть право записи в эту страницу памяти?
права задаются в OpenProcess()

Кстати говоря, а Вы не из под 9x/Me случайно работаете?! Там область применения VirtualProtectEx() ограничена 2 Гб, а область загрузки системных DLL как раз идет дальше (т.н. shared virtual address space).

p.s.: получать адрес из числа (Integer->Pointer) в Delphi лучше функцией ptr(), например ptr($4FFF).

Отправлено: 11:58, 27-07-2005 | #11



Для отключения данного рекламного блока вам необходимо зарегистрироваться или войти с учетной записью социальной сети.

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


Аватара для DillerInc

Обратный инженер


Сообщения: 644
Благодарности: 47

Профиль | Отправить PM | Цитировать


Savant
Цитата:
Кстати говоря, а Вы не из под 9x/Me случайно работаете?!
...нет,Win2k SP4 .
Цитата:
Этого не может быть
...да,походу я действительно погорячился.Я имел в виду смещения в секции кода - та же точка входа позволяет проводить данную экзекуцию,пробовал ещё над несколькими смещениями - без проблем .
Цитата:
права задаются в OpenProcess()
...а если чужой процесс создан следующим образом:
Код: Выделить весь код
var
 sInfo : TStartupInfo;
 pInfo : TProcessInformation;
begin
 sInfo.cb := SizeOf(sInfo.cb); // Обрубок структуры класса TStartupInfo

 CreateProcess(OpenFileName.lpstrfile, NIL, NIL, NIL, False, CREATE_SUSPENDED, NIL, NIL, sInfo, pInfo);
...возможна ли тут какая-то заковырка ?

-------
То,что неясно,следует выяснить.То,что трудно творить,следует делать с великой настойчивостью. © Конфуций


Отправлено: 15:53, 27-07-2005 | #12


Аватара для DillerInc

Обратный инженер


Сообщения: 644
Благодарности: 47

Профиль | Отправить PM | Цитировать


В общем,почитав всякого и наковырявшись с кодом "по полной программе",я к сожалению так конкретно и не понял почему возникает вышеописанная ошибка - ну,да бог с ним...
Во большинстве материалов,которые я читал,преподавалась следующая техника т.н. "сплайсинга" системных функций:
в адресном пространстве чужого процесса создаётся удалённый поток с помощью CreateRemoteThread,в который потом подгружается библиотека,ответственная за перехват системных функций (размещение своих команд в начале таких функций,перенаправление управления на свой код-перехватчик)...
Причём такой вариант трактуется именно как наиболее предпочтительный и эффективный.

Но теперь я здесь по иному вопросу.
Функция GetModuleHandle возвращает дескриптор указанного модуля,который,как я понял,является ни чем иным как базовым адрестом загрузки этого самого модуля.Проблема заключается походу в следующем:
Цитата MSDN:
The GetModuleHandle function retrieves a module handle for the specified module if the file has been mapped into the address space of the calling process.
...если опять-таки правильно понял,функция способна возвратить хэндлы только тех модулей,которые являются загруженными в адресное простанство вызывающего процесса.
А как можно получить такой дескриптор какого-нибудь модуля в чужом процессе ?

-------
То,что неясно,следует выяснить.То,что трудно творить,следует делать с великой настойчивостью. © Конфуций


Отправлено: 23:56, 01-08-2005 | #13


Аватара для DillerInc

Обратный инженер


Сообщения: 644
Благодарности: 47

Профиль | Отправить 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;
...недочёт в том,что функция GetModuleFileNameEx постоянно проваливается,возвращая нуль.
Соответственно,кто-нибудь может сказать в чём могут быть причины ?

Можно,конечно,пытаться использовать поле dEvent.LoadDll.lpImageName структуры _DEBUG_EVENT, которое,как я понял,должно содержать указатель на имя загруженной библиотеки,но там какие-то трудности,о которых как-то размыто пишут на MSDN...и сколько я не пробЫвал использовать эту возможность - ничего путного не выходило.Хотя это был бы наверное самый идеальный вариант получения имени загруженной библиотеки.

-------
То,что неясно,следует выяснить.То,что трудно творить,следует делать с великой настойчивостью. © Конфуций


Последний раз редактировалось DillerInc, 05-08-2005 в 00:08.


Отправлено: 00:19, 04-08-2005 | #14


Аватара для DillerInc

Обратный инженер


Сообщения: 644
Благодарности: 47

Профиль | Отправить 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


Аватара для DillerInc

Обратный инженер


Сообщения: 644
Благодарности: 47

Профиль | Отправить 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;
После того как процесс,только набрав обороты,упрётся в наш опкод на точке входа мы будем в состоянии работать с API-функциями,отображёнными в адресное пространство подопытного процесса.

Под конец стоит заметить,что зацикливание библиотечных функций не будет работать на 9х-ой линейке Windows,т.к. если я не ошибаюсь,библиотеки там отображаются в некую общую область памяти,а не в каждый процесс отдельно.

-------
То,что неясно,следует выяснить.То,что трудно творить,следует делать с великой настойчивостью. © Конфуций


Отправлено: 16:53, 21-04-2006 | #16


Новый участник


Сообщения: 2
Благодарности: 0

Профиль | Отправить 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
Благодарности: 0

Профиль | Отправить 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



Компьютерный форум OSzone.net » Программирование, базы данных и автоматизация действий » Программирование и базы данных » Delphi - Delphi | Работа с памятью чужого процесса, перехват API

Участник сейчас на форуме Участник сейчас на форуме Участник вне форума Участник вне форума Автор темы Автор темы Шапка темы Сообщение прикреплено

Похожие темы
Название темы Автор Информация о форуме Ответов Последнее сообщение
Перехват 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




 
Переход