Access Violation using ReadProcessMemory to get a string value - c++

I'm new to reverse engineering, and quite new to C++. I'm trying to collect a player's character name in a game using ReadProcessMemory() from the Win32 API, but it throws an exception whenever I try to read it:
if (procId != NULL) {
hprocess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, procId);
ModuleBase = getModuleBaseAddr(procId, "ac_client.exe");
localPlayerptr = ModuleBase + 0x10f4f4;
healthaddr = findDMAaddy(hprocess, localPlayerptr, { 0xf8 });
//load to entitylist Array
ReadProcessMemory(hprocess, (BYTE*)localPlayerptr, &Entitylist[0], sizeof(Entitylist[0]), 0);
for (int i = 1; i < 10; ++i) {
ReadProcessMemory(hprocess, (BYTE*)ModuleBase + 0x10f4f8, &Entitylist[i], sizeof(Entitylist[i]), 0);
ReadProcessMemory(hprocess,(BYTE*) Entitylist[i]+(i*4), &Entitylist[i], sizeof(Entitylist[i]), 0);
std::cout << std::hex << Entitylist[i] << std::endl;
uintptr_t nameaddres;
std::string name;
nameaddres = Entitylist[i] + 0x225;
//ReadProcessMemory(hprocess, (BYTE*)nameaddres, &name, sizeof(name), 0);
/*--> ** This is where I have a problem. ***/
std::cout << name << std::endl;
}

First, you need to determine whether the string you want to read is a wide-byte (wchar) or multi-byte (char) version, then you could use std::string/char* or std::wstring/wchar_t*.
Second, do not use sizeof(std::string), you need to determine the length of the string you want to read.
For wide-byte:
&(std::string)name is not a writable address, as comments pointed out, you could use a wchat_t array instead:
wchat_t name[100];
BOOL ret = ReadProcessMemory(hprocess, (BYTE*)nameaddres, name, sizeof(name), 0);
Or you could use &name[0](From #Remy):
std::wstring name;
name.reserve(100);
BOOL ret = ReadProcessMemory(hprocess, (BYTE*)nameaddres, &name[0], 100*sizeof(wchar_t), 0);
std::wcout << name << std::endl;
Then, std::cout is not available for the wchar_t*, it only prints the address value. It is a local variable in the for loop, so it will reallocate the address every time comes in. Due to certain rules, the system may prefer to choose the same address, so you've got the same address value.
Use the std::wcout << name to out put the wchar_t string, and If the output is always only one character, then you may consider using the multi-byte version to read memory.

Related

why can i assign a raw string value but not a variable? [duplicate]

This question already has answers here:
What is the datatype of string literal in C++?
(2 answers)
Closed 7 months ago.
I followed a tutorial on youtube to develop a program in c++ to send a short message over a serialport and listen for a response. I am using the Serialport library(not the default c++ one, an external one) (https://github.com/greiman/SerialPort/blob/master/SerialPort/SerialPort.h). The program in the video uses the port 10 to communicate, but I want the user to be able to enter a specific port which the program then uses to communicate. But i'm struggling with the assignment of a variable. The library has a class called Serialport, that takes a char pointer as a parameter like so:
char* port;
SerialPort arduino(port);
The guy in the video then gives the char pointer the value of a String, like so:
char* port = "\\\\.\\COM10";
and then the code works flawlessly. Which I find odd for several reasons.
First of all, "port" is a pointer, so shoulnd't it be pointing to some other value? like so:
char port1 = 'a';
char* port2 = port1;
second of all, why does he use a char pointer to point to a string? and why does that work?
i've tried using a variable instead of assigning the value to the pointer directly, so that the user can enter the port they want to use, like so:
string portone;
cout << "specify port: " << endl;
cin >> portone;
string porttwo = "\\\\.\\COM" + portone;
port = porttwo;
But then vs studio tells me "there is no suitable conversion function from string to char".
so, in conclusion i'm asking:
why does this:
char* port = "\\\\.\\COM10";
work, but this:
string portone = "\\\\.\\COM10";
char* porttwo = portone;
does not.
And is there any way to assign a variable value to the char pointer to let the user specify the port?
my entire code:
#include<iostream>
#include<string>
#include<stdlib.h>
using namespace std;
#include"SerialPort.h"
char output[MAX_DATA_LENGTH];
char incomingData[MAX_DATA_LENGTH];
// change the name of the port with the port name of your computer
// must remember that the backslashes are essential so do not remove them
char* port;
int main() {
string data;
string portone;
cout << "Escribi el port: " << endl;
cin >> portone;
string porttwo = "\\\\.\\COM" + portone;
port = porttwo;
SerialPort arduino(port);
if (arduino.isConnected()) {
cout << "Conectado" << endl << endl;
}
else {
cout << "Puerto 10 vacio" << endl << endl;
}
if (arduino.isConnected()) {
cout << "Escribi el string: " << endl;
cin >> data;
char* charArray = new char[data.size() + 1];
copy(data.begin(), data.end(), charArray);
charArray[data.size()] = '\n';
arduino.writeSerialPort(charArray, MAX_DATA_LENGTH);
arduino.readSerialPort(output, MAX_DATA_LENGTH);
cout << "Respuesta: " << output << endl;
delete[] charArray;
}
cout << "Terminado" << endl << endl;
system("PAUSE");
return 0;
}
serialport class:
#include "SerialPort.h"
SerialPort::SerialPort(char *portName)
{
this->connected = false;
this->handler = CreateFileA(static_cast<LPCSTR>(portName),
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (this->handler == INVALID_HANDLE_VALUE){
if (GetLastError() == ERROR_FILE_NOT_FOUND){
printf("ERROR: Handle was not attached. Reason: %s not available\n", portName);
}
else
{
printf("ERROR!!!");
}
}
else {
DCB dcbSerialParameters = {0};
if (!GetCommState(this->handler, &dcbSerialParameters)) {
printf("failed to get current serial parameters");
}
else {
dcbSerialParameters.BaudRate = CBR_9600;
dcbSerialParameters.ByteSize = 8;
dcbSerialParameters.StopBits = ONESTOPBIT;
dcbSerialParameters.Parity = NOPARITY;
dcbSerialParameters.fDtrControl = DTR_CONTROL_ENABLE;
if (!SetCommState(handler, &dcbSerialParameters))
{
printf("ALERT: could not set Serial port parameters\n");
}
else {
this->connected = true;
PurgeComm(this->handler, PURGE_RXCLEAR | PURGE_TXCLEAR);
Sleep(ARDUINO_WAIT_TIME);
}
}
}
}
SerialPort::~SerialPort()
{
if (this->connected){
this->connected = false;
CloseHandle(this->handler);
}
}
int SerialPort::readSerialPort(char *buffer, unsigned int buf_size)
{
DWORD bytesRead;
unsigned int toRead = 0;
ClearCommError(this->handler, &this->errors, &this->status);
if (this->status.cbInQue > 0){
if (this->status.cbInQue > buf_size){
toRead = buf_size;
}
else toRead = this->status.cbInQue;
}
if (ReadFile(this->handler, buffer, toRead, &bytesRead, NULL)) return bytesRead;
return 0;
}
bool SerialPort::writeSerialPort(char *buffer, unsigned int buf_size)
{
DWORD bytesSend;
if (!WriteFile(this->handler, (void*) buffer, buf_size, &bytesSend, 0)){
ClearCommError(this->handler, &this->errors, &this->status);
return false;
}
else return true;
}
bool SerialPort::isConnected()
{
return this->connected;
}
links:
youtube vid: https://www.youtube.com/watch?v=8BWjyZxGr5o
serialport.h: https://github.com/greiman/SerialPort/blob/master/SerialPort/SerialPort.h
char* port = "\\\\.\\COM10";
and then the code works flawlessly. Which I find odd for several reasons.
First of all, "port" is a pointer, so shoulnd't it be pointing to some other value? like so:
char port1 = 'a';
char* port2 = port1;
char *port = "whatever";
is creating a variable (named port) that points at a value (the characters you put inside the quotes). It's basically telling the compiler to store the string you specified somewhere in memory (but we don't care much exactly where), then create a variable (named port, in this case) holding its address.
As far as your second example goes, yes, you could create a pointer referring to the value in some other variable, but you need one minor change. A pointer holds an address, so you need to take the address of that variable, so your example would work more like this:
char port1 = 'a';
char *port2 = &port1;
Note, however, that the name of an array normally evaluates to the address of the beginning of the array, so in this case we don't need to use the address-of operator (we just get the address by default):
static char portCharacters[] = "\\\\.\\COM10";
char *port1 = portCharacters;
This is almost the same as the first example you gave. The minor difference is that in this case we've given a name directly to the storage where the characters are stored, and also to a pointer to that location.
A couple other points worth noting here:
in C it's pretty routine to assume that a char * will point at a NUL-terminated string. That is, that it'll point to the beginning of an array of characters with a '\0' byte signalling the end of the array. That's not necessarily the case with the char *port1 = &port2; case, so we have to be kind of careful with it, to assure against accidentally trying to use it like a string, when it's really only referring to a single character.
In current C++, you can't actually do char *a = "foo";. You need to use char const *a = "foo"; (or, equivalently) const char *a = "foo";. This doesn't really change anything materially--trying to modify a string literal gives undefined behavior, and will often fail (e.g., get your program killed). But by requiring the const there, a modern compiler will enforce this by stopping your code from compiling if you try to modify a string literal (though if you insist, you can bypass that).

dereferencing causes crash, even for non-NULL pointer, why?

I tried to scan the whole process, but it crashed. I do not understand why that happened. What's another equivalent but safer way to do so?
void searchAddrByValue(const int value) {
int *p = (int *)0x00FFFFFF;
while ((int *)0x0FFFFFFF >= p) {
if(value == *p)
fprintf(filePointer, "Addr:%p -- Val:%d\n", p, *p);
++p;
}
display(L"Finished");
}
If you want to search all memory inside your process, you should first use VirtualQueryEx to find out which pages are valid addresses, and then search inside readable pages.
The MSDN article on Managing Virtual Memory outlines how to walk the address ranges in your process address space.
To loop through all properly allocated memory you can use VirtualQueryEx, ensure the region's state is MEM_COMMIT and the protection is not PAGE_NOACCESS, before doing anything else. If you want to ReadProcessMemory() each region into a local buffer you can certainly do that, just replace the console output in this code with the code you want to execute on each region:
MEMORY_BASIC_INFORMATION meminfo;
unsigned char* addr = 0;
HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());
MEMORY_BASIC_INFORMATION mbi;
while (VirtualQueryEx(hProc, addr, &mbi, sizeof(mbi)))
{
if (mbi.State == MEM_COMMIT && mbi.Protect != PAGE_NOACCESS)
{
std::cout << "base : 0x" << std::hex << mbi.BaseAddress << " end : 0x" << std::hex << (uintptr_t)mbi.BaseAddress + mbi.RegionSize << "\n";
}
addr += mbi.RegionSize;
}
CloseHandle(hProc);
This code will print out the start and end address of each region
Make sure you run as admin and you may also want to check for PAGE_GUARD as well, but I haven't run into that being a problem.

Get value from registry C++ crashes

What's wrong? It crashes when I want to get value of AUVersion. This key exists in registry but I can't get it.
int main(int argc, char *argv[])
{
HKEY key;
if (RegOpenKey(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\JavaSoft\\Auto Update\\"), &key) != ERROR_SUCCESS)
{
cout << "Unable to open registry key\n\n";
}
char path[1024];
DWORD value_length = 1024;
//here is the crash
RegQueryValueEx(key, "AUVersion", NULL, (LPDWORD)REG_SZ, (LPBYTE)&path, &value_length);
cout << "the value read from the registry is: " << path << endl;
system("pause");
return 0;
}
That fourth parameter is an LPDWORD -- a pointer to a DWORD. You took a regular integer and cast it to a pointer, which (when dereferenced) will crash.
That parameter receives the type of the registry value. Set it to NULL if you are not interested in knowing the type.
There are two errors with the call to RegQueryValueEx():
the type parameter is written to so must be a valid address, and this is not:
(LPDWORD)REG_SZ
and this is the probable cause of the crash.
&path should be path
Change to:
DWORD type;
RegQueryValueEx(key, "AUVersion", NULL, &type, (LPBYTE) path, &value_length);
You must check the result of RegQueryValueEx() to ensure path has been populated and subsequent code is not processing an unitialized variable:
const DWORD result = RegQueryValueEx(key,
"AUVersion",
NULL,
&type,
(LPBYTE) path,
&value_length);
// Check status of the query and ensure it was a string
// that was read.
if (ERROR_SUCCESS == result && REG_SZ == type)
{
// Success.
}

Converting LPBYTE into String

I'm querying data from the registry and it's being outputted as LPBYTE, and this is where i'm stuck. I need to convert the LPBYTE into a type of data that I can manipulate such as a String.
This is my code so far
HKEY hk;
string poolID;
DWORD dwSize = 0;
DWORD dwDataType = 0;
DWORD dwValue;
LPBYTE lpValue = NULL;
CA2W registryLocation("Software\\Example");
// Check registry if exists, otherwise create.
LONG openReg = RegOpenKeyEx(HKEY_CURRENT_USER, registryLocation, 0, KEY_QUERY_VALUE, &hk);
if (openReg==ERROR_SUCCESS) { } else { cout << "Error (Could not open/create Registry Location)\n"; }
// Get buffer size
LONG getRegBuf = RegQueryValueExA(hk, "", 0, &dwDataType, lpValue, &dwSize);
if (getRegBuf==ERROR_SUCCESS) { cout << "Got reg key buf size\n"; } else { cout << "Error (registry key does not exist)/n"; intro(); }
lpValue = (LPBYTE)malloc(dwSize);
// Open reg value
LONG getReg = RegQueryValueExA(hk, "", 0, &dwDataType, (LPBYTE)&dwValue, &dwSize);
if (getReg==ERROR_SUCCESS) { cout << "Successful\n"; } else { cout << "Error\n"; }
cout << dwValue;
Any help or code examples will be much appreciated.
You need to declare lpValue to be char*.
char* lpValue;
Then allocate it with a call to new.
lpValue = new char[dwSize+1];
Allocate an extra element in case the registry data is mal-formed and is missing a null-terminator. That is something that can happen. Then set the last element to \0:
lpValue[dwSize] = '\0';
Then get the value:
LONG getReg = RegQueryValueExA(..., (LPBYTE)&dwValue, ...);
Deallocate using delete[]:
delete[] lpValue;

Memory leak when read from file

I'm trying to read data from XML file and store every element ("< some data/>") in vector container vector<TCHAR*> , why the Task Manager shows the memory usage much greater than vector size(~80mb instead of ~59mb) :
#define _UNICODE
#include<tchar.h>
#include<iostream>
#include<windows.h>
#include<vector>
using namespace std;
HANDLE hFile;
HANDLE hThread;
vector<TCHAR*> tokens;
DWORD tokensSize;
DWORD WINAPI Thread(LPVOID lpVoid);
void main()
{
tokensSize = 0;
hFile = CreateFile("db.xml",GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if(hFile == INVALID_HANDLE_VALUE) {
cout<<"CreateFile Error # "<<GetLastError()<<endl;
}
DWORD fileSize = GetFileSize(hFile,NULL);
cout<<"fileSize = "<<fileSize<<" bytes = "<<fileSize/1024/1024<<" mb"<<endl;
TCHAR* buffer = new TCHAR[fileSize / sizeof(TCHAR) + 1];
ZeroMemory(buffer,fileSize);
DWORD bytesRead;
if(!ReadFile(hFile,buffer,fileSize,&bytesRead,NULL)){
cout<<"ReadFile Error # "<<GetLastError()<<endl;
}
CloseHandle(hFile);
hThread = CreateThread(NULL,0,Thread,(LPVOID)buffer,0,NULL);
WaitForSingleObject(hThread,INFINITE);
for(int i=0;i<tokens.size();i++)
tokensSize+=(_tcslen(tokens[i])+1)*sizeof(TCHAR);
cout<<"vector size = "<<tokensSize<<" bytes = "<<tokensSize/1024/1024<<" mb"<<endl;
cin.get();
}
DWORD WINAPI Thread(LPVOID lpVoid)
{
wstring entireDB = (TCHAR*)lpVoid;
delete[]lpVoid;
wstring currentElement;
wstring::size_type lastPos = 0;
wstring::size_type next;
next = entireDB.find(_T(">"),lastPos);
TCHAR* szStr;
do
{
currentElement = entireDB.substr(lastPos,next+1-lastPos);
szStr = new TCHAR[currentElement.length()+1];
_tcscpy(szStr,currentElement.c_str());
tokens.push_back(szStr);
lastPos = next+1;
next = entireDB.find(_T(">"),lastPos);
}
while(next != wstring::npos);
entireDB.clear();
return 0;
}
OUTPUT:~
fileSize = 57mb
vectorSize = 58mb
but the TaskManager shows ~ 81mb.
What am I doing wrong?
THNX!
First, as Aesthete as pointed out, you never clear the token vector once you're finished with it. This should be done, or change the token vector to utilize self-cleaning content like std::string or std::wstring.
Which brings me to the side-by-side below. Please review this against your existing code. There are a number of changes you'll want to compare. The one you will likely not see until you cmopile+run is the memory footprint difference, which may surprise you.
Major Changes
Global tokens is now a vector of std::wstring rather than raw wchar_t pointers
Uses MultiByteToWideChar to translate the input file.
Allocates a std::wstring dynamically as the thread parameter. This removes one full copy of the file image. The thread is responsible for deleteing the wstring once finished parsing the content.
Uses _beginthreadex() for starting the thread. The fundamental reason for this is because of the C/C++ runtime usage. In the past the runtime sets up various thread-local-storage that must be properly cleaned, and are so when using _beginthreadex(). It is almost identical to CreateThread(), but honestly I look forward to the day when MS has their stuff together and gives us std::thread officially like the rest of the civilized world.
Minor/Meaningless Changes
Global variables are brought to local scope where appropriate. this means the only real global now is the tokens vector.
The thread procedure now pushes substrings straight to the tokens vector.
uses argv[1] for the filename (easy to debug that way, no other special reason). can be changed back to your hard-coded filename as needed.
I hope this gives you some ideas on cleaning this up, and more importantly, how yoy can do almost the entire task you're given without having to go new and delete nuts.
Notes: this does NOT check the input file for a byte-order-mark. I'm taking it on faith that your claim it is UTF8 is straight-up and doesn't have a BOM at the file beginning. If your input file does have a BOM, you need to adjust the code that reads the file in to account for this.
#include <windows.h>
#include <tchar.h>
#include <process.h>
#include <iostream>
#include <vector>
#include <string>
using namespace std;
// global map of tokens
vector<wstring> tokens;
// format required by _beginthreadex()
unsigned int _stdcall ThreadProc(void *p);
int main(int argc, char *argv[])
{
HANDLE hThread = NULL;
std::string xml;
std::wstring* pwstr = NULL;
// check early exit
if (argc != 2)
{
cout << "Usage: " << argv[0] << " filename" << endl;
return EXIT_FAILURE;
}
// use runtime library for reading the file content. the WIN32 CreateFile
// API is required for some things, but not for general file ops.
HANDLE hFile = CreateFileA(argv[1], GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile != INVALID_HANDLE_VALUE)
{
DWORD dwFileSize = GetFileSize(hFile, NULL);
if (dwFileSize > 0)
{
// allocate a string large enough for the whole file.
std::string xml(dwFileSize, 0);
DWORD bytesRead = 0;
if (ReadFile(hFile, &xml.at(0), dwFileSize, &bytesRead, NULL) && (bytesRead == dwFileSize))
{
// invoke MB2WC to determine wide-char requirements
int ires = MultiByteToWideChar(CP_UTF8, 0, xml.c_str(), -1, NULL, 0);
if (ires > 0)
{
// allocate a wstring for our thread parameter.
pwstr = new wstring(ires, 0);
MultiByteToWideChar(CP_UTF8, 0, xml.c_str(), -1, &pwstr->at(0), ires);
// launch thread. it own the wstring we're sending, including cleanup.
hThread = (HANDLE)_beginthreadex(NULL, 0, ThreadProc, pwstr, 0, NULL);
}
}
}
// release the file handle
CloseHandle(hFile);
}
// wait for potential thread
if (hThread != NULL)
{
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
}
// report space taken by tokens
size_t tokensSize = 0;
for (vector<wstring>::const_iterator it = tokens.begin(); it != tokens.end(); ++it)
tokensSize += it->size()+1;
cout << "tokens count = " << tokens.size() << endl
<< "tokens size = "<< tokensSize <<" bytes" << endl;
cin.get();
}
// our thread parameter is a dynamic-allocated wstring.
unsigned int _stdcall ThreadProc(void *p)
{
// early exit on null insertion
if (p == NULL)
return EXIT_FAILURE;
// use string passed to us.
wstring* pEntireDB = static_cast<wstring*>(p);
wstring::size_type last = 0;
wstring::size_type next = pEntireDB->find(L'>',last);
while(next != wstring::npos)
{
tokens.push_back(pEntireDB->substr(last, next-last+1));
last = next+1;
next = pEntireDB->find(L'>', last);
}
// delete the wstring (no longer needed)
delete pEntireDB;
return EXIT_SUCCESS;
}
You allocate memory here, in the do-while loop:
szStr = new TCHAR[currentElement.length()+1];
And you never release it with the delete operator