[C++][Windows] Acessing process address space

Questions about programming languages and debugging
Post Reply
User avatar
ayu
Staff
Staff
Posts: 8109
Joined: 27 Aug 2005, 16:00
18
Contact:

[C++][Windows] Acessing process address space

Post by ayu »

This thread is a part of another thread

Code: Select all

https://suck-oold.com/modules.php?name=Forums&file=viewtopic&t=8271
The reason I only wrote C++ in the subject is because some of the libraries used simply doesn't agree with a C compiler (I might have missed something though, nothing unusual).

This is the second time I write this thread. The first time I realized in the middle of it that the experiment had failed, and I had to research some more about it. Credits to IceDane who mentioned the existence of "ASLR", which proved to be the issue with the compiler, it seems that VC++ has that setting (/DYNAMICBASE) enabled per default to protect that address space of the applications compiled with it.

The purpose of the experiment was simply to write an application that creates a variable that holds some random value. Then write another application which purpose is to access to address space of the first application process, and read the variable value, output it, write something new to that address, and then output it again.

The reason for the experiment is that we have been talking a lot about address spaces at the university, and I wanted to play around with it some more to get a better hold of it, code wise that is. Another purpose of the experiment is to use this knowledge for my "lifeware" project.

Anyway, the first application, is rather simple

Code: Select all

#include <iostream>

using namespace std;

int var = 1234;

int main()
{
	while(1)
	{
		cout << var << endl;
		system("PAUSE");
	}

	return 0;
}
Now, compiling it and starting it will give it a PID (Process ID). We need that for the other application since it isn't written to discover the PID by itself, we also need to know the address of the variable value, OllyDBG or tsearch can be used for that rather easily.

Code: Select all

#include <windows.h>
#include <iostream>

//The address to read from
#define APP_VAR 0x013E301C
//The PID of the process we are reading from
#define APP_PID 4820

using namespace std;

BOOL EnablePriv(LPCWSTR, HANDLE*);

int main()
{
	HANDLE						hProcess;

	SIZE_T						stBytes			= 0;
	LPCVOID						memAddr			= 0;
	int							buff			= 0;
	int							vqRet			= 0;

	//Open the process specified by PID
	hProcess = OpenProcess(
							PROCESS_VM_READ | 
							PROCESS_VM_WRITE | 
							PROCESS_TERMINATE | 
							PROCESS_QUERY_INFORMATION |
							PROCESS_VM_OPERATION, 
							FALSE, 
							APP_PID); //Don't forget to change the PID!

	//Enable the SeDebugPrivilege privilege to get full access
	//Not needed in this experiment though
	//EnablePriv(SE_DEBUG_NAME, &hProcess);

	//Check if the process was opened without fail
	if(hProcess == NULL)
		cout << "ERROR: " << GetLastError() << "\n";
	else
	{
		cout << "Process was opened successfully\n";

		//Read memory and output result
		if(ReadProcessMemory(hProcess, (LPCVOID)APP_VAR, &buff, sizeof(buff), &stBytes))
			cout << "Read " << buff << " from 0x" << hex << APP_VAR << "\n";
		else
			cout << "ERROR: " << GetLastError() << "\n";


		//Set the value that is to be written
		buff = 5678;
		//Write memory and output result
		if(WriteProcessMemory(hProcess, (LPVOID)APP_VAR, &buff, sizeof(buff), &stBytes))
			cout << "Wrote " << dec << buff << " to 0x" << hex << APP_VAR << "\n"; 
		else
			cout << "ERROR: " << GetLastError() << "\n";
	}

	//Close the handle for the opened process
	CloseHandle(hProcess);

	system("PAUSE");
	return 0;
}
You'll notice that the "BOOL EnablePriv(LPCWSTR, HANDLE*);" function isn't included, this is because it was a part of the experiment at first, but it wasn't needed since debug privs weren't needed to access the test processes address space.

Anyway, here's that part as well, just in case

Code: Select all

//Change the token privileges for a process
BOOL EnablePriv(LPCWSTR privStr, HANDLE* hProcess)
{
	HANDLE				hToken;
	LUID				luid;
	TOKEN_PRIVILEGES	tPriv;

	if(!OpenProcessToken(hProcess, (TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY), &hToken))
		return false;

	if(!LookupPrivilegeValue(NULL, privStr, &luid))
	{
		CloseHandle(hToken);
		return false;
	}

	tPriv.PrivilegeCount			= 1;
	tPriv.Privileges[0].Luid		= luid;
	tPriv.Privileges[0].Attributes	= SE_PRIVILEGE_ENABLED;

	BOOL retVal = AdjustTokenPrivileges(hToken, FALSE, &tPriv, sizeof(tPriv), NULL, NULL);
	CloseHandle(hToken);

	return retVal;

}


The application that reads and writes to the memory, results in this

Image

And then the "simple" application results in this

Image


Due to the horrible way PHPBB2 handles code, it looks like shit. But if you want to study it, then you can simply copy/paste it.
Last edited by ayu on 11 Dec 2009, 10:09, edited 3 times in total.
"The best place to hide a tree, is in a forest"

User avatar
ayu
Staff
Staff
Posts: 8109
Joined: 27 Aug 2005, 16:00
18
Contact:

Post by ayu »

I noticed something interesting that is in need of some more investigation. The experiment only works on the debug version of the applications, not the release. Feels like yet another VC++ "feature" *sigh*.

Will come back to that when I have the answer, or if anyone else has an idea.
"The best place to hide a tree, is in a forest"

User avatar
IceDane
Fame ! Where are the chicks?!
Fame ! Where are the chicks?!
Posts: 197
Joined: 12 Aug 2009, 16:00
14

Post by IceDane »

cats wrote:I noticed something interesting that is in need of some more investigation. The experiment only works on the debug version of the applications, not the release. Feels like yet another VC++ "feature" *sigh*.

Will come back to that when I have the answer, or if anyone else has an idea.
It is because the debug config and the release config are two completely different ones. If you link an external library that you're using in debug, and then try to compile in release, you'll need to link it again in the release config.

Ultimately, linking something is just passing a flag with a parameter to compiler over the command line. Disabling the /DYNAMICBASE flag is the same thing, I assume. You just need to disable it in release again.

Code: Select all

//Change the token privileges for a process 
BOOL EnablePriv(LPCWSTR privStr, HANDLE* hProcess) 
{ 
   HANDLE            hToken; 
   LUID            luid; 
   TOKEN_PRIVILEGES   tPriv; 

   if(!OpenProcessToken(hProcess, (TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY), &hToken)) 
      return false; 

   if(!LookupPrivilegeValue(NULL, privStr, &luid)) 
   { 
      CloseHandle(hToken); 
      return false; 
   } 

   tPriv.PrivilegeCount         = 1; 
   tPriv.Privileges[0].Luid      = luid; 
   tPriv.Privileges[0].Attributes   = SE_PRIVILEGE_ENABLED; 

   BOOL retVal = AdjustTokenPrivileges(hToken, FALSE, &tPriv, sizeof(tPriv), NULL, NULL); 
   CloseHandle(hToken); 

   return retVal; 

}
Looking at the prototype for the OpenProcessToken function, I can see that it actually wants a HANDLE, not a pointer to a handle. You probably didn't notice it because you didn't need it, or something.

Here's one from my own DLL injection code. It's in C(E.g., no native bool type, but if it matters, you can modify it).

Code: Select all

int GetDebugPrivs(void)
{
     LUID               debugPrivLUID;         // LUID for debug privilege token
     HANDLE             ownHandle, tokHandle;  // Handle for this process and its token
     TOKEN_PRIVILEGES   tokPrivs;              // Struct used to set the privileges
     
     // Finds the LUID for the Debug privilege.
     if(!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &debugPrivLUID))
          return 0;
     
     ownHandle = OpenProcess(PROCESS_ALL_ACCESS, 0, GetCurrentProcessId());
     
     if(ownHandle == NULL)
          return 0;
     
     if(!OpenProcessToken(ownHandle, TOKEN_ADJUST_PRIVILEGES, &tokHandle))
          return 0;

     // Only one new privilege
     tokPrivs.PrivilegeCount           = 1;
     // We're enabling it
     tokPrivs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
     // And we're going after debug privileges
     tokPrivs.Privileges[0].Luid       = debugPrivLUID;
     
     // Adjust the privileges
     if(AdjustTokenPrivileges(tokHandle, 0, &tokPrivs, 0, 0, 0) == 0)
          return 0;

     // Clean up.
     CloseHandle(tokHandle);
     CloseHandle(ownHandle);
     return 1;
}

User avatar
ayu
Staff
Staff
Posts: 8109
Joined: 27 Aug 2005, 16:00
18
Contact:

Post by ayu »

Looks nice :D

Will take a look at the EnablePriv code again, I only used it a few times after I wrote it, but since I didn't need it in the first place it might be why I didn't notice any difference with it's functionality (assuming that it doesn't function correctly).

IceDane wrote: It is because the debug config and the release config are two completely different ones. If you link an external library that you're using in debug, and then try to compile in release, you'll need to link it again in the release config.

Ultimately, linking something is just passing a flag with a parameter to compiler over the command line. Disabling the /DYNAMICBASE flag is the same thing, I assume. You just need to disable it in release again.
hmm, well yeah I did change the release config as well, still didn't work though. Will have to take another look at that later. I dropped my toothbrush on the bathroom floor, and I couldn't get it up in under 5 seconds (the 5 second rule applies in the bathroom), so I need to run down the shop and get a new one before it closes : |
"The best place to hide a tree, is in a forest"

User avatar
ayu
Staff
Staff
Posts: 8109
Joined: 27 Aug 2005, 16:00
18
Contact:

Post by ayu »

Ok I found the error in the release config.

The following flag was set "/LTCG" (Link-time Code Generation)

By removing it, the release version worked perfectly as well :)


The exact cause will have to be the next little project ^^


Code: Select all

http://msdn.microsoft.com/en-us/library/xbf3tbeh%28VS.80%29.aspx
"The best place to hide a tree, is in a forest"

User avatar
IceDane
Fame ! Where are the chicks?!
Fame ! Where are the chicks?!
Posts: 197
Joined: 12 Aug 2009, 16:00
14

Post by IceDane »

cats wrote:Ok I found the error in the release config.

The following flag was set "/LTCG" (Link-time Code Generation)

By removing it, the release version worked perfectly as well :)


The exact cause will have to be the next little project ^^


Code: Select all

http://msdn.microsoft.com/en-us/library/xbf3tbeh%28VS.80%29.aspx
Ah, cool.

If you do start a project out, keep us updated. I like fucking around with the Windows API internals, and seeing what others are doing with it is fun.

User avatar
ayu
Staff
Staff
Posts: 8109
Joined: 27 Aug 2005, 16:00
18
Contact:

Post by ayu »

I changed this threads subject to .NET before, but I changed it back now. I misread the .NET API and thought that this was managed code that belonged there. I was wrong though (just discovered while I was reading on MSDN).

The process lister I wrote, however, belongs to .NET. Thus I will create a new example using the Tool Help library.
"The best place to hide a tree, is in a forest"

Post Reply