Это далеко от вашей полной проблемы (C# ...), но это может дать вам некоторые подсказки.
Этот пример сделан в C с g cc на Linux - 64; вам, возможно, придется адаптировать его на вашей платформе.
Первым шагом было написать функцию с некоторой встроенной сборкой (синтаксис gnu-asm), чтобы увидеть, как она выглядит с objdump (на самом деле он никогда не вызывается) .
Здесь был найден трюк для перехода к постоянному адресу: { ссылка }
После этого мы должны создать исполняемый сегмент памяти и заполните его байтами, вдохновленными предыдущей функцией (благодаря objdump).
Если единственное, что можно изменить, это адрес, то мы просто перезаписываем этот адрес в предыдущем коде.
В этом примере адрес другой функции используется для этой цели.
Тогда этот исполняемый сегмент памяти можно рассматривать как функцию (гуд ... надеюсь), и мы используем его через указатель на функцию.
И, похоже, работа!
Единственная проблема, которую я вижу, это инструкция movb $0xff,0xa(%ecx,%ebx,4)
, которая делает что-то плохое, потому что я не знаю точно, что должны содержать регистры.
Я решил замените эту инструкцию на шесть nop
, чтобы занять то же место и сохранить этот пример аналогичным исходной задаче.
(я полагаю, что в контексте вашей проблемы эти регистры будут иметь соответствующее значение).
/**
gcc -std=c99 -o prog_c prog_c.c \
-pedantic -Wall -Wextra -Wconversion \
-Wc++-compat -Wwrite-strings -Wold-style-definition -Wvla \
-g -O0 -UNDEBUG -fsanitize=address,undefined
**/
#undef __STRICT_ANSI__ // for MAP_ANONYMOUS
#include <sys/mman.h>
#include <stdio.h>
#include <string.h>
#include <stddef.h>
void
target_function(void)
{
printf("~~~~ %s ~~~~\n", __func__);
}
void
inline_asm_example(void)
{
__asm__ __volatile__(
"\tnop\n"
"\tmovb $0xff,0xa(%ecx,%ebx,4)\n"
"\tjmpq *0x0(%rip)\n"
".quad 0xAA00BB11CC22DD33\n");
// the jump relative to rip is inspired from
// https://stackoverflow.com/a/53876008/11527076
}
int
main(void)
{
// create an executable page
void *page=mmap(NULL, 6+6+8,
PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
if(page==MAP_FAILED)
{
fprintf(stderr, "cannot allocate memory page\n");
return 1;
}
// initialise code pattern
// objdump --disassemble=inline_asm_example prog
char *code_pattern=(char *)page;
#if 0 // this instruction causes something wrong
memcpy(code_pattern+0,
"\x67\xc6\x44\x99\x0a\xff", 6); // movb $0xff, 10(%ecx,%ebx,4)
#else // use some useless instructions instead
memcpy(code_pattern+0,
"\x90\x90\x90\x90\x90\x90", 6); // 6x nop
#endif
memcpy(code_pattern+6,
"\xff\x25\x00\x00\x00\x00", 6); // jmpq *0x0(%rip)
// insert into the pattern the address we want to jump to
ptrdiff_t target_address=(ptrdiff_t)target_function;
memcpy(code_pattern+6+6, &target_address, sizeof(target_address));
// consider the code pattern as a function
void (*fnct_ptr)(void)=NULL;
memcpy(&fnct_ptr, &code_pattern, sizeof(code_pattern));
// here we go
printf("about to do something I will probably regret...\n");
fnct_ptr();
printf("ah? it was not so painful after all!\n");
// let's forget everything about that
munmap(code_pattern, 6+6+8);
return 0;
}