Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Общие вопросы > Перехват API


Автор: <Spawn> 2.6.2003, 21:31
Пробую делать перехват вызовов WinSock API, а именно функции recv. Но что то, используемый мною класс ее ни как не меняет. Внедряюсь в чужое АП при помощи хуков - внедрение проходит успешно, поскольку проверяю наличие библиотеки winsock в процессе через GetModuleHandle.

Вот утсановка хука( часть DLL):
Код
...
const
wsocket='wsock32.dll';
WM_SETSOCKETHOOK=WM_USER+100;
SpecificId=65535;

type
THook_Recv=function(s: TSocket; var Buf; len, flags: Integer): Integer; stdcall;

var
OldRecv:THook_Recv=nil;
PeImportHooks:=TJclPeMapImgHooks;
Hooked:Boolean=False;

function Hook_Recv(s: TSocket; var Buf; len, flags: Integer): Integer; stdcall;
var
CopyData:TCOPYDATASTRUCT;
begin
//пересылка данных в компонент обработки
Result:=OldRecv(s,Buf,len,flags);
end;

function SetSocketHook:Boolean;
begin
Result:=False;
PeImportHooks:=nil;
PeImportHooks:=TJclPeMapImgHooks.Create;
if PeImportHooks.HookImport(Pointer(HInstance), wsocket, 'recv',
   @Hook_Recv, @OldRecv) then
begin
 Result:=True;
 ShowMessage('Set Hook');
end
else
begin
 ShowMessage('Error Set Hook);
 PeImportHooks.Free;
end;
end;

function MsgProc(Code: integer; WParam: word; LParam: Longint): Longint; stdcall;
var
msg: PMSG;
begin
if Code >= 0 then
begin
Result := 0;
Msg := Pointer(LParam);
if (Msg.message=WM_SETSOCKETHOOK) and (Msg.wParam=SpecificId) then
begin
 if SetSocketHook then
  Hooked:=True;
end;
end
else
Result := CallNextHookEx(HookHandle, code, WParam, LParam);
end;

procedure SetHook;export;stdcall;
begin
HookHandle:=SetWindowsHookEx(WH_GETMESSAGE, @MsgProc, HInstance, 0);
end;
...


Я заглянул в класс подмены функции таблицы импорта, но там все ок - ошибок не было. Причины была в том, что класс, видимо, не нашел этой функции в таблице импорта, поскольку в цикле просморта я подставлял ShowMessage но нахождения не было:
Код
ImportDesc := PImageImportDescriptor(DWORD(Base) + ImportDir.VirtualAddress);
 while ImportDesc^.Name <> 0 do
 begin
   CurrName := PChar(Base) + ImportDesc^.Name;
   if StrIComp(CurrName, PChar(ModuleName)) = 0 then
   begin
     ImportEntry := PImageThunkData(DWORD(Base) + ImportDesc^.FirstThunk);
     while ImportEntry^.Function_ <> 0 do
     begin
       if IsThunked then
       begin
         ImportThunk := PWin9xDebugThunk(ImportEntry^.Function_);
         FoundProc := IsWin9xDebugThunk(ImportThunk) and (ImportThunk^.Addr = FromProcDebugThunk^.Addr);
       end
       else
         FoundProc := Pointer(ImportEntry^.Function_) = FromProc;
       if FoundProc and not IsBadStringPtr(Pointer(ImportEntry^.Function_), 4) then
       begin
         Pointer(ImportEntry^.Function_) := ToProc; ShowMessage('Proc Finded');
         Result := True;
       end;
       Inc(ImportEntry);
     end;
   end;
   Inc(ImportDesc);
 end;

. Продезассемблировав нужную мне прогу при помощи IDA Pro, я увидел там вот это:
Код
.idata:004E435C                 extrn __imp_recv:dword; DATA XREF: recvr
.idata:004E435C                                        ; Receive data from a socket

Почему в заголовке файла она хранится как __imp_recv?
Подскажите пожалста в чем может быть ошибка подмены импорта.

Автор: man2002ua 3.6.2003, 09:46
сделай вывод ImportEntry^.Function_ при поиске адреса.
здесь:
FoundProc := Pointer(ImportEntry^.Function_) = FromProc;
"вывод"(ImportEntry^.Function_ );

и убедись, что в списке импорта есть адрес recv...

Автор: <Spawn> 3.6.2003, 10:24
Цитата(man2002ua @ 3.6.2003, 01:46)
и убедись, что в списке импорта есть адрес recv...

Как я уже говорил, я проверял наличие самой библиотеки через GetModuleHandle - все было ок. И еще я проверял наличие самой функции при помощи GetProcAddress. Результат тот же - ее адресс был найден.

Автор: man2002ua 3.6.2003, 11:46
Ок, выведи значение ImportEntry для меня

Автор: <Spawn> 3.6.2003, 17:15
Не найдено таких значений!!!!

Автор: man2002ua 3.6.2003, 17:18
То есть:
CurrName := PChar(Base) + ImportDesc^.Name;
if StrIComp(CurrName, PChar(ModuleName)) = 0 then
begin
// не попадает ?

Автор: <Spawn> 3.6.2003, 17:24
Да результат функции StrIComp всегда не равен 0. Значения ImportDesc^.Name меняется с 354104 по 360268 за 13 итераций и при этом ни разу не выполняется код после if StrIComp(CurrName, PChar(ModuleName)) = 0 then.

Автор: <Spawn> 3.6.2003, 17:37
Я посмотрел значения всех CurrName := PChar(Base) + ImportDesc^.Name - там небыло wsock32.dll !!!!!!!!!!!!!!!!!!!!!!!!!!

Автор: <Spawn> 3.6.2003, 20:17
Как же такое может быть, что GetProcAddress(GetModuleHandle('wsock32.dll'),'recv') возвращает адресс функции, а в таблице импорта она не находится? И не находитcя там сама библиотека wsock32.dll.

Вот список импортируемых ДЛЛ (Почему идет повторение?):

kernel32.dll
user32.dll
advapi32.dll
oleaut32.dll
kernel32.dll
advapi32.dll
kernel32.dll
version.dll
gdi32.dll
user32.dll
kernel32.dll
oleaut32.dll
comctrl32.dll

Я пробовал подменить SelectObject - все было ок.

Автор: stab 4.6.2003, 08:12
может я не совсем что-то понимаю, но получается что на момент установки хука сокеты еще не загружены и динамически подгружаются позже... но может я что-то не понимаю smile.gif

Автор: man2002ua 4.6.2003, 09:08
нет, просто wsock32.dll грузит не сам exe, а одна из библиотек до него.
Дай полный список импортируемых dll. Или скажи - там есть wsock32.dll? Смотри PEViewer.exe например.

Автор: <Spawn> 4.6.2003, 10:32
А где эту прогу взять можно?

Я при помощи того класса вытащил вот эти библиотеки:
kernel32.dll
user32.dll
advapi32.dll
oleaut32.dll
kernel32.dll
advapi32.dll
kernel32.dll
version.dll
gdi32.dll
user32.dll
kernel32.dll
oleaut32.dll
comctrl32.dll

Автор: man2002ua 4.6.2003, 10:37
Отправил тебе прогу - смотри почту. Посмотришь, если ли в списке импорта wsock32.dll. Если нет - давай Exе мне.

Автор: <Spawn> 4.6.2003, 10:59
ок

Автор: <Spawn> 4.6.2003, 13:14
У меня пока небольшие проблемки смоим основным мылом sad.gif Не мог бы ты, пожалста, послать прогу на Crafter@list.ru

Автор: man2002ua 4.6.2003, 13:17
Done

Автор: <Spawn> 4.6.2003, 13:30
В списке импорта WinSock есть, но что странно - напротив адресов нету имен импортируемых функций.
П.С. Класная прога.

Автор: man2002ua 4.6.2003, 14:22
ага, значит не все так плохо, как кажется на первый взгляд ;). То что нет имен - ерунда, т.к. твой компонент ищет их не по имени (разумно smile.gif), а по адресу.
Теперь насчет того, что компонент не находит - это не понятно...
Кинь мне если можешь.

Автор: <Spawn> 4.6.2003, 14:33
Я тебе тогда в привате его давал))

Автор: man2002ua 4.6.2003, 14:37
вижу, токо я уже себе сам такое сделал, не компонентом конечно, но зато все понятно. Поэтому и говорю - давай свой exe, я попробую его пропустить через свой перехватчик. Если не поймает буду ковырять.

Автор: <Spawn> 5.6.2003, 05:23
Он весит 60 Мб где то)

Автор: man2002ua 5.6.2003, 09:15
Мать-перемать... Ладно, говоришь IDA - показывает его, как extern, значит таки включается. Попробуй все найденные имена импортируемых библиотек записать в массив. Потом, для каждого имени - вызывай свой перехватчик, т.е. чтобы компонент искал Recv не в Exe, а этих dll, может какая-то из них импортирует ее.

Автор: <Spawn> 5.6.2003, 15:55
Пробовал для всех найденых ДЛЛ - функция recv не найдена((((

Автор: man2002ua 5.6.2003, 16:00
Щас докалупаю перечисление открытых процессом дескрипторов и вышлю тебе dll с перехватом recv.

Автор: <Spawn> 5.6.2003, 16:02
ОО)) Заранее спасибо.

Автор: <Spawn> 6.6.2003, 16:01
Я пробую запустить так(Для примера возьму Form1, чтоб было понятнее как описать имя класса):

InjSpool.exe c:\Download\Temp\InjLib.dll Form1 - при таком запуске ругается, что Process instance not found.

Может я что то делаю неправильно?

Автор: man2002ua 6.6.2003, 16:07
Form1 - это имя процесса? Наверно Process1 - более правильно. или вызови диспетчер задач и посмотри как называется процесс, т.к. программа внедряет любую dll в любой процесс...

Автор: <Spawn> 6.6.2003, 16:46
Если процесс имеет имя состоящееиз нескольких строк, то вылетает ошибка (

Автор: man2002ua 6.6.2003, 17:16
Блин, ехе-переименуй!
Я не делал для всех случаев проверку- облом, мне это для работы не надо smile.gif
и еще момент - запускать лучше из Far или подобного командера.

Автор: <Spawn> 6.6.2003, 17:31
656: >> WSOCK32.dll [004E4324]
656: <start> 004E4324
656: ---> 71A91890
656: ---> 71A91B7B
656: ---> 71A932CA
656: ---> 71A91AF4
656: ---> 71A91740
656: ---> 71A93ECE
656: ---> 71A91ED3
656: ---> 71AB2E5F
656: ---> 71A912A7
656: ---> 71A91746
656: ---> 71A93C22
656: ---> 71AB1072
656: ---> 71A93E5D
656: ---> 71A9155A
656: ---> 71AB1020
656: ---> 71A91746
656: ---> 71A91A6D
656: ---> 71A941DA
656: ---> 71A92BBF
656: ---> 71A912A7
656: ---> 71A91836

Автор: man2002ua 7.6.2003, 09:01
а сообщения Address Found - patching %08X не было?
Вышли мне wsock32.dll - или сам ida раскрути и скажи, функция recv - Какой адрес имеет?

Автор: <Spawn> 8.6.2003, 13:03
Cори что не мог раньше ответить. У меня дома инет вырубился до понедельника( Завтра вышлю тебе winsock.

Автор: <Spawn> 9.6.2003, 19:40
Это из wsock32.dll

.text:74FE10B2 public recv
.text:74FE10B2 recv proc near
.text:74FE10B2
.text:74FE10B2 Buffers = _WSABUF ptr -8
.text:74FE10B2 s = dword ptr 8
.text:74FE10B2 Flags = dword ptr 0Ch
.text:74FE10B2 NumberOfBytesRecvd= dword ptr 10h
.text:74FE10B2 flags = dword ptr 14h

Автор: man2002ua 10.6.2003, 09:01
бред какой-то. Импортируются функции по адресам 71Axxxxxx, а в wsock32 они с 74ххххххххх.
Скопируй мне из ida файла программы
1) обращение к recv _jmp ds:recv - адреса и код
2) значение по адресу, куда переходит jmp __extern recv - запомни адрес XXX
3) открой программу с помощью Hiew и перейди на XXX (нажми F5 и введи .ХХХ (точка впереди), ентер)
4) скопируй мне 4 байта оттеда.

Автор: <Spawn> 10.6.2003, 11:27
Обращение к recv из проги

.text:004B6222 call recv
.text:004B6227 cmp eax, 0FFFFFFFFh
.text:004B622A jnz short loc_4B6249
.text:004B622C call WSAGetLastError
.text:004B6231 cmp eax, 2733h
.text:004B6236 mov [esi+41Ch], eax
.text:004B623C jz short loc_4B6247
.text:004B623E push eax
.text:004B623F call sub_4B63C0
.text:004B6244 add esp, 4
.text:004B6247
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Я тут маленько порылся и вот, что заметил:

.text:004D063E ; [00000006 BYTES: COLLAPSED FUNCTION recv. PRESS KEYPAD "+" TO EXPAND]

Раскрытое значение
.text:004D063E
.text:004D063E ; --------------- S U B R O U T I N E ---------------------------------------
.text:004D063E
.text:004D063E
.text:004D063E ; int __stdcall recv(SOCKET s,char *buf,int len,int flags)
.text:004D063E
.text:004D063E recv proc near ; CODE XREF: sub_4B6210+12p
.text:004D063E ; sub_4B6FC0+12Dp ...
.text:004D063E jmp ds:__imp_recv ; Receive data from a socket
.text:004D063E recv endp
.text:004D063E

Я что то не совсем понимаю назначение данного кода. То есть при вызове recv вызывается __imp_recv? Для чего?
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Recv в таблице импорта.

.idata:004E435C ; int __stdcall __imp_recv(SOCKET s,char *buf,int len,int flags)
.idata:004E435C extrn __imp_recv:dword ; DATA XREF: recvr
.idata:004E435C ; Receive data from a socket
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
А что за прога Hiew? Где ее можно взять.

Автор: man2002ua 10.6.2003, 14:15
надеюсь тебе в craft@.. пролезет 320 Кб smile.gif
выслал Hiew

Автор: <Spawn> 11.6.2003, 13:55
Байты по адресу 004E435C(вместе с тем на которых оказался курсор) - 10 00 00 80. Если это не поможет, то могу выслать сам exe(я ошибся, сказав что он весит 60Мб. Он весит около 1Мб, а вот с сопутствующими файлами он весит порядочно).

Автор: man2002ua 11.6.2003, 14:00
Высылай!

Автор: <Spawn> 11.6.2003, 14:06
Done smile.gif

Автор: man2002ua 11.6.2003, 15:29
У меня все нормально обнаруживается той утилиткой, что я тебе высылал InjSpool... Адрес патчится на новый! Ты наверно не тот exe выслал?
1) Запускаем Client.exe
2) Запускаем InjSpool.exe C:\download\InjLib.DLL client
3) - в отладчике Address found - 4E435C smile.gif

Или что-то ты не то делаешь или у меня ОС такая раздолбаная, что позволяет делать с ней что угодно biggrin.gif

Автор: <Spawn> 11.6.2003, 17:17
У меня выводит лишь все используемые модули с функциями. Address found нет. Запускаю клиент, потом
InjSpool.exe C:\download\Delphi\Temp\InjLib.DLL client.exe. У меня Винь ХП. Что делать?

Автор: man2002ua 11.6.2003, 17:21
без понятия... Ставить W2K наверное smile.gif Мне не на чем проверить - ХР нету...

Автор: <Spawn> 11.6.2003, 17:24
Попробую на Вин2К сервер.

Автор: <Spawn> 11.6.2003, 17:30
На одном форуме мне ответили, что возможно функции импортируются по ординалу и для этого необходимо модифицировать таблицу импорта. И там дали две функции для получения и модификации таблицы. Щас буду с этим разбираться.

Автор: man2002ua 11.6.2003, 17:33
так не "возможно", а так оно и есть. Но при запуске - они преобразуются в нормальные адреса...

Автор: <Spawn> 11.6.2003, 17:42
Ну тогда не знаю) Остается один выход - детально изучить заголовок файла и пытаться, пытаться, пытаться...

Автор: <Spawn> 11.6.2003, 17:49
Вот, кстати, как это реализуется на Си, в одной похожей рабочей проге -

Код
void SocketHookSet::install()
{
   DWORD oldProtect;

   DWORD image_base = (DWORD)GetModuleHandle(NULL);
   IMAGE_DOS_HEADER *idh = (IMAGE_DOS_HEADER *)image_base;
   IMAGE_FILE_HEADER *ifh = (IMAGE_FILE_HEADER *)(image_base +
       idh->e_lfanew + sizeof(DWORD));
   IMAGE_OPTIONAL_HEADER *ioh = (IMAGE_OPTIONAL_HEADER *)((DWORD)(ifh) +
       sizeof(IMAGE_FILE_HEADER));
   IMAGE_IMPORT_DESCRIPTOR *iid = (IMAGE_IMPORT_DESCRIPTOR *)(image_base +
       ioh->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);

   VirtualProtect((LPVOID)(image_base +
       ioh->DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress),
       ioh->DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size, PAGE_READWRITE,
       &oldProtect);

   while(iid->Name)
   {
       for(ImportDescriptorHook * dhook = desc_hooks; dhook->name != 0; dhook++)
           if(stricmp(dhook->name, (char *)(image_base + iid->Name)) == 0)
           {
               //trace_printf("Found descriptor: %s\n", dhook->name);
               IMAGE_THUNK_DATA * pThunk = (IMAGE_THUNK_DATA *)
                   ((DWORD)iid->OriginalFirstThunk + image_base);
               IMAGE_THUNK_DATA * pThunk2 = (IMAGE_THUNK_DATA *)
                   ((DWORD)iid->FirstThunk + image_base);
               while(pThunk->u1.AddressOfData)
               {
                   char * name = 0;
                   int ordinal;
                   // Imported by ordinal only:
                   if(pThunk->u1.Ordinal & 0x80000000)
                       ordinal = pThunk->u1.Ordinal & 0xffff;
                   else    // Imported by name, with ordinal hint
                   {
                       IMAGE_IMPORT_BY_NAME * pname = (IMAGE_IMPORT_BY_NAME *)
                           ((DWORD)pThunk->u1.AddressOfData + image_base);
                       ordinal = pname->Hint;
                       name = (char *)pname->Name;
                   }
                   for(ImportEntryHook * ehook = dhook->entries; ehook->name != 0; ehook++)
                   {
                       if(name != 0 && strcmp(name, ehook->name) == 0)
                       {
                           //trace_printf("Found entry name: %s\n", ehook->name);
                           pThunk2->u1.Function = (PDWORD)ehook->hook_func;
                       }
                       else if(ordinal == ehook->ordinal)
                       {
                           //trace_printf("Found entry ordinal: %s\n", ehook->name);
                           pThunk2->u1.Function = (PDWORD)ehook->hook_func;
                       }
                   }
                   pThunk++;
                   pThunk2++;
               }
           }
       iid++;
   }
}

Автор: <Spawn> 8.7.2003, 21:45
Все дело было в том, что при подключении к чужому процессу я указывал в роли hInstance стандартную переменную, а нужно было сделать GetModuleHandle(nil) ))))

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)