版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/weixin_35390390/article/details/72730166
看libco,要搞明白怎么hook栈内存的
hook栈内存就是要 让函数中使用的临时变量 都 在指定的内存 上进行分配
首先看了一些关于函数栈的资料 X86汇编调用框架浅析与CFI简介,对函数压栈过程有了一些认识。
结合libco的代码,对hook栈内存有了一些自己的理解
在coctx_swap做了一些注释,如下:
//-------------
// 64 bit
//low | regs[0]: r15 |
// | regs[1]: r14 |
// | regs[2]: r13 |
// | regs[3]: r12 |
// | regs[4]: r9 |
// | regs[5]: r8 |
// | regs[6]: rbp |
// | regs[7]: rdi |
// | regs[8]: rsi |
// | regs[9]: ret | //ret func addr
// | regs[10]: rdx |
// | regs[11]: rcx |
// | regs[12]: rbx |
//hig | regs[13]: rsp |
struct coctx_t
{
void *regs[ 14 ];
size_t ss_size;
char *ss_sp;
};
extern "C"
{
extern void coctx_swap( coctx_t * x,coctx_t* y) asm("coctx_swap");
};
#elif defined(__x86_64__) // 该函数调用之前,rip(返回地址)会被压栈,所以rsp此时指向返回地址
leaq 8(%rsp),%rax // 此时rax=rsp+8 表示 调用方的栈顶
leaq 112(%rdi),%rsp // rsp 指向regs数组最后一个元素之后,也就是x.ss_size的位置 -- rdi是第一个入参 x rdi+112 = x.ss_size //rsp是栈顶指针
pushq %rax // 当前调用方的栈顶入栈 x.regs[13] = rsp // rsp被上一个指令修改了地址,此时rax保存着调用方的栈顶
pushq %rbx // 当前rbx入栈 x.regs[12] = rbx
pushq %rcx // 当前rcx入栈 x.regs[11] = rcx
pushq %rdx // 当前rdx入栈 x.regs[10] = rdx
pushq -8(%rax) //ret func addr // 当前返回地址入栈 x.regs[9] = 返回地址
pushq %rsi // rsi==参数y的地址 x.regs[8] == y
pushq %rdi // rdi==参数x的地址 x.regs[7] == x
pushq %rbp // 当前rbp入栈 x.regs[6] = rbp
pushq %r8 // 当前r8入栈 x.regs[5] = r8
pushq %r9 // 当前r9入栈 x.regs[4] = r9
pushq %r12 // 当前r12入栈 x.regs[3] = r12
pushq %r13 // 当前r13入栈 x.regs[2] = r13
pushq %r14 // 当前r14入栈 x.regs[1] = r14
pushq %r15 // 当前r15入栈 x.regs[0] = r15
// 以上操作的意思就是: 将当前线程的寄存器状态,保存到x中去,此时x让出cpu
movq %rsi, %rsp // 调整栈顶指针到 参数y的地址
popq %r15 // r15 = y.regs[0]
popq %r14 // ...
popq %r13
popq %r12
popq %r9
popq %r8
popq %rbp
popq %rdi // rdi = y.regs[7] = y // 如上 x.regs[7] == x // 当一个新协程开始执行时, rdi 中保存的是 新协程的地址
popq %rsi // rsi = y.regs[8] = xyz? // 未定,指向上一次y让出cpu时候的另一个协程的地址 // 当一个新协程开始执行时,rsi保存的是NULL
popq %rax //ret func addr // rax = y.regs[9] // 当一个新的协程开始执行时, 指向协程的回调函数,实际是对回调函数的封装
popq %rdx
popq %rcx
popq %rbx
popq %rsp // rsp = y.regs[13] // 当一个新协程开始执行时, regs[13]为栈内存的栈底-8 的位置, 此时函数运行时的栈hook到了已设定的内存
// 以上操作的意思就是: 将y中保存的寄存器状态,恢复到寄存器中,此时rsp指向保存时调用方的栈顶,以此作为当前y协程执行的栈底
pushq %rax // 把新协程保存的返回地址压栈,rsp此时指向 返回地址
xorl %eax, %eax // eax=0 eax是rax的低32位,也就是让rax的低32位置0
ret // 弹出返回地址到rip,到返回地址继续执行; 相当于 pop %rip; 此时 rsp -= 8
#endif