[英]__asm__ gcc call to a memory address
我有一个分配内存的代码,将一些缓冲区复制到该分配的内存中,然后跳转到该内存地址。
问题是我无法跳转到内存地址。 我正在使用gcc和__asm__
但是我无法调用该内存地址。
我想做类似的事情:
address=VirtualAlloc(NULL,len+1, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
dest=strncpy(address, buf, len);
然后我要在ASM中执行此操作:
MOV EAX, dest
CALL EAX.
我已经尝试过类似的东西:
__asm__("movl %eax, dest\n\t"
"call %eax\n\t");
但这行不通。 我该怎么做?
通常不需要为此使用asm,您可以简单地通过一个函数指针并让编译器来处理细节。
将机器代码复制到缓冲区之后__builtin___clear_cache(buf, buf+len)
您确实需要使用__builtin___clear_cache(buf, buf+len)
,然后再取消引用功能指针,否则可以将其优化为无效存储。 。 x86具有一致的指令高速缓存,因此它不会编译为任何额外的指令,但是您仍然需要它,以便优化器知道正在发生的事情。
static inline
int func(char *dest, int len) {
__builtin___clear_cache(dest, dest+len); // no instructions on x86 but still needed
int ret = ((int (*)(void))dest)(); // cast to function pointer and deref
return ret;
}
func(char*, int):
jmp [DWORD PTR [esp+4]] # tailcall
另外,您实际上不需要复制字符串,只需mprotect
或VirtualProtect
它所在的页面即可使其可执行。 但是,如果要确保它确实在第一个0
字节处停止以测试您的shellcode,请确保将其复制。
如果您仍然坚持使用内联汇编,那么您应该知道gcc内联汇编是一件复杂的事情。 另外,如果希望函数返回,则应确保它遵循调用约定,特别是它保留应有的寄存器。
AT&T的语法是op src, dst
因此您的mov
实际上是全局符号dest
的存储区。
就是说,这是该问题的措词:
int ret;
__asm__ __volatile__ ("call *%0" : "=a" (ret) : "0" (dest) : "ecx", "edx", "memory");
说明: https : //gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html
call *%0
= %0
引用第一个替代参数, *
是间接调用的标准gas
语法
"=a" (ret)
= eax
寄存器中的输出参数应在块后分配给变量ret
"0" (dest)
=输入参数与输出参数0
(即eax
)位于同一位置,应在块之前从dest
加载
"ecx", "edx"
=告诉编译器,按照正常的调用约定,这些寄存器可能会被asm块更改。
"memory"
=告诉编译器asm块可能对内存进行了未指定的修改,因此请勿缓存任何内容
请注意,在x86-64系统V(Linux / OS X)中,从这样的内联asm进行函数调用并不安全。 无法在RSP下方的红色区域中声明破坏者。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.