内核相关基础知识
1. CPU模式:实模式、保护魔术、8086虚拟模式
实模式:操作系统和软件权限一样,可以随便访问内存的每一个地方
保护模式:32位开始、开启了段页的保护,分为了用户模式和特权模式,这样可以保护关键内存不被访问修改。用户权限的应用程序,是不能访问特效模式的。
8086虚拟模式:CPU提供这种模式,使得可以跑16位程序
2. 内核:就是操作系统的一部分,这部分在0环运行
3. 驱动:可以看做是操作系统的一个dll,在0环运行操控硬件,但是我们肯定不是用来操控硬件。硬件不是微软产的,所有他肯定得让厂家能够编写,驱动代码控制硬件。所有我们就有机会能够访问内核。到了win7 64位后编写驱动需要增加签名才能够,被系统加载进去。
4. 用户模式和内核模式通信图
用户模式和内核模式对内核驱动程序进行证明签名以便公开发布
安装开发驱动包(WDK)
我们现在学习的是XP系统,所有我们要开发XP的驱动,所以选择这个。
自己随便安装到一个目录、我安装的是D:\WinDDK
介绍WDK
第一个重要的是WDK的帮助文档
这个部分就是我们关于内核的帮助,驱动还有开发硬件的相关的,这些我们不需要了解。
这些就是内核函数
1. ob开头的API: 一般是对象使用,操作系统是C和汇编写的,但是用的却是面向对象设计,比如进程.还有引用计数等等.所以需要调用这种API.
2. Mm开头的API: Mm开头的API,都是内存管理的API,比如锁定一块内存,不让其与磁盘交换数据等等.
3. Ps开头的API: ps开头的API,一般都是管理进程和线程的API,比如psGetCurrentProcessId,获得当前进程ID.
4. Io开头的API: Io开头的API一般就是负责IO操作的.如果写硬件驱动则不用管这些.直接使用in 或者out进行操作.
5. Po开头的API: Po开头的API一般就是管理电源的API.对于写内核驱动的我们,不关心这些.写硬件驱动的则要关心,比如通电了.硬件驱动需要做些初始化什么的.
6. Cm开头的API: Cm开头的API一般是注册表常用的API.
7. Zw开头的API: Zw开头的API,一般是内核版本的API,比如三环有CreateFile,那么在内核API中则是ZwCreateFile.
8. Ke开头API: ke开头的API,一般是内核层的API.在内核中,分为内核层还有执行层.
9. Ex开头的API: Ex开头的API,则是执行层的API.
10. Rtl开头的API : Rtl开头的Api和C库函数很像,在驱动中可以使用C库函数,但是 微软不建议使用.所以提供了Rtl开头的API,甚至比C库函数还多.
11. DMA开头的API: 一般是写硬件驱动用的,我们不用.
12. HAL开头的API: 操作硬件抽象层的API.
13. Dbg开头的是调试函数
编译环境
我们现在看的是编译XP内核的环境
free编译的就是Release版
Checked编译的就是debug版
编写第一个内核程序
dll编写时候有一个dllmain
驱动有DriverEntry
编写代码
然后在DKK目录下找到src
找到这两个文件夹,然后拷贝到我们源码那里
把不需要的删除并且改名字就可以了
然后打开编译环境
进入源码路径,然后编译(build),发现这个错误就时路径有空格
得到sys的程序
#include VOID DriverUnload(__in struct _DRIVER_OBJECT *DriverObject){DbgPrint("DriverUnload\n");}int g_num = 100;NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject,PUNICODE_STRING RegistryPath){//注册卸载函数DriverObject->DriverUnload = DriverUnload;DbgPrint("Hello WDK!:%p\n", &g_num);return STATUS_SUCCESS;}
编写加载驱动软件
我们知道dll加载进入程序需要loadlibrary。而安装驱动等于创建服务,CreateSever把驱动信息记录注册表。
CreateServiceA
SC_HANDLE hService=CreateServiceA(hSCM, // handle to SCM database"CR33", // name of service to start"CR33Display", // display nameSERVICE_ALL_ACCESS, // type of access to serviceSERVICE_KERNEL_DRIVER, // type of serviceSERVICE_DEMAND_START, // when to start serviceSERVICE_ERROR_NORMAL, // severity of service failurestrPath.toStdString().c_str(), // name of binary file sys路径NULL, // name of load ordering groupNULL, // tag identifierNULL, // array of dependency namesNULL, // account nameNULL // account password);
就这几个参数比较重要
dwServiceType
选这个就表示写内核程序
dwStartType
这个是驱动方式
第一个是系统启动后就会启动
第二个会开机就启动
第三个只有调用startSever才会启动
第四个不能启动
第五个系统初始化之前启动
lpBinaryPathName
sys路径
StartService(开启驱动)
ControlService(停止)
DeleteService(卸载)
SERVICE_STATUS status;SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);//check//1.安装 CreateServiceSC_HANDLE hService = CreateService(hSCM,"cr33Hello","cr33Hello",SERVICE_ALL_ACCESS,SERVICE_KERNEL_DRIVER, //内核驱动SERVICE_DEMAND_START, /*启动方式*/SERVICE_ERROR_NORMAL,"C:\\Documents and Settings\\Administrator\\桌面\\Hello.sys", //驱动路径NULL, NULL, NULL, NULL, NULL);if (hService == NULL){printf("CreateService Error:%d\n", GetLastError());CloseServiceHandle(hSCM);system("pause");return 0;}else{printf("CreateService OK\n");}//2.启动 StartServiceif (StartService(hService, NULL, NULL) == 0){printf("StartService Error:%d\n", GetLastError());DeleteService(hService);CloseServiceHandle(hService);CloseServiceHandle(hSCM);system("pause");return 0;}else{printf("StartService OK\n");}//3.停止 ControlServiceControlService(hService, SERVICE_CONTROL_STOP, &status);//4.卸载 DeleteService//OpenService();DeleteService(hService);CloseServiceHandle(hService);CloseServiceHandle(hSCM);system("pause");return 0;
调试驱动程序
蓝屏保存DUM
当系统出错后会dump内存保存下来
为了看到蓝屏把这个取消
现在编写一个有问题的驱动程序
启动运行后出错了,可以看到里面有错误驱动名,错误类型还有代码位置
如果真的蓝屏,上面也写了,可以进入安全模式,然后把驱动删除,因为安全模式,只会加载基础的驱动,第三方的都不会加载。
这个就是我们DUM的文件
拷贝出来用windbg打开
点击自动分析
能分析错误位置,和错误类型,还能调试,有源码的话还能判断哪行出错
双机调式
我系统64位的所以打开这个
然后重启虚拟机里面的xp系统
最后打开windbg
然后输入g,系统就能正常跑起来
现在可以编写驱动的调试代码了,用代码给下断点,我们一般不用int 3
用DbgBreakPoint()
DbgBreakPoint()
_asm int 3
编译好,用加载器启动
触发断点就能调试了
end