Visualization of process memory

Visualization of process memory

I started a new multi-player game, after a while I wondered about the game’s memory and what is kept in it. I know one strategy is to visually represent process’ memory as pixels. Take a byte from a memory and associate it with a 8bit color or take 4 bytes and create an ARGB color. There are many tools to read or write memory (Cheat Engine), but that felt to easy and I would not learn much. So I started a simple project for reading and visualizing process’ memory.

On a Windows system it is very easy to read memory of a process. You only need three APIs from WinAPI to get the job done. First thing is to get a handle of a process, for that use OpenProcess. The method takes in configuration of the required access (read/write etc) and process id. Third parameter is about sending handles to the child process, in this case it is not required, so we can leave it as FALSE.

int pID = 10;
handle_t hprocess = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, pID)

In the example above, I passed two flags as a configuration. The first one is obvious, that is for having permissions to read memory. The second flag is to have access to information about memory regions, this is required for our second API VirtualQueryEx. It is important that your application that tries to execute OpenProcess has administrator permissions, as some applications cannot be opened with the regular user rights. Another import thing is about architecture, if you are trying to open 64bit process, make sure that your application that is calling OpenProcess is compiled as 64bit application. Otherwise it is not possible to read other process’ memory from a 32bit application. There are ways to achieve that, but it is not in scope for this article.

Lets go to our second method VirtualQueryEx. It is used to retrieve information about memory regions. It is possible to read process memory without this, but sometimes you will have unexpected results. Some regions are not accessible or readable, so in that case if you try to read memory across two regions and one is readable and the second is not, you will not get anything back. Therefore before reading a memory block verify that it is accessible.

MEMORY_BASIC_INFORMATION regionInfo;
VirtualQueryEx(hprocess, (void*)address, &regionInfo, sizeof(regionInfo));

if (regionInfo.Protect != PAGE_NOACCESS && regionInfo.State == MEM_COMMIT)
{
	//proceed
}

The information about a region is basic, it contains information about the baseaddress, size of a region and the access level. When executing VirtualQueryEx you don’t need to point the address at the very start of the region, anywhere in the region will do. Next step is to verify if this region is useful for our third method ReadProcessMemory. This can be done by checking if the region is not protected and it has committed pages. As you can see in the code example from above.

After getting the process handle and verifying regions we can read memory. The code below is self explanatory, so I will not go in detail here.

size_t bytesRead;
size_t len = 10;
std::vector<unsigned char> memBuff;
memBuff.resize(10);

ReadProcessMemory(hprocess, (void*)0x7FFDCF0EE6CC, &memBuff[0], len, &bytesRead);

After getting the memory reading peace done, there are couple options how to proceed to visualization. There are many GUI frameworks available for C++ that can be used for drawing, WINAPI to draw with GDI or OpenGL/DirectX frameworks. For the best performance I would suggest to go with a solution that support 2D Hardware Acceleration, as there will be a lot of drawing. Good candidate is SDL (Simple DirectMedia Layer).

For my project I went with C++/CLI and C# as I am more experienced with GUI development on C# then on C++ and I did not want to invest a lot of time on the rendering piece. The memory reader is compiled as a managed library and used from a C# WinForms Application. C# WinForms sits on top of GDI+ so you can forget about GPU rendering, everything is rendered by CPU. After spending couple days on trying different approaches to improve GDI rendering I started to regret my decision about the C# WinForms solution. It does not perform as good as I wanted, it is better to go straight to OpenGL or Direct2D drawing.

Bitmap bm = new Bitmap(500, 500, PixelFormat.Format32bppPArgb);

Graphics g = Graphics.FromImage(bm);
g.CompositingMode = CompositingMode.SourceCopy;
g.CompositingQuality = CompositingQuality.HighSpeed;
g.PixelOffsetMode = PixelOffsetMode.None;
g.SmoothingMode = SmoothingMode.None;
g.InterpolationMode = InterpolationMode.Default;

For the drawing I used the bitmap component, afterwards it is loaded in the picturebox component. I tried different configuration options and this configuration from above seems to be performing best. The graphics object is used for drawing, in the attached solution you can see that it is passed to visualizer class, which reads 4 bytes of a process memory, creates a new color from those 4 bytes and draws on the graphics component. The trickiest part was when reading a long memory blocks that goes across multiple regions and some of them are are protected. For that I used recursive approach and if memory region is not accessible it is is displayed as black blocks.

The application is simple, you need to attach to a running process and enter address what you want to display. There are two controls - for setting up length of the pixel line, the size of a pixel. The first scrollbar is important, because the length of the line matters, if it is not correct, the representation will not be correct. In the picture you can see that I set the length of the pixel line to 96, otherwise the images from the memory would not be correctly displayed. The picturebox has an event listeners for mouse movement, so you can click and move your mouse to go to a different memory region and display it.

Source Code

comments powered by Disqus