Johnaudi
Johnaudi

Reputation: 257

Searching for string in memory causes to crash

I am not so good with C++, but I am experiencing issues scanning for a string in my own memory.

Here's a small sample of my code:

for (unsigned int i = 0x400000; i < 0xFFFFFFFFFF; i++) {
    string s = (char *) i;
    if (s[0] == 'H') {
        if (s == "Hello") {
            cout << "Found at address: " << i << endl;
        }
    }
}

It keeps scanning until it comes to a certain "position" where the application crashes. I am guessing it is reaching unallocated memory and is crashing due to undefined behavior.

But the question is, what's the best way to do this? I'm trying to stay away from ReadProcessMemory and WriteProcessMemory.

In general: What's the best way to search for a string within its own process?

Thanks in advance.

Upvotes: 0

Views: 453

Answers (2)

Jerry Coffin
Jerry Coffin

Reputation: 490338

Although it's not mentioned in the tags, based on the mention of ReadProcessMemory, I'm going to assume you want this for Windows.

To do this in Windows, you pretty much need to use VirtualQuery to figure out what parts of your address space are usable (particularly important on 64-bit systems, where valid addresses are much sparser than on 32-bit systems).

Code using VirtualQuery to find searchable blocks could look something like this:

#include <iostream>
#include <vector>
#include <string>
#include <windows.h>
#include <algorithm>
#include <iterator>

template <class InIter1, class InIter2, class OutIter>
void find_all(InIter1 buf_begin, InIter1 buf_end, InIter2 pat_begin, InIter2 pat_end, OutIter output) { 
    for (auto pos = buf_begin;
        buf_end != (pos = std::search(pos, buf_end, pat_begin, pat_end));
        ++pos)
    {
        *output++ = (void *)pos;
    }
}

template <class outIter>
void find_locs(std::string const &pat, outIter output) {

    unsigned char *p;
    MEMORY_BASIC_INFORMATION info;

    for ( p = nullptr;
        VirtualQuery(p, &info, sizeof(info)) == sizeof(info);
        p += info.RegionSize ) 
    {
        if (info.State == MEM_COMMIT && 
           (info.Type == MEM_MAPPED || info.Type == MEM_PRIVATE)) 
        {
            find_all(p, p + info.RegionSize, pat.begin(), pat.end(), output);
        }
    }
}

int main(int argc, char **argv) {
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <pattern>", argv[0]);
        return 1;
    }

    find_locs(argv[1], std::ostream_iterator<void *>(std::cout, "\n"));
}

Expect this to turn up a few "spurious" matches. In particular, even if the string you search for doesn't occur anywhere else in the process' memory space, there will be one copy as part of argv and (at least) one more for the temporary std::string that's passed to find_locs, so expect a bare minimum of two matches for any string you might pass.

You'll probably also want to read through the docs for MEMORY_BASIC_INFORMATION. I've chosen a subset of blocks that (I'm pretty sure) is safe to read (i.e., those that are committed and either mapped or private) but depending on what you're looking for, you might want to change that to restrict it to searching only through program text rather than text and data.

Upvotes: 1

Thomas Matthews
Thomas Matthews

Reputation: 57753

Deferencing arbitrary pointer values (addresses) is undefined behavior and varies by platform and operating system.

Crashing is one of many undefined behaviors.

Upvotes: 1

Related Questions