系統要調用一個函數,是不是先將函數頭部載入,接著就是函數的參數信息,以及函數中所調用的功能,最后是函數尾部信息?
我想知道的是系統調用一個函數的具体過程?函數結构的定義?以及用C語言模擬的具体方法!謝謝!

解决方案 »

  1.   

    先将返回地址压栈,再压入参数,然后指令指针条转到你call的函数地址处,执行完毕,退栈,指令直指针跳会call点执行下面的指令
      

  2.   

    对 blh(老猫)的一点补充:
    不同的 Calling Conventions(我不知道汉语怎么翻译)压出栈的顺序是不一样的。对stdcall方式来说是这样的:
    函数:int MyProc(int a, int b);
    调用:MyProc(2, 3);
    被编译成:
    push 3
    push 2
    call MyProc
    堆栈的恢复工作是由MyProc来做的。
      

  3.   

    如果是__cedcl方式(VC的默认调用方式),MyProc(2, 3);是这样的:
    push 3
    push 2
    call MyProc
    add esp, 8    // 恢复栈
      

  4.   

    // 函數第一部分代碼
    //typedef struct _APF_HOOK_FUNCTION_HEAD {

    BYTE bPush_EBP;
    WORD wMov_EBP_ESP; _APF_HOOK_FUNCTION_HEAD() {
    bPush_EBP = INSTR_PUSH_EBP;
    wMov_EBP_ESP = INSTR_MOV_EBP_ESP;
    };}APF_HOOK_FUNCTION_HEAD, * PAPF_HOOK_FUNCTION_HEAD;//
    // 构造 push dword ptr [ebp + xxh] 指令
    //typedef struct _APF_HOOK_FUNCTION_PUSH_PARAMETER {

    WORD wPush_Dword_Ptr;
    BYTE bOffset; _APF_HOOK_FUNCTION_PUSH_PARAMETER() {
    wPush_Dword_Ptr = INSTR_PUSH_DWORD_PTR;
    }} APF_HOOK_FUNCTION_PUSH_PARAMETER, * PAPF_HOOK_FUNCTION_PUSH_PARAMETER;//
    // 調用原來那一部分的代碼
    //typedef struct _APF_HOOK_CALL {
    BYTE bPushLong;
    DWORD dwConstant;
    BYTE bMov_EAX_DWORD;
    DWORD dwAddress;
    WORD wCall_EAX;
    _APF_HOOK_CALL() {
    bPushLong = INSTR_PUSH_LONG;
    bMov_EAX_DWORD = INSTR_MOV_EAX_DWORD;
    wCall_EAX = INSTR_CALL_EAX;
    }
    } APF_HOOK_CALL, * PAPF_HOOK_CALL;
    //
    // 函數的返回部分
    //typedef struct _APF_HOOK_FUNCTION_TAIL { WORD wMov_ESP_EBP;
    BYTE bPop_EBP;
    BYTE bRet;
    WORD wAdjustSize; _APF_HOOK_FUNCTION_TAIL() {
    wMov_ESP_EBP = INSTR_MOV_ESP_EBP;
    bPop_EBP = INSTR_POP_EBP;
    bRet = INSTR_RETN;
    };}APF_HOOK_FUNCTION_TAIL, * PAPF_HOOK_FUNCTION_TAIL;
      

  5.   

    非常感謝各位阿!
    各位請看看上面的代碼,我也是在看別人的代碼!
    上面是hook另外的函數時所定義的一些結构!然后在程序中和所要hook的函數交換地址以及參數等.
    它是怎樣按照這些步驟來實現的阿!能不能詳細說一下上面這段代碼定義的方式!
      

  6.   

    還有些定義是這樣的!
    #define INSTR_PUSH_EBP ( ( BYTE )0x55 )
    #define INSTR_MOV_EBP_ESP         ( ( WORD )0xEC8B )
    #define INSTR_MOV_ESP_EBP ( ( WORD )0xE58B )
    #define INSTR_POP_EBP ( ( BYTE )0x5D )
    #define INSTR_RETN ( ( BYTE )0xC2 )
    #define INSTR_MOV_EAX_DWORD ( ( BYTE )0xB8 )
    #define INSTR_PUSH_LONG ( ( BYTE )0x68 )
    #define INSTR_CALL_EAX ( ( WORD )0xD0FF )
    #define INSTR_PUSH_DWORD_PTR ( ( WORD )0x75FF )
      

  7.   

    感觉这些代码是用动态修改代码的方式Hook API?这些结构应该是对应于函数调用过程中各部分的二进制代码片段。其中指令的部分都在构造函数中预先编码好了,用的时候填入一些要求的常量,然后按顺序把结构写入代码中指定的位置。APF_HOOK_FUNCTION_HEAD保存栈顶指针到ebp
    push ebp
    mov ebp, espAPF_HOOK_FUNCTION_PUSH_PARAMETER 就是将栈中bOffset处的参数入栈
    push doword ptr[ebp + bOffset]APF_HOOK_CALL 压入常量,调用函数
    push dwConstant
    mov eax, dwAddress // Address应该是相对于模块加载首部的地址
    call eaxAPF_HOOK_FUNCTION_TAIL
    mov esp, ebp
    pop ebp
    ret wAdjustSize那些宏的定义值就是用到的某些指令编译后的二进制值。
      

  8.   

    呵呵!非常感謝: In355Hz(好象一条狗) 以及各位,上面的我在把原代碼抄上去的時候已經想的查不多了,但是有些地方一直心存疑惑:
    1.栈中"bOffset处"怎么樣得到,是否根据參數個數所計算出來的偏移值
    2.ret wAdjustSize一句中"wAdjustSize"代表了什么,這個一般又該怎樣得到
    3.象那些宏定義的机器碼(應該是這樣吧),如果這樣直接抄上去的話,它在內存里面可否正常運作,是不是就象那种純粹的單片机一樣只要把机器碼直接寫到內存的相應地址就可以了,拿
    typedef struct _APF_HOOK_FUNCTION_TAIL { WORD wMov_ESP_EBP;
    BYTE bPop_EBP;
    BYTE bRet;
    WORD wAdjustSize; _APF_HOOK_FUNCTION_TAIL() {
    wMov_ESP_EBP = INSTR_MOV_ESP_EBP;
    bPop_EBP = INSTR_POP_EBP;
    bRet = INSTR_RETN;
    };}APF_HOOK_FUNCTION_TAIL, * PAPF_HOOK_FUNCTION_TAIL;
    這個來說,把這個結構寫入內存后,它上面定義的那些參數怎么一下子都沒有了,只剩下這些類似的匯編代碼:
    mov esp, ebp
    pop ebp
    ret wAdjustSize
    是不是衹要象這樣就可以了啊!為什么???
    _APF_HOOK_FUNCTION_TAIL() {
    wMov_ESP_EBP = INSTR_MOV_ESP_EBP;
    bPop_EBP = INSTR_POP_EBP;
    bRet = INSTR_RETN;
    };
      

  9.   

    1.是參數個數的棧偏移地址,看參數的類型而定,由類型(比如byte)
      來計算參數偏移地址,一般從最后一個參數開始,往前計算( BYTE )( ( i +   1   ) * STACK_ELEMENT_SIZE );
    2.wAdjustSize代表調用返回的地址大小,由參數個數*STACK_ELEMENT_SIZE 計算出來, 然后ret wAdjustSize,
    3.在聲明參數的時候就相當于給其分配了內存,然后接下來就相當于往內存中寫入..比如WORD wMov_ESP_EBP;wMov_ESP_EBP=.......