API Interception

/**
 * Usage:
 *  "kernel32.dll", "Beep", 0, "arg_1", (FARPROC)func, __CDECL, 0 //- intercepts Beep func.
 *  "", "", 0x12345678, "eax,edx,ecx", (FARPROC)func, __STDCALL, 0 //- intercepts @ 0x12345678 offset of module base
 *  "some.dll", "", 0x12345678, "eax,edx,ecx", (FARPROC)func, __STDCALL, 0 //- intercepts @ 0x12345678 offset of some.dll base
 *
 *
 *  api_intercept.h
 *
 *
 *
 */

#define APII_PRE_BUFFER   128
#define APII_ARG_SEPARATOR  ','

#define APII_CONTINUE  0
#define APII_ERROR   -1

/// Calling convetion | __cdecl or __stdcall
enum C_CONV { __CDECL, __STDCALL };

typedef struct
{
 char  m_name[32]; // module name or "" for executable module
 char  f_name[16]; // function name
 DWORD  offset;  // function offset [IGNORED: if f_name set]
 char  f_arg[32]; // arg_1,eax,arg_2,ecx | selective function arguments
 FARPROC  function;
 enum C_CONV calling_convention; // name says it all lolz | default __CDECL
 FARPROC  call;  // set to original function call
} apii, *p_apii;


/// Helper dump_log function
#ifdef _DEBUG
void dump_log( char* txt, ... )
{
 va_list va;
 va_start( va, txt );
 char buffer[1024];
 wvsprintfA( buffer, txt, va );
 OutputDebugStringA( buffer );
 va_end( va );
}
#else
#define dump_log
#endif

/// helper defines
#define SAVE_EAX if ( !apii_eax ) { *p_buffer++ = 0x50; apii_eax = TRUE; };

BYTE* make_arg( BYTE* p_buffer, BYTE ss_position )
{
 p_buffer -= 5;

 memcpy( p_buffer, "\x8B\x44\x24", 3 );
 p_buffer += 3;
 *p_buffer++ = ss_position; // mov eax, dword ptr ss:[esp + ss_position]

 *p_buffer = 0x50; // push eax

 return p_buffer - 4;
}

 


/**
 * Name: apii_install
 * Desc: installs all hooks
 *
 */
int apii_install( p_apii api, int size )
{
 if ( api == NULL || !size )
  return -1;

 int installed = 0;

 for(int i=0; i<size; i++, api++)
 {
  DWORD address;

  /// get the module base
  address = (DWORD) GetModuleHandleA( api->m_name[0] == '\0' ? NULL : api->m_name );
  if ( address == NULL )
  {
   dump_log( "apii_install(): GetModuleHandleA() failed on \"%s\" [%i. entry]\n", api->m_name, i+1 );
   continue;
  }

  /// get the write address
  if ( api->f_name[0] != '\0' )
  {
   address = (DWORD) GetProcAddress( (HMODULE)address, api->f_name );
   if ( address == NULL )
   {
    dump_log( "apii_install(): GetProcAddress() failed on \"%s\" [%i. entry]\n", api->f_name, i+1 );
    continue;
   }
  } else
   address += api->offset;

  // post-write-values
  DWORD* call_address, *jmp_address;

  // pre_buffer  
  BYTE buffer[ APII_PRE_BUFFER + 1 ] = { 0x60 };
  BYTE* p_buffer = buffer + 1;     // real buffer
  BYTE* r_buffer = buffer + APII_PRE_BUFFER; // reverse buffer | right-2-left alignement
  BOOL apii_eax = FALSE;      // eax saved ?

  int  operation= APII_CONTINUE; // operation flow | APII_CONTINUE or APII_ERROR
  
  // count the arguments
  int  n_arg = 0;
  for(char* p = api->f_arg; *p != '\0' ; p++ )
   n_arg += *p == APII_ARG_SEPARATOR;
  int  t_arg = n_arg; // temp arguments

  for(char* p = api->f_arg; ; p++ )
  {
   while( *p == ' ' ) p++; // trim spaces
   if ( !memcmp( p, "this", 4) ) // this
   {
    r_buffer -= 5;
    *r_buffer++ = 0x68;
    *(DWORD*)r_buffer-- = (DWORD)api;
    p += 4;
    t_arg--;
   } else
   if ( !memcmp( p, "arg_", 4) ) // arg_[argument_#]
   {
    p += 4;
    if ( *p >= '0' && *p <= '9' )
    {
     BYTE ss_position = 0x24 + 0x4 + ( *p++ - '1' ) * 0x4 + t_arg * 0x4; // stack segment position
     SAVE_EAX
     r_buffer = make_arg( r_buffer, ss_position );
     t_arg--;
    } else
    {
     dump_log( "apii_install(): Bad arguments: \"%s\" [%i. entry]\n", api->f_arg, i+1 );
     operation = APII_ERROR;
     break;
    }
   }else
    if ( !memcmp( p, "caller", 6) )
    {
     SAVE_EAX
     r_buffer = make_arg( r_buffer, 0x20 + 0x4 + t_arg * 0x4 ); // pushad + push eax + pushed_arguments
     t_arg--;
     p += 6;
    } else
    {
     BYTE reg = 0x50; // push eax
     int c_sum = *p << 16 | *(p+1) << 8 | *(p+2);
     switch( c_sum )
     {
     case 0x00656469: // edi
      reg++;
     case 0x00657369: // esi
      reg++;
     case 0x00656270: // ebp
      reg++;
     case 0x00657370: // esp
      reg++;
     case 0x00656278: // ebx
      reg++;
     case 0x00656478: // edx
      reg++;
     case 0x00656378: // ecx
      reg++;
     case 0x00656178: // eax
      break;
     default:
      dump_log( "apii_install(): Bad arguments: \"%s\" [%i. entry]\n", api->f_arg, i+1 );
      operation = APII_ERROR;
      break;
     }

     // don't stop @ failed input
     if ( operation == APII_ERROR )
      break;

     *--r_buffer = reg;
     p += 3;
     t_arg--;
    }
   while( *p == ' ' ) p++; // trim spaces

   if ( *p == '\0' )
    break;
   else
    if ( *p != APII_ARG_SEPARATOR )
    {
     dump_log( "apii_install(): Bad arguments: \"%s\" [%i. entry]\n", api->f_arg, i+1 );
     operation = APII_ERROR;
     break;
    }
  }

  // don't stop @ failed input
  if ( operation == APII_ERROR )
   continue;

  // right to left - alignement
  int code_size = (buffer + APII_PRE_BUFFER) - r_buffer;
  memcpy( p_buffer, r_buffer, code_size  );
  p_buffer += code_size;

  *p_buffer++  = 0xE8;
  call_address = (DWORD*)p_buffer; // post-write-value
  p_buffer += 4;     // call apii->function
  
  if ( api->calling_convention == __CDECL && n_arg )
  {
   memcpy( p_buffer, "\x83\xC4", 2 );
   p_buffer[2] = (BYTE)n_arg * 4 + 4; // at least one arg must exist
   p_buffer += 3;
  }
  
  *p_buffer++  = 0x58;   // pop eax
  *p_buffer++  = 0x61;   // popad

  api->call  = (FARPROC)p_buffer;  // for orginal call function | must post change

  // rebuild first 5 bytes
  memcpy( p_buffer, (LPVOID)address, 5 );
  p_buffer += 5;

  *p_buffer++ = 0xE9;     
  jmp_address = (DWORD*)p_buffer;  // post-write-value
  p_buffer += 4;      // jmp back_to_function

  // allocate memory
  code_size = p_buffer - buffer;
  BYTE* p_alloc = (BYTE*) VirtualAlloc( NULL, code_size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE );
  if ( p_alloc == NULL )
  {
   dump_log( "apii_install(): VirtualAlloc() failed on %i. entry\n", i+1 );
   continue;
  }

  /// post-write
  *call_address = (DWORD)api->function - ((DWORD)p_alloc + ((DWORD)call_address) - (DWORD)buffer + 0x4);
  *jmp_address  = ((DWORD)address + 0x5) - ((DWORD)p_alloc + ((DWORD)jmp_address) - (DWORD)buffer + 0x4);
  api->call   = (FARPROC)(p_alloc - ((DWORD)buffer - (DWORD)api->call));
  memcpy( p_alloc, buffer, code_size );

  DWORD old_protection;
  if ( !VirtualProtect( (LPVOID)address, 5, PAGE_READWRITE, &old_protection ) )
  {
   dump_log( "apii_install(): VirtualProtect() failed on address 0x%.8x [%i. entry]\n", address, i+1 );
   VirtualFree( p_alloc, 0, MEM_RELEASE );
   continue;
  }

  *p_buffer  = 0xE9;
  call_address = (DWORD*)( p_buffer + 1 );
  *call_address = (DWORD)p_alloc - ( (DWORD)address + 0x5 ); // jmp [to_allocation]

  /// write jmp code
  memcpy( (LPVOID)address, p_buffer, 5 );
  VirtualProtect( (LPVOID)address, 5, old_protection, &old_protection );

  installed++;
 }

 return installed;
}


////////////////////////////////////////
#include "api_intercept.h"

 // "kernel32.dll", "Beep", 0, "arg_1", (FARPROC)func, __CDECL, 0 //- intercepts Beep func.
 // "", "", 0x12345678, "eax,edx,ecx", (FARPROC)func, __STDCALL, 0 //- intercepts @ 0x12345678 offset of module base
 // "some.dll", "", 0x12345678, "eax,edx,ecx", (FARPROC)func,   //- intercepts @ 0x12345678 offset of some.dll base
 // posible arguments:
 //  eax,ebx,ecx... - registers
 //  arg_#   - arguments
 //  caller   - caller address
 //  this   - pointer to apii structure

typedef BOOL(WINAPI* BEEP)(DWORD,DWORD);
void test_beep(apii* api,DWORD arg1,DWORD arg2,DWORD caller_address)
{
 ((BEEP)api->call)(arg1,arg2); // call it once more
 printf("Beep() called from: 0x%.8X\n", caller_address);
}

void WINAPI test_msg( DWORD caller_address, char* caption, char* text )
{
 printf("caption: %s | text: %s\n", caption, text);
}

int main()
{
 apii api[] = { "kernel32.dll", "Beep", 0, "this,arg_1,arg_2,caller", (FARPROC)test_beep, __CDECL, 0,
     "user32.dll", "MessageBoxA", 0, "caller,arg_3,arg_2", (FARPROC)test_msg, __STDCALL, 0 };
 apii_install( api, sizeof(api)/sizeof(api[0]) );

 Beep(0x1234,1000);
 MessageBoxA( NULL,"test-text", "test-caption", 0);

 return 0;
}

posted on 2011-03-08 20:45 挑灯看剑 阅读(190) 评论(0)  编辑 收藏 引用

<2009年1月>
28293031123
45678910
11121314151617
18192021222324
25262728293031
1234567

导航

公告

【自我介绍】 08年南开大学硕士毕业 最近关注:算法、Linux、c++、高并发 爱好:滑旱冰、打乒乓球、台球、保龄球

常用链接

随笔分类(139)

文章分类

我常去的网站

技术博客(都是大牛)

技术站点

搜索

积分与排名