在notepad.exe中挂钩CreateFile不会捕获API调用

Sue*_*ode 2 c++ dll hook winapi

我的最终目标是通过在kernel32.dll中挂钩文件api来跟踪explorer.exe完成的文件操作,但是我还没有完成它的工作(explorer.exe没有调用API,或者我的结果有问题).为了弄清楚发生了什么,我设定了一个目标来跟踪notepad.exe创建文件的时间,但是由于某种原因这也失败了!

我有3个Visual Studio 2012 C++项目:我的DLL,一个DLL注入器,它将强制任何可执行文件加载我的dll(虽然如果Unicode/Multibyte和32/64bit设置不匹配可能会失败),以及一个测试程序,调用API.我有一个批处理文件,它将启动我的测试程序,然后使用注入器程序将我的DLL加载到测试程序中.奇怪的是输出确实显示在测试程序上跟踪API(生成控制台并打印所有内容!)但是没有任何事情发生在notepad.exe(没有控制台=没有捕获操作).

这是挂钩API的DLL(使用mhook库).格式和概念取自指南.需要注意的重要事项是我挂起CreateFile(A/W),并在第一次操作发生时生成一个控制台来打印文件I/O日志.

#include "stdafx.h"
#include "mhook/mhook-lib/mhook.h"

//////////////////////////////////////////////////////////////////////////
// Defines and typedefs
typedef HANDLE (WINAPI *CreateFileWFP)(
    _In_ LPCWSTR lpFileName,
    _In_ DWORD dwDesiredAccess,
    _In_ DWORD dwShareMode,
    _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
    _In_ DWORD dwCreationDisposition,
    _In_ DWORD dwFlagsAndAttributes,
    _In_opt_ HANDLE hTemplateFile
    );
typedef HANDLE (WINAPI *CreateFileAFP)(
    _In_ LPCSTR lpFileName,
    _In_ DWORD dwDesiredAccess,
    _In_ DWORD dwShareMode,
    _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
    _In_ DWORD dwCreationDisposition,
    _In_ DWORD dwFlagsAndAttributes,
    _In_opt_ HANDLE hTemplateFile
    );

//////////////////////////////////////////////////////////////////////////
// Original function
CreateFileWFP OriginalCreateFileW = (CreateFileWFP)::GetProcAddress(::GetModuleHandle(TEXT("kernel32")), "CreateFileW");
CreateFileAFP OriginalCreateFileA = (CreateFileAFP)::GetProcAddress(::GetModuleHandle(TEXT("kernel32")), "CreateFileA");

//////////////////////////////////////////////////////////////////////////
// Some Helper Stuff

struct Console{
    HANDLE handle;

    Console(){ handle = INVALID_HANDLE_VALUE; }

    void write(LPCWSTR text){
        if(handle==INVALID_HANDLE_VALUE){
            AllocConsole();
            handle = GetStdHandle(STD_OUTPUT_HANDLE);
        }
        DWORD numCharsWritten = 0;
        WriteConsoleW(handle, text, (DWORD)wcslen(text), &numCharsWritten,NULL);
    }
    void write(LPCSTR text){
        if(handle==INVALID_HANDLE_VALUE){
            AllocConsole();
            handle = GetStdHandle(STD_OUTPUT_HANDLE);
        }
        DWORD numCharsWritten = 0;
        WriteConsoleA(handle, text, (DWORD)strlen(text), &numCharsWritten,NULL);
    }
} console;

void operationPrint(LPCWSTR left, LPCWSTR middle, LPCWSTR right){
    console.write(left);
    console.write(middle);
    console.write(right);
    console.write(L"\n");
}
void operationPrint(LPCSTR left, LPCSTR middle, LPCSTR right){
    console.write(left);
    console.write(middle);
    console.write(right);
    console.write(L"\n");
}

//////////////////////////////////////////////////////////////////////////
// Hooked function

HANDLE HookedCreateFileW(
    _In_ LPCWSTR lpFileName,
    _In_ DWORD dwDesiredAccess,
    _In_ DWORD dwShareMode,
    _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
    _In_ DWORD dwCreationDisposition,
    _In_ DWORD dwFlagsAndAttributes,
    _In_opt_ HANDLE hTemplateFile
    ){
        HANDLE out = OriginalCreateFileW(
                        lpFileName,
                        dwDesiredAccess,
                        dwShareMode,
                        lpSecurityAttributes,
                        dwCreationDisposition,
                        dwFlagsAndAttributes,
                        hTemplateFile);
        if(out == INVALID_HANDLE_VALUE) return out; //ignore failiures
        operationPrint(L"CreatedW file",L" at ",lpFileName);
        return out;
}
HANDLE HookedCreateFileA(
    _In_ LPCSTR lpFileName,
    _In_ DWORD dwDesiredAccess,
    _In_ DWORD dwShareMode,
    _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
    _In_ DWORD dwCreationDisposition,
    _In_ DWORD dwFlagsAndAttributes,
    _In_opt_ HANDLE hTemplateFile
    ){
        HANDLE out = OriginalCreateFileA(
                        lpFileName,
                        dwDesiredAccess,
                        dwShareMode,
                        lpSecurityAttributes,
                        dwCreationDisposition,
                        dwFlagsAndAttributes,
                        hTemplateFile);
        if(out == INVALID_HANDLE_VALUE) return out; //ignore failiures
        operationPrint("CreatedA file"," at ",lpFileName);
        return out;
}

//////////////////////////////////////////////////////////////////////////
// Entry point

BOOL WINAPI DllMain(
    __in HINSTANCE  hInstance,
    __in DWORD      Reason,
    __in LPVOID     Reserved
    )
{        
    switch (Reason)
    {
    case DLL_PROCESS_ATTACH:
        Mhook_SetHook((PVOID*)&OriginalCreateFileW, HookedCreateFileW);
        Mhook_SetHook((PVOID*)&OriginalCreateFileA, HookedCreateFileA);
        break;

    case DLL_PROCESS_DETACH:
        FreeConsole();
        Mhook_Unhook((PVOID*)&OriginalCreateFileW);
        Mhook_Unhook((PVOID*)&OriginalCreateFileA);
        break;
    }

    return TRUE;
}
Run Code Online (Sandbox Code Playgroud)

我找不到我找到注射器程序的确切位置,但它几乎指南相同.有些评论甚至是相同的,所以我很确定一个人从另一个人那里拿走了(不知道从哪个人那里拿走了).在任何情况下,我只是做了一些小改动,以便在Unicode或Multibyte下编译时它可以工作.我不会在这里发布整个代码,除非我要求,因为我认为这是浪费空间,但这是重要的部分.

#include "Injector.h"
#include <windows.h>
#include <tlhelp32.h>
#include <shlwapi.h>
#include <conio.h>
#include <stdio.h> 
#include "DebugPrint.h"
#include <atlbase.h>

using namespace std;

Injector::Injector(void)
{
}


Injector::~Injector(void)
{
} 

#define CREATE_THREAD_ACCESS (PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ) 

bool Injector::Inject(string procName, string dllName){
   DWORD pID = GetTargetThreadIDFromProcName(procName.c_str()); 
   return Inject(pID,dllName);
}

bool Injector::Inject(DWORD pID, string dllName){
   const char* DLL_NAME = dllName.c_str();

   HANDLE Proc = 0; 
   HMODULE hLib = 0; 
   LPVOID RemoteString, LoadLibAddy; 

   if(!pID) 
      return false; 

   Proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pID); 
   if(!Proc) 
   { 
      DEBUG_PRINT("OpenProcess() failed: %d", GetLastError()); 
      return false; 
   } 

   LoadLibAddy = (LPVOID)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "LoadLibraryA"); 

   // Allocate space in the process for our <strong class="highlight">DLL</strong> 
   RemoteString = (LPVOID)VirtualAllocEx(Proc, NULL, strlen(DLL_NAME), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); 

   // Write the string name of our <strong class="highlight">DLL</strong> in the memory allocated 
   WriteProcessMemory(Proc, (LPVOID)RemoteString, DLL_NAME, strlen(DLL_NAME), NULL); 

   // Load our <strong class="highlight">DLL</strong> 
   CreateRemoteThread(Proc, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibAddy, (LPVOID)RemoteString, NULL, NULL); 

   CloseHandle(Proc); 
   return true; 
}

DWORD Injector::GetTargetThreadIDFromProcName(const char* ProcName)
{
    PROCESSENTRY32 pe;
    HANDLE thSnapShot;
    BOOL retval, ProcFound = false;

    thSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if(thSnapShot == INVALID_HANDLE_VALUE)
    {
        //MessageBox(NULL, "Error: Unable to create toolhelp snapshot!", "2MLoader", MB_OK);
        DEBUG_PRINT("Error: Unable to create toolhelp snapshot!");
        return false;
    }

    pe.dwSize = sizeof(PROCESSENTRY32);

    retval = Process32First(thSnapShot, &pe);
    while(retval)
    {
#ifdef _UNICODE
        char peSzExeFile[MAX_PATH];
        wcstombs_s(NULL,peSzExeFile,MAX_PATH,pe.szExeFile,MAX_PATH);
#else
        const char* peSzExeFile = pe.szExeFile;
#endif
        DEBUG_PRINT("\nSearching for process: %s ",peSzExeFile);
        if(!strcmp(peSzExeFile, ProcName))
        {
            DEBUG_PRINT(" Found!\n\n");
            return pe.th32ProcessID;
        }
        retval = Process32Next(thSnapShot, &pe);
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

最后,我的测试程序只调用一些文件API来查看注入的DLL是否可以捕获它们.如前所述,它确实很成功地捕获了这些调用.

#include <windows.h>
#include <tchar.h>

using namespace std;

#ifdef _UNICODE
#define printf(X,...) wprintf(TEXT(X),__VA_ARGS__); //I don't want to have to keep replacing printf whenever I switch to Unicode or Multibyte
#endif

#ifdef _DEBUG
int _tmain(int argc, TCHAR* argv[]){ //makes a console.  printf() will have a place to go in this case
#else
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){ //no console
#endif
    Sleep(2000); //let DLL finish loading

    LPCTSTR fileSrc = TEXT("C:\\Users\\jajoach\\Desktop\\hi.txt");
    LPCTSTR fileDst = TEXT("C:\\Users\\jajoach\\Desktop\\hi\\hi.txt");

    printf("Moving file from %s to %s\n",fileSrc,fileDst);
    MoveFile(fileSrc,fileDst);
    Sleep(1000);

    printf("Moving file from %s to %s\n",fileSrc,fileDst);
    MoveFile(fileDst,fileSrc);
    Sleep(1000);

    printf("Copying file from %s to %s\n",fileSrc,fileDst);
    CopyFile(fileSrc,fileDst,true);
    Sleep(1000);

    printf("Deleting file %s\n",fileDst);
    DeleteFile(fileDst);
    Sleep(1000);

    printf("Creating file %s\n",fileDst);
    HANDLE h=CreateFile(fileDst,0,0,NULL,CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL);
    Sleep(1000);

    printf("Deleting file %s\n",fileDst);
    CloseHandle(h);
    DeleteFile(fileDst);

    Sleep(5000);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这是Unicode的确认输出(由'W'和释放模式指出),以及我从notepad.exe和explorer.exe中得到的(但没有得到).为了记录,该测试也适用于多字节,但是按照预期给出'A'. 在此输入图像描述

我曾经想过,explorer.exe和notepad.exe可能不会将这些API用于他们的文件I/O,但我的研究却说不然. 帖子使用Detours在notepad.exe中挂钩CreateFile并报告该应用程序的成功.此外,ProgramMonitor清楚地显示了在Saveas操作期间调用CreateFile的notepad.exe (在许多具有不同参数的失败请求之后...): 在此输入图像描述

暂时没关系explorer.exe; 当我做Saveas时,为什么我的钩子不能用于notepad.exe?

编辑:我忘了提到我还使用测试程序挂钩MoveFile(A/W)和CopyFile(A/W),但为了简洁,我在这篇文章中从DLL中删除了该代码.

rod*_*igo 5

如OP的评论中所述,似乎notepad.exe使用ASLR并且您的测试程序没有.这样,LoadLibraryA的地址在每个进程中都会有所不同,并且您的注入代码会失败.

情况是您正在获取LoadLibraryA注入器地址空间中的地址并假设它与目标进程中的地址相同.这通常是正确的,但ASLR专门设计用于使该假设失败.它确实......你创建的线程得到了一个可能无效的地址,并且失败了.