Click here to Skip to main content
15,889,281 members
Home / Discussions / C / C++ / MFC
   

C / C++ / MFC

 
QuestionWhich would you use - a static or member function for your worker thread? Pin
Ben Aldhouse15-Feb-10 4:49
Ben Aldhouse15-Feb-10 4:49 
AnswerRe: Which would you use - a static or member function for your worker thread? Pin
Chris Losinger15-Feb-10 8:47
professionalChris Losinger15-Feb-10 8:47 
GeneralRe: Which would you use - a static or member function for your worker thread? Pin
Ben Aldhouse15-Feb-10 8:58
Ben Aldhouse15-Feb-10 8:58 
QuestionHelp plz Pin
zakria8115-Feb-10 4:49
zakria8115-Feb-10 4:49 
AnswerRe: Help plz Pin
Avi Berger15-Feb-10 5:00
Avi Berger15-Feb-10 5:00 
QuestionRe: Help plz Pin
Maximilien15-Feb-10 5:00
Maximilien15-Feb-10 5:00 
AnswerRe: Help plz Pin
Michael Schubert15-Feb-10 5:51
Michael Schubert15-Feb-10 5:51 
QuestionProblem with DLL injection and API hooking Pin
vtorri15-Feb-10 4:44
professionalvtorri15-Feb-10 4:44 
Hi,

My purpose is to help the author of mpatrol to make that program as easy to use than valgrind on Windows. So i tried to look at DLL injection and API hooking.

I have written a program (named valgrind :p) and a DLL to test those 2 technics. More precisely, I have:


  • valgrind.exe : the program that will inject the DLL below
  • valgrind.dll : the DLL that will be injected in an executable and that will do API hooking
  • valgrind_test.exe : a executable that calls a function overloaded in valgrind.dll


I have taken some bits of code here and there in CodeProject. For the DLL injection, I used the VirtualAllocEx() / CreateRemoteThread() technic. For the API hooking, I enumerate all the modules and use ImageDirectoryEntryToData().

Here are the different codes:

valgrind.c

#include <stdio.h>
#include <string.h>

#include <windows.h>

#define CREATE_THREAD_ACCESS (PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_SUSPEND_RESUME | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ)

typedef HMODULE (*_load_library) (const char *);
typedef BOOL    (*_free_library) (HMODULE);

typedef struct _Vg Vg;

struct _Vg
{
  _load_library        ll;
  _free_library        fl;

  char                *dll_fullname;
  int                  dll_length;

  struct {
    HANDLE process1;
    HANDLE thread;
    HANDLE process2;
  } child;

  DWORD exit_code; /* actually the base address of the mapped DLL */
};

FARPROC
_vg_symbol_get (const char *module, const char *symbol)
{
  HMODULE  mod;
  FARPROC  proc;

  printf (" * loading library %s... ", module);
  mod = LoadLibrary(module);
  if (!mod)
    {
      printf("failed\n", module);
      return NULL;
    }
  printf ("done\n");

  printf (" * retrieving symbol %s... ", symbol);
  proc = GetProcAddress(mod, symbol);
  if (!proc)
    {
      printf("failed\n", symbol);
      goto free_library;
    }

  printf ("done\n");

  FreeLibrary(mod);

  return proc;

 free_library:
  FreeLibrary(mod);

  return NULL;
}

Vg *
vg_new()
{
  char    buf[MAX_PATH];
  Vg     *vg;
  HMODULE kernel32;
  DWORD   length;

  /* Check if CreateRemoteThread() is available. */
  /* MSDN suggests to check the availability of a */
  /* function instead of checking the Windows version. */

  kernel32 = LoadLibrary("kernel32.dll");
  if (!kernel32)
    {
      printf("no kernel32.dll found\n");
      return 0;
    }

  if (!GetProcAddress(kernel32, "CreateRemoteThread"))
    {
      printf("no CreateRemoteThread found\n");
      goto free_kernel32;
    }

  vg = (Vg *)calloc (1, sizeof (Vg));
  if (!vg)
    goto free_kernel32;

  vg->ll = (_load_library)_vg_symbol_get("kernel32.dll", "LoadLibraryA");
  if (!vg->ll)
    goto free_vg;

  vg->fl = (_free_library)_vg_symbol_get("kernel32.dll", "FreeLibrary");
  if (!vg->fl)
    goto free_vg;

  length = GetFullPathName("valgrind_dll.dll", MAX_PATH, buf, NULL);
  if (!length)
    {
      printf ("can't get full path name\n");
      goto free_vg;
    }

  vg->dll_fullname = _strdup(buf);
  if (!vg->dll_fullname)
    goto free_vg;

  vg->dll_length = length + 1;

  FreeLibrary(kernel32);

  return vg;

 free_vg:
  free(vg);
 free_kernel32:
  FreeLibrary(kernel32);

  return 0;
}

void
vg_del(Vg *vg)
{
  if (!vg)
    return;

  if (vg->child.process2)
    CloseHandle(vg->child.process2);
  if (vg->child.thread)
    CloseHandle(vg->child.thread);
  if (vg->child.process1)
    CloseHandle(vg->child.process1);
  free(vg->dll_fullname);
  free(vg);
}

int vg_dll_inject(Vg *vg, const char *prog)
{
  STARTUPINFO         si;
  PROCESS_INFORMATION pi;
  HANDLE              process;
  HANDLE              remote_thread;
  LPVOID              remote_string;
  DWORD               exit_code; /* actually the base address of the mapped DLL */

  ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
  ZeroMemory(&si, sizeof(STARTUPINFO));
  si.cb = sizeof(STARTUPINFO);

  printf (" * creating child process %s... ", prog); 
  if (!CreateProcess(NULL, (char *)prog, NULL, NULL, TRUE,
                     CREATE_SUSPENDED, NULL, NULL, &si, &pi))
    {
      printf ("failed\n * can't spawn child process %s\n", prog);
      return 0;
    }
  printf ("done\n");

  printf (" * waiting for the child process to initialize... ");
  if (!WaitForInputIdle(pi.hProcess, INFINITE))
    {
      printf("failed\n * no process for %s\n", prog);
      goto close_handles;
    }
  printf ("done\n");

  printf (" * opening child process... ");
  process = OpenProcess(CREATE_THREAD_ACCESS, FALSE, pi.dwProcessId);
  if (!process)
    {
      printf("failed\n * no process for %s\n", prog);
      goto close_handles;
    }
  printf ("done\n");

  printf (" * allocating virtual memory... ");
  remote_string = VirtualAllocEx(process, NULL, vg->dll_length, MEM_COMMIT, PAGE_READWRITE);
  if (!remote_string)
    {
      printf("failed\n");
      goto close_process;
    }
  printf ("done\n");

  printf(" * writing process in virtual memory... ");
  if (!WriteProcessMemory(process, remote_string, vg->dll_fullname, vg->dll_length, NULL))
    {
      printf("failed\n");
      goto virtual_free;
    }
  printf ("done\n");

  printf (" * execute thread... ");
  remote_thread = CreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)vg->ll, remote_string, 0, NULL);
  if (!remote_thread)
    {
      printf("failed\n");
      goto virtual_free;
    }
  printf ("done\n");

  WaitForSingleObject(remote_thread, INFINITE);

  printf (" * getting exit code... ");
  if (!GetExitCodeThread(remote_thread, &exit_code))
    {
      printf("failed\n");
      goto close_thread;
    }
  printf ("done\n");

  CloseHandle(remote_thread);
  VirtualFreeEx(process, remote_string, vg->dll_length + 1, MEM_RELEASE);

  printf(" * resume child process\n");
  ResumeThread(pi.hThread);

  vg->child.process1 = pi.hProcess;
  vg->child.thread = pi.hThread;
  vg->child.process2 = process;
  vg->exit_code = exit_code;

  return 1;

 close_thread:
  CloseHandle(remote_thread);
 virtual_free:
  VirtualFreeEx(process, remote_string, vg->dll_length, MEM_RELEASE);
 close_process:
  CloseHandle(process);
 close_handles:
  CloseHandle(pi.hThread);
  CloseHandle(pi.hProcess);

  return 0;
}

void
vg_dll_extract(Vg *vg)
{
  HANDLE thread;

  thread = CreateRemoteThread(vg->child.process2, NULL, 0,
                              (LPTHREAD_START_ROUTINE)vg->fl,
                              (void*)vg->exit_code, 0, NULL );
  WaitForSingleObject(thread, INFINITE );
  CloseHandle(thread );
}

int main(int argc, char *argv[])
{
  Vg *vg;

/*   if (argc < 2) */
/*     { */
/*       printf ("Usage: %s file\n\n", argv[0]); */
/*       return -1; */
/*     } */

  vg = vg_new();
  if (!vg)
    return -1;

  if (!vg_dll_inject(vg, "valgrind_test.exe"/*argv[1]*/))
    {
      printf(" * injection failed\n * exiting...\n");
      goto del_vg;
    }

  Sleep(2000);
  printf(" * fin process\n");

  vg_dll_extract(vg);

  vg_del(vg);
  printf(" * ressources freed\n");

  return 0;

 del_vg:
  vg_del(vg);

  return -1;
}


valgrind.dll

#include <stdio.h>

#include <windows.h>
#include <psapi.h>
#include <imagehlp.h>

typedef struct
{
  char *func_name_old;
  PROC func_proc_old;
  PROC func_proc_new;
} Vg_Hook;

typedef LPVOID (WINAPI *vgd_heap_alloc_t) (HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes);
typedef BOOL   (WINAPI *vgd_heap_free_t)  (HANDLE hHeap, DWORD dwFlags, LPVOID lpMem);
typedef void   (WINAPI *vgd_get_system_info_t)(LPSYSTEM_INFO lpSystemInfo);
typedef void   (WINAPI *vgd_get_system_time_t)(LPSYSTEM_INFO lpSystemTime);


Vg_Hook vg_hooks_kernel32[2];

LPVOID WINAPI VG_HeapAlloc(HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes)
{
  vgd_heap_alloc_t *ha;
  LPVOID data;

  printf("HeapAlloc !!!\n");

  ha = (vgd_heap_alloc_t *)vg_hooks_kernel32[0].func_proc_old;
  data = (*ha)(hHeap, dwFlags, dwBytes);

  return data;
}

BOOL WINAPI VG_HeapFree(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem)
{
  vgd_heap_free_t *hf;
  BOOL res;

  printf("HeapFree !!!\n");

  hf = (vgd_heap_free_t *)vg_hooks_kernel32[1].func_proc_old;
  res = (*hf)(hHeap, dwFlags, lpMem);

  return res;  
}

void WINAPI VG_GetSystemInfo(LPSYSTEM_INFO lpSystemInfo)
{
  vgd_get_system_info_t *gsi;

  printf ("GetSystemInfo !!!\n");
  gsi = (vgd_get_system_info_t *)vg_hooks_kernel32[0].func_proc_old;
  (*gsi)(lpSystemInfo);
}

void WINAPI VG_GetSystemTime(LPSYSTEM_INFO lpSystemTime)
{
  vgd_get_system_time_t *gst;

  printf ("GetSystemTime !!!\n");
  gst = (vgd_get_system_time_t *)vg_hooks_kernel32[1].func_proc_old;
  (*gst)(lpSystemTime);
}




#define MakePtr( cast, ptr, addValue ) (cast)( (DWORD)(ptr)+(DWORD)(addValue))

void
_vgd_modules_hook_set(HMODULE module, const char *lib_name, PROC old_function_proc, PROC new_function_proc)
{
  PIMAGE_IMPORT_DESCRIPTOR iid;
  PIMAGE_THUNK_DATA thunk;
  ULONG size;

  iid = (PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData(module, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &size);
  if (!iid)
    return;

  while (iid->Name)
    {
      PSTR module_name;

      module_name = (PSTR)((PBYTE) module + iid->Name);
      if (_stricmp(module_name, lib_name) == 0)
        break;
      iid++;
    }

  if (!iid->Name)
    return;

  thunk = (PIMAGE_THUNK_DATA)((PBYTE)module + iid->FirstThunk );
  while (thunk->u1.Function)
    {
      PROC *func;

      func = (PROC *)&thunk->u1.Function;
      if (*func == old_function_proc)
        {
          MEMORY_BASIC_INFORMATION mbi;
          DWORD dwOldProtect;

          VirtualQuery(func, &mbi, sizeof(MEMORY_BASIC_INFORMATION));

          if (!VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_READWRITE, &mbi.Protect))
            return;

          *func = *new_function_proc;

          VirtualProtect(mbi.BaseAddress, mbi.RegionSize, mbi.Protect, &dwOldProtect);

          break;
        }
      thunk++;
    }
}

void
_vgd_modules_hook(HMODULE main_module, const char *lib_name)
{
  HMODULE mods[1024];
  HMODULE lib_module;
  DWORD mods_nbr;
  unsigned int i;
  unsigned int j;

  lib_module = LoadLibrary(lib_name);

  for (j = 0; vg_hooks_kernel32[j].func_name_old; j++)
    vg_hooks_kernel32[j].func_proc_old = GetProcAddress(lib_module, vg_hooks_kernel32[j].func_name_old);

  if (!EnumProcessModules(GetCurrentProcess(), mods, sizeof(mods), &mods_nbr))
    return;

  for (i = 0; i < (mods_nbr / sizeof(HMODULE)); i++)
    {
      if (mods[i] == main_module)
        continue;

      for (j = 0; vg_hooks_kernel32[j].func_name_old; j++)
        _vgd_modules_hook_set(mods[i], lib_name,
                              vg_hooks_kernel32[j].func_proc_old,
                              vg_hooks_kernel32[j].func_proc_new);
    }

  FreeLibrary(lib_module);
}

void
_vgd_modules_unhook(HMODULE main_module, const char *lib_name)
{
  HMODULE mods[1024];
  DWORD mods_nbr;
  unsigned int i;
  unsigned int j;

  if (!EnumProcessModules(GetCurrentProcess(), mods, sizeof(mods), &mods_nbr))
    return;

  for (i = 0; i < (mods_nbr / sizeof(HMODULE)); i++)
    {
      if (mods[i] == main_module) continue;

      for (j = 0; vg_hooks_kernel32[j].func_name_old; j++)
        _vgd_modules_hook_set(mods[i], lib_name,
                              vg_hooks_kernel32[j].func_proc_new,
                              vg_hooks_kernel32[j].func_proc_old);
    }
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ulReason, LPVOID lpReserved)
{
/*   vg_hooks_kernel32[0].func_name_old = "HeapAlloc"; */
/*   vg_hooks_kernel32[0].func_proc_old = NULL; */
/*   vg_hooks_kernel32[0].func_proc_new = (PROC)VG_HeapAlloc; */

/*   vg_hooks_kernel32[1].func_name_old = "HeapFree"; */
/*   vg_hooks_kernel32[1].func_proc_old = NULL; */
/*   vg_hooks_kernel32[1].func_proc_new = (PROC)VG_HeapFree; */

  vg_hooks_kernel32[0].func_name_old = "GetSystemInfo";
  vg_hooks_kernel32[0].func_proc_old = NULL;
  vg_hooks_kernel32[0].func_proc_new = (PROC)VG_GetSystemInfo;

  vg_hooks_kernel32[1].func_name_old = "GetSystemTime";
  vg_hooks_kernel32[1].func_proc_old = NULL;
  vg_hooks_kernel32[1].func_proc_new = (PROC)VG_GetSystemTime;

  vg_hooks_kernel32[2].func_name_old = NULL;
  vg_hooks_kernel32[2].func_proc_old = NULL;
  vg_hooks_kernel32[2].func_proc_new = NULL;

  switch (ulReason)
    {
    case DLL_PROCESS_ATTACH:
      printf ("DLL attach\n");
      printf ("hooking... ");
      _vgd_modules_hook(hModule, "kernel32.dll");
      printf ("finished\n");
      break;
    case DLL_PROCESS_DETACH:
      printf ("DLL detach\n");
/*       _vgd_modules_unhook(hModule, "kernel32.dll"); */
      break;
    }

    return TRUE;
}


and the test code :

#include <stdio.h>

#include <windows.h>

int main()
{
  SYSTEMTIME st;

  GetSystemTime(&st);

  /* Exception non gérée à 0x100115b6 dans valgrind_test.exe : 0xC0000005: Violation d'accès lors de la lecture de l'emplacement 0x00000000. */

  return 0;
}


Now, the problems:


  • If i don't hook the functions in valgrind.dll, the injection is correctly done (there is a message displayed when the DLLL process is attached and one when the test example is executed).
  • If I hook several functions, the test program is executed, but an exception is raised (see the comment at the bottom of the test file. Sorry it is in french...)


I don't understand at all the problem.

Here is an archive of the code (with a Makefile for the gcc users or a visual studio solution) to test the code)

Does someone see the problem ?

thank you
QuestionID_FILE_SAVE lost Pin
CODEPC15-Feb-10 3:37
CODEPC15-Feb-10 3:37 
QuestionRe: ID_FILE_SAVE lost Pin
David Crow15-Feb-10 3:56
David Crow15-Feb-10 3:56 
AnswerRe: ID_FILE_SAVE lost Pin
CODEPC15-Feb-10 4:06
CODEPC15-Feb-10 4:06 
AnswerRe: ID_FILE_SAVE lost Pin
«_Superman_»15-Feb-10 4:02
professional«_Superman_»15-Feb-10 4:02 
GeneralRe: ID_FILE_SAVE lost [modified] Pin
CODEPC15-Feb-10 4:07
CODEPC15-Feb-10 4:07 
GeneralRe: ID_FILE_SAVE lost Pin
«_Superman_»15-Feb-10 17:27
professional«_Superman_»15-Feb-10 17:27 
Questioncompact database Pin
kk.tvm15-Feb-10 1:15
kk.tvm15-Feb-10 1:15 
AnswerRe: compact database Pin
CPallini15-Feb-10 1:38
mveCPallini15-Feb-10 1:38 
Questionconguring a special style for CMFCOutlookBarTabCtrl class Pin
A&Ms14-Feb-10 23:42
A&Ms14-Feb-10 23:42 
AnswerRe: conguring a special style for CMFCOutlookBarTabCtrl class Pin
A&Ms15-Feb-10 10:06
A&Ms15-Feb-10 10:06 
QuestionUnstable Thread runs! Pin
mostafa_pasha14-Feb-10 22:38
mostafa_pasha14-Feb-10 22:38 
AnswerRe: Unstable Thread runs! Pin
Rajesh R Subramanian14-Feb-10 22:43
professionalRajesh R Subramanian14-Feb-10 22:43 
GeneralRe: Unstable Thread runs! Pin
mostafa_pasha15-Feb-10 3:59
mostafa_pasha15-Feb-10 3:59 
GeneralRe: Unstable Thread runs! Pin
Rajesh R Subramanian15-Feb-10 6:38
professionalRajesh R Subramanian15-Feb-10 6:38 
GeneralRe: Unstable Thread runs! Pin
mostafa_pasha15-Feb-10 10:16
mostafa_pasha15-Feb-10 10:16 
AnswerRe: Unstable Thread runs! Pin
Rajesh R Subramanian15-Feb-10 17:03
professionalRajesh R Subramanian15-Feb-10 17:03 
QuestionCoUninitialize in ExitInstance hangs Pin
VictorSotnikov14-Feb-10 22:28
VictorSotnikov14-Feb-10 22:28 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.