欢迎来到四川泊祎废旧物资回收有限公司官方网站,全川咨询服务热线:1388-0022-916
您的位置: 首页 > 回收百科 > TsFltMgr.sys系统蓝屏的原因分析(小心QQ电脑管家)

TsFltMgr.sys系统蓝屏的原因分析(小心QQ电脑管家)

发布时间:2023-10-7 7:02:18   作者:佚名

同事一WindowsXP系统,正常执行,关闭后,第二天无法启动,详细症状为:

(1)安全模式以及带网络功能的安全模式都能够进入;

(2)正常模式,还没出现WindowXP滚动栏就開始重新启动;

(3)进安全模式,禁用自己主动重新启动后,再正常启动,出现蓝屏,报TsFltMgr.sys内存错误!

经过互联网查询,和不断摸索,最后发现居然是可恶的QQ软件管家惹的祸,进安全模式果断卸载QQ软件管家后,再重新启动,系统全然正常了。

以下转载了一篇分析QQ电脑管家的文章,请參考:

QQ电脑管家中的TsFltMgrHook框架分析

新版的QQ电脑管家中多了一个名字叫TsFltMgr.sys的驱动(应该是Sysnap大牛开发的,膜拜),对该驱动进行了一些简单的分析,看见了一套美丽的Hook框架,发出来与大家分享。分析不正确的地方请多多包涵。

首先TsFltMgr挂钩了KiFastCallEntry函数,Hook点在这里:

代码:

复制代码代码如下:

kd>uKiFastCallEntry+e3

nt!KiFastCallEntry+0xe3:

8053dbb3c1e902shrecx,2

-------------------------------------------------------------------------

8053dbb690nop

8053dbb790nop

8053dbb890nop

8053dbb9e962170c77jmpTsFltMgr+0x2320(f75ff320)

-------------------------------------------------------------------------

8053dbbe0f83a8010000jaent!KiSystemCallExit2+0x9f(8053dd6c)

8053dbc4f3a5repmovsdwordptres:[edi],dwordptr[esi]

8053dbc6ffd3callebx

原始的KiFastCallEntry在shrecx,2指令后面应该是movedi,esp;cmpesi,MmUserProbeAddress,共8个字节,在这里被TsFltMgr替换成了3个nop和一个jmp。

该jmp会跳转到KiFastCallEntry_Detour函数中,KiFastCallEntry_Detour函数代码例如以下:

代码:

复制代码代码如下:

//保存现场

pushfd

pushad

//调用KiFastCallEntry_Filter函数,实现过滤

pushedi//本次系统调用相应的SysCallTable的地址(SSDT或SSDTShadow的地址)

pushebx//本次系统调用在SysCallTable中相应的内核函数地址

pusheax//本次系统调用相应的内核函数在SysCallTable中的功能号

callKiFastCallEntry_Filter//调用KiFastCallEntry_Filter,实现过滤

mov[esp+10h],eax//更改本次调用相应的内核函数地址!

//恢复现场

popad

popfd

//运行KiFastCallEntry函数中被替换掉的指令,并跳回原函数

movedi,esp

cmpesi,g_7fff0000

pushg_JmpBack

ret

这里须要注意的是callKiFastCallEntry_Filter之后的mov[esp+10h],eax。之前保存现场时的指令pushad会导致寄存器EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI依次入栈,并通过后面的popad指令恢复这些寄存器的值。因此此处的mov[esp+10h],eax实际上是用KiFastCallEntry_Filter函数的返回值来改写堆栈中保存的ebx的值,即改写本次系统调用相应的内核函数地址。

KiFastCallEntry_Filter是真正实现过滤的函数,该函数的參数和返回值上文已经说明了,其详细实现分析整理后,C语言描写叙述例如以下:

代码:

复制代码代码如下:

ULONG__stdcallKiFastCallEntry_Filter(ULONGulSyscallId,ULONGulSyscallAddr,PULONGpulSyscallTable)

{

PFAKE_SYSCALLpFakeSysCall=NULL;

if(ulSyscallId>=0x400)

returnulSyscallAddr;

if(pulSyscallTable==g_KiServiceTable&&ulSyscallId<=g_ServiceNum )

{

pFakeSysCall=g_FakeSysCallTable[ulSyscallId];//SSDT

}

elseif(pulSyscallTable==g_KeServiceDescriptorTable&&

g_KeServiceDescriptorTable&&ulSyscallId<=g_ServiceNum)

{

pFakeSysCall=g_FakeSysCallTable[ulSyscallId];//SSDT

}

elseif(pulSyscallTable==g_W32pServiceTableAddr&&ulSyscallId<=g_ShadowServiceNum)

{

pFakeSysCall=g_FakeSysCallTable[ulSyscallId+1024];//ShadowSSDT

}

if(pFakeSysCall&&pFakeSysCall->ulFakeSysCallAddr)

{

pFakeSysCall->ulOrigSysCallAddr=ulSyscallAddr;

returnpFakeSysCall->ulFakeSysCallAddr;

}

returnulSyscallAddr;

}

这里须要说明的是,TsFltMgr内部有一张表,暂且命名为g_FakeSysCallTable,该表中存放的是指向FAKE_SYSCALL结构的指针。表中的每个FAKE_SYSCALL结构相应一个系统调用,表的前半部分相应SSDT中的系统调用,1024项以后相应ShadowSSDT里的系统调用。

当中FAKE_SYSCALL结构大致例如以下(当中非常多域的作用没弄明确):

代码:

复制代码代码如下:

typedefstruct__FAKE_SYSCALL__{

ULONGxxx1;

ULONGulSyscallId;//该系统调用的功能号

ULONGxxx3;

ULONGulTableIndex;

ULONGxxx5;

ULONGulCountForPreWork;

ULONGulCountForPostWork;

ULONGxxx8;

ULONGulOrigSysCallAddr;//真实的系统调用地址

ULONGulFakeSysCallAddr;//假的系统调用地址

ULONGxxx11;

ULONGxxx12;

ULONGxxx13;

……

}FAKE_SYSCALL,*PFAKE_SYSCALL,**PPFAKE_SYSCALL;

因此KiFastCallEntry_Filter函数的所做的就是依据系统调用的功能号在g_FakeSysCallTable中索引出相应的pFakeSysCall对象,然后推断该系统调用是否须要hook,假设须要则将真实的系统调用地址保存到pFakeSysCall->ulOrigSysCallAddr中,并将pFakeSysCall->ulFakeSysCallAddr作为假系统调用的地址返回。

这样的调用过程中动态获取真实系统调用地址的方法使TsFltMgr的Hook框架有较高的兼容性,比如不会使载入顺序晚于TsFltMgr的驱动中的SSDTHook失效,比如QQ电脑管家本身带的TSKsp.sys驱动。

对于我的測试系统(XP_SP2),TsFltMgrhook的函数有:

代码:

复制代码代码如下:

//SSDT中:

NtCreateFile、NtCreateKey、NtCreateSection、NtCreateSymbolicLinkObject、NtCreateThread、NtDeleteFile、NtDeleteKey、NtDeleteValueKey、NtDeviceIoControlFile、NtDuplicateObject、NtEnumerateValueKey、NtLoadDriver、NtOpenProcess、NtOpenSection、NtProtectVirtualMemory、NtQueryValueKey、NtRequestWaitReplyPort、NtSetContextThread、NtSetInformationFile、NtSetSystemInformation、NtSetValueKey、NtSuspendThread、NtSystemDebugControl、NtTerminateProcess、NtTerminateThread、NtWriteFile、NtWriteVirtualMemory

//ShadowSSDT中:

NtUserBuildHwndList、NtUserFindWindowEx、NtUserGetForegroundWindow、NtUserMoveWindow、NtUserQueryWindow、NtUserSendInput、NtUserSetParent、NtUserSetWindowLong、NtUserSetWindowPlacement、NtUserSetWindowPos、NtUserShowWindow、NtUserShowWindowAsync、NtUserWindowFromPoint

全部假系统函数都有统一的代码框架,假系统函数的代码框架大致例如以下:

代码:

复制代码代码如下:

NTSTATUS__stdcallFakeNt_XXX(xxx)

{

PFAKE_SYSCALLpFakeSysCall;

ULONGulXXX=0;

ULONGulStatus;

NTSTATUSstatus;

ULONGLONGullTickCount;

pFakeSysCall=g_pFakeSysCall_Nt_XXX;//该系统调用相应的pFakeSysCall对象

status=STATUS_ACCESS_DENIED;

//貌似是做性能測试时候须要的,实际版本号中g_bPerformanceTest为FALSE

if(g_bPerformanceTest){

ullTickCount=KeQueryInterruptTime();

}

//系统调用的调用前处理!

//+++

InterlockedIncrement(&pFakeSysCall->ulCountForPreWork);

ulStatus=PreWork(&ulXXX,pFakeSysCall);

InterlockedDecrement(&pFakeSysCall->ulCountForPreWork);

//---

if(ulStatus!=0xEEEE0004&&ulStatus!=0xEEEE0005)

{

OrigSysCall*pOrigSysCall=pFakeSysCall->ulOrigSysCallAddr;

//调用原始系统调用!

if(pOrigSysCall&&NT_SUCCESS(pOrigSysCall(xxx)))

{

//系统调用的调用后处理!

//+++

InterlockedIncrement(&pFakeSysCall->ulCountForPostWork),

ulStatus=PostWork(&ulXXX),

InterlockedDecrement(&pFakeSysCall->ulCountForPostWork),

//---

}

}

//0xEEEE0004应该是拒绝调用的意思,0xEEEE0005应该是同意调用的意思

if(ulStatus==0xEEEE0005)

status=STATUS_SUCCESS;

//PsGetCurrentProcessId这个调用的返回值后面并没实用到,可能是多余的

PsGetCurrentProcessId();

//貌似是做性能測试时候须要的

if(g_pFakeSysCall_NtTerminateProcess->xxx5&&ullTickCount&&g_bPerformanceTest){

PerformanceTest(&g_pFakeSysCall_NtTerminateProcess->xxx13,ullTickCount);

}

returnstatus;

}

以上就是对TsFltMgrHook框架的一些分析,祝大家元宵快乐~


下一篇:   上一篇:

成功案例