Форум: "WinAPI";
Текущий архив: 2004.08.22;
Скачать: [xml.tar.bz2];
ВнизЗагрузка и выгрузка dll в чужой процесс Найти похожие ветки
← →
bar (2004-07-08 15:16) [0]Загружаю свой дллку в процесс 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;
......
← →
DeadMeat © (2004-07-08 23:50) [1]Дай угадаю... Ты прочитал статью на xakep.ru, про невидимый процесс?? Просто интересно...
---
...Death Is Only The Begining...
← →
Kerk © (2004-07-09 08:31) [2]Попробуй GetModuleHandle / FreeLibrary
← →
Digitman © (2004-07-09 08:41) [3]
> bar (08.07.04 15:16)
открой процесс эксплорера (см. OpenProcess)
запроси в АП эксплорера блок вирт.памяти c параметром защиты страниц PAGE_EXECUTE_READWRITE под дальнейшее размещение там кода поточной ф-ции (см. VirtualAllocEx)
скопируй в этот блок памяти код поточной ф-ции (см. WriteProcessMemory)
стартуй в АП эксплорера удаленный кодовый поток вызовом CreateRemoteThread(), в качестве параметра, указывающего адрес поточной ф-ции, передай адрес точки входа в скопированную поточную ф-цию в АП эксплорера
при удаленном старте потока поточная ф-ция получает управление и загружает твою библиотеку в АП эксплорера, после чего завершается
← →
Digitman © (2004-07-09 08:49) [4]
> bar (08.07.04 15:16)
а если уж пошел методом глоб.хука, то выкрутасы с обработкой WH_GETMESSAGE и иже с ним вовсе не нужны для этой цели
в момент загрузки хук-модуля в АП процесса эксплорера процедура иниц-ции хук-модуля получает управление, и в этот момент как раз и можно выполнить loadlibrary() ... но перед тем как выполнить loadlibrary() процедура иниц-ции хук-модуля должна проанализировать имя тек.процесса и выполнить loadlibrary() лишь в том случае, если вызов GetModuleFileName вернул именно explorer.exe, иначе библ-ка будет загружена во все GUI-процессы, а не только в эксплорер
← →
SammIk © (2004-07-09 09:50) [5]Дескриптор возвращаемыи лоадлиброри, это адрес
куда грузится библеотека.
А винлоадер старается грузить их в одно место,
по этому возвращает один хендл
← →
bar (2004-07-09 10:14) [6]>>DeadMeat © (08.07.04 23:50) [1]
Нет не процесс невидимка. Просто нужно отловить некоторые сообщения SHELLDLL_DefView, а хук на него не работает(Runtime error 216 at FF640227 при нажатии win+d )( см ветку)
http://delphimaster.net/view/4-1089095680/
Кстати кто нибудь знает что такое 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 сейчас попробую.
← →
DeadMeat © (2004-07-09 10:23) [7]
> Нет не процесс невидимка
Ну извини... Просто код взят из этой статьи...
---
...Death Is Only The Begining...
← →
bar (2004-07-09 10:38) [8]>>DeadMeat © (09.07.04 10:23) [7]
Ну да, скоприровал откуда-то и подправил для свох нужд.
Но скопировал не с xakep.ru
Кстати а там про выгрузку длл есть инфа. Пойду посмотрю.
← →
Тимохов © (2004-07-09 10:41) [9]не совсем въехал про что тут говорится (квалификации не хватает), но про запуск потока в другом прочессе через загрузку/выгрузку библиоткb подробно рассказывается в главе 21, 22 или 23 рихтера 4 издание (ключевое слово для поиска CreateRemoteThread).
← →
Digitman © (2004-07-09 10:42) [10]
> bar (09.07.04 10:14) [6]
> как её потом выгрузить
все просто - вновь стартуй удаленный трэд, который выполнит freelibrary()
← →
Тимохов © (2004-07-09 10:50) [11]Это не офф, т.к. в струе вопроса.
> Digitman © (09.07.04 10:42) [10]
Я так понимаю, что Вы имеете в виду стартовать удаленный поток с поточкной функцией, равной FreeLibrary. Но при этом должна быть уверенность в том, что kernel32.dll загружена по тому же базовому адресу. По факту оказывается именно так - kernel32.dll загруже всегда по одному и тому же базовому адресу. Я уже подинмал этот вопрос, но тогда ответа не получил - где факт того, что kernel32.dll загружена по одному адресу описан в msdn?
← →
bar (2004-07-09 11:12) [12]>>Digitman © (09.07.04 10:42) [10]
А пример можно пожалуйста. А то я с WriteProcessMemory не общался.
← →
Digitman © (2004-07-09 11:16) [13]
> Тимохов © (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:20) [14]Я думал Вам просто дать пример. Или ссылку хорошую по теме.
Ну ладно буду искать.
см http://delphimaster.net/view/4-1089095680/
А первоисточники на русском не посоветуете. Лучше в инете.
← →
Digitman © (2004-07-09 11:23) [15]
> 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.
← →
Тимохов © (2004-07-09 11:27) [16]
>
> 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 всегда по одному адресу? Понимаю, что вопрос не совсем практичен, т.к. это и так ясно - но все же документальное подтверждение было бы не лишним.
← →
Игорь Шевченко © (2004-07-09 11:30) [17]
> Все-таки - где доказательство того, что kernel32.dll всегда
> по одному адресу?
Практика - критерий истины
← →
Тимохов © (2004-07-09 11:34) [18]
> Игорь Шевченко © (09.07.04 11:30) [17]
> Практика - критерий истины
Если бы меня спросли на интервью при приеме на работу "Всегда ли kernel32.dll расположена по одному базовому адресу". Я бы сказал конечно да и был бы прав. Так что здесь не вопрос опыта. А вопрос скрытых пока от меня мест в документации, которые не плохо бы иметь на примете :)))
← →
Digitman © (2004-07-09 11:36) [19]
> Тимохов © (09.07.04 11:27) [16]
> Да?
> У рихтера пример имеено с передачей FreeLibrary в качестве
> поточной функции
вот ты заладил - Рихтер да Рихтер) ...да я понятия не имею кто такой Рихтер !) ... ну не читал я его ни разу, хоть и на слуху он без конца здесь, иными источниками пользовался и пользуюсь ..
> Все-таки - где доказательство того, что kernel32.dll всегда
> по одному адресу?
ну нашута это надо - трюки эти ? ничем они не оправданы, кроме сомнительной экономии пару-тройки сотен байт АП целевого процесса ..
← →
Тимохов © (2004-07-09 11:41) [20]
> Digitman © (09.07.04 11:36) [19]
Я вас не понимаю.
Особенно это
> ну нашута это надо - трюки эти
Какие трюки?
Вы сами привели пример, где адрес LoadLibraryA находите в одном процессе, а запускаете поток в другом. Ясно, что вы предполагаете, что адрес загрузки kernel32.dll одинаков. Вот и вопрос - почему вы так полагаете. Игорь говорит, что "практика критерий истинины". Все же кроме практики должна быть дока! :)
А вот это вообще к чему?
> кроме сомнительной экономии пару-тройки сотен байт АП целевого
> процесса ..
ЗЫ. А рихтер, что рихтер. Виноват я что-ли, что книжка хорошая.
← →
bar (2004-07-09 11:43) [21]>>Digitman © (09.07.04 11:23) [15]
Спасибо большое. Буду пробовать.
А кто такой Рихтер??
← →
Игорь Шевченко © (2004-07-09 11:44) [22]bar (09.07.04 11:43)
> А кто такой Рихтер??
Пианист
← →
Тимохов © (2004-07-09 11:46) [23]
> bar (09.07.04 11:43) [21]
Это дядька такой, который написал хорошую книгу по windows.
http://www.books.ru/shop/books/8283
← →
Digitman © (2004-07-09 12:10) [24]
> Тимохов © (09.07.04 11:41) [20]
это как раз пример того самого трюка, который при любом раскладе с "практикой" я бы не рекомендовал применять
и приведен он НЕ для подражания, а в качестве примера использования вызова WriteProcessMemory() (см. [12]) и сопутствующих вызовов .. не более того
← →
Тимохов © (2004-07-09 12:14) [25]
> Digitman © (09.07.04 12:10) [24]
делаю выводы (подвожу итог):
1. Вы считаете, что закладываться на одинаковость базового адреса Kernel32.dll во всех процессах из области трюков, которые исползовать не нужно.
2. У вас есть свое ноухау как можно сделать CreateRemoteThread без того, чтобы полагаться на удиный базовый адрес Kernel32.dll, а например в удаленном процессе явно строите поточную фунцию, с использованием WriteProcessMemory.
← →
Digitman © (2004-07-09 12:28) [26]
> Тимохов © (09.07.04 12:14) [25]
1. Все верно. На то что недокументировано полагаться нельзя при любом раскладе.
2. Никаких ноу-хау. Все это старо как мир - с пом. WriteProcessMemory() из АП тек.процесса в АП целевого процесса копируется готовый к "употреблению" машкод, который при получении управления вызовает документированную ф-цию LoadLibrary или FreeLibrary
← →
Тимохов © (2004-07-09 12:34) [27]
> Digitman © (09.07.04 12:28) [26]
Как бальзам на душу :)))))
Я честно говоря так не делал - т.к. не особо силен в создании машкода да еще готового к употреблению, но если бы знал как писать машкод, то делал бы именно так.
Я еще когда рихтера читал - как-то мне это не понравилось: полагаться на однозначность базового адреса kernel32.dll.
Спасибо, теперь, если придется это делать, буду знать, что нужно копировать маш код...
← →
Тимохов © (2004-07-09 12:37) [28]Скажу честно, то, что написано в 26 я и хотел услышать и в процессе прошлого обсуждения и сейчас.
:))
← →
Digitman © (2004-07-09 12:41) [29]
> Тимохов © (09.07.04 12:34) [27]
> не особо силен в создании машкода да еще готового к употреблению,
> но если бы знал как писать машкод, то делал бы именно так.
занаешь ли, я думаю что редкий мазохист возьмется строить машкод (да еще и позиционно-независимый) в ран-тайм, когда под руками есть мощный/гибкий/изящный Делфи-компилятор, делающий то же самое без каких-либо затрат мозговых усилий))))
← →
Тимохов © (2004-07-09 12:45) [30]
> (да еще и позиционно-независимый)
вот об этом подробнее пожалуйста :)))
Как это можно в дельфи сделать?
Если посмотреть в момент выполнени, то видно много явных ссылок, например на константы строк. И как в дельфи сделать позиционно-независимый код?
← →
bar (2004-07-09 13:08) [31]>>Digitman ©
А для выгрузки дллки как нужно делать? так как ниже или иначе?
function Unload(ProcessID: Cardinal; DllId: Cardinal): 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 := SizeOf(DllId);
MemPtr := VirtualAllocEx(hProcess, nil, DllNameLen, MEM_COMMIT, PAGE_READWRITE);
// FreeLibrary
// FreeLibrary()
if MemPtr <> nil then
begin
if WriteProcessMemory(hProcess, MemPtr, Pointer(DllId), DllNameLen, BytesWritten) then
begin
LoadLibraryProc := GetProcAddress(GetModuleHandle("kernel32.dll"), "FreeLibrary");
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;
← →
bar (2004-07-09 13:16) [32]>> All
Спасибо, мастера Delphi, знатоки Рихтера и прочие гении.
С CreateRemoteThread разберусь позже а пока сделал чтобы работала загрузка/выгрузка с пом. хука.
Вот процедура хука кому интересно. Можете покритиковать.
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: boolean;
begin
if nCode = HC_ACTION then
begin
ok := false;
if tmsg(pointer(lparam)^).hwnd = H then
begin
ok := true;
if GlobalData^.Flag then
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) ;
Invalidaterect(H, nil, false);
end else
end else
begin
{ я заменяю оконную процедуру в SHELLDLL_DefView и по этому сообщению(WM_User + 456) возвращаю на место старую WndProc }
SendMessage(H, WM_User + 456, 0, 0);
sleep(1000);{Дабы точно WndProc заменилась на старую. Пожет это параноя :-)}
hl := loadlibrary(remdll);
repeat
until not FreeLibrary(Hl);;
end;
end;
result := CallNextHookex(GlobalData^.SysHook, ncode, wparam, lparam);
if ok then
begin
UnHookWindowsHookEx(GlobalData^.SysHook);
end
end
else
result := CallNextHookex(GlobalData^.SysHook, ncode, wparam, lparam);
//
end;
Пока.
← →
Digitman © (2004-07-09 15:16) [33]
> Тимохов © (09.07.04 12:45) [30]
чуть позже
← →
Тимохов © (2004-07-12 12:06) [34]
> Digitman © (09.07.04 15:16) [33]
> чуть позже
Эххх :((
видать, я состарюсь раньше :))))
← →
Бином Ньютоныч (2004-07-12 18:33) [35]Тимохов © (12.07.04 12:06) [34]
Пишешь дважды одну функцию под разными именами, компилишь. Сравнивая код, строишь таблицу коррекции адресов. Так еще под 580ВМ80 делали перемещаемый код.
О kernel32. Все системные библиотеки скомпонованы с неперекрывающимися базовыми адресами. Так что вероятность их загрузки по иному адресу практически равна нулю. Реальный адрес загрузки своей библиотеки можно посмотреть в окне Modules и соответственно скорректировать компоновку. Там же можно посмотреть адрес загрузки kernel32 и сравнить с показаниями TDUMP.exe. Кстати, в Visual Studio есть утилита Rebase.exe, которая позволяет произвести оптимизацию базовых адресов.
PS: Все это описано у Рихтера.
← →
Тимохов © (2004-07-12 18:46) [36]
> PS: Все это описано у Рихтера.
читал, знаю.
спасибо.
все же именно на мой вопрос ответа нет (т.е. где явно описан факт одинаковости базового адреса загрузки kernel32.dll)
← →
Бином Ньютоныч (2004-07-12 20:35) [37]>Тимохов © (12.07.04 18:46) [36]
Может и есть компоновщики, которые не размещают системные библиотеки первыми в секции импорта, но я о таком не слышал.
Страницы: 1 вся ветка
Форум: "WinAPI";
Текущий архив: 2004.08.22;
Скачать: [xml.tar.bz2];
Память: 0.58 MB
Время: 0.052 c