2

There are probably several post that explain my problem in several ways... But I have been searching in google and stackoverflow searchbox and I didn't found anything. So here I go.

I want to Write in a Process Memory a String Changing it in c++, but I don't even know clearly how it work so..

I have this pointer: Image of the pointer Please, can someone help me doing it?

I've tried it but it's not working..

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

int main() {
    HWND hWnd = FindWindow(0, "WindowName");
    if (hWnd == 0) {
        std::cout << "Cannot find window." << std::endl;
    }
    DWORD pId;
    GetWindowThreadProcessId(hWnd, &pId);
    HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pId);
    DWORD baseAddress = 0x009B03D0;
    DWORD offset = 0xA7;
    DWORD ptrAddress;
    char *newString = "newvalue";
    ReadProcessMemory(hProc, (void*)baseAddress, &ptrAddress, sizeof(DWORD), 0);
    WriteProcessMemory(hProc, (void*)(ptrAddress + offset), newString, strlen(newString), 0);
    std::cout << "Done. " << &ptrAddress << std::endl;
    std::getchar();
}

I should get the pointer and jumpt to the last one because I only have one offset.. But I'm not getting the correct one..


Edit:

Here is my new code, it works until the WriteProcessMemory function.. What can be wrong?

CODE THAT ACTUALLY WORKS:

int main()
{
    unsigned long Pointer;   /* to hold the final value */
    unsigned long temp;      /* hold the temp values    */
    unsigned long address = 0x009B03D0;
    unsigned long offset = 0xA7;
    unsigned long newString = 0;
    DWORD pid;
    HWND hwnd;
    hwnd = FindWindow(0, TEXT("NewWindow"));
    if (!hwnd)
    {
        cout << "No!\n";
        cin.get();
    }
    else
    {
        GetWindowThreadProcessId(hwnd, &pid);
        HANDLE phandle = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
        if (!phandle)
        {
            cout << "None!\n";
            cin.get();
        }
        else
        {
            while (1)
            {

                ReadProcessMemory(phandle, reinterpret_cast<LPVOID>(address), &temp, sizeof(temp), 0);
                Pointer = temp + offset;
                //Good
                ReadProcessMemory(phandle, reinterpret_cast<LPVOID>(Pointer), &newString, 16, 0);
                cout << reinterpret_cast<LPVOID>(Pointer) << " en " << newString;
                Sleep(1000);
            }
            return 0;
        }
    }
}

CODE THAT NOT WORK:

int main()
{
    unsigned int Pointer;   /* to hold the final value */
    unsigned int temp;      /* hold the temp values    */
    unsigned int address = 0x009B03D0;
    unsigned int offset = 0xA7;
    unsigned int newString = 1768060259;
    DWORD pid;
    HWND hwnd;
    hwnd = FindWindow(0, TEXT("NewWindow"));
    if (!hwnd)
    {
        cout << "NO\n";
        cin.get();
    }
    else
    {
        GetWindowThreadProcessId(hwnd, &pid);
        HANDLE phandle = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
        if (!phandle)
        {
            cout << "NONE\n";
            cin.get();
        }
        else
        {
            while (1)
            {

                ReadProcessMemory(phandle, reinterpret_cast<LPVOID>(address), &temp, sizeof(temp), 0);
                Pointer = temp + offset;
                //Good
                if (!WriteProcessMemory(phandle, reinterpret_cast<LPVOID>(Pointer), &newString, sizeof(newString), 0))
                    std::cerr << "Couldn't write process memory:" << GetLastError() << std::endl;
                cout << reinterpret_cast<LPVOID>(Pointer) << " en " << newString;
                Sleep(1000);
            }
            return 0;
        }
    }
}
Onelio
  • 313
  • 1
  • 4
  • 16
  • 3
    Please do not post `void main`: it's non-standard and as far as I know only Visual C++ accepts it, i.e. the other compilers *don't* accept it. – Cheers and hth. - Alf Mar 25 '16 at 16:26
  • I can't because I even not know the code xD – Onelio Mar 25 '16 at 16:34
  • So, what's wrong. You didn't check for errors. Perhaps one of the API calls failed. What do you expect to happen? How did you verify that it did not happen? What did happen? You didn't write the null terminator. – David Heffernan Mar 25 '16 at 16:35
  • I was expecting to change a value in a Process with the Pointer "WindowName.exe" + 009B03D0 + A7 but As I see, ptrAddress should be 00B94247 but I get 0018FA68 and I don't know why... And yes, I forgot the terminator, thnks – Onelio Mar 25 '16 at 16:38
  • You are printing the address of your local rather than its value. You don't check for errors. Why not? – David Heffernan Mar 25 '16 at 17:06
  • I can't understand you very good David.. I don't know very well the code so provably I should be doing very much things wrong.. I just copied this code: http://stackoverflow.com/questions/26570087/how-to-writeprocessmemory-with-multipointers What do you suggest? – Onelio Mar 25 '16 at 17:13
  • 1
    I think you need to get some basics sorted out. Your code is totally wrong, and you've no idea what any of it does. You don't understand pointers and you don't know how to check for errors. You are out of your depth. Copying code that you don't understand is not sensible. If you can't understand what I say then you aren't in a position to write this code. You should hire a programmer, or do some study. – David Heffernan Mar 25 '16 at 18:04

1 Answers1

1

Each process has its own memory and address space. So ReadProcessMemory() and WriteProcessMemory() use an intermediary buffer to do their job of accessing memory of another process.

Unfortunately, there are issues with your ReadProcessMemory() call:

  • you don't initialise ptrAddress to point to a buffer
  • you pass the address of ptrAddress and not its value that should point to a valid buffer
  • you pass 0 (i.e. a nullptr) instead of passing the address of the zie variable that should contain the number of bytes that could be read.

Note also that you manage the address in the target process using a DWORD for a LPCVOID. The first is always 32 bits, while the latter depend on your compiling options (32 bit code or 64 bit code).

You should also verify the error code in case of failure. It is almost certain taht special priviledges are required to read/write in distinct processes.

Here an adjusted code, with some diagnosis messages to help you further.

HWND hWnd = FindWindow(0, TEXT("WindowName") );
if (hWnd == 0) {
    std::cerr << "Cannot find window." << std::endl;
}
else {
    DWORD pId;
    GetWindowThreadProcessId(hWnd, &pId);
    HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pId);
    if (hProc) {
        char *newString = "newvalue";
        size_t sz = strlen(newString) + 1; 
        LPVOID baseAddress = (LPVOID)0x009B03D0;
        DWORD offset = 0xA7;
        LPVOID ptrAddress = new char[sz];
        SIZE_T bytes_read = 0, bytes_written=0;
        if (ReadProcessMemory(hProc, baseAddress, ptrAddress, sz, &bytes_read) || GetLastError()== ERROR_PARTIAL_COPY) {
            if (bytes_read == 0)
                std::cerr << "Houston, we have a problem..." << std::endl; 
            if(!WriteProcessMemory(hProc, baseAddress, (LPCVOID)newString, sz, &bytes_written)) 
                std::cerr << "Couldn't write process memory:" << GetLastError() << std::endl;
            std::cout << "Done. " << bytes_read <<" bytes read and "<<bytes_written<<" bytes written"<< std::endl;
        }
        else {
            std::cerr<< "Couldn't read process memory:" << GetLastError() << std::endl;
        }
        delete[] ptrAddress; 
    }
    else {
        std::cerr << "Couldn't open process " << pId << ": " << GetLastError() << std::endl; 
    }
}
std::getchar();
Christophe
  • 68,716
  • 7
  • 72
  • 138
  • You Forgot a ")" in ("WindowName")); XD (Let me try) – Onelio Mar 25 '16 at 18:19
  • Executed as admin I get this: https://i.gyazo.com/b2ec7c5fb53e6c410df801ffb51db94e.png But I noticed that something changed in CE because it stopped showing the value(But it's still In the Memory Region) – Onelio Mar 25 '16 at 18:25
  • 1
    @James Sorry, I just realized that a `!` was missing in the write condition, causing it to display the writing error message despite everything went fine. I edited the answer. – Christophe Mar 25 '16 at 18:45
  • Sorry for being so annoying but.. It now says "Done" and in CE change something and the address stop working(so I need to restart the program for the pointers to load again) – Onelio Mar 25 '16 at 18:56
  • I note that in your original program, you didn't write at the same point than you read, but usd and offset. In my code snippet, I got rid of the offset, in order not to break anything during my tests. Now if it's done, without errors, and the bytes read and written correspond to the expected values, the windows function worked. I can't help you about what happens in the target code, especially if ASLR is set. – Christophe Mar 25 '16 at 19:08
  • I did that because as I saw in this picture http://i.stack.imgur.com/jQMds.png I thought that this was how the program should have worked so I tried this, Thnks anyway :D – Onelio Mar 25 '16 at 19:25
  • I found what's wrong, How can I add offset to ptrAddress ? Thnks – Onelio Mar 25 '16 at 21:25
  • @James as LPVOID is a void pointer to objects on unknown size, you can't just add the offset. You have to use casting, such as for example: `LPVOID newAddress = (char*)baseAddress + offset;` – Christophe Mar 25 '16 at 21:32
  • And if I get in the "newAddress" a DEC but I want to pass it in HEX.. What could I do? – Onelio Mar 25 '16 at 21:54
  • decimal and hex are only diplay caracteristics. The value is the same. So in your code you can write `... + 0x0A` or `... + 10` with the same result. – Christophe Mar 25 '16 at 22:03
  • Ok, Just a last request. I edited my first post and added my own code(Please don't be mad, your code is too hard for me xD) made in the most part by myself and I know that if instead of Writing the Memory I Read it, It works. But when i try this code just Give me Couldn't write process memory:5. Any idea? – Onelio Mar 25 '16 at 22:18
  • Error 5 means access denied. In your edited code, you read the address of the the place to write in the address space, asuming it's long long. But long long is 64 bits, so if your target process is compiled in 32 bits, you'll get a number that will go out of range. – Christophe Mar 25 '16 at 22:52
  • The what should I do? I've changed everything to int and keep giving me this error. – Onelio Mar 25 '16 at 23:07
  • Ok, It was happening because "PROCESS_VM_READ" Now I've added two codes, the working one and the other one.. I can't see what is worng with them... – Onelio Mar 25 '16 at 23:54
  • 1
    Fixxed, now it works. I just needed to change the VirtualProtect – Onelio Mar 26 '16 at 13:29
  • 1
    There's nothing wrong with passing `nullptr` to the last parameter, it is an optional parameter. If you pass `nullptr` it will simply be ignored. – frostbyte Nov 14 '18 at 09:43
  • i had to use const char newString = "1911"; to initialise my string. Might want to overlook this. Also, personally I think that "FindWindow" is kind of a newbish approach – clockw0rk Apr 10 '20 at 17:36
  • @clockw0rk how would you do it instead of using FindWindow? I'm very new to this type of Windows programming in-depth. – Rick Henderson Nov 11 '21 at 19:40
  • @RickHenderson yeah sry if my comment sounded offensive... FindWindow looks for a window with string as title. Can't link you any code right now, but the basic concept of finding a process is to search for a process id (PID on linux, dunno windows counterpart right now), for a process handle or even a process name, not just a window name. if you want to find the browser, what are you searching for? google.com? facebook.com/something? the window title changes often, maybe not in a videogame, but still dont do this. reading window titles is for keyloggers only ;) – clockw0rk Nov 19 '21 at 16:38