app*_*der 6 c++ windows assembly
我有一个Windows 7 callgate函数,我用来直接调用NT函数:
//Windows 7 syscall
__declspec(naked)
NTSTATUS __fastcall wow64 ( DWORD ecxId, char *edxArgs )
{
__asm
{
mov eax, ecx;
mov ecx, m_param;
call DWORD ptr fs:[0xc0];
add esp, 0x4;
retn;
};
}
NTSTATUS callGate ( DWORD id, ... )
{
va_list valist;
va_start(valist,id);
return wow64(id,valist);
}
//Example NTClose function
NTSTATUS closeHandle ( void *object )
{
m_param = 0;
return callGate ( 0xc, object );
}
Run Code Online (Sandbox Code Playgroud)
我试图为Windows 8.1做同样的事情.我已经更新了所有的函数调用索引; 但是我注意到Windows 8.1上实际的callgate功能完全不同:
以下是函数ZwCreateThreadEx的实际调用门(位于ntdll.dll中)
mov eax, 0xA5 //the call index
xor ecx, ecx //(m_param)
lea edx, dword ptr ss:[esp + 0x4] //this causes an sp-analysis failure in IDA
call dword ptr fs:[0xC0]
add esp, 0x4
retn 0x2C
Run Code Online (Sandbox Code Playgroud)
现在这里是Windows 8.1上的完全相同的NT函数(ZwCreateThreadEx)
mov eax, 0xB0 //the call index
call dword ptr fs:[0xC0]
retn 0x2C //2c/4 = 11 parameters
Run Code Online (Sandbox Code Playgroud)
我一直在尝试各种各样的东西,以便在Windows 8.1上工作,但无济于事.我无法解释问题是什么或出了什么问题,我所知道的是我在Windows 7上正确地做到了.
从W8.1功能的外观来看,我试图提出这个单一的功能(不起作用):
DWORD dwebp,dwret,dwparams; //for saving stuff
NTSTATUS __cdecl callGate ( DWORD id, DWORD numparams, ... )
{
_asm
{
pop dwebp; //save ebp off stack
pop dwret; //save return address
pop eax; //save id
pop dwparams; //save param count
push dwret; //push return addy back onto stack cuz thats how windows has it
JMP DWORD ptr fs:[0xc0]; //call with correct stackframe (i think)
mov ecx, numparams; //store num params
imul ecx, 4; //multiply numparams by sizeof(int)
add esp, ecx; //add to esp
ret;
};
}
Run Code Online (Sandbox Code Playgroud)
任何帮助将非常感激.
您的新 callGate 函数没有设置您想要的堆栈帧,堆栈顶部的返回地址是 callGate 的返回地址,而不是调用后的指令。
这是在 Windows 8.1 的示例 ZwCreateThreadEx 中执行 CALL 指令后堆栈的样子:
retn 0x2c
指令)以下是在新的 callGate 函数中执行 JMP 指令后堆栈的样子:
您的新 callGate 函数还存在其他问题。它将值保存在全局变量中,这意味着您的函数不是线程安全的。两个线程不能callBack
同时调用而不破坏这些保存的值。它使用内联汇编,这既使您的代码变得更加复杂,又使其依赖于未记录的行为:编译器如何为函数设置堆栈。
以下是我在 MASM 中编写 Windows 8.1 版本的 callGate 的方法:
_text SEGMENT
MAXARGS = 16
do_call MACRO argcount
@@call&argcount:
call DWORD PTR fs:[0C0h]
ret argcount * 4
ENDM
call_table_entry MACRO argcount
DD OFFSET @@call&argcount
ENDM
_callGate PROC
pop edx ; return address
pop eax ; id
pop ecx ; numparams
push edx ; return address
cmp ecx, MAXARGS
jg @@fail
jmp [@@call_table + ecx * 4]
@@args = 0
REPT MAXARGS + 1
do_call %@@args
@@args = @@args + 1
ENDM
@@fail:
; add better error handling
int 3
jmp @@fail
@@call_table:
@@args = 0
REPT MAXARGS + 1
call_table_entry %@@args
@@args = @@args + 1
ENDM
_callGate ENDP
_TEXT ENDS
END
Run Code Online (Sandbox Code Playgroud)
此实现仅限于MAXARGS
参数(如果任何 Windows 系统调用采用超过 16 个参数,请更改值)。它使用宏生成 CALL/RET 代码块表,以避免在调用过程中在某处存储参数数量。我有一个支持任意数量参数的版本,但它更复杂并且速度慢一些。此实现未经测试,我没有 Windows 8.1。