内嵌汇编实现的函数转发

内嵌汇编实现的函数转发
  弄着玩的。功能是简单的实现函数转发,即
      调用CALL(func),转为调用func(),
      调用CALL(func, arg1, arg2) ,转为调用func(arg1, arg2)

  代码中,宏CALL/STDCALL分别用来调用  __cdecl/__stdcall 调用规定的函数
             unsafe_call 两者都可调用,但它不是多线程安全的。

  代码只支持x86 32位, 除内嵌汇编部分,尽量符合C++11标准。
       
原理:
     刚进入函数时,
     [esp]           函数返回地址
     [esp + 4]     第一个参数,即转发函数的地址
     [esp + 8]     第二个参数,即转发函数的的第一个参数
     ... 
   
      只要写三行汇编指令实现一个c_call函数,就可调用转发函数
      pop eax                             ; eax为函数返回地址
      xchg dword ptr[esp], eax     ; eax为转发函数的地址,[esp]为函数返回地址
      jmp eax
     
     当转发函数是__cdecl,即转发函数不会调节栈,由于在c_call,pop eax,使esp多加了4,因而在调用完c_call后应该手动将esp值减4,保证栈平衡。
   
    当转发函数是__stdcall,转发函数会调节栈,调用转发函数完毕后,栈已经保持平衡,因而调用c_call完毕,不应该进行栈指针调节。似乎将c_call的调用改为__stdcall即可,但实际上c_call有变长参数,改成__stdcall没效果,每次调用编译器还是会自动生成调节栈指针代码。因而只能每次调用完毕,编译器给esp加了多少,就手动减多少。(编译器不一定会生成 call  xxxx; add esp, xx这样的代码,通过改函数返回地址,忽略后面的add esp, xx指令是很糟糕的做法。)
call_redirect
  1 #include <cstdio>
  2 #include <cstdarg>
  3 #include <windows.h>
  4 
  5 #define CALL()    c_call(__VA_ARGS__); ASM_SUB_ESP(4);
  6 #define STDCALL() c_call(__VA_ARGS__); ASM_SUB_ESP(MACRO_ARGS(__VA_ARGS__) * 4);
  7 
  8 #define MACRO_EXPAND(x) x
  9 #define MACRO_NTH_ARG(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, ) a9
 10 #define MACRO_ARGS() \
 11     MACRO_EXPAND(MACRO_NTH_ARG(__VA_ARGS__, 9876543210))
 12 
 13 #if  __GNUC__
 14   // please enable option, -masm=intel
 15   #define ASM_SUB_ESP(x) asm("lea esp, dword ptr[esp - %0]" : : "i"(x))
 16 
 17   int c_call(void* pfn, ) asm("c_call");
 18   asm("                          \n\
 19     c_call:                      \n\
 20       pop eax;                   \n\
 21       xchg dword ptr[esp], eax;  \n\
 22       jmp eax;                   \n\
 23   ");
 24 
 25   int unsafe_call(void* pfn, )  asm("unsafe_call");
 26   asm("                                   \n\
 27       .lcomm old_ret_addr, 4              \n\
 28       .lcomm old_esp_value,4              \n\
 29     unsafe_call:                          \n\
 30       pop  dword ptr old_ret_addr;        \n\
 31       mov  dword ptr old_esp_value, esp;  \n\
 32       mov eax, dword ptr[esp];            \n\
 33       mov dword ptr[esp], offset last;    \n\
 34       jmp eax;                            \n\
 35     last:                                 \n\
 36       mov esp, dword ptr old_esp_value;   \n\
 37       jmp  dword ptr old_ret_addr;        \n\
 38   ");
 39 
 40 #elif  _MSC_VER
 41   #define ASM_SUB_ESP(x) __asm lea esp, dword ptr [esp - x]
 42 
 43   __declspec(naked) int c_call(void* pfn, )
 44   {
 45     __asm {
 46       pop eax;
 47       xchg dword ptr[esp], eax;
 48       jmp eax;
 49     }
 50   }
 51   __declspec(naked) int unsafe_call(void* pfn, )
 52   {
 53     static void* old_ret_addr;
 54     static void* old_esp_value;
 55     __asm {
 56       pop  old_ret_addr;
 57       mov  old_esp_value, esp;
 58       mov eax, dword ptr[esp];
 59       mov dword ptr[esp], offset last;
 60       jmp eax;
 61     last:
 62       mov esp, old_esp_value;
 63       jmp  old_ret_addr;
 64     }
 65   }
 66 
 67 #else
 68   #error "only gcc and msvc are supported"
 69 #endif
 70 
 71 
 72 void show(const char* format, )
 73 {
 74   va_list args;
 75   va_start(args, format);
 76   vprintf(format, args);
 77   va_end (args);
 78 }
 79 
 80 void mysleep() { Sleep(10); }
 81 
 82 void test1()
 83 {
 84   int a = 5, b = 6;
 85   show("%d + %d = %d\n", a, b, a + b);
 86   CALL((void*)printf, "%d + %d = %d\n", a, b, a + b);
 87   CALL((void*)mysleep);
 88   CALL((void*)show,   "%d + %d = %d\n", a, b, a + b);
 89 }
 90 
 91 void test2()
 92 {
 93   STDCALL((void*)MessageBoxA, NULL, "text1""caption1", MB_OK);
 94   STDCALL((void*)Sleep, 10);
 95   STDCALL((void*)MessageBoxA, NULL, "text2""caption2", MB_OK);
 96   STDCALL((void*)Sleep, 100);
 97 }
 98 
 99 void test3()
100 {
101   int a = 5, b = 6;
102   unsafe_call((void*)printf, "%d + %d = %d\n", a, b, a + b);
103   unsafe_call((void*)mysleep);
104   unsafe_call((void*)show,   "%d + %d = %d\n", a, b, a + b);
105   unsafe_call((void*)MessageBoxA, NULL, "text1""caption1", MB_OK);
106   unsafe_call((void*)Sleep, 10);
107   unsafe_call((void*)MessageBoxA, NULL, "text2""caption2", MB_OK);
108   unsafe_call((void*)Sleep, 100);
109 }
110 
111 int main()
112 {
113   test1();
114   test2();
115   test3();
116   return 0;
117 }
118 
119 
120

你可能感兴趣的:(内嵌汇编实现的函数转发)