看流星社区

 找回密码
 注册账号
查看: 2002|回复: 0

另类阻止驱动加载

[复制链接]

该用户从未签到

发表于 2017-6-1 17:25:22 | 显示全部楼层 |阅读模式
标 题: 【分享】【原创】另类阻止驱动加载
作 者: czcqq
时 间: 2010-05-04,22:27:47
链 接: http://bbs.pediy.com/showthread.php?t=112338

关于驱动的加载大概有几种方法
1在WINDOWS下动态加载
2在WINDOWS启动的时候加载
3感染系统文件


对于在WINDOWS启动的时候加载和感染系统文件我们暂时不讨论,玩么只讨论动态加载


一般的加载流程,是这样的:打开服务管理器->创建服务->启动服务->(系统加载驱动)
这个过程系统最终会调用NtLoadDriver来加载驱动(也可以用Ntdll.dll里面的NtSetSystemInformation来加载)


而NtLoadDriver会向系统插入一个作业,然后等待另外一个系统线程来加载驱动,并等待驱动的加载完成(NtSetSystemInformation也是一样的),然后返回
这样我们就可以HOOKNtLoadDriver和NtSetSystemInformation来阻止驱动加载,但是这个方法已经用烂了,这里我HOOKNtCreateSection来阻止驱动加载
为什么HOOKNtCreateSection呢???
因为在另外一个线程取得消息加载驱动的时候会调用NtCreateSection来映射驱动到内核内存空间


(流程:大概是这样IoCreateFile(打开驱动文件,将它的第二个参数设置为FILE_EXECUTE|SYNCHRONIZE)->NtCreateSection(为驱动在内核内存空间创建一个节)->NtMapViewOfSection(映射驱动到内核内存空间)->寻找驱动的DriverEntry,并调用->ZwClose(关闭文件句柄)->然后通知NtLoadDriver(或者NtSetSystemInformation)驱动加载完成->NtLoadDriver(或者NtSetSystemInformation)返回用户层,并通知用户驱动加载完成)


在驱动加载流程中,我们可以看到我们有很多机会劫持驱动的加载
我们可以HOOKNtCreateSection或者NtMapViewOfSection来阻止驱动加载
这里我采用HOOKNtCreateSection的办法阻止驱动加载

以下为代码



#include<ntifs.h>

//声明用到的头文件和结构宏等
#include"NtCreateSection.h"
#ifDBG
#defineDriversUnload(Address,p)\
Address->DriverUnload=p;
#else
#defineDriversUnload(Address,p)\
Address->DriverUnload=NULL;
#endif
typedefintBOOL;
typedefunsignedintUINT;
typedefunsignedlongDWORD;
typedefunsignedshortWORD;
typedefvoid*LPVOID;
typedefunsignedcharBYTE;
typedefDWORD*PDWORD;
typedefBYTE*PBYTE;
typedefWORD*PWORD;
#definePAGE_NOACCESS0x01
#definePAGE_READONLY0x02
#definePAGE_READWRITE0x04
#definePAGE_WRITECOPY0x08
#definePAGE_EXECUTE0x10
#definePAGE_EXECUTE_READ0x20
#definePAGE_EXECUTE_READWRITE0x40
#definePAGE_EXECUTE_WRITECOPY0x80
#definePAGE_GUARD0x100
#definePAGE_NOCACHE0x200
#definePAGE_WRITECOMBINE0x400
#defineMEM_COMMIT0x1000
#defineMEM_RESERVE0x2000
#defineMEM_DECOMMIT0x4000
#defineMEM_RELEASE0x8000
#defineMEM_FREE0x10000
#defineMEM_PRIVATE0x20000
#defineMEM_MAPPED0x40000
#defineMEM_RESET0x80000
#defineMEM_TOP_DOWN0x100000
#defineMEM_4MB_PAGES0x80000000
#defineSEC_FILE0x800000
#defineSEC_IMAGE0x1000000
#defineSEC_VLM0x2000000
#defineSEC_RESERVE0x4000000
#defineSEC_COMMIT0x8000000
#defineSEC_NOCACHE0x10000000
#defineMEM_IMAGESEC_IMAGE
PVOIDWriteAddress=NULL;
PMDLpMdl=NULL;
//声明所需要的函数
NTSYSAPI
NTSTATUS
NTAPI
ZwYieldExecution(
VOID
);
PVOIDNTAPIGetJmpAddress(PVOIDFun,BOOL*Call_Code);
NTSTATUS
NTAPI
CallBack_NtCreateSection(
OUTPHANDLESectionHandle,
INACCESS_MASKDesiredAccess,
INPOBJECT_ATTRIBUTESObjectAttributesOPTIONAL,
INPLARGE_INTEGERMaximumSizeOPTIONAL,
INULONGSectionPageProtection,
INULONGAllocationAttributes,
INHANDLEFileHandleOPTIONAL
);
NTSTATUS
NTAPI
OldNtCreateSection(
OUTPHANDLESectionHandle,
INACCESS_MASKDesiredAccess,
INPOBJECT_ATTRIBUTESObjectAttributesOPTIONAL,
INPLARGE_INTEGERMaximumSizeOPTIONAL,
INULONGSectionPageProtection,
INULONGAllocationAttributes,
INHANDLEFileHandleOPTIONAL
);
voidmakejmp(LPVOIDFun1,LPVOIDFun2,LPVOIDjmp);
#pragmaalloc_text(PAGE,makejmp)
#pragmaalloc_text(PAGE,OldNtCreateSection)
#pragmaalloc_text(PAGE,CallBack_NtCreateSection)
#pragmaalloc_text(PAGE,GetJmpAddress)

//所有声明结束


//驱动入口

NTSTATUSDriverEntry(
INPDRIVER_OBJECTDriverObject,
INPUNICODE_STRINGRegistryPath
)
{
NTSTATUSStatus=0;
PDEVICE_OBJECTpDeviceObject=NULL;
//创建设备,这个就不讲解了,大家明白就好,我重点讲解HOOK过程
Status=IoCreateDevice(
DriverObject,
0,
NULL,
FILE_DEVICE_UNKNOWN,
0,
FALSE,
&amp;pDeviceObject
);

if(NT_SUCCESS(Status)){
KIRQLoldIrql;
PVOIDHookAddress=NULL;

BOOLHook=0;
PVOIDJmpData=ExAllocatePool(NonPagedPool,5);//申请内存,用来保存内容为JmpCallBack_NtCreateSection的代码
DriversUnload(DriverObject,Unload);//设置DriverObject->DriverUnload=Unload;这个宏只有在调试版本的时候才会设置
//DriverObject->DriverUnload=Unload;如果不是调试版本,就会设置DriverObject->DriverUnload=NULL;
if(JmpData==NULL)
{
DbgPrint("HOOKNtCreateSection失败!内存申请失败\n");
returnStatus;
}
memset(JmpData,0x90,5);//初始化JmpData内容为NOP
//将NtCreateSection的头7个字节复制到OldNtCreateSection中来
pMdl=IoCreateWriteMdlForAddress(OldNtCreateSection,&amp;WriteAddress,7);
if(pMdl==NULL)
{
DbgPrint("HOOKNtCreateSection失败!OldNtCreateSection写入失败\n");
ExFreePool(JmpData);
JmpData=NULL;
WriteAddress=NULL;
pMdl=NULL;
returnStatus;
}
memcpy(WriteAddress,NtCreateSection,7);
IoFreeMdlForAddress(WriteAddress,pMdl);
WriteAddress=NULL;
//将NtCreateSection的头5字节变成可写
pMdl=IoCreateWriteMdlForAddress(NtCreateSection,&amp;WriteAddress,7);
if(pMdl==NULL)
{
DbgPrint("HOOKNtCreateSection失败!NtCreateSection写入失败\n");
ExFreePool(JmpData);
JmpData=NULL;
WriteAddress=NULL;
pMdl=NULL;
returnStatus;
}
//检查是否已经被别人HOOK,如果已经被别人HOOK则我们退出HOOK,这里是可以改进的,但是我没有时间写,只能退出HOOK
HookAddress=GetJmpAddress(NtCreateSection,&amp;Hook);
if(HookAddress!=NULL)
{
DbgPrint("HOOKNtCreateSection失败!发现NtCreateSection已经被别人HOOK所以本HOOK退出\n");
ExFreePool(JmpData);
JmpData=NULL;
IoFreeMdlForAddress(WriteAddress,pMdl);
WriteAddress=NULL;
pMdl=NULL;
returnStatus;
}
//HOOKNtCreateSection
if(NT_SUCCESS(ZwYieldExecution()))//先向系统申请CPU时间
{
_asmcli//关闭中断
oldIrql=KeRaiseIrqlToDpcLevel();//提升到DPC级别
memset(WriteAddress,0x90,7);//修改NtCreateSection的前7个字节为NOP指令
makejmp(NtCreateSection,CallBack_NtCreateSection,JmpData);//取得JmpCallBack_NtCreateSection的代码,代码保存在JmpData中
memcpy(WriteAddress,JmpData,5);//修改NtCreateSection前5个字节为JmpCallBack_NtCreateSection
KeLowerIrql(oldIrql);//还原到原来的IRQL级别
_asmsti//开中断

}else
{
DbgPrint("申请CPU时间失败,HOOK退出\n");
}
ExFreePool(JmpData);
JmpData=NULL;

}

returnStatus;
}

//我们的NtCreateSection过滤函数
NTSTATUS
NTAPI
CallBack_NtCreateSection(
OUTPHANDLESectionHandle,
INACCESS_MASKDesiredAccess,
INPOBJECT_ATTRIBUTESObjectAttributesOPTIONAL,
INPLARGE_INTEGERMaximumSizeOPTIONAL,
INULONGSectionPageProtection,
INULONGAllocationAttributes,
INHANDLEFileHandleOPTIONAL
)
{
NTSTATUSStatus=0;
Status=OldNtCreateSection(
SectionHandle,
DesiredAccess,
ObjectAttributes,
MaximumSize,
SectionPageProtection,
AllocationAttributes,
FileHandle);
if(NT_SUCCESS(Status))
{
//进行行为判断,如果是要加载驱动,我们就直接返回错误,并关闭句柄,如果不是就返回原来的结果
if(((DWORD)PsGetCurrentProcessId()==(DWORD)4)|((DWORD)PsGetCurrentProcessId()==(DWORD)8)|((DWORD)PsGetCurrentProcessId()==(DWORD)0))
{

if((FlagOn(DesiredAccess,SECTION_MAP_EXECUTE))||(FlagOn(DesiredAccess,PAGE_EXECUTE_READ)))
if((PAGE_EXECUTE==SectionPageProtection)|(AllocationAttributes==SEC_IMAGE))
{
ZwClose(*SectionHandle);
*SectionHandle=NULL;
returnSTATUS_ACCESS_DENIED;
}
}
}
returnStatus;
}
//用来跳转到原函数的一个裸函数
__declspec(naked)NTSTATUS
NTAPI
OldNtCreateSection(
OUTPHANDLESectionHandle,
INACCESS_MASKDesiredAccess,
INPOBJECT_ATTRIBUTESObjectAttributesOPTIONAL,
INPLARGE_INTEGERMaximumSizeOPTIONAL,
INULONGSectionPageProtection,
INULONGAllocationAttributes,
INHANDLEFileHandleOPTIONAL
)
{
_asm
{
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
moveax,NtCreateSection//将原函数地址送入eax
addeax,7//eax加7,用来跳过我们的HOOK
pusheax//将eax压入
ret//跳回原函数
}
}

//用来生成跳转代码的函数
voidmakejmp(LPVOIDFun1,LPVOIDFun2,LPVOIDjmp)
{
BYTE*data=(BYTE*)jmp;
longdFun1=(long)Fun1;
longdFun2=(long)Fun2;
DWORDH;
data[0]=0xe9;


_asm
{

moveax,dFun1
movedx,dFun2
subedx,eax
subedx,5
movH,edx
}

memcpy(&amp;data[1],(void*)&amp;H,4);

}
VOIDUnload(
INPDRIVER_OBJECTDriverObject
)
{
KIRQLoldIrql;
while(!NT_SUCCESS(ZwYieldExecution()))//取得CPU时间,如果取得失败,就一直获取,直到成功
{
}
if(pMdl!=NULL)//检查我们是否已经进行过HOOK,//如果我们进行过HOOK就还原
{
oldIrql=KeRaiseIrqlToDpcLevel();
memcpy(WriteAddress,OldNtCreateSection,7);
KeLowerIrql(oldIrql);
IoFreeMdlForAddress(WriteAddress,pMdl);
}
IoDeleteDevice(DriverObject->DeviceObject);//删除设备

pMdl=NULL;
WriteAddress=NULL;
}
PVOIDNTAPIGetJmpAddress(PVOIDFun,BOOL*Call_Code)
{
PVOIDReturn=NULL;
BYTE*data=(BYTE*)Fun;
DWORDOld=0;
if(data[0]==0xe9)
{
*Call_Code=0;
}elseif(data[0]==0xe8)
{
*Call_Code=1;
}else
{
*Call_Code=2;
returnNULL;
}

memcpy((void*)&amp;Old,&amp;data[1],4);
_asm
{
moveax,Old
movedx,Fun
addeax,edx
addeax,5
movReturn,eax
}
returnReturn;
}



这个驱动只支持单核心CPU多核心CPU请自行修改(将所有CPU都提升到DPC级别以后再进行HOOK)驱动加载流程是看了WIN2K的代码来讲的,WIN2K的代码很长,所以就简单的讲了一下*转载请注明来自看雪论坛@PEdiy.com
点击按钮快速添加回复内容: 支持 高兴 激动 给力 加油 苦寻 生气 回帖 路过 感恩
您需要登录后才可以回帖 登录 | 注册账号

本版积分规则

小黑屋|手机版|Archiver|看流星社区 |网站地图

GMT+8, 2024-4-20 01:22

Powered by Kanliuxing X3.4

© 2010-2019 kanliuxing.com

快速回复 返回顶部 返回列表