Ell*_*ink 7 c++ gcc inline-assembly att dynamic-function
我一直在研究一个(C++)项目,它需要完全动态分配的函数,这意味着malloc/new和mprotect,然后手动修改缓冲区到汇编代码.因此我完全想知道,我的这个"缓冲区"需要什么,因为它是任何其他_cdecl函数的复制品.例如:
int ImAcDeclFunc(int a, int b)
{
return a + b;
}
Run Code Online (Sandbox Code Playgroud)
如果我想从字面上创建这个函数的副本,但是完全动态,那需要什么(并记住它是带有内联汇编的C++ )?对于初学者,我想我必须做这样的事情(或类似的解决方案):
// My main....
byte * ImAcDeclFunc = new byte[memory];
mprotect(Align(ImAcDeclFunc), pageSize, PROT_EXEC | PROT_READ | PROT_WRITE);
Run Code Online (Sandbox Code Playgroud)
在此之后我将不得不找出汇编代码ImAcDeclFunc(int a, int b);.现在我在组装时仍然很糟糕,那么这个函数将如何用于AT&T语法?这是我的大胆尝试:
push %ebp
movl %%ebp, %%esp
movl 8(%ebp), %%eax
movl 12(%ebp), %%edx
addl edx, eax
pop ebp
ret
Run Code Online (Sandbox Code Playgroud)
现在如果这段代码是正确的(我非常怀疑,请纠正我)我只需要在十六进制中找到这个代码的值(例如,'jmp'是0xE9而'inc'是0xFE),并直接使用这些值C++?如果我继续以前的C++代码:
*ImAcDeclFunc = 'hex value for push'; // This is 'push' from the first line
*(uint)(ImAcDeclFunc + 1) = 'address to push'; // This is %ebp from the first line
*(ImAcDeclFunc + 5) = 'hex value for movl' // This is movl from the second line
// and so on...
Run Code Online (Sandbox Code Playgroud)
在我为整个代码/缓冲区完成此操作之后,这对于一个完全动态的_cdecl函数来说是否已足够(即我可以将其转换为函数指针并执行int result = ((int (*)(int, int))ImAcDeclFunc)(firstArg, secondArg)吗?).而且我对使用boost :: function或类似的东西不感兴趣,我需要函数完全动态,因此我的兴趣:)
注意:这个问题是我之前的问题的延续,但更具体.
如果你这样做lala.c:
int ImAcDeclFunc(int a, int b)
{
return a + b;
}
int main(void)
{
return 0;
}
Run Code Online (Sandbox Code Playgroud)
你可以编译它gcc -Wall lala.c -o lala.然后,您可以用objdump -Dslx lala >> lala.txt.反汇编可执行文件.你会发现ImAcDeclFunc组装到:
00000000004004c4 <ImAcDeclFunc>:
ImAcDeclFunc():
4004c4: 55 push %rbp
4004c5: 48 89 e5 mov %rsp,%rbp
4004c8: 89 7d fc mov %edi,-0x4(%rbp)
4004cb: 89 75 f8 mov %esi,-0x8(%rbp)
4004ce: 8b 45 f8 mov -0x8(%rbp),%eax
4004d1: 8b 55 fc mov -0x4(%rbp),%edx
4004d4: 8d 04 02 lea (%rdx,%rax,1),%eax
4004d7: c9 leaveq
4004d8: c3 retq
Run Code Online (Sandbox Code Playgroud)
实际上这个功能相对容易复制到其他地方.在这种情况下,你完全正确地说你可以复制字节,它只会工作.
当您开始使用将相对偏移作为操作码的一部分的指令时,将出现问题.例如,相对跳转或相对呼叫.在这些情况下,您需要正确地重新定位指令,除非您碰巧能够将其复制到与最初相同的地址.
简而言之,要重新定位,您需要找到它最初所在的位置,并计算您将基于它的位置的差异,并重新定位每个相对指令的偏移量.这本身是可行的.您真正的困难是处理对其他函数的调用,特别是对库的函数调用.在这种情况下,您需要保证链接库,然后以您定位的可执行格式定义的方式调用它.这非常重要.如果您仍然感兴趣,我可以指出您应该阅读的方向.
在上面的简单案例中,您可以这样做:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <sys/mman.h>
#include <unistd.h>
int main(void)
{
char func[] = {0x55, 0x48, 0x89, 0xe5, 0x89, 0x7d, 0xfc,
0x89, 0x75, 0xf8, 0x8b, 0x45, 0xf8,
0x8b, 0x55, 0xfc, 0x8d, 0x04, 0x02,
0xc9, 0xc3};
int (* func_copy)(int,int) = mmap(NULL, sizeof(func),
PROT_WRITE | PROT_READ | PROT_EXEC,
MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
memcpy(func_copy, func, sizeof(func));
printf("1 + 2 = %d\n", func_copy(1,2));
munmap(func_copy, sizeof(func));
return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)
这在x86-64上工作正常.它打印:
1 + 2 = 3
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2201 次 |
| 最近记录: |