01/10/2018, 15:12

Hỏi cách lấy Base Address của một Module

Mình không phải dân IT nên mấy thuật ngữ trên có dùng sai mọi người bỏ qua giùm nhé
Vấn đề là mình có debug game Minesweeper (game dò mìn có sẵn trên win) để lấy base address của số lượng bom trong game. Mà cái address sau cùng mình nhận được không phải dạng số mà là dạng chữ: “minesweeper.exe”+000AAA38.

Dạng số mình đã test thành công còn cái này có lên mạng search thì biết nó là Module gì đó. Viết code y như họ mà vẫn không đọc được address đó. Đây là code của mình, không biết sai chỗ nào mong cao nhân giúp đỡ

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

using namespace std;

DWORD_PTR dwGetModuleBaseAddress(DWORD dwProcID, TCHAR *szModuleName);

int main()
{
	DWORD d_address;
	DWORD d_offset[4] = { 0x000AAA38, 0x8, 0x1c8, 0x8 };
	//DWORD d_baseOffset = 0x000AAA38;
	DWORD d_temp;
	DWORD d_BaseAddress;
	int d_value;
	DWORD pid = NULL;

	HWND hwnd = FindWindow(NULL, TEXT("minesweeper"));
	if (!hwnd)
	{
		cout << "Loi roi! Khong dung` dc ham FindWindow" << endl;
	}
	GetWindowThreadProcessId(hwnd, &pid);
	HANDLE d_handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
	if (!d_handle)
	{
		cout << "Loi roi! Khong dung dc ham OpenProcess" << endl;
	}
	d_address = dwGetModuleBaseAddress(pid, _T("minesweeper.exe"));
	for (int n = 0; n < 5; n++)
	{
		if (n == 0)
		{
			ReadProcessMemory(d_handle, (LPCVOID*)d_address, &d_temp, sizeof(d_temp), 0);
		}
		else {
			ReadProcessMemory(d_handle, (LPCVOID*)d_BaseAddress, &d_temp, sizeof(d_temp), 0);
		}
		d_BaseAddress = d_temp + d_offset[n];
	}

	ReadProcessMemory(d_handle, (void*)d_address, &d_value, sizeof(d_value), 0);

	cout << d_value << endl;
	system("pause");
	return 0;
}

DWORD dwGetModuleBaseAddress(DWORD dwProcessIdentifier, TCHAR *lpszModuleName)
{
	DWORD dwModuleBaseAddress = 0;
	HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessIdentifier);
	if (hSnapshot != INVALID_HANDLE_VALUE)
	{
		MODULEENTRY32 ModuleEntry32 = { 0 };
		ModuleEntry32.dwSize = sizeof(MODULEENTRY32);
		if (Module32First(hSnapshot, &ModuleEntry32))
		{
			do
			{
				if (_tcscmp(ModuleEntry32.szModule, lpszModuleName) == 0)
				{
					dwModuleBaseAddress = (DWORD)ModuleEntry32.modBaseAddr;
					break;
				}
			} while (Module32Next(hSnapshot, &ModuleEntry32));
		}
		CloseHandle(hSnapshot);
	}
	return dwModuleBaseAddress;
}
Nguyễn Phạm Anh Quân viết 17:14 ngày 01/10/2018

Theo như link này thì bạn phải build trong môi trường 64 bit (x64) thì mới thành công:
http://forum.cheatengine.org/viewtopic.php?t=557296&sid=b8a27a09465f8d07c31317e67de46709

Tuy nhiên nếu bạn muốn làm tiếp thì phải học khá nhiều đấy, vì cái này là lập trình Windows, process management in Windows, khó hơn lập trình bình thường nữa!

Bạn có thể tham khảo thêm link này https://stackoverflow.com/questions/26572459/c-get-module-base-address-for-64bit-application

*grab popcorn* viết 17:14 ngày 01/10/2018
int main() {
  DWORD d_offset[3] = { 0x000AAA38, 0x18, 0x20}; // Mỗi máy mỗi khác
  void * d_temp;
  void * d_BaseAddress;
  float d_value;
  DWORD pid = NULL;

  HWND hwnd = FindWindow(NULL, TEXT("minesweeper"));
  if (!hwnd) {
    cout << "Loi roi! Khong dung` dc ham FindWindow" << endl;
    return 0;
  }
  GetWindowThreadProcessId(hwnd, &pid);
  HANDLE d_handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
  if (!d_handle) {
    cout << "Loi roi! Khong dung dc ham OpenProcess" << endl;
    return 0;
  }
  d_temp = dwGetModuleBaseAddress(pid, _T("minesweeper.exe"));
// chạy tới 2(i =0, 1) là do ở offset thứ 3 ta lấy value chứ ko lấy giá trị con trỏ nữa
  for(int i = 0; i < 2; i++) {
    d_BaseAddress = d_temp + d_offset[i];
    ReadProcessMemory(d_handle, d_BaseAddress, &d_temp, sizeof(void *), 0);
  }

  d_BaseAddress = d_temp + 0x20;

  ReadProcessMemory(d_handle, d_BaseAddress, &d_value, sizeof(float), 0);
  cout << d_value << endl;
  system("pause");
  return 0;
}

Bạn chạy x64 OS thì compile bằng x64 compiler như anh Quân nói.

明玉 viết 17:21 ngày 01/10/2018

Nếu vùng bộ nhớ đó là static thì chắc cứ viết y chang con số offset lúc đó là được.

kaster viết 17:19 ngày 01/10/2018

Thanks các bạn đã giúp đỡ. Mình mò một hồi cuối cùng cũng ra . Mình sai ở những chỗ sau:

  • Build 64bit (đây là lý do chính). Thanks bạn @hitman17528 đã giúp
  • Vòng lập for bị sai (vì chưa hiểu hết các hàm api) Thanks bạn @drgnz đã giúp
  • Hàm ReadProcessMemory cuối cùng phải dùng biến d_BaseAddress chứ không phải d_address (do sửa nhiều lần nên bị loạn )
    Dưới đây là code đã chạy thành công cho bạn nào muốn thử:
#include <iostream>
#include <windows.h>
#include <tlhelp32.h>
#include <tchar.h>

using namespace std;

DWORD dwGetModuleBaseAddress(DWORD dwProcID, TCHAR *szModuleName);

int main()
{
	DWORD d_address;
	DWORD d_offset[4] = { 0x000AAA38, 0x8, 0x1c8, 0x8 }; //Mỗi máy mỗi khác
	DWORD d_temp;
	DWORD d_BaseAddress;
	int d_value;
	DWORD pid = NULL;

	HWND hwnd = FindWindow(NULL, TEXT("minesweeper"));
	if (!hwnd) {
		cout << "Loi roi! Khong dung` dc ham FindWindow" << endl;
	}
	GetWindowThreadProcessId(hwnd, &pid);
	HANDLE d_handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
	if (!d_handle) {
		cout << "Loi roi! Khong dung dc ham OpenProcess" << endl;
	}
	d_temp = dwGetModuleBaseAddress(pid, _T("minesweeper.exe"));
	for (int n = 0; n < 3; n++) {
		d_BaseAddress = d_temp + d_offset[n];

		ReadProcessMemory(d_handle, (LPCVOID*)d_BaseAddress, &d_temp, sizeof(d_temp), 0);
	}
	d_BaseAddress = d_temp + 0x8;
	ReadProcessMemory(d_handle, (void*)d_BaseAddress, &d_value, sizeof(d_value), 0);

	cout << d_value << endl;
	system("pause");
	return 0;
}

DWORD dwGetModuleBaseAddress(DWORD dwProcessIdentifier, TCHAR *lpszModuleName)
{
	DWORD dwModuleBaseAddress = 0;
	HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessIdentifier);
	if (hSnapshot != INVALID_HANDLE_VALUE)
	{
		MODULEENTRY32 ModuleEntry32 = { 0 };
		ModuleEntry32.dwSize = sizeof(MODULEENTRY32);
		if (Module32First(hSnapshot, &ModuleEntry32))
		{
			do
			{
				if (_tcscmp(ModuleEntry32.szModule, lpszModuleName) == 0)
				{
					dwModuleBaseAddress = (DWORD)ModuleEntry32.modBaseAddr;
					break;
				}
			} while (Module32Next(hSnapshot, &ModuleEntry32));
		}
		CloseHandle(hSnapshot);
	}
	return dwModuleBaseAddress;
}

void * d_temp;
void * d_BaseAddress;

Hai biến này mình thử giống bạn mà bị lỗi vì hàm dwGetModuleBaseAddress mình dùng kiểu dữ liệu DWORD

Dark.Hades viết 17:16 ngày 01/10/2018

Mình nghĩ bạn nên wrap 1 template để get value sau mỗi offset.
Và riêng chỉ cần sử dụng hwnd là đủ để đọc memory rồi, không cần sử dụng dwGetModuleBaseAddress, vì vốn dĩ pid và hwnd đã giữ hết thông tin về game rồi.

Vì dụ:

template<typename T>
    T readMemory(const DWORD address) const
    {
      T value;

      auto r = ::ReadProcessMemory(
            this->m_handle,
            reinterpret_cast<LPCVOID>(address),
            reinterpret_cast<LPVOID>(&value),
            sizeof(T), nullptr
            );
      if (r)
      {
      }
      else
      {
        qDebug() << "Can not read memory";
      }

      return value;
    }

    template<typename T>
    T readMemory(const std::vector<DWORD>& adrs) const
    {
      DWORD nextOffset = *adrs.cbegin();
      for (std::size_t i = 1; i < adrs.size(); i++)
      {
        nextOffset = this->readMemory<DWORD>(nextOffset) + adrs.at(i);
      }

      return this->readMemory<T>(nextOffset);
    }

Khi get chỉ cần:

int Player::getMaxHp() const
{
  std::vector<DWORD> adrs{
    0x145EB34, 0xC, 0x1EC, 0x4, 0x27D8
  };

  return m_gameWindowInfo->readMemory<int>(adrs);
}

Tham khảo: https://github.com/HadesD/AutoTLBB

FindWindow(NULL, TEXT("minesweeper")); -> hàm này nên thay bằng ::GetClassName, dùng Spy++ của vs để lấy class name, như vậy sẽ lấy được hwnd thay vì search theo tên file.

kaster viết 17:28 ngày 01/10/2018

Lần trước thấy bài chìm xuống dưới tưởng nó kết thúc luôn rồi chứ, mình đọc bình luận của bạn lâu rồi mà chưa có thời gian trả lời :D.
Đầu tiên là cảm ơn bạn Dark.Hades trước, nhưng mà trình độ của mình còn hơi gà nên đọc code của bạn chưa hiểu được nhiều lắm :D. Giống như bạn Nguyễn Phạm Anh Quân đã nói, mình phải học thêm rất nhiều. Cái mình đang học bây giờ là tìm base adress của một biến trong chương trình rồi dùng được hàm read và writeprocessmemory là được.
Mình đang tìm hiểu assembly để phục vụ quá trình tìm base address mà chưa biết học thế nào cho hiệu quả. Mấy tài liệu trên mạng thấy mơ hồ quá.
Nếu bạn có tài liệu assembly nào phụ hợp với mục đích trên thì share giùm mình với, cảm ơn nhiều :D.

Bài liên quan
0