How to use WriteProcessMemory (WPM) to replace strings? - c++

I am trying to write a simple code to replace a string in a program by another using WPM and I am able to make it work, but only partly. This is part of the code I used to get the result.
string strWrite;
cin >> strWrite;
strWrite = strWrite + "\0";
if (WriteProcessMemory(hProcess, (LPVOID) reqdAddr, &strWrite[0], strWrite.size(), NULL) == false)
{
cout << "WriteProcessMemory failed. GetLastError = " << dec << GetLastError() << endl;
system("pause");
return EXIT_FAILURE;
}
When I try to replace the original string DefaultString with blabla, the result I get is blablatString. I have tried things like replacing strWrite.size() by strWrite.size() + 1 and realized that the result changes to blabla String. I need help replacing the entire string and not just the part of it.

If (as appears to be the case) the target string is stored as a std::string then this approach is not going to work. These have an internal structure that programmers are not supposed to be privy to (unless you go digging around in the header file) and the code you have there is not taking account of that. And even if you do, the next version of the compiler is probably going to break your code.
So consider instead (if you can) storing the target string as a simple C string. Overwriting it is then straightforward just so long as you don't run off the end and you add a terminating nul. I would do this explicitly - don't assume that the source string is nul-terminated, it may not be. Or use std::string.c_str() and copy size() + 1 bytes from that.

std::string is a container that managed a char array on the back end.
As it stands right now, on x86 if the string you want to write is the same size or less than the current string, you can perform this with relative ease but it is not recommended.
offset 0x14 of the container is the size of the array
if the char array is less than 15 characters, the array is stored at offset 0x4
if the char array is greater than 15 characters, this offset is turned into a pointer to the dynamic array elsewhere
So you read the size of the array, then write to the correct address depending on it's size. This code will do that and output "goodbye m8"
void WriteExternalString(HANDLE hProc, BYTE* addr, char* newstr)
{
unsigned int arraySize;
//Get the size of the array, offset 0x14 is the size of the array
ReadProcessMemory(hProc, (BYTE*)(addr + 0x14), &arraySize, sizeof(arraySize), 0);
if (arraySize > 15)
{
uintptr_t addrOfCharArray;
//dereference the pointer in the second member variable to get the dynamic address of the array
ReadProcessMemory(hProc, (BYTE*)(addr + sizeof(void*)), &addrOfCharArray, sizeof(void*), 0);
//Write the buffer to the array, +1 to get the null terminator
WriteProcessMemory(hProc, (BYTE*)(addrOfCharArray), newstr, strlen(newstr) + 1, 0);
}
else
{
WriteProcessMemory(hProc, (BYTE*)(addr + sizeof(void*)), newstr, strlen(newstr) + 1, 0);
}
}
int main()
{
std::string str = "Hello Mate";
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());
char newstr[] = "Goodbye m8";
WriteExternalString(hProcess, (BYTE*)&str, newstr);
cout << "string char array = " << str << endl;
system("pause");
return 0;
}

Related

How to read custom string with C++ from binary recursively

I've recently been getting in to IO with C++. I am trying to read a string from a binary file stream.
The custom type is saved like this:
The string is prefixed with the length of the string. So hello, would be stored like this: 6Hello\0.
I am basically reading text from a table (in this case a name table) in a binary file. The file header tells me the offset of this table (112 bytes in this case) and the number of names (318).
Using this information I can read the first byte at this offset. This tells me the length of the string (e.g. 6). So I'll start at the next byte and read 5 more to get the full string "Hello". This seems to work fine with the first name at the offset. trying to recursively read the rest provides a lot of garbage really. I've tried using loops and recursive functions but its not working out so well. Not sure what the problem is, so reverted to the original one name retrieval method. Here's the code:
int printName(fstream& fileObj, __int8 buff, DWORD offset, int& iteration){
fileObj.seekg(offset);
fileObj.read((char*)&buff, sizeof(char));
int nameSize = (int)buff;
char* szName = new char[nameSize];
for(int i=1; i <= nameSize; i++){
fileObj.seekg(offset+i);
fileObj.read((char*)&szName[i-1], sizeof(char));
}
cout << szName << endl;
return 0;
}
Any idea how to iterate through all 318 names without creating dodgy output?
Thanks for taking the time to look through this, your help is greatly appreciated.
You're overcomplicating a bit - there's no need to seek to the next sequential read.
Removing unused and pointless parameters, I would write this function something like this:
void printName(fstream& fileObj, DWORD offset) {
char size = 0;
if (fileObj.seekg(offset) && fileObj.read(&size, sizeof(char)))
{
char* name = new char[size];
if (fileObj.read(name, size))
{
cout << name << endl;
}
delete [] name;
}
}

Successive calls to RegGetValue return two different sizes for the same string

In some code I use the Win32 RegGetValue() API to read a string from the registry.
I call the aforementioned API twice:
The purpose of the first call is to get the proper size to allocate a destination buffer for the string.
The second call reads the string from the registry into that buffer.
What is odd is that I found that RegGetValue() returns different size values between the two calls.
In particular, the size value returned in the second call is two bytes (equivalent to one wchar_t) less than the first call.
It's worth noting that the size value compatible with the actual string length is the value returned by the second call (this corresponds to the actual string length, including the terminating NUL).
But I don't understand why the first call returns a size two bytes (one wchar_t) bigger than that.
A screenshot of program output and Win32 C++ compilable repro code are attached.
Repro Source Code
#include <windows.h>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
void PrintSize(const char* const message, const DWORD sizeBytes)
{
cout << message << ": " << sizeBytes << " bytes ("
<< (sizeBytes/sizeof(wchar_t)) << " wchar_t's)\n";
}
int main()
{
const HKEY key = HKEY_LOCAL_MACHINE;
const wchar_t* const subKey = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion";
const wchar_t* const valueName = L"CommonFilesDir";
//
// Get string size
//
DWORD keyType = 0;
DWORD dataSize = 0;
const DWORD flags = RRF_RT_REG_SZ;
LONG result = ::RegGetValue(
key,
subKey,
valueName,
flags,
&keyType,
nullptr,
&dataSize);
if (result != ERROR_SUCCESS)
{
cout << "Error: " << result << '\n';
return 1;
}
PrintSize("1st call size", dataSize);
const DWORD dataSize1 = dataSize; // store for later use
//
// Allocate buffer and read string into it
//
vector<wchar_t> buffer(dataSize / sizeof(wchar_t));
result = ::RegGetValue(
key,
subKey,
valueName,
flags,
nullptr,
&buffer[0],
&dataSize);
if (result != ERROR_SUCCESS)
{
cout << "Error: " << result << '\n';
return 1;
}
PrintSize("2nd call size", dataSize);
const wstring text(buffer.data());
cout << "Read string:\n";
wcout << text << '\n';
wcout << wstring(dataSize/sizeof(wchar_t), L'*') << " <-- 2nd call size\n";
wcout << wstring(dataSize1/sizeof(wchar_t), L'-') << " <-- 1st call size\n";
}
Operating System: Windows 7 64-bit with SP1
EDIT
Some confusion seems to be arisen by the particular registry key I happened to read in the sample repro code.
So, let me clarify that I read that key from the registry just as a test. This is not production code, and I'm not interested in that particular key. Feel free to add a simple test key to the registry with some test string value.
Sorry for the confusion.
RegGetValue() is safer than RegQueryValueEx() because it artificially adds a null terminator to the output of a string value if it does not already have a null terminator.
The first call returns the data size plus room for an extra null terminator in case the actual data is not already null terminated. I suspect RegGetValue() does not look at the real data at this stage, it just does an unconditional data size + sizeof(wchar_t) to be safe.
(36 * sizeof(wchar_t)) + (1 * sizeof(wchar_t)) = 74
The second call returns the real size of the actual data that was read. That size would include the extra null terminator only if one had to be artificially added. In this case, your data has 35 characters in the path, and a real null terminator present (which well-behaved apps are supposed to do), thus the extra null terminator did not need to be added.
((35+1) * sizeof(wchar_t)) + (0 * sizeof(wchar_t)) = 72
Now, with that said, you really should not be reading from the Registry directly to get the CommonFilesDir path (or any other system path) in the first place. You should be using SHGetFolderPath(CSIDL_PROGRAM_FILES_COMMON) or SHGetKnownFolderPath(FOLDERID_ProgramFilesCommon) instead. Let the Shell deal with the Registry for you. This is consistent across Windows versions, as Registry settings are subject to be moved around from one version to another, as well as accounting for per-user paths vs system-global paths. These are the main reasons why the CSIDL API was introduced in the first place.

Ustring error (during printing)

I want to parse UTF-8 file to ustring, I read this file in str.
There is an error:
terminate called after throwing an instance of 'Glib::ConvertError'.
What should I do?
char* cs = (char*) malloc(sizeof(char) * str.length());
strcpy(cs, str.c_str());
ustring res;
while (strlen(cs) > 0) {
gunichar ch = g_utf8_get_char(cs);
res.push_back(ch);
cs = g_utf8_next_char(cs);
}
wofstream wout("output");
cout << res << endl;
This looks very wrong:
char* cs = (char*) malloc(sizeof(str.c_str()));
as sizeof(str.c_str()) is bound to give you some small number like 4 or 8 (whichever is the size of a pointer on your machine, as the result of str.c_str().
Of course, it doesn't REALLY matter, since the next line, you are leaking the memory you just allocated incorrectly:
cs = const_cast<char*> (str.c_str());
I'm far from convinced that you need the const_cast<char *> (it is certainly WRONG to do this, since modifying the string inside a string is undefined behaviour).

About socket recv and char[] in C++

I am creating a program that can get package and print it to console by C++.
I set the char array to 1024 like :
char* buffer = new char[1024];
When I get a message is not exactly 1024 character, there is many unknown character on the end of my message because of the empty space in the array. What can I do?
More information (I dont know if it is useful)
The socket is sent by a Java program
Socket socket = new Socket("127.0.0.1", 27555);
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
out.write("I am your client :D");
out.flush();
And the server is written by C++ console application
char* recvData = new char[1024];
recv(socket, recvData, strlen(recvData), 0);
cout << recvData << endl;
There are three problems with the code:
recvData is unitialised when passed to strlen(). strlen() determines the length of the buffer when it finds a null terminating character, which could be within the buffer or outside. The size of the buffer, less one for terminating null character, should be passed as the maximum number of bytes to read.
the result of recv() is not queried. The code will use recvData even if the recv() failed, which is a bug.
recv() does not null terminate the buffer.
Save the result of recv() and if not -1 use it as an index into recvData to insert the null terminating character.
Alternatively, as this is c++ use a std::vector<char> and to manage dynamic memory allocation for you (if dynamic memory allocation is really required):
std::vector<char> recvData(1025); // Default initializes all elements to 0.
int result = recv(socket, recvData.data(), recvData.size() - 1);
if (result != -1)
{
std::cout << recvData.data() << std::endl;
}
Remember that data sent via sockets it just a stream of bytes, it is not separated into distinct messages. This means that:
out.write("I am your client :D");
might not be read by a single call to recv(). Equally:
out.write("I am your client :D");
out.write("OK");
might be read by a single call to recv(). It is the programmer's responsibility to implement a protocol if message-based processing is required.
strlen counts the number of bytes until a null ('\0') character is encountered. There is no guarantee that data returned by a single recv call wil be nul-terminated so you'll need to check the number of bytes returned then add your own terminator.
char* recvData = new char[1024];
int bytes = recv(socket, recvData, 1023, 0);
if (bytes == -1) {
cout << "error on recv" << endl;
}
else {
recvData[bytes] = '\0';
cout << recvData << endl;
}
recvData is not null terminated, so result of strlen() is undefined in this case. you have to do something like the following:
int len = 1024;
char *recvData = new char[len + 1];
int lenRead = recv(socket, recvData, len, 0);
if (lenRead < len)
recvData[lenRead] = '\0';
else
recvData[len] = '\0';
cout << recvData << endl;
Isn't this obvious? :)
Just send the length of the string first or terminate the string "properly" (by sending a \0 after the end of your string; I guess that's something Java isn't doing here).
But overall, you should include the "packet length" anyway, because you might want to ensure there's enough free space before writing to the buffer (using strlen() on an uninitialized array is usually a bad idea).

Passing a character array to function | Strange error

Basically I have a buffer in which i am looking for various flags to read certain fields from a binary file format. I have file read into a buffer but as i started to write code to search the buffer for the flags i immediately hit a wall. I am a C++ noob, but here is what i have:
void FileReader::parseBuffer(char * buffer, int length)
{
//start by looking for a vrsn
//Header seek around for a vrns followed by 32 bit size descriptor
//read 32 bits at a time
int cursor = 0;
char vrsn[4] = {'v','r','s','n'};
cursor = this->searchForMarker(cursor, length, vrsn, buffer);
}
int FileReader::searchForMarker(int startPos, int eof, char marker[], char * buffer)
{
int cursor = startPos;
while(cursor < eof) {
//read ahead 4 bytes from the cursor into a tmpbuffer
char tmpbuffer[4] = {buffer[cursor], buffer[cursor+1], buffer[cursor+2], buffer[cursor+3]};
if (strcmp(marker, tmpbuffer)) {
cout << "Found: " << tmpbuffer;
return cursor;
}
else {
cout << "Didn't Find Value: " << marker << " != " << tmpbuffer;
}
cursor = cursor + 4;
}
}
my header looks like this:
#ifndef __FILEREADER_H_INCLUDED__
#define __FILEREADER_H_INCLUDED__
#include <iostream>
#include <fstream>
#include <sys/stat.h>
class FileReader {
public:
FileReader();
~FileReader();
int open(char *);
int getcode();
private:
void parseBuffer(char *, int);
int searchForMarker(int, int, char[], char *);
char *buffer;
};
#endif
I would expect to get back a match for vrsn with strcmp but my result looks like this
Didn't Find Value: vrsn != vrsn
Found:
It looks like it finds it on the second pass after its passed the char array i am looking for.
Relevant hexcode
Your problem is two-fold:
strcmp returns "0" on success, not on failure. Read the documentation.
strcmp expects null-terminated strings. You say that you have chosen non-terminated char arrays because that's what your DB library uses. Well, fine. But still, you are violating the requirements of strcmp. Use strncmp instead (which takes a length argument) or, preferably, actually write C++ and start using std::vector<char> and friends.
Shouldn't that be something like int FileReader::searchForMarker(...) { .... }?
For the second query, I guess the strcmp works when it has two null terminated strings as its arguments. For example str1[]="AAA"; and str2[]="AAA"; then strcmp() would be used as
if(strcmp(str1,str2)==0) which will return 0 to indicate that they are equal. In your case, the tmpbuffer that you have created is not a null terminated string unless you add \0 in the end.So you might want to add \0 in the end of your tmpbuffer to create a string of 'v' 'r' 'n' 's'.
char vrsn[4] = {'v','r','s','n'};
Contains only the 4 characters specified. There is no room for a null character at the end.
char tmpbuffer[4] = {buffer[cursor], buffer[cursor+1], buffer[cursor+2], buffer[cursor+3]};
Contains only the 4 characters from buffer. There is no room for a null character at the end.
Eventually you call:
if (strcmp(marker, tmpbuffer)) {
The strcmp() function expects each of its parameters to end with a null character ('\0'). It wants to work with strings, which are null terminated.
Since your data is not null terminated, you probably want to use memcmp() instead of strcmp().
Also, strcmp() returns zero when its arguments are equal, so the condition in the if statement is inverted. (Zero is false, everything else is true.) The memcmp() function will also return zero when its arguments are equal.