简介

taskverse是《linux二进制分析》一书作者编写的一个隐藏进程的检测工具,它使用/proc/kcore来访问内核内存,github的地址在这里:https://github.com/elfmaster/taskverse。

/proc/kcore

这个文件是内核提供的用来遍历内核内存的接口,使用elf文件格式,他的实现在内核文件\fs\proc\kcore.c中,文件的主要操作在proc_kcore_operations中,围绕一个链表kclist_head来组织elf中的各个段。而一个段就代表着一段内存,将这些内存映射成可执行文件的段。看看这些段的信息,在这之前有一个note段,这里面保存着一些其他信息,这里就不分析了,从内核源码里的get_kcore_size可以看出网note段里面放的是什么。

为了解释这个文件的用法,我写了一个简单的例子,代码在这里:https://github.com/smakk/kocre_sample

可以使用readelf -h的命令去查看,可以发现/proc/kcore这个文件是没有节区的,也就是没有办法访问到符号表,这里使用了/proc/kallsyms这个文件来访问符号地址,具体代码如下,根据名字,不断读取符号文件来找到符号地址

//由于/proc/kcore没有节头,找不到符号表,所以通过kallsym来找符号地址
unsigned long get_sym(char* name){
FILE *fd;
char symbol_s[];
int i;
unsigned long address;
char tmp[], type; if ((fd = fopen("/proc/kallsyms", "r")) == NULL)
{
printf("fopen /proc/kallsym wrong\n");
exit(-);
}
while(!feof(fd))
{
if(fscanf(fd, "%lx %c %s", &address, &type, symbol_s)<=){
printf("fscanf wrong\n");
exit(-);
}
if (strcmp(symbol_s, name) == )
{
fclose(fd);
return address;
}
if (!strcmp(symbol_s, ""))
break;
}
fclose(fd);
return ;
}

接着就是/proc/kcore的使用,这里使用一个全局的链表kcore,来表示/kcore的一个段信息中的虚拟地址,文件偏移量和大小,有这3个量就可以访问内存了

struct kcore_list{
struct kcore_list* list;
unsigned long vaddr;
unsigned long offset;
size_t size;
};
struct kcore_list kcore; /*
生成kcore链表,按照虚拟地址升序存放kcore提供的所有的地址空间,而且这些地址空间是不重叠的
*/
void* init_kcore_list(){
int fd = open("/proc/kcore", O_RDONLY);
if(fd < ){
printf("open /proc/kcore wrong\n");
exit(-);
}
Elf64_Ehdr head;
read(fd,&head,sizeof(Elf64_Ehdr));
if(lseek(fd,head.e_phoff,SEEK_SET)<){
printf("lseek /proc/kcore wrong\n");
exit(-);
}
Elf64_Phdr phdr[head.e_phnum];
read(fd,&phdr,sizeof(Elf64_Phdr)*head.e_phnum);
close(fd);
int i;
for(i=;i<head.e_phnum;i++){
struct kcore_list* k_list = malloc(sizeof(struct kcore_list));
k_list->vaddr = phdr[i].p_vaddr;
k_list->offset = head.e_phoff+sizeof(Elf64_Phdr)*i;
k_list->size = phdr[i].p_memsz;
struct kcore_list* tmplist = &kcore;
while(tmplist->list != NULL && tmplist->list->vaddr<k_list->vaddr){
tmplist = tmplist->list;
}
k_list->list = tmplist->list;
tmplist->list = k_list;
//printf("%lx\n",k_list->vaddr);
}
return;
}

现在已经存储完kcore的段信息,要想访问符号虚拟地址指向处的地址,就是要先找出虚拟地址位于哪个段中,然后转换成这个段在文件中的偏移,最终根据文件偏移去访问文件。代码如下:

/*
根据虚拟地址addr,从/proc/kcore这个位置读取size大小的内存
*/
void* get_area(unsigned long addr, size_t size){
void* ret;
struct kcore_list* k_list = kcore.list;
while(k_list != NULL && addr>k_list->vaddr + k_list->size){
k_list = k_list->list;
}
if(addr>=k_list->vaddr && addr+size<k_list->vaddr + k_list->size){
int fd = open("/proc/kcore", O_RDONLY);
if(fd < ){
printf("open /proc/kcore wrong\n");
exit(-);
}
if(lseek(fd,k_list->offset+(addr-k_list->vaddr),SEEK_SET)<){
printf("lseek /proc/kcore wrong\n");
exit(-);
}
ret = malloc(size);
read(fd,ret,size);
close(fd);
}
return ret;
}

最后,使用这个借口,我做了一个简单的使用例子,找到init_task的进程描述符,在内核的进程描述符中,第一个字段表示的是进程状态,这里输出init_task的进程状态,打印这和结果。

int main(){
init_kcore_list();
printf("_text addrs is %lx\n",get_sym("_text"));
void * code = get_area(get_sym("init_task"),);
unsigned long * statue = (unsigned long *)code;
//0代表正在运行,大于0表示停止了
printf("init_task statue is %ld\n", *statue);
return ;
}

taskverse分析

程序入口地址在主目录下的taskverse.c中的mian函数,在taskverse中,可以使用两种寻找符号的方式,一种是kallsyms,另一种是systemmap文件。

沿着主函数,load_live_kcore函数去分析kcore文件,然后取出该文件的一些部分,存放形成一个Elf_t,在遍历段的过程中,作者关注了3个段,一个是文本段,一个是vmalloc使用的段,一个是kmalloc使用的段。地址分别是0xffff880100000000和0xffff880000100000,text段的起始地址放在_text符号的位置。

值得注意的是elf结构中的mem结构,这里的mem结构放了3个内容

1、elf头
2、程序头表
3、text段内容
后面从mem中取值的时候要注意,这里的地址计算
然后就开始获取符号地址,这里获取到init_task的位置,然后kcore_translate_kernel将它翻译为文件地址,最后从文件中读取task_struct结构的内容,遍历tasklist来获取到进程列表,然后和proc目录下的进程进行对比,如果发现不一样则是发现了隐藏进程。
 

taskverse学习的更多相关文章

  1. 从直播编程到直播教育:LiveEdu.tv开启多元化的在线学习直播时代

    2015年9月,一个叫Livecoding.tv的网站在互联网上引起了编程界的注意.缘于Pingwest品玩的一位编辑在上网时无意中发现了这个网站,并写了一篇文章<一个比直播睡觉更奇怪的网站:直 ...

  2. Angular2学习笔记(1)

    Angular2学习笔记(1) 1. 写在前面 之前基于Electron写过一个Markdown编辑器.就其功能而言,主要功能已经实现,一些小的不影响使用的功能由于时间关系还没有完成:但就代码而言,之 ...

  3. ABP入门系列(1)——学习Abp框架之实操演练

    作为.Net工地搬砖长工一名,一直致力于挖坑(Bug)填坑(Debug),但技术却不见长进.也曾热情于新技术的学习,憧憬过成为技术大拿.从前端到后端,从bootstrap到javascript,从py ...

  4. 消息队列——RabbitMQ学习笔记

    消息队列--RabbitMQ学习笔记 1. 写在前面 昨天简单学习了一个消息队列项目--RabbitMQ,今天趁热打铁,将学到的东西记录下来. 学习的资料主要是官网给出的6个基本的消息发送/接收模型, ...

  5. js学习笔记:webpack基础入门(一)

    之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...

  6. Unity3d学习 制作地形

    这周学习了如何在unity中制作地形,就是在一个Terrain的对象上盖几座小山,在山底种几棵树,那就讲一下如何完成上述内容. 1.在新键得项目的游戏的Hierarchy目录中新键一个Terrain对 ...

  7. 《Django By Example》第四章 中文 翻译 (个人学习,渣翻)

    书籍出处:https://www.packtpub.com/web-development/django-example 原作者:Antonio Melé (译者注:祝大家新年快乐,这次带来<D ...

  8. 菜鸟Python学习笔记第一天:关于一些函数库的使用

    2017年1月3日 星期二 大一学习一门新的计算机语言真的很难,有时候连函数拼写出错查错都能查半天,没办法,谁让我英语太渣. 关于计算机语言的学习我想还是从C语言学习开始为好,Python有很多语言的 ...

  9. 多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类)

    前言:刚学习了一段机器学习,最近需要重构一个java项目,又赶过来看java.大多是线程代码,没办法,那时候总觉得多线程是个很难的部分很少用到,所以一直没下决定去啃,那些年留下的坑,总是得自己跳进去填 ...

随机推荐

  1. scrapy框架之spider

    爬取流程 Spider类定义如何爬取指定的一个或多个网站,包括是否要跟进网页里的链接和如何提取网页内容中的数据. 爬取的过程是类似以下步骤的循环: 1.通过指定的初始URL初始化Request,并指定 ...

  2. AE开发之shp转txt

    using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...

  3. 带下划线的 HTTP Header无法获取到可能是因为nginx

    背景:新版本修改了个功能是在老版本的基础上做的,同一个接口,需要兼容老版本,因此让前台在header中封装了 version版本号,client_type 客户端类型,根据这两个字段判断接口要走的逻辑 ...

  4. 树莓派中将caplock映射为esc键

    据说,喜欢vimer都呵caplock有仇,明明caplock占着原来esc的位置,却从来没有起到应有的作用,你说气人吗,没关系,我改啊:将下面语句加入到.bashrc中,启动即可xmodmap -e ...

  5. Web开发中 MTV模式与MVC模式的区别 联系 概念

    MTV 与 MVC模式的区别 联系 概念: MTV: 所谓MTV指的就是: M:model (模型),指的是ORM模型. T:template (模板),一般Python都是使用模板渲染的方式来把HT ...

  6. linux安装后需要进行的一些基本设置

    修改网络: 在终端中输入:vi /etc/sysconfig/network-scripts/ifcfg-ens33 然后重启网络服务:systemctl restart network.servic ...

  7. MySQL中的sys系统数据库是干嘛的

    mysql5.7增加了sys 系统数据库,通过这个库可以快速的了解系统的元数据信息 这个库确实可以方便DBA发现数据库的很多信息,解决性能瓶颈都提供了巨大帮助   这个库在mysql5.7中是默认存在 ...

  8. kafka和rabbitmq对比

    1.吞吐量kafka吞吐量更高:1)Zero Copy机制,内核copy数据直接copy到网络设备,不必经过内核到用户再到内核的copy,减小了copy次数和上下文切换次数,大大提高了效率.2)磁盘顺 ...

  9. kotlin泛型基本使用

    class box<T> (t :T){ var vlaue =t } fun main(arg: Array<String>) { val box1:box<Int&g ...

  10. 使用rsync备份数据

    (1).实验环境与目标 源主机:youxi1 192.168.5.101 目标主机:youxi2 192.168.5.102 目标:将源主机youxi1的数据备份到youxi2上. rsync是C/S ...