C сгенерировать функцию и вызвать ее

#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 - занимает две точки в памяти (область функций), выделяет, копирует их в выделенную память и возвращает ее (void* используется как функция для вызова с помощью сборки)

CallRuntimeFunction - выполняет функции, возвращаемые из CreateFunction

#define AddressOfLabel(sectionname,out) - Выводит адрес метки (имя раздела) в переменную (out)

Когда я отлаживал этот код и вступил в вызов CallRuntimeFunction и перешел на разборку, Я видел много ??? вместо кода сборки между метками __start и __end.

Я попытался скопировать машинный код между двумя метками, а затем запустил его. Но я не знаю, почему я не могу назвать функцию, выделенную malloc.

Edit:

Я изменил код и выполнил часть работы. Память функции времени выполнения выделяет:

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 он переходит к другой функции и странным вещам.

Ответ 1

void CallRuntimeFunction(void* address) {
    __asm {
        call 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);

yes func - это указатель

Важно: проверьте параметры компилятора "вызов". Попробуйте объявить один

Ответ 2

Не забудьте сделать недействительными кеши (обе команды и данные) между генерацией кода функции и ее вызовом. Подробнее см. самомодифицирующийся код.