首页
论坛
课程
招聘
[原创]对WriteFile全面Hook
2012-2-3 19:00 5421

[原创]对WriteFile全面Hook

2012-2-3 19:00
5421
WriteFileHook.rar

本文的内容笔者还发表在http://www.cnblogs.com/zhxfl/archive/2011/11/10/2243825.html

http://www.cnblogs.com/zhxfl/archive/2011/11/03/2233846.html 这个是笔者之前写过的WriteFile HOOK代码
LoadLibraryA
LoadLibraryExA
LoadLibraryExW
LoadLibraryW

WriteFile
WriteFileEx
WriteFileGather
必须补充对这几个函数的HOOK,才能对WriteFile的所有操作做“比较彻底的拦截”,笔者知道应用层的拦截很容易出现遗漏的,只有编写驱动做文件过滤才会有比较好的效果,不过在实现那个之前,想再应用层做好这些实验,看一下效果。

具体的api函数参数可以在http://msdn.microsoft.com/en-us/library/aa365749%28VS.85%29.aspx里面翻出来

 BOOL WriteFileEx(
  HANDLE hFile,
  LPCVOID lpBuffer,
  DWORD nNumberOfBytesToWrite,
  LPOVERLAPPED lpOverlapped,
  LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);
#include <windows.h>
#include <ImageHlp.h>
#include <TlHelp32.h>
#include <stdio.h>
#pragma comment(lib,"ImageHlp")

#pragma data_seg("Shared")
HHOOK hhk = NULL;
#pragma data_seg()
#pragma comment(linker, "/Section:Shared,rws")

HMODULE hmodThisDll;
#define MyName "DLL.DLL"
typedef struct _IO_STATUS_BLOCK
{
    LONG Status;
    LONG Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;

typedef struct _FILE_NAME_INFORMATION
{
    ULONG FileNameLength;
    WCHAR FileName[MAX_PATH];
} FILE_NAME_INFORMATION;

FARPROC ZwQueryInformationFile;
//通过文件句柄,得到文件所在盘符
BOOL GetVolumeNameByHandle(HANDLE hFile, char *szFullPath){
    //得到所有磁盘卷的卷序号
    char szBuf[500];
    int i;
    DWORD dwVolumeSerialNumber;
    memset(szBuf, 0, sizeof(szBuf));
    //通过句柄得到文件的卷序号
    //得到卷序号 lpFileInformation.dwVolumeSerialNumber
    BY_HANDLE_FILE_INFORMATION lpFileInformation;
    if(!GetFileInformationByHandle(hFile, &lpFileInformation) || (lpFileInformation.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)){
        //通过句柄得到文件信息失败 或者 此句柄为文件夹句柄,并非文件句柄
        return FALSE;
    }
    if(::GetLogicalDriveStringsA(sizeof(szBuf) - 1,szBuf)){
        for(i = 0; szBuf[i]; i += 4){
            //得到卷信息->卷序号
            if(!stricmp(&(szBuf[i]), "A:\\") || !stricmp(&(szBuf[i]), "B:\\")){
                //忽略软盘 (一般不会使用,并且查询它的速度非常之慢)
                continue;
            }
            if(GetVolumeInformationA(&(szBuf[i]), NULL, NULL,&dwVolumeSerialNumber,NULL, NULL, NULL, NULL)){
                // 与 lpFileInformation.dwVolumeSerialNumber 比较
                // 如果相同,则找到该磁盘
                if(dwVolumeSerialNumber == lpFileInformation.dwVolumeSerialNumber){
                    //找到
                    char szVolumeName[4];
                    memset(szVolumeName, 0, sizeof(szVolumeName));
                    strcpy(szVolumeName, &(szBuf[i]));
                    szVolumeName[strlen(szVolumeName)-1] = '\0';
                    //得到路径
                    IO_STATUS_BLOCK isb;
                    FILE_NAME_INFORMATION fni;
                    HMODULE hNt = LoadLibraryA("ntdll.dll");
                    if(hNt){
                        ZwQueryInformationFile = ::GetProcAddress(hNt, "ZwQueryInformationFile");
                        if(ZwQueryInformationFile){
                            DWORD dwfni = sizeof(fni);
                            DWORD dwRet = 0;
                            __asm{
                                push 9 ;
                                push dwfni ;
                                lea eax, fni ;
                                push eax ;
                                lea eax, isb ;
                                push eax ;
                                push hFile ;
                                mov eax, ZwQueryInformationFile ;
                                call eax ;//调用 ZwQueryInformationFile 函数
                                mov dwRet, eax;//得到返回值
                            }
                            if(!dwRet){
                                //获取文件路径成功
                                fni.FileName[fni.FileNameLength/2] = 0;
                                //构造成完整路径名
                                char szFilePath[MAX_PATH+1];
                                memset(szFilePath, 0, sizeof(szFilePath));
                                WideCharToMultiByte( CP_ACP, 0, fni.FileName, -1, szFilePath, sizeof(szFilePath) - 1, NULL, NULL);
                                sprintf(szFullPath, "%s%s", szVolumeName, szFilePath);
                                return TRUE;
                            }
                        }
                        FreeLibrary(hNt);
                    }
                }
            }
        }
    }
    //没有找到
    return FALSE;
}
LRESULT CALLBACK GetMsgProc( int nCode,WPARAM wParam,LPARAM lParam){
    return CallNextHookEx(hhk,nCode,wParam,lParam);
}
BOOL MyWriteFile(
                 HANDLE hFile, // 文件句柄
                 LPCVOID lpBuffer,// 数据缓存区指针
                 DWORD nNumberOfBytesToWrite, // 你要写的字节数
                 LPDWORD lpNumberOfBytesWritten, // 用于保存实际写入字节数的存储区域的指针
                 LPOVERLAPPED lpOverlapped // OVERLAPPED结构体指针
                 ){
    char szFullPath[MAX_PATH];
    memset(szFullPath, 0, sizeof(szFullPath));
    if(GetVolumeNameByHandle(hFile, szFullPath))
    {
        MessageBoxA(NULL,szFullPath,"DLL",MB_OK);
    }
    else MessageBoxA(NULL,"HOOK","DLL",MB_OK);
    return WriteFile(hFile,lpBuffer,nNumberOfBytesToWrite,lpNumberOfBytesWritten,lpOverlapped);
}
BOOL MyWriteFileEx( HANDLE hFile,
                   LPCVOID lpBuffer,
                   DWORD nNumberOfBytesToWrite,
                   LPOVERLAPPED lpOverlapped,
                   LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
                   ){
    char szFullPath[MAX_PATH];
    memset(szFullPath, 0, sizeof(szFullPath));
    if(GetVolumeNameByHandle(hFile, szFullPath))
    {
        MessageBoxA(NULL,szFullPath,"DLL",MB_OK);
    }
    else MessageBoxA(NULL,"HOOK","DLL",MB_OK);
    return WriteFileEx(hFile,lpBuffer,nNumberOfBytesToWrite,lpOverlapped,lpCompletionRoutine);
}
BOOL WINAPI MyWriteFileGather( HANDLE hFile,
                              FILE_SEGMENT_ELEMENT aSegmentArray[],
                              DWORD nNumberOfBytesToWrite,
                              LPDWORD lpReserved,
                              LPOVERLAPPED lpOverlapped
                              ){
    char szFullPath[MAX_PATH];
    memset(szFullPath, 0, sizeof(szFullPath));
    if(GetVolumeNameByHandle(hFile, szFullPath))
    {
        MessageBoxA(NULL,szFullPath,"DLL",MB_OK);
    }
    else MessageBoxA(NULL,"HOOK","DLL",MB_OK);
    return WriteFileGather(hFile,aSegmentArray,nNumberOfBytesToWrite,lpReserved,lpOverlapped);
}
VOID ModifyIAT(HMODULE hmodCaller,LPCSTR szDllName,PROC pfnOrg,PROC pfnNew){
    PIMAGE_THUNK_DATA pITD;
    ULONG ulSize;
    PIMAGE_IMPORT_DESCRIPTOR pIID;
    pIID = (PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData(hmodCaller,TRUE,IMAGE_DIRECTORY_ENTRY_IMPORT,&ulSize);
    if( !pIID )
        return;
    for( ; pIID->Name; pIID++ ){
        if( !lstrcmpiA(szDllName,(LPSTR)((PBYTE)hmodCaller+pIID->Name)) )
            break;
    }
    if( !pIID->Name )
        return;
    pITD = (PIMAGE_THUNK_DATA)((PBYTE)hmodCaller+pIID->FirstThunk);
    for( ; pITD->u1.Function ; pITD++ ){
        PROC* ppfn = (PROC*)&pITD->u1.Function;
        if(*ppfn == pfnOrg){
            WriteProcessMemory(GetCurrentProcess(),ppfn,&pfnNew,sizeof(pfnNew),NULL);
            return;
        }
    }
}
VOID ModifyIATs(LPCSTR szDllName,PROC pfnOrg,PROC pfnNew){
    BOOL fOk = FALSE;
    MODULEENTRY32 me32;
    HANDLE hSnapshot;
    hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,GetCurrentProcessId());
    me32.dwSize = sizeof( me32 );
    for( fOk = Module32First( hSnapshot,&me32 ); fOk ; fOk = Module32Next(hSnapshot,&me32)){
        if( me32.hModule != hmodThisDll ){
            ModifyIAT(me32.hModule,szDllName,pfnOrg,pfnNew);
        }
    }
    CloseHandle( hSnapshot );
}
FARPROC WINAPI MyGetProcAddress( HMODULE hModule,LPCSTR lpProcName ){
    if( hModule == GetModuleHandle("kernel32.DLL") &&
        !lstrcmpiA(lpProcName,"WriteFile") )
        return (PROC)MyWriteFile;
    else
        return GetProcAddress( hModule,lpProcName );
}
HMODULE WINAPI MyLoadLibraryA( LPCSTR lpLibFileName ){
    HMODULE hmod = LoadLibraryA( lpLibFileName );
    ModifyIAT(hmod,"kernel32.DLL",GetProcAddress(GetModuleHandle("kernel32.DLL"),"WriteFile"),(PROC)MyWriteFile);
    ModifyIAT(hmod,"KERNEL32.DLL",GetProcAddress(GetModuleHandle("KERNEL32.DLL"),"GetProcAddress"),(PROC)MyGetProcAddress);
    ModifyIAT(hmod,"KERNEL32.DLL",GetProcAddress(GetModuleHandle("KERNEL32.DLL"),"WriteFileEx"),(PROC)MyWriteFileEx);
    ModifyIAT(hmod,"KERNEL32.DLL",GetProcAddress(GetModuleHandle("KERNEL32.DLL"),"WriteFileGather"),(PROC)MyWriteFileGather);
    return hmod;
}
HMODULE WINAPI MyLoadLibraryW( LPCWSTR  lpLibFileName ){
    HMODULE hmod = LoadLibraryW( lpLibFileName );
    ModifyIAT(hmod,"kernel32.DLL",GetProcAddress(GetModuleHandle("kernel32.DLL"),"WriteFile"),(PROC)MyWriteFile);
    ModifyIAT(hmod,"KERNEL32.DLL",GetProcAddress(GetModuleHandle("KERNEL32.DLL"),"GetProcAddress"),(PROC)MyGetProcAddress);
    ModifyIAT(hmod,"KERNEL32.DLL",GetProcAddress(GetModuleHandle("KERNEL32.DLL"),"WriteFileEx"),(PROC)MyWriteFileEx);
    ModifyIAT(hmod,"KERNEL32.DLL",GetProcAddress(GetModuleHandle("KERNEL32.DLL"),"WriteFileGather"),(PROC)MyWriteFileGather);
    return hmod;
}
HMODULE WINAPI MyLoadLibraryExA(LPCTSTR lpFileName,HANDLE hFile,DWORD dwFlags){
    HMODULE hmod = LoadLibraryExA( lpFileName,hFile,dwFlags);
    ModifyIAT(hmod,"kernel32.DLL",GetProcAddress(GetModuleHandle("kernel32.DLL"),"WriteFile"),(PROC)MyWriteFile);
    ModifyIAT(hmod,"KERNEL32.DLL",GetProcAddress(GetModuleHandle("KERNEL32.DLL"),"GetProcAddress"),(PROC)MyGetProcAddress);
    ModifyIAT(hmod,"KERNEL32.DLL",GetProcAddress(GetModuleHandle("KERNEL32.DLL"),"WriteFileEx"),(PROC)MyWriteFileEx);
    ModifyIAT(hmod,"KERNEL32.DLL",GetProcAddress(GetModuleHandle("KERNEL32.DLL"),"WriteFileGather"),(PROC)MyWriteFileGather);
    return hmod;
}
HMODULE WINAPI MyLoadLibraryExW(LPCWSTR lpFileName,HANDLE hFile,DWORD dwFlags){
    HMODULE hmod = LoadLibraryExW(lpFileName,hFile,dwFlags);
    ModifyIAT(hmod,"kernel32.DLL",GetProcAddress(GetModuleHandle("kernel32.DLL"),"WriteFile"),(PROC)MyWriteFile);
    ModifyIAT(hmod,"KERNEL32.DLL",GetProcAddress(GetModuleHandle("KERNEL32.DLL"),"GetProcAddress"),(PROC)MyGetProcAddress);
    ModifyIAT(hmod,"KERNEL32.DLL",GetProcAddress(GetModuleHandle("KERNEL32.DLL"),"WriteFileEx"),(PROC)MyWriteFileEx);
    ModifyIAT(hmod,"KERNEL32.DLL",GetProcAddress(GetModuleHandle("KERNEL32.DLL"),"WriteFileGather"),(PROC)MyWriteFileGather);
    return hmod;
}
extern "C"_declspec(dllexport) VOID SetHook( ){
    if( !hhk ){
        HINSTANCE hInst = LoadLibrary(MyName);
        if( !hInst )
            return;
        hhk = SetWindowsHookEx(WH_GETMESSAGE,GetMsgProc,hInst,0);
        FreeLibrary( hInst );
    }
}
extern"C"_declspec(dllexport) VOID UnHook(){
    if( hhk )
        UnhookWindowsHookEx( hhk );
}
BOOL WINAPI DllMain(HINSTANCE hInstance,DWORD dwReason,LPVOID lpvReserved){
    hmodThisDll = hInstance;
    switch( dwReason ){
    case DLL_PROCESS_ATTACH:
        ModifyIATs("kernel32.DLL",GetProcAddress(GetModuleHandle("kernel32.DLL"),      "WriteFile"),(PROC)MyWriteFile);
        ModifyIATs("KERNEL32.DLL",GetProcAddress(GetModuleHandle("KERNEL32.DLL"),   "LoadLibraryA"),(PROC)MyLoadLibraryA);
        ModifyIATs("KERNEL32.DLL",GetProcAddress(GetModuleHandle("KERNEL32.DLL"),   "LoadLibraryW"),(PROC)MyLoadLibraryW);
        ModifyIATs("KERNEL32.DLL",GetProcAddress(GetModuleHandle("KERNEL32.DLL"), "LoadLibraryExA"),(PROC)MyLoadLibraryExA);
        ModifyIATs("KERNEL32.DLL",GetProcAddress(GetModuleHandle("KERNEL32.DLL"), "LoadLibraryExW"),(PROC)MyLoadLibraryExW);
        ModifyIATs("KERNEL32.DLL",GetProcAddress(GetModuleHandle("KERNEL32.DLL"), "GetProcAddress"),(PROC)MyGetProcAddress);
        ModifyIATs("KERNEL32.DLL",GetProcAddress(GetModuleHandle("KERNEL32.DLL"),    "WriteFileEx"),(PROC)MyWriteFileEx);
        ModifyIATs("KERNEL32.DLL",GetProcAddress(GetModuleHandle("KERNEL32.DLL"),"WriteFileGather"),(PROC)MyWriteFileGather);
        break;
    case DLL_PROCESS_DETACH:
        ModifyIATs("KERNEL32.DLL",(PROC)MyWriteFile      ,GetProcAddress(GetModuleHandle("kernel32.DLL"),"WriteFile"));
        ModifyIATs("KERNEL32.DLL",(PROC)MyLoadLibraryA   ,GetProcAddress(GetModuleHandle("KERNEL32.DLL"),"LoadLibraryA"));
        ModifyIATs("KERNEL32.DLL",(PROC)MyLoadLibraryW   ,GetProcAddress(GetModuleHandle("KERNEL32.DLL"),"LoadLibraryW"));
        ModifyIATs("KERNEL32.DLL",(PROC)MyLoadLibraryExA ,GetProcAddress(GetModuleHandle("KERNEL32.DLL"),"LoadLibraryExA"));
        ModifyIATs("KERNEL32.DLL",(PROC)MyLoadLibraryExW ,GetProcAddress(GetModuleHandle("KERNEL32.DLL"),"LoadLibraryExW"));
        ModifyIATs("KERNEL32.DLL",(PROC)MyGetProcAddress ,GetProcAddress(GetModuleHandle("KERNEL32.DLL"),"GetProcAddress"));
        ModifyIATs("KERNEL32.DLL",(PROC)MyWriteFileEx    ,GetProcAddress(GetModuleHandle("KERNEL32.DLL"),"WriteFileEx"));
        ModifyIATs("KERNEL32.DLL",(PROC)MyWriteFileGather,GetProcAddress(GetModuleHandle("KERNEL32.DLL"),"WriteFileGather"));
        break;
    }
    return TRUE;
}

进行了比较全面的拦截,不过会造成系统不稳定,特别是LoadLibararyExA和LoadLibararyExW函数的拦截。另外令人纠结的是fopen打开的文件写操作没有拦截成功,自然freopen这些重定向的也不能成功啦,所有应用层DLL注入的方法实现文件write的过滤是非常不合理的想法,很难做全面的拦截,而且影响系统的正常运行。全面的文件过滤在这个实验里面,不得不承认api hook技术无法承担这个重任,看来只有驱动层能够实现真正意义上的完整文件过滤

[注意] 欢迎加入看雪团队!base上海,招聘安全工程师、逆向工程师多个坑位等你投递!

上传的附件:
收藏
点赞0
打赏
分享
最新回复 (13)
雪    币: 2081
活跃值: 活跃值 (109)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
exile 活跃值 1 2012-2-3 19:46
2
0
ntdll!ZwWriteFile
雪    币: 126
活跃值: 活跃值 (30)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
zhxfl 活跃值 2 2012-2-3 19:54
3
0
ZwWriteFile  好像是内核态才可以用的?我这里只hook应用层的
雪    币: 2081
活跃值: 活跃值 (109)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
exile 活跃值 1 2012-2-3 19:57
4
0
谁说ZwWriteFile就是内核的 ntdll里面不是还有个ZwWriteFile
雪    币: 5
活跃值: 活跃值 (18)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zgyknight 活跃值 2012-2-3 20:04
5
0
mark!!
雪    币: 126
活跃值: 活跃值 (30)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
zhxfl 活跃值 2 2012-2-3 20:15
6
0
查了一下ntdll的导出函数,确实有ZwWriteFile,感激
上传的附件:
雪    币: 2081
活跃值: 活跃值 (109)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
exile 活跃值 1 2012-2-3 20:17
7
0
hook 的时候 先用OD看看每个函数最终会调用最底层的函数是什么  然后HOOK之
雪    币: 126
活跃值: 活跃值 (30)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
zhxfl 活跃值 2 2012-2-3 20:19
8
0
大神最底层指的是内核态吗
雪    币: 126
活跃值: 活跃值 (30)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
zhxfl 活跃值 2 2012-2-3 20:21
9
0
上面那个代码对于c语言库的fwrite没作用,fwrite这个函数hook不了吗?
雪    币: 1480
活跃值: 活跃值 (74)
能力值: ( LV15,RANK:670 )
在线值:
发帖
回帖
粉丝
cntrump 活跃值 13 2012-2-3 22:14
10
0
正解,可以拦截到很多了。
雪    币: 126
活跃值: 活跃值 (30)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
zhxfl 活跃值 2 2012-2-3 22:26
11
0
fwrite这个怎么hook
雪    币: 220
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
广海混沌 活跃值 2012-2-3 22:50
12
0
呵呵 不错 不错
雪    币: 1047
活跃值: 活跃值 (229)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
天涯一鸿 活跃值 2012-2-3 23:05
13
0
fwirte没调用Zw(Nt)WriteFile?用OD跟一下……
雪    币: 126
活跃值: 活跃值 (30)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
zhxfl 活跃值 2 2012-2-3 23:31
14
0
这样说,所有的写操作在应用层都可以hook到,只要找到最底层的函数就行吗?
游客
登录 | 注册 方可回帖
返回