Linux內核之struct pt_regs結構

前沿

? ? ? ?項目開發最近進行系統hook功能實現相關業務,主要在centos7和8系列環境開發下關功能。調研了相關知識點,發現在系統7和8上內核版本差別比較大,7-3.10.x系列版本,8-4.18.x系列版本。依據兩個系統的內核情況根對應的內核符號表進行數據業務的鉤子功能開發。開發過程發現兩個系統雖然都定義對應的鉤子目標函數定義,但是實際過程發現在7系統上直接定義于目標函數相同的函數進行hook即可,而系統8系列可以直接將參數定義成pt_regs進行處理。那么問題來了,這個結構是個什么?有什么用?如何使用?帶著這么幾個問題來逐個來介紹。

1.struct pt_regs是什么

? ? ? ? pt_regs內核定義一個結構,其文件定義路徑通常為arch/x86/include/asm/ptrace.h,如下結構定義:

(__i386__)

struct pt_regs {unsigned long bx;// bx	%ebx	通用寄存器,通常用作基址寄存器(Base Register),保存數據或地址。unsigned long cx;// cx	%ecx	通用寄存器,常用作計數器(Counter),如循環計數或字符串操作。unsigned long dx;// dx	%edx	通用寄存器,通常與 %eax 配合使用,存放數據或 I/O 端口地址。unsigned long si;// si	%esi	源索引寄存器(Source Index),用于內存操作的源地址(如 movs 指令)。unsigned long di;// di	%edi	目的索引寄存器(Destination Index),用于內存操作的目的地址。unsigned long bp;// bp	%ebp	基址指針寄存器(Base Pointer),指向當前棧幀的基地址,用于函數調用。unsigned long ax;// ax	%eax	累加寄存器(Accumulator),用于算術運算和系統調用的返回值。unsigned long ds;// ds	%ds	數據段寄存器(Data Segment),指向當前數據段的段選擇子。unsigned long es;// es	%es	附加段寄存器(Extra Segment),用于某些內存操作(如字符串操作)。unsigned long fs;// fs	%fs	附加段寄存器,Linux 內核中通常用于線程本地存儲(TLS)或特定內核用途。unsigned long gs;// gs	%gs	附加段寄存器,用途與 %fs 類似,可能用于特定擴展。unsigned long orig_ax;// orig_ax	-	原始系統調用號或中斷錯誤碼:- 系統調用時保存系統調用號(如 __NR_read)。- 中斷或異常時保存錯誤碼或中斷向量號。unsigned long ip;// ip	%eip	指令指針寄存器(Instruction Pointer),指向下一條要執行的指令地址。unsigned long cs;// cs	%cs	代碼段寄存器(Code Segment),保存當前代碼段的段選擇子。unsigned long flags;// flags	%eflags	標志寄存器,保存 CPU 狀態標志(如中斷使能、方向標志、溢出標志等)。unsigned long sp;// sp	%esp	棧指針寄存器(Stack Pointer),指向當前棧頂地址。unsigned long ss;// ss	%ss	棧段寄存器(Stack Segment),指向當前棧段的段選擇子。
};

x86_64位:

struct pt_regs {unsigned long r15; // r15	%r15	通用寄存器,通常用于保存臨時數據或地址。在系統調用中可能作為第 6 個參數(若需要)。unsigned long r14; // r14	%r14	通用寄存器,用途同上。unsigned long r13; // r13	%r13	通用寄存器,用途同上。unsigned long r12; // r12	%r12	通用寄存器,用途同上。unsigned long bp; // bp	%rbp	基址指針寄存器,指向當前棧幀的基地址,用于函數調用棧回溯。unsigned long bx; // bx	%rbx	基址寄存器,常用于保存數據或地址(如內存操作的基地址)。unsigned long r11; // r11	%r11	通用寄存器,可能用于臨時存儲或特定指令(如 syscall 指令會破壞 %r11)。unsigned long r10; // r10	%r10	通用寄存器,在系統調用中作為第 4 個參數(若需要)。unsigned long r9; // r9	%r9	通用寄存器,在系統調用中作為第 5 個參數(若需要)。unsigned long r8; // r8	%r8	通用寄存器,在系統調用中作為第 6 個參數(若需要)。unsigned long ax; // ax	%rax	累加寄存器,用于系統調用的返回值(ret 前內核會設置 regs->ax)。unsigned long cx; // cx	%rcx	計數器寄存器,在 syscall 指令中保存返回地址(被破壞),某些場景下可能作為第 4 個參數。unsigned long dx; // dx	%rdx	數據寄存器,通常用于系統調用的第 3 個參數。unsigned long si; // si	%rsi	源索引寄存器,通常用于系統調用的第 2 個參數。unsigned long di; // di	%rdi	目的索引寄存器,通常用于系統調用的第 1 個參數。unsigned long orig_ax; // orig_ax-原始系統調用號或中斷錯誤碼:- 系統調用時保存系統調用號(如 __NR_read),- 中斷或異常時保存中斷向量號或錯誤碼。unsigned long ip; // ip	%rip	指令指針寄存器,指向觸發中斷/異常/系統調用的下一條指令地址(即用戶空間的返回地址)。unsigned long cs; // cs	%cs	代碼段寄存器,保存當前代碼段的段選擇子(用戶態為 0x33,內核態為 0x10)。unsigned long flags; // flags	%rflags	標志寄存器,保存 CPU 狀態標志(如中斷使能、方向標志、溢出標志等)。unsigned long sp; // sp	%rsp	棧指針寄存器,指向用戶空間的棧頂地址。unsigned long ss; // ss	%ss	棧段寄存器,保存當前棧段的段選擇子(用戶態為 0x2b)。
};

?上述兩個結構均為x86架構定義,但是實際次做中發現在arm重有偏差,這里簡要列出結構,后有文章詳細介紹相關用途,結構如下:

arm64架構pt_regs結構定義:

/** This struct defines the way the registers are stored on the stack during an* exception. Note that sizeof(struct pt_regs) has to be a multiple of 16 (for* stack alignment). struct user_pt_regs must form a prefix of struct pt_regs.*此結構定義了異常期間寄存器在堆棧上的存儲方式。需要注意的是,sizeof(struct pt_regs)必須是16的倍數(用于堆棧對齊)。*另外,結構user_pt_regs必須構成結構pt_regs的前綴。*/struct pt_regs {union {struct user_pt_regs user_regs;struct {u64 regs[31];  // X0-X30(通用寄存器)系統調用參數通過 regs[0]-regs[7](X0-X7)傳遞。u64 sp;        // 棧指針 (SP_EL0) 保存用戶空間棧頂地址,用于恢復用戶態執行。u64 pc;        // 程序計數器 (PC)保存觸發中斷/異常/系統調用的指令地址(即返回地址)。u64 pstate;    // 處理器狀態 (PSTATE)};};u64 orig_x0; //保存系統調用 第一個參數的原始值。某些系統調用(如 restart_syscall)需要恢復原始參數
#ifdef __AARCH64EB__u32 unused2;s32 syscallno; //在傳統 ARM64 系統調用中,系統調用號通過 X8 寄存器傳遞,但內核可能將其復制到 syscallno 字段。
#elses32 syscallno;u32 unused2;
#endifu64 orig_addr_limit; //保存用戶態進程的地址訪問限制(如 USER_DS)。在內核態執行時臨時擴大地址限制(如 KERNEL_DS),執行完畢后恢復/* Only valid when ARM64_HAS_IRQ_PRIO_MASKING is enabled. */u64 pmr_save; //中斷優先級掩碼保存:僅當啟用 ARM64_HAS_IRQ_PRIO_MASKING 時有效。保存中斷處理前的 PMR 值,處理完成后恢復。u64 stackframe[2]; //父函數的幀指針(FP)。父函數的返回地址(LR)。
};

2.pt_regs有什么用

? ? ? ?通過該結構,當需要進行內核函數hook時,可以簡化對應目標鉤子函數的定義以及接口函數的標準化,避免大量的函數指針來制定具體的函數定義(參數個數和參數類型差別)。從而統一接口類型,使鉤子函數實現簡化執行。例如:

原函類型:

typedef asmlinkage long (*sys_call_file_mkdirat_t)(int dfd, const char __user * pathname, umode_t mode);
static sys_call_file_mkdirat_t old_sys_mkdirat;typedef asmlinkage long (*sys_call_file_unlinkat_t)(int dfd, const char __user * pathname, int flag);
static sys_call_file_unlinkat_t old_sys_unlinkat;

pt_regs:

typedef asmlinkage long (*sys_call_file_t)(const struct pt_regs *);static sys_call_file_t[2];// 統一hook函數接口,具體參數依據實際函數定義從regs結構中按照寄存器位獲取。// 例如
static sys_call_file_t[2]; // 初始化是會將需要hook的函數地址進行存儲處理asmlinkage long mkdir_hook(const struct pt_regs *regs)
{int dfd = regs->di;char *filename = (char *)regs->si;umode_t mode = regs->dx;sys_call_file_t origin_mkdirat = sys_call_file_t[__NR_mkdirat]; //獲取hook后的原函數地址//todo ...return origin_mkdirat(regs); // 原函數}asmlinkage long unlinkat_hook(const struct pt_regs *regs)
{int dfd = regs->di;char *filename = (char *)regs->si;int flag = regs->dx;sys_call_file_t origin_unlinkat = sys_call_file_t[__NR_unlinkat]; //獲取hook后的原函數地址//todo ...return origin_unlinkat(regs); // 原函數
}

3.pt_regs如何使用

例如__NR_write對應32位機器調用內核函數原型如下:

asmlinkage long sys_write(unsigned int fd, const char __user *buf,size_t count);

通過自定義函數結合pt_regs進行hook處理:

asmlinkage long self_write_hook(const struct pt_regs* regs)
{int fd = regs->bx;           // 第一個參數 fd 通過bx 傳遞char *buf = (char *)regs->cx;// 第二個參數 buf 通過ecxsize_t count = regs->dx;     // 第三個參數 count 通過edx// to ...return origin_read(regs); // origin_read為hook時存儲的原始函數地址
}

上述為針對sys_write函數的hook調用時通過regs結構來實現相關參數的獲取處理。

4.實際使用案例

? ? 通過對openat為例子進行hook,具體代碼如下:

my_openat_hook.c:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/unistd.h>
#include <linux/sched.h>
#include <linux/syscalls.h>
#include <linux/string.h>
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/fdtable.h>
#include <linux/uaccess.h>
#include <linux/kallsyms.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
#include <linux/kprobes.h>
#include <linux/fs_struct.h>
#include <linux/mm.h>
#include <linux/delay.h>
#include <linux/namei.h>
#include <asm/syscall.h>
#include <uapi/linux/mount.h>//符號表獲取
typedef unsigned long (*kallsyms_lookup_name_t)(const char *name);
kallsyms_lookup_name_t get_kallsyms_lookup_name(void)
{int ret;kallsyms_lookup_name_t pfun;static struct kprobe kp ={.symbol_name = "kallsyms_lookup_name",};ret = register_kprobe(&kp);if (ret < 0){printk(KERN_INFO "register_kprobe failed, returned %d\n", ret);return NULL;}pfun = (kallsyms_lookup_name_t)kp.addr;unregister_kprobe(&kp);return pfun;
}static int obtain_sys_call_table_addr(unsigned long *sys_call_table_addr)
{unsigned long temp_sys_call_table_addr;kallsyms_lookup_name_t fn_kallsyms_lookup_name = 0;fn_kallsyms_lookup_name = get_kallsyms_lookup_name();if (fn_kallsyms_lookup_name == NULL){printk("Fail to get_allsyms_lookup_name\n");return -1;}temp_sys_call_table_addr = fn_kallsyms_lookup_name("sys_call_table");/* Return error if the symbol doesn't exist */if (0 == temp_sys_call_table_addr){printk("Can not found sys_call_table\n");return -1;}printk("Found sys_call_table: %p", (void *)temp_sys_call_table_addr);*sys_call_table_addr = temp_sys_call_table_addr;return 0;
}static unsigned long sys_call_table_ptr;
typedef asmlinkage long (*self_openat_hook_t)(const struct pt_regs*);
static self_openat_hook_t old_self_openat;
unsigned int disable_cr0(void)
{unsigned int cr0 = 0;unsigned int ret;asm volatile ("movq %%cr0, %%rax": "=a"(cr0));ret = cr0;cr0 &= 0xfffeffff;asm volatile ("movq %%rax, %%cr0"::"a"(cr0));return ret;
}
void enable_cr0(unsigned int val)
{asm volatile ("movq %%rax, %%cr0": : "a"(val));
}asmlinkage long self_openat_hook(const struct pt_regs* regs)
{int dfd = regs->di;char* filename = (char*)regs->si;int flag = regs->dx;umode_t mode = regs->r10;printk(KERN_INFO "dfd = %d,filename = %s,flag = %d,mode = %d",dfd,filename,flag,mode);return old_self_openat(regs);
}static int __init self_init(void) 
{int cr0;obtain_sys_call_table_addr(&sys_call_table_ptr);cr0 = disable_cr0();old_self_openat = (self_openat_hook_t)((unsigned long*)sys_call_table_ptr)[__NR_openat];// 保留舊函數((unsigned long*)sys_call_table_ptr)[__NR_openat] = (unsigned long)self_openat_hook; // 設置新函數enable_cr0(cr0);printk("Success to hook openat func !!!");return 0;
}static void __exit self_exit(void) {int cr0;cr0 = disable_cr0();((unsigned long*)sys_call_table_ptr)[__NR_openat] = old_self_openat;enable_cr0(cr0);printk("Exit to hook openat func !!!");return;
}module_init(self_init)
module_exit(self_exit)
MODULE_LICENSE("GPL");

Makefile:

obj-m := my_openat_hook.oPWD := $(shell pwd)KERNEL_DIR := "/lib/modules/$(shell uname -r)/build"EXTRA_CFLAGS += -I$(src)/includemodules:@$(MAKE) -C $(KERNEL_DIR) M=$(PWD) modulesclean:@rm -rf *.ko *.o *.mod.c *symvers *order .*cmd *cmd

將ko文件寫入到系統:

insmod my_openat.ko,通過dmesg -w查看系統日志:


?以上為使用pt_retgs結構實現的內核函數hook功能案例。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/80275.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/80275.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/80275.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

《從混亂到有序:ArkUI項目文件結構改造指南》

在ArkUI開發的廣袤天地里&#xff0c;構建一個清晰、有序的文件結構&#xff0c;是打造優質應用的關鍵。一個合理的文件結構&#xff0c;就像為開發者精心繪制的地圖&#xff0c;在項目的各個階段&#xff0c;都能提供明確的指引&#xff0c;讓開發過程順暢無阻。今天&#xff…

C#基于Sunnyui框架和MVC模式實現用戶登錄管理

C#基于Sunnyui框架和MVC模式實現用戶登錄管理 1 Controller1.1 UserManagementController.cs&#xff08;控制器入口&#xff09; 2 Model2.1 UserRepository.cs&#xff08;用戶管理模型&#xff09;2.2 User.cs&#xff08;用戶結構體&#xff09;2.3 SQLiteHelper.cs&#x…

自然語言處理(NLP)技術的實例

自然語言處理&#xff08;NLP&#xff09;技術在各個領域都有廣泛的應用&#xff0c;以下是幾個例子&#xff1a; 語音識別&#xff1a;通過NLP技術&#xff0c;計算機可以識別和理解語音指令&#xff0c;例如智能助手如Siri和Alexa就是通過語音識別技術實現與用戶的交互。 機…

Spring Boot實戰(三十六)編寫單元測試

目錄 一、什么是單元測試&#xff1f;二、Spring Boot 中的單元測試依賴三、舉例 Spring Boot 中不同層次的單元測試3.1 Service層3.2 Controller 層3.3 Repository層 四、Spring Boot 中 Mock、Spy 對象的使用4.1 使用Mock對象的背景4.2 什么是Mock對象&#xff0c;有哪些好處…

aws服務(四)文件存儲服務S3 介紹使用代碼集成

一、介紹 1、簡介 Amazon S3 是 Amazon Web Services 提供的一種對象存儲服務(Object Storage),用于在云中存儲和檢索任意數量的數據。它以高可用性、高擴展性和高持久性著稱,非常適合用來存儲網站資源、數據備份、日志文件、大數據、機器學習輸入輸出等。 2、主要特性 …

應用信息1.13.0發布

增加工具箱 增加啟動器功能 增加布局查看器 增加手動安裝和卸載應用 增加APK文件解析 增加應用多選功能 增加查看應用預裝版本 增加應用信息和ADB命令導出 修復其它問題... 百度下載&#xff1a;百度網盤 請輸入提取碼 提取碼&#xff1a;1234

【Vue3 實戰】插槽封裝與懶加載

一、為什么需要插槽&#xff1f;從一個面板組件說起 在電商首頁開發中&#xff0c;經常遇到這樣的場景&#xff1a; 「新鮮好物」「人氣推薦」同樣類型模塊都需要相同的標題欄&#xff0c;但內容區布局不同 這時候&#xff0c;插槽&#xff08;Slot&#xff09;就像一個「內容…

虛無隧穿產生宇宙(true nothing tunneling) 是誰提出的

是 亞歷克斯.維連金 英文名&#xff08;alex vilenkin 或者 Alexander Vilenkin)提出來的。 “虛無隧穿產生宇宙”&#xff08;true nothing tunneling&#xff09;這一概念并非一個標準的物理學術語&#xff0c;它更像是對某些現代宇宙學理論的描述&#xff0c;尤其是涉及宇宙…

postgis:添加索引時提示“對訪問方法 gist 數據類型 geometry 沒有默認的操作符表“

問題 在對gis表的geom字段創建空間索引時&#xff0c;出現“對訪問方法 "gist" 數據類型 geometry 沒有默認的操作符表”的提示報錯。 解決方案 按系列步驟進行排查并解決。 1.先確認已安裝postgis -- 查看postgis版本 SELECT postgis_full_version() 若安裝了則…

圖論---Prim堆優化(稀疏圖)

題目通常會提示數據范圍&#xff1a; 若 V ≤ 500&#xff0c;兩種方法均可&#xff08;樸素Prim更穩&#xff09;。 若 V ≤ 1e5&#xff0c;必須用優先隊列Prim vector 存圖。 #include <iostream> #include <vector> #include <queue> #include <…

代碼隨想錄算法訓練營第一天:數組part1

今日學習的文章鏈接和視頻鏈接 ● 自己看到題目的第一想法 ● 看完代碼隨想錄之后的想法 ● 自己實現過程中遇到哪些困難 ● 今日收獲&#xff0c;記錄一下自己的學習時長 狀態 思路理解完成 30% 代碼debug完成 60% 代碼模板總結并抽象出來 100% 題目 704 二分查找 題目鏈接…

企業為何要求禁用缺省口令?安全風險及應對措施分析

在當今數字化時代&#xff0c;企業網絡安全面臨著前所未有的挑戰。缺省口令的使用是網絡安全中的一個重要隱患&#xff0c;許多企業在制定網絡安全紅線時&#xff0c;明確要求禁用缺省口令。本文將探討這一要求的原因及其對企業安全的重要性。 引言&#xff1a;一個真實的入侵場…

PostgreSQL 中的權限視圖

PostgreSQL 中的權限視圖 PostgreSQL 提供了多個系統視圖來查詢權限信息&#xff0c;雖然不像 Oracle 的 DBA_SYS_PRIVS 那樣集中在一個視圖中&#xff0c;但可以通過組合以下視圖獲取完整的系統權限信息。 一 主要權限相關視圖 Oracle 視圖PostgreSQL 對應視圖描述DBA_SYS_…

【防火墻 pfsense】1簡介

&#xff08;1&#xff09; pfSense 有以下可能的用途&#xff1a; 邊界防火墻 路由器 交換機 無線路由器 / 無線接入點 &#xff08;2&#xff09;邊界防火墻 ->要充當邊界防火墻&#xff0c;pfSense 系統至少需要兩個接口&#xff1a;一個廣域網&#xff08;WAN&#xff0…

數據庫+Docker+SSH三合一!深度評測HexHub的全棧開發體驗

作為一名技術博主&#xff0c;我最近一直被各種開發工具切換搞得焦頭爛額。數據庫要用Navicat&#xff0c;服務器管理得開Termius&#xff0c;Docker操作還得切到命令行&#xff0c;每天光在不同工具間切換就浪費了大量時間。直到團隊里的一位架構師向我推薦了HexHub這個一體化…

第十天 Shader編程:編寫簡單表面著色器 Addressable資源管理系統 DOTS(面向數據技術棧)入門

前言 作為Unity初學者&#xff0c;在實現復雜場景時經常會遇到性能瓶頸。本文將帶你通過四個關鍵技術的實戰學習&#xff0c;掌握現代Unity開發的核心優化方案&#xff1a; Shader編程 - 編寫表面著色器控制物體渲染Addressable系統 - 實現高效資源管理DOTS技術棧 - 解鎖百萬…

項目自動化測試

一.設計測試用例(細致全面) 二.先引入所需要的pom.xml依賴 1.selenium依賴 2.webdrivermanager依賴 3.commons-io依賴 編寫測試用例–按照頁面對用例進行劃分,每個頁面是Java文件,頁面下的所有用例統一管理 三.common包(放入公用包) 類1utils 可以調用driver對象,訪問url …

ap無法上線問題定位(交換機發包沒有剝掉pvid tag)

一中學&#xff0c;新開的40臺appoe交換機核心交換機旁掛ac出口路由的組網&#xff0c;反饋ap無法上線&#xff0c;讓協助解決。 組網如下&#xff1a; 排查過程&#xff1a; 檢查ac的配置&#xff0c;沒有發現問題 發現配置沒有問題&#xff0c;vlan1000配置子接口&#xff…

第十七屆山東省職業院校技能大賽 中職組網絡建設與運維賽項

第十七屆山東省職業院校技能大賽 中職組網絡建設與運維賽項 賽題 B 卷 第十七屆山東省職業院校技能大賽中職組網絡建設與運維賽項 1 賽題說明 一、競賽項目簡介 “網絡建設與運維”競賽共分為以下三個模塊&#xff1a; ? 網絡理論測試&#xff1b; ? 網絡建設與調試&#xf…

關于QT信號、槽、槽函數的講解

也是好久沒有發帖子了&#xff0c;最近博主主要還是在邊學QT邊完成任務&#xff0c;所以進度很慢&#xff0c;但確實在這幾天對于QT自身槽和信號這類特殊的機制有了一定簡單的理解&#xff0c;所以還是想記錄下來&#xff0c;如果有初學者看到帖子對他有一定的幫助&#xff0c;…