11
#include <stdio.h>

#define uint unsigned int
#define AddressOfLabel(sectionname,out) __asm{mov [out],offset sectionname};

void* CreateFunction(void* start,void *end) {
    uint __start=(uint)start,__end=(uint)end-1
        ,size,__func_runtime;
    void* func_runtime=malloc(size=(((__end)-(__start)))+1);
    __func_runtime=(uint)func_runtime;
    memcpy((void*)(__func_runtime),start,size);
    ((char*)func_runtime)[size]=0xC3; //ret
    return func_runtime;
}
void CallRuntimeFunction(void* address) {
    __asm {
        call address
    }
}

main() {
    void* _start,*_end;
    AddressOfLabel(__start,_start);
    AddressOfLabel(__end,_end);
    void* func = CreateFunction(_start,_end);
    CallRuntimeFunction(func); //I expected this method to print "Test"
    //but this method raised exception
    return 0;
__start:
    printf("Test");
__end:
}

CreateFunction- メモリ (関数スコープ) 内の 2 つのポイントを取得し、割り当て、割り当てられたメモリにコピーして返します (void*アセンブリで呼び出す関数のように使用されます) 。

CallRuntimeFunction- から返される関数を実行しますCreateFunction

#define AddressOfLabel(sectionname,out)・ラベル(sectionname)のアドレスを変数(out)に出力する

このコードをデバッグして、CallRuntimeFunctionand go to disassemblyの呼び出しを実行すると、とラベル???の間のアセンブリ コードの代わりに多くのコードが表示されました。__start__end

2 つのラベル間でマシンコードをコピーして実行しようとしました。しかし、で割り当てられた関数を呼び出せない理由がわかりませんmalloc

編集:

私はいくつかのコードを変更し、作業の一部を行いました。ランタイム関数のメモリ割り当て:

void* func_runtime=VirtualAlloc(0, size=(((__end)-(__start)))+1, MEM_COMMIT, PAGE_EXECUTE_READWRITE);

関数スコープからコピー:

CopyMemory((void*)(__func_runtime),start,size-1);

しかし、このプログラムを実行すると、次のことができます。

mov         esi,esp  
push        0E4FD14h  
call        dword ptr ds:[0E55598h] ; <--- printf ,after that I don't know what is it
add         esp,4  
cmp         esi,esp  
call        000B9DBB  ; <--- here
mov         dword ptr [ebp-198h],0  
lea         ecx,[ebp-34h]  
call        000B9C17  
mov         eax,dword ptr [ebp-198h]
jmp         000D01CB  
ret  

それhereは別の機能と奇妙なものに入ります。

4

2 に答える 2

2
void CallRuntimeFunction(void* address) {
    __asm {
        call address
    }
}

ここで address は、ポインタでもあるこの関数のパラメータへの「ポインタ」です。

ポインターへのポインター

使用する:

void CallRuntimeFunction(void* address) {
_asm {
    mov ecx,[address] //we get address of "func"
    mov ecx,[ecx]   //we get "func"
    call [ecx]      //we jump func(ecx is an address. yes)
    }
}

ポインタである func を呼び出したい。CallRunt... 関数に渡されると、そのポインターを指す新しいポインターが生成されます。二度のポインター。

void* func = CreateFunction(_start,_end);

はい func はポインタです

重要: コンパイラの「呼び出し規約」オプションを確認してください。decl one を試してください

于 2012-07-31T11:45:13.070 に答える
0

関数コードの生成とその呼び出しの間に、必ずキャッシュ (命令とデータの両方) を無効にしてください。詳細については、自己変更コードを参照してください。

于 2012-07-31T11:51:42.747 に答える