Scan through process' memory

I wanted to learn all about memory and thus like I usually do when I want to learn something I make a program that does something using it.

Now I'm making something like Tsearch, I'm learning threads, processes and their memory. My program is to scan through the memory of another process given a certain string or value. Don't worry, I won't hack with it - or I would've used Tsearch instead...

Anyway, I'm now using Toolhelp23 functions and ReadProcessMemory to read a process' memory and search a value. After a lot of hassle and searching around I got to find partly the results that Tsearch finds, only tons of others in addition. For example, when I let my program search through CreateCD's process for value 167 (2 bytes), it finds 320 matches when I go through all of its modules and read their memory. Tsearch though finds only 92 matches.

When I listed my program's results in a file and I compared them I found that a good 75 out of 92 addresses that Tsearch returned were also among mine.

At first I thought that the explanation was that Tsearch knows from what point on the memory isn't used by the program, and mine doesn't, but that doesn't explain why Tsearch finds matches that I don't. I also tried to include a heap search in my program by enumerating all of a process' heaps and search them, but that didn't help. Most of it is all zero.

So my question is, how do I exactly and effectively find and get access to the memory used by a process, so that I can search through it? Am I on the right way? If yes, what should I change?

Thank you very much in advance.
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Why do you expect the results being the same? Comditions change and in fact are different every time a program is started. Furthermore, a process' memory is a dynamic thig that is in a constant state of change...
Each process's memory includes all kinds of things, code, data, stack, heap, mapped in files, shared memory segments, shared dll's, and more.   Some of the memory manager API's will tell you what those regions are (some of them).

LuncinandorAuthor Commented:
jkr, the results are 92 matches constant over half an hour, CreateCD is an idle program in my system tray waiting to be double clicked. So yes, I do expect the results to be the same.

grg99, what API should I use to find out what kind of memory I am reading? Also, how come Tsearch found an additional 10-15 addresses that my program didn't find?

I hope this problem can be solved very quickly.
Cloud Class® Course: Python 3 Fundamentals

This course will teach participants about installing and configuring Python, syntax, importing, statements, types, strings, booleans, files, lists, tuples, comprehensions, functions, and classes.

LuncinandorAuthor Commented:
And pardon me, but I work on Windows 98. I have found many ways of finding out working set sizes and such for NT/XP but those are no use for Windows 98.
LuncinandorAuthor Commented:
Isn't there anyone ho can help me out?
Try calling this function below.  it will tell you a lot about what's up:

The VirtualQueryEx function provides information about a range of pages within the virtual address space of a specified process.

DWORD VirtualQueryEx(

    HANDLE hProcess,      // handle of process
    LPCVOID lpAddress,      // address of region
    PMEMORY_BASIC_INFORMATION lpBuffer,      // address of information buffer  
    DWORD dwLength       // size of buffer



Identifies the process whose memory information is queried. The handle must have PROCESS_QUERY_INFORMATION access.


Points to the base address of the region of pages to be queried. This value is rounded down to the next page boundary. To determine the size of a page on the host computer, use the GetSystemInfo function.


Points to a MEMORY_BASIC_INFORMATION structure in which information about the specified page range is returned.


Specifies the size, in bytes, of the buffer pointed to by the lpBuffer parameter.


Return Values

The return value is the actual number of bytes returned in the information buffer.


VirtualQueryEx provides information about a region of consecutive pages beginning at a specified address that share the following attributes:

·      The state of all pages is the same with the MEM_COMMIT, MEM_RESERVE, MEM_FREE, MEM_PRIVATE, MEM_MAPPED, or MEM_IMAGE flag.
·      If the initial page is not free, all pages in the region are part of the same initial allocation of pages reserved by a call to the VirtualAlloc function.


The VirtualQueryEx function determines the attributes of the first page in the region and then scans subsequent pages until it scans the entire range of pages, or until it encounters a page with a nonmatching set of attributes. The function returns the attributes and the size, in bytes, of the region of pages with matching attributes. For example, if there is a 40 megabyte (MB) region of free memory, and VirtualQueryEx is called on a page that is 10 MB into the region, the function will obtain a state of MEM_FREE and a size of 30 MB.

This function is identical to the VirtualQuery function, except that it enables access to information about memory in a specified process.

See Also

GetSystemInfo, MEMORY_BASIC_INFORMATION, VirtualAlloc, VirtualProtectEx, VirtualQuery
>>So yes, I do expect the results to be the same

Better don't. It simply unrealistic.
LuncinandorAuthor Commented:
Thank you very much grg99, I'll try setting it up with that function.

Meanwhile, this function I will call to find out if my program should scan the specified block of memory or not, but it still won't help me finding the additional 15 addresses that Tsearch finds and mine doesn't.

Do you have any idea about that, perhaps?

I'll let you know if the function works :)

jkr, why is it unrealistic to expect the results to be the same if consecutive searches spread over a while with Tsearch all return the same number of matches? My program also keeps returning the same matches, but like I said they don't match.

Just a few guesses:

If your search includes the stack segment, anything below the stack pointer is going to vary from call to call.

If your hit a system DLL, it may have memory areas that you do not have enough privilidges to access, or return garbage when read.

Data segments of course are going to be twiddling a lot.

LuncinandorAuthor Commented:
Well as of now I am scanning through all of the modules returned by Module32First() and Module32Next(). Shouldn't I? Of every module returned, I read the data from MODULEENTRY32::modBaseAddr through (MODULEENTRY32::modBaseAddr + (BYTE*)MODULEENTRY32::modBaseSize).

Also, I got it to work with VirtualQueryEx(), but what types of memory (or states) should I ignore?

I really appreciate you helping me :)
LuncinandorAuthor Commented:
Goddamnit! I posted this really long report of what I found out trying everything and it's not there!

Well anyway, in short, I found out that of a good 35 DLLs that CreateCD uses, only 10 DLLs have matches that Tsearch has too. The others also have matches in their memory space, but those are not posted by Tsearch.

Also, a few of those 10 'good' DLLs also have a block of matching addresses that Tsearch doesn't post. In this case, the block of memory returned by VirtualQueryEx() for the first time is either a block of matching addresses that Tsearch shares or not, but then I loop back because not all of the module's memory has been scanned, and the next block of memory that VirtualQueryEx() returns (though all of the blocks are MEM_COMMIT and MEM_PRIVATE) is otherwise.

By the way, as I said, VirtualQueryEx() says all of the memory blocks are MEM_COMMIT and MEM_PRIVATE. So this function doesn't really provide me a way of filtering out matches that are not used or found in executable code or whatever. Anyway, the flags you mentioned in your post defining VirtualQueryEX() do look helpful, grg99 - isn't there a way of finding out those or alikes? Filtering out complete modules won't help because of what I mentioned earlier, module memory spaces containing both a block of matches do found by Tsearch and not.

Isn't there a possibility that Tsearch knows what basic range of memory it has to look for, and doesn't really scan specific modules but by hand of querying memory addresses it finds out what to scan and what not? The 10 'good' DLLs range from 0x63000000 through 0x78044000. Also, Tsearch first finds matches close to the beginning, 0x00400000, and then jumps to much more away.

That would explain matches not found by my program (the modules' memory spaces don't line up perfectly of course, on the contrary) and also that I find matches in a module not found by Tsearch. In this case, there must be a way of finding out more information than those 6 flags returned by VirtualQueryEx().

I guess this isn't just a short version anyway... Well I think I got everything I wrote earlier today. I'm sorry for the long post, but I just want to lay out all the information and guesses I got so that you can help me in the best way.

I'm ver very very much hoping that you can help me, I'm dying to get this done fast.

Thanks in advance :)
PAQed, with points refunded (500)

EE Admin

Experts Exchange Solution brought to you by ConnectWise

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.