下面的代码适用于从32位应用程序获取32位进程的命令行string,64位应用程序的64位进程和64位应用程序的32位进程。 如果我尝试从32位应用程序使用64位进程,这将中断。 原因是PROCESS_BASIC_INFORMATION和地址大小的结构大小不同。 所以这里是我的问题 –
1)过程黑客( http://processhacker.sourceforge.net/forums/viewtopic.php?f=15&t=181 )中使用wow64函数给出的build议似乎不工作,并失败,并出现以下错误 –
NtWow64ReadVirtualMemory64错误:8000000D读取从A68291A0004028E0 ProcessParameters地址
有没有人试过,可以成功获取信息? 我在论坛上发表了同样的意见。
2)是否有任何其他方法来查询peb信息,可以为x86和x64可靠工作?
int get_cmdline_from_pid( DWORD dwPid, char** cmdLine ) { DWORD dw, read; HANDLE hProcess; NtQueryInformationProcess* pNtQip; PROCESS_BASIC_INFORMATION pbInfo; UNICODE_STRING cmdline; WCHAR* wcmdLine; *cmdLine = NULL; hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwPid ); if( !hProcess ) return FALSE; pNtQip = (NtQueryInformationProcess*) GetProcAddress(GetModuleHandle("ntdll.dll"), "NtQueryInformationProcess"); if(!pNtQip) return FALSE; pNtQip(hProcess, PROCESSBASICINFOMATION, &pbInfo, sizeof(pbInfo), NULL); #ifdef _WIN64 ReadProcessMemory(hProcess, pbInfo.PebBaseAddress + 0x20, &dw, sizeof(dw), &read); #else ReadProcessMemory(hProcess, pbInfo.PebBaseAddress + 0x10, &dw, sizeof(dw), &read); #endif #ifdef _WIN64 ReadProcessMemory(hProcess, (PCHAR)dw+112, &cmdline, sizeof(cmdline), &read); #else ReadProcessMemory(hProcess, (PCHAR)dw+64, &cmdline, sizeof(cmdline), &read); #endif wcmdLine = (WCHAR *)malloc(sizeof(char)*(cmdline.Length + 2)); if( !wcmdLine ) return FALSE; ReadProcessMemory(hProcess, (PVOID)cmdline.Buffer, wcmdLine, cmdline.Length+2, &read); *cmdLine = mmwin32_util_widetoansi(wcmdLine); free(wcmdLine); CloseHandle(hProcess); return TRUE; }
也许有点晚,但这是一个代码。 它支持32位或64位处理,以及WOW64上的32位处理(这意味着你可以编译Win32和X64)。 它使用无证的功能,所以使用您自己的风险:-)
GetCmdLine.cpp:
#include "stdafx.h" #include "GetCmdLine.h" int _tmain(int argc, _TCHAR* argv[]) { if (argc < 2) { printf("Format is GetCmdLine <process id>\n"); return 0; } // get process identifier DWORD dwId = _wtoi(argv[1]); // open the process HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwId); DWORD err = 0; if (hProcess == NULL) { printf("OpenProcess %u failed\n", dwId); err = GetLastError(); return -1; } // determine if 64 or 32-bit processor SYSTEM_INFO si; GetNativeSystemInfo(&si); // determine if this process is running on WOW64 BOOL wow; IsWow64Process(GetCurrentProcess(), &wow); // use WinDbg "dt ntdll!_PEB" command and search for ProcessParameters offset to find the truth out DWORD ProcessParametersOffset = si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 ? 0x20 : 0x10; DWORD CommandLineOffset = si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 ? 0x70 : 0x40; // read basic info to get ProcessParameters address, we only need the beginning of PEB DWORD pebSize = ProcessParametersOffset + 8; PBYTE peb = (PBYTE)malloc(pebSize); ZeroMemory(peb, pebSize); // read basic info to get CommandLine address, we only need the beginning of ProcessParameters DWORD ppSize = CommandLineOffset + 16; PBYTE pp = (PBYTE)malloc(ppSize); ZeroMemory(pp, ppSize); PWSTR cmdLine; if (wow) { // we're running as a 32-bit process in a 64-bit OS PROCESS_BASIC_INFORMATION_WOW64 pbi; ZeroMemory(&pbi, sizeof(pbi)); // get process information from 64-bit world _NtQueryInformationProcess query = (_NtQueryInformationProcess)GetProcAddress(GetmoduleeHandleA("ntdll.dll"), "NtWow64QueryInformationProcess64"); err = query(hProcess, 0, &pbi, sizeof(pbi), NULL); if (err != 0) { printf("NtWow64QueryInformationProcess64 failed\n"); CloseHandle(hProcess); return -1; } // read PEB from 64-bit address space _NtWow64ReadVirtualMemory64 read = (_NtWow64ReadVirtualMemory64)GetProcAddress(GetmoduleeHandleA("ntdll.dll"), "NtWow64ReadVirtualMemory64"); err = read(hProcess, pbi.PebBaseAddress, peb, pebSize, NULL); if (err != 0) { printf("NtWow64ReadVirtualMemory64 PEB failed\n"); CloseHandle(hProcess); return -1; } // read ProcessParameters from 64-bit address space PBYTE* parameters = (PBYTE*)*(LPVOID*)(peb + ProcessParametersOffset); // address in remote process adress space err = read(hProcess, parameters, pp, ppSize, NULL); if (err != 0) { printf("NtWow64ReadVirtualMemory64 Parameters failed\n"); CloseHandle(hProcess); return -1; } // read CommandLine UNICODE_STRING_WOW64* pCommandLine = (UNICODE_STRING_WOW64*)(pp + CommandLineOffset); cmdLine = (PWSTR)malloc(pCommandLine->MaximumLength); err = read(hProcess, pCommandLine->Buffer, cmdLine, pCommandLine->MaximumLength, NULL); if (err != 0) { printf("NtWow64ReadVirtualMemory64 Parameters failed\n"); CloseHandle(hProcess); return -1; } } else { // we're running as a 32-bit process in a 32-bit OS, or as a 64-bit process in a 64-bit OS PROCESS_BASIC_INFORMATION pbi; ZeroMemory(&pbi, sizeof(pbi)); // get process information _NtQueryInformationProcess query = (_NtQueryInformationProcess)GetProcAddress(GetmoduleeHandleA("ntdll.dll"), "NtQueryInformationProcess"); err = query(hProcess, 0, &pbi, sizeof(pbi), NULL); if (err != 0) { printf("NtQueryInformationProcess failed\n"); CloseHandle(hProcess); return -1; } // read PEB if (!ReadProcessMemory(hProcess, pbi.PebBaseAddress, peb, pebSize, NULL)) { printf("ReadProcessMemory PEB failed\n"); CloseHandle(hProcess); return -1; } // read ProcessParameters PBYTE* parameters = (PBYTE*)*(LPVOID*)(peb + ProcessParametersOffset); // address in remote process adress space if (!ReadProcessMemory(hProcess, parameters, pp, ppSize, NULL)) { printf("ReadProcessMemory Parameters failed\n"); CloseHandle(hProcess); return -1; } // read CommandLine UNICODE_STRING* pCommandLine = (UNICODE_STRING*)(pp + CommandLineOffset); cmdLine = (PWSTR)malloc(pCommandLine->MaximumLength); if (!ReadProcessMemory(hProcess, pCommandLine->Buffer, cmdLine, pCommandLine->MaximumLength, NULL)) { printf("ReadProcessMemory Parameters failed\n"); CloseHandle(hProcess); return -1; } } printf("%S\n", cmdLine); return 0; }
GetCmdLine.h:
#pragma once #include "stdafx.h" // NtQueryInformationProcess for pure 32 and 64-bit processes typedef NTSTATUS (NTAPI *_NtQueryInformationProcess)( IN HANDLE ProcessHandle, ULONG ProcessInformationClass, OUT PVOID ProcessInformation, IN ULONG ProcessInformationLength, OUT PULONG ReturnLength OPTIONAL ); typedef NTSTATUS (NTAPI *_NtReadVirtualMemory)( IN HANDLE ProcessHandle, IN PVOID BaseAddress, OUT PVOID Buffer, IN SIZE_T Size, OUT PSIZE_T NumberOfBytesRead); // NtQueryInformationProcess for 32-bit process on WOW64 typedef NTSTATUS (NTAPI *_NtWow64ReadVirtualMemory64)( IN HANDLE ProcessHandle, IN PVOID64 BaseAddress, OUT PVOID Buffer, IN ULONG64 Size, OUT PULONG64 NumberOfBytesRead); // PROCESS_BASIC_INFORMATION for pure 32 and 64-bit processes typedef struct _PROCESS_BASIC_INFORMATION { PVOID Reserved1; PVOID PebBaseAddress; PVOID Reserved2[2]; ULONG_PTR UniqueProcessId; PVOID Reserved3; } PROCESS_BASIC_INFORMATION; // PROCESS_BASIC_INFORMATION for 32-bit process on WOW64 // The definition is quite funky, as we just lazily doubled sizes to match offsets... typedef struct _PROCESS_BASIC_INFORMATION_WOW64 { PVOID Reserved1[2]; PVOID64 PebBaseAddress; PVOID Reserved2[4]; ULONG_PTR UniqueProcessId[2]; PVOID Reserved3[2]; } PROCESS_BASIC_INFORMATION_WOW64; typedef struct _UNICODE_STRING { USHORT Length; USHORT MaximumLength; PWSTR Buffer; } UNICODE_STRING; typedef struct _UNICODE_STRING_WOW64 { USHORT Length; USHORT MaximumLength; PVOID64 Buffer; } UNICODE_STRING_WOW64;
您的32位指针不足以在目标进程的64位地址空间中存储地址,并将被截断。 因此,你正在尝试的是不可能的。 这是Raymond Chen建议你停止使用模拟器的情况之一。
引用雷蒙德的名字后,我迅速查了一下,看他有没有什么有用的金块。 该搜索出现了这篇文章: 为什么没有支持的方式来获得另一个进程的命令行? 。 有用的金块是观察Win32_Process.CommandLine
给你你需要(以某种方式)。 所以,我的建议是给WMI一个去。