linux内核:sys_call_talbe hook案例(通讯录读取hook的教程)

最近在学习安卓goldfish的内核hook,把最近半个月的成果写个教程,供大家分享,希望大家不要走弯路。

关于源码下载、内核编译、动态插入内核等等再次不介绍了,可以参考其他的博客,里面写的很详细,在这里我主要介绍如何进行通讯录的调用hook:

应用环境:

       本教程适用于,下载安卓模拟器的goldfish源码,然后自己编译运行,并且可以把虚拟机运行在上面。然后通过动态插入内核,可以验证已经安卓模拟器上已经假如了自己的内核。当然,这样做基本都是为了hook  linux内核调用。然后写了自己的模块,用于当应用程序去读取安卓设备的通讯录时,去动态hook。

程序代码:

-----------------------------------------------------hook.c

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/unistd.h>
#include <linux/semaphore.h>
#include <asm/cacheflush.h>
#include <linux/string.h>
#include <net/sock.h>
#include <linux/netlink.h>
#include <linux/skbuff.h>
#include <stddef.h>

#define NETLINK_USER 16

struct sock *nl_sk = NULL;

void **sys_call_table;

asmlinkage int (*original_call_open) (const char*, int, int);

asmlinkage int (*original_call_read) (unsigned int, char*, int);

asmlinkage long (*sys_openat) (int, const char*, int, int);

asmlinkage long our_openat(int dfd, const char *filename, int flags, int mode){
    printk("%s\n",filename);
    return sys_openat(dfd,filename,flags,mode);
}

asmlinkage int our_sys_read(unsigned int fd, char * buf, int count){
    
    if(fd == 0 && count == 1){
        //printk("有文件正在被读取intercept 0x%02X", buf[0]);
    }
    
    return original_call_read(fd, buf, count);
}

asmlinkage int our_sys_open(const char* file, int flags, int mode)
{
    //联系人 /data/data/com.android.providers.contacts/databases/contacts2.db
       //通话记录  /data/data/com.android.providers.telephony/databases/telephony.db
    //短信记录  /data/data/com.android.providers.telephony/databases/mmssms.db
    char * contact = "/data/data/com.android.providers.contacts/databases/contacts2.db";
    char * telephony = "/data/data/com.android.providers.telephony/databases/telephony.db";
    char * sms = "/data/data/com.android.providers.telephony/databases/mmssms.db";
   if (strcmp(file, contact) == 0 || strstr(file, contact) != NULL){   //这里一定要注意比较条件
     printk("应用程序正在读取手机的联系人记录!!!\n");
   }
   if (strcmp(file, telephony) == 0){
     printk("应用程序正在读取手机的通话记录!!!\n");
   }
   if (strcmp(file, sms) == 0){
     printk("应用程序正在读取手机的短信记录!!!\n");
   }
       return original_call_open(file, flags, mode);
}

//用来接受用户态发来的消息
 void hello_nl_recv_msg(struct sk_buff *skb)
{

    struct nlmsghdr *nlh;
    int pid;/data/data/com.android.providers.contacts/databases/contacts2.db
    struct sk_buff *skb_out;
    int msg_size;
    char *msg = "Hello from kernel";
    int res;

    printk(KERN_INFO "Entering: %s\n", __FUNCTION__);

    msg_size = strlen(msg);

    nlh = (struct nlmsghdr *)skb->data;
    printk(KERN_INFO "Netlink received msg payload:%s\n", (char *)nlmsg_data(nlh));
    pid = nlh->nlmsg_pid; //pid of sending process

    skb_out = nlmsg_new(msg_size, 0);

    if (!skb_out)
    {

        printk(KERN_ERR "Failed to allocate new skb\n");
        return;

    }
    nlh = nlmsg_put(skb_out, 0, 0, NLMSG_DONE, msg_size, 0);
    NETLINK_CB(skb_out).dst_group = 0; //not in mcast group
    strncpy(nlmsg_data(nlh), msg, msg_size);

    res = nlmsg_unicast(nl_sk, skb_out, pid);

    if (res < 0)
        printk(KERN_INFO "Error while sending bak to user\n");
 
}


static void disable_page_protection(void){
//    unsigned long value = 0xc000de04;
//    asm volatile ("mov %%cr0,%0" : "=r" (value));
//    if(value & 0x00010000){
//        value &= ~0x00010000;
//        asm volatile("mov %0,%%cr0" : : "r" (value));
//    }
}

void set_addr_rw(unsigned long addr){
    //unsigned int lever;
    //pte_t *pte = lookup_address(addr,&level);
    //if(pte->pte &~ _PAGE_RW)
    //    pte->pte |= _PAGE_RW;
}

int set_page_rw(long unsigned int _addr)
{
  // struct page *pg;
  //pgprot_t prot;
  // pg = virt_to_page(_addr);
  // prot = VM_READ | VM_WRITE;
  // return change_page_attr(pg, 1, prot);

    // return set_memory_rw(PAGE_ALIGN(_addr) - PAGE_SIZE, 1);
  // unsigned int level;
  // pte_t * pte = lookup_address(address,&level);
  // if(pte->pte &~ _PAGE_RW)
  //    pte->pte |= _PAGE_RW;
  // return 0;
    //return set_memory_rw(PAGE_ALIGN(_addr) - PAGE_SIZE, 1);
}

int init_module()
{
   // sys_call_table address in System.map
    sys_call_table = (void*)0xc0022f24;
    original_call_open = sys_call_table[__NR_open];
    original_call_read = sys_call_table[__NR_read];
    sys_openat = sys_call_table[__NR_openat];

   // set_page_rw(sys_call_table);
   // set_addr_rw(sys_call_table);
   // disable_page_protection();
    sys_call_table[__NR_open] = our_sys_open;
    sys_call_table[__NR_read] = our_sys_read;
    sys_call_table[__NR_openat] = our_openat;
  //  printk("Entering: %s\n", __FUNCTION__);
  //  nl_sk = netlink_kernel_create(&init_net, NETLINK_USER, 0, &hello_nl_recv_msg, NULL, THIS_MODULE);

   // nl_sk = netlink_kernel_create(NETLINK_USER, input);
    //if (!nl_sk)
    //{

      //  printk(KERN_ALERT "Error creating socket.\n");
       // return -10;

    //}

    return 0;
}

void cleanup_module()
{
   // Restore the original call
   sys_call_table[__NR_open] = original_call_open;
   sys_call_table[__NR_read] = original_call_read;
   sys_call_table[__NR_openat] = sys_openat;
   printk(KERN_INFO "exiting hello module\n");
   netlink_kernel_release(nl_sk);
}

//MODULE_LICENSE("GPL");  
//module_init(init_module);  
//module_exit(cleanup_module);  

--------------------------------------------------------Makefile

    obj-m := sys-hook.o        
    sys-hook-objs := hook.o #由于我们的模块叫做hello-yf,所以写hello-yf-objs :=表示该模块由N个模块组成,例如hello-yf-objs := file1.o  file2.o     
            
    KID :=~/android-kernel-2.6/goldfish  
    PWD := $(shell pwd)  #表示当前Makefile所在的路径
    ARCH=arm    
    CROSS_COMPILE=arm-eabi-  
    CC=$(CROSS_COMPILE)gcc  
    LD=$(CROSS_COMPILE)ld     
            
    all:  
    make -C $(KID) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) M=${PWD} modules  
          #M=表示在建立模块target的时候,makefile回归到我们模块程序的目录。
            
    clean:  
    rm -rf *.o .cmd *.ko *.mod.c .tmp_versions *.order *.symvers
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

关于代码部分,我只想说一个地方:

  if (strcmp(file, contact) == 0 || strstr(file, contact) != NULL){
     printk("应用程序正在读取手机的联系人记录!!!\n");
   }

大家一定注意,这里一定是用strstr和strcmp同时去比较,他们之间的关系是“或”的关系。因为应用程序读取用户通讯录的时候不是去死板的调用

"/data/data/com.android.providers.contacts/databases/contacts2.db"这个目录,而是去调用这个数据库的其中几个表和几个字段,这里不赘述了,所以如果只是比较strcmp()的话,并不能准确的hook,这个问题我纠结了三天终于想到了问题的症结。另外,我把部分代码的注释用‘//’加了注释。

最后,希望大家看到这个教程之后,能够顺利的hook,少走弯路。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值