【问题标题】:Reading the environment variables of another process读取另一个进程的环境变量
【发布时间】:2016-10-20 18:37:34
【问题描述】:

我正在尝试获取进程环境字符串,下面的代码是我已经写的。

#include <windows.h>
#include <tchar.h>

#define ProcessBasicInformation 0

typedef struct _PROCESS_BASIC_INFORMATION {
    NTSTATUS  ExitStatus;
    PVOID     PebBaseAddress;
    ULONG_PTR AffinityMask;
    LONG      BasePriority;
    HANDLE    UniqueProcessId;
    HANDLE    InheritedFromUniqueProcessId;
} PROCESS_BASIC_INFORMATION, *PPROCESS_BASIC_INFORMATION;

int _tmain(int argc, TCHAR* argv[]) {
  TCHAR   *app;
  DWORD    pid;
  HANDLE  proc;
  NTSTATUS nts;
  PVOID   rupp; // RTL_USER_PROCESS_PARAMETERS, offset 0x10
  PVOID    env; // Environment, offset 0x48
  TCHAR   *buf;
  PROCESS_BASIC_INFORMATION pbi;
  MEMORY_BASIC_INFORMATION  mbi;

  if (argc != 2) {
    app = _tcsrchr(argv[0], '\\');
    _tprintf(TEXT("Usage: %s [PID]\n"), app ? ++app : argv[0]);
    return -1;
  }

  _stscanf_s(argv[1], TEXT("%lu"), &pid);
  if (!(proc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid))) {
    return -1;
  }

  if (!(nts = NtQueryInformationProcess(
    proc, ProcessBasicInformation, &pbi, sizeof(pbi), NULL
      ))) {
  if (ReadProcessMemory(
    proc, (PCHAR)pbi.PebBaseAddress + 0x10, &rupp, sizeof(rupp), NULL
      )) {
  if (ReadProcessMemory(proc, (PCHAR)rupp + 0x48, &env, sizeof(env), NULL)) {
     //what I need to do to get enironment strings?
  }
}
  }

  CloseHandle(proc);

  return 0;
}

有人可以解释我需要做什么来获取进程的环境字符串吗?

【问题讨论】:

  • 我不知道这样做的支持方式。保护环境变量的锁是进程本地的。您不能从另一个进程中获取锁。环境变量被认为是进程私有的,不应在外部进行操作。如果要操作进程的环境变量,则需要与进程协调。 (例如,请参阅the WM_SETTINGSCHANGE "Environment" notification。)
  • 目前尚不清楚,当存在已记录且受支持的解决方案时,为什么还要坚持使用未记录的方法。为什么痴迷于ReadProcessMemory
  • ReadProcessMemory 是与调用 SetEnvironmentVariable 的进程的固有竞争条件。它还依赖于大量未记录/不受支持的技术。
  • @kate:我们已经充分确定,调用ReadProcessMemory 不能可靠地检索另一个进程的环境。为什么老是找错树?你为什么坚持,你绝对必须使用ReadProcessMemory,而不是使用可以可靠工作的替代品?请尝试在不使用以下单词列表的情况下回答该问题:"idiots""stupid""loosers"(包括正确的拼写吊坠“失败者”)。祝你好运(你需要它)。
  • 请避免侮辱其他 Stack Overflow 成员并保持专业。

标签: c windows winapi


【解决方案1】:

首先您的代码仅适用于 x86,但是 x64 系统呢?在 x64 上,您必须从 x64 代码运行 x64 进程的访问环境。但是 Wow64 进程呢?他们有 2 个环境! 1 天真和 1 哇,这不是相等的字符串。所以任务可能足够复杂。但是当然存在解决方案。

NTSTATUS ReadProcessEnv(HANDLE hProcess, PVOID Environment, PWSTR* ppsz)
{
    NTSTATUS status;
    MEMORY_BASIC_INFORMATION mbi;

    if (0 > (status = ZwQueryVirtualMemory(hProcess, Environment, MemoryBasicInformation, &mbi, sizeof(mbi), 0))) return status;

    if (mbi.State != MEM_COMMIT || mbi.Type != MEM_PRIVATE)
    {
        return STATUS_UNSUCCESSFUL;
    }

    mbi.RegionSize -= RtlPointerToOffset(mbi.BaseAddress, Environment);

    //Environment must be WCHAR aligned and how minimum 2*sizeof(WCHAR) size
    if (mbi.RegionSize < 2*sizeof(WCHAR) || ((ULONG_PTR)Environment & (__alignof(WCHAR) - 1)))
    {
        return STATUS_UNSUCCESSFUL;
    }

    if (mbi.RegionSize > 0x10000)// >64Kb Environment ??
    {
        mbi.RegionSize = 0x10000;
    }

    if (PWSTR buf = new WCHAR[mbi.RegionSize])
    {
        if (0 <= (status = ZwReadVirtualMemory(hProcess, Environment, buf, mbi.RegionSize, 0)))
        {
            buf[mbi.RegionSize - 2] = 0;
            buf[mbi.RegionSize - 1] = 0;
            *ppsz = buf;

            return STATUS_SUCCESS;
        }
        delete buf;

        return status;
    }

    return STATUS_INSUFFICIENT_RESOURCES;
}

NTSTATUS ReadProcessEnv(HANDLE hProcess, PWSTR* ppsz)
{
    NTSTATUS status;
    PROCESS_BASIC_INFORMATION pbi;
    _RTL_USER_PROCESS_PARAMETERS* ProcessParameters;
    PVOID Environment;

    if (
        0 > (status = ZwQueryInformationProcess(hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), 0))
        ||
        0 > (status = ZwReadVirtualMemory(hProcess, &pbi.PebBaseAddress->ProcessParameters, &ProcessParameters, sizeof(PVOID), 0))
        ||
        0 > (status = ZwReadVirtualMemory(hProcess, &ProcessParameters->Environment, &Environment, sizeof(PVOID), 0))
        ) 
        return status;

    return ReadProcessEnv(hProcess, Environment, ppsz);
}

#ifdef _WIN64

NTSTATUS ReadProcessEnvWow(HANDLE hProcess, PWSTR* ppsz)
{
    ULONG WowPeb, ProcessParameters;
    NTSTATUS status;
    PVOID Environment = 0;

    if (0 > (status = ZwQueryInformationProcess(hProcess, ProcessWow64Information, &WowPeb, sizeof(PVOID), 0))) return status;

    if (!WowPeb)
    {
        return STATUS_SUCCESS;
    }

    enum {
        ofs32_ProcessParameters = 0x10,
        ofs32_Environment = 0x48
    };

    if (
        0 > (status = ZwReadVirtualMemory(hProcess, RtlOffsetToPointer(WowPeb, ofs32_ProcessParameters), &ProcessParameters, sizeof(ULONG), 0))
        ||
        0 > (status = ZwReadVirtualMemory(hProcess, RtlOffsetToPointer(ProcessParameters, ofs32_Environment), &Environment, sizeof(ULONG), 0))
        ) 
        return status;

    return ReadProcessEnv(hProcess, Environment, ppsz);
}
#endif

NTSTATUS ReadProcessEnv(
                        PCLIENT_ID cid, 
                        PWSTR* ppsz, 
                        PNTSTATUS pstatus
#ifdef _WIN64
                        , 
                        PWSTR* ppszWow, 
                        PNTSTATUS pstatusWow
#endif
                        )
{
    HANDLE hProcess;
    NTSTATUS status = ZwOpenProcess(&hProcess, PROCESS_QUERY_INFORMATION|PROCESS_VM_READ, &zoa, cid);

    if (0 <= status)
    {
        *ppsz = 0;
        *pstatus = ReadProcessEnv(hProcess, ppsz);
#ifdef _WIN64
        *ppszWow = 0;
        *pstatusWow = ReadProcessEnvWow(hProcess, ppszWow);
#endif
        ZwClose(hProcess);
    }

    return status;
}

void DumpEnv(PCWSTR sz)
{
    while (*sz)
    {
        DbgPrint("%S\n", sz);
        sz += wcslen(sz) + 1;
    }
}

void test(PCLIENT_ID cid)
{
    PWSTR env, envWow;
    NTSTATUS status, s;

#ifdef _WIN64
    NTSTATUS sWow;
#endif

    if (0 <= (status = ReadProcessEnv(cid, &env, &s
#ifdef _WIN64
        , &envWow, &sWow
#endif
        )))
    {
        if (0 <= s)
        {
            DumpEnv(env);
            delete env;
        }

#ifdef _WIN64
        if (0 <= sWow)
        {
            if (envWow)
            {
                DumpEnv(envWow);
                delete envWow;
            }
        }
#endif
    }
}

【讨论】:

  • 我不需要 x64 的代码,我需要以某种方式从我的代码中的 buf 中提取行。
  • 如何提取行 - 看 - void DumpEnv(PCWSTR sz) - 它转储行 vy 行。如果需要按名称查询一些变量 - 使用 RtlQueryEnvironmentVariable_U 或 RtlQueryEnvironmentVariable
  • DumpEnv 只是获取第一个变量,其他的都丢失了。我不需要查询变量,我只需要获取进程的变量。
  • "刚刚获得第一个变量,其他的都丢失了。" - 你错了。没有任何损失。“我只需要获取变量” - 我粘贴代码,您还想要什么?
  • @kate:既然你在努力理解,那么环境块在内存中是如何布局的,看看GetEnvironmentStrings
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-11
  • 2019-02-02
  • 1970-01-01
  • 2021-11-04
  • 1970-01-01
相关资源
最近更新 更多