[Code / C++] Basic hooking of API Functions

07/18/2010 12:07 buFFy!#1
Global:

Code:
typedef BOOL (__stdcall * ReadProcessMemory_t)(HANDLE hProcess,LPVOID lpBaseAddress,LPCVOID lpBuffer,SIZE_T nSize,SIZE_T *lpNumberOfBytesRead);
ReadProcessMemory_t pReadProcessMemory;
Functions:
Code:
//Credits to GD ; You can do it manually, too.
void* detourFunc(BYTE *src, const BYTE *dst, const int len)
{
	BYTE *jmp = (BYTE*)malloc(len+5);
	DWORD dwback;

	VirtualProtect(src, len, PAGE_READWRITE, &dwback);

	memcpy(jmp, src, len);	jmp += len;

	jmp[0] = 0xE9;
	*(DWORD*)(jmp+1) = (DWORD)(src+len - jmp) - 5;

	src[0] = 0xE9;
	*(DWORD*)(src+1) = (DWORD)(dst - src) - 5;

	VirtualProtect(src, len, dwback, &dwback);

	return (jmp-len);
}
The Hook:
Code:
DWORD dwReadProcessMemory = (DWORD)GetProcAddress(GetModuleHandleA("kernel32.dll"), "ReadProcessMemory");
pReadProcessMemory = (ReadProcessMemory_t)detourFunc((BYTE*)dwReadProcessMemory, (BYTE*)&hkReadProcessMemory, 5);
The Hooked Function:
Code:
BOOL __stdcall hkReadProcessMemory(HANDLE hProcess,LPVOID lpBaseAddress,LPCVOID lpBuffer,SIZE_T nSize,SIZE_T *lpNumberOfBytesRead)
{
        //your code goes here
	return pReadProcessMemory(hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesRead);
}
07/18/2010 22:11 Bl@ze!#2
Also, ich kenne diese Methode zum hooken, ich finde sie aber fehleranfällig und nicht gut. Es gibt ja wirklich mehere Methoden zum Hooken. [Only registered and activated users can see links. Click Here To Register...]

Mit Detours geht es ganz gut und auch leicht, das schöne ist einfach es gibt eine ordentliche Fehlerbehandlung, die bei dir nicht da ist.

Ich habe auch mal eine Klasse geschrieben um DLL Funktionen zu Hooken.

HookManager.hpp
Code:
#pragma once

// C++/STL Header Files:
#include <list>
#include <string>
#include <exception>

// Windows Header Files:
#include <windows.h>
#include <tlhelp32.h>

// Project Header Files:
#include "EnsureClosure.hpp"

namespace Utilities
{
   /*!-------------------------------------------------------------------------
   |      author: Unkn0wn0x
   |      brief : Hook helper Utilitie class.
   |
   |      example usage:
   |
   |         HookManager *sendPacketHook = new HookManager(
   |            "ws2_32.dll", "send", (DWORD)&sendPacketCallBack);
   |   
   |         int (WINAPI*RealSendPacket)(SOCKET, const char *, int, int);
   |         RealSendPacket = 
   |           (int(WINAPI*)(SOCKET, const char*, int, int))
   |              sendPacketHook->callAddress();
   |
   |-------------------------------------------------------------------------*/
	template < typename pfunction_t >
   class HookManager
   {
      public:
			HookManager(const std::string& moduleName, const std::string& apiCallName, pfunction_t callBack)
         {
            m_lpdwExportTableAddress = 0;

	         //Get module handle of import and export module.
				HMODULE thisModule	= ::GetModuleHandle(NULL);
				HMODULE targetModule	= ::GetModuleHandleA(moduleName.c_str());
            if(targetModule == NULL)
               std::runtime_error("GetModuleHandle");

            //Get the API call address
				FARPROC apiCallAddress = GetProcAddress(hModule, apiCallName.c_str());
            if (apiCallAddress == NULL)
					throw std::runtime_error("GetProcAddress");

				//Get a snapshot of all modules
            SafeHandle modSnapshot(CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, 0));
				if (!modSnapshot.isValid())
               throw std::runtime_error("CreateToolhelp32Snapshot");

            DWORD dwProtect;

            // Iterate the complete module list
				MODULEENTRY32 modEntry = { sizeof(modEntry) };
            for(BOOL moreModuleEntries = Module32First(modSnapshot, &modEntry); moreModuleEntries; moreModuleEntries = Module32Next(modSnapshot, &modEntry)) 
            {
               if (targetModule == modEntry.hModule)
					{
                  PIMAGE_DOS_HEADER lpsDOS   = (PIMAGE_DOS_HEADER)sME32.modBaseAddr;
                  PIMAGE_NT_HEADERS lpsNT    = (PIMAGE_NT_HEADERS)(sME32.modBaseAddr+lpsDOS->e_lfanew);
                  PIMAGE_EXPORT_DIRECTORY lpsExport = (PIMAGE_EXPORT_DIRECTORY)(sME32.modBaseAddr + lpsNT->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);

                  DWORD dwBase = (DWORD)sME32.modBaseAddr;
                  DWORD *lpdwAddressTable = (DWORD*)(lpsExport->AddressOfFunctions + dwBase);
                  
                  for (DWORD i = 0; i < lpsExport->NumberOfFunctions; ++i)
						{
                     if( (DWORD)hAPI == (lpdwAddressTable[i]+dwBase))
							{
                        //Save export address before changing it!
                        m_dwExportAddress = lpdwAddressTable[i];
                        VirtualProtect(&lpdwAddressTable[i],4,PAGE_EXECUTE_READWRITE,&dwProtect);
                        lpdwAddressTable[i] = dwHook - (DWORD)hOwnModule;
                        VirtualProtect(&lpdwAddressTable[i],4,dwProtect,&dwProtect);
                     }
                  }
					}
					else
					{
			         //Change imports for our API (if available)
			         PIMAGE_DOS_HEADER lpsDOS   = (PIMAGE_DOS_HEADER)sME32.modBaseAddr;
			         PIMAGE_NT_HEADERS lpsNT    = (PIMAGE_NT_HEADERS)(sME32.modBaseAddr+lpsDOS->e_lfanew);
			         
                  if (lpsNT->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size == 0)
				         continue;

                  PIMAGE_IMPORT_DESCRIPTOR lpsImport = (PIMAGE_IMPORT_DESCRIPTOR)(sME32.modBaseAddr + lpsNT->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
                  DWORD dwBase = (DWORD)sME32.modBaseAddr;

                  while (lpsImport->Name)
						{
				         PIMAGE_THUNK_DATA lpsThunk = (PIMAGE_THUNK_DATA)(lpsImport->FirstThunk + sME32.modBaseAddr);

                     while (lpsThunk->u1.AddressOfData)
							{
                        if (lpsThunk->u1.AddressOfData == (DWORD)hAPI)
								{
                           // Store import adderss, before changing
                           m_dwImportAddress = lpsThunk->u1.AddressOfData;

                           // Store the import address poitner
                           m_liImportTable.push_back(&lpsThunk->u1.AddressOfData);

                           // Store table address
                           m_lpdwExportTableAddress = &lpsThunk->u1.AddressOfData;

                           VirtualProtect(&lpsThunk->u1.AddressOfData, 4, PAGE_EXECUTE_READWRITE, &dwProtect);
                           lpsThunk->u1.AddressOfData = dwHook;
                           VirtualProtect(&lpsThunk->u1.AddressOfData,4,dwProtect,&dwProtect);
                        }
                        lpsThunk++;
                     }
                     lpsImport++;
                  }
               }
            }
         }

         ~HookManager()
         {
            DWORD dwProtect;

            // Restore the export address
            if (m_lpdwExportTableAddress) {
               VirtualProtect(
                  m_lpdwExportTableAddress,
                  4,
                  PAGE_EXECUTE_READWRITE,
                  &dwProtect);
               
               *m_lpdwExportTableAddress = m_dwExportAddress;
               
               VirtualProtect(
                  m_lpdwExportTableAddress,
                  4,
                  dwProtect,
                  &dwProtect);
            }

            // Restore our old import addresses
            for (tImportTable::iterator cPos = m_liImportTable.begin();
               cPos != m_liImportTable.end(); ++cPos) {
                  VirtualProtect(
                     *cPos,
                     4,
                     PAGE_EXECUTE_READWRITE,
                     &dwProtect);

                  **cPos = m_dwImportAddress;

                  VirtualProtect(
                     *cPos,
                     4,
                     dwProtect,
                     &dwProtect);
            }
         }

         DWORD callAddress()
         {
            return m_dwImportAddress;
         }

      private:
         DWORD m_dwImportAddress;
         DWORD m_dwExportAddress;

         DWORD *m_lpdwExportTableAddress;

         typedef std::list<DWORD*> tImportTable;
         tImportTable m_liImportTable;
   };
}
EnsureClosure.hpp
Code:
#pragma once

// Windows Header Files:
#include <windows.h>

namespace Utilities
{
	class SafeHandle
	{
	public:
		SafeHandle() : handle_(NULL)
		{
			/* VOID */
		}

		SafeHandle(HANDLE handle) : handle_(handle)
		{
			/* VOID */
		}

		~SafeHandle()
		{
			close();
		}

		HANDLE operator=(HANDLE handle)
		{
			close();
			handle_ = handle;
			return *this;
		}

		operator HANDLE() const
		{
			return handle_;
		}

		bool isValid() const
		{
			return (handle_ != NULL && handle_ != INVALID_HANDLE_VALUE);
		}

		void close()
		{
			if(isValid())
				CloseHandle(handle_);
		}

	private:
		HANDLE handle_;
	};
}
Die tuts natürlich auch. (Beispiel zur Benutzung im Kommentar vorhanden)
Aber wie gesagt, letzendlich zum normalen Hooken bevorzuge ich Detours.

Edit: Außerdem habe ich gerade gesehen, dass dein Code nichts anderes macht als dieser hier: [Only registered and activated users can see links. Click Here To Register...], der besser beschrieben ist. *g*
07/19/2010 01:41 buFFy!#3
Ich habs heut irgendwo beim Platte aufräumen gefunden und dachte mir ich klatsch das hier einfach mal lieblos rein. :D
Btw stehe ich nicht so auf MS Detours ;P