-
Notifications
You must be signed in to change notification settings - Fork 49
/
MapFile.cpp
355 lines (318 loc) · 10.3 KB
/
MapFile.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
#include "stdafx.h"
#include "mapfile.h"
CMapFile::CMapFile(char * pPath,bool bWrite,PVOID &pMap,DWORD &dwFileSize)
:pImageView(pMap)
,dwSize(dwFileSize)
{
this->hFileHandle=INVALID_HANDLE_VALUE;
this->hFileMapHandle=INVALID_HANDLE_VALUE;
this->pImageView =NULL;
this->dwSize =0;
try
{
if(bWrite)
{
this->hFileHandle = CreateFileA(pPath, GENERIC_READ|GENERIC_WRITE,0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL , NULL);
}
else
{
this->hFileHandle = CreateFileA(pPath, GENERIC_READ,0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL , NULL);
}
if(this->hFileHandle==INVALID_HANDLE_VALUE)
{
throw (0);
}
this->dwSize=GetFileSize(this->hFileHandle,NULL);
if(this->dwSize==0)
{
throw (1);
}
if(bWrite)
{
this->hFileMapHandle=CreateFileMappingA(this->hFileHandle,NULL,PAGE_READWRITE,0,0,NULL);
}
else
{
this->hFileMapHandle=CreateFileMappingA(this->hFileHandle,NULL,PAGE_READONLY,0,0,NULL);
}
if(this->hFileMapHandle==INVALID_HANDLE_VALUE)
{
throw (2);
}
CloseHandle(this->hFileHandle);
this->hFileHandle= INVALID_HANDLE_VALUE;
if(bWrite)
{
this->pImageView=MapViewOfFile(this->hFileMapHandle,FILE_MAP_WRITE|FILE_MAP_READ,0,0,0);
}
else
{
this->pImageView=MapViewOfFile(this->hFileMapHandle,FILE_MAP_READ,0,0,0);
}
if(this->pImageView==NULL)
{
throw (4);
}
}
catch(...)
{
this->pImageView=NULL;
}
}
CMapFile::~CMapFile(void)
{
try
{
if(this->pImageView!=NULL)
{
UnmapViewOfFile(this->pImageView);
}
if(this->hFileMapHandle!=INVALID_HANDLE_VALUE)
{
CloseHandle(this->hFileMapHandle);
}
if(this->hFileHandle!=INVALID_HANDLE_VALUE)
{
CloseHandle(this->hFileHandle);
}
}
catch(...)
{
}
}
PIMAGE_SECTION_HEADER
__AddImportTable_GetEnclosingSectionHeader(
DWORD rva,
PIMAGE_NT_HEADERS pNTHeader
)
{
PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(pNTHeader);
unsigned i;
for ( i=0; i < pNTHeader->FileHeader.NumberOfSections; i++, section++ )
{
// Is the RVA within this section?
if ( (rva >= section->VirtualAddress) &&
(rva < (section->VirtualAddress + section->Misc.VirtualSize)))
return section;
}
return 0;
}
int
AddImportDll(
IN HANDLE hFile,
IN LPSTR lpDllName,
IN DWORD dwBase,
IN PIMAGE_NT_HEADERS pNTHeader
)
{
//
// 通过OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress
// 获得导入表的RVA, 利用此RVA找到ImportTable所在的Section,之后计算Offset,公式:
// Offset = (INT)(pSection->VirtualAddress - ->PointerToRawData)
// 之后利用Offset来定位文件中ImportTable的位置.pSection
//
PIMAGE_IMPORT_DESCRIPTOR pImportDesc = 0;
PIMAGE_SECTION_HEADER pSection = 0;
PIMAGE_THUNK_DATA pThunk, pThunkIAT = 0;
int Offset = -1;
pSection = __AddImportTable_GetEnclosingSectionHeader(
pNTHeader->OptionalHeader.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress,
pNTHeader);
if(!pSection)
{
fprintf(stderr, "没找到导入表。我日..\n");
return -1;
}
Offset = (int) (pSection->VirtualAddress - pSection->PointerToRawData);
//
// 计算ImportTable在文件中的位置
//
pImportDesc =(PIMAGE_IMPORT_DESCRIPTOR)(pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress - Offset + dwBase);
// 取出导入的DLL的个数 ,有问题暂时保留 ---2012-11-20
//int nImportDllCount = 0;
//while(1)
//{
// if ((pImportDesc->TimeDateStamp==0 ) && (pImportDesc->Name==0))
// break;
// pThunk = (PIMAGE_THUNK_DATA)(pImportDesc->Characteristics);
// pThunkIAT = (PIMAGE_THUNK_DATA)(pImportDesc->FirstThunk);
// if(pThunk == 0 && pThunkIAT == 0)
// return -1;
// nImportDllCount++;
// pImportDesc++;
//}
////
//// 恢复pImportDesc的值,方便下面的复制当前导入表的操作.
////
//pImportDesc -= nImportDllCount;
// 取出导入的DLL的个数 ,有问题暂时保留---2012-11-20
int nImportDllCount = 5;//我们输入法导入DLL个数为5个
//
// 取得ImportTable所在Section的RawData在文件中的末尾地址,计算公式:
// dwOrigEndOfRawDataAddr = pSection->PointerToRawData + pSection->Misc.VirtualSize
//
DWORD dwEndOfRawDataAddr = pSection->PointerToRawData + pSection->Misc.VirtualSize;
PIMAGE_IMPORT_DESCRIPTOR pImportDescVector =
(PIMAGE_IMPORT_DESCRIPTOR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 20 * (nImportDllCount+1));
if(pImportDescVector == NULL)
{
//fprintf(stderr, "分配内存失败. --错误号: %d\n", GetLastError());
return -1;
}
CopyMemory(pImportDescVector+1, pImportDesc, 20*nImportDllCount);
//
// 构造添加数据的结构
//
struct _Add_Data
{
char szDllName[MAX_PATH]; // 导入DLL的名字
int nDllNameLen; // 实际填充的名字的长度
WORD Hint; // 导入函数的Hint
char szFuncName[MAX_PATH]; // 导入函数的名字
int nFuncNameLen; // 导入函数名字的实际长度
int nTotal; // 填充的总长度
} Add_Data;
memset(Add_Data.szDllName,0,MAX_PATH);
memset(Add_Data.szFuncName,0,MAX_PATH);
strcpy(Add_Data.szDllName, lpDllName);
strcpy(Add_Data.szFuncName, "CBFunA");
//
// +1表示'\0'字符
//
Add_Data.nDllNameLen = strlen(Add_Data.szDllName) + 1;
Add_Data.nFuncNameLen = strlen(Add_Data.szFuncName) + 1;
Add_Data.Hint = 0;
//
// 计算总的填充字节数
//
Add_Data.nTotal = Add_Data.nDllNameLen + sizeof(WORD) + Add_Data.nFuncNameLen;
//
// 检查ImportTable所在的Section中的剩余空间是否能够容纳新的ImportTable.
// 未对齐前RawData所占用的空间存放在pSection->VirtualSize中,用此值加上新的ImportTable长度与
// 原长度进行比较.
//
// nTotalLen 为新添加内容的总长度
// Add_Data.nTotal 为添加的DLL名称,Hint与导入函数的名字的总长度.
// 8 为IMAGE_IMPORT_BY_NAME结构的长度.
// 20*(nImportDllCount+1) 为新的ImportTable的长度.
//
int nTotalLen = Add_Data.nTotal + 8 + 20*(nImportDllCount+1);
// printf("TotalLen: %d byte(s)\n", nTotalLen);
if(pSection->Misc.VirtualSize + nTotalLen > pSection->SizeOfRawData)
{
return -1;
}
IMAGE_IMPORT_DESCRIPTOR Add_ImportDesc;
//
// ThunkData结构的地址
//
Add_ImportDesc.Characteristics = dwEndOfRawDataAddr + Add_Data.nTotal + Offset;
Add_ImportDesc.TimeDateStamp = -1;
Add_ImportDesc.ForwarderChain = -1;
//
// DLL名字的RVA
//
Add_ImportDesc.Name = dwEndOfRawDataAddr + Offset;
Add_ImportDesc.FirstThunk = Add_ImportDesc.Characteristics;
CopyMemory(pImportDescVector, &Add_ImportDesc, 20);
//
// 对文件进行修改
//
DWORD dwBytesWritten = 0;
DWORD dwBuffer = dwEndOfRawDataAddr + Offset + Add_Data.nTotal + 8;
long lDistanceToMove = (long)&(pNTHeader->OptionalHeader.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress) - dwBase;
int nRet =0;
//
// 修改IMAGE_DIRECTOR_ENTRY_IMPORT中VirtualAddress的地址,
// 使其指向新的导入表的位置
//
SetFilePointer(hFile, lDistanceToMove, NULL, FILE_BEGIN);
// printf("OrigEntryImport: %x\n", pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
nRet = WriteFile(hFile, (PVOID)&dwBuffer, 4, &dwBytesWritten, NULL);
if(!nRet)
{
//fprintf(stderr, "写 导入表地址的时候失败了耶. --错误号: %d\n", GetLastError());
return -1;
}
// printf("NewEntryImport: %x\n", pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
//
// 修改导入表长度
//
dwBuffer = pNTHeader->OptionalHeader.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT].Size + 40;
nRet = WriteFile(hFile, (PVOID)&dwBuffer, 4, &dwBytesWritten, NULL);
if(!nRet)
{
//fprintf(stderr, "写 导入表大小的的时候失败了耶. --错误号: %d\n", GetLastError());
return -1;
}
//
// 修改[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT]中VirtualAddress和Size成员,设置为0
//
lDistanceToMove = (long)&(pNTHeader->OptionalHeader.DataDirectory
[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress) - dwBase;
dwBuffer = 0;
SetFilePointer(hFile, lDistanceToMove, NULL, FILE_BEGIN);
WriteFile(hFile, (PVOID)&dwBuffer, 4, &dwBytesWritten, NULL);
WriteFile(hFile, (PVOID)&dwBuffer, 4, &dwBytesWritten, NULL);
//
// 修改ImportTable所在节的长度
//
lDistanceToMove = (long)&(pSection->Misc.VirtualSize) - dwBase;
SetFilePointer(hFile, lDistanceToMove, NULL, FILE_BEGIN);
dwBuffer = pSection->Misc.VirtualSize + nTotalLen;
nRet = WriteFile(hFile, (PVOID)&dwBuffer, 4, &dwBytesWritten, NULL);
if(!nRet)
{
//fprintf(stderr, "重写导入表地址的时候失败了耶. --错误号: %d\n", GetLastError());
return -1;
}
//
// 修改SECTION的Characteristics属性修改为E0000020
//
lDistanceToMove = (long)&(pSection->Characteristics) - dwBase;
dwBuffer = 0xE0000020;
SetFilePointer(hFile, lDistanceToMove, NULL, FILE_BEGIN);
nRet = WriteFile(hFile, (PVOID)&dwBuffer, 4, &dwBytesWritten, NULL);
if(!nRet)
{
//fprintf(stderr, "写E0000020的时候失败了耶. --错误号: %d\n", GetLastError());
return -1;
}
//
// 从节的末尾添加新的DLL内容
//
lDistanceToMove = dwEndOfRawDataAddr;
SetFilePointer(hFile, lDistanceToMove, NULL, FILE_BEGIN);
nRet = WriteFile(hFile, Add_Data.szDllName, Add_Data.nDllNameLen, &dwBytesWritten, NULL);
nRet = WriteFile(hFile, (LPVOID)&(Add_Data.Hint), sizeof(WORD), &dwBytesWritten, NULL);
nRet = WriteFile(hFile, Add_Data.szFuncName, Add_Data.nFuncNameLen, &dwBytesWritten, NULL);
dwBuffer = dwEndOfRawDataAddr + Add_Data.nDllNameLen + Offset;
nRet = WriteFile(hFile, (LPVOID)&dwBuffer, 4, &dwBytesWritten, NULL);
dwBuffer = 0;
nRet = WriteFile(hFile, (LPVOID)&dwBuffer, 4, &dwBytesWritten, NULL);
nRet = WriteFile(hFile, (LPVOID)pImportDescVector, 20*(nImportDllCount+1), &dwBytesWritten, NULL);
HeapFree(GetProcessHeap(), 0, pImportDescVector);
return 0;
}
LPVOID HookIMEdllIAT(char *SouceMode,char* hookdll)
{
DWORD dwFileSize =0 ;
LPVOID pPeImage=NULL;
CMapFile cMapFile(SouceMode,true,pPeImage,dwFileSize);
if(pPeImage!=NULL)
{
BYTE *pFileImage = (BYTE*)pPeImage;
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileImage;
PIMAGE_FILE_HEADER pFileHeader =(PIMAGE_FILE_HEADER)(pFileImage+pDosHeader->e_lfanew+4);
PIMAGE_OPTIONAL_HEADER32 pOptionalHeader =(PIMAGE_OPTIONAL_HEADER32)(pFileImage+pDosHeader->e_lfanew+4+sizeof(IMAGE_FILE_HEADER));
PIMAGE_NT_HEADERS pNTHeader=(PIMAGE_NT_HEADERS)&((const unsigned char *)(pFileImage))[pDosHeader->e_lfanew];
//这里加了以共享读写模式打开文件,解决文件未关闭时,打开文件报错的问题。
HANDLE handle = CreateFileA(SouceMode,GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
AddImportDll(handle,hookdll,(DWORD)pFileImage,pNTHeader);
CloseHandle(handle);
}
return pPeImage;
}