简体   繁体   中英

C++ read all memory from process within modulesize

I have been trying to read all memory addresses within a process range only, (see question: C++ read memory addresses within process range only ). I succeeded with reading from memory and it seems like I received the correct baseaddress for the process. The problem I was having was to find specific values which I assumed the program would have.

For example if I played a game and had the score 500 , I wanted to find 500 in the memory. I stepped through all the addresses but could not find the value. So I decided to read my own program (which is 64-bit) and set a value to 500 , print its address and manually search and see if I found it.

int number = 500;
std::cout << &number;

For some reason the address it was written to was out of bounds of the process range.

I calculate the address range with:

uintptr_t moduleBase = GetModuleBaseAddress(procId, L"x.exe");
uintptr_t moduleSize = GetModuleSize(procId, L"x.exe");

// Set base and last address and print them for user
uintptr_t dynamicPtrBaseAddr = moduleBase;
uintptr_t dynamicPtrLastAddr = (moduleBase + moduleSize);

Methods used:

uintptr_t GetModuleSize(DWORD procId, const wchar_t* modName) {
        uintptr_t modBaseSize = 0;
        HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | 0x10, procId);
        if(hSnap != INVALID_HANDLE_VALUE) {
            MODULEENTRY32 modEntry;
            modEntry.dwSize = sizeof(modEntry);
            if(Module32First(hSnap, &modEntry)) {
                do {
                    if(!_wcsicmp(modEntry.szModule, modName)) {
                        modBaseSize = (uintptr_t)modEntry.modBaseSize;
                        break;
                    }
                } while(Module32Next(hSnap, &modEntry));
            }
        }
        CloseHandle(hSnap);
        return modBaseSize;
    }

and

uintptr_t GetModuleBaseAddress(DWORD procId, const wchar_t* modName) {
    uintptr_t modBaseAddr = 0;
    HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | 0x10, procId);
    if(hSnap != INVALID_HANDLE_VALUE) {
        MODULEENTRY32 modEntry;
        modEntry.dwSize = sizeof(modEntry);
        if(Module32First(hSnap, &modEntry)) {
            do {
                if(!_wcsicmp(modEntry.szModule, modName)) {
                    modBaseAddr = (uintptr_t)modEntry.modBaseAddr;
                    break;
                }
            } while(Module32Next(hSnap, &modEntry));
        }
    }
    CloseHandle(hSnap);
    return modBaseAddr;
}

Since the value of number is written out of bounds I assume that GetModuleSize , might be incorrect.

Last address for me is: 0x4F4628 , std::cout << &number; gives me 0x6DFDD4

My questions are:

  • Is GetModuleSize an incorrect way of calculating the last address for the application? If so, can I correct it?
  • By multiplying the last address with 2, I was able to read the value of &number . Is this because modulesize gives me a 32-bit range or is this giving me addresses out of bounds for the process?

I compile with: g++ main.cpp -ox -lpsapi -DUNICODE -m64 , and had to add libgcc_s_seh-1.dll to my path in order to run my program.

My entire project on github: https://github.com/Darclander/memory-reading

(Not sure if it is better for me to post the entire code on here).

A "module" in WIN32 terms is an executable image file. This image contains things like code, static variables, stack unwind tables and more. The value you are attempting to read is a local variable and thus will be allocated on the stack. The stack is not part of the image, so you won't find it there.

What you need to do is find the address and size of the stack. See How can I locate a process' global and stack areas in Win32? on how to do that.

You probably also want to read the heap in addition to the stack, you can find all open heaps by using GetProcessHeaps and get the addresses/sizes with HeapSummary .

As @para said, the module is a image of PE file.

The variable you want to read is stored on the current thread stack, you will need to get the base address and limit address of the stack, with NtQueryInformationThread

#include <windows.h>
#include <iostream>
#include <winternl.h>
#include <tlhelp32.h>
#pragma warning(disable : 4996)
using namespace std; 
typedef enum _mTHREADINFOCLASS {
    ThreadBasicInformation = 0
} mTHREADINFOCLASS;
typedef struct _mTEB {
    NT_TIB                  Tib;
    PVOID                   EnvironmentPointer;
    CLIENT_ID               Cid;
    PVOID                   ActiveRpcInfo;
    PVOID                   ThreadLocalStoragePointer;
    PPEB                    Peb;
    ULONG                   LastErrorValue;
    ULONG                   CountOfOwnedCriticalSections;
    PVOID                   CsrClientThread;
    PVOID                   Win32ThreadInfo;
    ULONG                   Win32ClientInfo[0x1F];
    PVOID                   WOW32Reserved;
    ULONG                   CurrentLocale;
    ULONG                   FpSoftwareStatusRegister;
    PVOID                   SystemReserved1[0x36];
    PVOID                   Spare1;
    ULONG                   ExceptionCode;
    ULONG                   SpareBytes1[0x28];
    PVOID                   SystemReserved2[0xA];
    ULONG                   GdiRgn;
    ULONG                   GdiPen;
    ULONG                   GdiBrush;
    CLIENT_ID               RealClientId;
    PVOID                   GdiCachedProcessHandle;
    ULONG                   GdiClientPID;
    ULONG                   GdiClientTID;
    PVOID                   GdiThreadLocaleInfo;
    PVOID                   UserReserved[5];
    PVOID                   GlDispatchTable[0x118];
    ULONG                   GlReserved1[0x1A];
    PVOID                   GlReserved2;
    PVOID                   GlSectionInfo;
    PVOID                   GlSection;
    PVOID                   GlTable;
    PVOID                   GlCurrentRC;
    PVOID                   GlContext;
    NTSTATUS                LastStatusValue;
    UNICODE_STRING          StaticUnicodeString;
    WCHAR                   StaticUnicodeBuffer[0x105];
    PVOID                   DeallocationStack;
    PVOID                   TlsSlots[0x40];
    LIST_ENTRY              TlsLinks;
    PVOID                   Vdm;
    PVOID                   ReservedForNtRpc;
    PVOID                   DbgSsReserved[0x2];
    ULONG                   HardErrorDisabled;
    PVOID                   Instrumentation[0x10];
    PVOID                   WinSockData;
    ULONG                   GdiBatchCount;
    ULONG                   Spare2;
    ULONG                   Spare3;
    ULONG                   Spare4;
    PVOID                   ReservedForOle;
    ULONG                   WaitingOnLoaderLock;
    PVOID                   StackCommit;
    PVOID                   StackCommitMax;
    PVOID                   StackReserved;
} mTEB;
typedef NTSTATUS (WINAPI *fpNtQueryInformationThread)(
    IN HANDLE          ThreadHandle,
    IN mTHREADINFOCLASS ThreadInformationClass,
    OUT PVOID          ThreadInformation,
    IN ULONG           ThreadInformationLength,
    OUT PULONG         ReturnLength
);
typedef struct _THREAD_BASIC_INFORMATION {

    NTSTATUS                ExitStatus;
    mTEB*                   TebBaseAddress;
    CLIENT_ID               ClientId;
    KAFFINITY               AffinityMask;
    KPRIORITY               Priority;
    KPRIORITY               BasePriority;
} THREAD_BASIC_INFORMATION, * PTHREAD_BASIC_INFORMATION;

void fun()
{
    return;
}
int main()
{
    DWORD pid = 21112;//process id
    DWORD tid = 5512;//thread id
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, pid);
    if (hProcess == NULL)
    {
        int error = GetLastError();
        cout << "OpenProcess error: " << error << endl;
    }
    HANDLE hThread = OpenThread(THREAD_ALL_ACCESS,false, tid);
    if (hThread == NULL)
    {
        int error = GetLastError();
        cout << "OpenThread error: " << error << endl;
    }

    HMODULE h = LoadLibrary(L"ntdll.dll");
    fpNtQueryInformationThread NtQueryInformationThread = (fpNtQueryInformationThread)GetProcAddress(h,"NtQueryInformationThread");

    THREAD_BASIC_INFORMATION info = { 0 };
    NTSTATUS ret = NtQueryInformationThread(hThread, ThreadBasicInformation, &info, sizeof(THREAD_BASIC_INFORMATION), NULL);

    NT_TIB tib = { 0 };
    if (!ReadProcessMemory(hProcess, info.TebBaseAddress, &tib, sizeof(NT_TIB), nullptr))
    {
        int error = GetLastError();
        cout << "ReadProcessMemory error: " << error << endl;
    }

    cout << tib.StackLimit << " to " << tib.StackBase << endl;
    return 0;
}

Process module sample:

#include <windows.h>
#include <iostream>

int main()
{
    int number = 500;
    std::cout << &number << std::endl;

    std::cout << "Pid = " << GetCurrentProcessId() << std::endl;
    std::cout << "Tid = " << GetCurrentThreadId() << std::endl;
    getchar();
    return 0;
}

Result:

在此处输入图像描述

If you do not know the specific thread ID, you can refer to this document to Traversing the Thread List

(Note: NtQueryInformationThread may be altered or unavailable in future versions of Windows. )

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM