extern "C" DWORD64 __cdecl X64Call(DWORD64 func, int argC, ...) { if (!g_isWow64) return 0; va_list args; va_start(args, argC); reg64 _rcx = { (argC > 0) ? argC--, va_arg(args, DWORD64) : 0 }; reg64 _rdx = { (argC > 0) ? argC--, va_arg(args, DWORD64) : 0 }; reg64 _r8 = { (argC > 0) ? argC--, va_arg(args, DWORD64) : 0 }; reg64 _r9 = { (argC > 0) ? argC--, va_arg(args, DWORD64) : 0 }; reg64 _rax = { 0 }; reg64 restArgs = { (DWORD64)&va_arg(args, DWORD64) }; // conversion to QWORD for easier use in inline assembly #ifdef _M_IX86 reg64 _argC = { (DWORD64)argC }; DWORD back_esp = 0; WORD back_fs = 0; __asm { ;// reset FS segment, to properly handle RFG mov back_fs, fs mov eax, 0x2B mov fs, ax ;// keep original esp in back_esp variable mov back_esp, esp ;// align esp to 0x10, without aligned stack some syscalls may return errors ! ;// (actually, for syscalls it is sufficient to align to 8, but SSE opcodes ;// requires 0x10 alignment), it will be further adjusted according to the ;// number of arguments above 4 and esp, 0xFFFFFFF0 X64_Start(); ;// below code is compiled as x86 inline asm, but it is executed as x64 code ;// that's why it need sometimes REX_W() macro, right column contains detailed ;// transcription how it will be interpreted by CPU ;// fill first four arguments REX_W mov ecx, _rcx.dw[0] ;// mov rcx, qword ptr [_rcx] REX_W mov edx, _rdx.dw[0] ;// mov rdx, qword ptr [_rdx] push _r8.v ;// push qword ptr [_r8] X64_Pop(_R8); ;// pop r8 push _r9.v ;// push qword ptr [_r9] X64_Pop(_R9); ;// pop r9 ;// REX_W mov eax, _argC.dw[0] ;// mov rax, qword ptr [_argC] ;// ;// final stack adjustment, according to the ;// ;// number of arguments above 4 ;// test al, 1 ;// test al, 1 jnz _no_adjust ;// jnz _no_adjust sub esp, 8 ;// sub rsp, 8 _no_adjust: ;// ;// push edi ;// push rdi REX_W mov edi, restArgs.dw[0] ;// mov rdi, qword ptr [restArgs] ;// ;// put rest of arguments on the stack ;// REX_W test eax, eax ;// test rax, rax jz _ls_e ;// je _ls_e REX_W lea edi, dword ptr [edi + 8*eax - 8] ;// lea rdi, [rdi + rax*8 - 8] ;// _ls: ;// REX_W test eax, eax ;// test rax, rax jz _ls_e ;// je _ls_e push dword ptr [edi] ;// push qword ptr [rdi] REX_W sub edi, 8 ;// sub rdi, 8 REX_W sub eax, 1 ;// sub rax, 1 jmp _ls ;// jmp _ls _ls_e: ;// ;// ;// create stack space for spilling registers ;// REX_W sub esp, 0x20 ;// sub rsp, 20h ;// call func ;// call qword ptr [func] ;// ;// cleanup stack ;// REX_W mov ecx, _argC.dw[0] ;// mov rcx, qword ptr [_argC] REX_W lea esp, dword ptr [esp + 8*ecx + 0x20] ;// lea rsp, [rsp + rcx*8 + 20h] ;// pop edi ;// pop rdi ;// // set return value ;// REX_W mov _rax.dw[0], eax ;// mov qword ptr [_rax], rax X64_End(); mov ax, ds mov ss, ax mov esp, back_esp ;// restore FS segment mov ax, back_fs mov fs, ax } #endif // _M_IX86 return _rax.v; }
DWORD64 Wow64Local::X64CallV( DWORD64 func, int argC, va_list args ) { DWORD64 _rcx = (argC > 0) ? argC--, va_arg(args, DWORD64) : 0; DWORD64 _rdx = (argC > 0) ? argC--, va_arg(args, DWORD64) : 0; DWORD64 _r8 = (argC > 0) ? argC--, va_arg(args, DWORD64) : 0; DWORD64 _r9 = (argC > 0) ? argC--, va_arg(args, DWORD64) : 0; reg64 _rax; _rax.v = 0; DWORD64 restArgs = (DWORD64)&va_arg(args, DWORD64); //conversion to QWORD for easier use in inline assembly DWORD64 _argC = argC; DWORD64 _func = func; DWORD back_esp = 0; __asm { ;//keep original esp in back_esp variable mov back_esp, esp ;//align esp to 8, without aligned stack some syscalls may return errors ! and esp, 0xFFFFFFF8 X64_Start(); ;//fill first four arguments push _rcx X64_Pop(_RCX); push _rdx X64_Pop(_RDX); push _r8 X64_Pop(_R8); push _r9 X64_Pop(_R9); push edi push restArgs X64_Pop(_RDI); push _argC X64_Pop(_RAX); ;//put rest of arguments on the stack test eax, eax jz _ls_e lea edi, dword ptr [edi + 8*eax - 8] _ls: test eax, eax jz _ls_e push dword ptr [edi] sub edi, 8 sub eax, 1 jmp _ls _ls_e: ;//create stack space for spilling registers sub esp, 0x20 call _func ;//cleanup stack push _argC X64_Pop(_RCX); lea esp, dword ptr [esp + 8*ecx + 0x20] pop edi //set return value X64_Push(_RAX); pop _rax.dw[0] X64_End(); mov esp, back_esp } return _rax.v; }
/** * * X64Call Part of WOW64Ext Library * See internals.h */ extern __declspec(dllexport) unsigned __int64 X64Call( void * lvpFunctionPtr, int nArgc, ... ) { va_list args; DWORD64 arg1, arg2, arg3, arg4, _nArgc, _lvpFunctionPtr, rest; DWORD dwEspBackup; union reg64 sRax; va_start( args, nArgc ); arg1 = ( nArgc ) ? nArgc--, va_arg( args, DWORD64 ) : 0; arg2 = ( nArgc ) ? nArgc--, va_arg( args, DWORD64 ) : 0; arg3 = ( nArgc ) ? nArgc--, va_arg( args, DWORD64 ) : 0; arg4 = ( nArgc ) ? nArgc--, va_arg( args, DWORD64 ) : 0; rest = (DWORD64)&va_arg( args, DWORD64 ); _nArgc = nArgc; _lvpFunctionPtr = (DWORD64)lvpFunctionPtr; dwEspBackup; sRax.v = 0; __asm { mov dwEspBackup, esp and sp, 0xFFF8 X64_Start(); push arg1 X64_Pop(_RCX); push arg2 X64_Pop(_RDX); push arg3 X64_Pop(_R8); push arg4 X64_Pop(_R9); push edi push rest X64_Pop(_RDI); push _nArgc X64_Pop(_RAX); test eax, eax jz _ls_e lea edi, dword ptr [edi + 8*eax - 8] _ls: test eax, eax jz _ls_e push dword ptr [edi] sub edi, 8 sub eax, 1 jmp _ls _ls_e: sub esp, 0x20 call _lvpFunctionPtr push _nArgc X64_Pop(_RCX); lea esp, dword ptr [esp + 8*ecx + 0x20] pop edi X64_Push(_RAX); pop sRax.dw[0] X64_End(); mov esp, dwEspBackup } }