如何用C++给定的地址覆盖汇编程序栈的return地址?
How to overwrite the return address of the assembler stack with an address given by C++?
我得到了一个函数switchContext(void*& from, void*& to)
。它接收两个堆栈指针并应更改进程的上下文。因此,如果我有一个协程 A 并且它使用特定函数 resume()
,协程 B 将继续工作。
目前我的代码无法正常工作。
我正在使用 Nasm & GCC 进行编译。
汇编程序:(switchContext(void*& from, void*& to)
):
switchContext:
; epb = esp
mov ebp, esp
; save registers
push ebp
push ebx
push esi
push edi
; from <= returnadress
; eax <= returnadress
mov eax, [ebp+16]
mov edx, ebp
add edx, 20 ; make edx point to 'from'
; overwrite 'from' with returnadress
mov [edx], eax
; what to do now: returnadress <= to
; eax <= to
mov eax, [ebp+24]
mov edx, ebp
add edx, 16 ; make edx point to returnadress
; overwrite returnadress with 'to'
mov [edx], eax
pop edi ; RSA = esp + 12
pop esi ; RSA = esp + 8
pop ebx ; RSA = esp + 4
pop ebp ; RSA = esp + 0
; use new returnadress to jump to 'to'
ret
这是对应的C++ class:
extern "C" {
void switchContext(void*& from, void*& to);
}
class Coroutine {
public:
const char* name;
Coroutine(void* tos = 0)
{
setup(tos);
}
void resume(Coroutine* next)
{
switchContext(this->sp, next->sp);
}
virtual void body() = 0;
virtual void exit() = 0;
private:
static void startup(Coroutine* obj) {
obj->body();
obj->exit();
};
void setup(void* tos) {
if (tos == 0) {
unsigned temp_stack[1024];
this->sp = &temp_stack;
return;
}
this->sp = &tos;
return;
};
void* sp;
};
目前我的程序崩溃了。但它只能通过用 'to'.
覆盖汇编程序中的 return 地址来实现
这个过程我哪里出错了?
你的mov ebp,esp
放错地方了。应该是在寄存器保存之后。
您没有解除引用。从汇编程序的角度来看,C++ 引用只是一个指针,因此您的参数是 void **
。由于您想 save/load return 地址指向所指向的内容,因此您需要一个额外的间接寻址来将值保存到指向的地址。
与此问题无关:您使用 edx
进行的一些地址计算可以压缩为更少的指令。您也可以放弃使用 ebp
并使用基于 esp
的偏移量。
我得到了一个函数switchContext(void*& from, void*& to)
。它接收两个堆栈指针并应更改进程的上下文。因此,如果我有一个协程 A 并且它使用特定函数 resume()
,协程 B 将继续工作。
目前我的代码无法正常工作。
我正在使用 Nasm & GCC 进行编译。
汇编程序:(switchContext(void*& from, void*& to)
):
switchContext:
; epb = esp
mov ebp, esp
; save registers
push ebp
push ebx
push esi
push edi
; from <= returnadress
; eax <= returnadress
mov eax, [ebp+16]
mov edx, ebp
add edx, 20 ; make edx point to 'from'
; overwrite 'from' with returnadress
mov [edx], eax
; what to do now: returnadress <= to
; eax <= to
mov eax, [ebp+24]
mov edx, ebp
add edx, 16 ; make edx point to returnadress
; overwrite returnadress with 'to'
mov [edx], eax
pop edi ; RSA = esp + 12
pop esi ; RSA = esp + 8
pop ebx ; RSA = esp + 4
pop ebp ; RSA = esp + 0
; use new returnadress to jump to 'to'
ret
这是对应的C++ class:
extern "C" {
void switchContext(void*& from, void*& to);
}
class Coroutine {
public:
const char* name;
Coroutine(void* tos = 0)
{
setup(tos);
}
void resume(Coroutine* next)
{
switchContext(this->sp, next->sp);
}
virtual void body() = 0;
virtual void exit() = 0;
private:
static void startup(Coroutine* obj) {
obj->body();
obj->exit();
};
void setup(void* tos) {
if (tos == 0) {
unsigned temp_stack[1024];
this->sp = &temp_stack;
return;
}
this->sp = &tos;
return;
};
void* sp;
};
目前我的程序崩溃了。但它只能通过用 'to'.
覆盖汇编程序中的 return 地址来实现这个过程我哪里出错了?
你的mov ebp,esp
放错地方了。应该是在寄存器保存之后。
您没有解除引用。从汇编程序的角度来看,C++ 引用只是一个指针,因此您的参数是 void **
。由于您想 save/load return 地址指向所指向的内容,因此您需要一个额外的间接寻址来将值保存到指向的地址。
与此问题无关:您使用 edx
进行的一些地址计算可以压缩为更少的指令。您也可以放弃使用 ebp
并使用基于 esp
的偏移量。