들어가며
"게임사는 핵도 안막고 뭐하는거야?" 왜 게임핵은 아직도 근절되지 않는 것일까요.
게임을 즐기다 불법 프로그램 사용자에게 허무하게 당해본 유저라면 누구나 한 번쯤 품어봤을 의문입니다.
게임사들은 막대한 비용을 들여 안티치트(Anti-Cheat) 솔루션을 도입하고 방어막을 구축하지만, 해커들은 비웃기라도 하듯
매번 새로운 우회 기법을 들고 나옵니다. 마치 아무리 높은 담을 쌓아도 그보다 긴 사다리가 나타나는 것처럼요.
과거의 게임 핵이 단순히 내 메모리 값을 고치는 소박한 수준이었다면, 오늘날의 해커들은 더이상 사용자 영역(Ring 3)에 머물지 않습니다. 운영체제의 심장부인 커널(Ring 0)을 장악하고, 물리적 하드웨어(DMA)를 직접 조작하며, 인공지능(YOLO)을 동원해 시스템 바깥에서 게임을 통제합니다. 그것도 모자라 이제는 운영체제 그 아래, 하드웨어와 소프트웨어의 경계인 하이퍼바이저(Ring -1)까지 넘보고 있습니다.
이 글에서는 안티치트 우회 기술의 역사적 흐름을 짚어보려 합니다. 아주 기초적인 메모리 조작부터 시작해
C/C++ 기반의 후킹, 커널 드라이버의 한계, 그리고 현재의 통제 불능 상태에 이르기까지. 해커들이 어떤 방식으로 방어망의 빈틈을
파고 들었는지 그 진화의 과정을 해부해 보겠습니다.
본 글은 게임 보안의 공격 원리를 이해함으로써 방어 관점을 넓히기 위한 순수한 기술적 학습 목적으로 작성되었습니다. 실제 온라인 게임에서의 불법 프로그램 사용은 관련 법률에 의해 처벌받을 수 있습니다.
유저모드 기법들
NOP / RET
가장 원시적인 방법입니다.
NOP (No Operation)은 아무것도 안하는 어셈블리 명령어로 opcode는 0x90입니다.
예시로
안티치트 검사 코드가
JE 종료루틴 (조건이 맞으면 게임종료)
NOP으로 덮어쓰게 되면 아무것도 하지 않게되며 검사자체가 무력화 됩니다.
RET은 0xC3 이며 함수 자체를 즉시 반환시키는 방법입니다.
안티치트의 검사 함수가
PUSH EBP
MOV EBP, ESP
...(검사코드)
라면 첫 바이트를 C3으로 변경하면 함수가 시작되자마자 반환을 할거고 밑의 코드는 실행이 되지 않을겁니다.
검사 함수가 아무것도 안하고 반환이 되며, 무력화 되는 것이죠.
지금보면 이런 보안은 있으나마나 한데 왜 넣어두었나라는 생각이 들 수도 있겠습니다만, 이런 시대도 존재했다는게 신기합니다.
우회 난이도야 굉장히 낮았고, 기초 어셈블리만 알면 되었습니다.
이렇게되자 CRC 검사가 도입되며 메모리 변조를 감지하기 시작했습니다.
무결성 검사를 속여라 - CRC 우회와 후킹의 등장
CRC란 무엇일까요
게임사들이 메모리 패치를 막기 위해 도입한 첫 번째 본격적인 방어 수단이 바로 CRC(Cyclic Redundancy Check) 무결성 검사 입니다. 원리는 단순합니다. 게임이 실행될 때 자신의 코드 영역을 일정 주기로 검사해, 값이 바뀌었다면 변조로 간주하고 게임을 종료시키는 것입니다.
게임 실행
> 코드 영역 체크섬 저장
> 주기적으로 동일한 계산 반복
> 값이 다르면 종료
단순 NOP/RET 패치가 이 시점부터 통하지 않게 됩니다. 메모리를 건드는 순간 CRC가 달라지기 때문입니다.
인라인 후킹으로 CRC를 속이는 방법
해커들의 답은 영리했습니다. 메모리를 직접 수정하는 대신, CRC를 계산하는 함수 자체를 가로채는 것입니다.
CRC 검사 흐름:
게임: CalcCRC(코드영역) 호출
> 결과값 비교
> 다르면 종료
인라인 후킹 적용 후:
게임: CalcCRC(코드영역) 호출
> 후킹된 함수가 가로챔
> 항상 원본 CRC값 반환
> 게임: "정상이네" 판단
> 실제 메모리는 변조된 상태
즉 게임을 눈 먼 상태로 만들어버리는 것입니다.
인라인 후킹 동작 원리
원본 CalcCRC 함수:
55 8B EC ... (원본 코드)
후킹 후:
E9 XX XX XX XX (JMP 내코드로)
...
내 코드:
원본 CRC값 하드코딩해서 반환
> 어떤 메모리 상태든
항상 같은 값 반환
트램폴린을 통해 원본 함수도 정상 호출할 수 있게 유지하면서, 반환값만 조작하는 것이 핵심입니다.
더 영리한 변형 - 타이밍 공격 -
일부 해커들은 후킹 없이도 CRC를 우회했습니다. CRC 검사 주기를 파악해서 검사 직후에 메모리를 수정하고, 다음 검사 직전에 원복하는 타이밍 공격입니다.
CRC 검사 (통과) ✓
↓
메모리 수정 (치트 활성화)
↓
다음 CRC 검사 직전
↓
메모리 원복
↓
CRC 검사 (통과) ✓
↓
다시 수정...반복
Sleep(1000) 같은 고정 주기를 사용하는 안티치트에 효과적이었습니다.
또 다른 변형 - 원본 복사본 유지
게임 코드 원본을 별도 메모리에 복사
> CRC 계산 함수 후킹
> 검사할 때는 원본 복사본 읽도록
> 실제 실행 코드는 수정된 상태 유지
CRC 함수 입장:
"항상 원본 읽으니까 정상이네"
실제 실행:
수정된 코드가 동작
안티치트의 대응
랜덤 타이밍 검사를 통해 타이밍 공격을 방어하고, 후킹 패턴을 스캔해 후킹 자체를 탐지하기 시작했습니다.
함수 주소를 검증해 CRC 함수가 원래 모듈 범위 안에 있는지 확인하고 외부 코드를 가리키면 탐지했습니다.
다중 CRC를 이용해 여러 쓰레드에서 동시 검사를 진행하며, 서로 다른 알고리즘으로 검사하기도하고 하나를 속여도
나머지에서 탐지하는 방식도 사용되었습니다.
하드웨어 브레이크포인트
CRC를 우회하기가 힘들어지자 메모리를 변조하지 않는 방식이 등장합니다.
Hardware BreakePoint 를 이용해 EIP를 변조하는 방식이었습니다.
왜 이게 CRC를 완벽히 우회했나
기존 인라인 후킹:
> 함수 앞 5바이트를 JMP로 덮어씀
> 코드 섹션 메모리가 변조됨
> CRC 계산하면 값이 달라짐
> 탐지됨
DR0~DR3 방식:
> 메모리를 전혀 수정하지 않음
> CPU 레지스터만 건드림
> CRC 계산해도 원본과 동일
> 탐지 불가능
동작 원리
CPU 디버그 레지스터:
DR0: 브레이크포인트 주소 1
DR1: 브레이크포인트 주소 2
DR2: 브레이크포인트 주소 3
DR3: 브레이크포인트 주소 4
DR6: 상태 레지스터
DR7: 제어 레지스터 (활성화)
특정 주소에 브레이크포인트 설정
> CPU가 해당 주소 실행 직전
EXCEPTION_SINGLE_STEP 발생
> 예외 핸들러에서 EIP 변조
> 내 코드로 점프
> 메모리는 원본 그대로
코드 예시
#include <Windows.h>
// 내 코드로 실행 흐름 변경할 주소
PVOID g_TargetAddr = nullptr;
// 실행할 내 함수
PVOID g_MyFunc = nullptr;
...
// 현재 스레드의 컨텍스트 가져오기
CONTEXT ctx = {};
ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS;
GetThreadContext(GetCurrentThread(), &ctx);
// DR0에 타겟 주소 설정
ctx.Dr0 = (DWORD)targetAddr;
// DR7로 DR0 활성화
// 실행 브레이크포인트 (길이 1바이트)
ctx.Dr7 = 0x00000001;
SetThreadContext(GetCurrentThread(), &ctx);
...
void __declspec(naked) MyFunc()
{
__asm
{
// 원본 함수 로직 대신
mov eax, 0x12345678
ret
}
}
단점이라면 DR0 ~ DR3 로 총 4개이며 치트 입장에서는 4개의 함수만 후킹 가능합니다. 즉 4개의 치트만 사용가능하다는 것이죠.
안티치트의 대응
이 기법이 퍼지자 안티치트들은 대응하기 시작했습니다.
디버그 레지스터를 감시해 DR0~DR3를 확인해 치트를 의심하기 시작했고, 강제로 DR을 0으로 초기화 하기도 했습니다.
VEH 핸들러 감시를 통해 의심스러운 핸들러를 제거하기도 하였으며, DR 레지스터 접근 자체를 커널에서 모니터링 했습니다.
IAT/EAT 후킹
Import Address Table 후킹
DLL이 임포트하는 함수 목록을 내 함수로 교체하는 방식
예를 들어 game.exe가 사용하는 kernel32.dll!ReadFile 주소를 내 함수로 변경해 파일 읽기를 가로채며
인라인 후킹보다 쉽고 DLL 로드 시점에 적용되었습니다.
VTable 후킹
COM 인터페이스 기반 API 후킹으로
D3D9 IDirect3DDevice9의 VTable을 직접 수정해 EndScene, DIP 등 후킹해 렌더링 파이프라인에 개입하는 방식입니다.
포스팅 했던 Counter-Strike : Source 의 월핵을 만들때 사용한 방식이기도 합니다.
https://imoracle.tistory.com/67
[게임핵의 원리] 월핵은 어떻게 만들어지는가 -DirectX 후킹 원리 분석- 최종
들어가기에 앞서...본 포스팅은 학술적 연구 및 리버싱 학습을 목적으로 작성되었습니다. 모든 테스트는 오프라인(Local Bot Match) 환경에서 진행되었으며, 실제 멀티플레이 서버나 타인의 게임 경
imoracle.tistory.com
이와 같이 유저모드에서 치트를 사용하는데 한계에 봉착하면서 커널로 내려가기 시작했습니다.
화면 밖의 전쟁, 오버레이(Overlay)
메모리를 읽어낸 뒤, 화면에 적을 표시(ESP/WallHack)하는 방식입니다.
메모리 조작없이 좌표를 읽어 오버레이 창에 그려주는 방식으로 메모리 변조 없이 읽기만으로 ESP/WallHack을 구현 가능합니다.
포스팅 했었던 지뢰찾기 월핵 만들기에서 사용된 기법이 이 오버레이 기법입니다.
https://imoracle.tistory.com/51
[Game] 지뢰찾기 월핵 제작 - 2 -
https://imoracle.tistory.com/50 [Game] 지뢰찾기 월핵 제작 - 1 -https://imoracle.tistory.com/51 [Game] 지뢰찾기 월핵 제작 - 2 -이어서이제 메모리를 읽어와서, 2차원 배열에 값을 넣어주어야 합니다. 프로그램을
imoracle.tistory.com
하지만 게임사가 오버레이창을 탐지하기 시작하며 이또한 사용하기가 어려워집니다.
커널 레벨 전쟁
System Service Dispatch Table
윈도우 시스템 콜 테이블을 직접 수정하는 방식으로 32비트 운영체제에서만 사용이 가능했습니다.
당시엔 PatchGuard가 없었기 때문에 커널 테이블을 직접 수정이 가능했고
치트 / 안티치트 둘 다 사용했습니다. 자유로운 시대였죠
64비트 전환과 PatchGuard 가 등장하며 SSDT 직접 수정이 불가능해지면서 커널 코드 패치가 불가능해졌고, 수정시
즉시 BSOD를 띄우며 SSDT후킹은 32비트의 전유물로 그렇게 잊혀져 갑니다.
ObRegisterCallbacks
MS 공식 커널 API 로
프로세스/쓰레드 핸들 생성을 커널 레벨에서 가로채 OpenProcess 권한을 제거하고, 메모리 접근을 차단했습니다.
CheatEngine에서 game.exe를 들여다 볼때 스캔이 되지않고, 메모리뷰에서 ?? 로 뜨는 이유가 이것입니다.
초기에는 해당 기능을하는 sys파일을 StartService 되지않도록 해서 우회하는 방법도 존재했던 시절이 있었습니다.
WDDM
Windows Display Driver Model
D3D와 GPU 사이 레이어를 후킹해 게임 프로세스 밖에서 동작해 안티치트의 감시 범위를 벗어나서 렌더링 파이프라인을 조작하는 방식입니다. 게임 프로세스 메모리는 깨끗하며 D3D VTable 변조도 없기에 초기 등장했을때 탐지하는데 어려움을 겪지 않았나 생각이 듭니다.
BYOVD의 등장
Bring Your Own Vulnerable Driver는
취약점이 존재하는 정식 서명 드라이버를 활용해 커널 메모리 읽기/쓰기 권한을 획득합니다.
그 후 안티치트의 콜백을 제거하고 CRC 검사 무력화와 동시에, 모든 보호를 우회 가능하단 점에서 굉장히 강력하며 골머리 앓는
대표적인 기법입니다.
https://imoracle.tistory.com/70
[AntiCheat] 취약 드라이버를 이용한 커널 레벨 안티치트 우회 -1-
들어가며게임 해킹과 보안의 역사는 끊임없는 '창과 방패'의 대결입니다. 과거의 게임 핵(Hack)들이 단순히 유저 모드(User-Mode, Ring 3)에서 메모리를 변조하는 수준에 머물렀다면, 오늘날의 안티치
imoracle.tistory.com
https://imoracle.tistory.com/71
[AntiCheat] BYOVD 기법을 이용한 ObRegisterCallbacks 기반 커널 안티치트 우회 실습
들어가며일반적으로 게임 보안 프로세스인 안티치트(Anti-Cheat)는 크게 유저 모드(User-Mode)와 커널 모드(Kernel-Mode) 기반으로 나뉩니다. 유저 모드 안티치트는 과거부터 메모리 후킹이나 코드 인젝
imoracle.tistory.com
BYOVD를 통한 우회 원리
IOCTL을 이용한 콜백(Callback) 무력화
보안 프로그램이나 안티치트는 프로세스 생성, 쓰레드 생성, 핸들 접근 등을 감시하기 위해 커널에 콜백을 등록합니다.
BYOVD를 사용하면 취약한 드라이버에 특정 IOCTL 명령을 보내 커널 메모리에 임의의 값을 읽고 쓸 수 있는 권한을 얻게 되며,
이를 통해 안티치트가 등록한 콜백 배열을 찾아 지워버리거나, 자신의 코드로 우회시켜 버릴 수 있습니다.
윈도우 10과 윈도우 11 23H2에서 '부분적으로' 동작하는 이유
이러한 기법이 특정 윈도우 빌드나 환경에서만 부분적으로 동작하거나 블루스크린을 유발하는 이유는 마이크로소프트의 방어 메커니즘과 OS 구조의 변화 때문입니다.
취약한 드라이버 차단 목록
마이크로소프트는 악용되는 드라이버의 해시와 서명을 지속적으로 차단 목록에 업데이트합니다.
물론 제로데이 취약점 드라이버라면 11에서도 뚫릴 수 있습니다.
HVCI / VBS
윈도우11 에서는 가상화 기반 보안 및 HVCI(Hypervisor-Enforced Code Integrity)가 기본적으로 켜져 있습니다. HVCI 가 켜져 있으면 커널 메모리 영역을 수정하거나 실행 불가능한 영역에서 코드를 실행하려고 할 때 하이퍼바이저 단에서 이를 차단하고 블루스크린을 띄웁니다.
즉, 이러한 방어 메커니즘이 적용되어 있지 않은 윈도우 10의 경우에는 사용이 가능한 이유입니다.
간혹 지나가다 보면 치트프로그램의 운영체제 조건에 "Win 10 사용가능, Win 11 미지원" 이라는 문구를 보게된다면
BYOVD 기반이 확실합니다.
통제불능의 시대
소프트웨어적인 방어가 커널 레벨에서도 고도화되자, 아예 운영체제 밖으로 벗어나는 기법들이 주류가 되었습니다.
DMA (Direct Memory Access)
오픈소스를 활용해, FPGA 기반의 PCIe카드를 메인보드에 장착합니다.
이 카드는 CPU와 OS를 무시하고 물리 메모리 공간을 직접 읽어 두 번째 PC로 전송합니다.
게임이 실행되는 PC에는 어떠한 코드도 실행되지 않습니다.
즉, 메모리를 읽어 ESP/WallHack/Aimbot을 구현하기에 탐지해내기가 매우 어렵습니다.
현재의 안티치트들도 매우 골머리를 앓고있는 기법입니다.
안티치트가 DMA를 막기 위해 VT-d를 활성화해 메모리 접근 구역을 제한하고는 있지만, 펌웨어를 스푸핑하여 이를 우회하는
창과 방패의 싸움이 한창입니다.
하이퍼바이저 (Hypervisor)
Intel VT-x/AMD-V 기술을 이용해 치트가 운영체제 밑바닥(Ring -1)에서 하이퍼바이저로 동작합니다.
EPT 조작을 통해 안티치트가 읽는 메모리 페이지와 치트가 읽는 페이지를 다르게 보여주는 궁극의 은폐 기술입니다.
안티치트 드라이버(Ring 0)가 아무리 윈도우 커널을 뒤지고 다녀도, 하이퍼바이저(Ring -1)가 보여주는
'가짜 현실'만 보고 "아, 우리 게임은 깨끗하구나"라고 속게 됩니다.
운영체제 자체가 속고 있기 때문에, 그 안에서 실행되는 안티치트는 자신이 해킹당하고 있다는 사실조차 인지할 수 없는 극한의 은폐 기술인 셈입니다.
하지만, 구현하기가 극도로 어려우며 OS 아래에 존재하므로 OS가 제공하는 API를 전혀 쓸 수 없습니다.
이런 기법이 풀리게 된다면 안티치트의 입장에서는 정말 막막할거라 생각되네요.
YOLO
메모리 접근을 포기하고, AI모델을 이용해 적을 인식합니다.
이전 포스팅에서 YOLO를 이용한 에임봇을 만들어 보았습니다
https://imoracle.tistory.com/68
[AI 게임핵의 원리] YOLOv8로 CS:S 에임봇 구현하기
들어가며이전 포스팅에서 D3D9 HOOKING 으로 렌더링 파이프라인을 건드려봤다면, 이번엔 전혀 다른 접근법입니다.게임 내부를 전혀 건드리지 않고 오직 화면 캡처와 AI만으로 에임봇을 구현합니다.
imoracle.tistory.com
메모리나 파일 시스템을 전혀 건드리지 않아 사실상 탐지가 불가능에 가깝습니다.
마치며
지금까지 단순한 메모리 주소 스캐닝부터 커널의 심연(Ring 0), 그리고 하드웨어(DMA)와 하이퍼바이저(Ring -1)의 영역으로 확장되어 온 안티치트 우회 기술의 궤적을 쫓아보았습니다.
이 길고 치열한 기술적 진화가 말해주는 단 하나의 진실은 바로 "클라이언트(유저의 PC) 환경은 결코 신뢰할 수 없다"는 보안의 대원칙입니다. 서버에서 대부분 관리하는 게임의 경우는 강력한 핵들이 존재하지 않습니다만, FPS 게임 같이 지연속도가 중요한 게임에서는 서버를 활용할 수 없다는게 문제죠. 서버 사이드 권한이 강화되고는 있지만..
기계적인 입력이나 비정상적인 동체 시력과 속도를 잡아내는 AI기반 행동패턴분석이 다가오지 않을까 생각됩니다.
오늘도 완벽한 방어망을 구축하기 위해 뜬눈으로 밤을 지새우는 모든 보안 엔지니어들과, 공정한 게임 환경을 바라는 플레이어들에게 응원을 보내며 글을 마칩니다. 부족한 글 끝까지 봐주셔 감사합니다.
'Reverse Engineering > GAMEHACK' 카테고리의 다른 글
| [AntiCheat] 취약 드라이버를 이용한 커널 레벨 안티치트 우회 -1- (3) | 2026.04.08 |
|---|---|
| [AI 게임핵의 원리] YOLOv8로 CS:S 에임봇 구현하기 (0) | 2026.03.30 |
| [게임핵의 원리] 월핵은 어떻게 만들어지는가 -DirectX 후킹 원리 분석- 최종 (0) | 2026.03.27 |
| [게임핵의 원리] 월핵 제작기 및 월핵에 관해서 (D3D 월핵, OpenGL) -1- (0) | 2026.03.27 |
| [게임핵의 원리] 월핵 제작기 및 월핵에 관해서 -0- (4) | 2025.07.18 |