0

I'm attempting to scan the memory of a certain module in a certain process and find all ints in the memory, and output them.

I do this by getting the base address of the module (in this case the module is the name of the exe) and then using the module size to calculate the end address of the module.

I then iterate over every address and try to read an int. It works in some cases, but a good deal of the time, RPM returns error 299 (ERROR_PARTIAL_COPY). I'm not really sure as to why, because I check the page rights, and I check if the page has backing.

It seems to work on x86 processes (when I compile it in x86) but not x64 processes (when I compile in x64)? Any suggestions are appreciated, I'm kind of lost. My RPM call is correct as well, as it works on some processes. Thanks!

void ScanProcess(DWORD processID){
    char szProcessName[MAX_PATH];

    HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID);
    HMODULE hMod = NULL;
    if (hProcess){
            DWORD cbNeeded;
        if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded)) {
            GetModuleBaseName(hProcess, hMod, szProcessName, sizeof(szProcessName));
            MODULEINFO lpm;
            GetModuleInformation(hProcess, hMod, &lpm, sizeof(lpm));

            DWORD start, end;

            start = (DWORD)hMod;
            end = start + lpm.SizeOfImage;
            printf("Scanning module %s  (PID: %u) Range: %x to %x\n", szProcessName, processID, start, end);

            for (uintptr_t i = start; i < end; i++) {
                PSAPI_WORKING_SET_EX_INFORMATION * pWSX = (PSAPI_WORKING_SET_EX_INFORMATION *)malloc(sizeof(PSAPI_WORKING_SET_EX_INFORMATION));
                pWSX->VirtualAddress = reinterpret_cast<void*>(i);
                QueryWorkingSetEx(hProcess, &pWSX, sizeof(PSAPI_WORKING_SET_EX_INFORMATION));

                if (pWSX->VirtualAttributes.Valid == 1) {
                    if ((pWSX->VirtualAttributes.Win32Protection & PAGE_READWRITE) || (pWSX->VirtualAttributes.Win32Protection & PAGE_READONLY) || (pWSX->VirtualAttributes.Win32Protection & PAGE_EXECUTE_READWRITE) || (pWSX->VirtualAttributes.Win32Protection & PAGE_EXECUTE_READ)) {
                        printf("Page: %x. Page backing is %s. Page protection: %X\n", i, pWSX->VirtualAttributes.Valid ? "valid" : "invalid", pWSX->VirtualAttributes.Win32Protection);
                        int j = 0;
                        if (ReadProcessMemory(hProcess, (LPCVOID)i, &j, sizeof(int), 0))
                            printf("%s SUCCESS %i\n",szProcessName, j);
                        else
                            printf("Error: %x", GetLastError());
                    }
                }
            }
        }
    }


    CloseHandle(hProcess);
}
  • From my [previous answer](http://stackoverflow.com/a/34648230/65863): "*ReadProcessMemory would return FALSE and GetLastError would return ERROR_PARTIAL_COPY when the copy hits a page fault... When a process references pageable memory that is not currently in its working set, a page fault occurs*". You can't just scan an entire process from start to end and expect every address to be committed and readable. That is just not how Windows' virtual memory model works. – Remy Lebeau Jul 07 '16 at 04:46
  • @RemyLebeau How can I check for page faults though before I read the memory. Is that not what I'm already doing with QueryWorkingSectionEx? I know that a lot of the address space won't be readable, that's why I'm doing checks. There are certain processes that return error 299 for every page that I try to read, while others go through the whole process without a single error. – user3749382 Jul 07 '16 at 04:49
  • @RemyLebeau It also doesn't really seem to matter if the process I'm scanning is 64 or 32 bit, some processes scan all the way through with no issues (with the current checks I do), but some return error 299 on every page that I read. On those processes, I can't get 1 int out of memory, which is my real issue. – user3749382 Jul 07 '16 at 04:56
  • 1
    you are not checking the return value of `QueryWorkingSetEx` for error, and you are not accounting for the fact that your code has a race condition. The information from `QueryWorkingSetEx` may be stale as soon as it returns. The target process's working set can change before you have a chance to check the flags or call `ReadProcessMemory()`. That being said, your goal to "*find all ints in the memory*" is completely unrealistic, because EVERY value in memory can be *interpreted* as an integer even if it is not really an integer in the process that allocated it... – Remy Lebeau Jul 07 '16 at 04:58
  • 1
    Without intimate knowledge of the target process's source code, you CANNOT differentiate integer values from non-integer values. EVERYTHING is just a number to a computer, it is the logic of the source code that gives any valid meaning to those numbers. You cannot gleam that logic across process boundaries by simply reading arbitrary memory bytes. – Remy Lebeau Jul 07 '16 at 05:00
  • I'm basically trying to recreate something like CheatEngine, where you perform a search of ints, then change the value, search the results array again, and narrow down results, so that I can find the location of a certain value in memory. Anyway, even when I don't perform any checks with QueryWorkingSetEx , and just RPM every address from start to end of the module, there are still certain 64 bit processes that return error 299 for **every** RPM call. – user3749382 Jul 07 '16 at 05:10
  • let me say it again: "*You CANNOT just scan an entire process from start to end and expect every address to be committed and readable.*". Error 299 is telling you that you are causing page faults trying to access memory that is not actually accessible at the time. You really need to re-think your approach. And FYI, CheatEngine is open-source, so go look at its source code to see what it really does. – Remy Lebeau Jul 07 '16 at 17:24
  • @RemyLebeau I know that most memory won't be accessible at the time. My question is, how can i figure out weather or not the memory is readable, before actually reading it (that's what I'm trying to do with the QueryWorkingSection call. The process that I'm dealing with crashes if you read invalid memory (as an anti-reverse measure), so I need to **only** read good memory. – user3749382 Jul 08 '16 at 01:07
  • "*how can i figure out weather or not the memory is readable, before actually reading it*" - you can't reliably do it, it is a race condition trying to check it. But if you must, at least ignore guard pages (which you are not checking for), and you should also change your loop condition to `i < (end-sizeof(int))` instead of `i < end`, since you can't read a full `sizeof(int)` number of bytes when you reach the last few bytes of the process memory. And again, if all else fails, study CheatEngine's own source code to figure out how it deals with this issue (if it does at all). – Remy Lebeau Jul 08 '16 at 01:33
  • Alright, I'll look into that. CheatEngine doesn't deal with it, which is why I'm making my own software. – user3749382 Jul 08 '16 at 02:15

0 Answers0