使用memoryadress从另一个程序读取字符串变量

问题描述 投票:0回答:1

我正在尝试从另一个程序中读取数据(我自己将显示程序的代码)与memoryadress一切正常我可以读取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

c++ string
1个回答
0
投票

std :: string是一个容器,底层是一个char数组,但容器管理它。

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

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

如果初始字符串小于15个字符,则容器中的第二个变量(取决于体系结构的偏移量0x4 / 0x8)是字符数组本身。如果它超过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;
}
© www.soinside.com 2019 - 2024. All rights reserved.