windows驱动学习笔记

零零散散花了一个月的时间初步学习了windows驱动编程,接着开始要制定2013年的学习计划,即将步入另外一个学习战场,于是就将最近学习记录下来,也好将来再返回学习时有点基础。

一、windows驱动安装

1、到官方下载DDK安装,ex : 3790.1830.DDK

2、目录简介 

      示例代码: 安装目录/src/general/event/sys

      编译:build

      基本文件:源文件,sources, makefile

     

二、VC6 驱动设置

1、 Tools->Options->Directories->Executable files->新建   ...\3790.1830\BIN\X86 移到最上边

       Tools->Options->Directories->Include files->新建  ...\3790.1830\INC\CRT

       Tools->Options->Directories->Include files->新建  ...\3790.1830\INC\DDK\WXP

       Tools->Options->Directories->Include files->新建  ...\3790.1830\INC\WXP

       Tools->Options->Directories->Include files->新建  ...\3790.1830\INC\DDK\WDM\WXP

       Tools->Options->Directories->Library files->新建  ...\3790.1830\LIB\WXP\I386

2、编译设置:适用于NT驱动,WDM驱动

       Project->Configurations->Add... 新建编译选项

       Project->Setting->C/C++->Project Options

       /nologo /Gz /MLd /WZ /WX /Z7 /Od /D WIN32=100 /D _X86_=1 /D WINVER=0x501 /D DBG=1 /Fo "ddk_check1" /Fd "ddk_check1" /FD /c

       Project->Setting->Link->Project Options

       wdm.lib ntoskrnl.lib /nologo /base:"0x10000" /stack:0x400000,0x1000

       /entry:"DriverEntry" /subsystem:console /incremental=no

       /pdb:"ddk_check/event.pdb" /debug /machine:I386

       /nodefaultlib  /out:"ddk_check/event.sys"  /subsystem:native

       /driver   /SECTION:INIT,D  /RELEASE   /IGNORE:4078


三、VS2003设置

一、配置移到最上面 

        工具->选项-》项目-》VC++目录-》包含文件-》新建...  3790.1830\inc\crt

       工具->选项-》项目-》VC++目录-》包含文件-》新建...  3790.1830\inc\ddk\wxp

       工具->选项-》项目-》VC++目录-》包含文件-》新建...  3790.1830\inc\wxp

       工具->选项-》项目-》VC++目录-》包含文件-》新建...  3790.1830\inc\ddk\wdm\wxp

       工具->选项-》项目-》VC++目录-》库文件-》新建  ...3790.1830\Bin\x86

       工具->选项-》项目-》VC++目录-》可执行文件-》新建  ...3790.1830\Bin\x86


       项目-》event属性-》配置管理器-》项目上下文-》新建项目配置    + "check"

       项目-》event属性-》配置属性-》C/C++-》常规-》调试信息格式@c7

       项目-》event属性-》配置属性-》C/C++-》常规-》警告等级@wz

       项目-》event属性-》配置属性-》C/C++-》预处理器: WIN32=100;_X86_=1, WINVER=0X501; DBG=1

       项目-》event属性-》配置属性-》C/C++-》代码生成-》运行时库 @多线程

       项目-》event属性-》配置属性-》C/C++-》代码生成-》缓冲区安全检查 @否

       项目-》event属性-》配置属性-》C/C++-》高级-》调用约定 @__stdcall   

       项目-》event属性-》链接器-》常规-》输出文件 @.sys

       项目-》event属性-》链接器-》输入-》附加依赖项@wdm.lib

       项目-》event属性-》高级-》入口点 @DriverEntry

       项目-》event属性-》高级-》基址@ 0x10000


四、驱动编写
DDK_HelloWorld书写
int DriverEntry( PDRIVER_OBJECT,    PUNICODE_STRING)
头文件  #include <ntddk.h>
makefile  固定格式:
    !INCLUDE $(NTMAKEENV)\makefile.def
sources文件:
     TARGETNAME=
     TARGETTYPE=
     TARGETPATH=
     INCLUDES=
    SOURCES=
编译:build -C
#include <ntddk.h>
#define INITCODE code_seg("INIT")
#pragma  INITCODE
VOID DDK_Unload (IN PDRIVER_OBJECT pDriverObject); //前置说明 卸载例程
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING B) //TYPEDEF LONG NTSTATUS
{
    KdPrint(("驱动成功被加载...OK++++++++"));
    pDriverObject->DriverUnload = DDK_Unload;
    return (1);
}
VOID DDK_Unload (IN PDRIVER_OBJECT pDriverObject)
{
    KdPrint(("驱动成功被卸载...OK-----------")); //sprintf,printf
    DbgPrint("卸载成功");
}

五、原理介绍

windows API:   user函数、gdi函数、kernel函数

user32.dll          管理窗口、菜单、对话框和控件

gdi32.dll             在物理设备上执行绘图操作

kernel32.dll       进程、线程、文件和同步服务

MFC库:在应用程序和win32子系统中间加了一层封装

SSDT:       system service descriptor table 把ring3的win32 api 和ring0的内核api联系起来

应用层到内核层:

OpenProcess   xx.dll->kernel32.OpenProcess->NtOpenProcess->ntdll.ZwOpenProcess->ntdll.KiFastSystemCall    // eax参数+SSDT表

sysenter指令切换到内核

保护原理:inline hook这些API函数

内核:ntkrnlpa.ZwOpenProcess -> SSDT ->ntkrnlpa.NtOpenProcess

kernel32.dll  -> SSDT

user32.dll  gdi32.dll  -> shadow SSDT -> win32k.sys


六、添加设备驱动例程 

//_stdcall
#include <ntddk.h>
#define INITCODE code_seg("INIT")
#define PAGECODE code_seg("PAGE") /*表示内存不足时,可以被置换到硬盘*/
#pragma INITCODE /*指的代码运行后 就从内存释放掉*/
NTSTATUS CreateMyDevice (IN PDRIVER_OBJECT pDriverObject)
{
    NTSTATUS status;
    PDEVICE_OBJECT pDevObj;/*用来返回创建设备*/

    //创建设备名称
    UNICODE_STRING devName;
    UNICODE_STRING symLinkName; //
    RtlInitUnicodeString(&devName, L"\\Device\\yjxDDK_Device"); /*对devName初始化字串为 "\\Device\\yjxDDK_Device"*/

    //创建设备
    status = IoCreateDevice( pDriverObject, \
                             0, \
                             &devName, \
                             FILE_DEVICE_UNKNOWN, \
                             0, TRUE, \
                             &pDevObj);
    if (!NT_SUCCESS(status))
    {
        if (status == STATUS_INSUFFICIENT_RESOURCES)
        {
            KdPrint(("资源不足 STATUS_INSUFFICIENT_RESOURCES"));
        }
        if (status == STATUS_OBJECT_NAME_EXISTS )
        {
            KdPrint(("指定对象名存在"));
        }
        if (status == STATUS_OBJECT_NAME_COLLISION)
        {
            KdPrint(("//对象名有冲突"));
        }
        KdPrint(("设备创建失败...++++++++"));
        return status;
    }
    KdPrint(("设备创建成功...++++++++"));

    pDevObj->Flags |= DO_BUFFERED_IO;
    //创建符号链接

    RtlInitUnicodeString(&symLinkName, L"\\??\\yjx888");
    status = IoCreateSymbolicLink( &symLinkName, &devName );
    if (!NT_SUCCESS(status)) /*status等于0*/
    {
        IoDeleteDevice( pDevObj );
        return status;
    }
    return STATUS_SUCCESS;
}
#pragma  INITCODE
VOID DDK_Unload (IN PDRIVER_OBJECT pDriverObject); //前置说明 卸载例程
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING B) //TYPEDEF LONG NTSTATUS
{
    KdPrint(("驱动成功被加载...OK++++++++"));
    //jmp指令
    CreateMyDevice(pDriverObject);
    pDriverObject->DriverUnload = DDK_Unload;
    return (1);
}
VOID DDK_Unload (IN PDRIVER_OBJECT pDriverObject)
{
    KdPrint(("驱动成功被卸载...OK-----------")); //sprintf,printf
    //删掉所有设备
    DbgPrint("卸载成功");
}

七、WinDBG安装

1、在调试目标机上创建串口设备,创建命名管理 \\.\ipip\com_1

2、主机增加winddbg快捷方式,在windbg属性的目标里添加参数:-b -k com:pipe, port=\\.\pipe\com1, baud=115200, reconnect -y

3、被调试机boot.ini中添加一行:  /fastdetect /debug /debugport=com1 /baudrate=115200

4、windgb调试命令

代码中断点加:__asm  int 3;

命令: 

G  运行

U  汇编

F8, F11

F10  步过

shift + F11 跳出,返回到上层call执行

bp 下断点

bl   断点列表

bd / be  断点禁用启用

bc  清除断点

a  修改汇编代码


八、添加默认派遣例程

IRP : IO Request Package

用户模式下所有对驱动程序的IO请求,全部由OS转化为IRP数据结构,不同IRP派遣到不同派遣函数中。

常用IRP:

IRP_MJ_CREATE  

IRP_MJ_CLOSE

IRP_MJ_READ

IRP_MJ_WRITE

IRP_MJ_DEVICE_CONTROL

过程:

1、创建IRP处理函数

2、在驱动入口DriverEntry注册IRP处理函数

3、编写IRP处理函数

//_stdcall
#include "mini_ddk.h"
#pragma  INITCODE
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING B) //TYPEDEF LONG NTSTATUS
{
    KdPrint(("驱动成功被加载...OK++++++++"));
    //注册派遣函数
    pDriverObject->MajorFunction[IRP_MJ_CREATE] = ddk_DispatchRoutine_CONTROL; //IRP_MJ_CREATE相关IRP处理函数
    pDriverObject->MajorFunction[IRP_MJ_CLOSE] = ddk_DispatchRoutine_CONTROL; //IRP_MJ_CREATE相关IRP处理函数
    pDriverObject->MajorFunction[IRP_MJ_READ] = ddk_DispatchRoutine_CONTROL; //IRP_MJ_CREATE相关IRP处理函数
    pDriverObject->MajorFunction[IRP_MJ_CLOSE] = ddk_DispatchRoutine_CONTROL; //IRP_MJ_CREATE相关IRP处理函数
    pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ddk_DispatchRoutine_CONTROL; //IRP_MJ_CREATE相关IRP处理函数
    CreateMyDevice(pDriverObject);//创建相应的设备
    pDriverObject->DriverUnload = DDK_Unload;
    return (1);
}
//#pragma code_seg("PAGE")
#pragma PAGECODE
VOID DDK_Unload (IN PDRIVER_OBJECT pDriverObject)
{
    PDEVICE_OBJECT pDev;//用来取得要删除设备对象
    UNICODE_STRING symLinkName; //

    pDev = pDriverObject->DeviceObject;
    IoDeleteDevice(pDev); //删除设备

    //取符号链接名字
    RtlInitUnicodeString(&symLinkName, L"\\??\\yjx888");
    //删除符号链接
    IoDeleteSymbolicLink(&symLinkName);
    KdPrint(("驱动成功被卸载...OK-----------")); //sprintf,printf
    //取得要删除设备对象
    //删掉所有设备
    DbgPrint("卸载成功");
}
#pragma PAGECODE
NTSTATUS ddk_DispatchRoutine_CONTROL(IN PDEVICE_OBJECT pDevobj, IN PIRP pIrp	)
{
    //对相应的IPR进行处理
    pIrp->IoStatus.Information = 0; //设置操作的字节数为0,这里无实际意义
    pIrp->IoStatus.Status = STATUS_SUCCESS; //返回成功
    IoCompleteRequest(pIrp, IO_NO_INCREMENT); //指示完成此IRP
    KdPrint(("离开派遣函数\n"));//调试信息
    return STATUS_SUCCESS; //返回成功
}

九、保护理论知识

如何知道函数被HOOK?

工具Kernel Detective -》系统服务描述表-》查看函数对应“当前地址”与“源地址”是否相等-》转入反汇编-》修改汇编

SSDT结构:

typedef struct ServiceDescriptorTable 
{
    PVOID ServiceTableBase;
    PVOID ServiceCounterTable(0);
    unsigned int NumberOfServices;
    PVOID ParamTableBase;
} 

符号表:windbg中查看

srv *D:\winddk\symbols* http://msdl.microsoft.com/download/symbols

dd [KeServiceDescriptorTable]

dd poi[KeServiceDescriptorTable]

dd poi[KeServiceDescriptorTable]  + 0x17 * 4 

由SSDT索引号获取当前函数地址:[[KeServiceDescriptorTable] + index * 4 ]

如何获取索引号:

1、Kernel Detective 工具

2、OllDbg 断点看索引号

获取函数源地址: MmGetSystemRoutineAddress

读SSDT表当前函数地址:
法一:
extern long KeServiceDescriptorTable;
__asm {
    push ebx
    push eax
    mov ebx, KeServiceDescriptorTable
    mov ebx, [ebx]
    mov eax, 0x7a
    imul eax, eax, 4
    add ebx, eax
    mov ebx, [ebx]
    mov NtOpenProcess_Addr, ebx
    pop eax
    pop ebx
}
法二:
extern pServiceDescriptorTable KeServiceDescriptorTable;
ULONG GetNt_CurAddr() 
{
    t_addr = (LONG)KeServiceDescriptorTable->ServiceTableBase;
    SSDT_addr = (PLONG)(t_addr + 0x7a * 4);
    SSDT_NtOpenProcess_Cur_Addr = *SSDT_addr;
    return SSDT_NtOpenProcess_Cur_Addr;
}
获取系统原始NtOpenProcess地址
ULONG GetNt_OldAddr()
{
    UNICODE_STRING Old_NtOpenProcess;
    RtlInitUnicodeString(&Old_NtOpenProcess, L"NoOpenProcess");
    ULONG Old_Addr;
    Old_Addr = (ULONG) MmGetSystemRoutineAddress(&Old_NtOpenProcess);
    KdPrint(("Old Addr is %u", Old_Addr);
}

被HOOK:GetNt_CurAddr() != GetNt_OldAddr()

十、NT式驱动加载和缷载
void CLoadsysDlg::OnButtonLoadsys()
{
    // TODO: Add your control notification handler code here
    CFileDialog sysFile(true, NULL, NULL, 0, "驱动文件sys|*.sys|所有文件|*.*|");
    if (IDOK == sysFile.DoModal())
    {
        m_syspathname = sysFile.GetPathName();
        m_syspathname = sysFile.GetFileName();
        DriverName = sysFile.GetFileName();
        UpdateData(false);
        //LoadNtDriver;
        LoadNTDriver(sysFile.GetFileName().GetBuffer(256), sysFile.GetPathName().GetBuffer(256));
    }

}
/*
BOOL LoadNTDriver(char* lpszDriverName, char* lpszDriverPathName)
{
	BOOL bRet=false;
	SC_HANDLE hServiceDDK=NULL;
//   	A、OpenSCManager
       SC_HANDLE hServiceMgr=OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
	   if (hServiceMgr==NULL)
	   {
		   TRACE("OpenSCManager 调用失败");
		   goto BExit;
	   }
//		B、CreateService
   hServiceDDK= CreateService( hServiceMgr,//SCM管理器句柄
		   lpszDriverName, //驱动程序的在注册表中的名字
		   lpszDriverName, // 注册表驱动程序的 DisplayName 值
		   SERVICE_ALL_ACCESS, // 加载驱动程序的访问权限
		   SERVICE_KERNEL_DRIVER,// 表示加载的服务是驱动程序
		   SERVICE_DEMAND_START, // 注册表驱动程序的 Start 值
		   SERVICE_ERROR_IGNORE, // 注册表驱动程序的 ErrorControl 值
		   lpszDriverPathName, // 注册表驱动程序的 ImagePath 值
		   NULL,              //要开启服务的 用户组
		   NULL,  //输出验证标签
		   NULL,   //所依赖的服务的名称
		   NULL,   //用户账户名称
		   NULL);  //用户口令
//		C、OpenService
   if (hServiceDDK==NULL)
   {   TRACE("CreateService 失败,继续调用OpenService");
	   hServiceDDK=OpenService(hServiceMgr,lpszDriverName,SERVICE_ALL_ACCESS);
      if (hServiceDDK==NULL)
	  {   TRACE("OpenService 失败");
		  goto BExit;
	  }
   }
//		D、StartService
   StartService(hServiceDDK,NULL,NULL);

//      E、CloseServiceHandle
BExit:
	//CloseServiceHandle
	//CloseServiceHandle
	   return bRet;
} */

BOOL LoadNTDriver(char *lpDriverName, char *lpDriverPathName)
{
    BOOL bRet = FALSE;

    SC_HANDLE hServiceMgr = NULL; //SCM管理器的句柄
    SC_HANDLE hServiceDDK = NULL; //NT驱动程序的服务句柄

    //打开服务控制管理器
    hServiceMgr = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );

    if( hServiceMgr == NULL )
    {
        //OpenSCManager失败
        TRACE( "OpenSCManager() Faild %d ! \n", GetLastError() );
        bRet = FALSE;
        goto BExit;
    }
    else
    {
        OpenSCManager成功
        TRACE( "OpenSCManager() ok ! \n" );
    }

    //创建驱动所对应的服务
    hServiceDDK = CreateService( hServiceMgr,
                                 lpDriverName, //驱动程序的在注册表中的名字
                                 lpDriverName, // 注册表驱动程序的 DisplayName 值
                                 SERVICE_ALL_ACCESS, // 加载驱动程序的访问权限
                                 SERVICE_KERNEL_DRIVER,// 表示加载的服务是驱动程序
                                 SERVICE_DEMAND_START, // 注册表驱动程序的 Start 值
                                 SERVICE_ERROR_IGNORE, // 注册表驱动程序的 ErrorControl 值
                                 lpDriverPathName, // 注册表驱动程序的 ImagePath 值
                                 NULL,
                                 NULL,
                                 NULL,
                                 NULL,
                                 NULL);

    DWORD dwRtn;
    //判断服务是否失败
    if( hServiceDDK == NULL )
    {
        dwRtn = GetLastError();
        if( dwRtn != ERROR_IO_PENDING && dwRtn != ERROR_SERVICE_EXISTS )
        {
            //由于其他原因创建服务失败
            TRACE( "CrateService() 失败 %d ! \n", dwRtn );
            bRet = FALSE;
            goto BExit;
        }
        else
        {
            //服务创建失败,是由于服务已经创立过
            TRACE( "CrateService() 服务创建失败,是由于服务已经创立过 ERROR is ERROR_IO_PENDING or ERROR_SERVICE_EXISTS! \n" );
        }

        // 驱动程序已经加载,只需要打开
        hServiceDDK = OpenService( hServiceMgr, lpDriverName, SERVICE_ALL_ACCESS );
        if( hServiceDDK == NULL )
        {
            //如果打开服务也失败,则意味错误
            dwRtn = GetLastError();
            TRACE( "OpenService() 失败 %d ! \n", dwRtn );
            bRet = FALSE;
            goto BExit;
        }
        else
        {
            TRACE( "OpenService() 成功 ! \n" );
        }
    }
    else
    {
        TRACE( "CrateService() 成功 ! \n" );
    }

    //开启此项服务
    bRet = StartService( hServiceDDK, NULL, NULL );
    if( !bRet )  //开启服务不成功
    {
        TRACE( "StartService() 失败 服务可能已经开启%d ! \n", dwRtn );
    }
    bRet = TRUE;
    //离开前关闭句柄
BExit:
    if(hServiceDDK)
    {
        CloseServiceHandle(hServiceDDK);
    }
    if(hServiceMgr)
    {
        CloseServiceHandle(hServiceMgr);
    }
    return bRet;
}
//卸载驱动程序
BOOL UnLoadSys( char *szSvrName )
{
    //一定义所用到的变量
    BOOL bRet = FALSE;
    SC_HANDLE hSCM = NULL; //SCM管理器的句柄,用来存放OpenSCManager的返回值
    SC_HANDLE hService = NULL; //NT驱动程序的服务句柄,用来存放OpenService的返回值
    SERVICE_STATUS SvrSta;
    //二打开SCM管理器
    hSCM = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
    if( hSCM == NULL )
    {
        //带开SCM管理器失败
        TRACE( "OpenSCManager() Faild %d ! \n", GetLastError() );
        bRet = FALSE;
        goto BeforeLeave;
    }
    else
    {
        //打开SCM管理器成功
        TRACE( "OpenSCManager() ok ! \n" );
    }
    //三打开驱动所对应的服务
    hService = OpenService( hSCM, szSvrName, SERVICE_ALL_ACCESS );

    if( hService == NULL )
    {
        //打开驱动所对应的服务失败 退出
        TRACE( "OpenService() Faild %d ! \n", GetLastError() );
        bRet = FALSE;
        goto BeforeLeave;
    }
    else
    {
        TRACE( "OpenService() ok ! \n" );  //打开驱动所对应的服务 成功
    }
    //四停止驱动程序,如果停止失败,只有重新启动才能,再动态加载。
    if( !ControlService( hService, SERVICE_CONTROL_STOP , &SvrSta ) )
    {
        TRACE( "用ControlService() 停止驱动程序失败 错误号:%d !\n", GetLastError() );
    }
    else
    {
        //停止驱动程序成功
        TRACE( "用ControlService() 停止驱动程序成功 !\n" );
    }
    //五动态卸载驱动服务。
    if( !DeleteService( hService ) )  //TRUE//FALSE
    {
        //卸载失败
        TRACE( "卸载失败:DeleteSrevice()错误号:%d !\n", GetLastError() );
    }
    else
    {
        //卸载成功
        TRACE ( "卸载成功 !\n" );

    }
    bRet = TRUE;
    //六 离开前关闭打开的句柄
BeforeLeave:
    if(hService > 0)
    {
        CloseServiceHandle(hService);
    }
    if(hSCM > 0)
    {
        CloseServiceHandle(hSCM);
    }
    return bRet;
}

void CLoadsysDlg::OnButtonUnloadsys()
{
    // TODO: Add your control notification handler code here
    //卸载驱动程序
    UnLoadSys(DriverName.GetBuffer(256))  ;
}

驱动代码中C++代码编译问题:
1、声明 extern "C" PServiceDescriptorTable  KeServiceDescriptorTable;
      extern "C" NTSTATUS DriverEntry(...)
2、预编译
#pragma once
#ifdef __cplusplus
extern "C"
{
#endif 
#include <NTDDK.h>
#ifdef __cpluspus
}
#endif

十一、应用程序与驱动交互访问
交换过程:
1、用户层传入数据 
2、驱动层接收数据
3、驱动层回传数据

用户层缓冲模式实现:
#include<winioctl.h> //CTL_CODE
#define add_code CTL_CODE(FILE_DEVICE_UNKNOWN, 	0x800, 	METHOD_BUFFERED,FILE_ANY_ACCESS)
#define sub_code CTL_CODE(FILE_DEVICE_UNKNOWN, 	0x801, 	METHOD_BUFFERED,FILE_ANY_ACCESS)

int add(HANDLE hDevice, int a, int b)
{

    int port[2];
    int bufret;
    ULONG dwWrite;
    port[0] = a;
    port[1] = b;

    DeviceIoControl(hDevice, add_code , &port, 8, &bufret, 4, &dwWrite, NULL);
    return bufret;

}

int main(int argc, char *argv[])
{
    //add
    //CreateFile 打开设备 获取hDevice
    HANDLE hDevice =
        CreateFile("\\\\.\\My_DriverLinkName", //\\??\\My_DriverLinkName
                   GENERIC_READ | GENERIC_WRITE,
                   0,		// share mode none
                   NULL,	// no security
                   OPEN_EXISTING,
                   FILE_ATTRIBUTE_NORMAL,
                   NULL );		// no template
    printf("start\n");
    if (hDevice == INVALID_HANDLE_VALUE)
    {
        printf("获取驱动句柄失败: %s with Win32 error code: %d\n", "MyDriver", GetLastError() );
        getchar();
        return -1;
    }
    int a = 55;
    int b = 33;
    int r = add(hDevice, a, b);
    printf("%d+%d=%d \n", a, b, r);
    getchar();
    return 0;
}

内核层缓冲模式实现:
#pragma PAGECODE
NTSTATUS ddk_DispatchRoutine_CONTROL(IN PDEVICE_OBJECT pDevobj, IN PIRP pIrp	)
{
    //
    ULONG info;
    //得到当前栈指针
    PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
    ULONG mf = stack->MajorFunction; //区分IRP
    switch (mf)
    {
    case IRP_MJ_DEVICE_CONTROL:
    {
        KdPrint(("Enter myDriver_DeviceIOControl\n"));
        NTSTATUS status = STATUS_SUCCESS;

        //得到输入缓冲区大小
        ULONG cbin = stack->Parameters.DeviceIoControl.InputBufferLength;
        //得到输出缓冲区大小
        ULONG cbout = stack->Parameters.DeviceIoControl.OutputBufferLength;
        //得到IOCTL码
        ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;
        switch (code)
        {
        case add_code:
        {
            int a, b;
            KdPrint(("add_code 1111111111111111111\n"));
            //缓冲区方式IOCTL
            //获取缓冲区数据	a,b
            int *InputBuffer = (int *)pIrp->AssociatedIrp.SystemBuffer;
            _asm
            {
                mov eax, InputBuffer
                mov ebx, [eax]
                mov a, ebx
                mov ebx, [eax+4]
                mov b, ebx
            }
            KdPrint(("a=%d,b=%d \n", a, b));

            a = a + b;
            //C、驱动层返回数据至用户层
            //操作输出缓冲区
            int *OutputBuffer = (int *)pIrp->AssociatedIrp.SystemBuffer;
            _asm
            {
                mov eax, a
                mov ebx, OutputBuffer
                mov [ebx], eax //bufferet=a+b

            }
            KdPrint(("a+b=%d \n", a));

            //设置实际操作输出缓冲区长度
            info = 4;
            break;
        }
        case sub_code:
            {
                break;
            }
            }//end code switch
        break;
    }

    //对相应的IPR进行处理
    pIrp->IoStatus.Information = info; //设置操作的字节数为0,这里无实际意义
    pIrp->IoStatus.Status = STATUS_SUCCESS; //返回成功
    IoCompleteRequest(pIrp, IO_NO_INCREMENT); //指示完成此IRP
    KdPrint(("离开派遣函数\n"));//调试信息
    return STATUS_SUCCESS; //返回成功
}

十二、一些理论知识
windows驱动程序  VS 进程
1、驱动可看成特殊DLL库,内核地址,可访问4GB地址
2、驱动不同例程运行于不同的进程中
DriverEntry是运行于系统(system)进程中。
其他例程IRP_MJ_*运行于某个进程的环境中,所能访问的只是该进程的虚拟地址空间。

分页内存与非分页内存
分页内存:可交换到文件中
非分页内存:永远不会交换到文件中
#define INIT code_seg("INIT")     // 使用一次释放
#define PAGECODE code_seg("PAGE") // 表示内存不足可置换到硬盘
#define PAGEDATA data_seg("PAGE") // 定义数据和变量
中断请求在DISPATCH_LEVEL及之上程序只能使用非分页内存,否则蓝屏

内存管理相关API
1、RtlCopyMemory, RtlCopyBytes, RltMoveMemory
2、RtlZeroMemory, RtlFillMemory
3、RtlEqualMemory, RtlCompareMemory
4、ExAllocatePool, ExFreePool, NonPagedPool, PagedPool

内核模式下字串操作:
1、ANSI, UNICODE
char *s1 = "abc";
KdPrint(("%s", s1));
wchar_t *s2 = L"abc";
KdPrint(("%S, s2));
2、ANSI_STRING  UNICODE_STRING
ANSI_STRING s1;
KdPrint(("%Z", s1));
UNICODE_STRING s2;
KdPrint(("%wZ", s2));
3、RtlInitAnsiString,  RtlInitUnicodeString
4、RtlCopyUnicodeString,  RtlEqualUnicodeString
5、RtlUnicodeStringToAnsiString 

文件操作:
1、RtlInitUnicodeString
2、InitializeObjectAttribute
3、ZwCreateFile  ZwOpenFile
4、ZwReadFile  ZwWriteFile  ZwSetInformationFile
5、ZwCloseFile

十三、应用层HOOK
IAT:import address table
HOOKAPIPROXY
typedef struct 
{
    byte PushCode1;
    ULONG OrgAddr;
    byte PushCode2;
    ULONG NameAddr;
    byte JmpCode;
    ULONG JmpParam;
} *PHOOKAPIPROXY, HOOKAPIPROXY;
导入表遍历:
PVOID EnumAPI()  
{  
	PBYTE ImageBase;
	PIMAGE_THUNK_DATA r;   
	PIMAGE_NT_HEADERS pNtHeader;   
	PIMAGE_IMPORT_DESCRIPTOR pImport;   
	//取得DOS头基址
	ImageBase=(PBYTE)GetModuleHandle(NULL);//0x400000

	//PE头=ImageBase+[ImageBase+3c]
	pNtHeader = (PIMAGE_NT_HEADERS) (ImageBase + ((PIMAGE_DOS_HEADER) ImageBase)->e_lfanew);   

	//IMAGE_DIRECTORY_ENTRY_IMPORT值为1 表示import tabale

	pImport = (PIMAGE_IMPORT_DESCRIPTOR) 
	(ImageBase + pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);   

 	遍历整个 输入表 
	for (; pImport->Name; pImport++)   
	{      
		printf("导入模块:%s\n",ImageBase+pImport->Name);   
        	//遍历IAT信息  PIMAGE_THUNK_DATA基址
	 	for (r = (PIMAGE_THUNK_DATA) (ImageBase + pImport->FirstThunk); r->u1.Function; r++)   //枚举函数地址
		{  	if (Sleep==(PVOID)r->u1.Function)
			{   DWORD pSleep=(DWORD)(&r->u1.Function);
				__asm
				{
					mov ebx,pSleep /// mov ebx,0x42A190
					lea eax,mySleep
					mov [ebx],eax
		 
				}
			}
			printf("Function=%x \n", &(r->u1.Function));     			
		}   
	  
	}   
	return NULL;   
}   
  
int main(int argc, char* argv[])   
{   
    EnumAPI();
    Sleep(111);
    return 0;   
}  

应用层Hook示例:
#include <windows.h>
typedef   int   (__stdcall *MessageBox_type)(
						HWND hWnd,          // handle of owner window
						LPCTSTR lpText,     // address of text in message box
						LPCTSTR lpCaption,  // address of title of message box
						UINT uType          // style of message box
			   ) ;
MessageBox_type old_MessageBoxA;

#pragma pack(1)  
typedef struct _JMPCODE
{ 
	BYTE jmp;
	DWORD addr;

}JMPCODE,*PJMPCODE;

_declspec(naked) 
 VOID __stdcall my_MessageBox(
			   HWND hWnd,          // handle of owner window
			   LPCTSTR lpText,     // address of text in message box
			   LPCTSTR lpCaption,  // address of title of message box
			   UINT uType          // style of message box
			   ) 
{
	// old_MessageBoxA(hWnd,"Hook ok",lpCaption,uType);
	__asm
	{
		PUSH EBP
		MOV EBP,ESP 
	}
	 printf("取得参数 %x,%s,%s,%x\n",hWnd,lpText,lpCaption,uType);
	 __asm
	 {
		 mov ebx,old_MessageBoxA
	     add ebx,5
		

		 jmp ebx
	 }
	  printf("hook Error\n");

}


 VOID InLine_HookMessageBoxA()
 {       JMPCODE jcode;
	 //取得MessageBoxA函数当前地址
	 HMODULE h=LoadLibraryA("user32.dll");
         old_MessageBoxA=(MessageBox_type)(GetProcAddress(h,"MessageBoxA"));
	 //替换 jmp指令
	 jcode.jmp=0xe9;
	 jcode.addr=(DWORD)(&my_MessageBox)-(DWORD)(&MessageBoxA)-5;//目的地址-当前地址-5 //跳到my
	 old_MessageBoxA=&MessageBoxA;
	 WriteProcessMemory(GetCurrentProcess(),&MessageBoxA,&jcode,sizeof(JMPCODE),NULL);
	 CloseHandle(h);
 }

 int main(int argc, char* argv[])
 {
	 printf("Hello World!\n");
         InLine_HookMessageBoxA();
	 MessageBoxA(NULL,"333","222",MB_OK);
	 return 0;
 }

十四、内核层HOOK
#pragma PAGECODE
DWORD Get_KeServiceDescriptorTableShadow_Addr()
{
    DWORD KeServiceDescriptorTableShadow = 0;
    DWORD Version = GetVersion();
    switch (Version  )
    {
    case VERSION_2K:
        KeServiceDescriptorTableShadow = (DWORD)KeServiceDescriptorTable + 0xE0;
        break;
    case VERSION_2K3:
        break;
    case VERSION_XP:
        KeServiceDescriptorTableShadow = (DWORD)KeServiceDescriptorTable - 0x40;
        break;
    default:
        break;

    }
    return KeServiceDescriptorTableShadow;

}
#pragma PAGECODE
VOID Show_SSDTShadowList()
{
    KdPrint(("Entry  Show_SSDTShadowList \n"));

    DWORD TableBase = Get_KeServiceDescriptorTableShadow_Addr();
    TableBase = TableBase + 0x10; //表基址
    DWORD TableCount = TableBase + 8; //表函数 数量


    DWORD count = *((PDWORD)TableCount); //函数数量
    KdPrint(("SSDT_Shadow Base=%x Count=%x\n", TableBase, count));
    //__asm  int 3
    PDWORD CFun_Addr = PDWORD(TableBase); //+=355
    CFun_Addr = PDWORD(*CFun_Addr);
    for (DWORD i = 0; i < count; i++)
    {
        KdPrint(("\n %d=%x\n", i, *CFun_Addr ));
        CFun_Addr++;
        //__asm int 3

    }

}
HWND myh;
typedef BOOL (__stdcall *PNtUserDestroyWindow)(HWND hwnd);
PNtUserDestroyWindow Old_NtUserDestroyWindow, Cur_NtUserDestroyWindow;

#pragma PAGECODE
BOOL __stdcall My_NtUserDestroyWindow(HWND h)
{
    KdPrint(("h=%x \n", h));
    if (h == myh)
    {
        KdPrint(("被保护窗口h=%x \n", h));
        return FALSE;
    }
    else	return Old_NtUserDestroyWindow(h);
}


#pragma PAGECODE
VOID SSDT_HOOK_NtUserDestroyWindow() //355
{
    KdPrint(("Entry  Show_SSDTShadowList \n"));

    DWORD TableBase = Get_KeServiceDescriptorTableShadow_Addr();
    TableBase = TableBase + 0x10;
    DWORD TableCount = TableBase + 8;


    DWORD count = *((PDWORD)TableCount);
    KdPrint(("SSDT_Shadow Base=%x Count=%x\n", TableBase, count));
    //__asm  int 3
    PDWORD CFun_Addr = PDWORD(TableBase);
    CFun_Addr = PDWORD(*CFun_Addr);
    CFun_Addr += 355;
    Old_NtUserDestroyWindow = (PNtUserDestroyWindow)(*CFun_Addr);
    KdPrint(("\n NtUserDestroyWindow当前地址=%x,%x \n", CFun_Addr, *CFun_Addr));
    __asm //去掉页面保护
    {
        cli
        mov eax, cr0
        and eax, not 10000h //and eax,0FFFEFFFFh
        mov cr0, eax

    }

    *CFun_Addr = (DWORD)(&My_NtUserDestroyWindow);
    KdPrint(("\n NtUserDestroyWindow HOOK后地址=%x,%x \n", CFun_Addr, *CFun_Addr));

    __asm
    {
        mov     eax, cr0
        or     eax, 10000h
        mov     cr0, eax
        sti
    }

}



#pragma PAGECODE
VOID SSDT_UNHOOK_NtUserDestroyWindow() //335
{
    KdPrint(("Entry  Show_SSDTShadowList \n"));

    DWORD TableBase = Get_KeServiceDescriptorTableShadow_Addr();
    TableBase = TableBase + 0x10;
    DWORD TableCount = TableBase + 8;


    DWORD count = *((PDWORD)TableCount);
    KdPrint(("SSDT_Shadow Base=%x Count=%x\n", TableBase, count));
    //__asm  int 3
    PDWORD CFun_Addr = PDWORD(TableBase);
    CFun_Addr = PDWORD(*CFun_Addr);
    CFun_Addr += 355;
    __asm //去掉页面保护
    {
        cli
        mov eax, cr0
        and eax, not 10000h //and eax,0FFFEFFFFh
        mov cr0, eax

    }
    *CFun_Addr = (DWORD)(Old_NtUserDestroyWindow);


    __asm
    {
        mov     eax, cr0
        or     eax, 10000h
        mov     cr0, eax
        sti
    }
}

十五、绕过应用层HOOK
目的:脱离API函数直接调用,防止被调试断点跟踪 

以FindWindow示例:
#pragma pack(1)
typedef struct _UNICODE_STRING
{
    USHORT Length;
    USHORT MaximumLength;
    PWSTR  Buffer;

} UNICODE_STRING, *PUNICODE_STRING;
#pragma pack()
__declspec(naked)   void sysFastCall()
{
    __asm
    {
        //	7C92E510 >  8BD4          MOV EDX,ESP
        //7C92E512    0F34            SYSENTER
        mov edx, esp
        __emit 0x0f
        __emit 0x34
    }
}
/*
77D28285   .  FF75 18       PUSH DWORD PTR SS:[EBP+18]                    ;  0
77D28288   .  FF75 E8       PUSH DWORD PTR SS:[EBP-18]                    ;  PU_LCatipn
77D2828B   .  FF75 F8       PUSH DWORD PTR SS:[EBP-8]                     ;  NULL
77D2828E   .  FF75 0C       PUSH DWORD PTR SS:[EBP+C]                     ;  0
77D28291   .  FF75 08       PUSH DWORD PTR SS:[EBP+8]                     ;  0
77D28294   .  E8 13450000   CALL USER32.77D2C7AC                          ;  NtUserFindWindow


*/
__declspec(naked) HWND  __stdcall My_FindWindow(
    int p1,
    int p2,
    PUNICODE_STRING pu_classname,
    PUNICODE_STRING pu_catption,
    int p5)
{
    __asm
    {
        MOV EAX, 0x117A
        call sysFastCall
        RETN 0x14

    }
}


void CTest_APIDlg::OnBUTTONsysfind()
{
    // TODO: Add your control notification handler code here
    HWND h =::FindWindow(NULL, "计算器");
    ::SendMessage(h, WM_CLOSE, 0, 0);
}

void CTest_APIDlg::OnButtonMyFindwindow()
{
    // TODO: Add your control notification handler code here
    UNICODE_STRING pu_className, pu_Caption;
    typedef   (__stdcall * PRtlInitUnicodeString)( PUNICODE_STRING , PCWSTR  );
    PRtlInitUnicodeString  RtlInitUnicodeString;
    RtlInitUnicodeString = (PRtlInitUnicodeString)GetProcAddress(GetModuleHandle("ntdll.dll"), "RtlInitUnicodeString");
    RtlInitUnicodeString(&pu_className, L"SciCalc");
    RtlInitUnicodeString(&pu_Caption, L"计算器");
    HWND h = My_FindWindow(0, 0, &pu_className, &pu_Caption, 0);
    ::SendMessage(h, WM_CLOSE, 0, 0);
}

十六、内核HOOK
示例:保护指定ID的进程,防止被其他程序访问,HOOK NtOpenProcess函数。
#pragma once
#ifdef __cplusplus
extern "C"
{
#endif
#include <NTDDK.h> //这里包含需要用C方式编译的头文件

#ifdef __cplusplus
}
#endif
//#include <windef.h>

bool ssdthook_flag = false;
ULONG     RealNtOpenAddress;
HANDLE    MyPID;


// A、构建自己的内核函数(用来替换对应的内核函数)

// 定义一下NtOpenProcess的原型
extern "C"    typedef  NTSTATUS      __stdcall NTOPENPROCESS
(
    OUT PHANDLE ProcessHandle,


    IN ACCESS_MASK AccessMask,


    IN POBJECT_ATTRIBUTES ObjectAttributes,


    IN PCLIENT_ID ClientId


);
NTOPENPROCESS     *RealNtOpenProcess;

PEPROCESS  EP;

// 自定义的NtOpenProcess函数 ZwOpenProcess
#pragma PAGECODE
extern "C" NTSTATUS __declspec(naked) __stdcall MyNtOpenProcess(
    OUT     PHANDLE ProcessHandle,
    IN     ACCESS_MASK DesiredAccess,
    IN     POBJECT_ATTRIBUTES ObjectAttributes,
    IN     PCLIENT_ID ClientId )
{
    NTSTATUS     rc;
    HANDLE       PID;

    //KdPrint(("++++++++++++Entry MyNtOpenProcess int   ++++++++++++++\n"));

    //rc = (NTSTATUS)RealNtOpenProcess( ProcessHandle, DesiredAccess, ObjectAttributes, ClientId );

    if( (ClientId != NULL) )
    {
        PID = ClientId->UniqueProcess;
        KdPrint(( "------------------------- PID=%d--------------\n", (int *)PID ));

        // 如果是被保护的PID,则拒绝访问,并将句柄设置为空
        if(PID == MyPID)
        {
            KdPrint(("被保护进程 MyPID=%d \n", (int)MyPID));
            //调试输出 类似C语言的 Printf
            ProcessHandle = NULL; //这个是关键
            rc = STATUS_ACCESS_DENIED; //这个返回值
            //PsLookupProcessByProcessId((ULONG)PID,&EP);
            EP = PsGetCurrentProcess();
            KdPrint((" ACESS Process Name  --:%s--   \n", (PTSTR)((ULONG)EP + 0x174)));
            __asm
            {
                retn 0x10
            }


        }
    }
    __asm
    {
        int 3
        push    0C4h
        mov eax, RealNtOpenProcess //
        add eax, 5
        jmp eax

    }
    //return rc;
}

//HOOK 函数构建
#pragma PAGECODE
VOID Hook()
{
    ssdthook_flag = true; //设置被HOOK标志
    KdPrint(("++++HOOK START ++++-\n"));
    LONG *SSDT_Adr, SSDT_NtOpenProcess_Cur_Addr, t_addr;

    KdPrint(("驱动成功被加载中.............................\n"));
    //读取SSDT表中索引值为0x7A的函数
    //poi(poi(KeServiceDescriptorTable)+0x7a*4)
    t_addr = (LONG)KeServiceDescriptorTable->ServiceTableBase;
    SSDT_Adr = (PLONG)(t_addr + 0x7A * 4);

    SSDT_NtOpenProcess_Cur_Addr = *SSDT_Adr;
    RealNtOpenAddress = *SSDT_Adr;
    RealNtOpenProcess = ( NTOPENPROCESS *)RealNtOpenAddress;

    KdPrint(( "真实的NtOpenProcess地址: %x\n", (int) RealNtOpenAddress ));
    KdPrint((" 伪造NTOpenProcess地址: %x\n", (int)MyNtOpenProcess ));


    __asm //去掉页面保护
    {
        cli
        mov eax, cr0
        and eax, not 10000h //and eax,0FFFEFFFFh
        mov cr0, eax

    }

    //[804e5a88]=MyNtOpenProcess
    //[8058270a]=jmp MyNtOpenProcess=E9 jmpaddr
    ULONG jmpaddr = (ULONG)MyNtOpenProcess - RealNtOpenAddress - 5;
    SSDT_Adr = (PLONG) * SSDT_Adr; //SSDT HOOK jmp jz jnz
    // in line hook
    __asm
    {
        mov ebx, SSDT_Adr //RealNtOpenAddress
        mov byte ptr ds:[ebx], 0xe9
        mov eax, jmpaddr
        mov DWORD ptr ds:[ebx+1], eax
    }

    __asm
    {
        int 3
        mov     eax, cr0
        or     eax, 10000h
        mov     cr0, eax
        sti
    }
    return;
}

//UnHook函数构建
//
#pragma PAGECODE
VOID UnHook()
{
    ULONG Old_ssdt;
    Old_ssdt = (ULONG)KeServiceDescriptorTable->ServiceTableBase + 0x7A * 4;
    if    (ssdthook_flag)
    {
        ssdthook_flag = false;
        __asm
        {
            cli
            mov     eax, cr0
            and     eax, not 10000h
            mov     cr0, eax
        }

        // 还原SSDT
        *((ULONG *)Old_ssdt) = (ULONG)RealNtOpenAddress;

        __asm
        {
            mov     eax, cr0
            or     eax, 10000h
            mov     cr0, eax
            sti
        }
        KdPrint(("UnHook还原SSDT OK \n"));
    }

    return;
}

十七、IDT
反断点原理:
1、不能正常下断点(int 3)
2、正常下断点后,让他不能断下

typedef struct _IDTR
{
    USHORT limit;  // 范围
    ULONG base; // 基地址
}  IDTR, *PIDTR;

typdef struct _IDTR_ENTRY
{
    USHORT  offset_low;
    USHORT  selector;
    UCHAR   reserved;
    UCHAR   type:4;
    UCHAR   always0:1;
    UCHAR   dpl:2;
    UCHAR   present:1;
    USHORT  offset_high;  // 中断处理函数地址
} IDT_ENTRY, *PIDT_ENTRY;

读IDT表, sidt指令
IDTR idtr;
__asm sidt idtr;
PIDT_ENTRY aidt = PIDT_ENTRY(idtr.base);
for (int i = 0; i < 0xff; i++)
{
    ULONG cur_idt = aidt->offset_high;
    cur_idt = cur_idt << 16 + ULONG(aidt->offset_low);
    aidt++;
}
return idtr.base;

IDT HOOK实例:
#pragma pack(pop) //#pragma pack(pop)
//-----------全局变量--------------------------------
ULONG int3proc_addr; //用来存放int 3处理函数地址
ULONG jmpaddr_int3proc_9; //用来存放intproc+9处理函数地址
//-----------全局变量 定义结束-----------------------

#pragma PAGECODE
ULONG ReadIdtBase(ULONG CPUNUM)
{
    IDTR idtr;//获取表基址
    PIDT_ENTRY Aidt;
    KdPrint(("IDT_ENTRY size=%d \n", sizeof(IDT_ENTRY)));
    __asm sidt idtr;//获取表基址信息
    KdPrint(("IDT BASE=%x \n", idtr.base));
    Aidt = PIDT_ENTRY(idtr.base);
    return idtr.base;
}
void __declspec(naked)  int3UnHookcode()
{
    __asm
    {
        push    0
        mov     word ptr [esp+2], 0
    }
}


#pragma PAGECODE
void __declspec(naked)  myInt3Proc()
{
    //__asm retn 100;
    __asm
    {
        pushad
        pushfd
    }

    KdPrint(("\n entry my Int3Proc \n"));
    //在这里添加自己的条件过滤代码
    //获取进程上下文
    PEPROCESS EP;
    EP = PsGetCurrentProcess();
    // (PTSTR)((ULONG)EP+0x174)是否等于 需要反断点的进程
    if (strcmp((PTSTR)((ULONG)EP + 0x174), "notepad.exe") == 0)
    {
        //需要保护的进程 直接蓝屏
        KdPrint(("\n 蓝屏 蓝屏 蓝屏 \n"));
        __asm retn 100;
    }
    __asm
    {
        popfd
        popad
    }

    __asm
    {
        push 0
        mov word ptr [esp+2], 0
        //前2条需要恢复的指令 占9字节
        jmp jmpaddr_int3proc_9
    }
}


#pragma  PAGECODE
ULONG HookInt3Proc()
{

    ULONG status = 1;
    PIDT_ENTRY Pidt_info = (PIDT_ENTRY)ReadIdtBase(0);
    ULONG jmpaddr;

    Pidt_info += 3; //转到IDT 数组3 里边存放着 int 3 处理函数地址
    //Pidt_info=Pidt_info+sizeof(Pidt_info)*3;
    //begin计算出int3处理函数地址
    int3proc_addr = Pidt_info->offset_high << 16; //makelong 0x804d0000
    //MAKELONG(Pidt_info->offset_high,Pidt_info->offset_Slow) //0xfaa1 =804dfaa1
    int3proc_addr = int3proc_addr + Pidt_info->offset_low;
    KdPrint (("\n int proc addr=%x \n", int3proc_addr));
    //end;
    //begin inline hook int3Proc write
    // E9+jmp地址//jmp地址=myInt3Proc-int3proc_addr-5;
    jmpaddr = ULONG(&myInt3Proc) - int3proc_addr - 5;
    jmpaddr_int3proc_9 = int3proc_addr + 9;
    __asm
    {
        push ebx
        push eax
        mov ebx, int3proc_addr
        mov byte ptr ds:[ebx], 0xE9
        mov eax, jmpaddr
        mov dword ptr ds:[ebx+1], eax
        pop eax
        pop ebx
    }
    //end;inline hook int3proc write
    return status;
}


#pragma  PAGECODE
ULONG UnHookInt3Proc()
{
    ULONG status = 1;

    KdPrint(("\n 卸载 Idt Hook \n"));
    __asm
    {
        push ebx
        push eax
        push ecx

        mov ebx, int3proc_addr //0x804dfaa1
        lea ecx, int3UnHookcode

        mov eax, [ecx+0]
        mov dword ptr ds:[ebx], eax

        mov eax, [ecx+4]
        mov dword ptr ds:[ebx+4], eax

        mov eax, [ecx+8]
        mov byte ptr ds:[ebx+8], al
        pop ecx
        pop eax
        pop ebx
    }
    //end;inline hook int3proc write
    return status;
}


























  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值