1 /*
2  * Copyright 2011 kubtek <kubtek@mail.com>
3  *
4  * This file is part of StarDict.
5  *
6  * StarDict is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * StarDict is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with StarDict.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include "HookImportFunction.h"
21 #include <tlhelp32.h>
22 
23 
24 // These code come from: http://dev.csdn.net/article/2/2786.shtm
25 // I fixed a bug in it and improved it to hook all the modules of a program.
26 
27 #define MakePtr(cast, ptr, AddValue) (cast)((size_t)(ptr)+(size_t)(AddValue))
28 
GetNamedImportDescriptor(HMODULE hModule,LPCSTR szImportModule)29 static PIMAGE_IMPORT_DESCRIPTOR GetNamedImportDescriptor(HMODULE hModule, LPCSTR szImportModule)
30 {
31 	PIMAGE_DOS_HEADER pDOSHeader;
32 	PIMAGE_NT_HEADERS pNTHeader;
33 	PIMAGE_IMPORT_DESCRIPTOR pImportDesc;
34 
35 	if ((szImportModule == NULL) || (hModule == NULL))
36 		return NULL;
37 	pDOSHeader = (PIMAGE_DOS_HEADER) hModule;
38 	if (IsBadReadPtr(pDOSHeader, sizeof(IMAGE_DOS_HEADER)) || (pDOSHeader->e_magic != IMAGE_DOS_SIGNATURE)) {
39 		return NULL;
40 	}
41 	pNTHeader = MakePtr(PIMAGE_NT_HEADERS, pDOSHeader, pDOSHeader->e_lfanew);
42 	if (IsBadReadPtr(pNTHeader, sizeof(IMAGE_NT_HEADERS)) || (pNTHeader->Signature != IMAGE_NT_SIGNATURE))
43 		return NULL;
44 	if (pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress == 0)
45 		return NULL;
46 	pImportDesc = MakePtr(PIMAGE_IMPORT_DESCRIPTOR, pDOSHeader, pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
47 	while (pImportDesc->Name) {
48 		PSTR szCurrMod = MakePtr(PSTR, pDOSHeader, pImportDesc->Name);
49 		if (_stricmp(szCurrMod, szImportModule) == 0)
50 			break;
51 		pImportDesc++;
52 	}
53 	if (pImportDesc->Name == (DWORD)0)
54 		return NULL;
55 	return pImportDesc;
56 }
57 
IsNT()58 static BOOL IsNT()
59 {
60 	OSVERSIONINFO stOSVI;
61 	BOOL bRet;
62 
63 	memset(&stOSVI, 0, sizeof(OSVERSIONINFO));
64 	stOSVI.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
65 	bRet = GetVersionEx(&stOSVI);
66 	if (FALSE == bRet) return FALSE;
67 	return (VER_PLATFORM_WIN32_NT == stOSVI.dwPlatformId);
68 }
69 
HookImportFunction(HMODULE hModule,LPCSTR szImportModule,LPCSTR szFunc,PROC paHookFuncs,PROC * paOrigFuncs)70 static BOOL HookImportFunction(HMODULE hModule, LPCSTR szImportModule, LPCSTR szFunc, PROC paHookFuncs, PROC* paOrigFuncs)
71 {
72 	PIMAGE_IMPORT_DESCRIPTOR pImportDesc;
73 	PIMAGE_THUNK_DATA pOrigThunk;
74 	PIMAGE_THUNK_DATA pRealThunk;
75 
76 	if (!IsNT() && ((size_t)hModule >= 0x80000000))
77 		return FALSE;
78 	pImportDesc = GetNamedImportDescriptor(hModule, szImportModule);
79 	if (pImportDesc == NULL)
80 		return FALSE;
81 	pOrigThunk = MakePtr(PIMAGE_THUNK_DATA, hModule, pImportDesc->OriginalFirstThunk);
82 	pRealThunk = MakePtr(PIMAGE_THUNK_DATA, hModule, pImportDesc->FirstThunk);
83 	while (pOrigThunk->u1.Function) {
84 		if (IMAGE_ORDINAL_FLAG != (pOrigThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG)) {
85 			PIMAGE_IMPORT_BY_NAME pByName = MakePtr(PIMAGE_IMPORT_BY_NAME, hModule, pOrigThunk->u1.AddressOfData);
86 			BOOL bDoHook;
87 			// When hook EditPlus, read pByName->Name[0] will case this dll terminate, so call IsBadReadPtr() here.
88 			if (IsBadReadPtr(pByName, sizeof(IMAGE_IMPORT_BY_NAME))) {
89 				pOrigThunk++;
90 				pRealThunk++;
91 				continue;
92 			}
93 			if ('\0' == pByName->Name[0]) {
94 				pOrigThunk++;
95 				pRealThunk++;
96 				continue;
97 			}
98 			bDoHook = FALSE;
99 			if ((szFunc[0] == pByName->Name[0]) && (_strcmpi(szFunc, (char*)pByName->Name) == 0)) {
100 				if (paHookFuncs)
101 					bDoHook = TRUE;
102 			}
103 			if (bDoHook) {
104 				MEMORY_BASIC_INFORMATION mbi_thunk;
105 				DWORD dwOldProtect;
106 
107 				VirtualQuery(pRealThunk, &mbi_thunk, sizeof(MEMORY_BASIC_INFORMATION));
108 				VirtualProtect(mbi_thunk.BaseAddress, mbi_thunk.RegionSize, PAGE_READWRITE, &mbi_thunk.Protect);
109 				if (paOrigFuncs)
110 					*paOrigFuncs = (PROC)pRealThunk->u1.Function;
111 				pRealThunk->u1.Function = (DWORD)paHookFuncs;
112 
113 				VirtualProtect(mbi_thunk.BaseAddress, mbi_thunk.RegionSize, mbi_thunk.Protect, &dwOldProtect);
114 				return TRUE;
115 			}
116 		}
117 		pOrigThunk++;
118 		pRealThunk++;
119 	}
120 	return FALSE;
121 }
122 
HookAPI(LPCSTR szImportModule,LPCSTR szFunc,PROC paHookFuncs,PROC * paOrigFuncs)123 BOOL HookAPI(LPCSTR szImportModule, LPCSTR szFunc, PROC paHookFuncs, PROC* paOrigFuncs)
124 {
125 	HANDLE hSnapshot;
126 	MODULEENTRY32 me = {sizeof(MODULEENTRY32)};
127 	BOOL bOk;
128 
129 	if ((szImportModule == NULL) || (szFunc == NULL)) {
130 		return FALSE;
131 	}
132 
133 	hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,0);
134 
135 	bOk = Module32First(hSnapshot,&me);
136 	while (bOk) {
137 		HookImportFunction(me.hModule, szImportModule, szFunc, paHookFuncs, paOrigFuncs);
138 		bOk = Module32Next(hSnapshot,&me);
139 	}
140 	return TRUE;
141 }
142