繁体   English   中英

__asm__ gcc调用内存地址

[英]__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;
}

用GCC9.1 -O2 -m32编译为

func(char*, int):
    jmp     [DWORD PTR [esp+4]]    # tailcall

另外,您实际上不需要复制字符串,只需mprotectVirtualProtect它所在的页面即可使其可执行。 但是,如果要确保它确实在第一个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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM