VMware对挂起linux快照文件的进程分析
2017-05-06 19:24
190 查看
写作业,记录一下心得。致敬阳神。
以下内容都是我的个人理解,可能有各种偏差。。。orz
虚拟机在进行挂起时,为了在下一次打开时能够直接使用,它保存了当前状态的内存信息!
我猜是虚拟机突然剥夺了什么资源吧,然后整个系统就在等资源了,然后趁机拷贝内存。。。
内存拷贝好后是一个*.vmem文件,大小应该是等于你分配的内存大小。
把它复制到一个风水宝地,比如你外界的的c++工程目录。
![](https://img-blog.csdn.net/20170508124839027?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbWFlcjY2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
然后就开始分析吧:
首先要看进程信息,就要知道进程的管理是靠PCB控制块,那么,内存里的PCB控制块放在哪里呢?
讲道理我是不知道的,但是,所有的总得有个头吧。也就是传说中的0号进程——init_task
0号进程是linux初始化的第一个进程,直接由系统生成,他被定义在Syetem.map里,这个文件在linux的boot里
![](https://img-blog.csdn.net/20170508125108437?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbWFlcjY2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
无法直接查看的,只有用命令行,要root才能cat
![](https://img-blog.csdn.net/20170508125419342?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbWFlcjY2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
这样你生成一个xxxx.txt的文件,其实就是把这个玩意复制了一份,现在你可以查看xxxx.txt了
通过简单的搜索,可以找到init_task的位置。
我的在56410行
![](https://img-blog.csdn.net/20170508125529812?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbWFlcjY2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
我还是不太习惯linux,所以大部分操作都在windows(其实现在已经对linux有些好感了)
好了,我们找到了它对应的地址,就是c1863200,这个是个虚拟地址,映射到物理地址就是直接减去0xc0000000.
因为我们查询的文件就是物理的内存条,所以,所有地址都是物理地址。但在指针的寻址时,却是虚拟地址,反正要有个转换
找到了这个地址的物理地址 就是0x01863200.至此我们找到了0号进程的地址。
我们要访问进程的信息,就要知道PCB中各种信息的位置偏移。
怎么找偏移呢?难点来了
我们要用到一个函数
offsetof(类型名,成员名);
这个函数是查看指定成员在指定类型里的偏移。
但是我们却要在linux里编写程序,而且还是内核程序!因为我们要用到内核的数据结构。。反正我之前是想的太简单,耽误很久时间,还是黄巨指导说要在内核编程。
怎么进行内核编程呢,百度各种博客,,我就直接抄了一篇,http://blog.csdn.net/chang198932/article/details/17006537
我也忘了当时抄的那一篇了。
直接抄,然后改。
这个的意思是内核加载时候,就执行hello_init,退出时候加载exit那个
你的代码写在init里面就好;
这里的代码写你需要查询的偏移量啊,验证一些数据结构的大小什么的。
我的查询,查询了pid,comm,tasks,uid,gid这几样
然后,你如果每次按照常规的方法编译,很麻烦,每次提供版本号啊各种神奇的东西,网上提供了一个简易方法,就是写一个Makefile文件
Makefile文件内容
如果你要改文件名,两个要一起改。。
现在你有两个文件
放一起
![](https://img-blog.csdn.net/20170508125703390?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbWFlcjY2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
然后打开命令行里cd到这个目录
直接make
![](https://img-blog.csdn.net/20170508130001688?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbWFlcjY2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
然后加载这个.ko文件
![](https://img-blog.csdn.net/20170508130045861?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbWFlcjY2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
加载的时候还是要root
加载成功没有任何提示,每错,,,并么有标准的输出,,但是我们可以查看日志
![](https://img-blog.csdn.net/20170508130244924?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbWFlcjY2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20170508130330158?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbWFlcjY2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
我们刚刚写的东西,都出来了。
最后,别忘了卸载
![](https://img-blog.csdn.net/20170508130406891?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbWFlcjY2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
找到了偏移,我就就可以愉快的写程序了
直接上代码吧:
很简单,,就是读入文件,找到对应的偏移量。
对了忘了很重要的一点
就是循环的读取进程控制块
在task_struct里面
tasks这个结构就是进行连接用的指针,这个结构有两个指针,一个后,一个前,不停往后遍历就好了。。
其实主要就是内核找偏移麻烦点,搞定了那里,C++的部分简单了。
其实要查看什么信息,直接网上搜一搜,很多结构啊什么的都有了,第一篇博客,记录一下实验心得,结束。
(博客贴图差评啊!为啥不能直接粘贴!!)
以下内容都是我的个人理解,可能有各种偏差。。。orz
虚拟机在进行挂起时,为了在下一次打开时能够直接使用,它保存了当前状态的内存信息!
我猜是虚拟机突然剥夺了什么资源吧,然后整个系统就在等资源了,然后趁机拷贝内存。。。
内存拷贝好后是一个*.vmem文件,大小应该是等于你分配的内存大小。
把它复制到一个风水宝地,比如你外界的的c++工程目录。
然后就开始分析吧:
首先要看进程信息,就要知道进程的管理是靠PCB控制块,那么,内存里的PCB控制块放在哪里呢?
讲道理我是不知道的,但是,所有的总得有个头吧。也就是传说中的0号进程——init_task
0号进程是linux初始化的第一个进程,直接由系统生成,他被定义在Syetem.map里,这个文件在linux的boot里
无法直接查看的,只有用命令行,要root才能cat
这样你生成一个xxxx.txt的文件,其实就是把这个玩意复制了一份,现在你可以查看xxxx.txt了
通过简单的搜索,可以找到init_task的位置。
我的在56410行
我还是不太习惯linux,所以大部分操作都在windows(其实现在已经对linux有些好感了)
好了,我们找到了它对应的地址,就是c1863200,这个是个虚拟地址,映射到物理地址就是直接减去0xc0000000.
因为我们查询的文件就是物理的内存条,所以,所有地址都是物理地址。但在指针的寻址时,却是虚拟地址,反正要有个转换
找到了这个地址的物理地址 就是0x01863200.至此我们找到了0号进程的地址。
我们要访问进程的信息,就要知道PCB中各种信息的位置偏移。
怎么找偏移呢?难点来了
我们要用到一个函数
offsetof(类型名,成员名);
这个函数是查看指定成员在指定类型里的偏移。
但是我们却要在linux里编写程序,而且还是内核程序!因为我们要用到内核的数据结构。。反正我之前是想的太简单,耽误很久时间,还是黄巨指导说要在内核编程。
怎么进行内核编程呢,百度各种博客,,我就直接抄了一篇,http://blog.csdn.net/chang198932/article/details/17006537
我也忘了当时抄的那一篇了。
//必要的头文件 #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> //模块许可证声明(必须) MODULE_LICENSE("Dual BSD/GPL"); //模块加载函数(必须) static int hello_init(void) { printk(KERN_ALERT "Hello World enter/n"); return 0; } //模块卸载函数(必须) static void hello_exit(void) { printk(KERN_ALERT "Hello World exit/n"); } //模块的注册 module_init(hello_init); module_exit(hello_exit);
直接抄,然后改。
这个的意思是内核加载时候,就执行hello_init,退出时候加载exit那个
你的代码写在init里面就好;
这里的代码写你需要查询的偏移量啊,验证一些数据结构的大小什么的。
我的查询,查询了pid,comm,tasks,uid,gid这几样
//hello.c 源码 #include <linux/kernel.h> #include <linux/module.h> #include <linux/sched.h> static int __init mini2440_hello_module_init(void) { /* Set up the anchor point */ struct task_struct *task = &init_task; printk (KERN_WARNING "===OPEN===\ntask_struct-size:%d\n\n",sizeof(struct task_struct)); printk (KERN_WARNING "task->pid-size:%d\n",sizeof(task->pid)); printk (KERN_WARNING "task->comm-size:%d\n",sizeof(task->comm)); printk (KERN_WARNING "task->tasks-size:%d\n",sizeof(task->tasks)); printk (KERN_WARNING "struct cred-size:%d\n",sizeof(struct cred)); printk (KERN_WARNING "task->real_cred-size:%d\n\n",sizeof(task->real_cred)); printk (KERN_WARNING "task->real_cred->uid-size:%d\n\n",sizeof(task->real_cred->uid)); printk (KERN_WARNING "pid:%d\n",offsetof(struct task_struct,pid)); printk (KERN_WARNING "comm:%d\n",offsetof(struct task_struct,comm)); printk (KERN_WARNING "tasks:%d\n",offsetof(struct task_struct,tasks)); printk (KERN_WARNING "real_cred:%d\n",offsetof(struct task_struct,real_cred)); printk (KERN_WARNING "tasks.next:%d\n",offsetof(struct list_head,next)); printk (KERN_WARNING "cred.uid:%d\n",offsetof(struct cred,uid)); printk (KERN_WARNING "cred.gid:%d\n",offsetof(struct cred,gid)); return 0; } static int __exit mini2440_bye_module_exit(void) { printk (KERN_WARNING "bye , mini2440\n"); return 0; } module_init(mini2440_hello_module_init); module_exit(mini2440_bye_module_exit); MODULE_LICENSE("GPL");
然后,你如果每次按照常规的方法编译,很麻烦,每次提供版本号啊各种神奇的东西,网上提供了一个简易方法,就是写一个Makefile文件
Makefile文件内容
obj-m := hello.o KERNEL_DIR := /lib/modules/$(shell uname -r)/build #KERNEL_DIR := /opt/FriendlyARM/mini2440/linux-2.6.32.2 PWD := $(shell pwd) all: make -C $(KERNEL_DIR) M=$(PWD) modules clean: rm *.o *.ko *.mod.c Module.symvers modules.order
如果你要改文件名,两个要一起改。。
现在你有两个文件
放一起
然后打开命令行里cd到这个目录
直接make
然后加载这个.ko文件
加载的时候还是要root
加载成功没有任何提示,每错,,,并么有标准的输出,,但是我们可以查看日志
我们刚刚写的东西,都出来了。
最后,别忘了卸载
找到了偏移,我就就可以愉快的写程序了
直接上代码吧:
#define _CRT_SECURE_NO_WARNINGS #include<bits/stdc++.h> using namespace std; unsigned int charToUint(char* ch) { unsigned int tmp = 0; for (int i = 0; i < 4; ++i) { tmp |= (0x000000ff & ch[i]) << 8 * i; } return tmp; } int main() { ifstream ifile("mem.vmem",ios::binary); ofstream ofile("Print.txt"); int count = 0; char comm_c[16],pid_c[4],taskN_c[4],uidc[4],gidc[4]; unsigned int pid = -1, next = 0x01863200 + 440, uid, gid; ofile << "pid " << "\t" << "name" << "\t" << "uid " << "\t" << "gid " << endl; while (1) { ifile.seekg(next + 80); ifile.read(pid_c, 4); pid = charToUint(pid_c); if (pid == 0 && count != 0)break; ifile.seekg(next + 300); ifile.read(comm_c, 16); ifile.seekg(next + 292); ifile.read(uidc, 4); uid = charToUint(uidc); ifile.seekg(uid - 0xc0000000 + 4); ifile.read(uidc, 4); uid = charToUint(uidc); ifile.seekg(next + 292); ifile.read(gidc, 4); gid = charToUint(gidc); ifile.seekg(gid - 0xc0000000 + 8); ifile.read(gidc, 4); gid = charToUint(gidc); ifile.seekg(next); ifile.read(taskN_c, 4); next = charToUint(taskN_c); next -= 0xc0000000; ofile << pid << "\t" << comm_c << "\t" << uid << "\t" << gid << endl; ++count; } }
很简单,,就是读入文件,找到对应的偏移量。
对了忘了很重要的一点
就是循环的读取进程控制块
在task_struct里面
tasks这个结构就是进行连接用的指针,这个结构有两个指针,一个后,一个前,不停往后遍历就好了。。
其实主要就是内核找偏移麻烦点,搞定了那里,C++的部分简单了。
其实要查看什么信息,直接网上搜一搜,很多结构啊什么的都有了,第一篇博客,记录一下实验心得,结束。
(博客贴图差评啊!为啥不能直接粘贴!!)
相关文章推荐
- 关于linux中进程打开同一文件操作的一点分析
- MTD系列 - android平台上linux启动时init进程解析init.rc文件分析
- MTD系列 - android平台上linux启动时init进程解析init.rc文件分析
- Linux\Unix IPC进程通信实例分析(一):共享内存通信---文件映射mmap方式
- Linux进程-fork创建新进程之文件分析
- Linux 2.4进程调度分析 8
- Linux 2.4进程调度分析 3
- 用VMware装Red Hatlinux的共享文件的解决方法
- 如何获取linux进程的执行文件路径
- UNIX/LINUX 平台可执行文件格式分析(转)
- [转载]UNIX/LINUX 平台可执行文件格式分析
- Linux 2.4进程调度分析 5
- UNIX-LINUX平台可执行文件格式分析
- 在linux下利用程序崩溃后的core文件分析bug
- Intel平台下Linux中 ELF文件动态链接的加载、解析及实例分析(一): 加载
- Intel平台下linux中 ELF文件动态链接的加载、解析及实例分析(二): 函数解析与卸载
- Linux 2.4进程调度分析 2
- Windows与Vmware下的Linux文件共享方式总结
- UNIX/LINUX 平台可执行文件格式分析
- Windows与VMware下Linux的文件共享问题