简体   繁体   English

尝试创建Windows 8 Syscall Callgate函数

[英]Trying to create a windows 8 syscall callgate function

I have a windows 7 callgate function that I use to call NT functions directly: 我有一个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 );
}

I am trying to do the same thing for windows 8.1. 我正在为Windows 8.1做同样的事情。 I have updated all of the function call indexes; 我已经更新了所有的函数调用索引; however I noticed the actual callgate function is quite different on windows 8.1: 但是我注意到在Windows 8.1上实际的callgate函数是完全不同的:

Here is what the actual call gate looks like (located in ntdll.dll) for the function ZwCreateThreadEx 这是函数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

Now here is the EXACT same NT function (ZwCreateThreadEx) on windows 8.1 现在这里是Windows 8.1上完全相同的NT函数(ZwCreateThreadEx)

mov eax, 0xB0 //the call index
call dword ptr fs:[0xC0] 
retn 0x2C //2c/4 = 11 parameters

I have been trying all kinds of stuff to get this working on windows 8.1 but have had no avail. 我一直在尝试各种方法来使它在Windows 8.1上正常运行,但没有任何效果。 I cannot explain what the issue is or what is going wrong, all I know is I am doing it correctly on windows 7. 我无法解释问题是什么或出了什么问题,我所知道的是我在Windows 7上正确地执行了操作。

From the looks of the W8.1 function, I have attempted to come up with this single function (Does not work): 从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;
    };
}

Any help would be appreciated greatly. 任何帮助将不胜感激。

Your new callGate function doesn't set up the stack frame you want, the return address at the top of the stack is return address of callGate not the instruction after the call. 您新的callGate函数未设置您想要的堆栈框架,堆栈顶部的返回地址是callGate的返回地址,而不是调用后的指令。

This is what the stack looks like after the CALL instruction is executed in your example ZwCreateThreadEx from Windows 8.1: 这是在Windows 8.1中的示例ZwCreateThreadEx中执行CALL指令后的堆栈外观:

  • return address ( retn 0x2c instruction) 返回地址( retn 0x2c指令)
  • return address (caller of ZwCreateThreadEx) 返回地址(ZwCreateThreadEx的调用者)
  • arguments (11 DWORDs) 参数(11个双字)

Here's what the stack looks like after the JMP instruction is executed in your new callGate function: 这是在新的callGate函数中执行JMP指令后的堆栈外观:

  • return address (caller of callGate) 返回地址(callGate的调用者)
  • arguments 论点

There are other problems with your new callGate function. 您的新callGate函数还有其他问题。 It saves values in global variables which means you function isn't thread safe. 它将值保存在全局变量中,这意味着您执行的函数不是线程安全的。 Two threads can't call callBack at the same time without trashing these saved values. 两个线程不能同时调用callBack而不浪费这些保存的值。 It uses inline assembly which both makes your code more complicated that it needs to be and make its dependent on undocumented behaviour: how the compiler will set up the stack for the function. 它使用内联汇编,这既使您的代码变得更复杂,又使它依赖于未记录的行为:编译器将如何为该函数设置堆栈。

Here's how I write your Windows 8.1 version of callGate in MASM: 这是我在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

This implementation is limited to MAXARGS arguments (change the value if any Windows system call takes more than 16 arguments). 此实现仅限于MAXARGS参数(如果任何Windows系统调用使用的参数超过16个,则更改该值)。 It uses macros generate a table of CALL/RET code blocks to avoid having to store the number of arguments somewhere across the call. 它使用宏生成CALL / RET代码块表,以避免在调用过程中将参数数量存储在某个位置。 I have a version that supports any number of arguments but it's more complicated and a fair bit slower. 我有一个支持任何数量参数的版本,但它更复杂,而且速度稍慢。 This implementation is untested, I don't have Windows 8.1. 此实现未经测试,我没有Windows 8.1。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM