ReadProcessMemory - Adding 5 Offsets to a Pointer - c++

Now, I know questions similar to this may have been asked before, and trust me, for the past couple days I've been looking around the internet for an already-answered situation, however I still can't get this to work and to be honest, not sure why it isn't working. What I am attempting to do is get the ammo value in a game. readMemory, which is an int, is supposed to contain this value, however it's simply outputting 0.
ReadProcessMemory(handle, (PBYTE*)(base_adr), &pAddress1, sizeof(pAddress1), 0);
ReadProcessMemory(handle, (PBYTE*)(pAddress1 + offset_1), &pAddress2, sizeof(pAddress2), 0);
ReadProcessMemory(handle, (PBYTE*)(pAddress2 + offset_2), &pAddress3, sizeof(pAddress3), 0);
ReadProcessMemory(handle, (PBYTE*)(pAddress3 + offset_3), &pAddress4, sizeof(pAddress4), 0);
ReadProcessMemory(handle, (PBYTE*)(pAddress4 + offset_4), &pAddress5, sizeof(pAddress5), 0);
while (1)
{
ReadProcessMemory(handle, (PBYTE*)(pAddress5 + offset_5), &readMemory, sizeof(readMemory), 0);
cout << readMemory << endl;
}
Obviously, this isn't an efficient way of adding the pointers (nor is it a working way, I guess), and I'm looking for someone who can point me into the right direction. Thanks, and once again sorry for the (most likely in your eyes) a basic question.
DWORD base_adr = 0xCC8408;
const DWORD offset_1 = 0x23C;
const DWORD offset_2 = 0x7A4;
const DWORD offset_3 = 0x34C;
const DWORD offset_4 = 0x5B0;
const DWORD offset_5 = 0x2D8;
DWORD pAddress1;
DWORD pAddress2;
DWORD pAddress3;
DWORD pAddress4;
DWORD pAddress5;

Reading the MSDN article on function ReadProcessMemory the first thing I notice is this:
The entire area to be read must be accessible or the operation fails.
First thing I'd suggest is you check the return value of those calls. I'm pretty sure they all return 0 for "failed" so next thing you do is you call GetLastError to find out why exactly did it fail.
Once you figure that out you'll be able to fix it. More likely than not the problem is that your program doesn't have sufficient privileges to access another process's memory.
Quick search pops this OS article on how to properly access other process's memory: How is it possible to access memory of other processes?

Related

Reading Memory from Another Process in C++ | Copilot's Solution

As the title suggests, I am trying to read memory from another process in C++ in order to check if the values from the other process reach a certain level. Since I don't know anything about this, I decided to consult GitHub Copilot for help. On a normal basis, I would search the docs, but Github seems to disagree. Since I have access to GitHub Copilot, and since the front page advertisement clearly encourages users to trust Copilot's programming ability, I chose to let Copilot make this function.
So I gave it a prompt in the form of a comment: //A function that can grab an address from the memory of another process and store it as a double value
What it gave me seemed pretty good, but I will never take a function that copilot makes and blindly use it unless I know for sure it will work (because I don't trust that everything Copilot makes is never going to cause issues, especially when dealing with pointers and such). I wanted to see if someone who had experience with memory in C++ could tell me if this function will work and why it would or wouldn't work as I know nothing about getting memory from another process.
There are three main reasons why I am not just searching the docs anyway despite GitHub's statement:
Since this is a complicated and real-world use case, this will really test Copilot's programming ability and it will give me insight into how much I can trust Copilot in the future for stuff I don't know how to do (Obviously I wouldn't let this get out of hand, but it would be good to know I can trust Copilot a little more than I do right now).
Searching the docs anyways despite the statement that GitHub made on their website is quite the opposite of what Copilot is supposed to help users with, and while I understand that it's a public beta and it's not complete yet, it should at least be good enough for real-world use cases rather than simple coding cases. An answer from someone experienced will really show if it is good enough for real-world coding cases.
The docs only tell me what a function does and what to put as its parameters, it doesn't tell me how to use it. If I really wanted to know how to use it, I would have to search the web. Searching the web will most likely get me complicated examples that don't pertain to my issue and defer me from what I am actually trying to accomplish. Not only that, but it is the opposite of what Copilot is supposed to help users with, as stated in reason #2.
Here is the code that Copilot generated for me:
DWORD GetAddress(DWORD dwProcessId, LPCWSTR szModuleName, const char* szProcName)
{
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
if (hProcess == NULL)
return 0;
MODULEINFO modinfo;
GetModuleInformation(hProcess, GetModuleHandle(szModuleName), &modinfo, sizeof(MODULEINFO));
DWORD dwAddress = (DWORD)modinfo.lpBaseOfDll;
DWORD dwSize = (DWORD)modinfo.SizeOfImage;
MEMORY_BASIC_INFORMATION mbi;
while (dwSize > 0)
{
VirtualQueryEx(hProcess, (LPVOID)dwAddress, &mbi, sizeof(mbi));
if (mbi.State == MEM_COMMIT && !(mbi.Protect & PAGE_GUARD) && mbi.Protect & PAGE_EXECUTE_READWRITE)
{
DWORD dwOldProtect;
VirtualProtectEx(hProcess, (LPVOID)dwAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, &dwOldProtect);
char* szBuffer = new char[mbi.RegionSize];
ReadProcessMemory(hProcess, (LPVOID)dwAddress, szBuffer, mbi.RegionSize, NULL);
for (DWORD dwIndex = 0; dwIndex < mbi.RegionSize - 4; dwIndex++)
{
if (szBuffer[dwIndex] == '\x55' && szBuffer[dwIndex + 1] == '\x8B' && szBuffer[dwIndex + 2] == 'E' && szBuffer[dwIndex + 3] == 'A')
{
DWORD dwAddress2 = dwAddress + dwIndex + 7;
DWORD dwAddress3 = dwAddress2 + *(DWORD*)(dwAddress2);
if (strcmp((char*)dwAddress3, szProcName) == 0)
{
delete[] szBuffer;
CloseHandle(hProcess);
return dwAddress2 + 4;
}
}
}
delete[] szBuffer;
VirtualProtectEx(hProcess, (LPVOID)dwAddress, mbi.RegionSize, dwOldProtect, &dwOldProtect);
}
dwAddress += mbi.RegionSize;
dwSize -= mbi.RegionSize;
}
CloseHandle(hProcess);
return 0;
}
You may point out an immediately noticeable error: The function returns DWORD rather than double, which is what I asked Copilot to return. I saw that error but from examples that I have seen (Yes, I have done at least some searching), returning DWORD works as well. I could have seen those examples wrong, and if I am correct me.
The function returns double but it only returns the value that is stored in the memory, not actually double-typed data. If you do a casting to double, you get back your original data.
You can't search in memory with anything other than a byte pointer on 64-bit systems: http://msdn.microsoft.com/en-us/library/aa746449%28v=vs.85%29.aspx
There are different ways to search for a string in memory, depending on what you are looking for: http://www.catatonicsoft.com/blog/need-to-read-and-write-strings-and-data-in-a-processs-memory/
(Read more here: https://github.com/MicrosoftArchiveOrgMember/copilot)
Memory Scraper
This program uses several techniques to obtain information from processes and memory as it runs so that it can be added to the evidence file when Cofactor terminates the target process (by default) or when you terminate the program manually (with CTRL+C).
This code was mostly cobbled together from various examples at http://www.codeproject.com and https://forums.hak5.org, with some heavy modifications made to get the output in a useful format.
The process memory usage is checked continuously and added to the log file when it changes. This is done by getting a pointer to the process' memory region, then checking all of its pages as they are referenced. When they are changed, the contents of that page will be read and added to the log file as evidence. If a process goes in and out of sleep mode or is stopped for some other reason, this program will detect that and add it to the log file accordingly.
The current DLLs loaded by processes are recorded every 5 seconds so that if a DLL gets loaded after Cofactor terminates its target, it will still be included in the log file as evidence. A process is also checked every 5 seconds for new threads being spawned so that child processes are also included in our evidence files.
We could extend this program by having it check for two modules:
1) A module containing functions that correspond to debug breakpoints (which would detect whether a debugger was attached).
2) A module containing crash signatures - integers that would trigger an alert if they were found written to memory in any of our processes (like stack smashing protections might provide).
In order to do this without complicating things too much, I'd probably use CreateRemoteThread with an address within each module to continue execution from that thread into your own code where you can check for the breakpoint or crash signature and act accordingly.
Conclusion
If you need to debug a process and can't get it to stop for any reason, this program will still be able to grab the process memory at any time so that you can search for whatever you need.
You'll have to do some extra work in order to use the log file that is created, like parsing it with a parser of your choice and searching it (using regexes or something) which I assume is outside of the scope of what Copilot is designed to do.
If you end up using this program, please let me know! I'm curious to see how many people find this program useful.
Interesting Techniques I Learned From Other Programs
Finding DLLs Loaded by a Process
The C++ code below uses the Windows API GetModuleFileNameW() to get the full path of loaded DLLs and parses it with split() to extract just the filename and not the whole path. The rest of that code just tries to avoid duplicates while being simple enough that it doesn't get too confused between different processes and file system cases (hopefully).
// Code Example: Finding DLLs Loaded by a Process
#include <stdio.h>
#include <string.h>
#include <tchar.h>
#define BUFF_SIZE 200
// Find the full path to a loaded DLL by process ID (PID) and its filename (first 8 characters)
void GetModuleFileNameEx(int pid, const char* szName, char* buff, int buffSize)
{
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
if (hProcess == NULL) { return; }
HMODULE hMods[1024];
DWORD cbNeeded;
if (!EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded)) { return; }
for (int i = 0; i < (int)(cbNeeded / sizeof(HMODULE)); i++) {
TCHAR szModName[MAX_PATH];
if (!GetModuleFileNameEx(hProcess, hMods[i], szModName, sizeof(szModName))) { continue; }
strcat_s((char*)buff, buffSize - 1 , (char*)szModName);
// Check if the first 8 characters of the filename in the process matches
// with what we are looking for and avoid adding duplicates
char* chPtr = strchr((char*)buff, '\\');
if (chPtr != NULL) {
*chPtr = 0;
strcat_s((char*)buff, buffSize - 1 , "\\");
strcat_s((char*)buff, buffSize - 1 , szName);
HANDLE hFile = CreateFileA((LPCSTR)buff, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (hFile != INVALID_HANDLE_VALUE) { CloseHandle(hFile); return; }
} else { break; }
}
}
int main() {
char szDllName[8]; // Maximum length of a module name is MAXPATH - 1 bytes including the NULL terminator. However we only need 8 characters to store the DLL name so use this limit to save memory.
int pid; scanf("%d", &pid);
if (pid == 0) { return 0; }
char buff[BUFF_SIZE];
GetModuleFileNameEx(pid, szDllName, buff, BUFF_SIZE);
char* chPtr = strchr(buff, '\\');
// Change the path separator character to a null terminator so we can split it
if (chPtr != NULL) { *chPtr = 0; }
chPtr = strtok(buff, "\\");
while (chPtr != NULL) {
printf("%s\n", chPtr);
chPtr = strtok(NULL, "\\");
}
return 0;
}

WriteProcessMemory with multiple Offsets C++

I have struggled with a very annoying problem lately with writing to Process memory in c++... I can not write to process memory with multiple offsets! Even though there are thousands of pages explaining how you fix this problem, it still seems to not work for me. I have been searching around on google all day long, and found many examples of how to fix this problem, but it still seems to not work for me.
So, let me first explain how I am writing to process memory myself, and you could possibly correct it afterwards.
Let us say I have a base address of: 0x04AF3C94
First offsets as: 0x1C
Second offsets as: 0x20
Third as: 0x568
And fourth as: 0x134
How I am doing this myself:
DWORD offset1 = 0x1C;
DWORD offset2 = 0x20;
DWORD offset3 = 0x568;
DWORD offset4 = 0x134;
DWORD base = 0x04AF3C94;
DWORD pointer;
DWORD pointer2;
DWORD pointer3;
DWORD pointer4;
DWORD pointer5;
ReadProcessMemory(handle, LPVOID(base), &pointer, sizeof(pointer), 0);
ReadProcessMemory(handle, LPVOID(pointer + offset1), &pointer2, sizeof(pointer2), 0);
ReadProcessMemory(handle, LPVOID(pointer2 + offset2), &pointer3, sizeof(pointer3), 0);
ReadProcessMemory(handle, LPVOID(pointer3 + offset3), &pointer4, sizeof(pointer4), 0);
ReadProcessMemory(handle, LPVOID(pointer4 + offset4), &pointer5, sizeof(pointer4), 0);
int value = 500;
WriteProcessMemory(handle, LPVOID(pointer5), &value, sizeof(value), 0);
As you can see, if I have 4 offsets such as in this example, I am adding every offset one at a time to the base address, until I got one value that stores every offset added to the baseaddress.
This apparently don't work, what should I do!?
I can't reply to all with your description, but in the MSDN they say that ReadProcessMemory read memory from where it is asked to the given buffer. It means when you call...
ReadProcessMemory(handle, LPVOID(base), &pointer, sizeof(pointer), 0);
...your "pointer" will be filled with what is at the "base" address. So it will contain an address that is numericaly the value of the four bytes at address "base". This is probably not what you want, because if you didn't stored something there before, it's indeterminate. And if so, it will probably crash when you use "pointer".
If you want to read the memory at adresse "base + offset1" with that function, what you have to do is:
ReadProcessMemory(handle, LPVOID(base + offset1), some_buffer, some_buffer_size, 0);
Where some_buffer is a valid buffer you have to declare somewhere.

Save the changes of ptrace() PTRACE_POKEDATA call

I'm using ptrace(PTRACE_POKETEXT, pid, addr, (orig ^ flip_mask)); in order to change a live process's data, but as soon as the call is terminated the changes that have been made disappear, would it be possible to keep the PTRACE_POKETEXT changes permanently even after terminating the ptrace call ?
void run_pro1 (pid_t child_pid) {
srand(time(0));
int wait_status;
unsigned icounter = 0;
procmsg("debugger started\n");
wait(&wait_status);
while (WIFSTOPPED(wait_status)) {
icounter++;
struct user_regs_struct regs;
ptrace(PTRACE_GETREGS, child_pid, 0, &regs);
unsigned instr = ptrace(PTRACE_PEEKTEXT, child_pid, regs.rax , 0);
unsigned *instr3 ;
instr3 = &instr;
unsigned instr2 = instr ^ (1UL << (1 << (rand()%32)));
ptrace(PTRACE_POKETEXT, child_pid, instr, instr2);
unsigned *instr4 ;
instr4 = &instr2;
cout<<"addrctn="<< *instr3 <<endl;
cout<<"addrctn="<< *instr4 <<endl;
if (ptrace(PTRACE_SINGLESTEP, child_pid, 0, 0) < 0) {
perror("ptrace");
return;
} /* Wait for child to stop on its next instruction */
ptrace(PTRACE_CONT, child_pid, 0, 0);
wait(&wait_status); //break;
}
procmsg("the child executed %u instructions\n", icounter);
}
Your main problem, I think, is that you are calling ptrace twice. The first time you pass it PTRACE_SINGLESTEP, which tells it to continue just one instruction. Immediately after, however, you call PTRACE_CONT, which tells it to continue until the next signal. The end result is that your program doesn't single step at all. It just runs.
There are a couple of secondary problems with your code. The first is that you are always calling these two functions with zero as the signal argument. Effectively, you are masking signals from the program.
Also, you are calling PEEK and POKE TEXT, and storing this in a variable called "instr". All of those don't make any difference, but they suggest you think you are dealing with instructions. The memory you read this from is from rax, which will rarely point at instructions, and might often not point at anything mapped at all. This, too, means you are probably doing something different than what you think you are doing, which is a probable cause of your problem.
The arguments to POKETEXT are wrong. The 3rd argument should be an address, but you gave instr, which is the old value, not the address from which it was read. To replace the value that you read, it should be:
ptrace(PTRACE_POKETEXT, child_pid, regs.rax, instr2);
Schachar Shemesh also has good points in his answer, but I think this addresses the specific problem you asked about.

Problems with pointers and memory adresses

I wonder why this code doesn't work:
#include <iostream>
using namespace std;
int main()
{
int *pointer = (int*)0x02F70BCC;
cout<<*pointer;
return 0;
}
In my opinion it should write on the screen value of 0x02F70BCC,
instead of this my programm crashes.
I know that memory with adress 0x02F70BCC stores value of 20.
But like I said no matter what it just doesn't want to show correct number.
Please help me guys, detailed explanation would be very nice of you.
It doesn't work, because you won't get access to every location in memory you want. Not every location in memory is valid, you may want to read about Virtual Address Space.
Some addresses are reserved for device drivers and kernel mode operations. Another range of addresses (for example 0xCCCCCCCC and higher) may be reserved for uninitialized pointers.
Even if some location is valid, operating system may still deny access to write to/read from certain location, if that would cause undefined behaviour or violate system safety.
EDIT
I think you might be interested in creating some kind of "GameHack", that allows you to modify amount of resources, number of units, experience level, attributes or anything.
Memory access is not a simple topic. Different OSes use different strategies to prevent security violations. But many thing can be done here, after all there is a lot software for doing such things.
First of all, do you really need to write your own tool? If you just want some cheating, use ArtMoney - it is a great memory editor, that I have been using for years.
But if you really have to write it manually, you need to do some research first.
On Windows, for example, I would start from these:
ReadProcessMemory
WriteProcessMemory
Also, I am quite certain, that one of possible techniques is to pretend, that you are a debugger:
DebugActiveProcess.
EDIT 2
I have done some research and it looks, that on Windows (I assume this is your platform, since you mentioned gaming; can't imagine playing anything on crappy Linux), steps required to write another process' memory are:
1. Enumerate processes: (EnumProcesses)
const size_t MAX_PROC_NUM = 512;
DWORD procIDs[MAX_PROC_NUM] = { 0 };
DWORD idsNum = 0;
if(!EnumProcesses(procIDs, sizeof(DWORD) * MAX_PROC_NUM, &idsNum))
//handle error here
idsNum /= sizeof(DWORD); //After EnumProcesses(), idsNum contains number of BYTES!
2. Open required process. (OpenProcess,GetModuleFileNameEx)
const char* game_exe_path = "E:\\Games\\Spellforce\\Spellforce.exe"; //Example
HANDLE game_proc_handle = nullptr;
DWORD proc_access = PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_VM_WRITE; //read & write memory, query info needed to get .exe name
const DWORD MAX_EXE_PATH_LEN = 1024;
for(DWORD n = 0 ; n < idsNum ; ++idsNum)
{
DWORD current_id = procIDs[n];
HANDLE current_handle = OpenProcess(proc_access, false, current_id);
if(!current_handle)
{
//handle error here
continue;
}
char current_path[MAX_EXE_PATH_LEN];
DWORD length = GetModuleFileNameEx(current_handle, nullptr, current_path, MAX_EXE_PATH_LEN);
if(length > 0)
{
if(strcmp(current_path, game_exe_path) == 0) //that's our game!
{
game_proc_handle = current_handle;
break;
}
}
CloseHandle(current_handle); //don't forget this!
}
if(!game_proc_handle)
//sorry, game not found
3. Write memory (WriteProcessMemory)
void* pointer = reinterpret_cast<void*>(0x02F70BCC);
int new_value = 5000; //value to be written
BOOL success = WriteProcessMemory(game_proc_handle, pointer, &new_value, sizeof(int), nullptr);
if(success)
//data successfully written!
else
//well, that's... em...
This code is written just 'as is', but I see no errors, so you can use it as your starting point. I also provided links for all functions I used, so with some additional research (if necessary), you can achieve what you are trying to.
Cheers.
When you use,
cout<<*pointer;
the program tries to dereference the value of the pointer and writes the value at the address.
If you want to print just the pointer, use:
cout << pointer;
Example:
int main()
{
int i = 20;
int* p = &i;
std::cout << *p << std::endl; // print the value stored at the address
// pointed to by p. In this case, it will
// print the value of i, which is 20
std::cout << p << std::endl; // print the address that p points to
// It will print the address of i.
}

C++ memory allocation for windows

So I'm reading Windows via c/c++ fifth edition which was released before c11 so lacks some of the newer data types and methods, but was touted to be a great book on Windows.
I am just learning Windows development and c++ and when I posted questions related to file operations with code samples from the book, I got feedback that allocating buffers with the malloc function is not a good practice anymore as it requires freeing up the memroy. I should use vectors or strings instead.
That is ok. But what is the case with Windows's own data types? Here is a code sample from the book:
//initialization omitted
BOOL bResult = GetLogicalProcessorInformation(pBuffer, &dwSize);
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
_tprintf(TEXT("Impossible to get processor information\n"));
return;
}
pBuffer = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)malloc(dwSize);
bResult = GetLogicalProcessorInformation(pBuffer, &dwSize);
Is there a better solution for this type of query than using malloc to allocate the proper amount of memory?
Or is declaring a vector of type PROCESOR INFORMATION STRUCTRUE the way to go?
The win32 api is sometimes a pain to use, but you could allways use the raw bytes in a std::vector<char> as a SYSTEM_LOGICAL_PROCESSOR_INFORMATION:
std::vector<char> buffer(sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION));
size_t buffersize = buffer.size();
SYSTEM_LOGICAL_PROCESSOR_INFORMATION *ptr
= (SYSTEM_LOGICAL_PROCESSOR_INFORMATION *)&(buffer[0]);
BOOL bResult = GetLogicalProcessorInformation(ptr, &buffersize);
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
buffer.resize(buffersize);
ptr = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION *)&(buffer[0]);
bResult = GetLogicalProcessorInformation(ptr, &buffersize);
}
Just be avare that the value of &(buffer[0]) may change after buffer.resize(...);
Other than that, I normally don't use the win32 api, so any bugs concerning how to call win32, you have to fix yourself
Take a look at the MSDN documentation and you will see that buffer should be "A pointer to a buffer that receives an array of SYSTEM_LOGICAL_PROCESSOR_INFORMATION structures. If the function fails, the contents of this buffer are undefined." So Zdeslav Vojkovic's answer will not work here (as Raymond Chen has pointed out). You could use std::vector<SYSTEM_LOGICAL_PROCESSOR_INFORMATION> in this case and then just call 'resize' with dwSize / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION) as the argument. This would look something like:
using SLPI = SYSTEM_LOGICAL_PROCESSOR_INFORMATION;
std::vector<SLPI> slpi;
DWORD dwSize = 0;
if (!GetLogicalProcessorInformation(slpi.data(), &dwSize))
{
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { /* error handling */ }
// Not really necessary, but good to make sure
assert(dwSize % sizeof(SLPI) == 0);
slpi.resize(dwSize / sizeof(SLPI));
if (!GetLogicalProcessorInformation(slpi.data(), &dwSize)) { /* error handling */ }
}
Personally, I'd prefer to wrap the above into a function and just return slpi so you don't need to go through this entire shenanigans every time you wish to make a call to GetLogicalProcessorInformation.