Cheating

Wesnoth 해킹하기 (8) DLL Memory Hack

Bithub 2024. 3. 2. 03:07
728x90

Wesnoth 해킹하기 (7) 편에서 external program을 통해 Wesnoth의 가상메모리를 read, write하였고 이를 통해 게임의 재화인 골드를 바꿀 수 있었다.


External Hacking의 한계

아무래도 external program을 통해 게임 메모리를 해킹하는 것이다보니 제약사항이 많다.

예를 들어, ReadProcessMemory API를 통해 API 공식 문서에 의해 지정된 자료형으로만 받아올 수 있다.

게임 골드처럼 간단한 값을 받아올 때는 상관없지만 복잡한 데이터나 클래스를 받아올 때는 굉장히 어려움을 겪을 수 있다.

 

이러한 한계점을 극복하기 위해 DLL injection이 활용된다.

그래서 Wesnoth 해킹하기 (8) 편에서는 DLL injection하는 방법을 소개한다.


DLL이란?

그 전에 DLL이 무엇이고 어떤 기능을 하는지 살펴보자.

DLL은 우선 독자적으로 실행될 수는 없다. 다른 executable에 로드되어야만 한다. 그래서 DLL을 통해 개발자는 하여금 동적으로 로드될 수 있는 라이브러리를 만들 수 있다. 이렇게 DLL로 만든 라이브러리는 다양한 executable에 로드될 수 있어 코드의 재사용성을 올릴 수 있다.

예를 들어, user32.dll은 Windows UI 요소를 조작(띄워거나, 닫는 등)하는 라이브러리다. Windows를 타겟으로 하는 거의 모든 application은 user32.dll을 이용한다.

그리고 DLL은 일반 executable과 차이점이 크게 2가지가 있다.

  • DLL은 부모 프로세스 안에서 실행된다. DLL에서 선언된 변수도 부모 프로세스 메모리에 생성된다.
  • DLL은 main function 대신 DllMain function에서 시작한다. DllMain 함수의 구성은 아래와 같다.
BOOL WINAPI DllMain(
    _In_ HINSTANCE hinstDLL,
    _In_ DWORD     fdwReason,
    _In_ LPVOID    lpvReserved
);

 

 


DLL 개발 방법

이제 이 DLL을 만드는 방법을 알아보자.

1. 우선 Visual Studio에서 빈 프로젝트를 만들어주자. 프로젝트의 이름은 InternalMemoryHack이라고 지어주자.

2. 프로젝트 생성 후 Source Files에 main.cpp를 만들어주자.

이제 프로젝트 빌드 시 executable이 아니라 DLL로 빌드하기 위해서는 몇가지 설정을 건드려줘야 한다.

프로젝트를 우클릭하고 Properties에 진입하자.

 

 

 

3. Configuration Properties - General 탭에서 Configuration Type을 Application(.exe)에서 Dynamic Library(.dll)로 바꿔주자.

 

4. main.cpp에 다음과 같은 코드를 작성해보자.

#include <Windows.h>

void injected_thread() {
    while (true) {
        if (GetAsyncKeyState('M')) {
            // *(*(0x17EECB8 + 0x60) + 0xA90)+0x4
            DWORD* player_base = (DWORD*)(0x17EECB8 + 0x60);
            DWORD* game_base = (DWORD*)(*player_base + 0xA90);
            DWORD* gold = (DWORD*)(*game_base + 4);
            *gold = 999;
        }
        Sleep(1);
    }
}

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
    //MessageBox(0, 0, 0, 0);
    if (fdwReason == DLL_PROCESS_ATTACH) {
        CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)injected_thread, NULL, 0, NULL);
    }

    return true;
}

 

MessageBox는 메시지박스를 출력하는 Windows API다.

int MessageBox(
    HWND    hWnd,
    LPCTSTR lpText,
    LPCTSTR lpCaption,
    UINT    uType
);

 

메시지박스를 띄움으로써 우리는 DLL injection이 정상적으로 이루어졌음을 알 수 있을 것이다.

 

5. F5를 눌러 솔루션 빌드하자.

아래 경로에 dll이 생성된다.

C:\Users\사용자명\source\repos\InternalMemoryHack\Debug\InternalMemoryHack.dll


DLL Injection

이제 DLL을 로드할 차례다.

일반적인 경우라면 LoadLibrary API를 통해 DLL을 주입한다.

하지만 우리는 Wesnoth의 소스코드를 수정할 수 없는데 2가지 대안이 있다.

  • AppInit_DLLs를 이용한다.
    • AppInit_DLL은 Windows의 기능 중 하나로 사용자 정의 DLL을 모든 executable에 주입하는 기능이다.
  • DLL Injector를 사용한다.
    • DLL Injector는 executable의 메모리 안에 thread를 생성하는 프로그램이다.
    • CreateRemoteThread API를 통해 쓰레드를 생성하고 생성된 쓰레드가 LoadLibrary API를 호출하는 방식으로 DLL을 주입할 수 있다.

본 포스트에서는 AppInit_DLLs 기능을 사용하는 방법을 살펴볼 것이다.

 


AppInit_DLLs

AppInit_DLLs 기능을 사용하기 위해서는 BIOS 세팅에서 Secure Boot을 disable시켜주자.

다음, 레지스트리를 수정해주자.

윈도우 + R을 눌러 실행창을 띄우고 regedit을 입력하자.

 

그리고 다음 경로로 이동하자:

컴퓨터\HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows NT\CurrentVersion\Windows

 

 

 

 

AppInit_DLLs 레지스트리를 수정하기 위해 더블클릭.

 

 

레지스트리 값이 빈칸으로 되어 있을텐데 InternalMemoryHack.dll의 경로를 넣어주자.

 

 

다음으로 LoadAppInit_DLLs 레지스트리도 1로 바꿔주자.

 

이제 Wesnoth를 실행하고 DLL이 성공적으로 로드되었는지 확인해보자.

'오류' 메시지박스가 뜬다면 성공적으로 로드된 것이다.