zl程序教程

您现在的位置是:首页 >  硬件

当前栏目

内核知识第四讲,简单的认识内核函数.以及调试驱动技巧

驱动内核调试 函数 简单 技巧 以及 知识
2023-09-27 14:21:05 时间

        内核知识第四讲,简单的认识内核函数.以及调试驱动技巧

 

一丶驱动调试技巧.

我们写好的内核驱动代码要怎么调试?

1.自己内联汇编 进行调试

2.调用内核驱动调试API.

一丶内联汇编进行调试

内联汇编进行调试.

代码如下.

#include <Ntddk.h> //编写内核驱动需要包含NTddk头文件.


//卸载回调函数
VOID Unload(__in struct _DRIVER_OBJECT  *DriverObject)
{
  DbgPrint("Unload MyDrive\n");
}

NTSTATUS DriverEntry(__in struct _DRIVER_OBJECT  *DriverObject,
                      __in PUNICODE_STRING  RegistryPath)
{
    int i = 0;
     
    DbgPrint("HelloWorld, %p\r\n",&i);
    
    __asm int 3    //内联汇编,让自己的汇编代码在此处暂停.
    //注册一下驱动卸载的函数
    DriverObject->DriverUnload = Unload;

    return STATUS_SUCCESS;
}

int 3则是产生一个断点,请注意,一定要配合WinDbg进行调试,也就是双机调试,否则这条代码则会蓝屏.

2.内核断点API进行调试

VOID   NTAPI  DbgBreakPoint( VOID );

只要在我们的驱动代码中加入这一行则可以进行断点调试的

在WinDbg中,本质还是调用int 3指令.

如果我们要发布Release版本,但是又担心我们的断点没有去掉怎么办?

加上条件宏.

微软也意思到了这个问题,所以提供了一个API. 这个API的本质还是调用 DbgBreakePoint.

只不过加了条件宏.

VOID NTAPI  KdBreakPoint( VOID  );

有兴趣的跟进去可以看,本质还是我们上面的API,只不过用条件宏包了一下.

二丶内核中的内核函数简单介绍.

如果我们编写内核驱动程序.那么内核函数是我们常用的接口.那么我们要熟悉一下内核函数的意义.

图示:

在内核帮助文档中,我们可以看到操作系统提供了很多API,且它们都有一致性.

ob开头的API: 一般是对象使用,操作系统是C和汇编写的,但是用的却是面向对象设计,比如进程.还有引用计数等等.所以需要调用这种API.

Mm开头的API: Mm开头的API,都是内存管理的API,比如锁定一块内存,不让其与磁盘交换数据等等.

Ps开头的API: ps开头的API,一般都是管理进程和线程的API,比如psGetCurrentProcessId,获得当前进程ID.

Io开头的API: Io开头的API一般就是负责IO操作的.如果写硬件驱动则不用管这些.直接使用in 或者out进行操作.

Po开头的API: Po开头的API一般就是管理电源的API.对于写内核驱动的我们,不关心这些.写硬件驱动的则要关心,比如通电了.硬件驱动需要做些初始化什么的.

Cm开头的API: Cm开头的API一般是注册表常用的API.

Zw开头的API: Zw开头的API,一般是内核版本的API,比如三环有CreateFile,那么在内核API中则是ZwCreateFile.

 

Ke开头API: ke开头的API,一般是内核层的API.在内核中,分为内核层还有执行层.

Ex开头的API: Ex开头的API,则是执行层的API.

Rtl开头的API :  Rtl开头的Api和C库函数很像,在驱动中可以使用C库函数,但是微软不建议使用.所以提供了Rtl开头的API,甚至比C库函数还多.

DMA开头的API: 一般是写硬件驱动用的,我们不用.

HAL开头的API: 操作硬件抽象层的API.

ZwXXX系列的API: 这个意思就是参考ring3下的API,一般ring3下是什么,那么对应的加上个Zw开头即可.注意,Zw开头的参数不一定和Ring3下的API参数相同.