Thread: Reading Process Memory

  1. #1
    Registered User
    Join Date
    May 2008
    Location
    Australia
    Posts
    230

    Reading Process Memory

    Hi guys, so I'm trying to write a program that will read a user chosen process' memory starting at address 0x400000 and ending at 0x7FFFFFFF. The problem is it will only read a processes memory every 5 or so times I run the program. Some times I have to restart the program like 15 times before it reads the processes memory. The times it doesn't work GetLastError() will return 299, which is the following:

    ERROR_PARTIAL_COPY: Only part of a ReadProcessMemory or WriteProcessMemory request was completed.

    Can anyone tell me why it can work sometimes and not others?

    This is all a learning experience for me so it wouldn't surprise me if I'm doing something quite strange. You probably only need to see the ReadProcessMemory() loop but I'll post the whole program just in case.

    Thanks a lot guys!

    Code:
    #include <iostream>
    #include <windows.h>
    #include <Tlhelp32.h>
    #include <vector>
    
    using namespace std;
    
    typedef struct ProcessInfo {
    	int procId;
    	char * procName;
    } ProcessInfo;
    
    ProcessInfo EnumerateProcesses();
    
    int main(int argc, char * argv[]) {
    	if (argc != 2 && argc != 1) {
    		printf("Usage: <memHack.exe> <executable.exe>\n");
    		return 1;
    	}
    	
    	LUID privLuid;
    	HANDLE hTokenHandle = 0;
    	
    	/* Change the process security token to debug mode */
    	if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hTokenHandle))
    		printf("[!] Error opening process token: %d\n", GetLastError());
    
    	if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &privLuid))
    		printf("[!] Error looking up the privilege value: %d\n", GetLastError());
    
    	TOKEN_PRIVILEGES sTokenPrivs;
    	sTokenPrivs.PrivilegeCount = 1;
    	sTokenPrivs.Privileges[0].Luid = privLuid;
    	sTokenPrivs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    
    	if (!AdjustTokenPrivileges(hTokenHandle, FALSE, &sTokenPrivs, NULL, NULL, NULL))
    		printf("[!] Error adjusting process token privileges: %d\n", GetLastError());
    
    	CloseHandle(hTokenHandle);
    
    	bool userInput = false;
    	ProcessInfo sProcInfo;
    	memset(&sProcInfo, 0, sizeof(ProcessInfo));
    
    	/* Check if file exists */
    	if (argc == 2) {
    		OFSTRUCT fileInfo;
    		HFILE fileHandle = 0;
    		if ((fileHandle = OpenFile(argv[1], &fileInfo, OF_EXIST)) == HFILE_ERROR) {
    			if (GetLastError() == ERROR_FILE_NOT_FOUND) {
    				printf("[!] File \"%s\" does not exist.\n", argv[1]);
    				CloseHandle((HANDLE)fileHandle);
    				return 1;
    			}
    		}
    		CloseHandle((HANDLE)fileHandle);
    	}
    	
    	/* If not parsed a file to load, enumerate processes for user decision */
    	else {
    		userInput = true;
    		sProcInfo = EnumerateProcesses();
    	}
    	
    	HANDLE targetProcess = 0;
    
    	/* Opening a running process or loading a process */
    	if (userInput) {
    		if ((targetProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, sProcInfo.procId)) == NULL) {
    			printf("[!] Error acquiring %s process handle with PID %d: %d\n", 
    				sProcInfo.procName, 
    				sProcInfo.procId, 
    				GetLastError());
    			return 1;
    		}
    	}
    
    	else {
    		STARTUPINFO startupInfo;
    		PROCESS_INFORMATION processInformation;
    
    		memset(&startupInfo, 0, sizeof STARTUPINFO);
    		memset(&processInformation, 0, sizeof PROCESS_INFORMATION);
    
    		startupInfo.cb = sizeof STARTUPINFO;
    		
    		if (!CreateProcess(argv[1], NULL, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInformation)) {
    			printf("[!] Error loading program and creating process: %d\n", GetLastError());
    			return 1;
    		}
    		
    		if (processInformation.hProcess)
    			targetProcess = processInformation.hProcess;
    
    		if (processInformation.hThread)
    			CloseHandle(processInformation.hThread);
    	}
    
    	unsigned char memoryDump[65535];
    	int byteCount = 0;
    	SIZE_T readAmount = 0;
    	
    	// Read memory into buffer in 65k byte chunks
    	for (SIZE_T y = 0x00400000; y < 0x7FFFFFFF; y += 65535) {
    		if (ReadProcessMemory(targetProcess, &y, memoryDump, 65535, &readAmount)) {
    			for (SIZE_T n = 0; n < 65535; n++) {
    				// 16 bytes have been printed
    				if (byteCount % 16 == 0)
    					printf("\n0x%x: ", y+n);
    				printf("%02x ", memoryDump[n]);
    				byteCount++;
    			}
    		}
    		else {
    			printf("\n[!] Error reading process memory: %d, read %d bytes before error.\n", GetLastError(), readAmount);
    			break;
    		}
    	}
    
    	if (targetProcess)
    		CloseHandle(targetProcess);
    }
    
    
    // Returns the name of the user chosen process
    ProcessInfo EnumerateProcesses() {
    		HANDLE hSnapshot = 0;
    		hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    		
    		if (hSnapshot == INVALID_HANDLE_VALUE) {
    			printf("[!] Failed to obtain process snapshot handle: %d\n", GetLastError());
    			CloseHandle(hSnapshot);
    			exit(0);
    		}
    
    		PROCESSENTRY32 sProc;
    		sProc.dwSize = sizeof(PROCESSENTRY32);
    		if (!Process32First(hSnapshot, &sProc)) {
    			printf("Failed to enumerate first process from snapshot: %d\n", GetLastError());
    			CloseHandle(hSnapshot);
    			exit(0);
    		}
    		
    		vector<char *> processes;
    		vector<int> processIds;
    
    		do {
    			char * tmp = new char[MAX_PATH];
    			strcpy(tmp, sProc.szExeFile);
    			processes.push_back(tmp);
    			processIds.push_back(sProc.th32ProcessID);
    		} while (Process32Next(hSnapshot, &sProc));
    
    		for (int i = 2; i < processes.size(); i++) {
    			printf("[%d] %s - %d\n", i - 1, processes[i], processIds[i]);
    		}
    		
    		int process = 0;
    		printf("\nProcess #: ");
    		cin >> process;
    		process += 1;
    		
    		ProcessInfo sProcInfo;
    		sProcInfo.procName = new char[MAX_PATH];
    		strcpy(sProcInfo.procName, processes[process]);
    		sProcInfo.procId = processIds[process];
    
    		for (int i = 0; i < processes.size(); i++)
    			delete [] processes[i];
    
    		return sProcInfo;
    }
    Last edited by pobri19; 02-09-2010 at 07:22 AM. Reason: Fixed output
    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.

  2. #2
    Registered User
    Join Date
    May 2008
    Location
    Australia
    Posts
    230
    Okay so I just tested this on Windows XP and it runs fine every single time, which leads me to believe it's a new security feature on Windows 7 (my test environment) and possibly Windows Vista too. Does anyone have any ideas on what this security feature is and how I'm supposed to the problem it's causing?

    Edit: Well actually it also depends on the program I test it on. If I run it against the firefox process or msn messenger process it works fine on Windows XP every time, but if I test it on some other processes (non-windows) such as a C# app I developed it 299 errors every time... What the?

    And here's another problem I'm encountering, the program works fine when the user runs it without any paramaters and chooses a process from the enumerated process list, but if I attempt to run the program with an executable as a paramater it will run the program but it will also error with 299, on Windows XP as well, and it errors EVERY TIME. I'm assuming the process isn't inheriting the security access token therefore it's not allowing me to read its memory because it is not in Debug mode? Or is this wrong? Here's that section of code so you don't need to find it:

    Code:
    else {
    		STARTUPINFO startupInfo;
    		PROCESS_INFORMATION processInformation;
    
    		memset(&startupInfo, 0, sizeof STARTUPINFO);
    		memset(&processInformation, 0, sizeof PROCESS_INFORMATION);
    
    		startupInfo.cb = sizeof STARTUPINFO;
    		
    		if (!CreateProcess(argv[1], NULL, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInformation)) {
    			printf("[!] Error loading program and creating process: %d\n", GetLastError());
    			return 1;
    		}
    		
    		if (processInformation.hProcess)
    			targetProcess = processInformation.hProcess;
    
    		if (processInformation.hThread)
    			CloseHandle(processInformation.hThread);
    	}
    Last edited by pobri19; 02-09-2010 at 10:03 AM.
    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.

  3. #3
    Registered User
    Join Date
    May 2008
    Location
    Australia
    Posts
    230
    I did a bit more research and it turns out you get that error if you try and reference protected memory addresses. It's beyond me why it would work some times and not others... There's something new that changes the position of the code in memory I'm assuming, which is causing that?

    Anyways so how am I supposed to find what is protected and what is not... Suggestions? That is if you think I am indeed on the right track. Thanks.
    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.

  4. #4
    Registered User
    Join Date
    May 2008
    Location
    Australia
    Posts
    230
    I take it no one knows? Anyway I figured it out, posting the solution in case anyone else finds this thread has the same problem. Needed VirtualQueryEx() to check the protection type of each segment of memory. Now I'm saving all memory to disk that isn't protected.

    Code:
    #include <iostream>
    #include <windows.h>
    #include <Tlhelp32.h>
    #include <vector>
    #include <fstream>
    #include <Shlwapi.h>
    
    using namespace std;
    
    typedef struct ProcessInfo {
    	int procId;
    	char * procName;
    } ProcessInfo;
    
    ProcessInfo EnumerateProcesses();
    void PrintMemoryProtection(DWORD constant);
    int CheckProtection(DWORD constant);
    
    int main(int argc, char * argv[]) {
    	if (argc != 2 && argc != 1) {
    		printf("Usage: <memHack.exe> <executable.exe>\n");
    		return 1;
    	}
    
    	char path[MAX_PATH];
    
    	GetModuleFileName(0, path, MAX_PATH);
    	PathRemoveFileSpec(path);
    	SetCurrentDirectory(path);
    	
    	LUID privLuid;
    	HANDLE hTokenHandle = 0;
    
    	// Change the process security token to debug mode
    	if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hTokenHandle))
    		printf("[!] Error opening process token: %d\n", GetLastError());
    
    	if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &privLuid))
    		printf("[!] Error looking up the privilege value: %d\n", GetLastError());
    
    	TOKEN_PRIVILEGES sTokenPrivs;
    	sTokenPrivs.PrivilegeCount = 1;
    	sTokenPrivs.Privileges[0].Luid = privLuid;
    	sTokenPrivs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    
    	if (!AdjustTokenPrivileges(hTokenHandle, FALSE, &sTokenPrivs, NULL, NULL, NULL))
    		printf("[!] Error adjusting process token privileges: %d\n", GetLastError());
    
    	CloseHandle(hTokenHandle);
    
    	bool userInput = false;
    	ProcessInfo sProcInfo;
    	memset(&sProcInfo, 0, sizeof(ProcessInfo));
    
    	/* Check if file exists */
    	if (argc == 2) {
    		OFSTRUCT fileInfo;
    		HFILE fileHandle = 0;
    		if ((fileHandle = OpenFile(argv[1], &fileInfo, OF_EXIST)) == HFILE_ERROR) {
    			if (GetLastError() == ERROR_FILE_NOT_FOUND) {
    				printf("[!] File \"%s\" does not exist.\n", argv[1]);
    				CloseHandle((HANDLE)fileHandle);
    				return 1;
    			}
    		}
    		CloseHandle((HANDLE)fileHandle);
    	}
    	
    	/* If not parsed a file to load, enumerate processes for user decision */
    	else {
    		userInput = true;
    		sProcInfo = EnumerateProcesses();
    	}
    	
    	HANDLE targetProcess = 0;
    
    	/* Opening a running process or loading a process */
    	if (userInput) {
    		if ((targetProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, sProcInfo.procId)) == NULL) {
    			printf("[!] Error acquiring %s process handle with PID %d: %d\n", sProcInfo.procName, sProcInfo.procId, GetLastError());
    			return 1;
    		}
    	}
    
    	else {
    		STARTUPINFO startupInfo;
    		PROCESS_INFORMATION processInformation;
    
    		memset(&startupInfo, 0, sizeof STARTUPINFO);
    		memset(&processInformation, 0, sizeof PROCESS_INFORMATION);
    
    		startupInfo.cb = sizeof STARTUPINFO;
    		
    		if (!CreateProcess(argv[1], NULL, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInformation)) {
    			printf("[!] Error loading program and creating process: %d\n", GetLastError());
    			return 1;
    		}
    		
    		if (processInformation.hProcess)
    			targetProcess = processInformation.hProcess;
    
    		if (processInformation.hThread)
    			CloseHandle(processInformation.hThread);
    	}
    
    	MEMORY_BASIC_INFORMATION mbi;
    	SYSTEM_INFO si;
    
    	GetSystemInfo(&si);
    
    	void * memCount = 0;
    	unsigned char * memoryDump = 0;
    	ofstream file("dump.txt");
    
    	while (memCount < si.lpMaximumApplicationAddress) {
    		VirtualQueryEx(targetProcess, memCount, &mbi, sizeof(MEMORY_BASIC_INFORMATION));
    		memoryDump = new unsigned char[mbi.RegionSize];
    		if (CheckProtection(mbi.Protect)) {
    			if (ReadProcessMemory(targetProcess, mbi.BaseAddress, memoryDump, mbi.RegionSize, NULL)) {
    				for (SIZE_T n = 0; n < mbi.RegionSize; n++) {
    					if (byteCount % 16 == 0)
    						sprintf((char *)file, "\n0x%x: ", (unsigned long)mbi.BaseAddress + n);
    				file.write((const char *)memoryDump, mbi.RegionSize);
    				delete [] memoryDump;
    			}
    		}
    		memCount = (LPVOID)((unsigned long)mbi.BaseAddress + (unsigned long)mbi.RegionSize);
    	}
    
    	file.close();
    
    	if (targetProcess)
    		CloseHandle(targetProcess);
    }
    
    // Returns the name of the user chosen process
    ProcessInfo EnumerateProcesses() {
    		HANDLE hSnapshot = 0;
    		hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    		
    		if (hSnapshot == INVALID_HANDLE_VALUE) {
    			printf("[!] Failed to obtain process snapshot handle: %d\n", GetLastError());
    			CloseHandle(hSnapshot);
    			exit(0);
    		}
    
    		PROCESSENTRY32 sProc;
    		sProc.dwSize = sizeof(PROCESSENTRY32);
    		if (!Process32First(hSnapshot, &sProc)) {
    			printf("Failed to enumerate first process from snapshot: %d\n", GetLastError());
    			CloseHandle(hSnapshot);
    			exit(0);
    		}
    		
    		vector<char *> processes;
    		vector<int> processIds;
    
    		do {
    			char * tmp = new char[MAX_PATH];
    			strcpy(tmp, sProc.szExeFile);
    			processes.push_back(tmp);
    			processIds.push_back(sProc.th32ProcessID);
    		} while (Process32Next(hSnapshot, &sProc));
    
    		for (unsigned int i = 2; i < processes.size(); i++)
    			printf("[%02d] %s - %d\n", i - 1, processes[i], processIds[i]);
    		
    		int process = 0;
    		printf("\nProcess #: ");
    		cin >> process;
    		process += 1;
    		
    		ProcessInfo sProcInfo;
    		sProcInfo.procName = new char[MAX_PATH];
    		strcpy(sProcInfo.procName, processes[process]);
    		sProcInfo.procId = processIds[process];
    
    		for (unsigned int i = 0; i < processes.size(); i++)
    			delete [] processes[i];
    
    		return sProcInfo;
    }
    
    int CheckProtection(DWORD constant) {
    	switch (constant) {
    	case PAGE_EXECUTE:
    		return 1;
    		break;
    	case PAGE_EXECUTE_READ:
    		return 1;
    		break;
    	case PAGE_EXECUTE_READWRITE:
    		return 1;
    		break;
    	case PAGE_EXECUTE_WRITECOPY:
    		return 1;
    		break;
    	case PAGE_NOACCESS:
    		return 0;
    		break;
    	case PAGE_READONLY:
    		return 1;
    		break;
    	case PAGE_READWRITE:
    		return 1;
    		break;
    	case PAGE_WRITECOPY:
    		return 1;
    		break;
    	default:
    		return 0;
    	}
    }
    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.

  5. #5
    Registered User
    Join Date
    Jan 2010
    Posts
    412
    You should also test for PAGE_GUARD
    A page where the PAGE_GUARD flag is set cannot be read even if you have read access to it.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Bug in Best-Fit Memory Allocation program (Simulation)
    By RommelTJ in forum C Programming
    Replies: 6
    Last Post: 12-13-2009, 04:43 PM
  2. sequenceing or queueing multiple process
    By sv_joshi_pune in forum Windows Programming
    Replies: 1
    Last Post: 08-14-2009, 09:43 AM
  3. Question regarding Memory Leak
    By clegs in forum C++ Programming
    Replies: 29
    Last Post: 12-07-2007, 01:57 AM
  4. patching memory in another process
    By 44ffcc in forum Windows Programming
    Replies: 2
    Last Post: 02-06-2006, 09:32 AM
  5. Reading from file into memory
    By GaPe in forum C Programming
    Replies: 15
    Last Post: 12-17-2001, 04:19 PM