2016-02-18 2 views
0

Во всех примерах, которые я видел, третий параметр или buffer является целым числом, но я не совсем уверен, что это значение должно представлять или как оно полезно в любом случае, поэтому я попробовал массив char и получил случайный мусор, поэтому Мне любопытно, как это значение может быть использовано для лучшего контейнера, и если тип данных зависит от значения, которое мы запрашиваем.Какой тип данных должен быть для буфера для ReadProcessMemory?

После того, как я просмотрел свой код, я понял, что совершил действительно тупую ошибку, не инициализируя дескриптор процесса при его объявлении. Вот мой код, хотя и теперь я получаю ERROR_PARTIAL_COPY. И dwRead 0. WTF

#include <iostream> 
#include <windows.h> 
using namespace std; 

int main() 
{ 
    system("tasklist"); 

    SYSTEM_INFO SysInfo; 
    GetSystemInfo(&SysInfo); 

    DWORD proc_Id = 0; 
    cin >> proc_Id; 
    HANDLE hProc = INVALID_HANDLE_VALUE; 
    char value[500]; 
    SIZE_T dwRead; 

    hProc = OpenProcess(PROCESS_ALL_ACCESS, TRUE, proc_Id); 
    if(hProc == NULL) 
    { 
     cout << "Error when trying to retrieve process handle" << endl; 
    } 

    void *baseAddr = (void*)hProc; 

    if(VirtualAllocEx(hProc, NULL, SysInfo.dwPageSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READ) == NULL) 
    { 
     cout << "VirtualAllocEx error" << endl; 
    } 

    if(ReadProcessMemory(hProc, baseAddr, &value, sizeof(value), &dwRead) == 0) 
    { 
     cout << "ReadProcessMemory failed: " << GetLastError() << endl; 
    } 
    cout << "Value is: " << value << endl; 
    cout << "Amount read successfully: " << dwRead << endl; 
} 
+1

Похоже, вы зависите от [этого ответа] (http://stackoverflow.com/a/11564232/886887), который, к сожалению, является полной бессмыслицей. Попробуйте [этот] (http://stackoverflow.com/a/25355713/886887). –

ответ

1
BOOL WINAPI ReadProcessMemory(
    HANDLE hProcess, 
    LPCVOID lpBaseAddress, 
    LPVOID lpBuffer, 
    SIZE_T nSize, 
    SIZE_T *lpNumberOfBytesRead 
); 

Параметр объявлен LPVOIDtypedef для void*). Любой указатель может неявно преобразовывать в указатель-на-void - это означает, что предоставленный вами буфер может быть любым типом, который вам нравится. Единственное ограничение состоит в том, что оно должно быть достаточно большим, чтобы содержать nSize байтов данных.

SIZE_T dwRead; 
int iValue; 
if (ReadProcessMemory(hProcess, lpAddress, &iValue, sizeof(iValue), &dwRead)) // read an int 
{ 
    if (dwRead == sizeof(iValue)) 
    { 
     // got int successfully 
    } 
} 

char buf[256]; 
if (ReadProcessMemory(hProcess, lpAddress, buf, sizeof(buf), &dwRead)) // read 256 chars 
{ 
    // got dwRead bytes successfully 
} 

Если вы получаете мусор в возвращаемом буфере это, вероятно, потому, что чтение не удалось, или не читали столько данных, сколько вы просили, и вы не проверять возвращаемое значение правильно. Если функция выполнена успешно, параметр lpNumberOfBytesRead позволяет узнать, сколько байтов было успешно прочитано.

Если функция возвращает 0, это означает, что она вообще не удалась - в этом случае содержимое предоставленного вами буфера не определено и не должно использоваться.

+0

Он не возвращает нуль, но когда я делаю 'GetLastError', он возвращает 18' ERROR_NO_MORE_FILES'. Есть идеи? И спасибо за помощь. :) –

+1

Не вызывайте 'GetLastError()', если функция не работает. Если он возвращает ненулевое значение, это не сработает. –

+0

Я проверил 'lpNumberOfBytesRead', и это было то же количество, которое я указал в моем массиве символов' значение [500] '. –

0

Вы должны использовать типы данных, которые вы хотите использовать.

https://msdn.microsoft.com/en-us/library/windows/desktop/ms680553(v=vs.85).aspx

Что касается третьего параметра вы можете использовать указатель любого типа данных, которые вы, как до тех пор, как вы настраиваете четвертый параметр соответственно.

например. передавая указатель на int как третий, и sizeof(int), поскольку четвертый параметр может быть совершенно точным.

Я бы рекомендовал, чтобы инициализировать данные ваши проезжают с нулем (по крайней мере для отладки причин) и проверить, что все данные, возвращаемая функцией (особенно значение переменного, которая ый указатель вы прошли, как 5-й переменные.)

Какой тип данных действительно подходит для вашего использования, зависит от вас.

В случае, если вы используете char -array это будет способ сделать это:

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


int main() 
{ 
    HANDLE hProcess = NULL;  //to be initialized 
    LPCVOID lpBaseAddress = NULL; //to be initialized 

    char buffer[256]; 
    SIZE_T bufferSize = sizeof(buffer); 
    SIZE_T bytesRead = 0; 
    if (::ReadProcessMemory(hProcess, lpBaseAddress, buffer, bufferSize, &bytesRead)) // read 256 chars 
    { 
     std::cout << "ReadProcessMemory succeeded by reading " << bytesRead << " bytes"; 
     //Do something with the buffer.... 
    } 
    else 
    { 
     char messageBuffer[256]; 
     DWORD messageBufferSize = sizeof(messageBuffer); 
     DWORD lastError = ::GetLastError(); 
     DWORD realMessageSize = ::FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, 
             NULL, 
             lastError, 
             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 
             messageBuffer, 
             messageBufferSize, 
             NULL); 

     //If FormatMessageA fails it returns 0. So we make sure that the string is empty 
     messageBuffer[realMessageSize] = 0; 

     std::cerr << "ReadProcessMemory failed with " << lastError << ": " << messageBuffer; 
    } 
} 

Потому что «Дэвид Heffernan» отметил, что непонятно, что я имел в виду инициализации буфера с нулями Я попытаюсь объяснить:

Это означало «подсказку» для отладки, поскольку я думаю, что легче увидеть, какие данные были изменены в отладчике, чем когда у вас есть унифицированные данные. Это определенно не нужно.

Предположим, что ваш звонок ReadProcessMemory успешно возвращается, и вы хотите проверить данные в буфере. Вам нужно будет проверить, сколько байтов было записано в буфер сначала, а затем посмотреть первые байты bytesWritten вашего массива.

Если данные, которые вы передавали в качестве буфера, не были инициализированы 0, может оказаться труднее найти разрыв между «реальными данными» и просто данными, которые были унифицированы, что может привести к неправильной интерпретации. Особенно для больших ошибок.

Это было предназначено только как инструмент для использования в процессе разработки, чтобы было легче проверить данные, и следует удалить, как только все будет работать так, как ожидалось.

+1

Нулевой инициализация бессмысленна. Проверьте возвращаемое значение ошибок. –

+0

@ Давид Хеффернан Да, это так. Но это может помочь отладке, поскольку более очевидно, какие данные были изменены в большинстве случаев. –

+0

Я не согласен. Я не знаю, почему вы не доверяете функции вести себя так, как описано. Представляете ли вы, что он может сообщить об успехе, когда на самом деле он не прошел? То, что вы не упоминаете возвращаемое значение функции, заставляет меня думать, что вы его не проверяете. –

Смежные вопросы