![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Загрузка и выгрузка dll в чужой процесс
bar © (2004-07-08 15:16:00)Загружаю свой дллку в процесс explorer`a с помощью хука на WH_GETMESSAGE. Загрузка проходит нормально. Но потом не могу выгрузить эту библиотеку. Хотя по идеи всё должно быть OK. Дескриптор загруженной в эксплорер библиотеки я первоночально сохранял в FileMapping и потом пытался выгрузить дллку по этому дескриптору из хука эксплорера(адресного пространства). Потом заметил, что при очередной загрузки loadlibrary возвращает одинаковый дескриптор уже загруженной дллки и использовал это для выяснения дескриптора библиотеки в адреснов пространстве explorer`а, но все равно не выгружается. Ж:-(
Помогите кто понял суть проблемы, может предложите другой мметод загрузки и выгрузки библиотеки в чужой процесс или объясните где у меня ошибка.
Пример кода из библиотеки хука.
type
PGlobalDLLData = ^TGlobalDLLData;
TGlobalDLLData = packed record
SysHook: HWND; // дескриптор установленной ловушки
MyAppWnd: HWND; // дескриптор нашего приложения
Flag: Boolean;
HLIB: THANDLE;
end;
var
GlobalData: PGlobalDLLData;
MMFHandle: THandle;
H: THAndle;
GetAndSet: procedure(h: integer); stdcall; // процедура из 2-ой ДЛЛки, которая заменит оконную процедуру часов.
..............
//Процедура хука
function CallWndProc(
nCode: integer; // hook code
wParam: WPARAM; // current-process flag
lParam: LPARAM // address of structure with message data
): LRESULT; stdcall;
var
hl: THAndle;
ok, a: boolean;
begin
if nCode = HC_ACTION then
begin
ok := false;
if tmsg(pointer(lparam)^).hwnd = H then
begin
ok := true;
if GlobalData^.Flag then
{ Если GlobalData^.Flag=true загружаем дллку в процесс окна с хендлом H}
begin
GlobalData^.HLIB := loadlibrary(remdll);
@GetAndSet := nil;
if GlobalData^.HLIB > HINSTANCE_ERROR then
begin
@GetAndSet := GetProcAddress(GlobalData^.HLIB, 'GetAndSet');
if @GetAndSet <> nil then
GetAndSet(H)
end else
end else
begin{ Если GlobalData^.Flag=false загружаем дллку в процесс окна с хендлом H}
PostMessage(H, WM_User + 456, 0, 0);
sleep(1000);
hl := loadlibrary(remdll);
repeat
a := FreeLibrary(Hl);
PostMessage(GlobalData^.MyAppWnd,
WM_MYCMD, $55, HL);
PostMessage(GlobalData^.MyAppWnd,
WM_MYCMD, $56, integer(a));
until a;
end;
end;
result := CallNextHookex(GlobalData^.SysHook, ncode, wparam, lparam);
if ok then
UnHookWindowsHookEx(GlobalData^.SysHook);
end
else
result := CallNextHookex(GlobalData^.SysHook, ncode, wparam, lparam);
//
end;
......
Игорь Шевченко (2004-07-09 11:30:00) [21]
> Все-таки - где доказательство того, что kernel32.dll всегда
> по одному адресу?
Практика - критерий истины
Тимохов (2004-07-09 11:27:00) [22]
>
> Digitman © (09.07.04 11:16) [13]
> неправильно понимаешь
> поточная ф-ция вызывает FreeLibrary
Да?
У рихтера пример имеено с передачей FreeLibrary в качестве поточной функции
// Get the real address of LoadLibraryW in Kernel32.dll
PTHREAD_START_ROUTINE pfnThreadRtn = (PTHREAD_START_ROUTINE)
GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "FreeLibrary");
if (pfnThreadRtn == NULL) __leave;
// Create a remote thread that calls LoadLibraryW(DLLPathname)
hThread = CreateRemoteThread(hProcess, NULL, 0,
pfnThreadRtn, me.modBaseAddr, 0, NULL);
if (hThread == NULL) __leave;
Все-таки - где доказательство того, что kernel32.dll всегда по одному адресу? Понимаю, что вопрос не совсем практичен, т.к. это и так ясно - но все же документальное подтверждение было бы не лишним.
Digitman (2004-07-09 11:23:00) [23]
> bar (09.07.04 11:20) [14]
ну держи, не жалко
на авторство не претендую, текст этот взят когда-то где-то только для анализа варианта решения
//
// внедрение dll в чужой процесс с помощью CreateRemoteThread.
// работать будет только там, где эта самая CreateRemoteThread реализована,
// а это nt/w2k/xp
// использовать так:
// loader.exe идентификатор_процесса полный_путь_и_имя_dll
// paul_shmakov@mail.ru
//
program loader;
{$APPTYPE CONSOLE}
uses
Windows, Messages, SysUtils;
function SetDebugPriv: Boolean;
var
Token: THandle;
tkp: TTokenPrivileges;
begin
Result := false;
if OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, Token) then
begin
if LookupPrivilegeValue(nil, PChar('SeDebugPrivilege'), tkp.Privileges[0].Luid) then
begin
tkp.PrivilegeCount := 1;
tkp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
Result := AdjustTokenPrivileges(Token, false, tkp, 0, PTokenPrivileges(nil)^, PDWord(nil)^);
end;
end;
end;
function Start(ProcessID: Cardinal; DllFileName: string): Boolean;
var
hProcess, hTh: THandle;
BytesWritten, ThreadID, DllNameLen: Cardinal;
LoadLibraryProc, MemPtr: Pointer;
ExitCode: DWord;
begin
Result := false;
//
// этот вызов нужен только для внедрения в системные процессы
// btw, нужны привилегии администратора
//
SetDebugPriv();
hProcess := OpenProcess(PROCESS_CREATE_THREAD or PROCESS_VM_OPERATION or PROCESS_VM_WRITE,
true, ProcessID);
if hProcess <> 0 then
begin
DllNameLen := Length(DllFileName) + 1;
MemPtr := VirtualAllocEx(hProcess, nil, DllNameLen, MEM_COMMIT, PAGE_READWRITE);
if MemPtr <> nil then
begin
if WriteProcessMemory(hProcess, MemPtr, PChar(DllFileName), DllNameLen, BytesWritten) then
begin
LoadLibraryProc := GetProcAddress(GetModuleHandle('kernel32.dll'), 'LoadLibraryA');
hTh := CreateRemoteThread(hProcess, nil, 0, LoadLibraryProc, MemPtr, 0, ThreadID);
if hTh <> 0 then
begin
if (WaitForSingleObject(hTh, INFINITE) = WAIT_OBJECT_0) and
GetExitCodeThread(hTh, ExitCode) then
Result := ExitCode <> 0;
CloseHandle(hTh);
end;
end;
VirtualFreeEx(hProcess, MemPtr, 0, MEM_RELEASE);
end;
CloseHandle(hProcess);
end;
end;
var
ProcessID: Cardinal;
DllName: string;
begin
if ParamCount < 2 then
begin
WriteLn('usage: loader.exe process_id dll_full_path_and_name');
Exit;
end;
ProcessID := StrToInt(ParamStr(1));
WriteLn('process id: ' + IntToStr(ProcessID));
DllName := ParamStr(2);
WriteLn('dllname: ' + DllName);
if ProcessID <> 0 then
begin
if Start(ProcessID, DllName) then
WriteLn('success')
else
WriteLn('fail');
end;
end.
bar (2004-07-09 11:20:00) [24]Я думал Вам просто дать пример. Или ссылку хорошую по теме.
Ну ладно буду искать.
см http://www.delphimaster.ru/cgi-bin/forum.pl?id=1089275745&n=5
А первоисточники на русском не посоветуете. Лучше в инете.
Digitman (2004-07-09 11:16:00) [25]
> Тимохов © (09.07.04 10:50) [11]
> Это не офф, т.к. в струе вопроса.
>
> > Digitman © (09.07.04 10:42) [10]
>
> Я так понимаю, что Вы имеете в виду стартовать удаленный
> поток с поточкной функцией, равной FreeLibrary
неправильно понимаешь
поточная ф-ция вызываетFreeLibrary
> bar (09.07.04 11:12) [12]
> >>Digitman © (09.07.04 10:42) [10]
> А пример можно пожалуйста. А то я с WriteProcessMemory не
> общался.
а почитать для начала справку и первоисточники ?
bar (2004-07-09 11:12:00) [26]>>Digitman © (09.07.04 10:42) [10]
А пример можно пожалуйста. А то я с WriteProcessMemory не общался.
Тимохов (2004-07-09 10:50:00) [27]Это не офф, т.к. в струе вопроса.
> Digitman © (09.07.04 10:42) [10]
Я так понимаю, что Вы имеете в виду стартовать удаленный поток с поточкной функцией, равной FreeLibrary. Но при этом должна быть уверенность в том, что kernel32.dll загружена по тому же базовому адресу. По факту оказывается именно так - kernel32.dll загруже всегда по одному и тому же базовому адресу. Я уже подинмал этот вопрос, но тогда ответа не получил - где факт того, что kernel32.dll загружена по одному адресу описан в msdn?
Digitman (2004-07-09 10:42:00) [28]
> bar (09.07.04 10:14) [6]
> как её потом выгрузить
все просто - вновь стартуй удаленный трэд, который выполнит freelibrary()
Тимохов (2004-07-09 10:41:00) [29]не совсем въехал про что тут говорится (квалификации не хватает), но про запуск потока в другом прочессе через загрузку/выгрузку библиоткb подробно рассказывается в главе 21, 22 или 23 рихтера 4 издание (ключевое слово для поиска CreateRemoteThread).
bar (2004-07-09 10:38:00) [30]>>DeadMeat © (09.07.04 10:23) [7]
Ну да, скоприровал откуда-то и подправил для свох нужд.
Но скопировал не с xakep.ru
Кстати а там про выгрузку длл есть инфа. Пойду посмотрю.
DeadMeat (2004-07-09 10:23:00) [31]
> Нет не процесс невидимка
Ну извини... Просто код взят из этой статьи...
---
...Death Is Only The Begining...
bar (2004-07-09 10:14:00) [32]>>DeadMeat © (08.07.04 23:50) [1]
Нет не процесс невидимка. Просто нужно отловить некоторые сообщения SHELLDLL_DefView, а хук на него не работает(Runtime error 216 at FF640227 при нажатии win+d )( см ветку)
http://www.delphimaster.ru/cgi-bin/forum.pl?id=1089095680&n=5
Кстати кто нибудь знает что такое Runtime error 216 ?
>>Digitman © (09.07.04 08:49) [4]
Знаю. Делал загрузку dll-ки в процесс в момент загрузки библиотеки хука, результат такой же, даже гдето глюков больше (скорее всего код корявый)а с WH_GETMESSAGE это второй более отлаженный вариант. Кроме того разве влияет то кога грузить dll.?
>>Digitman © (09.07.04 08:41) [3]
а как её потом выгрузить
>>Kerk © (09.07.04 08:31) [2]
Попробуй GetModuleHandle / FreeLibrary
В каком процессе? В споем приложении пробовал http://delphiworld.narod.ru/base/kill_dll.htmlне работает. В процессе explorer`a сейчас попробую.
SammIk (2004-07-09 09:50:00) [33]Дескриптор возвращаемыи лоадлиброри, это адрес
куда грузится библеотека.
А винлоадер старается грузить их в одно место,
по этому возвращает один хендл
Digitman (2004-07-09 08:49:00) [34]
> bar (08.07.04 15:16)
а если уж пошел методом глоб.хука, то выкрутасы с обработкой WH_GETMESSAGE и иже с ним вовсе не нужны для этой цели
в момент загрузки хук-модуля в АП процесса эксплорера процедура иниц-ции хук-модуля получает управление, и в этот момент как раз и можно выполнить loadlibrary() ... но перед тем как выполнить loadlibrary() процедура иниц-ции хук-модуля должна проанализировать имя тек.процесса и выполнить loadlibrary() лишь в том случае, если вызов GetModuleFileName вернул именно explorer.exe, иначе библ-ка будет загружена во все GUI-процессы, а не только в эксплорер
Digitman (2004-07-09 08:41:00) [35]
> bar (08.07.04 15:16)
открой процесс эксплорера (см. OpenProcess)
запроси в АП эксплорера блок вирт.памяти c параметром защиты страниц PAGE_EXECUTE_READWRITE под дальнейшее размещение там кода поточной ф-ции (см. VirtualAllocEx)
скопируй в этот блок памяти код поточной ф-ции (см. WriteProcessMemory)
стартуй в АП эксплорера удаленный кодовый поток вызовом CreateRemoteThread(), в качестве параметра, указывающего адрес поточной ф-ции, передай адрес точки входа в скопированную поточную ф-цию в АП эксплорера
при удаленном старте потока поточная ф-ция получает управление и загружает твою библиотеку в АП эксплорера, после чего завершается
Kerk (2004-07-09 08:31:00) [36]Попробуй GetModuleHandle / FreeLibrary
DeadMeat (2004-07-08 23:50:00) [37]Дай угадаю... Ты прочитал статью на xakep.ru, про невидимый процесс?? Просто интересно...
---
...Death Is Only The Begining...