0

I'm trying to read a Unicode string from another process's memory with this code:

Function:

bool ReadWideString(const HANDLE& hProc, const std::uintptr_t& addr, std::wstring& out) {
    std::array<wchar_t, maxStringLength> outStr;
    auto readMemRes = ReadProcessMemory(hProc, (LPCVOID)addr,(LPVOID)&out, sizeof(out), NULL);
    if (!readMemRes)
        return false;
    else {
        out = std::wstring(outStr.data());
    }
    return true;
}

Call:

std::wstring name;
bool res = ReadWideString(OpenedProcessHandle, address, name);
std::wofstream test("test.txt");
test << name;
test.close();

This is working well with English letters, but when I try to read Cyrillic, it outputs nothing. I tried with std::string, but all I get is just a random junk like "EC9" instead of "Дебил".

I'm using Visual Studio 17 and the C++17 standard.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Shiroe
  • 43
  • 1
  • 7
  • 1
    Do some debugging. Is the issue in the code that reads from the other process, or the code that saves the text to a file. Once you know the answer to that, keep debugging to narrow it down further. SO is not meant to be a substitute for debugging. – David Heffernan Jan 30 '19 at 14:40
  • Possible duplicate of [Why does my std::wofstream write ansi?](https://stackoverflow.com/questions/2380307/why-does-my-stdwofstream-write-ansi) – Raymond Chen Jan 30 '19 at 14:49
  • I did, and i reached limit of my knowledge on this. That's why i posted a question. – Shiroe Jan 30 '19 at 14:50
  • What you need to do is learn to use the debugger. Getting us to tell you the answer won't help you next time you are stuck. Are you going to ask a question every time you get stuck, or are you going to learn to use a debugger? Using a debugger you can convince yourself that the string is being read correctly from the other process, or not. If not then the error lies in that code. Or, if it is read correctly, the error lies in the code that outputs to the file. So, you tell me, which is it? – David Heffernan Jan 30 '19 at 15:00
  • `std::wstring out` can't be used like that. `(LPVOID)&out` is wrong usage. `sizeof(out)` is always 4 or 8. Use instead `wchar_t buf[1000]; ReadProcessMemory(hProc, (LPCVOID)addr, buf, sizeof(buf), NULL);` (I am not sure if there are other errors) - Use `OutputDebugStringW(buf)` to view the result. – Barmak Shemirani Jan 30 '19 at 15:12

1 Answers1

2

You can't read directly into the wstring the way you are doing. That will overwrite it's internal data members and corrupt surrounding memory, which would be very bad.

You are allocating a local buffer, but you are not using it for anything. Use it, eg:

bool ReadWideString(HANDLE hProc, std::uintptr_t addr, std::wstring& out) {
    std::array<wchar_t, maxStringLength> outStr;
    SIZE_T numRead = 0;
    if (!ReadProcessMemory(hProc, reinterpret_cast<LPVOID>(addr), &outStr, sizeof(outStr), &numRead))
        return false;
    out.assign(outStr.data(), numRead / sizeof(wchar_t));
    return true;
}

std::wstring name;
if (ReadWideString(OpenedProcessHandle, address, name)) {
    std::ofstream test("test.txt", std::ios::binary);
    wchar_t bom = 0xFEFF;
    test.write(reinterpret_cast<char*>(&bom), sizeof(bom));
    test.write(reinterpret_cast<const char*>(name.c_str()), name.size() * sizeof(wchar_t));
}

Alternatively, get rid of the local buffer and preallocate the wstring's memory buffer instead, then you can read directly into it, eg:

bool ReadWideString(HANDLE hProc, std::uintptr_t addr, std::wstring& out) {
    out.resize(maxStringLength);
    SIZE_T numRead = 0;
    if (!ReadProcessMemory(hProc, reinterpret_cast<LPVOID>(addr), &out[0], maxStringLength * sizeof(wchar_t), &numRead)) {
        out.clear();
        return false;
    }
    out.resize(numRead / sizeof(wchar_t));
    return true;
}

Or

bool ReadWideString(HANDLE hProc, std::uintptr_t addr, std::wstring& out) {
    std::wstring outStr;
    outStr.resize(maxStringLength);
    SIZE_T numRead = 0;
    if (!ReadProcessMemory(hProc, reinterpret_cast<LPVOID>(addr), &outStr[0], maxStringLength * sizeof(wchar_t), &numRead))
        return false;
    outStr.resize(numRead / sizeof(wchar_t));
    out = std::move(outStr);
    return true;
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770