TsFltMgr.sys系统蓝屏的原因就在于QQ电脑管家!

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

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

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

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

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

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

QQ电脑管家中的TsFltMgr Hook框架分析

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

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

代码:

kd> u KiFastCallEntry+e3
nt!KiFastCallEntry+0xe3:
8053dbb3 c1e902        shr     ecx,2
-------------------------------------------------------------------------
8053dbb6 90            nop
8053dbb7 90            nop
8053dbb8 90            nop
8053dbb9 e962170c77    jmp     TsFltMgr+0x2320 (f75ff320)
-------------------------------------------------------------------------
8053dbbe 0f83a8010000  jae     nt!KiSystemCallExit2+0x9f (8053dd6c)
8053dbc4 f3a5          rep movs dword ptr es:[edi],dword ptr [esi]
8053dbc6 ffd3          call    ebx

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

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

代码:

// 保存现场
pushfd        
pushad        

// 调用 KiFastCallEntry_Filter 函数,实现过滤
push edi                    // 本次系统调用相应的SysCall Table的地址(SSDT或SSDTShadow的地址)
push ebx                    // 本次系统调用在SysCall Table中相应的内核函数地址
push eax                    // 本次系统调用相应的内核函数在SysCall Table中的功能号
call KiFastCallEntry_Filter // 调用KiFastCallEntry_Filter,实现过滤
mov  [esp+10h], eax         // 更改本次调用相应的内核函数地址!

// 恢复现场
popad        
popfd

// 运行 KiFastCallEntry 函数中被替换掉的指令,并跳回原函数
mov     edi,esp
cmp     esi, g_7fff0000
push    g_JmpBack
ret

这里须要注意的是 call KiFastCallEntry_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 __stdcall KiFastCallEntry_Filter(ULONG ulSyscallId, ULONG ulSyscallAddr, PULONG pulSyscallTable) 
{
    PFAKE_SYSCALL pFakeSysCall = NULL;

    if ( ulSyscallId >= 0x400 ) 
        return ulSyscallAddr;

    if ( pulSyscallTable == g_KiServiceTable && ulSyscallId <= g_ServiceNum/* 0x11c */ ) 
    {
        pFakeSysCall = g_FakeSysCallTable[ulSyscallId];        // SSDT
    }
    else if (pulSyscallTable == g_KeServiceDescriptorTable && 
             g_KeServiceDescriptorTable && ulSyscallId <= g_ServiceNum/* 0x11c */)
    {
        pFakeSysCall = g_FakeSysCallTable[ulSyscallId];        // SSDT
    }
    else if (pulSyscallTable == g_W32pServiceTableAddr && ulSyscallId <= g_ShadowServiceNum/* 0x29b */)
    {
        pFakeSysCall = g_FakeSysCallTable[ulSyscallId + 1024]; // ShadowSSDT
    }

    if ( pFakeSysCall && pFakeSysCall->ulFakeSysCallAddr )
    {
        pFakeSysCall->ulOrigSysCallAddr = ulSyscallAddr;
        return pFakeSysCall->ulFakeSysCallAddr;
    }
    return ulSyscallAddr;
}

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

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

代码:

typedef struct __FAKE_SYSCALL__ {
    ULONG xxx1;
    ULONG ulSyscallId;        // 该系统调用的功能号
    ULONG xxx3;
    ULONG ulTableIndex;    
    ULONG xxx5;
    ULONG ulCountForPreWork;
    ULONG ulCountForPostWork;
    ULONG xxx8;
    ULONG ulOrigSysCallAddr;    // 真实的系统调用地址
    ULONG ulFakeSysCallAddr;    // 假的系统调用地址
    ULONG xxx11;
    ULONG xxx12;
    ULONG xxx13;
    ……
} FAKE_SYSCALL, *PFAKE_SYSCALL, **PPFAKE_SYSCALL;

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

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

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

代码:

// 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 __stdcall FakeNt_XXX(xxx)
{
    PFAKE_SYSCALL pFakeSysCall;
    ULONG ulXXX = 0;
    ULONG ulStatus;
    NTSTATUS status;
    ULONGLONG ullTickCount;
    
    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);
    }

    return status;
}

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

时间: 2024-08-06 20:02:23

TsFltMgr.sys系统蓝屏的原因就在于QQ电脑管家!的相关文章

TsFltMgr.sys其原因是,该系统蓝屏QQ计算机管理器!

同事一WindowsXP系统,正常执行,关闭后,第二天无法启动.详细症状为: (1)安全模式以及带网络功能的安全模式都能够进入. (2)正常模式.还没出现WindowXP滚动栏就開始重新启动: (3)进安全模式,禁用自己主动重新启动后,再正常启动,出现蓝屏.报TsFltMgr.sys内存错误! 经过互联网查询,和不断摸索.最后发现居然是可恶的QQ软件管家惹的祸,进安全模式果断卸载QQ软件管家后,再重新启动,系统全然正常了. 以下转载了一篇分析QQ电脑管家的文章,请參考: QQ电脑管家中的TsFl

Win7升级到Win10后系统蓝屏数据丢失如何解决

Windows10是微软公司2015年7月发布的操作系统,改系统是新一代跨平台及设备应用的操作系统.Win10正式版发布后一年内,微软允许win7和win8用户(包括使用破解版系统的用户)免费升级为正版的windows10系统.在正式版发布之前,很多用户的系统都会提示win10发布的信息,并告知用户可以免费升级到新系统,用户只需在提示框内输入自己的邮箱即可,等正式版系统发布后会通知用户可以升级.用户开机进入系统后也会看到提示升级的消息框,并且在电脑任右下角的任务栏中可以看到微软将的小图标,点击图

电脑蓝屏的原因及解决方法

几乎所有使用电脑的朋友都遇到过电脑蓝屏的现象,电脑蓝屏是一个非常普遍的现象,即使是比尔.盖茨在介绍Windows 98 功能的发布会这么重要的场合仍未能避免蓝屏现象,之所以电脑蓝屏现象很常见,是因为电脑蓝屏的发生有着多种原因,硬件出现问题,硬件之间不兼容,软件之间不兼容都可能造成蓝屏的问题!今天就为大家介绍下电脑蓝屏的原因及解决方法,希望对大家解决电脑蓝屏现象有所帮助! 电脑蓝屏原因 1 软件兼容性问题引起电脑蓝屏刚安装的系统,若驱动与硬件不兼容可能会导致蓝屏现象,建议安装硬件赠送光盘中的驱动(

老司机示范win7系统蓝屏故障0x0000001的设置技巧分享干货的解决方法

此代码单从蓝屏出错界面给出的讯息不足以全面了解出错的原因,还需结合系统故障分析. 蓝屏故障图-1 再使用蓝屏查询器查询,就可以知道这个蓝屏代码的出错缘由是因为不正确的函数. 蓝屏代码0x0000001图-2 如果想知道具体的信息,就打开运行窗口,然后输入“EventVwr.msc”,再点确定.打开事件查看器,注意检查其中的系统日志和应用程序日志中标明错误的项. 蓝屏代码0x0000001图-3 要记得点选系统失败记录在案选项,否则蓝屏不能记录蓝屏事件(可能会被优化掉):先打开控制面板,接着点系统

烂泥:kvm安装windows系统蓝屏

本文由秀依林枫提供友情赞助,首发于烂泥行天下. 最近一直在学习有关KVM的知识,实验一直是在虚拟机VM中进行的.今天刚好公司有一台空闲的服务器,直接拿来安装centos.kvm等等,然后相关的配置. 但是在KVM安装windows系统时,一直会出现蓝屏,无法进行系统的安装.如下图: 查看虚拟机的日志,如下图: tac /var/log/libvirt/qemu/server2008.log 没有看到很有用的信息.查看libvirtd日志,如下: tac /var/log/libvirt/libv

一登录QQ就系统蓝屏

客户端数太多,什么稀奇古怪的情况都会发生,只有想不到,没有不发生.这不,一个办公室又打来电话,说他一登录QQ就系统蓝屏,没法工作了. 一听,还有这种事?抱着看稀奇的心理去看了.去了让他登录QQ,可不!一点登录,蓝屏了.他装了个QQ轻聊版.难道跟版本有关系?给他换成不是轻聊版的,照蓝屏不误.不敢轻举妄动了. 看他机器上装个360卫士,先扫扫修复蓝屏吧.扫了,说是驱动引起的蓝屏,点修复,以为万事大吉.结果说不成功. 看来只好自己动手了.看他的机器上的软件,有一款高级USB接口的驱动软件,看着貌似一个

系统蓝屏获取内存转储文件

如果系统出现频繁的蓝屏和重启,则需要注意了,这个时候分析蓝屏原因就需要崩溃当时的内存转储文件. 首先当然是要配置好转储文件. (1)WIN+R    输入sysdm.cpl打开系统属性. 找到高级选项,启动和故障恢复中的设置. (2)选择好保存的转储模式和转储文件路径,当系统出现蓝屏的时候,就会把文件保存在你设置的目录下,你只要取出来分析就可以了. (3)安装winDbg调试分析转储文件 先创建同步符号 打开WinDbg,选择file,选择Symbol File Path-, 然后在框体中输入下

Exchange服务器系统蓝屏及脱域后解决办法

在工作中有时会出现Exchange服务器在意外重启后蓝屏并且无法直接恢复的情况,通过灾难恢复方式处理之后稳定运行一个月该服务器又出现脱域的现象.在此我总结处理问题的过程及思路,希望能对同行有所帮助. 环境: 操作系统:Windows Server 2008 R2 sp1 Exchange版本:Exchange2010sp3 CU8 架构:3台CAS+4台MBX 现象:CAS服务器中的一台(用CAS2表示)系统在意外重启后无法进入系统.测试同样无法进入安全模式和最后一次正确配置. 解决过程: 确认

解决虚拟内存设置错误导致的系统蓝屏无法启动问题

一次偶然设置虚拟内存由于设置过大导致系统重启后蓝屏,进入无限系统修复界面,但怎么修复都无法正常进入系统,修复过程如下: 首先得有个Ghost 系统U盘,制作方法百度. 然后开机进入U盘引导,进入Ghost系统 ①  桌面→更多工具→设置虚拟内存→初始大小500最大值设置成和物理内存一致即可 ②  桌面→修复系统引导 ③  重启进入系统,重点:然后再重新设置一下虚拟内存.