Alb*_*rto 0 c c++ assembly gcc inline-assembly
我有一个分配内存的代码,将一些缓冲区复制到该分配的内存中,然后跳转到该内存地址。
问题是我无法跳转到内存地址。我正在使用gcc,__asm__但无法调用该内存地址。
我想做类似的事情:
address=VirtualAlloc(NULL,len+1, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
dest=strncpy(address, buf, len);
Run Code Online (Sandbox Code Playgroud)
然后我要在ASM中执行此操作:
MOV EAX, dest
CALL EAX.
Run Code Online (Sandbox Code Playgroud)
我已经尝试过类似的东西:
__asm__("movl %eax, dest\n\t"
"call %eax\n\t");
Run Code Online (Sandbox Code Playgroud)
但这行不通。我该怎么做?
通常不需要为此使用asm,您可以简单地通过一个函数指针,让编译器来处理细节。
您确实需要__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;
}
Run Code Online (Sandbox Code Playgroud)
func(char*, int):
jmp [DWORD PTR [esp+4]] # tailcall
Run Code Online (Sandbox Code Playgroud)
此外,你实际上并不需要复制一个字符串,你可以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");
Run Code Online (Sandbox Code Playgroud)
说明: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下方的红色区域中声明破坏者。
| 归档时间: |
|
| 查看次数: |
745 次 |
| 最近记录: |