网站首页 新闻首页 网页设计图形动画软件编程网站开发办公软件操作系统数据库网络技术认证考试范文资料黑客攻防 书籍教程 进入论坛

在Ring3上实现文件碎甲(解锁)功能

http://www.diybl.com/ 2008-3-24  网络 点击:  [ 评论 ]
文章搜索:    【点击打包该文章】

作者:cbns888
电邮:cbns888@163.com
一.概述:
如果一个病毒文件被植入正在运行的进程中,我们想要清除它时系统总会提供无法删除;有时编辑文件的进程被意外中止而文件句柄没有正确释放,导致此文件无法进行改写操作。现在我们会使用Unlocker之类的小工具去解锁,但在编写程序的可能会需要把这些功能包含在自己的代码中,本文就是自己写代码实现”如何关闭已经被加载的DLL或是正在使用的文件”功能,使用文章中的方法能很方便的完成文件解锁功能。
按最初的想法准备在ring0中完成这些功能,但在查找资料的过程中发现既然我们能在ring3中做,为什么不让这些方法更通用一些呢。其实功能实现并不难,主要是前期从哪里入手比较麻烦。
我们知道无论是动态库或是文件在加载到进程中时,总会有一个指向它的指针,如果让进程释放这段指针,那么这些文件就不会被系统锁定。下面将是我们的需要实现文件解锁功能而分解出的步骤
1.    枚举当前系统所有进程;
2.    查找进程中打开的文件句柄和加载的动态库句柄;
3.    通知进程关闭这些句柄。
二.详细设计
2.1查找进程加模的动态库模块
Let’s go,我们来分步完成它吧。对于枚举当前系统所有进程,在这里就不给出代码了,相信实现的方法很多。下面的代码段完成查找指定进程加载动库信息的功能(在这里使用了Jeffrey在《Windows核心编程》一书中提供的CToolhelp类,用它可以完成进程加载信息的分析功能,感谢Jeffrey,我一直在使用它)

// 自定义结构,保存打开句柄的的信息
typedef struct _UNFILE_INFO    {
    int nFileType;
    DWORD dwHandle;
    char *strFileName;
} UNFILE_INFO, *PUNFILE_INFO;
//////////////////////////////////////////////////////////////////////////
// 通过PID号取得PID打开的文件句柄信息
//////////////////////////////////////////////////////////////////////////
void
GetModules(DWORD dwProcessID, CList<PUNFILE_INFO, PUNFILE_INFO> &plsUnFileInfo)
{
    CToolhelp::EnableDebugPrivilege(TRUE);
    CToolhelp th(TH32CS_SNAPALL, dwProcessID);
    // 显示进程的详细资料
    MODULEENTRY32 me = { sizeof(me) };
    BOOL fOk = th.ModuleFirst(&me);
    for (; fOk; fOk = th.ModuleNext(&me))
    {
        PVOID pvPreferredBaseAddr = NULL;
        pvPreferredBaseAddr =GetModulePreferredBaseAddr(dwProcessID, me.modBaseAddr);
        // 取得进程模块信息
        PUNFILE_INFO pUnFileInfo = new UNFILE_INFO;
        // 模块地址
        pUnFileInfo->dwHandle = (DWORD)me.modBaseAddr;
        // 模块类型
        pUnFileInfo->nFileType = UNTYPE_DLL;
        // 模块名称
        pUnFileInfo->strFileName = new char[strlen(me.szExePath)+1];
        memset( pUnFileInfo->strFileName, 0, strlen(me.szExePath)+1);
        strcpy( pUnFileInfo->strFileName, me.szExePath);
        // 保存打开的模块信息
        plsUnFileInfo.AddTail( pUnFileInfo);
    }
}

上面功能完成了枚举进程加载的模块功能,我们把得到的枚举信息加入了链表中,以备后面使用。
2.2枚举进程打开的文件信息
下面将分段说明如何枚举指定进程打开的文件句柄。在这里我们需要使用两个DDK中提供的函数:
NTSTATUS
ZwQuerySystemInformation(
    IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
    OUT PVOID SystemInformation,
    IN ULONG SystemInformationLength,
    OUT PULONG ReturnLength OPTIONAL
);
NTSTATUS
  ZwQueryInformationFile(
    IN HANDLE  FileHandle,
    OUT PIO_STATUS_BLOCK  IoStatusBlock,
    OUT PVOID  FileInformation,
    IN ULONG  Length,
    IN FILE_INFORMATION_CLASS  FileInformationClass
);
ZwQuerySystemInformation是个未公开函数,通过它的SYSTEM_INFORMATION_CLASS结构,我们能完成许多进程和线程的操作,下面是它的部分内容,在这时我们使用它的SystemHandleInformation(0x10),来完成文件句柄的操作。
typedef enum _SYSTEM_INFORMATION_CLASS {
    SystemBasicInformation,                 // 0
    SystemProcessorInformation,             // 1
    SystemPerformanceInformation,             // 2

    SystemHandleInformation,                 // 16

    SystemSessionProcessesInformation        // 53
} SYSTEM_INFORMATION_CLASS;
ZwQueryInformationFile可以根据参数FileInformationClass的不同值来返回不同的类型,在这里我们使用FileInformationClass=FileInformationClass来得到FILE_NAME_INFORMATION,从而得到文件句柄指向的文件名,下面是它的结构定义。
typedef struct _FILE_NAME_INFORMATION {
  ULONG  FileNameLength;
  WCHAR  FileName[1];
} FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION;

因为需要在Ring3上使用DDK提供的函数,我们需要导出这些两个函数,下面是导出函数的示例代码:
{
    g_hNtDLL = LoadLibrary( "ntdll.dll" );
    if ( !g_hNtDLL )
    {
        return FALSE;
    }

    ZwQuerySystemInformation =
    (ZWQUERYSYSTEMINFORMATION)GetProcAddress( g_hNtDLL, "ZwQuerySystemInformation");
    if( ZwQuerySystemInformation == NULL)
    {
        return FALSE;
    }

    ZwQueryInformationFile =
  &n

文章整理:DIY部落 http://www.diybl.com (本站)   【点击打包该文章】
如果图片或页面不能正常显示请点击这里 站内搜索:   

文章评论

请您留言

 

最新新闻