Linux Hook--ptrace的常用參數使用

簡介

ptrace是一種系統調用,也就是進程追蹤(process trace);用於對進程的執行進行干涉以及寄存器狀態(值)的讀取以及設置,內存的寫入與讀取;我們常用的Linux下的gdb主要功能實現就是通過ptrace系統調用的:

#include <sys/ptrace.h>
long ptrace(enum __ptrace_request request, pid_t pid,void *addr, void *data);

通過request參數的不同來實現不同的功能;

常用的Ptrace參數

  1. PTRACE_ATTACH:建立不同進程間的跟蹤關係,附加成功後,目標進程將處於掛起狀態;被跟蹤進程,將會發送SIGSTOP信號給跟蹤者;跟蹤着需要調用wait()函數接收被跟蹤進程傳來的SIGSTOP信號,使用此參數時pid,addr,data參數都會被忽略:
ptrace(PTRACE_ATTACH, pid,NULL,NULL);
  1. PTRACE_TRACEME:指示其父進程,對其進行跟蹤;使用此參數時pid,addr,data參數都會被忽略:
if (ptrace(PTRACE_TRACEME, pid, NULL, NULL) < 0) {
	perror("PTRACE_TRACEME");
	exit(0);
}
  1. PTRACE_PEEKTEXTPTRACE_PEEKDATA:從addr參數指示的地址開始取一個WORD的長度的數據並通過返回值傳遞回來;使用此參數時data參數會被忽略:
data = ptrace(PTRACE_PEEKTEXT, pid, addr, NULL);
if (errno != 0) {
	perror("PTRACE_PEEKTEXT");
	exit(0);
}
  1. PTRACE_POKETEXTPTRACE_POKEDATA:從addr參數指示的地址開始入一個WORD長度的數據:
if (ptrace(PTRACE_POKETEXT, pid, addr, data) < 0) {
	perror("PTRACE_POKETEXT");
	exit(0);
}
  1. PTRACE_GETREGS:從被跟蹤的進程中讀取用戶寄存器的值到一個struct user_regs_struct結構體中,使用此參數時addr和data參數會被忽略:
#include<sys/user.h>
struct user_regs_struct reg;
if (ptrace(PTRACE_GETREGS, pid, NULL, &reg) < 0) {
	perror("PTRACE_GETREGS");
	exit(0);
}
printf("RIP: %p\n",reg.rip);
  1. PTRACE_SETREGS:將一個struct user_regs_struct類型的結構體中變量的值設置到被跟蹤進程的用戶寄存器中去;與上一個PTRACE_GETREGS請求配合使用,使用此參數時addr和data參數會被忽略:
if (ptrace(PTRACE_SETREGS, pid, NULL, &reg) < 0) {
	perror("PTRACE_SETREGS");
	exit(0);
}
  1. PTRACE_CONT:恢復pid指定的進程執行;當data參數不爲零時,data將會被解釋爲一個signal,傳遞給被跟蹤進程,使用此參數時addr參數被忽略:
if (ptrace(PTRACE_CONT, pid, NULL, NULL) < 0) {
	perror("PTRACE_CONT");
	exit(0);
}
  1. PTRACE_DETACHPTRACE_KILL:將會把SIGKILL發送給被跟蹤進程,脫離進程間的跟蹤關係,使用此參數時addr和data參數會被忽略:
if (ptrace(PTRACE_DETACH, pid, NULL, NULL) < 0) {
	perror("PTRACE_KILL");
	exit(0);
}

模擬gdb的break和continue操作

思路:

  1. 將需要下斷點的地址的代碼讀出並保存;
  2. 將需要下斷點的地址的代碼修改爲0xcc(int 3);
  3. 將需要下斷點的地址的代碼恢復.

被attach的程序

re.c:

#include <stdio.h>
#include <time.h>
#include <unistd.h>
void show()
{
    printf("Hello, ptrace! [pid:%d]\n", getpid());
}
int main() {
    while(1){
        show();
        sleep(2);
    }
    return 0;
}

編譯:

gcc re.c -o re

Ptarce程序

hook.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h> 
#include <unistd.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/reg.h>   /* For constants ORIG_EAX etc */
#include <sys/user.h>

void new_show()
{
    printf("Hooked by cc-sir!\n");
}

int main(int argc, char *argv[])
{   
    if(argc!=2) {
        printf("Usage: %s pid\n", argv[0]);
        return 0;
    }
    printf("new_show_addr: %p\n",new_show);
    struct user_regs_struct reg;
    pid_t pid = atoi(argv[1]);
    ptrace(PTRACE_ATTACH, pid,NULL,NULL);
    wait(NULL);
    ptrace(PTRACE_GETREGS,pid,NULL,&reg);
    printf("rip: 0x%lx\n",reg.rip);
    long addr = reg.rip;
    long show_addr = 0x400586;
    long code = 0xcc80cd;
    long back_code;
    int id;
    back_code = ptrace(PTRACE_PEEKTEXT, pid, addr, NULL);   //保留源碼
    printf("back_code: %llx\n",back_code);

    if(ptrace(PTRACE_POKETEXT, pid, addr, code) < 0){   //修改源碼
        perror("PTRACE_POKETEXT");
        return 0;
    }
    ptrace(PTRACE_CONT, pid, NULL, NULL);
    wait(NULL);
    printf("The process has int 0x3!\n");
    getchar();
    if(ptrace(PTRACE_POKETEXT, pid, addr, back_code) < 0){  //還原代碼
        perror("PTRACE_POKETEXT");
        return 0;
    }
    ptrace(PTRACE_SETREGS, pid, NULL, &reg); //還原寄存器
    ptrace(PTRACE_CONT, pid, NULL, NULL);
    printf("The process has continue run!\n");
    ptrace(PTRACE_DETACH, pid, NULL, NULL);
    return 0;
}

編譯:

gcc hook.c -o hook

結果:
效果

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章