Ir al contenido


Foto

[MULTILENGUAJE] HOOK a la API en delphi y en C (trampolín)


  • Por favor identifícate para responder
28 respuestas en este tema

#21 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 19 junio 2014 - 10:53

Voy a completar el tutorial con el código en C que está expuesto en delphi:

APIHook.h


cpp
  1. //---------------------------------------------------------------------------
  2. #ifndef APIHookH
  3. #define APIHookH
  4. //---------------------------------------------------------------------------
  5. //#include "APIdef.h"
  6.  
  7. #include <Windows.h>
  8. #ifdef __cplusplus
  9. extern "C" {
  10. #endif
  11.  
  12. void  InstallHook(void* HookAPI, void** ToAPI, char* dllName, char* ApiName, BOOL Resume);
  13. void  InstallHookFromAddr(void* HookAPI, void** ToAPI,  void* API, BOOL Resume);
  14. void  SuspendHook(void* ToAPI, char* dllName, char* ApiName);
  15. void  SuspendHookFromAddr(void* ToAPI, void* API);
  16. void  ResumeHook(void* HookFunc, char* dllName, char* ApiName);
  17. void  ResumeHookFromAddr(void* HookFunc, void* API);
  18. void  UnInstallHook(void** pToAPI, char* dllName, char* ApiName);
  19. void  UnInstallHookFromAddr(void** pToAPI, void* API);
  20. DWORD Transfer(BYTE* Source, BYTE* Dest);
  21.  
  22. #ifdef __cplusplus
  23. }
  24. #endif
  25.  
  26. /---------------------------------------------------------------------------
  27. #endif



APIHook.c


cpp
  1. #pragma hdrstop
  2.  
  3. #include "APIHook.h"
  4. //---------------------------------------------------------------------------
  5. #pragma hdrstop
  6.  
  7. #include "APIHook.h"
  8. //---------------------------------------------------------------------------
  9. #pragma package(smart_init)
  10.  
  11. #pragma link "ldasm.obj"
  12.  
  13. #ifdef __cplusplus
  14. extern "C" {
  15. #endif
  16.   unsigned long SizeOfCode(unsigned char *code);
  17.   unsigned long x_code_flags(unsigned char *code);
  18. #ifdef __cplusplus
  19. }
  20. #endif
  21.  
  22. #define  OP_REL32  0x40
  23. #define  OP_REL8  0x80
  24.  
  25. int GetOverloadBytes(BYTE* pB);
  26. int ASMmemcpy(BYTE* Dest, BYTE* Source, DWORD NBytes);
  27.  
  28.  
  29. ////////////////////////////////////////////////////////////////////////////////
  30. // Instalación general de API_Hooks
  31. // HookAPI: API Hookeada
  32. // ToAPI:  Salta a la API original
  33. // ddlName: Nombre de la DLL donde se encuentra la API
  34. // ApiName: Nombre de la API que vamos a Hookear
  35. ////////////////////////////////////////////////////////////////////////////////
  36. void InstallHook(void* HookAPI, void** pToAPI, char* dllName, char* ApiName, BOOL Resume)
  37. {
  38.   HMODULE hLib = GetModuleHandle(dllName);
  39.   if(!hLib) hLib = LoadLibrary(dllName);
  40.   if(hLib){
  41.     BYTE* API = (BYTE*)GetProcAddress(hLib, ApiName);
  42.     InstallHookFromAddr(HookAPI, pToAPI, API, Resume);
  43.   }
  44. }
  45.  
  46. void InstallHookFromAddr(void* HookAPI, void** pToAPI,  void* API, BOOL Resume)
  47. {
  48.   int NBytes;
  49.   PBYTE HookFunc, ToAPI;
  50.   DWORD OldProtect;
  51.  
  52.   NBytes  = GetOverloadBytes((BYTE*)API); // Bytes a sobreescribir de la API
  53.   *pToAPI        = VirtualAlloc(0, NBytes+5, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
  54.   HookFunc = (BYTE*)HookAPI;
  55.   ToAPI    = (BYTE*)*pToAPI;
  56.  
  57.   // Preparar la función ToAPI
  58.   // Autorizo escribir en ToAPI
  59.  
  60.   VirtualProtectEx((void*)-1, ToAPI, NBytes+5, PAGE_EXECUTE_READWRITE, &OldProtect);
  61.   ASMmemcpy((BYTE*)ToAPI, (BYTE*)API, NBytes); // Copio los primeros bytes de la api
  62.   ToAPI[NBytes] = 0xE9 ; //jmp
  63.   *(DWORD*)(ToAPI + NBytes+1) = ((BYTE*)API + NBytes) - (ToAPI + NBytes+5);
  64.   VirtualProtectEx((void*)-1, ToAPI, NBytes+5, OldProtect, 0);
  65.  
  66.   // Preparar la API a Hookear
  67.   if(Resume) ResumeHookFromAddr(HookFunc, API);
  68.  
  69.   FlushInstructionCache(GetCurrentProcess(), NULL, 0);
  70. }
  71.  
  72. void UnInstallHook(void** pToAPI, char* dllName, char* ApiName)
  73. {
  74.   HMODULE hLib = GetModuleHandle(dllName);
  75.   if(!hLib) hLib = LoadLibrary(dllName);
  76.   if(hLib){
  77.     void* API = GetProcAddress(hLib, ApiName);
  78.     if(API) UnInstallHookFromAddr(pToAPI, API);
  79.   } 
  80. }
  81.  
  82. void UnInstallHookFromAddr(void** pToAPI, void* API)
  83. {
  84.   if(*pToAPI==0 || API==0) return;
  85.   SuspendHookFromAddr(*pToAPI, API);
  86.   VirtualFree(*pToAPI, 0, MEM_RELEASE);
  87.   *pToAPI = 0;
  88. }
  89.  
  90. ////////////////////////////////////////////////////////////////////////////////
  91. // Calcula los Bytes que se pueden modificar en la API Original
  92. ////////////////////////////////////////////////////////////////////////////////
  93. int GetOverloadBytes(BYTE* pB)
  94. {
  95.   int Result = 0;
  96.   for(; Result < 5;)
  97.     Result += SizeOfCode(pB+Result);
  98.  
  99.   return Result;
  100. }
  101.  
  102.  
  103. // Transfiere una instrucción asm completa desde fuente a destino
  104. // Si es un salto relativo lo recalcula.
  105. // Devuelve el nº de Bytes transferidos en destino.
  106. DWORD Transfer(BYTE* Source, BYTE* Dest)
  107. {
  108.   int  Offset;
  109.   DWORD Size = SizeOfCode(Source);
  110.   DWORD Flag = x_code_flags(Source);
  111.   CopyMemory(Dest, Source, Size);
  112.  
  113.   // Si es un salto relativo
  114.   if(Flag & (OP_REL8 | OP_REL32)){
  115.     // Salto relativo lejano:
  116.     if(Flag & OP_REL32){
  117.       Offset = *(int*)&Source[Size-4];
  118.       *(int*)&Dest[Size-4] = Offset - (Dest - Source);
  119.     }
  120.     // Salto relativo cercano
  121.     else if(Flag & OP_REL8){
  122.       Offset = *(signed char*)&Source[1];
  123.       Dest[0] = 0xE9;
  124.       *(int*)&Dest[1] = Offset - (Dest - Source);
  125.       Size = 5;
  126.     }
  127.   }
  128.   return Size;
  129. }
  130.  
  131. ////////////////////////////////////////////////////////////////////////////////
  132. // Escribe los Bytes a modificar ajustando saltos condicionales
  133. ////////////////////////////////////////////////////////////////////////////////
  134. int ASMmemcpy(BYTE* Dest, BYTE* Source, DWORD NBytes)
  135. {
  136.   DWORD Result = 0;
  137.   for(; Result < NBytes;){
  138.     Transfer(Source + Result, Dest + Result);
  139.     Result += SizeOfCode(Source + Result);
  140.   }
  141.   return Result;
  142. }
  143.  
  144. ////////////////////////////////////////////////////////////////////////////////
  145. // Suspende momentaneamente el Hook sin desinatalar ToHook
  146. ////////////////////////////////////////////////////////////////////////////////
  147. void SuspendHookFromAddr(void* ToAPI, void* API)
  148. {
  149.   int n;
  150.   DWORD OldProtect;
  151.  
  152.   if(ToAPI==0 || API ==0) return;
  153.   // Autorizo escribir en la API Hookeada
  154.   VirtualProtectEx((void*)-1, API, 5, PAGE_EXECUTE_READWRITE, &OldProtect);
  155.   for(n=0; n<5; n++) ((BYTE*)API)[n] = ((BYTE*)ToAPI)[n];
  156.   //memcpy(API, ToAPI, 5);
  157.   VirtualProtectEx((void*)-1, API, 5, OldProtect, 0);
  158. }
  159.  
  160. void SuspendHook(void* ToAPI, char* dllName, char* ApiName)
  161. {
  162.   void* API = 0;
  163.   HMODULE hLib = 0;
  164.  
  165.   if(ToAPI==0 || dllName==0 || ApiName==0) return;
  166.  
  167.   hLib = GetModuleHandle(dllName);
  168.   if(!hLib) hLib = LoadLibrary(dllName);
  169.   if(!hLib) return;
  170.  
  171.   API = GetProcAddress(hLib, ApiName);
  172.   if(API)
  173.     SuspendHookFromAddr(ToAPI, API);
  174. }
  175.  
  176. ////////////////////////////////////////////////////////////////////////////////
  177. // Resume o reinicia el Hook
  178. ////////////////////////////////////////////////////////////////////////////////
  179. void ResumeHookFromAddr(void* HookFunc, void* API)
  180. {
  181.   DWORD OldProtect;
  182.   BYTE* Api;
  183.  
  184.   if(HookFunc==0 || API==0) return;
  185.  
  186.   // Autorizo escribir en la API a Hookear
  187.   VirtualProtectEx((void*)-1, API, 5, PAGE_EXECUTE_READWRITE, &OldProtect);
  188.   Api = (BYTE*)API;
  189.   *Api = 0xE9 ; //jmp
  190.   *(DWORD*)(Api+1) = (BYTE*)HookFunc - (Api+5);
  191.   VirtualProtectEx((void*)-1, API, 5, OldProtect, 0);
  192. }
  193.  
  194. void ResumeHook(void* HookFunc, char* dllName, char* ApiName)
  195. {
  196.   void* API;
  197.  
  198.   if(HookFunc==0) return;
  199.   API = GetProcAddress(GetModuleHandle(dllName), ApiName);
  200.   if(API)
  201.     ResumeHookFromAddr(HookFunc, API);
  202. }



Dado que las explicaciones a dicho código están expuestas más arriba, no creo que merezca la  pena repetir.


Saludos.
  • 0

#22 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 19 junio 2014 - 11:49

Para seguir ilustrando el tema, os dejo una dll que realiza un Hook a la API MessageBox en el que el mensaje será cambiado por "HOOKED" seguido del mensaje original y expondrá el icono MB_ICONWARNING



cpp
  1. #include <windows.h>
  2. #include "APIHook.h"
  3.  
  4. #pragma argsused
  5.  
  6. typedef int (__stdcall *PMESSAGEBOX)(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType);
  7. PMESSAGEBOX OMessageBox = 0;
  8.  
  9. //----------------------------------------------------------------------------
  10. int WINAPI NewMessageBox(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType)
  11. {
  12.   char Buffer[256];
  13.   lstrcat(lstrcpy(Buffer, "HOOKED\n"), lpText);
  14.   return OMessageBox(hWnd, Buffer, "HOOK", MB_ICONWARNING);
  15. }
  16.  
  17. //----------------------------------------------------------------------------
  18. // Aquí instalaremos todos los Hooks a las API que deseemos
  19. void InstallHook()
  20. {
  21.   InstallHook(NewMessageBox, (void**)&OMessageBox, "User32.dll", "MessageBoxA", true);
  22. }
  23.  
  24. //----------------------------------------------------------------------------
  25. // Aquí desinstalaremos todos los Hooks
  26. void UnInstallHook()
  27. {
  28.   UnInstallHook((void**)&OMessageBox, "User32.dll", "MessageBoxA");
  29. }
  30.  
  31. //----------------------------------------------------------------------------
  32. // El punto de entrada a nuestra dll
  33. BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fwdreason, LPVOID lpvReserved)
  34. {
  35.   switch (fwdreason) {
  36.     case DLL_PROCESS_ATTACH:
  37.       InstallHook();
  38.       break;
  39.     case DLL_PROCESS_DETACH:
  40.       UnInstallHook();
  41.       break;
  42.   }
  43.   return 1;
  44. }
  45. //---------------------------------------------------------------------------


Al cargar o inyectar la dll instala los Hooks en el proceso y los desninstala al descargarla
La inyección sólo se puede hacer efectiva en procesos 32bits, ya que el sistema de Hooks está diseñado para ellos.


Saludos
  • 0

#23 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 19 junio 2014 - 12:22

Y como no podía dejar a delphi huerfano, vamos a escribir la dll en ese lenguaje:



delphi
  1. library Hookdll;
  2.  
  3. uses
  4.   SysUtils,
  5.   Windows, APIHook;
  6.  
  7. type PMESSAGEBOX = function(hWnd: THandle; lpText, lpCaption: PCHAR; uType: integer): Integer; stdcall;
  8.  
  9. var
  10.   OMessageBox: PMESSAGEBOX = nil;
  11.  
  12.  
  13. //----------------------------------------------------------------------------
  14. // La API MessageBox Hookeada
  15. function NewMessageBox(hWnd: THandle; lpText, lpCaption: PCHAR; uType: integer): Integer; stdcall;
  16. begin
  17.   Result:= OMessageBox(hWnd, 'MessageBox HOOKED    ', lpCaption, uType or MB_ICONEXCLAMATION);
  18. end;
  19.  
  20. //----------------------------------------------------------------------------
  21. // Aquí instalaremos todos los Hooks a las API que deseemos
  22. procedure InstallHooks;
  23. begin
  24.   InstallHook(@NewMessageBox, @OMessageBox, 'User32.dll', 'MessageBoxA', true)
  25. end;
  26.  
  27. //----------------------------------------------------------------------------
  28. // Aquí desinstalaremos todos los Hooks
  29. procedure UnInstallHooks;
  30. begin
  31.   UnInstallHook(@OMessageBox, 'User32.dll', 'MessageBoxA');
  32. end;
  33.  
  34. procedure DllMain(reason: integer) ;
  35. begin
  36.   case reason of
  37.     DLL_PROCESS_ATTACH:
  38.       InstallHooks;
  39.     DLL_PROCESS_DETACH:
  40.       UnInstallHooks;
  41.   end;
  42. end; (*DllMain*)
  43.  
  44. begin
  45. DllProc := @DllMain;
  46. DllProc(DLL_PROCESS_ATTACH) ;
  47. end.




Saludos.
  • 0

#24 aguml

aguml

    Newbie

  • Miembros
  • Pip
  • 7 mensajes

Escrito 19 junio 2014 - 12:35

en mi caso me hará falta ya que la funcion NtSetInformationThread es asi:


delphi
  1. 7C91DCAE > B8 E5000000      MOV EAX,0E5
  2. 7C91DCB3  BA 0003FE7F      MOV EDX,7FFE0300
  3. 7C91DCB8  FF12            CALL DWORD PTR DS:[EDX]
  4. 7C91DCBA  C2 1000          RETN 10



Y la funcion NtQueryInformationProcess es así:


delphi
  1. 7C91D7FE > B8 9A000000      MOV EAX,9A
  2. 7C91D803  BA 0003FE7F      MOV EDX,7FFE0300
  3. 7C91D808  FF12            CALL DWORD PTR DS:[EDX]
  4. 7C91D80A  C2 1400          RETN 14



El parcheo no me sirve ya que esas apis son llamadas con mucha asiduidad por el sistema y si parcheo a fuego no funcionan como deben ya que dependen de los parametros para que hagan una cosa u otra. Toca hacer un hook con filtro pero antes de nada tengo que ver porque la dll no corre si la inyecto en otro proceso, es lo mas urgente y luego ya se van viendo otras cosas.
  • 0

#25 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 19 junio 2014 - 12:43

en mi caso me hará falta ya que la funcion NtSetInformationThread es asi:


delphi
  1. 7C91DCAE > B8 E5000000      MOV EAX,0E5
  2. 7C91DCB3  BA 0003FE7F      MOV EDX,7FFE0300
  3. 7C91DCB8  FF12            CALL DWORD PTR DS:[EDX]
  4. 7C91DCBA  C2 1000          RETN 10



Y la funcion NtQueryInformationProcess es así:


delphi
  1. 7C91D7FE > B8 9A000000      MOV EAX,9A
  2. 7C91D803  BA 0003FE7F      MOV EDX,7FFE0300
  3. 7C91D808  FF12            CALL DWORD PTR DS:[EDX]
  4. 7C91D80A  C2 1400          RETN 14



El parcheo no me sirve ya que esas apis son llamadas con mucha asiduidad por el sistema y si parcheo a fuego no funcionan como deben ya que dependen de los parametros para que hagan una cosa u otra. Toca hacer un hook con filtro pero antes de nada tengo que ver porque la dll no corre si la inyecto en otro proceso, es lo mas urgente y luego ya se van viendo otras cosas.


Si ves, los 5 primeros bytes son una instrucción completa con lo que no debes tener problemas. El código que dejo usa automáticamente el desnsamblador de longitud, de forma que en principio no debes preocuparte del tema. Revisa la dll que dejé mas arriba, es completamente funcional.

Ten en cuenta que desde win32 no puedes inyectar un proceso win64, CreateRemoteTread no funciona en estos casos y los hooks te darán problema al ser tratados como enteros de 32bits en parte del código, eso habría que revisarlo.


Saludos.
  • 0

#26 aguml

aguml

    Newbie

  • Miembros
  • Pip
  • 7 mensajes

Escrito 19 junio 2014 - 01:49

El ejemplo de la dll que has puesto no compila. Haces algo extraño, tienes declarada por ejemplo la funcion para hookear como: void InstallHook() y la llamas al crear la dll en el entrypoint de la dll pero dentro de la funcion haces: InstallHook(NewMessageBox, (void**)&OMessageBox, "User32.dll", "MessageBoxA", true);
Eso es como si hicieras una sobrecarga de la funcion pero no la tienes declarada con esos parametros y ademas ¿seria recursiva la funcion? lo digo porque se llama a si misma aunque con diferentes parametros.
  • 0

#27 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 19 junio 2014 - 05:43

Si compila. No publico código sin probarlo antes.  (h)

La función está sobrecargada, pero puedes cambiar el nombre a InstallHooks si te gusta mas. La declaración está en APIHook.h

Te subo el proyecto y el binario.


Saludos.

Archivos adjuntos


  • 0

#28 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 07 marzo 2020 - 08:11

Los tiempos han cambiado en el entorno de delphi y Builder. Se impone el Unicode y con ello quedan obsoletas algunas implementaciones. En este caso vuelvo sobre este tema para actualizar el código tras una pregunta en el vecino CD: localizada aquí.

 

La revisión no hace más cambios que adaptarse al unicode forzando a no usarlo, la razón es porque GetProcAddress no tiene equivalente en GetProcAddressW y resulta más cómodo usar las versiones no unicode del resto de las API (LoadLibraryA y GetModuleHandleA)

 

He preparado un proyecto para compilar una dll que porta el Hook, otro para usarla y un tercero que no hace uso de la dll y sirve para experimentar todo en una sola app.

La utilidad del los hooks es mediante la inyección de dll, esa es la razón de los dos primeros proyectos, el tercero es para simplificar el aprendizaje y la experimentación. La inyección dll no es asunto de este turorial.

 

Dejo la revisión para Builder Berlín.

 

 

Saludos.

Archivos adjuntos


  • 0

#29 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 07 marzo 2020 - 11:00

Para delphi también tenemos que actualizar con ajustes en el Unicode para forzar su no uso debido a la API GetProcAddress. No se usa Unicode en las funciones que usan el hook pero el resto del programa es normal. Hay que tener presente que las APIs suelen tener una versión Unicode y otra clásica. Para el ejemplo que se usa MessageBox, tenemos MessageBoxA para la versión clásica y MessageBoxW para la versión unicode. No tratéis de hacer un hook con el nombre MessageBox sin especificar la versión, pues no existe ese nombre. El compilador lo ajusta y es por eso que estamos acostumbrados a no especificar. Para realizar el hook hay que especificar con exactitud que versión queremos.

 

Como he hecho para Builder, presento tres ejemplos, un proyecto para una dll que realiza un hook al cargarla o inyectarla, un proyecto que funciona con esa dll y otro proyecto para experimentar que se "hookea" a si mismo.

 

Subo los ejemplos para Berlin con código y binarios.

Archivos adjuntos


  • 1




IP.Board spam blocked by CleanTalk.