【问题标题】:C++ read all memory from process within modulesizeC ++从模块大小中的进程读取所有内存
【发布时间】:2020-08-29 19:37:37
【问题描述】:

我一直在尝试仅读取进程范围内的所有内存地址(请参阅问题:C++ read memory addresses within process range only)。我成功地从记忆中读取,并且似乎我收到了正确的baseaddress 用于该过程。我遇到的问题是找到我认为程序会有的特定值。

例如,如果我玩了一个游戏,分数 500,我想在内存中找到 500。我遍历了所有地址,但找不到值。所以我决定阅读我自己的程序(它是 64 位的)并将值设置为 500,打印它的地址并手动搜索,看看是否找到它。

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

由于某种原因,它写入的地址超出了进程范围。

我计算地址范围:

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);

使用的方法:

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;
    }

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;
}

由于number 的值超出范围,我认为GetModuleSize 可能不正确。

我的最后一个地址是:0x4F4628, std::cout &lt;&lt; &amp;number; 给我0x6DFDD4

我的问题是:

  • GetModuleSize 是不是计算最后一个地址的不正确方法 应用程序?如果是这样,我可以更正吗?
  • 通过将最后一个地址乘以 2,我能够读取该值 的&amp;number。这是因为 modulesize 给了我一个 32 位的范围,还是给我的地址超出了进程的范围?

我编译时使用:g++ main.cpp -o x -lpsapi -DUNICODE -m64,并且必须将 libgcc_s_seh-1.dll 添加到我的路径中才能运行我的程序。

我在github上的整个项目:https://github.com/Darclander/memory-reading

(不确定将整个代码发布在这里是否更好)。

【问题讨论】:

    标签: c++ winapi


    【解决方案1】:

    WIN32 术语中的“模块”是可执行映像文件。此图像包含代码、静态变量、堆栈展开表等内容。您尝试读取的值是局部变量,因此将在堆栈上分配。堆栈不是图像的一部分,因此您不会在那里找到它。

    您需要做的是找到堆栈的地址和大小。请参阅How can I locate a process' global and stack areas in Win32? 了解如何执行此操作。

    除了堆栈之外,您可能还想读取堆,您可以使用GetProcessHeaps 找到所有打开的堆,并使用HeapSummary 获取地址/大小。

    【讨论】:

    • 是的,我正在调查这个,我调查了Heap32First。将moduleSizeheapSize 添加到基地址会给我进程总范围吗?或者这只会给我一个随机值?
    • 可以使用 Heap32First 专门查找堆地址空间。 “总进程范围”不是很有用,因为这会假设虚拟地址空间被连续使用,而事实并非如此。如果你真的想扫描整个进程内存,你可以使用VirtualQueryEx,但是像玩家分数这样的东西通常只能在堆或堆栈中找到,扫描其他区域可能会给你带来误报。
    • 所以VirtualQuery 不会扫描模块部分,而是扫描堆和堆栈?或者如果我想找到堆和堆栈,我应该扫描什么? (只有分数等)@para
    【解决方案2】:

    正如@para 所说,该模块是PE 文件的图像。

    要读取的变量存放在当前线程栈中,需要获取栈的基地址和限制地址,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;
    }
    

    流程模块示例:

    #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;
    }
    

    结果:

    如果不知道具体的线程ID,可以参考这个文档Traversing the Thread List

    (注意:NtQueryInformationThread 在未来的 Windows 版本中可能会更改或不可用。)

    【讨论】:

      猜你喜欢
      • 2011-09-24
      • 2023-03-12
      • 1970-01-01
      • 1970-01-01
      • 2012-05-09
      • 2020-07-19
      • 2022-06-24
      • 2013-08-09
      相关资源
      最近更新 更多