Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Системное программирование и WinAPI > Перехват АПИ функций


Автор: Coocky 6.3.2007, 12:58
Привет. Нужно перехватит функции создания и запись в файл..
Вообщем с теорией знаком, но НЕ ФИГА не работает. Есть куча примеров (и даже Рихтер).
Все с ошибками и все не работают. Может кто-то подсказать либо пример, либо выложить простенький примерик. Очень надо.. Уже второй день парюсь. Что б не писал. Инет кишма кишит примерами на делфи, а на С++ не рабочие либо не внятные отрывки.
Спасибо

Автор: Coocky 6.3.2007, 13:35
Вижу желающих много, хорошо. Давайте подумаем вместе smile)
Итак, создадим длл, которая будет ставить хуки на прцессы. Код ТУПО передрал с Делфятины, потомы возможны ошибки..
Код

DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
    // Remove this if you use lpReserved
    UNREFERENCED_PARAMETER(lpReserved);

    if (dwReason == DLL_PROCESS_ATTACH)
    {
        TRACE0("Iject2.DLL Initializing!\n");
        
        // Extension DLL one-time initialization
        if (!AfxInitExtensionModule(Iject2DLL, hInstance))
            return 0;

        new CDynLinkLibrary(Iject2DLL);

    SetGlobalHook();// Устанавливаем хук
    SetHook();
   
    }
    else if (dwReason == DLL_PROCESS_DETACH)
    {
        TRACE0("Iject2.DLL Terminating!\n");

        // Terminate the library before destructors are called
        AfxTermExtensionModule(Iject2DLL);
    }
    return 1;   // ok
}


int WINAPI NewMessageBoxExA(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType,WORD wLanguageId)
{
  lpText="Byfet";// Тут меняем текст на свой
  return MessageBoxEx(hWnd, lpText, lpCaption, uType, wLanguageId);
}


int WINAPI NewMessageBoxExW(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType,WORD wLanguageId)
{
    DWORD Written ;
    WriteProcessMemory(INVALID_HANDLE_VALUE, MbwAdr, &OldMbw, sizeof(OldCode), &Written);
    pText="Byfet";// Тут меняем текст на свой
    int result= MessageBoxEx(hWnd, lpText, lpCaption, uType, wLanguageId);
    WriteProcessMemory(INVALID_HANDLE_VALUE, MbwAdr,&JmpMbw, sizeof(far_jmp),& Written);

  return result;
}


void  SetHook()
{
  // Это метода джампа, путем подмены адреса нужной функции на адрес своей и обратно
HMODULE hUser32;
DWORD Bytes;
hUser32 = GetModuleHandle("user32.dll");
MbwAdr = GetProcAddress(hUser32, "MessageBoxExW");
MbaAdr = GetProcAddress(hUser32, "MessageBoxExA");
  ReadProcessMemory(INVALID_HANDLE_VALUE, MbwAdr, &OldMbw, sizeof(OldCode), &Bytes);
  ReadProcessMemory(INVALID_HANDLE_VALUE, MbaAdr, &OldMba, sizeof(OldCode), &Bytes);
  JmpMbw.PuhsOp  = 0x68;
  JmpMbw.PushArg = &NewMessageBoxExW;
  JmpMbw.RetOp   = 0xC3;
  JmpMba.PuhsOp  = 0x68;
  JmpMba.PushArg = &NewMessageBoxExA;
  JmpMba.RetOp   = 0xC3;
  WriteProcessMemory(INVALID_HANDLE_VALUE, MbwAdr, &JmpMbw, sizeof(far_jmp), &Bytes);
  WriteProcessMemory(INVALID_HANDLE_VALUE, MbaAdr, &JmpMba, sizeof(far_jmp), &Bytes);
  
}


void Unhook()
{
  DWORD Bytes;
  WriteProcessMemory(INVALID_HANDLE_VALUE, MbaAdr, &OldMba, sizeof(OldCode), &Bytes);
  WriteProcessMemory(INVALID_HANDLE_VALUE, MbwAdr, &OldMbw, sizeof(OldCode), &Bytes);
}


LRESULT CALLBACK GetMsgProc(int code, WPARAM wParam,LPARAM lParam )
{
    CallNextHookEx(0, code, wParam, lParam);// по идее должны попасть сюда

    return 0;
}


DWORD WINAPI SetGlobalHookProc(LPVOID lpParam)
{
  SetWindowsHookEx(WH_GETMESSAGE, &GetMsgProc, NULL, 0); //Заходим сюда и ждем.Кстати отсюда я еще не разу не выходил :)
  Sleep(INFINITE);
  return 0;
}


void SetGlobalHook()
{
  
HANDLE hMutex;
DWORD TrId;

hMutex = CreateMutex(NULL, false, "AdvareHook");

  if (GetLastError() == 0)
  {
    CreateThread(NULL, 0, SetGlobalHookProc, NULL, 0, &TrId);
  }

  else
  {
    CloseHandle(hMutex);
  }

}



Вот в принципе и все.
Осталось заставить заработать DllMain
Для этого в своем экзешнике пишем
Код

 LoadLibrary("Iject2.dll");
  Sleep(INFINITE);

Вот и все, для начала,но у меня не работает. В коментариях к коду в либе я написал то место, где замираю

Автор: Coocky 7.3.2007, 10:34
Хорошо, опять молчим. Ну что ж, я нашел перехват функций с помощью библиотеки detours ,позже выложу библиотеку и исходники, для тех, кто не смог скачать с сайта мелкософтных или кто скачал, но не смог скомпилировать.. Теперь другой вопрос-КАК МНЕ ВНЕДРИТЬ своюю длл в нужный ЧУЖОЙ процесс? Знаю, статей много, но у меня не работает. Ну уж я точно не попадаю на точку останова в DllMain при отладке свое dll.
А может и не долен попадать? Реально ли так отлаживать? 

Автор: W4FhLF 7.3.2007, 15:28
Цитата(Coocky @  6.3.2007,  12:58 Найти цитируемый пост)
Вообщем с теорией знаком, но НЕ ФИГА не работает.


Значит с теорией не знакомsmile Если тебе понятен весь процесс, то причём здесь примеры из сети? Надо было писать самому. 


Цитата(Coocky @  6.3.2007,  13:35 Найти цитируемый пост)
Итак, создадим длл, которая будет ставить хуки на прцессы


Ну не на процессы, а в данном случае на функции MessageBoxA/MessageBoxW. Такая библиотека будет подгружена во все ОКОННЫЕ приложений, а так же будет подгружаться по все вновь созданные ОКОННЫЕ приложения.

Цитата(Coocky @  7.3.2007,  10:34 Найти цитируемый пост)
Теперь другой вопрос-КАК МНЕ ВНЕДРИТЬ своюю длл в нужный ЧУЖОЙ процесс?


Что тебе известно о чужом процессе? В любом случае для непорсдественно внедрения нужно знать PID, найти его по имени процесса труда не составляет(CreateToolhelp32Snapshot & TH32CS_SNAPPROCESS), далее всё стандартно. Создаём базонезависимый участок кода, который будет подгружать нашу dll, записываем этот код в чужой процесс и запускаем на удалённое выполнение. 

По каким-то конкретно моментам есть вопросы?
Есть примеры на Delphi, но я так понял тебя они не устраивают, тогда я могу помочь с примерами на ассемблере, когда-то писал такое для своего снифера, надо?smile


Цитата(Coocky @  7.3.2007,  10:34 Найти цитируемый пост)
А может и не долен попадать? Реально ли так отлаживать? 


Этот процесс я отлаживал следующим образом:
Загружал процесс-жертву в отладчик, стартовал её. После чего ставил прерывание на загрузку нового модуля(DLL), далее в своём процессе я нажимал кнопочку аля "внедрить DLL в чужой процесс(этим процессом естественно был процесс-жертва)" и в отладчике прерывался на события "New module is loaded", т.е. моя dll была загружена в адресное пространство процесса-жертвы, но DllMain ещё не выполнилась, т.о. после этого я просто ставил прерывание на DllMain и запускал процесс дальше на выполнение. После чего мог спокойно отлаживать процедуру установки хука. 
Отладить процедуру перехвата функции ещё проще. Нужно просто поставить прерывание на функцию, которую собираешься перехватить. Как известно на её начало ставится переходник в функцию перехвата, а значит прервавшись на начале функции мы спокойно переходим в функцию перехвата и отлаживаем её.
Но это всё конечно требует определённых навыков и знаний. 

Автор: piritus 8.3.2007, 11:29
одно из решений
код написан КК (Крисом Касперски)
у него для MessageBox, но думаю, что можно переделать под свои нужды:

Код

/*----------------------------------------------------------------------------
 *
 *      универсальнй перехватчик API-функций (см. так же kpnc-hack.c)
 *      ====================================
 *                                           
 *                                             криска ака мыщъх
-----------------------------------------------------------------------------*/
#include <windows.h>

#define JUMP_SZ            0x69         // must be >= sizeof(jump)

#define _INSTALL_THUNK_      jump
#define _UNINSTALL_THUNK_   buff

DWORD saved;                        // сюда записыватся адрес возврата

char my_string[]="hacked";               // строка для вывода в заголвок

char buff[JUMP_SZ], *p; jump(); _do_asm();   // объявляем переменные



// наш thunk
//============================================================================
// получаем управление до вызова перехватываемой API-функции
// здесь можем делать что угодно с параметрами и т.д.
 __declspec( naked ) thunk()
{
__asm{
   push offset _UNINSTALL_THUNK_      ; снимаем thunk с функции
   call _do_asm
   add esp,4

   
   pop [saved]                     ; подменяем ret_addr на post_exit
   push offset post_exit


   ; "боевая нагрузка" до вызоза функции
   ; ========================================================================
   ; подменяем строку заголовка и меняем тип диалогового окна
pre_run:
   mov eax, offset my_string
   ;mov [esp+12], offset my_string                              
   mov [esp+12], eax
   mov [esp+10h], 1                                            


   mov eax,[p]                     ; вызываем перехваченную функцию as is
   jmp eax

   ; "боевая нагрузка" после вызова функции
   ;=========================================================================
   ; ничего не делаем (добавьте сюда собственный код)
post_exit:
   
   push offset _INSTALL_THUNK_         ; снова устанавливаем thunk на функцию
   call _do_asm
   add esp,4
   
   push [saved]                  ; возвращаемся туда,откуда нас вызывали
   retn
   }
}

// код, внедряющийся в начало API-функции и передающий управление на thunk
//============================================================================
__declspec( naked ) jump()
{
   __asm
   {
      ; можно сразу дать jmp thunk, но лениво вычислять смещение
      ; однако, следует учитывать, что в некоторых случаях мы имеем
      ; всего лишь 5 команд для внедрения, jmp туда влезет, а вот
      ; mov eax/jmp eax уже нет
      mov eax, offset thunk         
      jmp eax   
   }
}

// устанавливет/удаляет thunk
//============================================================================
 __declspec( naked )  _do_asm(char *src)
{
__asm
{
      ; сохраняем регистры
      push ecx            
      push esi   
      push edi

      ; резервируем место под локальные переменные
      push esp            ; резервируем место под old-old (hack!!!)
      push eax            ; резервируем место под old

      ; вызываем VirtualProtect(p,0x1000,PAGE_READWRITE, &old);
      ; присваивая себе атриубут записи
      push esp            ; &old
      push PAGE_READWRITE      ; нелзя PAGE_EXECUTE_READWRITE!
      push 0x1000            ; size
      push [p]            ; указатель на регион
      call ds:VirtualProtect

      ; копируем дв. словами
      mov ecx, JUMP_SZ/4      ; size в дв. словах
      mov esi, [esp+18h]      ; src
      mov edi, [p]         ; dst
      rep movsd            ; копируем!
   
      ; вызываем VirtualProtect(p,0x1000,old,&old-old),восстанавливая атриубы
      ; (в принципе, чтобы постоянно не менять атрибуты туда-сюда, достаточно
      ; присвоиить WRITE один раз и так и оставить)
      push esp            ; old (hack!!!)
      push 1000h            ; size
      push [p]            ; указатель на регион
      call ds:VirtualProtect   

      pop eax               ; выталкиваем old
      ;pop eax            ; old-old уже вытолкнут v_prot

      ; восстанавливаем регистры
      pop edi         
      pop esi
      pop ecx

      ; выходим
      retn               
   }
}


// демонстрационный вызов MessageBoxA, подтержающий перехват
demo(){ MessageBox(0, "==[ demo ]==","not hacked yet",0); }

main()
{
   // получаем адрес MessageBoxA
   p = (char*)GetProcAddress(LoadLibrary("USER32.DLL"), "MessageBoxA");

   // копируем оригинальное содержимое MessageBoxA в свое тело
   memcpy(buff, p, JUMP_SZ);

   // MessageBoxA до перехвата
   demo();   

   // устанавливаем перехватчик
    _do_asm(_INSTALL_THUNK_);

   // MessageBoxA после перехвата
   demo();

   // удаляем перехватчик
   _do_asm(_UNINSTALL_THUNK_);

   // MessageBoxA после удаления перехватчика
   demo();

}

Автор: Coocky 12.3.2007, 16:11
Цитата(W4FhLF @  7.3.2007,  15:28 Найти цитируемый пост)
Ну не на процессы, а в данном случае на функции MessageBoxA/MessageBoxW. Такая библиотека будет подгружена во все ОКОННЫЕ приложений, а так же будет подгружаться по все вновь созданные ОКОННЫЕ приложения.

Да нет! ИМЕНО на ПРОЦЕЕСЫ. С помощью хуков мы заставим длл внедрится во все ПРОЦЕССЫ!! smile 

Цитата(W4FhLF @  7.3.2007,  15:28 Найти цитируемый пост)
Этот процесс я отлаживал следующим образом:

Я уже разобрался
Цитата

Что тебе известно о чужом процессе? В любом случае для непорсдественно внедрения нужно знать PID, найти его по имени процесса труда не составляет(CreateToolhelp32Snapshot & TH32CS_SNAPPROCESS), далее всё стандартно. Создаём базонезависимый участок кода, который будет подгружать нашу dll, записываем этот код в чужой процесс и запускаем на удалённое выполнение. 

По каким-то конкретно моментам есть вопросы?

Примере есть в инете, но там нет выравнивания структуры. Я тоже разобрался. Вообщем разобрался САМ... smile 
Вот рабочий код
Код


Вот рабочий код внедрения в процесс .Обратите внимание на #pragma pack(1) и #pragma pack()


BOOL OpenProcessin(DWORD dwProcessId, CString Dll_name)
{
LPTHREAD_START_ROUTINE Memory;
DWORD Code;
DWORD BytesWritten;
DWORD hreadId;
HANDLE hThread;
HMODULE hKernel32;
DWORD ThreadId;

#pragma pack(1)

struct Inject
{
BYTE PushCommand;
DWORD PushArgument;
WORD CallCommand;
DWORD CallAddr;
BYTE PushExitThread;
DWORD ExitThreadArg;
WORD CallExitThread;
DWORD CallExitThreadAddr;
void*AddrLoadLibrary;
void*AddrExitThread;
TCHAR LibraryName[MAX_PATH];
 
};

#pragma pack()

Inject in;
TCHAR ModulePath [MAX_PATH];

BOOL Result = FALSE;
HANDLE hProcess=NULL;
hProcess = OpenProcess(
                       PROCESS_CREATE_THREAD   |
                       PROCESS_VM_OPERATION    |
                       PROCESS_VM_WRITE,
                       FALSE, dwProcessId);
Memory =(LPTHREAD_START_ROUTINE) VirtualAllocEx(hProcess, NULL, sizeof(Inject),
          MEM_COMMIT, PAGE_EXECUTE_READWRITE);

        if (Memory ==NULL) 
        {
return FALSE;
        }

Code = (DWORD)(Memory);
        //инициализация внедряемого кода:
        in.PushCommand    = 0x68;
        in.PushArgument   = Code + 0x1E;
        in.CallCommand    = 0x15FF;
        in.CallAddr       = Code + 0x16;
        in.PushExitThread = 0x68;
        in.ExitThreadArg  = 0;
        in.CallExitThread = 0x15FF;
        in.CallExitThreadAddr = Code + 0x1A;
hKernel32 = GetModuleHandle("kernel32.dll");
        in.AddrLoadLibrary = GetProcAddress(hKernel32, "LoadLibraryA");
        in.AddrExitThread = GetProcAddress(hKernel32, "ExitThread");
        lstrcpy(in.LibraryName, Dll_name.GetBuffer());
        //записать машинный код по зарезервированному адресу
        WriteProcessMemory(hProcess, Memory, &in, sizeof(Inject), &BytesWritten);
        //выполнить машинный код
hThread = CreateRemoteThread(hProcess, NULL, 0, Memory, NULL, 0, &ThreadId);
        if (hThread ==NULL)
        {
          return FALSE;
        }
        CloseHandle(hThread);
Result = TRUE;
        
 return Result;
}


Эту функцию нужно вызвать первой, для получения доступа


BOOL SetDebugePrivilegie(void)
{
 
HANDLE hToken;
LUID SeDebugNameValue;
TOKEN_PRIVILEGES tkp;
DWORD ReturnLength;
BOOL Result=FALSE;
  //Добавляем привилегию SeDebugPrivilege
  //Получаем токен нашего процесса
  OpenProcessToken(INVALID_HANDLE_VALUE, TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &hToken);
  //Получаем LUID привилегии
  if (!LookupPrivilegeValue(NULL, "SeDebugPrivilege", &SeDebugNameValue))
  {
    CloseHandle(hToken);
  return FALSE;
  }
  tkp.PrivilegeCount= 1;
  tkp.Privileges[0].Luid = SeDebugNameValue;
  tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  //Добавляем привилегию к процессу
  AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(TOKEN_PRIVILEGES),
    &tkp, &ReturnLength);
  if (GetLastError() != ERROR_SUCCESS) 
  {
    return FALSE;
  }
Result=TRUE;
  return Result;
}


Автор: dumb 13.3.2007, 19:04
произошла небольшая путаница со смысловой нагрузкой слова "хук"... smile

Цитата(Coocky @  12.3.2007,  16:11 Найти цитируемый пост)
С помощью хуков мы заставим длл внедрится во все ПРОЦЕССЫ!!

нет. чтобы убедиться, в DLL_PROCESS_ATTACH сделай вывод куда-либо(OutputDebugString/MessageBox/log-file) pid'ов(GetCurrentProcessId), например.

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