__asm__ gcc调用内存地址 [英] __asm__ gcc call to a memory address

查看:177
本文介绍了__asm__ gcc调用内存地址的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个分配内存的代码,将一些缓冲区复制到分配的内存中,然后跳转到该内存地址.

I have a code that allocates memory, copies some buffer to that allocated memory and then it jumps to that memory address.

问题是我无法跳转到内存地址.我正在使用gcc和__asm__,但无法调用该内存地址.

the problem is that I cant jump to the memory address. Im using gcc and __asm__ but I cant call that memory address.

我想做类似的事情:

address=VirtualAlloc(NULL,len+1, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
dest=strncpy(address, buf, len);

然后我要在ASM中执行此操作:

And then I want to do this in ASM:

MOV EAX, dest
CALL EAX.

我尝试过类似的事情:

  __asm__("movl %eax, dest\n\t"
 "call %eax\n\t");

但是它不起作用. 我该怎么办?

But it does not work. How can I do it?

推荐答案

通常不需要为此使用asm,您可以简单地通过一个函数指针,让编译器来处理细节.

There is usually no need to use asm for this, you can simply go through a function pointer and let the compiler take care of the details.

将机器代码复制到缓冲区之后,您确实需要使用__builtin___clear_cache(buf, buf+len),然后才能取消引用功能指针,否则可以为

You do need to use __builtin___clear_cache(buf, buf+len) after copy machine code to a buffer before you dereference a function-pointer to it, otherwise it can be optimized away as a dead store.. x86 has coherent instruction caches so it doesn't compile to any extra instructions, but you still need it so the optimizer knows what's going on.

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;
}

此外,您实际上不需要复制字符串,只需mprotectVirtualProtect该页面所在的页面即可使其可执行.但是,如果要确保它不会在第一个0字节处停止以测试您的shellcode,请确保将其复制.

Also, you don't actually need to copy a string, you can just mprotect or VirtualProtect the page it's in to make it executable. But if you want to make sure it does stop at the first 0 byte to test your shellcode, then sure copy it.

如果您仍然坚持使用内联汇编,则应该知道gcc内联汇编是一件复杂的事情.另外,如果希望函数返回,则应确保它遵循调用约定,特别是保留了应保留的寄存器.

If you nevertheless insist on inline asm, you should know that gcc inline asm is a complex thing. Also, if you expect the function to return, you should really make sure it follows the calling convention, in particular it preserves the registers it should.

AT& T的语法为op src, dst,因此您的mov实际上是全局符号dest的存储.

AT&T syntax is op src, dst so your mov was actually a store to the global symbol dest.

也就是说,这是该问题的答案:

That said, here is the answer to the question as worded:

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语法

call *%0 = the %0 refers to the first substitued argument, the * is standard gas syntax for indirect call

"=a" (ret) = eax寄存器中的输出参数应在块之后分配给变量ret

"=a" (ret) = output argument in eax register should be assigned to variable ret after the block

"0" (dest) =输入自变量与输出自变量0(即eax)位于同一位置,应在块之前从dest加载

"0" (dest) = input argument in the same place as output argument 0 (which is eax) should be loaded from dest before the block

"ecx", "edx" =告诉编译器,根据正常的调用约定,这些寄存器可能会被asm块更改.

"ecx", "edx" = tell the compiler these registers may be altered by the asm block, as per normal calling convention.

"memory" =告诉编译器asm块可能对内存进行了未指定的修改,因此不要缓存任何内容

"memory" = tell the compiler the asm block might make unspecified modifications to memory, so don't cache anything

请注意,在x86-64 System V(Linux/OS X)中,从这样的内联asm进行函数调用并不安全.无法在RSP下方的红色区域声明一个破坏者.

Note that in x86-64 System V (Linux / OS X), it's not safe to make a function call from inline asm like this. There's no way to declare a clobber on the red zone below RSP.

这篇关于__asm__ gcc调用内存地址的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆