【编程技术-四种获取目标进程导入DLL模块地址的方法】此文章归类为:编程技术。
本人在校大学生一枚,技术不太行,各位师傅将就看看。
tlhelp32.h
头文件中,提供了CreateToolhelp32Snapshot
API,可以获取获取指定进程以及这些进程使用的堆、模块和线程的快照。
1
2
3
4
|
HANDLE
CreateToolhelp32Snapshot(
[in]
DWORD
dwFlags,
[in]
DWORD
th32ProcessID
);
|
在进程快照信息中,包含着进程导入模块的信息。因此,我们可以有如下实现思路:
CreateToolhelp32Snapshot
指定TH32CS_SNAPPROCESS
属性,获取进程快照句柄。Process32Next
遍历进程信息,对比进程名查找到目标进程。OpenProcess
验证目标进程状态。CreateToolhelp32Snapshot
指定TH32CS_SNAPMODULE
属性,获取目标进程的模块快照。Module32Next
遍历模块,直到获取到目标模块信息,返回目标模块的句柄。GetProcAddress
获取目标函数的地址。
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
|
#include <iostream>
#include <Windows.h>
#include <Tlhelp32.h>
#include <tchar.h>
#include <string>
#include <stdio.h>
HMODULE
GetProcessModuleHandle(
DWORD
pid, CONST
TCHAR
* moduleName) {
// 根据 PID 、模块名(需要写后缀,如:".dll"),获取模块入口地址
MODULEENTRY32 moduleEntry;
HANDLE
handle = NULL;
moudleInfoHandle = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid);
// 获取进程快照的打开句柄,包含模块信息(TH32CS_SNAPMODULE指定)
if
(!moudleInfoHandle) {
CloseHandle(moudleInfoHandle);
return
NULL;
}
ZeroMemory(&moduleEntry,
sizeof
(MODULEENTRY32));
moduleEntry.dwSize =
sizeof
(MODULEENTRY32);
if
(!Module32First(moudleInfoHandle, &moduleEntry)) {
CloseHandle(moudleInfoHandle);
return
NULL;
}
do
{
if
(_tcscmp(moduleEntry.szModule, moduleName) == 0) {
CloseHandle(moudleInfoHandle);
return
moduleEntry.hModule;
}
}
while
(Module32Next(moudleInfoHandle, &moduleEntry));
CloseHandle(moudleInfoHandle);
return
0;
}
int
main() {
HANDLE
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
// 进程快照句柄
PROCESSENTRY32 process = {
sizeof
(PROCESSENTRY32)
};
// 存放进程快照的结构体
// 遍历进程
while
(Process32Next(hProcessSnap, &process)) {
// 找到目标进程
std::string s_szExeFile = process.szExeFile;
// char* 转 string
if
(s_szExeFile ==
"xxx.exe"
) {
HANDLE
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, process.th32ProcessID);
if
(hProcess)
{
HMODULE
hMod = GetProcessModuleHandle(process.th32ProcessID,
"xxx.dll"
);
if
(hMod)
{
auto
fnAddress = GetProcAddress(hMod,
"xxFunc"
);
std::cout << fnAddress <<
" "
<< GetLastError();
}
}
}
}
}
|
按照微软官方的建议,使用EnumProcessModules
函数枚举进程模块可以确定哪些进程加载了特定的DLL。这个函数在psapi.h
中。以下是微软给出的实例代码。
1
2
3
4
5
6
|
BOOL
EnumProcessModules(
[in]
HANDLE
hProcess,
[out]
HMODULE
*lphModule,
[in]
DWORD
cb,
[out]
LPDWORD
lpcbNeeded
);
|
OpenProcess
获取进程句柄。EnumProcessModules
函数枚举模块信息。模块句柄都返回到hMods数组中。进一步筛选即可。
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
|
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <psapi.h>
// 为了确保正确解析符号,需要将 Psapi.lib 添加到 TARGETLIBS,并使用 -DPSAPI_VERSION=1 编译
int
PrintModules(
DWORD
processID )
{
HMODULE
hMods[1024];
HANDLE
hProcess;
DWORD
cbNeeded;
unsigned
int
i;
// 打印进程标识符。
printf
(
"\n进程 ID:%u\n"
, processID );
// 获取进程的句柄。
hProcess = OpenProcess( PROCESS_QUERY_INFORMATION |
PROCESS_VM_READ,
FALSE, processID );
if
(NULL == hProcess)
return
1;
// 获取此进程中所有模块的列表。
if
( EnumProcessModules(hProcess, hMods,
sizeof
(hMods), &cbNeeded))
{
for
( i = 0; i < (cbNeeded /
sizeof
(
HMODULE
)); i++ )
{
TCHAR
szModName[MAX_PATH];
// 获取模块文件的完整路径。
if
( GetModuleFileNameEx( hProcess, hMods[i], szModName,
sizeof
(szModName) /
sizeof
(
TCHAR
)))
{
// 打印模块名和句柄值。
_tprintf( TEXT(
"\t%s (0x%08X)\n"
), szModName, hMods[i] );
}
}
}
// 释放对进程的句柄。
CloseHandle( hProcess );
return
0;
}
int
main(
void
)
{
DWORD
aProcesses[1024];
DWORD
cbNeeded;
DWORD
cProcesses;
unsigned
int
i;
// 获取进程标识符的列表。
if
( !EnumProcesses( aProcesses,
sizeof
(aProcesses), &cbNeeded ) )
return
1;
// 计算返回了多少个进程标识符。
cProcesses = cbNeeded /
sizeof
(
DWORD
);
// 打印每个进程的模块名称。
for
( i = 0; i < cProcesses; i++ )
{
PrintModules( aProcesses[i] );
}
return
0;
}
|
PEB +0x00c
成员Ldr
指向_PEB_LDR_DATA
结构,此结构的第三成员InMemoryOrderModuleList
包含进程的已加载模块的双向链表的头部。列表中的每个项目都是指向LDR_DATA_TABLE_ENTRY
结构的指针。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
typedef
struct
_LDR_DATA_TABLE_ENTRY {
PVOID
Reserved1[2];
LIST_ENTRY InMemoryOrderLinks;
PVOID
Reserved2[2];
PVOID
DllBase;
PVOID
EntryPoint;
PVOID
Reserved3;
UNICODE_STRING FullDllName;
BYTE
Reserved4[8];
PVOID
Reserved5[3];
union
{
ULONG
CheckSum;
PVOID
Reserved6;
};
ULONG
TimeDateStamp;
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
|
因此,这种方法的思路如下:
NtWow64QueryInformationProcess64
获取PROCESS_BASIC_INFORMATION64(32)
结构NtWow64ReadVirtualMemory64
(32位用ReadProcessMemory
)读出PebBaseAddress
_PEB_LDR_DATA
遍历_LDR_DATA_TABLE_ENTRY
FullDllName
筛选,DllBase
返回模块基地址。贴一个大佬的获取PEB代码(原谅我实在忘了在哪找到的,知道的朋友请留言一下)
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
|
#include "stdafx.h"
#include <iostream>
#include <windows.h>
#include <subauth.h>
#pragma region 依赖
#define NT_SUCCESS(x) ((x) >= 0)
#define ProcessBasicInformation 0
typedef
NTSTATUS(WINAPI *pfnNtWow64QueryInformationProcess64)
(
HANDLE
ProcessHandle,
UINT32
ProcessInformationClass,
PVOID
ProcessInformation,
UINT32
ProcessInformationLength,
UINT32
* ReturnLength);
typedef
NTSTATUS(WINAPI *pfnNtWow64ReadVirtualMemory64)
(
HANDLE
ProcessHandle, PVOID64 BaseAddress,
PVOID
BufferData,
UINT64
BufferLength,
PUINT64
ReturnLength);
typedef
NTSTATUS(WINAPI *pfnNtQueryInformationProcess)
(
HANDLE
ProcessHandle,
ULONG
ProcessInformationClass,
PVOID
ProcessInformation,
UINT32
ProcessInformationLength,
UINT32
* ReturnLength);
template
<
typename
T>
struct
_UNICODE_STRING_T
{
WORD
Length;
WORD
MaximumLength;
T Buffer;
};
template
<
typename
T>
struct
_LIST_ENTRY_T
{
T Flink;
T Blink;
};
template
<
typename
T,
typename
NGF,
int
A>
struct
_PEB_T
{
typedef
T type;
union
{
struct
{
BYTE
InheritedAddressSpace;
BYTE
ReadImageFileExecOptions;
BYTE
BeingDebugged;
BYTE
BitField;
};
T dummy01;
};
T Mutant;
T ImageBaseAddress;
T Ldr;
T ProcessParameters;
T SubSystemData;
T ProcessHeap;
T FastPebLock;
T AtlThunkSListPtr;
T IFEOKey;
T CrossProcessFlags;
T UserSharedInfoPtr;
DWORD
SystemReserved;
DWORD
AtlThunkSListPtr32;
T ApiSetMap;
T TlsExpansionCounter;
T TlsBitmap;
DWORD
TlsBitmapBits[2];
T ReadOnlySharedMemoryBase;
T HotpatchInformation;
T ReadOnlyStaticServerData;
T AnsiCodePageData;
T OemCodePageData;
T UnicodeCaseTableData;
DWORD
NumberOfProcessors;
union
{
DWORD
NtGlobalFlag;
NGF dummy02;
};
LARGE_INTEGER CriticalSectionTimeout;
T HeapSegmentReserve;
T HeapSegmentCommit;
T HeapDeCommitTotalFreeThreshold;
T HeapDeCommitFreeBlockThreshold;
DWORD
NumberOfHeaps;
DWORD
MaximumNumberOfHeaps;
T ProcessHeaps;
T GdiSharedHandleTable;
T ProcessStarterHelper;
T GdiDCAttributeList;
T LoaderLock;
DWORD
OSMajorVersion;
DWORD
OSMinorVersion;
WORD
OSBuildNumber;
WORD
OSCSDVersion;
DWORD
OSPlatformId;
DWORD
ImageSubsystem;
DWORD
ImageSubsystemMajorVersion;
T ImageSubsystemMinorVersion;
T ActiveProcessAffinityMask;
T GdiHandleBuffer[A];
T PostProcessInitRoutine;
T TlsExpansionBitmap;
DWORD
TlsExpansionBitmapBits[32];
T SessionId;
ULARGE_INTEGER AppCompatFlags;
ULARGE_INTEGER AppCompatFlagsUser;
T pShimData;
T AppCompatInfo;
_UNICODE_STRING_T<T> CSDVersion;
T ActivationContextData;
T ProcessAssemblyStorageMap;
T SystemDefaultActivationContextData;
T SystemAssemblyStorageMap;
T MinimumStackCommit;
T FlsCallback;
_LIST_ENTRY_T<T> FlsListHead;
T FlsBitmap;
DWORD
FlsBitmapBits[4];
T FlsHighIndex;
T WerRegistrationData;
T WerShipAssertPtr;
T pContextData;
T pImageHeaderHash;
T TracingFlags;
T CsrServerReadOnlySharedMemoryBase;
};
typedef
_PEB_T<
DWORD
,
DWORD64
, 34> _PEB32;
typedef
_PEB_T<
DWORD64
,
DWORD
, 30> _PEB64;
typedef
struct
_STRING_32
{
WORD
Length;
WORD
MaximumLength;
UINT32
Buffer;
} STRING32, *PSTRING32;
typedef
struct
_STRING_64
{
WORD
Length;
WORD
MaximumLength;
UINT64
Buffer;
} STRING64, *PSTRING64;
typedef
struct
_RTL_DRIVE_LETTER_CURDIR_32
{
WORD
Flags;
WORD
Length;
ULONG
TimeStamp;
STRING32 DosPath;
} RTL_DRIVE_LETTER_CURDIR32, *PRTL_DRIVE_LETTER_CURDIR32;
typedef
struct
_RTL_DRIVE_LETTER_CURDIR_64
{
WORD
Flags;
WORD
Length;
ULONG
TimeStamp;
STRING64 DosPath;
} RTL_DRIVE_LETTER_CURDIR64, *PRTL_DRIVE_LETTER_CURDIR64;
typedef
struct
_UNICODE_STRING_32
{
WORD
Length;
WORD
MaximumLength;
UINT32
Buffer;
} UNICODE_STRING32, *PUNICODE_STRING32;
typedef
struct
_UNICODE_STRING_64
{
WORD
Length;
WORD
MaximumLength;
UINT64
Buffer;
} UNICODE_STRING64, *PUNICODE_STRING64;
typedef
struct
_CURDIR_32
{
UNICODE_STRING32 DosPath;
UINT32
Handle;
} CURDIR32, *PCURDIR32;
typedef
struct
_RTL_USER_PROCESS_PARAMETERS_32
{
ULONG
MaximumLength;
ULONG
Length;
ULONG
Flags;
ULONG
DebugFlags;
UINT32
ConsoleHandle;
ULONG
ConsoleFlags;
UINT32
StandardInput;
UINT32
StandardOutput;
UINT32
StandardError;
CURDIR32 CurrentDirectory;
UNICODE_STRING32 DllPath;
UNICODE_STRING32 ImagePathName;
UNICODE_STRING32 CommandLine;
UINT32
Environment;
ULONG
StartingX;
ULONG
StartingY;
ULONG
CountX;
ULONG
CountY;
ULONG
CountCharsX;
ULONG
CountCharsY;
ULONG
FillAttribute;
ULONG
WindowFlags;
ULONG
ShowWindowFlags;
UNICODE_STRING32 WindowTitle;
UNICODE_STRING32 DesktopInfo;
UNICODE_STRING32 ShellInfo;
UNICODE_STRING32 RuntimeData;
RTL_DRIVE_LETTER_CURDIR32 CurrentDirectores[32];
ULONG
EnvironmentSize;
} RTL_USER_PROCESS_PARAMETERS32, *PRTL_USER_PROCESS_PARAMETERS32;
typedef
struct
_CURDIR_64
{
UNICODE_STRING64 DosPath;
UINT64
Handle;
} CURDIR64, *PCURDIR64;
typedef
struct
_RTL_USER_PROCESS_PARAMETERS_64
{
ULONG
MaximumLength;
ULONG
Length;
ULONG
Flags;
ULONG
DebugFlags;
UINT64
ConsoleHandle;
ULONG
ConsoleFlags;
UINT64
StandardInput;
UINT64
StandardOutput;
UINT64
StandardError;
CURDIR64 CurrentDirectory;
UNICODE_STRING64 DllPath;
UNICODE_STRING64 ImagePathName;
UNICODE_STRING64 CommandLine;
UINT64
Environment;
ULONG
StartingX;
ULONG
StartingY;
ULONG
CountX;
ULONG
CountY;
ULONG
CountCharsX;
ULONG
CountCharsY;
ULONG
FillAttribute;
ULONG
WindowFlags;
ULONG
ShowWindowFlags;
UNICODE_STRING64 WindowTitle;
UNICODE_STRING64 DesktopInfo;
UNICODE_STRING64 ShellInfo;
UNICODE_STRING64 RuntimeData;
RTL_DRIVE_LETTER_CURDIR64 CurrentDirectores[32];
ULONG
EnvironmentSize;
} RTL_USER_PROCESS_PARAMETERS64, *PRTL_USER_PROCESS_PARAMETERS64;
typedef
struct
_PROCESS_BASIC_INFORMATION64 {
NTSTATUS ExitStatus;
UINT32
Reserved0;
UINT64
PebBaseAddress;
UINT64
AffinityMask;
UINT32
BasePriority;
UINT32
Reserved1;
UINT64
UniqueProcessId;
UINT64
InheritedFromUniqueProcessId;
} PROCESS_BASIC_INFORMATION64;
typedef
struct
_PROCESS_BASIC_INFORMATION32 {
NTSTATUS ExitStatus;
UINT32
PebBaseAddress;
UINT32
AffinityMask;
UINT32
BasePriority;
UINT32
UniqueProcessId;
UINT32
InheritedFromUniqueProcessId;
} PROCESS_BASIC_INFORMATION32;
#pragma endregion
int
_tmain(
int
argc, _TCHAR* argv[])
{
HANDLE
m_ProcessHandle =
OpenProcess(
PROCESS_ALL_ACCESS,
// 所有权限
FALSE,
// 不继承句柄
8016
// 进程ID,此处为了方便直接写死
);
BOOL
bSource = FALSE;
// 判断自身进程是否为 64位
BOOL
bTarget = FALSE;
// 判断目标进程是否为 64位
IsWow64Process(
GetCurrentProcess(),
// 进程句柄
&bSource
// 用来接收返回值的变量,64位 FLASE | 32位 TRUE
);
IsWow64Process(
m_ProcessHandle,
// 进程句柄
&bTarget
// 用来接收返回值的变量,64位 FLASE | 32位 TRUE
);
// 目标 64位,自身 32位
if
(bTarget == FALSE && bSource == TRUE)
{
// 获取 ntdll.dll 模块句柄
HMODULE
NtdllModule = GetModuleHandle(
"ntdll.dll"
);
pfnNtWow64QueryInformationProcess64 NtWow64QueryInformationProcess64 = (pfnNtWow64QueryInformationProcess64)GetProcAddress(NtdllModule,
"NtWow64QueryInformationProcess64"
);
pfnNtWow64ReadVirtualMemory64 NtWow64ReadVirtualMemory64 = (pfnNtWow64ReadVirtualMemory64)GetProcAddress(NtdllModule,
"NtWow64ReadVirtualMemory64"
);
PROCESS_BASIC_INFORMATION64 pbi = {0};
UINT64
ReturnLength = 0;
NTSTATUS Status = NtWow64QueryInformationProcess64(m_ProcessHandle,ProcessBasicInformation,&pbi,(
UINT32
)
sizeof
(pbi),(
UINT32
*)&ReturnLength);
if
(NT_SUCCESS(Status)){
_PEB64* Peb = (_PEB64*)
malloc
(
sizeof
(_PEB64));
RTL_USER_PROCESS_PARAMETERS64* ProcessParameters = (RTL_USER_PROCESS_PARAMETERS64*)
malloc
(
sizeof
(RTL_USER_PROCESS_PARAMETERS64));
Status = NtWow64ReadVirtualMemory64(m_ProcessHandle,(PVOID64)pbi.PebBaseAddress,(_PEB64*)Peb,
sizeof
(_PEB64),&ReturnLength);
std::cout <<
"PEB地址:"
<< std::hex << pbi.PebBaseAddress << std::endl;
//cout << "Ldr:" << hex << Peb->Ldr << endl;
//cout << "ImageBaseAddress:" << hex << Peb->ImageBaseAddress << endl;
}
}
// 目标 32位,自身 32位
else
if
(bTarget == TRUE && bSource == TRUE)
{
HMODULE
NtdllModule = GetModuleHandle(
"ntdll.dll"
);
pfnNtQueryInformationProcess NtQueryInformationProcess = (pfnNtQueryInformationProcess)GetProcAddress(NtdllModule,
"NtQueryInformationProcess"
);
PROCESS_BASIC_INFORMATION32 pbi = {0};
UINT32
ReturnLength = 0;
NTSTATUS Status = NtQueryInformationProcess(m_ProcessHandle,ProcessBasicInformation,&pbi,(
UINT32
)
sizeof
(pbi),(
UINT32
*)&ReturnLength);
if
(NT_SUCCESS(Status)){
_PEB32* Peb = (_PEB32*)
malloc
(
sizeof
(_PEB32));
ReadProcessMemory(m_ProcessHandle, (
PVOID
)pbi.PebBaseAddress,(_PEB32*)Peb,
sizeof
(_PEB32),NULL);
std::cout <<
"PEB地址:"
<< std::hex << pbi.PebBaseAddress << std::endl;
//printf("LdrAddress:%x\r\n", ((_PEB32*)Peb)->Ldr);
//printf("ImageBaseAddress:%x\r\n", ((_PEB32*)Peb)->ImageBaseAddress);
}
}
getchar
();
return
0;
}
|
对目标进程进行DLL注入,Hook GetMoudleHandle
、Loadlibary
等函数,让目标进程自己调用,进行IPC通信。
更多【编程技术-四种获取目标进程导入DLL模块地址的方法】相关视频教程:www.yxfzedu.com