【问题标题】:C++ winapi VirtualQueryEx function gives me "000000"C++ winapi VirtualQueryEx 函数给了我“000000”
【发布时间】:2021-01-26 07:36:02
【问题描述】:

我正在尝试显示有关系统上每个进程的虚拟内存的信息:

#include <windows.h>
#include <conio.h>
#include <tlhelp32.h>
#include <iostream>
using namespace std;


void main() {
HANDLE CONST hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
PROCESSENTRY32 proc;
TCHAR Buffer[1024];
TCHAR Buffer2[1024];
DWORD temp;


HANDLE CONST hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

if (INVALID_HANDLE_VALUE == hSnap)
{
    return;
}

proc.dwSize = sizeof(PROCESSENTRY32);

Process32First(hSnap, &proc);

do {
    MEMORY_BASIC_INFORMATION    mbi = {};
    wsprintf(Buffer, L" %s %d \n ", proc.szExeFile, proc.th32ProcessID);
    WriteConsole(hStdOut, Buffer, lstrlen(Buffer), &temp, NULL);
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, proc.th32ProcessID);
    VirtualQueryEx(hProcess, 0, &mbi, sizeof(MEMORY_BASIC_INFORMATION));
    printf("Alloc = %p, base = %p , size = %d, type = %d, state = %p\n", mbi.AllocationBase, mbi.BaseAddress, mbi.RegionSize, mbi.Type,mbi.State);

} while (Process32Next(hSnap, &proc));

CloseHandle(hSnap);


}

输出如下所示:

output

我得到基地址和分配等于 0000000 并输入 0 如何获得正常值?我的意思是大小和状态似乎还可以,但其余的是“0000000” 不知道是什么问题

【问题讨论】:

  • 尝试检查它之前的每个函数的返回值,并将它们与文档进行比较。问题可能不在您认为的位置。
  • 您的 printf 格式字符串与您的参数类型不对应。更喜欢std::cout
  • 注意编译器警告,在编译你的代码时,我收到三个不同的 printf 调用警告。所有与格式字符串的错误类型有关。但正如我所说,最简单的方法是使用std::cout
  • cout 不起作用
  • @DussyPestroyer 请详细说明,它是否无法编译?如果是这样,它会产生什么错误?或者它只是不写任何东西? (另外,在您的回复中标记人。这样,与您交谈的人都会收到通知)

标签: c++ winapi virtualquery


【解决方案1】:

您目前仅检索有关每个进程的第一个内存块的信息。一个进程通常会有很多个内存块,而不仅仅是一个(几千到几万是很典型的)。

这里有一些代码可以检索并打印出指定进程中每个数据块的状态。

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <iostream>
#include <string>

unsigned long show_module(MEMORY_BASIC_INFORMATION info) {
    unsigned long usage = 0;

    std::cout << info.BaseAddress << "(" << info.RegionSize / 1024 << ")\t";

    switch (info.State) {
    case MEM_COMMIT:
        std::cout << "Committed";
        break;
    case MEM_RESERVE:
        std::cout << "Reserved";
        break;
    case MEM_FREE:
        std::cout << "Free";
        break;
    }
    std::cout << "\t";
    switch (info.Type) {
    case MEM_IMAGE:
        std::cout << "Code Module";
        break;
    case MEM_MAPPED:
        std::cout << "Mapped     ";
        break;
    case MEM_PRIVATE:
        std::cout << "Private    ";
    }
    std::cout << "\t";

    int guard = 0, nocache = 0;

    if ( info.AllocationProtect & PAGE_NOCACHE)
        nocache = 1;
    if ( info.AllocationProtect & PAGE_GUARD )
        guard = 1;

    info.AllocationProtect &= ~(PAGE_GUARD | PAGE_NOCACHE);

    if ((info.State == MEM_COMMIT) && (info.AllocationProtect == PAGE_READWRITE || info.AllocationProtect == PAGE_READONLY))
        usage += info.RegionSize;

    switch (info.AllocationProtect) {
    case PAGE_READONLY:
        std::cout << "Read Only";
        break;
    case PAGE_READWRITE:
        std::cout << "Read/Write";
        break;
    case PAGE_WRITECOPY:
        std::cout << "Copy on Write";
        break;
    case PAGE_EXECUTE:
        std::cout << "Execute only";
        break;
    case PAGE_EXECUTE_READ:
        std::cout << "Execute/Read";
        break;
    case PAGE_EXECUTE_READWRITE:
        std::cout << "Execute/Read/Write";
        break;
    case PAGE_EXECUTE_WRITECOPY:
        std::cout << "COW Executable";
        break;
    }

    if (guard)
        std::cout << "\tguard page";
    if (nocache)
        std::cout << "\tnon-cacheable";
    std::cout << "\n";
    return usage;
}

unsigned long show_modules(HANDLE process) {

    unsigned long usage = 0;

    unsigned char* p = NULL;
    MEMORY_BASIC_INFORMATION info;

    for ( p = NULL;
        VirtualQueryEx(process, p, &info, sizeof(info)) == sizeof(info);
        p += info.RegionSize )
    {
        usage += show_module(info);
    }
    return usage;
}

int main(int argc, char **argv) {

    int pid;

    if (argc != 2) {
        std::cerr << "Usage: " << argv[0] << " <process ID>\n";
        return EXIT_FAILURE;
    }

    pid = std::stoi(argv[1]);

    HANDLE process = OpenProcess(
        PROCESS_VM_READ | PROCESS_QUERY_INFORMATION,
        false,
        pid);

    unsigned long mem_used = show_modules(process);
    std::cout << "Total memory used: " << mem_used / 10224 << "KB\n";
}

为了了解结果,这里是我系统上一个进程的前几行输出:

0000000000000000(64)    Free
0000000000010000(64)    Committed       Mapped          Read/Write
0000000000020000(4)     Committed       Mapped          Read Only
0000000000021000(60)    Free
0000000000030000(4)     Committed       Private
0000000000031000(60)    Reserved        Private

但请注意:您可能会获得比大多数典型流程更多的输出很多。该特定过程(Thunderbird)总共产生了 3,686 行输出。使用 Chrome 进行快速测试(使用几 GB 的内存)会产生超过 46,000 行的输出(即系统正在跟踪超过 46,000 个单独的内存块)。

如果您要为系统中的每个进程打印一些内容,您可能需要大量汇总数据(但不知道为什么要这样,很难猜出您会得到什么样的结果)可能想要)。

【讨论】:

  • 更正确地使用p = (PBYTE)info.BaseAddress + info.RegionSize;,因为RegionSize 来自BaseAddress,有时(很少)可以是p != BaseAddress。和return usage; 也是错别字
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-16
  • 2018-12-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多