汇编和C混合:重新分配RSP寄存器导致分段错误
我试图为一个子函数重新分配堆栈。我试图通过在Linux x86_64体系结构上混合汇编和C来实现这一点 以下是我的计划: 1.通过汇编和C混合:重新分配RSP寄存器导致分段错误,c,gcc,assembly,x86-64,inline-assembly,C,Gcc,Assembly,X86 64,Inline Assembly,我试图为一个子函数重新分配堆栈。我试图通过在Linux x86_64体系结构上混合汇编和C来实现这一点 以下是我的计划: 1.通过mmapsyscall获取一段内存。 2.将映射内存传递给asm func,然后将其分配给RSP寄存器并跳转到该函数 C功能: typedef struct Context { uint64_t rbx; // 0 uint64_t rsp; // 8 uint64_t rbp; // 16 uint
mmap
syscall获取一段内存。
2.将映射内存传递给asm func,然后将其分配给RSP寄存器并跳转到该函数
C功能:
typedef struct Context
{
uint64_t rbx; // 0
uint64_t rsp; // 8
uint64_t rbp; // 16
uint64_t r12; // 24
uint64_t r13; // 32
uint64_t r14; // 40
uint64_t r15; // 48
uint64_t rip; // 56
uint64_t break_point; // 64
} Context_st;
main_func()
{
...
Context_st contexts[1];
Context_st mainContexts;
// inittialize main stack and the function's stack. This should make the func return to main function, which is this one.
_init_contexts(contexts);
// This should backup main function's context and jump to another function with customized stack
_run_contexts(&mainContexts, contexts);
printf("Successfully returned\n"); // This could not be executed.
...
}
static void _init_contexts(Context_st pContexts[1])
{
int mmapFlags = MAP_PRIVATE | MAP_ANONYMOUS;
const size_t STACK_SIZE = 512;
asm_init_context(&(pContexts[0]));
pContexts[0].rip = (uint64_t)_some_func;
pContexts[0].break_point = (uint64_t)_func_to_go;
pContexts[0].rsp = (uint64_t)mmap(NULL, STACK_SIZE, PROT_READ | PROT_WRITE, mmapFlags, -1, 0);
pContexts[0].rsp += STACK_SIZE;
return;
}
static void _run_contexts(Context_st *pMainCtx, Context_st *pSubCtx)
{
asm_save_main_and_go(pMainCtx, pSubCtx);
return;
}
和装配功能:
#################################################
##
.text
.align 4
.globl asm_init_context
.type asm_init_context, @function
asm_init_context:
movq %rbx, (%rdi)
movq %rsp, 8(%rdi)
movq %rbp, 16(%rdi)
movq %r12, 24(%rdi)
movq %r13, 32(%rdi)
movq %r14, 40(%rdi)
movq %r15, 48(%rdi)
retq
#################################################
##
.text
.align 4
.globl asm_save_main_and_go
.type asm_save_main_and_go, @function
asm_save_main_and_go:
movq %rbx, (%rdi)
movq %rsp, 8(%rdi)
movq %rbp, 16(%rdi)
movq %r12, 24(%rdi)
movq %r13, 32(%rdi)
movq %r14, 40(%rdi)
movq %r15, 48(%rdi)
movl %esi, %eax
movq (%rsi), %rbx
movq 8(%rsi), %rsp # This is the code which causes SIGSEGV
movq 16(%rsi), %rbp
movq 24(%rsi), %r12
movq 32(%rsi), %r13
movq 40(%rsi), %r14
movq 48(%rsi), %r15
movq 56(%rsi), %rdx
push %rdx
jmp 64(%rsi)
我已经标记了导致SIGSEGV的asm代码。如果我把它注释掉,程序可能会正确运行并返回shell。但我不知道为什么
我做错什么了吗?或者如果我需要做一些额外的事情,使mmapped内存部分能够作为定制的堆栈空间用于RSP寄存器
非常感谢您
11月22日更新: 这很奇怪:当我切换到另一个虚拟机时,成功地调用了_func_to_go()。虽然返回后还有另一个分段错误,但由于错误堆栈,可能是已知问题 如果复制问题,我将不断更新。但我希望这仍然是“工作模式”
特别感谢和。您的讨论指出了我的一些错误,我已经或将在我的项目中纠正它们。:-) 我要求您做的第一件事是检查
mmap
是否成功。它可能失败了,您可能正试图读取/写入不可访问的内存。最后,您需要从asm\u save\u main\u和\u go
附加一个调试器和单步,并检查它到底在哪里失败。@AjayBrahmakshatriya如果movq 8(%rsi),%rsp
真的是SIGSEGV,那就不能是对齐问题,只需将mov
转换为rsp
即可。对齐将在以后引起问题。所以你关于无效内存的观点更有可能。但是我希望它已经在movq(%rsi),%rbx
.Oh和pContexts[0]崩溃了如果您仅使用mmap
堆栈大小。虽然它在技术上是正确的,但如果堆栈完全为空,[rsp]
仍然被视为“堆栈顶部值”,并且仅出于某些检查目的而达到该值的任何代码都将到达mmap
区域之外,我宁愿将一些nullptr
或“canary”值放入新堆栈中,因此,它将指向stack\u region.end()-8
地址,而不是确切地指向end()
@Ped7g。我不认为是该指令导致了问题。好吧,没有理由指令会失败。就像OP提到的那样,他通过观察代码在没有指令的情况下运行良好来挑出指令。所以这一定是因为这个指令而发生的事情。这里的不对准肯定会在libc中的某个地方导致崩溃。我要求您做的第一件事是检查mmap
是否成功。它可能失败了,您可能正试图读取/写入不可访问的内存。最后,您需要从asm\u save\u main\u和\u go
附加一个调试器和单步,并检查它到底在哪里失败。@AjayBrahmakshatriya如果movq 8(%rsi),%rsp
真的是SIGSEGV,那就不能是对齐问题,只需将mov
转换为rsp
即可。对齐将在以后引起问题。所以你关于无效内存的观点更有可能。但是我希望它已经在movq(%rsi),%rbx
.Oh和pContexts[0]崩溃了如果您仅使用mmap
堆栈大小。虽然它在技术上是正确的,但如果堆栈完全为空,[rsp]
仍然被视为“堆栈顶部值”,并且仅出于某些检查目的而达到该值的任何代码都将到达mmap
区域之外,我宁愿将一些nullptr
或“canary”值放入新堆栈中,因此,它将指向stack\u region.end()-8
地址,而不是确切地指向end()
@Ped7g。我不认为是该指令导致了问题。好吧,没有理由指令会失败。就像OP提到的那样,他通过观察代码在没有指令的情况下运行良好来挑出指令。所以这一定是因为这个指令而发生的事情。这里的不对准肯定会导致像libc这样的系统崩溃。