Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Загрузка и выгрузка dll в чужой процесс


Страницы:   1 2

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 расположена по одному базовому адресу". Я бы сказал конечно да и был бы прав. Так что здесь не вопрос опыта. А вопрос скрытых пока от меня мест в документации, которые не плохо бы иметь на примете :)))


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо