Я создаю простой игровой макрос в качестве хобби. Чтобы прочитать HP, MP или координаты, я пытаюсь найти память игры, используя функцию ReadProcessMemory () из API Win32. Несмотря на то, что он отлично работает для некоторых игр, в других поиск памяти вообще не работает, адресов памяти не найдено. < /P>
Я подозреваю, что эта проблема вызвана программой безопасности игры. /p>
Чтобы решить это, я попробовал несколько методов, включая: < /p>
[*] Дешифрование /шифрование с помощью Decryptxor () < /code>
[*] Изменение атрибутов защиты памяти с использованием VirtualProtectex ()
[*] Функция, подключающаяся к библиотеке обходов
Несмотря на эти попытки, я все еще не могу сканировать память в проблемных играх. < /p>
Как я могу обойти это ограничение и успешно читать память в этих играх? p>
#include
#include
#include
#include
#include
#include
#include
#include
#include // Moved after windows.h
#include
#include
#pragma comment(lib, "comctl32.lib")
#pragma comment(lib, "detours.lib")
#define ID_BUTTON_FIND_HP 101
#define ID_BUTTON_FIND_MP 102
#define ID_BUTTON_FIND_X 103
#define ID_BUTTON_FIND_Y 104
#define ID_EDIT_PID 105
#define ID_EDIT_VALUE 106
#define ID_BUTTON_SEARCH 107
#define ID_LISTVIEW 113
#define ID_EDIT_NEXT_VALUE 110
#define ID_BUTTON_NEXT 111
#define ID_TIMER 109
// 전역 변수
HWND hButtonFindHP, hButtonFindMP, hButtonFindX, hButtonFindY;
HWND hEditPID, hEditValue, hButtonSearch;
HWND hEditNextValue, hButtonNext;
HWND hListView;
DWORD targetPID = 0;
std::vector foundAddresses;
HANDLE hProcess = NULL;
// 새로운 윈도우 핸들
HWND hNewWindow = NULL;
// 메모리 캐시
std::unordered_map memoryCache;
// 스레드 풀
std::vector threadPool;
const int numThreads = std::thread::hardware_concurrency();
// XOR 암호화 키 값
BYTE xorKey = 0x5A; // 임의 값
// 함수 선언
LRESULT CALLBACK NewWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
void OpenFindMeorryWindow();
void FindValueInMemory(DWORD pid, int searchValue);
void UpdateMemoryValues();
void FilterByNextValue();
void OnSearchClick();
void OnFindHPClick();
void OnFindMPClick();
void OnFindXClick();
void OnFindYClick();
void OnTimer(HWND hwnd);
void OnNextClick();
// 메모리 보호 변경 함수
BOOL ChangeMemoryProtection(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect);
// XOR 복호화 함수
BYTE DecryptXOR(BYTE encryptedValue, BYTE key);
// Detours 함수 선언
BOOL(WINAPI* OriginalIsDebuggerPresent)();
BOOL WINAPI HookIsDebuggerPresent();
NTSTATUS(NTAPI* OriginalNtQueryInformationProcess)(
HANDLE hProcess,
PROCESSINFOCLASS ProcessInformationClass,
PVOID ProcessInformation,
ULONG ProcessInformationLength,
PULONG ReturnLength
);
NTSTATUS NTAPI HookNtQueryInformationProcess(
HANDLE hProcess,
PROCESSINFOCLASS ProcessInformationClass,
PVOID ProcessInformation,
ULONG ProcessInformationLength,
PULONG ReturnLength
);
// 스레드 풀 초기화
void InitializeThreadPool() {
for (int i = 0; i < numThreads; ++i) {
threadPool.push_back(std::thread()); // 빈 스레드 생성 (나중에 작업 할당)
}
}
// 스레드 풀 종료
void JoinThreadPool() {
for (auto& thread : threadPool) {
if (thread.joinable()) {
thread.join();
}
}
threadPool.clear();
}
// 새로운 윈도우 생성 및 관련 컨트롤 생성
void OpenFindMeorryWindow() {
if (hNewWindow == NULL) {
WNDCLASS wc = { 0 };
wc.lpfnWndProc = NewWindowProc;
wc.hInstance = GetModuleHandle(NULL);
wc.lpszClassName = L"NewWindowClass";
if (!RegisterClass(&wc)) {
MessageBox(NULL, L"Window class registration failed!", L"Error", MB_OK | MB_ICONERROR);
return;
}
hNewWindow = CreateWindow(L"NewWindowClass", L"Memory Scanner", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT, 380, 320, NULL, NULL, wc.hInstance, NULL);
if (hNewWindow == NULL) {
MessageBox(NULL, L"Failed to create new window!", L"Error", MB_OK | MB_ICONERROR);
}
}
else {
SetForegroundWindow(hNewWindow);
}
}
// 메모리 보호 변경 함수
BOOL ChangeMemoryProtection(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect) {
return VirtualProtectEx(hProcess, lpAddress, dwSize, flNewProtect, lpflOldProtect);
}
// XOR 복호화 함수
BYTE DecryptXOR(BYTE encryptedValue, BYTE key) {
return encryptedValue ^ key;
}
// 메모리 검색 함수
void FindValueInMemory(DWORD pid, int searchValue) {
if (hProcess) CloseHandle(hProcess);
hProcess = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, pid);
if (!hProcess) {
MessageBox(NULL, L"Failed to open process!", L"Error", MB_OK | MB_ICONERROR);
return;
}
SYSTEM_INFO si;
GetSystemInfo(&si);
BYTE* addr = (BYTE*)si.lpMinimumApplicationAddress;
BYTE* endAddr = (BYTE*)si.lpMaximumApplicationAddress;
foundAddresses.clear();
memoryCache.clear(); // 캐시 초기화
// 페이지 단위로 메모리 검색
while (addr < endAddr) {
MEMORY_BASIC_INFORMATION mbi;
if (VirtualQueryEx(hProcess, addr, &mbi, sizeof(mbi)) == 0) break;
if (mbi.State == MEM_COMMIT && (mbi.Protect & PAGE_READWRITE)) {
// 메모리 캐시 확인 및 갱신
if (memoryCache.find(addr) == memoryCache.end() || memoryCache[addr].size() != mbi.RegionSize) {
SIZE_T bytesRead;
std::vector buffer(mbi.RegionSize);
if (ReadProcessMemory(hProcess, addr, buffer.data(), mbi.RegionSize, &bytesRead)) {
memoryCache[addr] = buffer;
}
else {
// 읽기 실패 시 캐시에서 제거
memoryCache.erase(addr);
addr += mbi.RegionSize;
continue; // 다음 페이지로 이동
}
}
std::vector& buffer = memoryCache[addr];
size_t count = buffer.size() / sizeof(int);
// 검색 (SIMD, Aho-Corasick 등 적용 고려)
for (size_t i = 0; i < count; ++i) {
BYTE* valuePtr = buffer.data() + (i * sizeof(int));
int encryptedValue = *reinterpret_cast(valuePtr);
int decryptedValue = 0;
// 암호화된 값인지 확인하는 조건
// 예: 특정 비트 패턴을 확인하여 암호화된 값인지 판단
if (encryptedValue & 0x80000000) { // 예시: 상위 비트가 1이면 암호화된 값으로 간주
// XOR 복호화
for (int j = 0; j < sizeof(int); ++j) {
*((BYTE*)&decryptedValue + j) = DecryptXOR(*(valuePtr + j), xorKey);
}
}
else {
decryptedValue = encryptedValue; // 암호화되지 않은 값 그대로 사용
}
if (decryptedValue == searchValue) {
foundAddresses.push_back({ addr + (i * sizeof(int)), decryptedValue });
}
}
}
addr += mbi.RegionSize;
}
}
// ListView 항목 업데이트
void UpdateMemoryValues() {
if (!hProcess || foundAddresses.empty()) return;
ListView_DeleteAllItems(hListView);
for (auto& entry : foundAddresses) {
int currentValue = 0;
SIZE_T bytesRead;
if (ReadProcessMemory(hProcess, entry.first, ¤tValue, sizeof(int), &bytesRead)) {
// 암호화 여부 확인 및 복호화
// 예시: 암호화된 값이 상위 비트가 1인 경우 복호화
if (currentValue & 0x80000000) { // 상위 비트가 1인 경우 복호화
currentValue = DecryptXOR((BYTE)currentValue, xorKey);
}
entry.second = currentValue;
wchar_t addressStr[64], valueStr[64];
swprintf(addressStr, sizeof(addressStr) / sizeof(wchar_t), L"0x%p", entry.first);
swprintf(valueStr, sizeof(valueStr) / sizeof(wchar_t), L"%d", currentValue);
LVITEM lvItem;
lvItem.mask = LVIF_TEXT;
lvItem.iItem = ListView_GetItemCount(hListView);
lvItem.iSubItem = 0;
lvItem.pszText = addressStr;
ListView_InsertItem(hListView, &lvItem);
lvItem.iSubItem = 1;
lvItem.pszText = valueStr;
ListView_SetItem(hListView, &lvItem);
}
}
}
// 다음 부분: 값으로 필터링
void FilterByNextValue() {
wchar_t nextValueStr[16];
GetWindowText(hEditNextValue, nextValueStr, sizeof(nextValueStr) / sizeof(wchar_t));
int nextValue = _wtoi(nextValueStr);
if (nextValue == 0) {
MessageBox(NULL, L"Invalid next value!", L"Error", MB_OK | MB_ICONERROR);
return;
}
std::vector filteredAddresses;
for (auto& entry : foundAddresses) {
if (entry.second == nextValue) {
filteredAddresses.push_back(entry);
}
}
foundAddresses = filteredAddresses;
// 타이머 설정: 1초마다 메모리 값 업데이트
SetTimer(hNewWindow, ID_TIMER, 1000, NULL);
}
// 검색 버튼 클릭 시 이벤트 처리
void OnSearchClick() {
wchar_t pidStr[16], valueStr[16];
GetWindowText(hEditPID, pidStr, sizeof(pidStr) / sizeof(wchar_t));
GetWindowText(hEditValue, valueStr, sizeof(valueStr) / sizeof(wchar_t));
DWORD pid = _wtoi(pidStr);
int searchValue = _wtoi(valueStr);
if (pid == 0 || searchValue == 0) {
MessageBox(NULL, L"Invalid PID or Value!", L"Error", MB_OK | MB_ICONERROR);
return;
}
targetPID = pid;
FindValueInMemory(pid, searchValue);
// 타이머 설정 제거: 실시간 업데이트 없음
UpdateMemoryValues(); // 검색 후 결과 바로 표시
}
// Find HP 버튼 클릭 시 이벤트 처리
void OnFindHPClick() {
OpenFindMeorryWindow();
}
// Find MP 버튼 클릭 시 이벤트 처리
void OnFindMPClick() {
OpenFindMeorryWindow();
}
// Find X 버튼 클릭 시 이벤트 처리
void OnFindXClick() {
OpenFindMeorryWindow();
}
// Find Y 버튼 클릭 시 이벤트 처리
void OnFindYClick() {
OpenFindMeorryWindow();
}
// WM_TIMER 메시지 처리
void OnTimer(HWND hwnd) {
UpdateMemoryValues();
}
// Next 버튼 클릭 시 이벤트 처리
void OnNextClick() {
// 메모리 보호 해제
DWORD oldProtect;
for (auto& entry : foundAddresses) {
ChangeMemoryProtection(entry.first, sizeof(int), PAGE_READWRITE, &oldProtect);
}
// 먼저 메모리 값을 업데이트한 후 필터링
UpdateMemoryValues();
FilterByNextValue();
}
// 새로운 윈도우 프로시저
LRESULT CALLBACK NewWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
static wchar_t colText1[] = L"Memory Address";
static wchar_t colText2[] = L"Value";
switch (msg) {
case WM_CREATE:
// 컨트롤 생성
hEditPID = CreateWindow(L"EDIT", L"", WS_CHILD | WS_VISIBLE | WS_BORDER | ES_NUMBER,
20, 20, 100, 20, hwnd, (HMENU)ID_EDIT_PID, NULL, NULL);
hEditValue = CreateWindow(L"EDIT", L"", WS_CHILD | WS_VISIBLE | WS_BORDER | ES_NUMBER,
140, 20, 100, 20, hwnd, (HMENU)ID_EDIT_VALUE, NULL, NULL);
hButtonSearch = CreateWindow(L"BUTTON", L"Search", WS_CHILD | WS_VISIBLE,
260, 20, 80, 25, hwnd, (HMENU)ID_BUTTON_SEARCH, NULL, NULL);
hEditNextValue = CreateWindow(L"EDIT", L"", WS_CHILD | WS_VISIBLE | WS_BORDER | ES_NUMBER,
20, 230, 100, 20, hwnd, (HMENU)ID_EDIT_NEXT_VALUE, NULL, NULL);
hButtonNext = CreateWindow(L"BUTTON", L"Next", WS_CHILD | WS_VISIBLE,
140, 230, 80, 25, hwnd, (HMENU)ID_BUTTON_NEXT, NULL, NULL);
// ListView 초기화 및 컬럼 추가
InitCommonControls();
hListView = CreateWindow(WC_LISTVIEW, L"", WS_CHILD | WS_VISIBLE | LVS_REPORT | LVS_SINGLESEL | WS_BORDER | WS_VSCROLL,
20, 60, 320, 160, hwnd, (HMENU)ID_LISTVIEW, NULL, NULL);
LVCOLUMN lvCol;
lvCol.mask = LVCF_TEXT | LVCF_WIDTH;
lvCol.cx = 160;
lvCol.pszText = colText1;
ListView_InsertColumn(hListView, 0, &lvCol);
lvCol.pszText = colText2;
ListView_InsertColumn(hListView, 1, &lvCol);
break;
case WM_COMMAND:
if (LOWORD(wParam) == ID_BUTTON_SEARCH) {
OnSearchClick();
}
else if (LOWORD(wParam) == ID_BUTTON_NEXT) {
OnNextClick();
}
break;
case WM_NOTIFY:
if (((LPNMHDR)lParam)->hwndFrom == hListView) {
LPNMHDR pnmh = (LPNMHDR)lParam;
if (pnmh->code == NM_CLICK) {
LPNMLISTVIEW pnmListView = (LPNMLISTVIEW)lParam;
if (pnmListView->iItem != -1) {
wchar_t addressStr[64];
wchar_t valueStr[64];
LVITEM lvItem;
lvItem.mask = LVIF_TEXT;
lvItem.iItem = pnmListView->iItem;
lvItem.iSubItem = 0;
lvItem.pszText = addressStr;
lvItem.cchTextMax = sizeof(addressStr) / sizeof(wchar_t);
ListView_GetItem(hListView, &lvItem);
lvItem.iSubItem = 1;
lvItem.pszText = valueStr;
lvItem.cchTextMax = sizeof(valueStr) / sizeof(wchar_t);
ListView_GetItem(hListView, &lvItem);
}
}
}
break;
case WM_TIMER:
OnTimer(hwnd);
break;
case WM_DESTROY:
if (hProcess) CloseHandle(hProcess);
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
// 메인 윈도우 프로시저
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_CREATE:
// 컨트롤 생성 (레이블 및 버튼)
CreateWindow(L"STATIC", L"HP:", WS_CHILD | WS_VISIBLE, 20, 20, 40, 20, hwnd, NULL, NULL, NULL);
CreateWindow(L"STATIC", L"MP:", WS_CHILD | WS_VISIBLE, 20, 60, 40, 20, hwnd, NULL, NULL, NULL); // 수정: 100 삭제
CreateWindow(L"STATIC", L"X:", WS_CHILD | WS_VISIBLE, 20, 100, 30, 20, hwnd, NULL, NULL, NULL);
hButtonFindX = CreateWindow(L"BUTTON", L"Find X", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 60, 100, 120, 30, hwnd, (HMENU)ID_BUTTON_FIND_X, NULL, NULL);
CreateWindow(L"STATIC", L"Y:", WS_CHILD | WS_VISIBLE, 200, 100, 30, 20, hwnd, NULL, NULL, NULL);
hButtonFindY = CreateWindow(L"BUTTON", L"Find Y", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 240, 100, 120, 30, hwnd, (HMENU)ID_BUTTON_FIND_Y, NULL, NULL);
hButtonFindHP = CreateWindow(L"BUTTON", L"Find HP", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 100, 20, 120, 30, hwnd, (HMENU)ID_BUTTON_FIND_HP, NULL, NULL);
hButtonFindMP = CreateWindow(L"BUTTON", L"Find MP", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 100, 60, 120, 30, hwnd, (HMENU)ID_BUTTON_FIND_MP, NULL, NULL);
break;
case WM_COMMAND:
if (LOWORD(wParam) == ID_BUTTON_FIND_HP) {
OnFindHPClick();
}
else if (LOWORD(wParam) == ID_BUTTON_FIND_MP) {
OnFindMPClick();
}
else if (LOWORD(wParam) == ID_BUTTON_FIND_X) {
OnFindXClick();
}
else if (LOWORD(wParam) == ID_BUTTON_FIND_Y) {
OnFindYClick();
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
// 메인 함수
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
// Detours 초기화
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
// IsDebuggerPresent 후킹
OriginalIsDebuggerPresent = IsDebuggerPresent;
DetourAttach(&OriginalIsDebuggerPresent, HookIsDebuggerPresent);
// NtQueryInformationProcess 후킹
OriginalNtQueryInformationProcess = NtQueryInformationProcess;
DetourAttach(&OriginalNtQueryInformationProcess, HookNtQueryInformationProcess);
// Detours 트랜잭션 종료
DetourTransactionCommit();
WNDCLASS wc = { 0 };
wc.lpfnWndProc = WndProc;
wc.hInstance = hInstance;
wc.lpszClassName = L"MemoryT2Class";
if (!RegisterClass(&wc)) return 0;
HWND hwnd = CreateWindow(L"MemoryT2Class", L"MemoryT2 - Memory Manager", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT, 380, 220, NULL, NULL, hInstance, NULL);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
// IsDebuggerPresent 후킹 함수
BOOL WINAPI HookIsDebuggerPresent() {
// 디버깅 중이 아님을 반환
return FALSE;
}
// NtQueryInformationProcess 후킹 함수 (수정됨)
NTSTATUS NTAPI HookNtQueryInformationProcess(
HANDLE hProcess,
PROCESSINFOCLASS ProcessInformationClass,
PVOID ProcessInformation,
ULONG ProcessInformationLength,
PULONG ReturnLength
) {
NTSTATUS status = OriginalNtQueryInformationProcess(
hProcess,
ProcessInformationClass,
ProcessInformation,
ProcessInformationLength,
ReturnLength
);
// ProcessDebugPort만 확인 (유효한 멤버)
if (ProcessInformationClass == ProcessDebugPort) {
memset(ProcessInformation, 0, ProcessInformationLength);
}
return status;
}
Подробнее здесь: https://stackoverflow.com/questions/794 ... om-the-win
Я не могу найти память, используя функцию ReadProcessMemory () из API Win32 ⇐ C++
-
- Похожие темы
- Ответы
- Просмотры
- Последнее сообщение
-
-
Я не могу найти память, используя функцию ReadProcessMemory () из API Win32
Anonymous » » в форуме C++ - 0 Ответы
- 6 Просмотры
-
Последнее сообщение Anonymous
-