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