Thread: ReadProcessMemory Error

  1. #1
    Registered User
    Join Date
    Oct 2005
    Location
    Brasil
    Posts
    220

    ReadProcessMemory Error

    Hey, I am trying to use the ReadProcessMemory function but every time I call it I get the error code 299 from the function GetLastError() that means: "Only part of a ReadProcessMemory or WriteProcessMemory request was completed.".

    OS: Windows Vista.
    Code from the "reader":
    Code:
    handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, getPid());
    
    SIZE_T bytesRead;
    std::string buffer(8, '\0');
    unsigned long address = 0x001cf834;
    
    if (ReadProcessMemory(handle, &address, &buffer[0], 8, &bytesRead))
    {
    	return true;
    }
    else
    {
    	cout << GetLastError() << '\n';
    	return false;
    }
    Remark: the process ID is correct, I assure you .

    Code from the "readed":
    Code:
    #include <iostream>
    #include <fstream>
    
    using namespace std;
    
    int main()
    {
    	char t[] = "my pattern" ;
    
    	cout << "addr: " << &t << '\n';
    
    	cin.get();
    }
    1) The address chosen to be the parameter of ReadProcessMemory is the address printed in the readed program, is that right?

    2) By the way, always when i restart the readed program the address of char t changes, why? If I am allocating it statically shouldn't it have always the same address?

    3) How can i search a program's memory like a debugger? I have tought of scanning its memory trough ReadProcessMemory respecting the maximum and minimum base addresses provided by the function GetSystemInfo(), is it the correct way of doing that?

    4) If the last question is true, how much should be the buffer size of the ReadProcessMemory because I imagine that a call to this function should take a lot of time so implementing a buffer would help?

    Thank You

  2. #2
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    The error 299 is ERROR_PARTIAL_COPY - so for some reason, the OS thinks it's fine to read parts of the memory, but not all.

    How many bytes does it report that you got?

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  3. #3
    Registered User
    Join Date
    Mar 2005
    Location
    Mountaintop, Pa
    Posts
    1,058
    Hey, I am trying to use the ReadProcessMemory function but every time I call it I get the error code 299 from the function GetLastError() that means: "Only part of a ReadProcessMemory or WriteProcessMemory request was completed.".
    It may be due to your not elevating the token privilege level since you're reading memory on the system level. But even if your are elevating the privilege level, you may not be doing it correctly. The reason being is that I noticed you were not elevating the privilege level correctly in one of your other posts. You were calling it after opening the process. It must be called prior to opening the process. Also, the 0x001cf834 address is incorrect. I put some info in the sample to explain the address.

    But anyway, the following example displays the command line parms (if any) of the process in question.

    Code:
    #define UNICODE
    #define _UNICODE
    
    #include <windows.h>
    #include <stdio.h>
    #include <tchar.h>
    
    #pragma comment(lib, "advapi32.lib")
    
    // Process data block is found in an NT machine.
    // on an Intel system at 0x00020000  which is the 32
    // memory page. At offset 0x0498 is what I believe to be
    // the process' startup directory which is followed by
    // the system's PATH. Next is  process full command
    // followed by the exe name.
    #define PROCESS_DATA_BLOCK_ADDRESS      (LPVOID)0x00020498
    // align pointer
    #define ALIGNMENT(x) ( (x & 0xFFFFFFFC) ? (x & 0xFFFFFFFC) + sizeof(DWORD) : x )
    
    BOOL GetCommandLine (HANDLE hProcess, LPWSTR lpszCmdLine)
    {
    	LPBYTE lpBuffer = NULL;
    	LPBYTE lpPosition = NULL; 
    	DWORD dwBytesRead;
    	MEMORY_BASIC_INFORMATION mbi;
    	SYSTEM_INFO sysinfo;
    
    	GetSystemInfo (&sysinfo);
    	lpBuffer = (LPBYTE)malloc (sysinfo.dwPageSize);
    	if ( lpBuffer == NULL )
    		return FALSE;
    	if ( VirtualQueryEx (hProcess, PROCESS_DATA_BLOCK_ADDRESS, &mbi, sizeof(mbi) ) == 0)
    		return FALSE;
    	if (!ReadProcessMemory ( hProcess, mbi.BaseAddress, (LPVOID)lpBuffer, 
    		sysinfo.dwPageSize, &dwBytesRead))
    		return FALSE;
    	lpPosition = lpBuffer + ((DWORD)PROCESS_DATA_BLOCK_ADDRESS - (DWORD)mbi.BaseAddress);
    	lpPosition = lpPosition + (wcslen ((LPWSTR)lpPosition) + 1) * sizeof(WCHAR);
    	lpPosition = (LPBYTE)ALIGNMENT((DWORD)lpPosition);
    	lpPosition = lpPosition + (wcslen ((LPWSTR)lpPosition) + 1) * sizeof(WCHAR);
    	if ( *lpPosition == '\0' ) lpPosition += sizeof(WCHAR);
    	wcsncpy  ( lpszCmdLine, (LPWSTR)lpPosition, MAX_PATH );
    	lpszCmdLine[MAX_PATH-1] = L'\0';
    	if (lpBuffer != NULL) free(lpBuffer);
    	return TRUE;
    }
    
    BOOL EnableTokenPrivilege (LPTSTR privilege)
    {
    	HANDLE hToken;                        
    	TOKEN_PRIVILEGES token_privileges;                  
    	DWORD dwSize;                        
    	ZeroMemory (&token_privileges, sizeof (token_privileges));
    	token_privileges.PrivilegeCount = 1;
    	if ( !OpenProcessToken (GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken))
    		return FALSE;
    	if (!LookupPrivilegeValue ( NULL, privilege, &token_privileges.Privileges[0].Luid))
    	{ 
    		CloseHandle (hToken);
    		return FALSE;
    	}
    
    	token_privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    	if (!AdjustTokenPrivileges ( hToken, FALSE, &token_privileges, 0, NULL, &dwSize))
    	{ 
    		CloseHandle (hToken);
    		return FALSE;
    	}
    	CloseHandle (hToken);
    	return TRUE;
    }
    
    int wmain (int argc, wchar_t *argv[])
    {
    	WCHAR      CommandLine[MAX_PATH] = {0};
    	WCHAR      *endptr;
    	DWORD      pID; 
    	HANDLE      hProcess = NULL;
    	if ( argc != 2 )
    		return 0;
    	pID = wcstoul ( argv[1], &endptr, 10 );
    
    	if ( !EnableTokenPrivilege (SE_DEBUG_NAME) )
    	{
    		printf ( "Cannot get required privilege %lu\n", GetLastError () );
    		return 0;
    	}
    	hProcess = OpenProcess (PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_QUERY_INFORMATION,
    		FALSE, pID);
    	if ( hProcess == NULL )
    	{
    		printf ("Cannot open process. pID: %lu, error %lu\n", pID, GetLastError ());
    		return 0;
    	}
    	if ( !GetCommandLine ( hProcess, CommandLine ) )
    	{
    		printf ("Cannot get process command line, error: %lu\n", GetLastError ());
    		return 0;
    	}
    	else
    		printf ("The command line is %S\n", CommandLine);
    	CloseHandle ( hProcess );
    	return 0;
    }

  4. #4
    Registered User
    Join Date
    Oct 2005
    Location
    Brasil
    Posts
    220
    @ matsp

    It says that i have read 0 bytes...

    @ BobS0327

    Even your example doesn't work... The functions all return ok with no error messages but the CommandLine is empty....

    And im sorry to say, i haven't understood well addressing, what I do to get and address now is do debug my application, search it for the bytes that form "my pattern" string and get its address... It is correct isn't it?

    I have adapted your code of enabling debug privilege into mine but i still get incomplete reads.

  5. #5
    Registered User
    Join Date
    Mar 2005
    Location
    Mountaintop, Pa
    Posts
    1,058
    OS: Windows Vista
    What I believe may be the problem is that you're running the code under Vista. I've tested the sample under XP and Win2K without any problems.

    Unfortunately, I won't have access to Vista until Monday morning to test the sample.

  6. #6
    Registered User
    Join Date
    Oct 2005
    Location
    Brasil
    Posts
    220
    Ok, i will try to find something until then, but im really lost =(

  7. #7
    Registered User
    Join Date
    Mar 2005
    Location
    Mountaintop, Pa
    Posts
    1,058
    I've encountered the same problem as you with Vista Enterprise edition.

    Vista has new security enhancements to thwart the malware folks. One feature is Address Space Load Randomization which randomly loads a process into memory. Under Vista, you have a 1 in 256 chance of finding the base address of a process. Whereas, under XP and W2K you knew exactly where in memory a process started as indicated above.

    This link will provide a more detailed explanation of Vista Address Space Load Randomization.

    BTW, you can create a hack to make the code work. You'll need Ollydebug to get the base address of the process. then recompile the code with the acquired base address. But every time you reboot, you'll have to execute Ollydebug for the new base address and recompile the code again with the new address.

  8. #8
    Registered User
    Join Date
    May 2008
    Posts
    2

    Hate to resurrect a zombie, but...

    this board is high enough on the search engine rankings that I think having an answer to this question would be useful. A lot of queries into the cause of this problem have been made, including Address Randomization (which only applies to system processes) and Vista's security (which doesn't apply if running as an administrator and not accessing a protected process). The real problem here is that people have not read the documentation for OpenProcess since Vista came out. OpenProcess is being called with PROCESS_ALL_ACCESS rights requested. On Vista, the size of PROCESS_ALL_ACCESS has changed, and is now 0x1fffff instead of 0x1f0fff, and unless you are using an updated definition for Vista and Server 2008, using PROCESS_ALL_ACCESS will request the incorrect rights, and you won't get the results you want. If you redefine PROCESS_ALL_ACCESS or use 0x1fffff in the call to OpenProcess instead of 0x1f0fff, your code will now work.

  9. #9
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    It's just that many people here are mostly unfamiliar with Vista, it seems.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  10. #10
    Registered User
    Join Date
    Mar 2005
    Location
    Mountaintop, Pa
    Posts
    1,058
    If
    you redefine PROCESS_ALL_ACCESS or use 0x1fffff in the call to OpenProcess instead of 0x1f0fff, your code will now work.
    The suggestion didn't work for me on Vista Enterprise. Out of curiosity, I tried it on XP Pro and it does work.

  11. #11
    Registered User
    Join Date
    May 2008
    Posts
    2

    Worked for me on Vista Ultimate, but...

    according to the MSN docs, using PROCESS_ALL_ACCESS isn't recommended procedure on Vista anyway (you should request only those rights you specifically need to do what you're going to do, piped together of course), which would allow you to accomplish much the same task, although slightly more verbose, definitely works. I got the information from
    http://msdn.microsoft.com/en-us/libr...80(VS.85).aspx
    in case anyone cares to read up on it more, but remember, you still can't gain certain rights when trying to use OpenProcess on protected processes anyway. Regardless, I just wanted to share what worked for me, as the issue had been bugging me and I could not find the answer in any easily searchable location, so I hope this helps somebody at least.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Getting an error with OpenGL: collect2: ld returned 1 exit status
    By Lorgon Jortle in forum C++ Programming
    Replies: 6
    Last Post: 05-08-2009, 08:18 PM
  2. An error is driving me nuts!
    By ulillillia in forum C Programming
    Replies: 5
    Last Post: 04-04-2009, 09:15 PM
  3. Making C DLL using MSVC++ 2005
    By chico1st in forum C Programming
    Replies: 26
    Last Post: 05-28-2008, 01:17 PM
  4. Connecting to a mysql server and querying problem
    By Diod in forum C++ Programming
    Replies: 8
    Last Post: 02-13-2006, 10:33 AM
  5. Couple C questions :)
    By Divx in forum C Programming
    Replies: 5
    Last Post: 01-28-2003, 01:10 AM