linux function hook笔记(二) - ptrace基础 - Blog of Mathias
Blog of Mathias Web Securtiy&Deep Learning
linux function hook笔记(二) - ptrace基础
发表于: | 分类: reverse | 评论:0 | 阅读:1,016

linux下,为了方便用户对目标程序进行调试,提供了ptrace这个函数
那么ptrace可以修改目标寄存器,内存,因此我们也可以使用它来对目标进行hook
过程大致如下
1.使用/proc/pid/maps获知自身和目标libc加载基址,并根据偏移计算出mmap函数地址
2.使用ptrace attach目标,并修改目标寄存器和eip
让其跳转到mmap,申请出一片内存(返回地址设置为0,触发异常使ptrace能重新获得其控制权)
3.获得返回内存的地址,并写入我们的shellcode,调用dlopen加载我们编写的.so文件
4.把.GOT表中的函数地址替换成我们.so文件加载后的地址,这可以用之前的偏移方法计算得出

那么接下来介绍ptrace的基本应用
使用ptrace需要如下头文件

#include <sys/ptrace.h>  
#include <sys/types.h>  
#include <sys/wait.h>  
#include <unistd.h>   
#include <sys/syscall.h> 

需要注意的是
#include <linux/user.h> 这个文件定义了ORIG_EAX的宏,其中ORIG_EAX*4的地址处保存着系统调用号(发生系统调用时,eax的数值就是对应的系统调用号,会被保存到这个地址)
使用PTRACE_PEEKUSER就可以通过ORIG_EAX * 4,ECX * 4等宏(用户区域地址)获取到对应的寄存器值
这个文件在不同linux中对应的文件是不同的
因此你可以使用find /usr/include -iname '*.h' |xargs grep 'ORIG_EAX'
而/usr/include/asm/unistd.h 中保存着系统调用号的定义(进行系统调用时需要用到)

那么ptrace主要的用法有两种
1.在父进程中fork一个子进程
首先父进程调用fork()
返回值为子进程的pid
根据这个pid做对应的if判断(子进程中这个数值为0)
子进程中调用

ptrace(PTRACE_TRACEME,0,NULL,NULL)

表示接受父进程的调试
它会在触发系统调用的时候(比如execl函数)或者本进程退出的时候,把进程的控制权交给父进程。

在父进程中调用
wait(&status),返回值为子进程的返回值,这样在子进程运行完毕后可以回收它。同时status返回了其是否正常的信息。
用WIFEXITED(status)来获取,如果其数值不等于0,那么子进程正常退出。

ptrace(PTRACE_PEEKUSER,子进程pid,user区域地址,data) 

可以根据用户区域地址获取对应的寄存器数值,如果data为null,那么读取的数值会直接作为返回值

ptrace(PTRACE_PEEKTEXT,子进程pid,内存地址,data)
可以读取对应内存地址的一个字节

PTRACE_POKEUSR为写入字节

ptrace(PTRACE_CONT, pid, 0, signal),signal为0则忽略让调试停止的信号

同时让程序继续运行

ptrace(PTRACE_GETFPREGS, pid, 0, data)
会读取所有寄存器的数值,返回到data

这个data的类型必须是struct user_regs_struct,它和ORIG_EAX宏一样在user.h中定义。
ptrace(PTRACE_SETREGS, pid, 0, data)
则会用data设置所有寄存器的值

这里测试了一下读取ebp等寄存器的数值

1.png

2.attach一个pid,对应的是现有的一个进程。

ptrace(PTRACE_ATTACH,pid)
开始attach到某个进程上。
ptrace(PTRACE_DETACH,pid)
从某进程离开。

还不快抢沙发

添加新评论