谁给解释下这两句驱动代码 #pragma PAGECODE __declspec dllimport(naked)VOID My_NtReadVirtualMemory()

4.2.1 XX游戏驱动保护代码书写
-(49课)_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
4.2.1 XX游戏驱动保护代码书写
上传于||文档简介
&&郁金香驱动班学习笔记。 VC DDK 驱动 驱动保护 HOOK WINDBG OD CE
阅读已结束,如果下载本文需要使用1下载券
想免费下载本文?
定制HR最喜欢的简历
下载文档到电脑,查找使用更方便
还剩2页未读,继续阅读
定制HR最喜欢的简历
你可能喜欢windows驱动学习笔记 - 推酷
windows驱动学习笔记
零零散散花了一个月的时间初步学习了windows驱动编程,接着开始要制定2013年的学习计划,即将步入另外一个学习战场,于是就将最近学习记录下来,也好将来再返回学习时有点基础。
一、windows驱动安装
1、到官方下载DDK安装,ex : .DDK
2、目录简介&
& & & 示例代码: 安装目录/src/general/event/sys
& & & 编译:build
& & & 基本文件:源文件,sources, makefile
二、VC6 驱动设置
1、 Tools-&Options-&Directories-&Executable files-&新建 & ...\\BIN\X86 移到最上边
& & & &Tools-&Options-&Directories-&Include files-&新建 &...\\INC\CRT
& & & &Tools-&Options-&Directories-&Include files-&新建 &...\\INC\DDK\WXP
& & & &Tools-&Options-&Directories-&Include files-&新建 &...\\INC\WXP
& & & &Tools-&Options-&Directories-&Include files-&新建 &...\\INC\DDK\WDM\WXP
& & & &Tools-&Options-&Directories-&Library files-&新建 &...\\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:0xx1000
& & & &/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++目录-》包含文件-》新建... &\inc\crt
& & & &工具-&选项-》项目-》VC++目录-》包含文件-》新建... &\inc\ddk\wxp
& & & &工具-&选项-》项目-》VC++目录-》包含文件-》新建... &\inc\wxp
& & & &工具-&选项-》项目-》VC++目录-》包含文件-》新建... &\inc\ddk\wdm\wxp
& & & &工具-&选项-》项目-》VC++目录-》库文件-》新建 &...\Bin\x86
& & & &工具-&选项-》项目-》VC++目录-》可执行文件-》新建 &...\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&)
VOID DDK_Unload (IN PDRIVER_OBJECT pDriverObject); //前置说明 卸载例程
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING B) //TYPEDEF LONG NTSTATUS
KdPrint((&驱动成功被加载...OK++++++++&));
pDriverObject-&DriverUnload = DDK_U
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)
PDEVICE_OBJECT pDevO/*用来返回创建设备*/
//创建设备名称
UNICODE_STRING devN
UNICODE_STRING symLinkN //
RtlInitUnicodeString(&devName, L&\\Device\\yjxDDK_Device&); /*对devName初始化字串为 &\\Device\\yjxDDK_Device&*/
//创建设备
status = IoCreateDevice( pDriverObject, \
&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((&设备创建失败...++++++++&));
KdPrint((&设备创建成功...++++++++&));
pDevObj-&Flags |= DO_BUFFERED_IO;
//创建符号链接
RtlInitUnicodeString(&symLinkName, L&\\??\\yjx888&);
status = IoCreateSymbolicLink( &symLinkName, &devName );
if (!NT_SUCCESS(status)) /*status等于0*/
IoDeleteDevice( pDevObj );
return STATUS_SUCCESS;
VOID DDK_Unload (IN PDRIVER_OBJECT pDriverObject); //前置说明 卸载例程
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING B) //TYPEDEF LONG NTSTATUS
KdPrint((&驱动成功被加载...OK++++++++&));
CreateMyDevice(pDriverObject);
pDriverObject-&DriverUnload = DDK_U
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;
shift + F11 跳出,返回到上层call执行
bl & 断点列表
bd / be &断点禁用启用
bc &清除断点
a &修改汇编代码
八、添加默认派遣例程
IRP : IO Request Package
用户模式下所有对驱动程序的IO请求,全部由OS转化为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&
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_U
return (1);
//#pragma code_seg(&PAGE&)
#pragma PAGECODE
VOID DDK_Unload (IN PDRIVER_OBJECT pDriverObject)
PDEVICE_OBJECT pD//用来取得要删除设备对象
UNICODE_STRING symLinkN //
pDev = pDriverObject-&DeviceO
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-&rmation = 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 ServiceTableB
PVOID ServiceCounterTable(0);
unsigned int NumberOfS
PVOID ParamTableB
符号表:windbg中查看
srv *D:\winddk\symbols* /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 KeServiceDescriptorT
mov ebx, KeServiceDescriptorTable
mov ebx, [ebx]
mov eax, 0x7a
imul eax, eax, 4
add ebx, eax
mov ebx, [ebx]
mov NtOpenProcess_Addr, ebx
extern pServiceDescriptorTable KeServiceDescriptorT
ULONG GetNt_CurAddr()
t_addr = (LONG)KeServiceDescriptorTable-&ServiceTableB
SSDT_addr = (PLONG)(t_addr + 0x7a * 4);
SSDT_NtOpenProcess_Cur_Addr = *SSDT_
return SSDT_NtOpenProcess_Cur_A
获取系统原始NtOpenProcess地址
ULONG GetNt_OldAddr()
UNICODE_STRING Old_NtOpenP
RtlInitUnicodeString(&Old_NtOpenProcess, L&NoOpenProcess&);
ULONG Old_A
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(sysFile.GetFileName().GetBuffer(256), sysFile.GetPathName().GetBuffer(256));
BOOL LoadNTDriver(char* lpszDriverName, char* lpszDriverPathName)
BOOL bRet=
SC_HANDLE hServiceDDK=NULL;
A、OpenSCManager
SC_HANDLE hServiceMgr=OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
if (hServiceMgr==NULL)
TRACE(&OpenSCManager 调用失败&);
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 值
//要开启服务的 用户组
//输出验证标签
//所依赖的服务的名称
//用户账户名称
//用户口令
C、OpenService
if (hServiceDDK==NULL)
TRACE(&CreateService 失败,继续调用OpenService&);
hServiceDDK=OpenService(hServiceMgr,lpszDriverName,SERVICE_ALL_ACCESS);
if (hServiceDDK==NULL)
TRACE(&OpenService 失败&);
D、StartService
StartService(hServiceDDK,NULL,NULL);
E、CloseServiceHandle
//CloseServiceHandle
//CloseServiceHandle
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;
////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 值
//判断服务是否失败
if( hServiceDDK == NULL )
dwRtn = GetLastError();
if( dwRtn != ERROR_IO_PENDING && dwRtn != ERROR_SERVICE_EXISTS )
//由于其他原因创建服务失败
TRACE( &CrateService() 失败 %d ! \n&, dwRtn );
bRet = FALSE;
//服务创建失败,是由于服务已经创立过
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;
TRACE( &OpenService() 成功 ! \n& );
TRACE( &CrateService() 成功 ! \n& );
//开启此项服务
bRet = StartService( hServiceDDK, NULL, NULL );
if( !bRet )
//开启服务不成功
TRACE( &StartService() 失败 服务可能已经开启%d ! \n&, dwRtn );
bRet = TRUE;
//离开前关闭句柄
if(hServiceDDK)
CloseServiceHandle(hServiceDDK);
if(hServiceMgr)
CloseServiceHandle(hServiceMgr);
//卸载驱动程序
BOOL UnLoadSys( char *szSvrName )
//一定义所用到的变量
BOOL bRet = FALSE;
SC_HANDLE hSCM = NULL; //SCM管理器的句柄,用来存放OpenSCManager的返回值
SC_HANDLE hService = NULL; //NT驱动程序的服务句柄,用来存放OpenService的返回值
SERVICE_STATUS SvrS
//二打开SCM管理器
hSCM = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
if( hSCM == NULL )
//带开SCM管理器失败
TRACE( &OpenSCManager() Faild %d ! \n&, GetLastError() );
bRet = FALSE;
goto BeforeL
//打开SCM管理器成功
TRACE( &OpenSCManager() ok ! \n& );
//三打开驱动所对应的服务
hService = OpenService( hSCM, szSvrName, SERVICE_ALL_ACCESS );
if( hService == NULL )
//打开驱动所对应的服务失败 退出
TRACE( &OpenService() Faild %d ! \n&, GetLastError() );
bRet = FALSE;
goto BeforeL
TRACE( &OpenService() ok ! \n& );
//打开驱动所对应的服务 成功
//四停止驱动程序,如果停止失败,只有重新启动才能,再动态加载。
if( !ControlService( hService, SERVICE_CONTROL_STOP , &SvrSta ) )
TRACE( &用ControlService() 停止驱动程序失败 错误号:%d !\n&, GetLastError() );
//停止驱动程序成功
TRACE( &用ControlService() 停止驱动程序成功 !\n& );
//五动态卸载驱动服务。
if( !DeleteService( hService ) )
//TRUE//FALSE
//卸载失败
TRACE( &卸载失败:DeleteSrevice()错误号:%d !\n&, GetLastError() );
//卸载成功
TRACE ( &卸载成功 !\n& );
bRet = TRUE;
//六 离开前关闭打开的句柄
BeforeLeave:
if(hService & 0)
CloseServiceHandle(hService);
if(hSCM & 0)
CloseServiceHandle(hSCM);
void CLoadsysDlg::OnButtonUnloadsys()
// TODO: Add your control notification handler code here
//卸载驱动程序
UnLoadSys(DriverName.GetBuffer(256))
驱动代码中C++代码编译问题:
1、声明 extern &C& PServiceDescriptorTable &KeServiceDescriptorT
& & & extern &C& NTSTATUS DriverEntry(...)
#pragma once
#ifdef __cplusplus
extern &C&
#include &NTDDK.h&
#ifdef __cpluspus
十一、应用程序与驱动交互访问
交换过程:
1、用户层传入数据&
2、驱动层接收数据
3、驱动层回传数据
用户层缓冲模式实现:
#include&winioctl.h& //CTL_CODE
#define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,
METHOD_BUFFERED,FILE_ANY_ACCESS)
#define sub_code CTL_CODE(FILE_DEVICE_UNKNOWN,
METHOD_BUFFERED,FILE_ANY_ACCESS)
int add(HANDLE hDevice, int a, int b)
int port[2];
DeviceIoControl(hDevice, add_code , &port, 8, &bufret, 4, &dwWrite, NULL);
int main(int argc, char *argv[])
//CreateFile 打开设备 获取hDevice
HANDLE hDevice =
CreateFile(&\\\\.\\My_DriverLinkName&, //\\??\\My_DriverLinkName
GENERIC_READ | GENERIC_WRITE,
// share mode none
NULL, // no security
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
// 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();
内核层缓冲模式实现:
#pragma PAGECODE
NTSTATUS ddk_DispatchRoutine_CONTROL(IN PDEVICE_OBJECT pDevobj, IN PIRP pIrp )
//得到当前栈指针
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
ULONG mf = stack-&MajorF //区分IRP
switch (mf)
case IRP_MJ_DEVICE_CONTROL:
KdPrint((&Enter myDriver_DeviceIOControl\n&));
NTSTATUS status = STATUS_SUCCESS;
//得到输入缓冲区大小
ULONG cbin = stack-&Parameters.DeviceIoControl.InputBufferL
//得到输出缓冲区大小
ULONG cbout = stack-&Parameters.DeviceIoControl.OutputBufferL
//得到IOCTL码
ULONG code = stack-&Parameters.DeviceIoControl.IoControlC
switch (code)
case add_code:
KdPrint((&add_code 1111111\n&));
//缓冲区方式IOCTL
//获取缓冲区数据 a,b
int *InputBuffer = (int *)pIrp-&AssociatedIrp.SystemB
mov eax, InputBuffer
mov ebx, [eax]
mov a, ebx
mov ebx, [eax+4]
mov b, ebx
KdPrint((&a=%d,b=%d \n&, a, b));
//C、驱动层返回数据至用户层
//操作输出缓冲区
int *OutputBuffer = (int *)pIrp-&AssociatedIrp.SystemB
mov eax, a
mov ebx, OutputBuffer
mov [ebx], eax //bufferet=a+b
KdPrint((&a+b=%d \n&, a));
//设置实际操作输出缓冲区长度
case sub_code:
}//end code switch
//对相应的IPR进行处理
pIrp-&rmation = //设置操作的字节数为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 OrgA
byte PushCode2;
ULONG NameA
ULONG JmpP
} *PHOOKAPIPROXY, HOOKAPIPROXY;
导入表遍历:
PVOID EnumAPI()
PBYTE ImageB
PIMAGE_THUNK_DATA
PIMAGE_NT_HEADERS pNtH
PIMAGE_IMPORT_DESCRIPTOR pI
//取得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-&N pImport++)
printf(&导入模块:%s\n&,ImageBase+pImport-&Name);
//遍历IAT信息
PIMAGE_THUNK_DATA基址
for (r = (PIMAGE_THUNK_DATA) (ImageBase + pImport-&FirstThunk); r-&u1.F r++)
//枚举函数地址
if (Sleep==(PVOID)r-&u1.Function)
DWORD pSleep=(DWORD)(&r-&u1.Function);
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);
应用层Hook示例:
#include &windows.h&
(__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
}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);
MOV EBP,ESP
printf(&取得参数 %x,%s,%s,%x\n&,hWnd,lpText,lpCaption,uType);
mov ebx,old_MessageBoxA
printf(&hook Error\n&);
VOID InLine_HookMessageBoxA()
//取得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);
十四、内核层HOOK
#pragma PAGECODE
DWORD Get_KeServiceDescriptorTableShadow_Addr()
DWORD KeServiceDescriptorTableShadow = 0;
DWORD Version = GetVersion();
switch (Version
case VERSION_2K:
KeServiceDescriptorTableShadow = (DWORD)KeServiceDescriptorTable + 0xE0;
case VERSION_2K3:
case VERSION_XP:
KeServiceDescriptorTableShadow = (DWORD)KeServiceDescriptorTable - 0x40;
return KeServiceDescriptorTableS
#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));
PDWORD CFun_Addr = PDWORD(TableBase); //+=355
CFun_Addr = PDWORD(*CFun_Addr);
for (DWORD i = 0; i & i++)
KdPrint((&\n %d=%x\n&, i, *CFun_Addr ));
CFun_Addr++;
//__asm int 3
typedef BOOL (__stdcall *PNtUserDestroyWindow)(HWND hwnd);
PNtUserDestroyWindow Old_NtUserDestroyWindow, Cur_NtUserDestroyW
#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));
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 //去掉页面保护
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));
eax, 10000h
#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));
PDWORD CFun_Addr = PDWORD(TableBase);
CFun_Addr = PDWORD(*CFun_Addr);
CFun_Addr += 355;
__asm //去掉页面保护
mov eax, cr0
and eax, not 10000h //and eax,0FFFEFFFFh
mov cr0, eax
*CFun_Addr = (DWORD)(Old_NtUserDestroyWindow);
eax, 10000h
十五、绕过应用层HOOK
目的:脱离API函数直接调用,防止被调试断点跟踪&
以FindWindow示例:
#pragma pack(1)
typedef struct _UNICODE_STRING
USHORT MaximumL
} UNICODE_STRING, *PUNICODE_STRING;
#pragma pack()
__declspec(naked)
void sysFastCall()
// 7C92E510 &
MOV EDX,ESP
//7C92E512
mov edx, esp
__emit 0x0f
__emit 0x34
PUSH DWORD PTR SS:[EBP+18]
PUSH DWORD PTR SS:[EBP-18]
PU_LCatipn
PUSH DWORD PTR SS:[EBP-8]
PUSH DWORD PTR SS:[EBP+C]
PUSH DWORD PTR SS:[EBP+8]
CALL USER32.77D2C7AC
NtUserFindWindow
__declspec(naked) HWND
__stdcall My_FindWindow(
PUNICODE_STRING pu_classname,
PUNICODE_STRING pu_catption,
MOV EAX, 0x117A
call sysFastCall
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_C
(__stdcall * PRtlInitUnicodeString)( PUNICODE_STRING , PCWSTR
PRtlInitUnicodeString
RtlInitUnicodeS
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&
#include &NTDDK.h& //这里包含需要用C方式编译的头文件
#ifdef __cplusplus
//#include &windef.h&
bool ssdthook_flag =
RealNtOpenA
// A、构建自己的内核函数(用来替换对应的内核函数)
// 定义一下NtOpenProcess的原型
extern &C&
__stdcall NTOPENPROCESS
OUT PHANDLE ProcessHandle,
IN ACCESS_MASK AccessMask,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN PCLIENT_ID ClientId
NTOPENPROCESS
*RealNtOpenP
// 自定义的NtOpenProcess函数 ZwOpenProcess
#pragma PAGECODE
extern &C& NTSTATUS __declspec(naked) __stdcall MyNtOpenProcess(
PHANDLE ProcessHandle,
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes,
PCLIENT_ID ClientId )
//KdPrint((&++++++++++++Entry MyNtOpenProcess int
++++++++++++++\n&));
//rc = (NTSTATUS)RealNtOpenProcess( ProcessHandle, DesiredAccess, ObjectAttributes, ClientId );
if( (ClientId != NULL) )
PID = ClientId-&UniqueP
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
\n&, (PTSTR)((ULONG)EP + 0x174)));
mov eax, RealNtOpenProcess //
add eax, 5
//HOOK 函数构建
#pragma PAGECODE
VOID Hook()
ssdthook_flag = //设置被HOOK标志
KdPrint((&++++HOOK START ++++-\n&));
LONG *SSDT_Adr, SSDT_NtOpenProcess_Cur_Addr, t_
KdPrint((&驱动成功被加载中.............................\n&));
//读取SSDT表中索引值为0x7A的函数
//poi(poi(KeServiceDescriptorTable)+0x7a*4)
t_addr = (LONG)KeServiceDescriptorTable-&ServiceTableB
SSDT_Adr = (PLONG)(t_addr + 0x7A * 4);
SSDT_NtOpenProcess_Cur_Addr = *SSDT_A
RealNtOpenAddress = *SSDT_A
RealNtOpenProcess = ( NTOPENPROCESS *)RealNtOpenA
KdPrint(( &真实的NtOpenProcess地址: %x\n&, (int) RealNtOpenAddress ));
KdPrint((& 伪造NTOpenProcess地址: %x\n&, (int)MyNtOpenProcess ));
__asm //去掉页面保护
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_A //SSDT HOOK jmp jz jnz
// in line hook
mov ebx, SSDT_Adr //RealNtOpenAddress
mov byte ptr ds:[ebx], 0xe9
mov eax, jmpaddr
mov DWORD ptr ds:[ebx+1], eax
eax, 10000h
//UnHook函数构建
//////////////////////////////////////////////////////
#pragma PAGECODE
VOID UnHook()
ULONG Old_
Old_ssdt = (ULONG)KeServiceDescriptorTable-&ServiceTableBase + 0x7A * 4;
(ssdthook_flag)
ssdthook_flag =
eax, not 10000h
// 还原SSDT
*((ULONG *)Old_ssdt) = (ULONG)RealNtOpenA
eax, 10000h
KdPrint((&UnHook还原SSDT OK \n&));
反断点原理:
1、不能正常下断点(int 3)
2、正常下断点后,让他不能断下
typedef struct _IDTR
ULONG // 基地址
IDTR, *PIDTR;
typdef struct _IDTR_ENTRY
always0:1;
present:1;
// 中断处理函数地址
} IDT_ENTRY, *PIDT_ENTRY;
读IDT表, sidt指令
PIDT_ENTRY aidt = PIDT_ENTRY(idtr.base);
for (int i = 0; i & 0 i++)
ULONG cur_idt = aidt-&offset_
cur_idt = cur_idt && 16 + ULONG(aidt-&offset_low);
return idtr.
IDT HOOK实例:
#pragma pack(pop) //#pragma pack(pop)
//-----------全局变量--------------------------------
ULONG int3proc_ //用来存放int 3处理函数地址
ULONG jmpaddr_int3proc_9; //用来存放intproc+9处理函数地址
//-----------全局变量 定义结束-----------------------
#pragma PAGECODE
ULONG ReadIdtBase(ULONG CPUNUM)
IDTR//获取表基址
PIDT_ENTRY A
KdPrint((&IDT_ENTRY size=%d \n&, sizeof(IDT_ENTRY)));
__//获取表基址信息
KdPrint((&IDT BASE=%x \n&, idtr.base));
Aidt = PIDT_ENTRY(idtr.base);
return idtr.
void __declspec(naked)
int3UnHookcode()
word ptr [esp+2], 0
#pragma PAGECODE
void __declspec(naked)
myInt3Proc()
//__asm retn 100;
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;
mov word ptr [esp+2], 0
//前2条需要恢复的指令 占9字节
jmp jmpaddr_int3proc_9
ULONG HookInt3Proc()
ULONG status = 1;
PIDT_ENTRY Pidt_info = (PIDT_ENTRY)ReadIdtBase(0);
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_
KdPrint ((&\n int proc addr=%x \n&, int3proc_addr));
//begin inline hook int3Proc write
// E9+jmp地址//jmp地址=myInt3Proc-int3proc_addr-5;
jmpaddr = ULONG(&myInt3Proc) - int3proc_addr - 5;
jmpaddr_int3proc_9 = int3proc_addr + 9;
mov ebx, int3proc_addr
mov byte ptr ds:[ebx], 0xE9
mov eax, jmpaddr
mov dword ptr ds:[ebx+1], eax
//inline hook int3proc write
ULONG UnHookInt3Proc()
ULONG status = 1;
KdPrint((&\n 卸载 Idt Hook \n&));
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
//inline hook int3proc write
已发表评论数()
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
标题不准确
排版有问题
主题不准确
没有分页内容
图片无法显示
视频无法显示
与原文不一致}

我要回帖

更多关于 declspec dllimport 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信