我的最終目標是通過在kernel32.dll中掛鉤文件api來跟蹤explorer.exe完成的文件操作,但是我還沒有得到那個工作(explorer.exe是沒有調用這些API,或者我的結果是錯誤的)。爲了弄清楚發生了什麼,我設定了一個目標,以便隨時記錄notepad.exe創建文件的情況,但由於某種原因,這也失敗了!我有3個Visual Studio 2012 C++項目:我的DLL,一個DLL注入器,將強制任何可執行文件加載我的DLL(儘管如果Unicode /多字節和32/64位設置不匹配,它可能會失敗),以及一個調用API的測試程序。我有一個批處理文件將啓動我的測試程序,然後使用注入程序將我的DLL加載到測試程序中。怪異的部分是輸出做表明API正在測試程序(產生控制檯和打印的一切!),但沒有發生notepad.exe(沒有控制檯=沒有操作被捕獲)的跟蹤。在notepad.exe中掛鉤CreateFile不會捕獲API調用
這是鉤住API的DLL(使用mhook庫)。格式和概念取自this指南。需要注意的重要事項是,我掛鉤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;
}
我無法找到確切位置,我發現噴油器程序,但它是幾乎相同this指南。有些評論甚至是相同的,所以我很確定一個從另一個拿走(不確定哪個是誰)。無論如何,我只是做了小的修改,以便在編譯時使用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;
}
最後,我的測試程序只是調用一些文件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;
}
這裏是Unicode的確認輸出(由「W的說明)和發佈模式,我是來自NOTEPAD.EXE和Explorer.exe的期待是什麼(但沒有得到)。爲了記錄,該測試也適用於Multibyte,但是會按照預期給出'A'。
我曾經想過,也許explorer.exe和notepad.exe不會將這些API用於他們的文件I/O,但是我的研究表明否則。 This使用Detours在notepad.exe中掛鉤CreateFile並報告該應用程序的成功。此外,ProgramMonitor清楚地表明NOTEPAD.EXE一個Saveas
操作過程中調用CreateFile(使用不同的參數很多失敗的請求後...):
沒關係約explorer.exe的現在; 當我做Saveas時,爲什麼我的鉤子不能用於notepad.exe?
編輯:我忘了提及,我也與測試程序鉤MoveFile(A/W)和的CopyFile(A/W),但我除去來自DLL的代碼對這個職位贅述。
你說,如果32/64位不匹配,它會失敗......你確定你注入的DLL具有與'notepad.exe'相同的_bitness_嗎?請注意,在64位Windows中,大多數包含的應用程序都是64位的。 – rodrigo
我嘗試了32/64bit和Unicode/Multibyte的所有4種組合(儘管現在我認爲後者並不重要,因爲我特別定義了每個字符串是什麼)。 – Suedocode
@rodrigo我把它拿回來;事實證明,問題在於我的注射器。由於某種原因,它與我的測試應用程序一起工作,但不是其他的東西。我只是找到了,因爲我下載了第三方注射器來測試它,並且它工作。我很好奇爲什麼我的注射器不工作... – Suedocode