API Hooking 에 대하여
API Hooking 이란, API 함수를 가로채어 조작하는 기술을 말합니다.
일반적으로 디버깅, 리버스 엔지니어링, 게임 치트 를 하는데 쓰입니다.
API Hooking 은 본래의 implementation에 동작을 추가하거나 변형하여 원래 수행해야할 동작을 하지 못하게 하거나, 보완하여 동작하게 합니다.
Trampoline
전통적인 API Hooking을 수행하는 방법입니다. Trampoline은 특정한 코드 구역으로 jumping 하는 shellcode를 말합니다.
Trampoline의 shellcode가 함수의 시작에 삽입되어 있으면, 그 함수는 hooked 됩니다.
hooked된 함수가 호출되면, trampoline shellcode가 대신 동작합니다. 그리고 실행 흐름이 다른 주소로 전달되고 변경되어 대신 다른 함수가 실행됩니다.
Inline Hooking
Inline hooking은 Trampoline-besed hooking의 다른 접근방식으로,
다른 점은 inline hook은 본래의 실행 흐름으로 돌아온다는 점입니다.
보다 복잡한 구현이나 잠재적으로 유지 보수가 어려울 때 inline hook 은 더욱 효과적입니다.
Minhook 이란
Minhook 이란, C언어로 작성된 hooking library로, api hooking을 할 때 사용되는 library입니다.
x86/x64 Windows 에서 돌아가는 32-bit 와 64-bit 두 architecture 모두 호환 되는 library입니다.
다른 api hooking library에 비하면, 더 간단하고 가벼운 구현으로 작업을 하기 쉽게 만들어줍니다.
드워프 포트리스
드워프 포트리스 라는 게임이 있습니다.
7명의 드워프와 함께 시작하며, 드워프에게 명령하여 요새를 짓고, 확장하여 자신만의 나라를 만드는것이 목표인 게임입니다.
이 게임은 영어로 되어 있는데다가, 문장이 고정되어 있는게 아닌 생성형으로 되어 있어 번역을 하기 매우 어렵게 되어있습니다.
앞으로, 이 게임의 번역 프로세스에 대해 설명하겠습니다.
문제 1. Internal Function
드워프 포트리스는 게임 내부 함수에서 문자열을 조립하여 SDL2 에 넘겨서 화면에 뿌려주는 방식을 채택했습니다.
문제는, SDL2.dll의 함수를 hooking하면 이미 이미지화 된 문자열을 받기에 이 문자열을 식별하려면 이미지 분석을 해야 하는 방법 밖에 없습니다.
그렇기에 제대로된 문자열을 hooking 하려면 내부 함수를 hooking 해야 하는데 이는 API가 아니므로 리버스 엔지니어링을 통해 함수를 찾아야 합니다.
치트 엔진
치트 엔진을 사용하여 인게임의 타이틀의 문자열을 검색하여 함수의 초기 부분으로 가보면,

이와 같이 함수 entry를 발견할 수 있습니다.
여기서 함수 entry는
"\x48\x89\x5C\x24\x08"
"\x48\x89\x6C\x24\x10"
"\x48\x89\x74\x24\x18"
"\x57"
"\x41\x56"
"\x41\x57"
"\x48\x83\xEC\x20"
"\x4D\x8B\xF0"
"\x48\x8B\xEA"
"\x48\x8B\xF1"
입니다.
RVA
함수에는 Offset이 있습니다.
위 사진에서 보이는 +AB2240이 함수 RVA 입니다.
이 offset을 알면 우리가 원하는 api hooking이 가능합니다.
문제는, 이 함수의 offset은 앱이 업데이트 될 때마다(또는 버전마다) 달라진다는 점입니다.
그래서 우리는 프로그램 내에서 이 offset을 찾는 프로그램을 만들어야 합니다.
Offset 찾기
RVA를 찾으려면 먼저 추출해뒀던 함수 entry를 사용하면 됩니다.
uintptr_t foundAddress_ptrst = MemoryScanner::FindPattern(hProcess, moduleBase, scanSize, 34, pattern_ptrst, mask_ptrst);
uintptr_t foundAddress_addst = MemoryScanner::FindPattern(hProcess, moduleBase, scanSize, 30, pattern_addst, mask_addst);
이 코드로 패턴을 찾아서, 각 함의 주소를 반환하면, 이제 원하는 함수를 hooking 할 수 있게 됩니다.
문제 2. Print
이제 문자열을 hooking하여 번역할 수 있게 되었습니다.
그런데 드워프 포트리스는 기본적으로 영어로 된 게임이므로 한글 인코딩을 지원하지 않습니다.
한글을 화면에 뿌려주려면 하나의 문제가 더 있습니다. 바로 위치 입니다.
우리는 그냥 소설을 번역하는게 아니라, 게임을 번역하는 것이기 때문에 이 글자의 위치를 알아내어 화면에 뿌려줘야 합니다.
우선 메모리 맵을 봐야 합니다.
if (val > 1 && val < 4000) {
char debugBuf[64];
sprintf_s(debugBuf, "[0x%X]: %d", i * 4, val);
TextRenderCommand cmd;
cmd.text = debugBuf;
cmd.x = 10;
cmd.y = y_pos;
cmd.r = 0; cmd.g = 255; cmd.b = 0;
g_renderQueue.push_back(cmd);
y_pos += 12;
if (y_pos > 800) break;
}
이 코드로, 메모리 맵을 보면
int grid_x = *(int*)((char*)gps + 0x84);
int grid_y = *(int*)((char*)gps + 0x88); // +4 offset
int tile_w = *(int*)((char*)gps + 0x1D8);
int tile_h = *(int*)((char*)gps + 0x1DC); // +4 offset
0x84, 0x88이 grid_x/grid_y 0x1D8, 0x1DC가 tile_w/tile_h 인걸 확인할 수 있습니다.
이 값들을 기반으로 Texture를 만들어 화면에 SDL2를 이용해 뿌려주면 우선 기술적인 부분은 해결됩니다.
문제 3.번역
하지만.. 한가지 문제가 또 남아 있습니다.
번역입니다. 앞서 말씀드렸다시피 이 게임은 문장을 생성합니다.
그렇기 때문에 일반적인 단순 문자열 치환 방법으로 번역을 하면 굉장히 어색해집니다.
API를 사용해 값을 외부 플랫폼을 통해 번역을 하는 방법도 있습니다. 이 방법은 비용이 많이 드는 단점이 있습니다.
여기서, 무료로 번역할 수 있는 방법이 한 가지 있습니다.
애플
애플에는 기본적으로 번역 앱이 있습니다. 무료이므로 간편하게 쓸 수 있다는 장점이 있습니다.
swift에도 translation api가 있어 애플 기기만 있다면 무료로 번역을 할 수 있습니다.
이 점을 이용하여 번역 서버를 만들어서 드워프 포트리스 dll에 접속하게 하면 번역을 무료로 진행할 수 있습니다.
결론
이렇게 해서 게임 api hooking을 알아봤습니다.
쓰시는 분이 없을 것 같아서 애플 맥 번역 서버는 배포를 하지 않았지만, glossary 기반 번역 로직을 가지고 있는 dll은 github에 배포를 해놓았습니다.
https://github.com/4st3risk/DF_Korean
GitHub - 4st3risk/DF_Korean: 이 프로젝트는 드워프 포트리스의 한글 번역을 위해 만들어졌습니다.
이 프로젝트는 드워프 포트리스의 한글 번역을 위해 만들어졌습니다. Contribute to 4st3risk/DF_Korean development by creating an account on GitHub.
github.com
사용법은 Release에 적혀 있습니다.
혹시 사용하실 분 계시면 배포해드릴 테니 댓글 남겨주세요.
'IT' 카테고리의 다른 글
| Syscall - 커널의 소통 창구 (0) | 2026.06.03 |
|---|---|
| IAT Hiding (0) | 2026.05.30 |
| Classic APC Injection (0) | 2026.05.25 |
| Process, Thread Enumeration (0) | 2026.05.25 |
| API Hooking with Custom structure (0) | 2026.05.24 |