0x00 简介


这个程序的目的是为了让calc程序显示中文。比如: 我是在XP下使用计算器,上面显示的都是阿拉伯数字,现在要用中文显示,如图所示:

32位下IAT Hook实现计算器修改执行-LMLPHP

使用OD追踪Windows下的calc程序就会发现,计算器的输入框是一个EDIT空间并且calc程序是通过SetWindowTextW来把键入结果显示在EDIT控件上。

32位下IAT Hook实现计算器修改执行-LMLPHP

在SetWindowTextW上下断点后运行程序,在calc程序上输入便会发现在SetWindowTextW上断下。这就证明了这个事实。

32位下IAT Hook实现计算器修改执行-LMLPHP

0x01 原理


由于calc程序是图形界面程序所以USER32.dll必然被加载到calc的线性地址空间中,所以只要在calc中调用GetProcAddress获取其中的SetWindowTextW的地址并且将该API截获替换成我们自己的代码就可以了。采用的方法是IAT Hook。

但是由于保护模式下进程间是隔离的,没办法进入calc的地址空间内,所以需要用到远程线程注入的方式把包含Hook代码的DLL注入到目标进程并运行。

0x02 代码


首先是注入程序:

// 注入程序代码
#include <windows.h>
#include <tchar.h>
#include <TlHelp32.h>
#include <cstdio>

/*
	获取DEBUG权限
*/
BOOL SetPrivileges(LPCTSTR pszPriName, BOOL fEnabled) {
	HANDLE hToken = NULL;
	TOKEN_PRIVILEGES tp = {0};

	if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
		return(FALSE);
	tp.PrivilegeCount = 1;
	tp.Privileges[0].Attributes = fEnabled ? SE_PRIVILEGE_ENABLED : 0;
	if (!LookupPrivilegeValue(NULL, pszPriName, &(tp.Privileges[0].Luid)))
		return(FALSE);
	if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL))
		return(FALSE);

	return(TRUE);
}

/*
	寻找到特定进程的地址空间中的相应DLL模块
	找到后就卸载
*/
PBYTE EnumModules(LPCTSTR pszModuleName, DWORD dwPID) {
	HANDLE hSnapshot = INVALID_HANDLE_VALUE;
	MODULEENTRY32 me = {sizeof(me)};
	BOOL bFound = FALSE;
	__try {
		hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwPID);
		if (INVALID_HANDLE_VALUE == hSnapshot)
			__leave;
		if (!Module32First(hSnapshot, &me))
			__leave;
		do {
			if (!_tcscmp(pszModuleName, me.szModule) ||
				!_tcscmp(pszModuleName, me.szExePath)) {
				bFound = TRUE;
				__leave;
			}
		} while (Module32Next(hSnapshot, &me));

	}
	__finally {
		if (INVALID_HANDLE_VALUE != hSnapshot)
			CloseHandle(hSnapshot);
		if (bFound)
			return(me.modBaseAddr);
	}
	return(NULL);
}

/*
	将指定进程的地址空间中指定模块进行释放
*/
BOOL EjectDll(LPCTSTR pszModuleName, DWORD dwPID) {
	HANDLE hProcess = NULL;
	LPVOID lpMem = NULL;
	DWORD dwSize = 0, dwWrite = 0;
	HMODULE hMod = NULL;
	HANDLE hThread = NULL;
	LPTHREAD_START_ROUTINE pThreadProc = NULL;
	PBYTE pAddr = NULL;

	if (!(pAddr = EnumModules(pszModuleName, dwPID))) {
		_tprintf("模块可能已经被卸载,不存在.\r\n");
		return(TRUE);
	}
	if (!(hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID)))
		return(FALSE);
	dwSize = _tcslen(pszModuleName) + 1;
	lpMem = VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	if (NULL == lpMem)
		return(FALSE);
	if (!WriteProcessMemory(hProcess, lpMem, pszModuleName, dwSize, &dwWrite))
		return(FALSE);
	if (!(hMod = GetModuleHandle("kernel32.dll")))
		return(FALSE);
	pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(hMod, "FreeLibrary");
	hThread = CreateRemoteThread(hProcess, NULL, 0, pThreadProc, (LPVOID)pAddr, 0, NULL);
	if (NULL == hThread)
		return(FALSE);
	WaitForSingleObject(hThread, INFINITE);
	CloseHandle(hProcess);
	CloseHandle(hThread);

	return(TRUE);
}

/*
	遍历进程,寻找对应名称的PID
*/
DWORD EnumProcesses(LPCTSTR pszProcessName) {
	HANDLE hSnapshot = INVALID_HANDLE_VALUE;
	PROCESSENTRY32 pe = {sizeof(pe)};
	BOOL fFind = FALSE;

	__try {
		hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
		if (INVALID_HANDLE_VALUE == hSnapshot)
			__leave;
		if (!Process32First(hSnapshot, &pe))
			__leave;
		do {
			if (!_tcscmp(pszProcessName, pe.szExeFile)) {
				fFind = TRUE;
				__leave;
			}
		} while (Process32Next(hSnapshot, &pe));
	}
	__finally {
		if (hSnapshot != INVALID_HANDLE_VALUE)
			CloseHandle(hSnapshot);
		if (fFind)
			return(pe.th32ProcessID);
	}

	return(-1);
}

/*
	pszDllName: 注入的DLL名称(要用绝对路径)
	pszProcessName: 进程名称, 是被注入目标
*/
BOOL InjectDll(LPCTSTR pszProcessName, LPCTSTR pszDllName) {
	DWORD dwPID = 0;
	HANDLE hProcess = NULL, hThread = NULL;
	LPVOID lpMem = NULL;
	DWORD dwSize = 0, dwWritten = 0;
	LPTHREAD_START_ROUTINE lpProcThread = NULL;
	HMODULE hMod = NULL;
	BOOL fOk = FALSE;

	if (NULL == pszProcessName || NULL == pszDllName)
		return(FALSE);
	if (-1 == (dwPID = EnumProcesses(pszProcessName)))
		return(FALSE);
	if (!(hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID)))
		return(FALSE);
	dwSize = _tcslen(pszDllName) + 1;
	__try {
		lpMem = VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
		if (NULL == lpMem)
			__leave;
		if (!WriteProcessMemory(hProcess, lpMem, pszDllName, dwSize, &dwWritten))
			__leave;
		hMod = LoadLibrary("kernel32.dll");
		if (NULL == hMod)
			__leave;
		lpProcThread = (LPTHREAD_START_ROUTINE)GetProcAddress(hMod, "LoadLibraryA");
		if (NULL == lpProcThread)
			__leave;
		hThread = CreateRemoteThread(hProcess, NULL, 0, lpProcThread, (LPVOID)lpMem, 0, NULL);
		if (NULL == hThread)
			__leave;
		WaitForSingleObject(hThread, INFINITE);
		fOk = TRUE;
	}
	__finally {
		if (hProcess)
			CloseHandle(hProcess);
		if (hThread)
			CloseHandle(hThread);
		if (fOk)
			return(TRUE);
	}

	return(FALSE);
}

#define DLLPATH ("C:\\Documents and Settings\\Administrator\\My Documents\\Visual Studio 2010\\Projects\\IATHook\\Debug\\calcHook.dll")
#define EXENAME ("calc.exe")
int _tmain() {

	InjectDll(EXENAME, DLLPATH);
	system("pause");
	DWORD dwPID = EnumProcesses(EXENAME);
	if (EjectDll(DLLPATH, dwPID))
		_tprintf("Yes\r\n");
	else
		_tprintf("No\r\n");
	system("pause");

	return(0);
}

接着是DLL代码:

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

typedef BOOL (WINAPI *PFSETWINDOWTEXTW)(HWND hWnd, LPWSTR lpString);

FARPROC g_pOrgFunc = NULL;

// 新的SetWindowTextW
BOOL WINAPI MySetWindowTextW(HWND hWnd, LPWSTR lpString) {
	WCHAR *pNum = L"零一二三四五六七八九";
	int i = 0, nLen = 0, nIndex = 0;

	nLen = wcslen(lpString);
	for (i = 0; i < nLen; ++i)
		for (nIndex = 0; nIndex < 10; ++nIndex)
			if (lpString[i] == (nIndex + L'0'))
				lpString[i] = pNum[nIndex];


	return(((PFSETWINDOWTEXTW)g_pOrgFunc)(hWnd, lpString));
}

// IATHOOK代码
BOOL IAT_Hook(LPCTSTR szDllName, FARPROC pfnOrg, FARPROC pfnNew){
	HMODULE hMod = NULL;
	LPCTSTR szLibName = NULL;
	PIMAGE_IMPORT_DESCRIPTOR pImportDesc = NULL;
	PIMAGE_THUNK_DATA pThunk = NULL;
	DWORD dwOldProtect, dwRVA;
	PBYTE pAddr = NULL;

	hMod = GetModuleHandle(NULL);
	pAddr = (PBYTE)hMod;
	pAddr += *((DWORD *)&pAddr[0x3C]);
	dwRVA = *((DWORD *)&pAddr[0x80]);

	pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)((PBYTE)hMod + dwRVA);
	for (; pImportDesc->Name; ++pImportDesc) {
		szLibName = (LPCTSTR)((PBYTE)hMod + pImportDesc->Name);
		if (!_tcscmp(szLibName, szDllName)) {
			pThunk = (PIMAGE_THUNK_DATA)((PBYTE)hMod + pImportDesc->FirstThunk);
			for (; pThunk->u1.Function; ++pThunk)
				if ((DWORD)pfnOrg == pThunk->u1.Function) {
					VirtualProtect((LPVOID)&pThunk->u1.Function, 4, PAGE_EXECUTE_READWRITE, &dwOldProtect);
					pThunk->u1.Function = (DWORD)pfnNew;
					VirtualProtect((LPVOID)&pThunk->u1.Function, 4, dwOldProtect, &dwOldProtect);
				}
		}
	}

	return(TRUE);
}


BOOL WINAPI DllMain(HINSTANCE hInst, DWORD fdwReason, LPVOID lpReserved) {
	switch(fdwReason) {
	case DLL_PROCESS_ATTACH:
		g_pOrgFunc = GetProcAddress(GetModuleHandle("USER32.dll"), "SetWindowTextW");
		IAT_Hook("USER32.dll", g_pOrgFunc, (FARPROC)MySetWindowTextW);
		break;
	case DLL_PROCESS_DETACH:
		break;
	}

	return(TRUE);
}

注意要把在注入程序中要把DLL写成绝对路径。

(完)

 

 

 

08-06 04:50