@ -3,151 +3,200 @@
static khook_stub_t * khook_stub_tbl = NULL ;
////////////////////////////////////////////////////////////////////////////////
/*
* 内 核 符 号 表 查 找 函 数 callback function
* 通 过 遍 历 data 数 组 中 的 元 素 , 并 与 name 字 符 串 进 行 比 较
* 如 果 找 到 匹 配 的 元 素 , 则 将 data 数 组 的 第 二 个 元 素 设 置 为 addr , 并 返 回 1
* 如 果 遍 历 完 整 个 数 组 仍 然 没 有 找 到 匹 配 的 元 素 , 则 返 回 0
*/
static int khook_lookup_cb ( long data [ ] , const char * name , void * module , long addr )
{
int i = 0 ; while ( ! module & & ( ( ( const char * ) data [ 0 ] ) ) [ i ] = = name [ i ] ) {
if ( ! name [ i + + ] ) return ! ! ( data [ 1 ] = addr ) ;
} return 0 ;
int i = 0 ;
while ( ! module & & ( ( ( const char * ) data [ 0 ] ) ) [ i ] = = name [ i ] ) {
if ( ! name [ i + + ] ) return ! ! ( data [ 1 ] = addr ) ; // 找到匹配的符号, 设置地址并返回1
}
return 0 ; // 未找到匹配的符号, 返回0
}
/*
* 利 用 kallsyms_on_each_symbol 可 以 查 询 符 号 表 , 只 需 要 传 入 查 询 函 数 就 可 以 了
* data [ 0 ] 表 示 要 查 询 的 地 址
* data [ 1 ] 表 示 结 果
* kernel all symbols 内 核 符 号 表
*/
static void * khook_lookup_name ( const char * name )
{
long data [ 2 ] = { ( long ) name , 0 } ;
kallsyms_on_each_symbol ( ( void * ) khook_lookup_cb , data ) ;
return ( void * ) data [ 1 ] ;
long data [ 2 ] = { ( long ) name , 0 } ;
kallsyms_on_each_symbol ( ( void * ) khook_lookup_cb , data ) ;
return ( void * ) data [ 1 ] ; // 返回找到的符号地址
}
/*
* 将 一 个 虚 拟 地 址 范 围 [ addr , addr + len ] 映 射 到 可 写 内 核 内 存 区 域
*/
static void * khook_map_writable ( void * addr , size_t len )
{
struct page * pages [ 2 ] = { 0 } ; // len << PAGE_SIZE
long page_offset = offset_in_page ( addr ) ;
int i , nb_pages = DIV_ROUND_UP ( page_offset + len , PAGE_SIZE ) ;
addr = ( void * ) ( ( long ) addr & PAGE_MASK ) ;
for ( i = 0 ; i < nb_pages ; i + + , addr + = PAGE_SIZE ) {
if ( ( pages [ i ] = is_vmalloc_addr ( addr ) ?
vmalloc_to_page ( addr ) : virt_to_page ( addr ) ) = = NULL )
return NULL ;
}
addr = vmap ( pages , nb_pages , VM_MAP , PAGE_KERNEL ) ;
return addr ? addr + page_offset : NULL ;
struct page * pages [ 2 ] = { 0 } ; // len << PAGE_SIZE
long page_offset = offset_in_page ( addr ) ;
int i , nb_pages = DIV_ROUND_UP ( page_offset + len , PAGE_SIZE ) ;
addr = ( void * ) ( ( long ) addr & PAGE_MASK ) ; // 对齐地址到页面边界
for ( i = 0 ; i < nb_pages ; i + + , addr + = PAGE_SIZE ) {
if ( ( pages [ i ] = is_vmalloc_addr ( addr ) ?
vmalloc_to_page ( addr ) : virt_to_page ( addr ) ) = = NULL )
return NULL ; // 如果无法获取页面, 返回NULL
}
addr = vmap ( pages , nb_pages , VM_MAP , PAGE_KERNEL ) ; // 映射页面到内核地址空间
return addr ? addr + page_offset : NULL ; // 返回映射后的地址
}
////////////////////////////////////////////////////////////////////////////////
# ifdef CONFIG_X86
# include "x86 / hook.c"
# include "x86 / hook.c" // 包含x86架构相关的钩子实现
# else
# error Target CPU architecture is NOT supported !!!
# error Target CPU architecture is NOT supported !!! // 不支持的CPU架构
# endif
////////////////////////////////////////////////////////////////////////////////
/*
* 唤 醒 所 有 进 程
*/
static void khook_wakeup ( void )
{
struct task_struct * p ;
rcu_read_lock ( ) ;
for_each_process ( p ) {
wake_up_process ( p ) ;
}
rcu_read_unlock ( ) ;
struct task_struct * p ;
rcu_read_lock ( ) ;
for_each_process ( p ) {
wake_up_process ( p ) ; // 唤醒进程
}
rcu_read_unlock ( ) ;
}
/*
* 初 始 化 所 有 钩 子
*/
static int khook_sm_init_hooks ( void * arg )
{
khook_t * p ;
KHOOK_FOREACH_HOOK ( p ) {
if ( ! p - > target . addr_map ) continue ;
khook_arch_sm_init_one ( p ) ;
}
return 0 ;
khook_t * p ;
KHOOK_FOREACH_HOOK ( p ) {
if ( ! p - > target . addr_map ) continue ;
khook_arch_sm_init_one ( p ) ; // 初始化单个钩子
}
return 0 ;
}
/*
* 清 理 所 有 钩 子
*/
static int khook_sm_cleanup_hooks ( void * arg )
{
khook_t * p ;
KHOOK_FOREACH_HOOK ( p ) {
if ( ! p - > target . addr_map ) continue ;
khook_arch_sm_cleanup_one ( p ) ;
}
return 0 ;
khook_t * p ;
KHOOK_FOREACH_HOOK ( p ) {
if ( ! p - > target . addr_map ) continue ;
khook_arch_sm_cleanup_one ( p ) ; // 清理单个钩子
}
return 0 ;
}
/*
* 解 析 所 有 钩 子 的 目 标 地 址
*/
static void khook_resolve ( void )
{
khook_t * p ;
KHOOK_FOREACH_HOOK ( p ) {
p - > target . addr = khook_lookup_name ( p - > target . name ) ;
}
khook_t * p ;
KHOOK_FOREACH_HOOK ( p ) {
p - > target . addr = khook_lookup_name ( p - > target . name ) ; // 查找符号地址
}
}
/*
* 映 射 所 有 钩 子 的 目 标 地 址 到 可 写 内 存 区 域
*/
static void khook_map ( void )
{
khook_t * p ;
KHOOK_FOREACH_HOOK ( p ) {
if ( ! p - > target . addr ) continue ;
p - > target . addr_map = khook_map_writable ( p - > target . addr , 32 ) ;
khook_debug ( " target %s@%p -> %p \n " , p - > target . name , p - > target . addr , p - > target . addr_map ) ;
}
khook_t * p ;
KHOOK_FOREACH_HOOK ( p ) {
if ( ! p - > target . addr ) continue ;
p - > target . addr_map = khook_map_writable ( p - > target . addr , 32 ) ; // 映射地址
khook_debug ( " target %s@%p -> %p \n " , p - > target . name , p - > target . addr , p - > target . addr_map ) ;
}
}
/*
* 取 消 映 射 所 有 钩 子 的 目 标 地 址
*/
static void khook_unmap ( int wait )
{
khook_t * p ;
KHOOK_FOREACH_HOOK ( p ) {
khook_stub_t * stub = KHOOK_STUB ( p ) ;
if ( ! p - > target . addr_map ) continue ;
while ( wait & & atomic_read ( & stub - > use_count ) > 0 ) {
khook_wakeup ( ) ;
msleep_interruptible ( 1000 ) ;
khook_debug ( " waiting for %s... \n " , p - > target . name ) ;
}
vunmap ( ( void * ) ( ( long ) p - > target . addr_map & PAGE_MASK ) ) ;
p - > target . addr_map = NULL ;
}
khook_t * p ;
KHOOK_FOREACH_HOOK ( p ) {
khook_stub_t * stub = KHOOK_STUB ( p ) ;
if ( ! p - > target . addr_map ) continue ;
while ( wait & & atomic_read ( & stub - > use_count ) > 0 ) {
khook_wakeup ( ) ; // 唤醒进程
msleep_interruptible ( 1000 ) ; // 休眠1秒
khook_debug ( " waiting for %s... \n " , p - > target . name ) ;
}
vunmap ( ( void * ) ( ( long ) p - > target . addr_map & PAGE_MASK ) ) ; // 取消映射
p - > target . addr_map = NULL ;
}
}
////////////////////////////////////////////////////////////////////////////////
/* khook_init()和khook_cleanup()对挂钩引擎进行初始化和注销 */
/*
* 初 始 化 挂 钩 引 擎
* 1. malloc 分 配 内 存 空 间 用 于 存 储 钩 子 函 数 的 桩 ( stub )
* 2. khook_resolve 查 找 并 解 析 内 核 符 号 表
* 3. 映 射 目 标 地 址 到 可 写 的 内 核 内 存 区 域
* 4. 调 用 stop_machine 函 数 , 将 钩 子 函 数 的 初 始 化 工 作 交 给 内 核 调 度 器 执 行
*/
int khook_init ( void )
{
void * ( * malloc ) ( long size ) = NULL ;
int ( * set_memory_x ) ( unsigned long , int ) = NULL ;
void * ( * malloc ) ( long size ) = NULL ;
int ( * set_memory_x ) ( unsigned long , int ) = NULL ;
malloc = khook_lookup_name ( " module_alloc " ) ;
if ( ! malloc | | KHOOK_ARCH_INIT ( ) ) return - EINVAL ;
malloc = khook_lookup_name ( " module_alloc " ) ;
if ( ! malloc | | KHOOK_ARCH_INIT ( ) ) return - EINVAL ;
khook_stub_tbl = malloc ( KHOOK_STUB_TBL_SIZE ) ;
if ( ! khook_stub_tbl ) return - ENOMEM ;
memset ( khook_stub_tbl , 0 , KHOOK_STUB_TBL_SIZE ) ;
khook_stub_tbl = malloc ( KHOOK_STUB_TBL_SIZE ) ;
if ( ! khook_stub_tbl ) return - ENOMEM ;
memset ( khook_stub_tbl , 0 , KHOOK_STUB_TBL_SIZE ) ;
//
// Since some point memory allocated by module_alloc() doesn't
// have eXecutable attributes. That's why we have to mark the
// region executable explicitly.
//
//
// Since some point memory allocated by module_alloc() doesn't
// have eXecutable attributes. That's why we have to mark the
// region executable explicitly.
//
set_memory_x = khook_lookup_name ( " set_memory_x " ) ;
if ( set_memory_x ) {
int numpages = round_up ( KHOOK_STUB_TBL_SIZE , PAGE_SIZE ) / PAGE_SIZE ;
set_memory_x ( ( unsigned long ) khook_stub_tbl , numpages ) ;
}
set_memory_x = khook_lookup_name ( " set_memory_x " ) ;
if ( set_memory_x ) {
int numpages = round_up ( KHOOK_STUB_TBL_SIZE , PAGE_SIZE ) / PAGE_SIZE ;
set_memory_x ( ( unsigned long ) khook_stub_tbl , numpages ) ;
}
khook_resolve ( ) ;
khook_resolve ( ) ; // 解析符号表
khook_map ( ) ;
stop_machine ( khook_sm_init_hooks , NULL , NULL ) ;
khook_unmap ( 0 ) ;
khook_map ( ) ; // 映射地址
stop_machine ( khook_sm_init_hooks , NULL , NULL ) ; // 初始化钩子
khook_unmap ( 0 ) ; // 取消映射
return 0 ;
return 0 ;
}
/*
* 注 销 挂 钩 引 擎
* 1. 映 射 目 标 地 址 到 可 写 的 内 核 内 存 区 域
* 2. 调 用 stop_machine 函 数 , 将 钩 子 函 数 的 清 理 工 作 交 给 内 核 调 度 器 执 行
* 3. 取 消 映 射 目 标 地 址
* 4. 释 放 分 配 的 内 存 空 间
*/
void khook_cleanup ( void )
{
khook_map ( ) ;
stop_machine ( khook_sm_cleanup_hooks , NULL , NULL ) ;
khook_unmap ( 1 ) ;
vfree ( khook_stub_tbl ) ;
}
khook_map ( ) ; // 映射地址
stop_machine ( khook_sm_cleanup_hooks , NULL , NULL ) ; // 清理钩子
khook_unmap ( 1 ) ; // 取消映射
vfree ( khook_stub_tbl ) ; // 释放内存
}