修改ebp带来的问题一例

来源:互联网 发布:securecrt linux版 编辑:程序博客网 时间:2024/06/05 08:31

        一般情况下我们很少去修改ebp,即使使用汇编也只是用到eax 、ebx等几个通用寄存器,ebp和esp都是让编译器自动安排的。但有时ebp的修改就成为必须,如进行inline hook的时候,这时就要小心因为ebp的修改而带来的bug,以下为示例代码:

 

NTSTATUS My_PsCreateSystemThread(                                                                       

                            _Out_      PHANDLE ThreadHandle,
                            _In_       ULONG DesiredAccess,
                            _In_opt_   POBJECT_ATTRIBUTES ObjectAttributes,
                            _In_opt_   HANDLE ProcessHandle,
                            _Out_opt_  PCLIENT_ID ClientId,
                            _In_       PKSTART_ROUTINE StartRoutine,
                            _In_opt_   PVOID StartContext
                           )
{
    char *FuncAddr = NULL;
    UNICODE_STRING UniCodeFunctionName;
    NTSTATUS ntStatus = STATUS_SUCCESS;

    RtlInitUnicodeString( &UniCodeFunctionName, L"PsCreateSystemThread" );
    FuncAddr = (char *)MmGetSystemRoutineAddress( &UniCodeFunctionName );
    if ( NULL == FuncAddr )
        return CANNOT_GET_ROUNTINE_ADDRESS;

    FuncAddr += 5;

    //做一些前期处理,主要是一些判断,代码省略

    __asm
    {
        pushad
        mov eax, StartContext
        push eax
        mov eax, StartRoutine
        push eax
        mov eax, ClientId
        push eax
        mov eax, ProcessHandle
        push eax
        mov eax, ObjectAttributes
        push eax
        mov eax, DesiredAccess
        push eax
        mov eax, ThreadHandle
        push eax
        push label
        push ebp
        _emit 0x8b     //mov ebp, esp的机器码
        _emit 0xec
        jmp FuncAddr


label:
        mov ntStatus, eax
        popad
    }


    //做些后期处理,代码省略

    return ntStatus;

   
}


    看上去上面的代码似乎没什么问题,执行起来却出乎意料,一运行这段程序系统就崩溃。逐行跟踪发现,程序运行到jmp FuncAddr就出错,此时FuncAddr的值已经不是原来的值了,切换到纯汇编代码,FuncAddr存放在ebp-4这个地方,由于ebp的修改,ebp-4已经不是原来那个地方了。
    编译器在编译代码时,一边都是以ebp作为基准来定位各个参数以及局部变量的,在函数开头执行完push ebp; mov ebp, esp;sub esp, xx;这三条典型代码后,ebp作为栈底指针是不会变的。对于在代码中的手动ebp修改,编译器是不会去修正变量定位的,这就导致以上问题的存在。事实上,vc编译器也不允许你用mov ebp, esp这样的汇编语句,碰到这样的语句编译器会给出错误并停止编译。基于此,以上代码采用直接嵌入机器指令的做法。
    上面的代码如何修正呢,其实很简单,看下修改后的代码就知道了:
   
     __asm
    {
        pushad
        mov eax, StartContext
        push eax
        mov eax, StartRoutine
        push eax
        mov eax, ClientId
        push eax
        mov eax, ProcessHandle
        push eax
        mov eax, ObjectAttributes
        push eax
        mov eax, DesiredAccess
        push eax
        mov eax, ThreadHandle
        push eax
        mov eax, FuncAddr
        push label
        push ebp
        _emit 0x8b     //mov ebp, esp的机器码
        _emit 0xec
        jmp eax


label:
        mov ntStatus, eax
        popad
    }

       

 

原创粉丝点击