Search code examples
c++memoryreadprocessmemory

Searching for every occurrence of a string in another process's memory


I am attempting to retrieve every occurrence of a certain string, say "ExampleString". What I currently have will find the first occurrence of the string in a process's memory but it won't find the subsequent strings. I tried to use a vector to store all the results but it only finds one result still.

Below is the function I am using to get the vector of memory locations. Again, it works for the first location.

std::vector<char*> GetAddressOfData(DWORD pid, const char *data, size_t len) {
    HANDLE process = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, pid);

    std::vector<char*> locations;
    int cur = 0;
    if(process){
        SYSTEM_INFO si;
        GetSystemInfo(&si);

        MEMORY_BASIC_INFORMATION info;
        std::vector<char> chunk;
        char* p = 0;
        while(p < si.lpMaximumApplicationAddress){
            if(VirtualQueryEx(process, p, &info, sizeof(info)) == sizeof(info)){
                p = (char*)info.BaseAddress;
                chunk.resize(info.RegionSize);
                SIZE_T bytesRead;
                if(ReadProcessMemory(process, p, &chunk[0], info.RegionSize, &bytesRead)){
                    for(size_t i = 0; i < (bytesRead - len); ++i){
                        if(memcmp(data, &chunk[i], len) == 0) {
                            cur++;
                            locations.resize(cur);
                            locations[cur-1] = (char*)p + i;
                            std::cout << "Found*: " << (void*)locations[cur-1] << "\n";
                        }
                    }
                }
                p += info.RegionSize;
            }
        }
    }
    return locations;
}

Solution

  • Here's some code I wrote years ago to do essentially what you're asking for:

    #include <iostream>
    #include <vector>
    #include <string>
    #include <windows.h>
    #include <algorithm>
    #include <iterator>
    
    template <class InIter1, class InIter2, class OutIter>
    void find_all(unsigned char *base, InIter1 buf_start, InIter1 buf_end, InIter2 pat_start, InIter2 pat_end, OutIter res) {
        for (InIter1 pos = buf_start;
            buf_end!=(pos=std::search(pos, buf_end, pat_start, pat_end));
            ++pos)
        {
            *res++ = base+(pos-buf_start);
        }
    }
    
    template <class outIter>
    void find_locs(HANDLE process, std::string const &pattern, outIter output) {
    
        unsigned char *p = NULL;
        MEMORY_BASIC_INFORMATION info;
    
        for ( p = NULL;
            VirtualQueryEx(process, p, &info, sizeof(info)) == sizeof(info);
            p += info.RegionSize ) 
        {
            std::vector<char> buffer;
            std::vector<char>::iterator pos;
    
            if (info.State == MEM_COMMIT && 
                (info.Type == MEM_MAPPED || info.Type == MEM_PRIVATE)) 
            {
                SIZE_T bytes_read;
                buffer.resize(info.RegionSize);
                ReadProcessMemory(process, p, &buffer[0], info.RegionSize, &bytes_read);
                buffer.resize(bytes_read);
                find_all(p, buffer.begin(), buffer.end(), pattern.begin(), pattern.end(), output);
            }
        }
    }
    
    int main(int argc, char **argv) {
        if (argc != 3) {
            fprintf(stderr, "Usage: %s <process ID> <pattern>", argv[0]);
            return 1;
        }
    
        int pid;
        sscanf(argv[1], "%i", &pid);
    
        std::string pattern(argv[2]);
    
        HANDLE process = OpenProcess( 
            PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, 
            false,
            pid);
    
        find_locs(process, pattern, 
            std::ostream_iterator<void *>(std::cout, "\n"));
    
        return 0;
    }
    

    I do think it's worth noting that it looks like your code has most of the same general ideas as this does--the differences are primarily in details that probably look pretty trivial, at least at first glance (but I guess that's not surprising, given that your code is close enough to at least find an initial occurrence).