Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2007.01.07;
Скачать: CL | DM;

Вниз

Перехват API методом исправления таблиц импорта.   Найти похожие ветки 

 
zXm ©   (2006-08-19 09:55) [0]

Здарствуйте. Столкнулся с необходимостью перехватывать вызовы некоторых функций в моей програме. Зделал перехват с помощью сплайсинга функцию(замена первых 5 байт на переход по адресу функции обработчика), но проблема в том что такой способ перехвата не работает если функция меньше 5 байт. К сожелению, одна из перехватываемых функций слишком малленькая. нашёл функцию на с осуществляющую замену адресов в таблице импорта. Просьба переделать на делфи(я пытался но безуспешно) или найти её готовую на делфи. Думаю это будет интересно не только мне.
ЗЫ Про int 3 просьба не рассказывать - знаю, но не подходит.

void CAPIHook::ReplaceIATEntryInOneMod(PCSTR pszCalleeModName,
 PROC pfnCurrent, PROC pfnNew, HMODULE hmodCaller)
{
 //Получим адрес секции импорта
 ULONG ulSize;
 PIMAGE_IMPORT_DESCRIPTOR pImportDesc =
   (PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData(hmodCaller, TRUE,
   IMAGE_DIRECTORY_ENTRY_IMPORT, &ulSize);
 if (pImportDesc == NULL)
   return;  //Здесь её нет
 //Найдём нужный модуль
 for (; pImportDesc->Name; pImportDesc++)
 {
   PSTR pszModName = (PSTR)((PBYTE) hmodCaller + pImportDesc->Name);
   if (lstrcmpiA(pszModName, pszCalleeModName) == 0)
   {
     //Нашли
     if (pImportDesc->Name == 0)
       return;  //Ни одна функция не импортируется
     //Получим адрес таблицы импорта
     PIMAGE_THUNK_DATA pThunk =
       (PIMAGE_THUNK_DATA)((PBYTE) hmodCaller + pImportDesc->FirstThunk);
     //Переберём все импортируемые функции
     for (; pThunk->u1.Function; pThunk++)
     {
       PROC* ppfn = (PROC*) &pThunk->u1.Function; //Получим адрес функции
       BOOL fFound = (*ppfn == pfnCurrent);     //Его ищем?
       if (!fFound && (*ppfn > sm_pvMaxAppAddr))
       {
         // Если не нашли, то поищем поглубже.
         // Если мы в Win98 под отладчиком, то
         // здесь может быть push с адресом нашей функции
         PBYTE pbInFunc = (PBYTE) *ppfn;
         if (pbInFunc[0] == cPushOpCode)
         {
           //Да, здесь PUSH
           ppfn = (PROC*) &pbInFunc[1];
           //Наш адрес?
           fFound = (*ppfn == pfnCurrent);
         }
       }

       if (fFound)
       {
         //Нашли!!!
         DWORD dwDummy;
         //Разрешим запись в эту страницу
         VirtualProtect(ppfn, sizeof(ppfn), PAGE_EXECUTE_READWRITE, &dwDummy);
         //Сменим адрес на свой
         WriteProcessMemory(GetCurrentProcess(), ppfn, &pfnNew,
           sizeof(pfnNew), NULL);
         //Восстановим атрибуты
         VirtualProtect(ppfn, sizeof(ppfn), dwDummy , &dwDummy);
         //Готово!!!
         return;
       }
     }
   }
 }
 //Здесь этой функции не нашлось
}


 
zXm ©   (2006-08-19 20:12) [1]

Нашёл функцию на делфи:

uses Windows,TlHelp32;

type
_IMAGE_IMPORT_DESCRIPTOR = packed record
case Integer of 0: (
Characteristics: DWORD);
1: (
OriginalFirstThunk: DWORD;
TimeDateStamp: DWORD;
ForwarderChain: DWORD;
Name: DWORD;
FirstThunk: DWORD);
end;
IMAGE_IMPORT_DESCRIPTOR = _IMAGE_IMPORT_DESCRIPTOR;
PIMAGE_IMPORT_DESCRIPTOR = ^IMAGE_IMPORT_DESCRIPTOR;
PFARPROC = ^FARPROC;

function ImageDirectoryEntryToData(Base: Pointer; MappedAsImage: ByteBool;DirectoryEntry: Word; var Size: ULONG): Pointer; stdcall; external "ImageHlp.dll";

function ReplaceIATEntryInOneMod(pszCallerModName:Pchar; pfnCurrent:FarProc; pfnNew:FARPROC; hmodCaller:hModule):Boolean;
var
ulSize:ULONG;
pImportDesc:PIMAGE_IMPORT_DESCRIPTOR;
pszModName:PChar;
pThunk:PDWORD;
ppfn:PFARPROC;
ffound:LongBool;
written:DWORD;
begin
result:=false;
pImportDesc := ImageDirectoryEntryToData(Pointer(hmodCaller),TRUE,IMAGE_DIRECTORY_ENTRY_IMPORT,  ulSize);
if pImportDesc = nil then exit;
while pImportDesc.Name <> 0 do
 begin
  pszModName := PChar(hmodCaller + pImportDesc.Name);
  if (lstrcmpiA(pszModName, pszCallerModName) = 0) then break;
  Inc(pImportDesc);
 end;
if (pImportDesc.Name = 0) then exit;
pThunk := PDWORD(hmodCaller + pImportDesc.FirstThunk);
while pThunk^ <> 0 do
 begin
  ppfn:= PFARPROC(pThunk);
  fFound:=(ppfn^ = pfnCurrent);
  if (fFound) then
   begin
    VirtualProtectEx(GetCurrentProcess, ppfn, 4, PAGE_EXECUTE_READWRITE,Written);
    WriteProcessMemory(GetCurrentProcess, ppfn, @pfnNew, sizeof(pfnNew),Written);
    VirtualProtectEx(GetCurrentProcess, ppfn, 4, PAGE_EXECUTE_READWRITE,Written);
    exit;
   end;
  Inc(pThunk);
 end;
result:=true;
end;

Проверил, хука работает с приложениями из виндоус, но на моём тестовом примере в делфе нет. В той же статье прочитал следующую фразу:
"Тест, написанный на Visual C++, работал прекрасно – функция GetDriveTypeA перехватывалась. А вот программа на Delphi всё равно для всех перехватываемых мной дисков возвращала реальные значения. Я посмотрел таблицу импорта тестовой программы при помощи утилиты DUMPBIN и обнаружил, что компилятор Delphi не поместил все импортируемые функции из kernel32.dll в один список, а разбил их на 3 части, причём GetDriveTypeA оказалась в третьей. Поэтому функция ReplaceIATEntryInOneMod Джеффри Рихтера, просмотрев все функции из первого списка Kernel32.dll, не нашла функции GetDriveTypeA, хотя она и импортировалась модулем DriveTypeTest.exe. Я исправил эту функцию таким образом, чтобы она проверяла всю таблицу импорта и перебирала все списки с функциями из kernel32.dll (как оказалось, их может быть несколько). В описании формата РЕ-файла нигде не оговаривается, что каждый модуль, из которого импортируются функции, должен встречаться в секции импорта только один раз, и, видимо, некоторые компиляторы этим пользуются."

Однако приведёная там функция соответсвует функции приведённой Джеффри Рихтером. Вобщем вопрос что нужно подправить. Чтобы перехват работал везде.


 
zXm ©   (2006-08-19 22:27) [2]

Всё всем спс. Ответ найден.


 
Сергей М. ©   (2006-08-21 08:55) [3]

Для полноценного перехвата недостаточно модификации одной лишь IAT - следует модифицировать еще и EAT.

EAT используется при вызове GetProcAddress(), т.е. при динамическом импорте. Если не модифицировать эту таблицу, то ф-ция всегда будет возвращать адрес оригинальной точки входа.


 
GrayFace ©   (2006-08-25 22:28) [4]

Поэтому Рихтер советует перехватывать и ее. Могу привести код DigitMan"а, меняющий не IAT и EAT, но мне кажется, что игра не стоит свечь - для EAT и код большой, и недокументированные особенности использует, и блок экспортов библиотеки в своп идет.


 
GrayFace ©   (2006-08-25 22:29) [5]

GrayFace ©   (25.08.06 22:28) [4]
не IAT и EAT

"не" лишнее.



Страницы: 1 вся ветка

Текущий архив: 2007.01.07;
Скачать: CL | DM;

Наверх




Память: 0.49 MB
Время: 0.042 c
2-1166366846
Bolt
2006-12-17 17:47
2007.01.07
Резервирование


15-1166140640
MikePetrichenko
2006-12-15 02:57
2007.01.07
Срочно требуются


15-1166206982
Knight
2006-12-15 21:23
2007.01.07
Ini-файл...


15-1166203691
Loginov Dmitry
2006-12-15 20:28
2007.01.07
Чушь получается. Почему? Кто скажет?


15-1166435666
AntiUser
2006-12-18 12:54
2007.01.07
Владелец онлайнового магазина подает в суд на блоггера за...