2012年10月25日 星期四

SetWindowHookEx to Inject DLL

要使用inject dll的技術並不困難, 雖然CreateRemoteThread的使用上非常的有創意, 但是我們還是可以用比較方便的方法來達成這件事情。

下面就演示如何使用SetWindowHookEx

 

// DllInjection.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <windows.h>
#include <TlHelp32.h>
#include <Shlwapi.h>
#include <vector>

unsigned long GetTargetThreadIdFromProcname(char *procName, std::vector<unsigned long>& allThread) {
PROCESSENTRY32 pe;
HANDLE thSnapshot, hProcess;
BOOL retval, ProcFound = false;
unsigned long pTID, threadID;
thSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if(thSnapshot == INVALID_HANDLE_VALUE) {
MessageBox(NULL, "Error: unable to create toolhelp snapshot", "Loader", NULL);
return false;
}
pe.dwSize = sizeof(PROCESSENTRY32);
retval = Process32First(thSnapshot, &pe);
while(retval) {
if(StrStrI(pe.szExeFile, procName) ) {
ProcFound = true;
break;
}
retval = Process32Next(thSnapshot,&pe);
pe.dwSize = sizeof(PROCESSENTRY32);
}

CloseHandle(thSnapshot);

thSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
THREADENTRY32 tEntry;
tEntry.dwSize = sizeof(THREADENTRY32);
DWORD result = 0;
DWORD currentPID = pe.th32ProcessID;

for (BOOL success = Thread32First(thSnapshot, &tEntry);
!result && success && GetLastError() != ERROR_NO_MORE_FILES;
success = Thread32Next(thSnapshot, &tEntry)) {
if (tEntry.th32OwnerProcessID == currentPID) {
allThread.push_back(tEntry.th32ThreadID);
}
}
CloseHandle(thSnapshot);
return result;
}

BOOL InjectDll(char *dllName) {
HMODULE hDll;
FARPROC cbtProcAddr;
hDll = LoadLibrary(dllName);
cbtProcAddr = GetProcAddress(hDll, "CBTProc");
std::vector<unsigned long> allThread;
std::vector<HHOOK> vecHook;
GetTargetThreadIdFromProcname("calc.exe", allThread);
//for(size_t i = 0; i < allThread.size(); ++i) {
// HHOOK hHook = SetWindowsHookEx(WH_DEBUG, (HOOKPROC)cbtProcAddr, hDll, allThread.at(i));
// vecHook.push_back(hHook);
//}
HHOOK hHook = SetWindowsHookEx(WH_DEBUG, (HOOKPROC)cbtProcAddr, hDll, allThread.at(0));
vecHook.push_back(hHook);
getc(stdin);
for(size_t i = 0; i < vecHook.size(); ++i) {
BOOL bUnHook = UnhookWindowsHookEx(vecHook.at(i));
}
return TRUE;
}

int _tmain(int argc, _TCHAR* argv[])
{
InjectDll("Inject.dll");
return 0;
}


另一個DLL的文檔:

// Inject.cpp : Defines the entry point for the DLL application.
//

#include "stdafx.h"
#include "Inject.h"
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <io.h>
#include <fcntl.h>
using namespace std;

#ifdef _MANAGED
#pragma managed(push, off)
#endif

LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam)
{
//MessageBox(NULL, "Hooked", "Hook error", MB_OK);
printf("Get Code: %ld\n", nCode);
printf("wParam: %lld\n", wParam);
printf("LPARAM: %lld\n", lParam);
return CallNextHookEx(0, nCode, wParam, lParam);
}

BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
ofstream fout;
char fileName[MAX_PATH] = {""};
sprintf(fileName, "C:\\testDll%d.txt", (int)GetCurrentProcessId());
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
fout.open(fileName);
fout << "dll type(" << ul_reason_for_call << ") in process(" << GetCurrentProcessId() << ")" << endl;
fout.flush();
}
{
#ifdef _DEBUG
AllocConsole();
SetConsoleTitleW(L"Windows Event Log Tracer Console");
HANDLE handle_out = GetStdHandle(STD_OUTPUT_HANDLE);
int hCrtOut = _open_osfhandle(/*(long)*/(intptr_t) handle_out, _O_TEXT);
FILE* hf_out = _fdopen(hCrtOut, "w");
setvbuf(hf_out, NULL, _IONBF, 1);
*stdout = *hf_out;

HANDLE handle_in = GetStdHandle(STD_INPUT_HANDLE);
int hCrtIn = _open_osfhandle(/*(long)*/(intptr_t) handle_in, _O_TEXT);
FILE* hf_in = _fdopen(hCrtIn, "r");
setvbuf(hf_in, NULL, _IONBF, 128);
*stdin = *hf_in;
#endif
}
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
fout.close();
break;
}
return TRUE;
}

#ifdef _MANAGED
#pragma managed(pop)
#endif

如此一來便可以讓我們把這個dll加入calc.exe裡, 這裡的calc就是windows內的小算盤。
上面還使用了一些方法得知一個process裡有多少thread及thread ID, 也算是一個小方法讓大家可以不用hook所有的process之後再到dll裡去查自身的module name, 算得上是一個好方法, 因為如果去hook所有的process是有點危險的。

沒有留言: