日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

導(dǎo)語

• linux下的Hook方式,從ring3到ring0,姿勢很多,但其實(shí)是互通的,這里總結(jié)自己實(shí)現(xiàn)的幾個。

/****** Ring3 ******/
LD_PRELOAD劫持.so
ptrace API調(diào)試技術(shù)Hook
PLT劫持
/******* Ring 0 *******/
針對系統(tǒng)調(diào)用的hook
--首先獲得sys_call_table
利用sys函數(shù)的嵌套實(shí)現(xiàn)hook調(diào)用的子函數(shù)
修改系統(tǒng)調(diào)用的前幾個字節(jié)為jmp之類的指令(內(nèi)聯(lián)

• 網(wǎng)上很多教程是針對Linux2.6左右的,很多方法需要自己重新摸索,記錄踩坑。

– 注: 以下所有代碼在Linux 5.0.3. x86_64內(nèi)核調(diào)試通過。

LD_PRELOAD劫持.so

• LDPRELOAD是一個Linux下的動態(tài)鏈接的程序的環(huán)境變量,幾乎我們用到的函數(shù)實(shí)現(xiàn)來自于glibc,.so文件是glibc編譯得到的庫,類似于Win下的DLL。而LDPRELOAD變量優(yōu)先于相關(guān)配置指定鏈接到哪個.so文件。

• 一旦我們可以控制該變量,也就可以決定程序調(diào)用函數(shù)時會做什么。

• 實(shí)例展示

– 目標(biāo)文件target.c

#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
if( strcmp(argv[1], "password") )
{
printf("Incorrect passwordn");
}
else
{
printf("Correct passwordn");
}
return 0;
}
//gcc target.c -o target

– 偽造的.so文件preload.c

#include <stdio.h>
#include <string.h>
#include <dlfcn.h>
typedef int(*Strcmp)(const char*, const char*);
int strcmp(const char* s1, const char* s2)
{
static void* handle = NULL;
static Strcmp org_strcmp = NULL;
if(!handle)
{ //解析得到真實(shí)的strcmp函數(shù)
handle = dlopen("libc.so.6", RTLD_LAZY);
org_strcmp = (Strcmp)dlsym(handle, "strcmp");
}
//做我們想做的
printf("Hacked by way of ld_preloadnnn");
//完成真實(shí)的功能
return org_strcmp(s1, s2);
}
//gcc -fPIC preload.c -shared -o preload.so -ldl

• 這種方式比較簡單,前提是程序不是靜態(tài)鏈接的。(不會再解析.so,程序已經(jīng)包含了庫函數(shù)的實(shí)現(xiàn))。

• 防護(hù)方案

– 關(guān)閉LD_PRELOAD

ptrace API調(diào)試技術(shù)Hook

• ptrace是很多Linux平臺下調(diào)試器實(shí)現(xiàn)的基礎(chǔ),包括syscall跟蹤程序strace。

• ptrace可以實(shí)現(xiàn)調(diào)試程序、跟蹤;但是一個進(jìn)程只能被一個進(jìn)程跟蹤。所以無法在gdb或者其他程序調(diào)試的時候去ptrace一個程序,同樣也無法在ptrace一個進(jìn)程的時候,再去gdb調(diào)試。后者經(jīng)常作為一個簡單的反調(diào)試手段。

• 而且Linux下的攻防中,ptrace也由于自己的特殊性,常常是必爭之地。

• 總體思路

ptrace attach目標(biāo)進(jìn)程
保存rip
控制跳轉(zhuǎn)到mmap分配一段rwx內(nèi)存
將一段機(jī)器碼copy進(jìn)去
控制跳轉(zhuǎn)到機(jī)器碼(可以以bin文件的形式)
恢復(fù)執(zhí)行。

• 簡單示例代碼

– 首先需要知道一些函數(shù)在目標(biāo)進(jìn)程的地址,下面是已知pid獲取libc基地址(讀取/proc/pid/maps),和函數(shù)地址(dlsym)

size_t getLibcbase(int pid)
{
size_t libcAddr;
char* buf;
char* end;
char* mapfile[0x18];
sprintf(mapfile, Mapfile, pid);
FILE* fd = fopen(mapfile, "r");
if(!fd)
{
printf("open maps error!");
exit(1);
}
//search the libc-.....
buf = (char*) malloc(0x100);
do{
fgets(buf, 0x100, fd);
} while(!strstr(buf, "libc-"));
end = strchr(buf, '-');
libcAddr = strtol(buf, &end, 16);
printf("The process %d's libcbase is: 0x%lxn", pid, libcAddr);
fclose(fd);
return libcAddr;
}
size_t getFuncAddr(int pid, char* funcName)
{
size_t funcAddr;
char* buf;
char* end;
char* mapfile[0x18];
sprintf(mapfile, Mapfile, pid);
//get function offset from self process, the shared libc.so
funcAddr = (size_t)dlsym(0, funcName);
funcAddr -= getLibcbase(getpid());
funcAddr += libc_addr;
printf("function %s address is: 0x%lxn", funcName, funcAddr);
return funcAddr;
}

– main代碼

• 為了得到存放shellcode的地址,我們需要先執(zhí)行mmap,而執(zhí)行mmap也需要一段可執(zhí)行地址。這里其實(shí)我們可以直接使用libcbase。在libcbase處寫入下面的opcode,其中int 0x3是為了發(fā)出信號,讓我們知道該opcode執(zhí)行完成。

call rax
int 0x3
;"\xff\xd0\xcd\x03"

• 實(shí)現(xiàn)mmap調(diào)用

– 備份數(shù)據(jù),寫入opcode,設(shè)置mmap參數(shù)

//save a bak of regs
ptrace(PTRACE_GETREGS, traced, 0, ®s_bak);
memcpy(®s, ®s_bak, sizeof(struct user_regs_struct));
//use libc_base to write our short hook code
buf.val = ptrace(PTRACE_PEEKTEXT, traced, libc_addr, 0);
hook_bak.val = buf.val;
memcpy(buf.chars, Call, 4);
ptrace(PTRACE_POKETEXT, traced, libc_addr, buf.val);
fd = open(argv[2], O_RDONLY);
fstat(fd, &sb);
if(fd < 0)
{
printf("open shellcode error!n");
exit(1);
}
shellcode = malloc(sb.st_size + 1);
read(fd, shellcode, sb.st_size);
regs.rax = mmap_addr;
//prepare for the mmap args
regs.rdi = 0;
regs.rsi = sb.st_size;
regs.rdx = 0x7;
regs.rcx = MAP_PRIVATE | MAP_ANONYMOUS;
regs.r8 = -1;
regs.r9 = 0;
regs.rip = libc_addr; //jmp to call rax
ptrace(PTRACE_SETREGS, traced, 0, ®s);
ptrace(PTRACE_CONT, traced, 0, 0);
//wait mmap is executed
waitpid(traced, &status, WUNTRACED);
if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP){
printf("SIGTRAP receivednn");
}

• 這里有幾個坑

– mmap的fd參數(shù),必須是open打開的返回值,而不能是fopen這種。

– x64傳參,順序是rdi、rsi、rdx、rcx、r8、r9;有些地方可能會說第四個參數(shù)是r10,發(fā)現(xiàn)有誤導(dǎo)。

void *mmap(void *addr, size_t length, int prot, int flags,
int fd, off_t offset);

– 由于我們open是在注入進(jìn)程得到的fd,而mmap是在被hook進(jìn)程執(zhí)行的,所以這個fd是不可以被當(dāng)作參數(shù)的。我們必須使用flag MAPPRIVATE | MAPANONYMOUS

• 往mmap返回的地址里寫入shellcode,并執(zhí)行。

ptrace(PTRACE_GETREGS, traced, 0, ®s);
tmp_addr = regs.rax;/
printf("We get address from mmap: 0x%lxn", tmp_addr);
copy_code(tmp_addr, shellcode, sb.st_size);
tmp_val = ptrace(PTRACE_PEEKTEXT, traced, tmp_addr, 0);
printf("the mApped val: 0x%lxn", tmp_val);
//jmp to shellcode from file
regs.rip = tmp_addr;
ptrace(PTRACE_SETREGS, traced, 0, ®s);
ptrace(PTRACE_CONT, traced, 0, 0);
//wait shellcode is executed
waitpid(traced, &status, WUNTRACED);
if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP){
printf("SIGTRAP receivednn");
}
ptrace(PTRACE_SETREGS, traced, 0, ®s_bak);
ptrace(PTRACE_CONT, traced, 0, 0);
close(fd);

– 其中copy_code的實(shí)現(xiàn)通過POKETEXT,每次可以向目標(biāo)進(jìn)程任意地址寫入long大小的值

void copy_code(size_t addr, char* shellcode, int len)
{
int i=0;
long word;
for(i=0; i<len; i+=sizeof(long)){
memcpy(&word, shellcode+i, sizeof(long));
if(ptrace(PTRACE_POKETEXT, traced, addr+i, word) == -1){
printerror();
exit(1);
}
}
}

• 我的shellcode,就是write(1, 'cba', 8),目標(biāo)進(jìn)程就是當(dāng)前終端/bin/bash看下效果。

黑客大神秘籍:Linux下Hook方式匯總

 

PLT重定向劫持Hook

• 這個主要是利用ELF文件的,GOT和PLT的方式解決地址無關(guān)的鏈接.so文件的機(jī)制。

• 在第一次調(diào)用前,Got里是PLT的地址;一般在調(diào)用之后Got里會寫入庫函數(shù)的真實(shí)地址。

• PLT在text段,一般不可寫;(所以迷,為啥有這一技術(shù))

– 是因?yàn)?strong>ptrace可以無視'rwx',這也是為什么gdb可以修改text,下斷點(diǎn)。

– 所以這個來說,算是plt和ptrace結(jié)合的一種方式。

• 一個簡單的在PLT處下斷,執(zhí)行完操作后恢復(fù)的樣例。這里主要解決的是代碼重定位的問題,我們從/proc/pid/maps下讀出Codebase即可。

#include <sys/reg.h>
#include <sys/ptrace.h>
#include <sys/user.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#define Mapfile "/proc/%d/maps"
//用于獲取plt內(nèi)容
union pltval{
size_t val;
unsigned char chars[sizeof(size_t)];
};
void usage(char** argv){
printf("USAGE: n --- %s pid plt_offset n", argv[0]);
}
void printerror(){
printf("Status: %sn", strerror(errno));
}
void mod_handle(pid_t tracee, void* addr1, void* addr2)
{
union pltval buf;
buf.val = ptrace(PTRACE_PEEKDATA, tracee, addr1, 0);
printf("mod_handle: ");
printerror();
memcpy(buf.chars, "hooked", 6);
buf.chars[6] = 0;
ptrace(PTRACE_POKEDATA, tracee, addr1, buf.val);
printf("hook: ");
printerror();
buf.val = ptrace(PTRACE_PEEKDATA, tracee, addr2, 0);
printf("mod_handle: ");
printerror();
memcpy(buf.chars, "/hooked", 7);
buf.chars[7] = 0;
ptrace(PTRACE_POKEDATA, tracee, addr2, buf.val);
printf("/hooked: ");
printerror();
}
size_t getCodebase(pid_t pid)
{
size_t addr;
char buf[2 * sizeof(size_t)];
char* end;
char* mapfile[0x18];
sprintf(mapfile, Mapfile, pid);
int fd = open(mapfile, O_RDONLY);
if(fd == -1)
{
printf("open maps error!");
exit(1);
}
read(fd, buf, 2 * sizeof(size_t));
end = strchr(buf, '-');
addr = strtol(buf, &end, 16);
printf("The codebase is: 0x%lxn", addr);
close(fd);
return addr;
}
int main(int argc, char* argv[]){
pid_t tracee;
union pltval plt;
struct user_regs_struct regs;
siginfo_t si;
int status;
size_t plt_offset, plt_addr, bak;
if(argc < 2){
usage(argv);
exit(1);
}
tracee = atoi(argv[1]);
plt_offset = atoi(argv[2]);
//獲取codebase
plt_addr = plt_offset + getCodebase(tracee);
printf("plt_addr ==> %lxn", plt_addr);
//attach the process
ptrace(PTRACE_ATTACH, tracee, 0, 0);
printf("Attach: ");
printerror();
wait(&status);
//獲取目標(biāo)的plt值,保存,修改,寫入, 繼續(xù)運(yùn)行
plt.val = ptrace(PTRACE_PEEKDATA, tracee, plt_addr, 0);
bak = plt.val;
plt.chars[0] = 0xcc; //breakpoint
ptrace(PTRACE_POKEDATA, tracee, plt_addr, plt.val);
ptrace(PTRACE_CONT, tracee, 0, 0);
//監(jiān)視有沒有觸發(fā)斷點(diǎn)
while(1){
printf("Wait....n");
wait(&status);
printf("Done!n");
if(WIFEXITED(status)) break;
//獲取regs和sig信息,判斷是否到達(dá)plt
ptrace(PTRACE_GETSIGINFO, tracee, 0, &si);
ptrace(PTRACE_GETREGS, tracee, 0, ®s);
if((si.si_signo != SIGTRAP) || (regs.rip != (size_t)plt_addr + 1)){
ptrace(PTRACE_GETREGS, tracee, 0, ®s);
ptrace(PTRACE_CONT, tracee, 0, 0);
continue;
}
//hook & modify
mod_handle(tracee, (void*)argv[0], (void*)argv[1]);
//修改回原值
plt.val = bak;
ptrace(PTRACE_POKEDATA, tracee, plt_addr, plt.val);
//返回0xcc前
regs.rip -= 1;
ptrace(PTRACE_SETREGS, tracee, 0, ®s);
ptrace(PTRACE_SINGLESTEP, tracee, 0, 0);
wait(0);
ptrace(PTRACE_GETREGS, tracee, 0, ®s);
plt.chars[0] = 0xcc;
ptrace(PTRACE_POKEDATA, tracee, plt_addr, plt.val);
ptrace(PTRACE_CONT, tracee, 0, 0);
}
return 0;
}

Ring0級別的Hook

前置知識

• linux內(nèi)核的編譯

– 最好選擇一個和自己虛擬機(jī)內(nèi)核版本一致的源碼,網(wǎng)上也很多教程。

– 再編譯一個busybox的文件系統(tǒng),為了方便添加文件。

• 模塊編譯

– makefile的基本格式(用于本機(jī)加載的模塊)

obj-m += inter.o
CURRENT_PATH := $(shell pwd)
LINUX_KERNEL := $(shell uname -r)
LINUX_KERNEL_PATH := /usr/src/linux-headers-$(LINUX_KERNEL)
all:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
clean:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean

– 交叉編譯(本機(jī)和編譯的內(nèi)核不同)

obj-m += mod1.o
CURRENT_PATH := $(shell pwd)
LINUX_KERNEL := $(shell uname -r)
LINUX_KERNEL_PATH := /home/tree/kernel/linux-5.0.3
all:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
clean:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean

• syscalltable

– 都知道linux通過int 0x80或者syscall都可以進(jìn)入kernel完成系統(tǒng)調(diào)用,而我們需要把對應(yīng)的系統(tǒng)調(diào)用號傳給rax。兩者最終還是用了system_call。

– int 0x80工作原理

1、系統(tǒng)維護(hù)一個叫做“向量中斷表的”,每個int xx都會去對應(yīng)的向量表的xx處
2、0x80對應(yīng)系統(tǒng)調(diào)用的服務(wù)例程,記錄了syscall的地址。
3、而eax的值,對應(yīng)具體的系統(tǒng)調(diào)用號。

– syscall的具體實(shí)現(xiàn),可以看到這里有syscalltable符號。

.globl system_call, buserr, trap, resume
.globl sys_call_table
................
................
ENTRY(system_call)
SAVE_ALL_SYS //保存
GET_CURRENT(%d1)
movel %d1,%a1
| save top of frame
movel %sp,%curptr@(TASK_THREAD+THREAD_ESP0)
| syscall trace? //有沒有被ptrace跟蹤
tstb %a1@(TINFO_FLAGS+2)
jmi do_trace_entry
cmpl #NR_syscalls,%d0
jcc badsys
syscall: //真實(shí)的執(zhí)行系統(tǒng)調(diào)用
jbsr @(sys_call_table,%d0:l:4)@(0)
movel %d0,%sp@(PT_OFF_D0) | save the return value
ret_from_syscall:
|oriw #0x0700,%sr
movel %curptr@(TASK_STACK),%a1
movew %a1@(TINFO_FLAGS+2),%d0
jne syscall_exit_work
1: RESTORE_ALL

• 獲得syscalltable地址的方式

– 由于syscall實(shí)現(xiàn)處有syscalltable的符號,我們可以從這里拿到地址。

1. 獲取中斷描述符表(IDT)的地址(使用C ASM匯編)
2. 從中查找0x80中斷(系統(tǒng)調(diào)用中斷)的服務(wù)例程(8*0x80偏移)
3. 搜索該例程的內(nèi)存空間
4. 從其中獲取sys_call_table(保存所有系統(tǒng)調(diào)用例程的入口地址)的地址

– 使用kallsymslookupname讀取。該函數(shù)本身也是一個符號,如果沒有導(dǎo)出就不能使用。

sys_call_table_addr = kallsyms_lookup_name("sys_call_table")

– 讀取/proc/kallsyms文件。我的理解就是和/proc/pid/maps差不多特殊的一個文件,由內(nèi)核動態(tài)生成,需要root權(quán)限,普通用戶讀到的全是0(但是加載模塊也是需要root權(quán)限的,所以不是問題)

sudo cat /proc/kallsyms | grep sys_call_table

– 修改內(nèi)核,添加EXPORTSYMBOL(syscalltable)或EXPORTSYMBOLGPL(syscall_table)。
這種方法適用于可以修改內(nèi)核的情形。在可以修改內(nèi)核的情況下,這是最簡單的方式。

• 實(shí)戰(zhàn)——hook系統(tǒng)調(diào)用 mkdir,我這里使用kallsymslookupname

//This kernel module locates the sys_call_table by kallsyms_lookup_name
#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/fdtable.h>
#include<linux/uaccess.h>
#include <linux/kallsyms.h>
#include<linux/rtc.h>
#include<linux/vmalloc.h>
#include <linux/slab.h>
//module macros
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("hook sys_mkdir");
//module constructor/destructor
typedef unsigned long (*sys_call_ptr_t)(void);
sys_call_ptr_t *_sys_call_table = NULL;
typedef asmlinkage long (*old_mkdir_t)(const char __user *pathname, umode_t mode);
old_mkdir_t old_mkdir = NULL;
// hooked mkdir function
asmlinkage long hooked_mkdir(const char __user *pathname, umode_t mode) {
printk("hooked sys_mkdir(), mkdir name: ");
printk(pathname);
old_mkdir(pathname, mode);
}
// memory protection shinanigans
unsigned int level;
pte_t *pte;
//obtain sys_call_table
static int get_sys_call_table(void){
unsigned long tmp_sys_call_table = 0;
int ans = 0;
tmp_sys_call_table = kallsyms_lookup_name("sys_call_table");
if(tmp_sys_call_table != 0)
{
ans = 1;
_sys_call_table = tmp_sys_call_table;
printk("[+] find sys_call_table: 0x%lxn", tmp_sys_call_table);
}
return ans;
}
// initialize the module
static int hooked_init(void) {
printk("+ Loading hook_mkdir modulen");
if(!get_sys_call_table()){
return 0;
}
// now we can hook syscalls ...such as uname
// first, save the old gate (fptr)
old_mkdir = (old_mkdir_t) _sys_call_table[__NR_mkdir];
// unprotect sys_call_table memory page
pte = lookup_address((unsigned long) _sys_call_table, &level);
// change PTE to allow writing
set_pte_atomic(pte, pte_mkwrite(*pte));
printk("+ unprotected kernel memory page containing sys_call_tablen");
// now overwrite the __NR_uname entry with address to our uname
_sys_call_table[__NR_mkdir] = (sys_call_ptr_t) hooked_mkdir;
printk("+ sys_mkdir hooked!n");
return 0;
}
static void hooked_exit(void) {
if(old_mkdir != NULL) {
// restore sys_call_table to original state
_sys_call_table[__NR_mkdir] = (sys_call_ptr_t) old_mkdir;
// reprotect page
set_pte_atomic(pte, pte_clear_flags(*pte, _PAGE_RW));
}
printk("+ Unloading hook_mkdir modulen");
}
/*entry/exit macros*/
module_init(hooked_init);
module_exit(hooked_exit);

– 效果(不知道為啥pathname參數(shù)不能輸出)

黑客大神秘籍:Linux下Hook方式匯總

 

• systemcall函數(shù)內(nèi)存內(nèi)搜索syscall_table,實(shí)現(xiàn)execve的hook

– 這里注意這種方式在x86和x64上的區(qū)別。

1、x86或者x64的兼容模式:使用int 0x80,MSR寄存器地址為0xc0000083,宏MSR_CSTAR來代表. 使用sidt獲取system_call地址
2、x64的long模式:使用syscall,MSR寄存器地址為0xc0000082,宏MSR_LSTAR來代表. 使用rdmsrl指令獲取system_call地址
3、x86 sys_call_table的特征碼 \xff\x14\x85
4、x86_64下 sys_call_table的特征碼 \xff\x14\xc5

– 網(wǎng)上有一大堆x86的獲取syscalltable的方法,我本來打算用下面的思路實(shí)現(xiàn)一個x64的。

1、在x64下,通過rdmsrl(MSR_LSTAR, xxxx)可以拿到entry_SYSCALL_64的地址。entry_SYSCALL_64的實(shí)現(xiàn)里會有sys_call_table的機(jī)器碼。
2、所以有兩種hook的思路
a、修改entry_SYSCALL_64起始的幾個字節(jié)(內(nèi)聯(lián)hook)
b、找到sys_call_table,修改對應(yīng)的系統(tǒng)調(diào)用。

– 但是在linux內(nèi)核5.x里,entrySYSCALL64的實(shí)現(xiàn)改了,不再試圖用過call syscalltable[index]的方式進(jìn)行系統(tǒng)調(diào)用,而是引入了一個dosyscall64的符號。具體的看下面截取的源碼

ENTRY(entry_SYSCALL_64)
UNWIND_HINT_EMPTY
.......
.......
/* IRQs are off. */
movq %rax, %rdi
movq %rsp, %rsi
call do_syscall_64 /* returns with IRQs disabled */

– 于是我找到了dosyscall64的實(shí)現(xiàn),幸運(yùn)的是在這里找到了對syscalltable的直接引用。

#ifdef CONFIG_X86_64
__visible void do_syscall_64(unsigned long nr, struct pt_regs *regs)
{
struct thread_info *ti;
enter_from_user_mode();
local_irq_enable();
ti = current_thread_info();
if (READ_ONCE(ti->flags) & _TIF_WORK_SYSCALL_ENTRY)
nr = syscall_trace_enter(regs);
/*
* NB: Native and x32 syscalls are dispatched from the same
* table. The only functional difference is the x32 bit in
* regs->orig_ax, which changes the behavior of some syscalls.
*/
nr &= __SYSCALL_MASK;
if (likely(nr < NR_syscalls)) {
nr = array_index_nospec(nr, NR_syscalls);
regs->ax = sys_call_table[nr](regs); //這里sys_call_table的直接引用
}
syscall_return_slowpath(regs);
}
#endif

– 所以,顯然我們就需要多一次的搜索,特征碼可以在gdb里查或者看它的匯編指令。

1、在entry_SYSCALL_64里搜索do_syscall_64; 特征碼'\x48\x89\xe6\xe8' <= mov rsi, rsp; call ....
2、在do_syscall_64里搜索sys_call_table; 特征碼 '\x48\x8b\x04\xfd' <= mov rax []

– 通過entrySYSCALL64的call dosyscall64找到call dosyscall64地址

 

黑客大神秘籍:Linux下Hook方式匯總

 

– 通過dosyscall64對syscalltable的引用找到syscalltable

 

黑客大神秘籍:Linux下Hook方式匯總

 

– 代碼實(shí)現(xiàn)

static void*
get_lstar_dosys_addr(void){
unsigned long lstar;
// temp variables for scan
unsigned int i;
unsigned char *off;
rdmsrl(MSR_LSTAR, lstar);
// print out int 0x80 handler
printk("[+] entry_SYSCALL_64 is at 0x%lxn", lstar);
// scan for known pattern(0xff14c5xx)
// pattern is just before sys_call_table address
for(i = 0; i <= PAGE_SIZE; i++) {
off = (char*)lstar + i;
if(*(off) == 0x48 && *(off+1) == 0x89 && *(off+2) == 0xe6) {
return (off + 3); //call do_syscall_64
}
}
return NULL;
}
static void*
get_lstar_dosys(void)
{
unsigned long* lstar_dosys_addr = get_lstar_dosys_addr();
if(lstar_dosys_addr != NULL) {
printk("[+] call_do_syscall_64 at: 0x%lxn", lstar_dosys_addr);
unsigned int offset = *(unsigned int*)((char*)lstar_dosys_addr + 1);
printk("[+] offset is: 0x%08xn", offset);
unsigned long base = 0xffffffff00000000;
return (void*)(base | ((unsigned long)lstar_dosys_addr + 5 + offset));
}
return NULL;
}
static void*
get_sys_sct_addr(unsigned long* do_syscall_64_addr)
{
unsigned char* off;
int i;
for(i = 0; i <= PAGE_SIZE; i++) {
off = (char*)do_syscall_64_addr + i;
if(*(off) == 0x48 && *(off+1) == 0x8b && *(off+2) == 0x04 && *(off+3) == 0xfd) {
return (off+4);
}
}
return NULL;
}
static void*
get_sys_sct(unsigned long* do_syscall_64_addr)
{
unsigned long* sct_addr = get_sys_sct_addr(do_syscall_64_addr);
if(!sct_addr){
return NULL;
}
unsigned int offset = *(unsigned int*)(sct_addr);
unsigned long base = 0xffffffff00000000;
return (void*)(base | offset);
}
//hooked execve
static int hook_execve_init(void){
printk("[+] Finding sys_call_tablen");
unsigned long* do_syscall_64_addr = 0;
do_syscall_64_addr = get_lstar_dosys();
if(!do_syscall_64_addr){
printk("[x] Failed to find do_syscall_64_addrn");
return 0;
}
printk("[+] Found do_syscall_64_addr at: 0x%lxn", do_syscall_64_addr);
_sys_call_table = get_sys_sct(do_syscall_64_addr);
if(!_sys_call_table) {
printk("[x] Failed to find sys_call_tablen");
return 0;
}
printk("[+] Found sys_call_table at: 0x%lxn", _sys_call_table);
return 0;
}

– 注意處理一些細(xì)節(jié)問題(比如unsigned long 還是 unsinged int),最終可以達(dá)到想要的效果。

 

黑客大神秘籍:Linux下Hook方式匯總

 

原文地址:https://xz.aliyun.com/t/6961

分享到:
標(biāo)簽:方式 Hook
用戶無頭像

網(wǎng)友整理

注冊時間:

網(wǎng)站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運(yùn)動步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績評定2018-06-03

通用課目體育訓(xùn)練成績評定