Search code examples
c++windowsmemorywindows-10

Scan notepad.exe memory does not work for windows 10


I have a program which scans a certain program's memory with a PID. It works very well for Windows XP and Windows 7, but suddenly it does not work for Windows 10.

I even have process privilege enabled. What is the reason that it fails to examine the memory of notepad.exe in Windows 10? It is not even a SYSTEM process.

Here is an example which does basically the same :

#include <Windows.h>
#include <iostream>
#include <iomanip>
#include <exception>
#include <cstdint>
#include <vector>
#include <sstream>
#include <fstream>

template <typename T>
void print_hex(std::ostream &stream, T x, int width = 8){
    stream << std::hex << std::setw(width) << std::setfill('0') << x << std::dec;
}

template <typename T>
void print_address(std::ostream &stream, T x){
    if (x < 0x100)
        print_hex(stream, x, 2);
    else if (x < 0x10000)
        print_hex(stream, x, 4);
    else if (x < 0x100000000ULL)
        print_hex(stream, x, 8);
    else
        print_hex(stream, x, 16);
}

class DebugProcess{
    DWORD pid;
public:
    DebugProcess(DWORD pid): pid(pid){
        if (!DebugActiveProcess(pid)){
            auto error = GetLastError();
            std::cerr << "DebugActiveProcess() failed with error " << error << " (0x";
            print_hex(std::cerr, error);
            std::cerr << ")\n";
            throw std::exception();
        }
    }
    ~DebugProcess(){
        if (!DebugActiveProcessStop(this->pid)){
            auto error = GetLastError();
            std::cerr << "DebugActiveProcessStop() failed with error " << error << " (0x";
            print_hex(std::cerr, error);
            std::cerr << ")\n";
        }
    }
};

bool is_handle_valid(HANDLE handle){
    return handle && handle != INVALID_HANDLE_VALUE;
}

class AutoHandle{
    HANDLE handle;
public:
    AutoHandle(HANDLE handle): handle(handle){}
    ~AutoHandle(){
        if (is_handle_valid(this->handle))
            CloseHandle(this->handle);
    }
};

template <typename T>
void zero_struct(T &mem){
    memset(&mem, 0, sizeof(mem));
}

struct memory_region{
    std::uint64_t start,
        size;
    MEMORY_BASIC_INFORMATION info;
};

void dump_process_memory(DWORD pid){
    DebugProcess dp(pid);

    auto proc = OpenProcess(PROCESS_ALL_ACCESS, false, pid);
    if (!is_handle_valid(proc)){
        auto error = GetLastError();
        std::cerr << "OpenProcess() failed with error " << error << " (0x";
        print_hex(std::cerr, error);
        std::cerr << ")\n";
        return;
    }
    AutoHandle autoproc(proc);

    std::vector<memory_region> regions;
    for (std::uint64_t address = 0; address < 0x10000000ULL;){
        MEMORY_BASIC_INFORMATION mbi;
        zero_struct(mbi);
        auto bytes = VirtualQueryEx(proc, (LPCVOID)address, &mbi, sizeof(mbi));
        if (!bytes){
            address += 4096;
            continue;
        }
        if (mbi.State == MEM_COMMIT && (mbi.Protect & PAGE_GUARD) != PAGE_GUARD)
            regions.push_back(memory_region{ (std::uint64_t)mbi.BaseAddress, mbi.RegionSize, mbi });

        address += mbi.RegionSize;
    }

    if (regions.size()){
        std::cout << "Flat size:   " << regions.back().start + regions.back().size << std::endl;
        std::uint64_t sum = 0;
        for (auto &region : regions)
            sum += region.size;
        std::cout << "Packed size: " << sum << std::endl;
    }

    std::ofstream file("dump.bin", std::ios::binary);
    std::uint64_t current_size = 0;
    for (auto &region : regions){
        std::vector<char> buffer(region.size);
        size_t read;
        if (!ReadProcessMemory(proc, (LPCVOID)region.start, &buffer[0], buffer.size(), &read)){
            auto error = GetLastError();
            if (error != ERROR_PARTIAL_COPY){
                std::cerr << "ReadProcessMemory() failed with error " << error << " (0x";
                print_hex(std::cerr, error);
                std::cerr << ")\n";
                return;
            }
        }

        if (read < region.size){
#if 1
            std::cerr << "Warning: region starting at 0x";
            print_address(std::cerr, region.start);
            std::cerr << " has size " << region.size << ", but only " << read
                << " bytes could be read by ReadProcessMemory().\n";
#endif
            memset(&buffer[read], 0, buffer.size() - read);
        }

        file.seekp(region.start);

        file.write(&buffer[0], buffer.size());
    }
}

int main(int argc, char **argv)
{
    DWORD pid;
    std::cout << "Enter PID : ";
    std::cin >> pid;

    try{
        dump_process_memory(pid);
    }catch (std::exception &){
        std::cerr << "Exception caught.\n";
    }

    std::cin.ignore();    
    std::cin.get();    
    return 0;
}

In the example, the program does not output the memory dump for notepad.exe when its PID is entered. Is there any helpful solution to make my program work well in Windows 10? Thank you in advance.


Solution

  • The sample program is designed for 32-bit processes. It tries to create a file of the process memory which is too big for 64-bit. If you comment out the attempts to write a file, fix the for loop to iterate over a much larger process space, and compile 64-bit it will work. Make these changes:

    for(std::uint64_t address = 0;;) // remove exit condition
    {
        MEMORY_BASIC_INFORMATION mbi;
        zero_struct(mbi);
        auto bytes = VirtualQueryEx(proc, (LPCVOID)address, &mbi, sizeof(mbi));
        if (!bytes){
            break;  // break loop when address exceeds maximum supported
        }
        if (mbi.State == MEM_COMMIT && (mbi.Protect & PAGE_GUARD) != PAGE_GUARD)
            regions.push_back(memory_region{ (std::uint64_t)mbi.BaseAddress, mbi.RegionSize, mbi });
    
        address += mbi.RegionSize;
    
    }
    

    Comment out file writing. Needs to be re-evaluated.

       //std::ofstream file("dump.bin", std::ios::binary);
    
       ...
    
       //file.seekp(region.start);
       //file.write(&buffer[0], buffer.size());
    

    Output for Notepad. Note that the flat size (the size of the file attempted to be written) is 140TB.

    Flat size:   140728080994304
    Packed size: 106180608
    Warning: region starting at 0x00007df600fe8000 has size 552960, but only 0 bytes could be read by ReadProcessMemory().
    Warning: region starting at 0x00007ff5f5d23000 has size 6721536, but only 0 bytes could be read by ReadProcessMemory().
    Warning: region starting at 0x00007ff5f638e000 has size 3747840, but only 0 bytes could be read by ReadProcessMemory().
    Warning: region starting at 0x00007ff5f672d000 has size 77824, but only 0 bytes could be read by ReadProcessMemory().
    Warning: region starting at 0x00007ff5f6748000 has size 147456, but only 0 bytes could be read by ReadProcessMemory().
    Warning: region starting at 0x00007ff5f6777000 has size 786432, but only 0 bytes could be read by ReadProcessMemory().
    Warning: region starting at 0x00007ff5f683a000 has size 16384, but only 0 bytes could be read by ReadProcessMemory().
    Warning: region starting at 0x00007ff5f683f000 has size 774144, but only 0 bytes could be read by ReadProcessMemory().
    Warning: region starting at 0x00007ff5f6902000 has size 4096, but only 0 bytes could be read by ReadProcessMemory().
    Warning: region starting at 0x00007ff5f6906000 has size 163840, but only 0 bytes could be read by ReadProcessMemory().
    Warning: region starting at 0x00007ff5f692f000 has size 8192, but only 0 bytes could be read by ReadProcessMemory().
    Warning: region starting at 0x00007ff5f6938000 has size 331776, but only 0 bytes could be read by ReadProcessMemory().
    Warning: region starting at 0x00007ff5f698c000 has size 32768, but only 0 bytes could be read by ReadProcessMemory().
    Warning: region starting at 0x00007ff5f699a000 has size 319488, but only 0 bytes could be read by ReadProcessMemory().
    Warning: region starting at 0x00007ff5f69ea000 has size 4096, but only 0 bytes could be read by ReadProcessMemory().
    Warning: region starting at 0x00007ff5f69ee000 has size 32768, but only 0 bytes could be read by ReadProcessMemory().
    Warning: region starting at 0x00007ff5f69fe000 has size 8192, but only 0 bytes could be read by ReadProcessMemory().
    Warning: region starting at 0x00007ff5f6a35000 has size 4096, but only 0 bytes could be read by ReadProcessMemory().
    Warning: region starting at 0x00007ff5f6a8e000 has size 77824, but only 0 bytes could be read by ReadProcessMemory().
    Warning: region starting at 0x00007ff5f6aad000 has size 32768, but only 0 bytes could be read by ReadProcessMemory().
    Warning: region starting at 0x00007ff5f6ac7000 has size 20480, but only 0 bytes could be read by ReadProcessMemory().