在Windows中,有没有办法检查另一个进程是否存在环境变量?只需要检查存在,不一定得到价值。
我需要从代码中执行此操作。
答案 0 :(得分:8)
如果您知道存储环境的虚拟地址,则可以使用OpenProcess
和ReadProcessMemory
从其他进程中读取环境。但是,要查找虚拟地址,您需要在其中一个进程'线程的Thread Information Block中查找。
为此,您需要在致电GetThreadContext()
后致电SuspendThread()
。但是为了调用它们,您需要一个线程句柄,您可以通过使用TH32CS_SNAPTHREAD
标志调用CreateToolhelp32Snapshot
来创建进程的快照,Thread32First
以获取线程ID进程中的第一个线程,以及OpenThread
获取线程的句柄。
答案 1 :(得分:1)
使用实用程序:
您可以使用Process Explorer。
右键点击该流程,转到属性... ,然后会出现环境标签,其中列出了该流程的环境变量。
使用代码:
似乎没有直接执行此操作的Win32 API调用,但显然您可以使用GetProcessStrings
的结果来获取对此信息的访问权限。 This CodeProject article有一些代码可以帮助您入门。
答案 2 :(得分:0)
这是一个工作示例,打印输出可用于检查是否存在以及读取值(将其构建为与您必须定位的可执行文件的进程标识符相同的体系结构):
getenv.cpp
#include <string>
#include <vector>
#include <cwchar>
#include <windows.h>
#include <winternl.h>
using std::string;
using std::wstring;
using std::vector;
using std::size_t;
// define process_t type
typedef DWORD process_t;
// #define instead of typedef to override
#define RTL_DRIVE_LETTER_CURDIR struct {\
WORD Flags;\
WORD Length;\
ULONG TimeStamp;\
STRING DosPath;\
}\
// #define instead of typedef to override
#define RTL_USER_PROCESS_PARAMETERS struct {\
ULONG MaximumLength;\
ULONG Length;\
ULONG Flags;\
ULONG DebugFlags;\
PVOID ConsoleHandle;\
ULONG ConsoleFlags;\
PVOID StdInputHandle;\
PVOID StdOutputHandle;\
PVOID StdErrorHandle;\
UNICODE_STRING CurrentDirectoryPath;\
PVOID CurrentDirectoryHandle;\
UNICODE_STRING DllPath;\
UNICODE_STRING ImagePathName;\
UNICODE_STRING CommandLine;\
PVOID Environment;\
ULONG StartingPositionLeft;\
ULONG StartingPositionTop;\
ULONG Width;\
ULONG Height;\
ULONG CharWidth;\
ULONG CharHeight;\
ULONG ConsoleTextAttributes;\
ULONG WindowFlags;\
ULONG ShowWindowFlags;\
UNICODE_STRING WindowTitle;\
UNICODE_STRING DesktopName;\
UNICODE_STRING ShellInfo;\
UNICODE_STRING RuntimeData;\
RTL_DRIVE_LETTER_CURDIR DLCurrentDirectory[32];\
ULONG EnvironmentSize;\
}\
// shortens a wide string to a narrow string
static inline string shorten(wstring wstr) {
int nbytes = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), (int)wstr.length(), NULL, 0, NULL, NULL);
vector<char> buf(nbytes);
return string { buf.data(), (size_t)WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), (int)wstr.length(), buf.data(), nbytes, NULL, NULL) };
}
// replace all occurrences of substring found in string with specified new string
static inline string string_replace_all(string str, string substr, string nstr) {
size_t pos = 0;
while ((pos = str.find(substr, pos)) != string::npos) {
str.replace(pos, substr.length(), nstr);
pos += nstr.length();
}
return str;
}
// func that splits string by first occurrence of equals sign
vector<string> string_split_by_first_equalssign(string str) {
size_t pos = 0;
vector<string> vec;
if ((pos = str.find_first_of("=")) != string::npos) {
vec.push_back(str.substr(0, pos));
vec.push_back(str.substr(pos + 1));
}
return vec;
}
// checks whether process handle is 32-bit or not
static inline bool IsX86Process(HANDLE process) {
BOOL isWow = true;
SYSTEM_INFO systemInfo = { 0 };
GetNativeSystemInfo(&systemInfo);
if (systemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
return isWow;
IsWow64Process(process, &isWow);
return isWow;
}
// helper to open processes based on pid with full debug privileges
static inline HANDLE OpenProcessWithDebugPrivilege(process_t pid) {
HANDLE hToken;
LUID luid;
TOKEN_PRIVILEGES tkp;
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid);
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Luid = luid;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges(hToken, false, &tkp, sizeof(tkp), NULL, NULL);
CloseHandle(hToken);
return OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
}
// get wide character string of pids environ based on handle
static inline wchar_t *GetEnvironmentStringsW(HANDLE proc) {
PEB peb;
SIZE_T nRead;
ULONG res_len = 0;
PROCESS_BASIC_INFORMATION pbi;
RTL_USER_PROCESS_PARAMETERS upp;
HMODULE p_ntdll = GetModuleHandleW(L"ntdll.dll");
typedef NTSTATUS (__stdcall *tfn_qip)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG);
tfn_qip pfn_qip = tfn_qip(GetProcAddress(p_ntdll, "NtQueryInformationProcess"));
NTSTATUS status = pfn_qip(proc, ProcessBasicInformation, &pbi, sizeof(pbi), &res_len);
if (status) { return NULL; }
ReadProcessMemory(proc, pbi.PebBaseAddress, &peb, sizeof(peb), &nRead);
if (!nRead) { return NULL; }
ReadProcessMemory(proc, peb.ProcessParameters, &upp, sizeof(upp), &nRead);
if (!nRead) { return NULL; }
PVOID buffer = upp.Environment;
ULONG length = upp.EnvironmentSize;
wchar_t *res = new wchar_t[length / 2 + 1];
ReadProcessMemory(proc, buffer, res, length, &nRead);
if (!nRead) { return NULL; }
res[length / 2] = 0;
return res;
}
// get env of pid as a narrow string
string env_from_pid(process_t pid) {
string envs;
HANDLE proc = OpenProcessWithDebugPrivilege(pid);
wchar_t *wenvs = NULL;
if (IsX86Process(GetCurrentProcess())) {
if (IsX86Process(proc)) {
wenvs = GetEnvironmentStringsW(proc);
}
} else {
if (!IsX86Process(proc)) {
wenvs = GetEnvironmentStringsW(proc);
}
}
string arg;
if (wenvs == NULL) {
return "";
} else {
arg = shorten(wenvs);
}
size_t i = 0;
do {
size_t j = 0;
vector<string> envVec = string_split_by_first_equalssign(arg);
for (const string &env : envVec) {
if (j == 0) {
if (env.find_first_of("%<>^&|:") != string::npos) { continue; }
if (env.empty()) { continue; }
envs += env;
} else { envs += "=\"" + string_replace_all(env, "\"", "\\\"") + "\"\n"; }
j++;
}
i += wcslen(wenvs + i) + 1;
arg = shorten(wenvs + i);
} while (wenvs[i] != L'\0');
if (envs.back() == '\n') { envs.pop_back(); }
if (wenvs != NULL) { delete[] wenvs; }
CloseHandle(proc);
return envs;
}
// test function (can be omitted)
int main(int argc, char **argv) {
if (argc == 2) {
printf("%s", env_from_pid(stoul(string(argv[1]), nullptr, 10)).c_str());
printf("%s", "\r\n");
} else {
printf("%s", env_from_pid(GetCurrentProcessId()).c_str());
printf("%s", "\r\n");
}
return 0;
}
buildx86.sh
g++ getenv.cpp -o getenv.exe -std=c++17 -static-libgcc -static-libstdc++ -static -m32
buildx64.sh
g++ getenv.cpp -o getenv.exe -std=c++17 -static-libgcc -static-libstdc++ -static -m64
为了清楚起见,在打印值周围添加了报价,并对内部报价应用了转义。