![]() |
| ||
|
|
Новости |
Поиск |
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-12 20:35:00) [1]>Тимохов © (12.07.04 18:46) [36]
Может и есть компоновщики, которые не размещают системные библиотеки первыми в секции импорта, но я о таком не слышал.
Тимохов (2004-07-12 18:46:00) [2]
> PS: Все это описано у Рихтера.
читал, знаю.
спасибо.
все же именно на мой вопрос ответа нет (т.е. где явно описан факт одинаковости базового адреса загрузки kernel32.dll)
Бином Ньютоныч (2004-07-12 18:33:00) [3]Тимохов © (12.07.04 12:06) [34]
Пишешь дважды одну функцию под разными именами, компилишь. Сравнивая код, строишь таблицу коррекции адресов. Так еще под 580ВМ80 делали перемещаемый код.
О kernel32. Все системные библиотеки скомпонованы с неперекрывающимися базовыми адресами. Так что вероятность их загрузки по иному адресу практически равна нулю. Реальный адрес загрузки своей библиотеки можно посмотреть в окне Modules и соответственно скорректировать компоновку. Там же можно посмотреть адрес загрузки kernel32 и сравнить с показаниями TDUMP.exe. Кстати, в Visual Studio есть утилита Rebase.exe, которая позволяет произвести оптимизацию базовых адресов.
PS: Все это описано у Рихтера.
Тимохов (2004-07-12 12:06:00) [4]
> Digitman © (09.07.04 15:16) [33]
> чуть позже
Эххх :((
видать, я состарюсь раньше :))))
Digitman (2004-07-09 15:16:00) [5]
> Тимохов © (09.07.04 12:45) [30]
чуть позже
bar (2004-07-09 13:16:00) [6]>> 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;
Пока.
bar (2004-07-09 13:08:00) [7]>>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;
Тимохов (2004-07-09 12:45:00) [8]
> (да еще и позиционно-независимый)
вот об этом подробнее пожалуйста :)))
Как это можно в дельфи сделать?
Если посмотреть в момент выполнени, то видно много явных ссылок, например на константы строк. И как в дельфи сделать позиционно-независимый код?
Digitman (2004-07-09 12:41:00) [9]
> Тимохов © (09.07.04 12:34) [27]
> не особо силен в создании машкода да еще готового к употреблению,
> но если бы знал как писать машкод, то делал бы именно так.
занаешь ли, я думаю что редкий мазохист возьмется строить машкод (да еще и позиционно-независимый) в ран-тайм, когда под руками есть мощный/гибкий/изящный Делфи-компилятор, делающий то же самое без каких-либо затрат мозговых усилий))))
Тимохов (2004-07-09 12:37:00) [10]Скажу честно, то, что написано в 26 я и хотел услышать и в процессе прошлого обсуждения и сейчас.
:))
Тимохов (2004-07-09 12:34:00) [11]
> Digitman © (09.07.04 12:28) [26]
Как бальзам на душу :)))))
Я честно говоря так не делал - т.к. не особо силен в создании машкода да еще готового к употреблению, но если бы знал как писать машкод, то делал бы именно так.
Я еще когда рихтера читал - как-то мне это не понравилось: полагаться на однозначность базового адреса kernel32.dll.
Спасибо, теперь, если придется это делать, буду знать, что нужно копировать маш код...
Digitman (2004-07-09 12:28:00) [12]
> Тимохов © (09.07.04 12:14) [25]
1. Все верно. На то что недокументировано полагаться нельзя при любом раскладе.
2. Никаких ноу-хау. Все это старо как мир - с пом. WriteProcessMemory() из АП тек.процесса в АП целевого процесса копируется готовый к "употреблению" машкод, который при получении управления вызовает документированнуюф-цию LoadLibrary или FreeLibrary
Тимохов (2004-07-09 12:14:00) [13]
> Digitman © (09.07.04 12:10) [24]
делаю выводы (подвожу итог):
1. Вы считаете, что закладываться на одинаковость базового адреса Kernel32.dll во всех процессах из области трюков, которые исползовать не нужно.
2. У вас есть свое ноухау как можно сделать CreateRemoteThread без того, чтобы полагаться на удиный базовый адрес Kernel32.dll, а например в удаленном процессе явно строите поточную фунцию, с использованием WriteProcessMemory.
Digitman (2004-07-09 12:10:00) [14]
> Тимохов © (09.07.04 11:41) [20]
это как раз пример того самого трюка, который при любом раскладе с "практикой" я бы не рекомендовал применять
и приведен он НЕ для подражания, а в качестве примера использования вызова WriteProcessMemory() (см. [12]) и сопутствующих вызовов .. не более того
Тимохов (2004-07-09 11:46:00) [15]
> bar (09.07.04 11:43) [21]
Это дядька такой, который написал хорошую книгу по windows.
http://www.books.ru/shop/books/8283
Игорь Шевченко (2004-07-09 11:44:00) [16]bar (09.07.04 11:43)
> А кто такой Рихтер??
Пианист
bar (2004-07-09 11:43:00) [17]>>Digitman © (09.07.04 11:23) [15]
Спасибо большое. Буду пробовать.
А кто такой Рихтер??
Тимохов (2004-07-09 11:41:00) [18]
> Digitman © (09.07.04 11:36) [19]
Я вас не понимаю.
Особенно это
> ну нашута это надо - трюки эти
Какие трюки?
Вы сами привели пример, где адрес LoadLibraryA находите в одном процессе, а запускаете поток в другом. Ясно, что вы предполагаете, что адрес загрузки kernel32.dll одинаков. Вот и вопрос - почему вы так полагаете. Игорь говорит, что "практика критерий истинины". Все же кроме практики должна быть дока! :)
А вот это вообще к чему?
> кроме сомнительной экономии пару-тройки сотен байт АП целевого
> процесса ..
ЗЫ. А рихтер, что рихтер. Виноват я что-ли, что книжка хорошая.
Digitman (2004-07-09 11:36:00) [19]
> Тимохов © (09.07.04 11:27) [16]
> Да?
> У рихтера пример имеено с передачей FreeLibrary в качестве
> поточной функции
вот ты заладил - Рихтер да Рихтер) ...да я понятия не имею кто такой Рихтер !) ... ну не читал я его ни разу, хоть и на слуху он без конца здесь, иными источниками пользовался и пользуюсь ..
> Все-таки - где доказательство того, что kernel32.dll всегда
> по одному адресу?
ну нашута это надо - трюки эти ? ничем они не оправданы, кроме сомнительной экономии пару-тройки сотен байт АП целевого процесса ..
Тимохов (2004-07-09 11:34:00) [20]
> Игорь Шевченко © (09.07.04 11:30) [17]
> Практика - критерий истины
Если бы меня спросли на интервью при приеме на работу "Всегда ли kernel32.dll расположена по одному базовому адресу". Я бы сказал конечно да и был бы прав. Так что здесь не вопрос опыта. А вопрос скрытых пока от меня мест в документации, которые не плохо бы иметь на примете :)))