使用内存地址从另一个程序读取字符串变量

时间:2019-02-10 13:49:13

标签: c++ string

我正在尝试从另一个程序中读取数据(我自己给我显示了程序的代码),内存地址一切正常,我可以读取int char和string数据,但是当我尝试读取值时字符串的问题我在Visual Studio上显示了一个错误(昨天没有发生),我仍然可以获得正确的输出,但是我无法使用循环重新运行该程序: 它说:“违反读取访问权限_Pnext为0xDE74C”

enter image description here

-我正在尝试从以下程序读取数据的程序代码:

#include <iostream>
#include <string>
#include <Windows.h>

using namespace std;
int main()
{
const int sizeArrChar = 128;
int varInt = 123456;
string varString = "DefaultString";
char arrChar[sizeArrChar] = "Long char array right there ->";
int *ptr2int = &varInt;
int **ptr2ptr = &ptr2int;
int ***ptr2ptr2 = &ptr2ptr;
for (;;)
{
    cout << "Process ID: " << GetCurrentProcessId() << "\n"<< endl;
    cout << "varInt     (0x" << &varInt << ") = " << varInt << endl;
    cout << "varString  (0x" << &varString << ") = " << varString << endl;
    cout << "arrChar    (0x" << &arrChar << ") = " << arrChar << endl;
    cout << "ptr2int    (0x" << &ptr2int << ") = " << ptr2int << endl;
    cout << "ptr2ptr    (0x" << &ptr2ptr << ") = " << ptr2ptr << endl;
    cout << "ptr2ptr2   (0x" << &ptr2ptr2 << ") = " << ptr2ptr2 << "\n" << endl;
    cout << "Press enter to cout again!" << "\n" << "\n" << endl;
    cout << "---------------------------------------------------------" << endl;

    system("pause");
}

system("pause");
return 0;

}

-读取上面程序数据的程序代码: (这只是读取字符串,而不是int或char)

#include <iostream>
#include <Windows.h>
#include <string>




int main()
{
using namespace std;
int processNumber;
cout << "Enter the process number" << endl;
cin >> processNumber;
for (;;)
{
    uintptr_t memoryAdress = 0x0;
    cout << "Enter memoryadress" << endl;
    cin >> hex >> memoryAdress;
    cout << hex << memoryAdress << endl;

    HANDLE hProcess = OpenProcess(PROCESS_VM_READ, FALSE, processNumber);
    if (hProcess == NULL) { // Failed to get a handle
        cout << "OpenProcess failed. GetLastError = " << dec << GetLastError() << endl;
        system("pause");
        return EXIT_FAILURE;
    }

    string intRead;
    ReadProcessMemory(hProcess, (LPCVOID)memoryAdress, &intRead, sizeof(string), NULL);
    cout << "intRead = " << intRead << endl;


    BOOL WINAPI CloseHandle(
        _In_ HANDLE hObject
    );
    system("pause");
}
return 0;
}

一切正常,我得到了正确的输出,但是由于发生错误,我只能读取一次数据,所以我不能连续多次读取数据,这是主要问题。

以下是输出:

Enter the process number 14788 Enter memoryadress 0x009DFC2C 9dfc2c intRead = DefaultString Appuyez sur une touche pour continuer...

enter image description here

1 个答案:

答案 0 :(得分:0)

std :: string是一个容器,位于其底下的是一个char数组,但该容器管理它。

当使用ReadProcessMemory将目标字符串从目标进程复制到本地进程时,您还将从容器中复制在本地进程中无效的指针。它们仅指向目标进程中的有效内存对象。这些无效的指针是导致您崩溃的原因。

但这是一个复杂的问题。如果对字符串类进行反向工程,则会发现第一个成员变量是指针。偏移量0x14是char数组的大小,偏移量0x18是“当前char数组的最大大小”变量。

如果初始字符串小于15个字符,则容器中的第二个变量(偏移量0x4 / 0x8取决于体系结构)是char数组本身。如果它超过15个字符,则第二个变量将变成一个指向char数组的指针。每次修改字符串时,都会在堆上分配一个新的char数组,并且指针会更改为指向新数组。

由于您的字符串少于15个字符,因此您的代码起初看起来可以正常工作。

那么我们如何解决这个问题?

读取偏移量0x14处的整数,该整数为我们提供了char数组大小,如果小于15,则从偏移量0x4中读取,如果大于15,则取消引用指针,然后从char数组的动态地址中读取

我没有在std :: wstring上测试它,这仅仅是解决当前问题的概念证明。我在Windows 10,Visual Studio 2017上对此进行了测试。它可能无法在所有情况下都起作用。

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

using namespace std;

void ReadExternalString(HANDLE hProc, uintptr_t addr, char* dstArray)
{

    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);

        char buffer[500];
        //Read the array into buffer, +1 to get the null terminator
        ReadProcessMemory(hProc, (BYTE*)(addrOfCharArray), &buffer, arraySize + 1, 0);

        //copy the buffer into our ouput argument
        memcpy(dstArray, &buffer, strlen(buffer) + 1);
    }
    else
    {
        ReadProcessMemory(hProc, (BYTE*)(addr + sizeof(void*)), dstArray, arraySize, 0);
    }
}

int main()
{

    int processNumber;
    cout << "Enter the process number" << endl;
    cin >> processNumber;
    for (;;)
    {
        uintptr_t memoryAddress = 0x0;
        cout << "Enter memoryAddress" << endl;
        cin >> hex >> memoryAddress;
        cout << hex << memoryAddress << endl;

        HANDLE hProcess = OpenProcess(PROCESS_VM_READ, FALSE, processNumber);
        if (hProcess == NULL) { // Failed to get a handle
            cout << "OpenProcess failed. GetLastError = " << dec << GetLastError() << endl;
            system("pause");
            return EXIT_FAILURE;
        }

        char* cString = new char[500];

        ReadExternalString(hProcess, memoryAddress, cString);

        cout << "string char array = " << cString << endl;
        system("pause");
    }
    return 0;
}