에임류 , 월핵류를 제외하곤 플레이에 영향을 주는 대표적인 핵이 또 무엇이 있는가?
'SpeedHacking'
약 20여 년 전만 하여도 Game은 Online 게임보단 Single 게임이 주류를 이뤘다.
이때 Single 게임은 스토리 모드, 퀘스트 같은 컨텐츠를 주로 하였는데
단지 게임을 빨리 클리어하고 싶다던지 좀 변칙적인 게임을 즐기기 위해 Game Hacking이 등장했다.
추 후 Online 게임이 등장하면서 Online게임들이 주류를 이루게 되는데
게임은 더 이상 혼자만 하는 것이 아닌 남들과 같이하는 , 경쟁하는 구도로 바뀌게 되면서
게임 중독성 및 경쟁의식을 강하게 키워 주었다.
공평한 조건에서 시작하는 Online 게임은 남들과 달리 변칙적인 행동이 있어야 게임 승산이 커지는 건 당연한 일이었고
이 계기로 사람들은 GameHacking에 점점 관심을 가지기 시작한다.
그때 대표적으로 한 가지 떠오르는 핵이 바로 스피드해킹이다.
스피드해킹은 다른 플레이어보다 빠르게 움직이며 말도 안 되는 속도로 몬스터를 사냥하거나
맵 필드를 이동하며 퀘스트를 수행하는 등 게임 플레이에 있어 매우 큰 영향을 줬다.
이는 현대인 지금도 Online게임이나 Single게임에서나 SpeedHack을 사용하는 유저가 주로 발견되고 있으며
이 때문에 여러 게임 사나 보안솔루션회사에서는 이 SpeedHack을 차단하기 위한 여러 연구를 하며
SpeedHack유저를 자동으로 탐지하여 차단할 수 있는 AntiSpeedHack 알고리즘으로
악성유저를 차단 하는 등 여러 사례를 보이고 있다.
https://www.edaily.co.kr/news/read?newsId=01679366580050640&mediaCodeNo=257
안철수연구소, 스피드핵 감지 방법 특허 취득
안철수연구소(053800)는 컴퓨터시스템 내부시간 변경 감지 방법에 관한 특허를 취득했다고29일 공시했다.안철수연구소는 "이번 발명은 온라인게임 등에서 컴퓨터시스템 시간 정보를 변경해 프로
www.edaily.co.kr
그럼 SpeedHacking이 무엇인지 알았으니 스피드핵은 어떤 원리로 동작할 까?
이번 글에선 SpeedHacking에 대해 알아보려 한다.
'SpeedHacking의 동작 원리'
1. 하드웨어 시스템 속도를 전체적으로 가속화시켜 속도를 늘리는 방법이 있다.
해당 방식은 하드웨어에 안 좋은 영향을 줄 수 있으므로 현재는 잘 사용되지 않는다고 한다.
8254 PIT 칩(Programmable Interval Timer) 값 조작
2. 시간 관련 함수 후킹
프로세스 개별 적으로 속도 조작이 가능하며 시간 관련함수를 후킹 하여 속도를 조작하는 일반적인 스피드 해킹이다.
현재는 기법이 많이 알려짐으로써 대부분 게임에선 기본적으로 탐지하는 코드들이 존재한다.
Win32 Api에 후킹을 하는 방식이라 따로 수고스러운 과정이 필요 없다.
3. 게임 메모리 내에서 Speed를 담당하는 변수 데이터를 조작
리버싱을 통하여 게임 클라이언트 메모리 내에서 이동속도를 담당하는 변수를 찾아 데이터를 조작한다.
이 또한 게임마다 이동속도를 체크하는 검사 코드가 존재할 것이고
2번째 방법과는 달리 직접 게임 클라이언트를 분석해서 찾아야 하는 수고가 필요하다.
'시간 관련 함수 후킹'
윈도우 운영체제에서 시간(Timer) 관련 함수는 어떤 게 있을까
주로 아래의 API들을 많이 사용한다.
GetTickCount()
timeGetTime()
QueryPerformanceCounter()
게임 개발자들은 스킬, 공격 딜레이 , 이동속도 같은 요소를 구현할 때
주로 일정한 딜레이 타임을 주기 위해
현재 시간을 체크하여 특정 딜레이 타임이 지나야 행동을 할 수 있도록 설계한다.
이때 딜레이 타임을 가져오기 위해 System 상 Time을 가져오는 경우가 일반적이기 때문에
주로 위의 3가지 Api함수를 사용한다.
또한 rdtsc 타임스탬프를 반환하는 레지스터도 존재하는데 안티디버깅 루틴에도 사용된다.
이때 사용되는 시간 관련 함수를 후킹 하여 내가 원하는 시간으로 배속한다면?
내가 원하는 배속으로 이동하며 딜레이 없이 스킬을 난사하며 맵 필드를 활개 치며 다닐 수 있을 것이다.
이게 시간 관련 함수를 조작하는 스피드핵의 기본적인 원리이다.
TimeGetTime() 함수는 시스템 시간을 밀리 초 단위로 반환한다.
즉 s_Time , f_Time 변수에 TimeGetTime()의 반환 값이 담긴다 가정한다.
첫 번째로 호출 후 s_Time에 밀리 초 단위로 시작시간을 반환을 받고 두 번째로 호출 후 f_Time에 종료시간을 반환을 받는다.
f_Time - s_Time 하게 되면 수행 시간을 구할 수 있다.
※이때 초 단위로 반환받고 싶다면 timeGetTime() / 1000 , timeGetTime() * 0.001f로 수행하면 된다.
이처럼 전 시간 - 후 시간 차로 딜레이 타임을 생성하게 되면
시간 관련 함수를 후킹 하여 이 차이를 좁힘으로써 시간이 빠르게 흐른 것처럼 게임을 속여 줄 수 있다.
GetTickCount() 함수는 시스템이 시작된 후 경과된 시간(밀리초)을 반환한다.
이때 GetTickCount()는 반환 값이 DWORD형이기 때문에 약 49.7일간의 카운트를 유지할 수 있고
그 이상은 Overflow가 발생하여 0으로 초기화되는 단점이 존재한다.
이 문제점을 해결하기 위해선 GetTickCount64() 사용한다.
QueryPerformanceCounter() 함수는 현재 CPU의 Tick을 받아올 수 있는 함수이다.
위의 2개의 함수는 오차가 존재하는 경우가 있기 때문에
고사양 타이머인 QueryPerformanceCounter() 함수를 사용한다.
다른 타이머보다 보다 상세한 수행시간을 측정할 수 있다.
'Hooking'
AssultCube 게임을 타겟으로 주로 사용되는 시간 관련 함수 4개에 BreakPoint를 걸어서
해당 게임에선 시간을 계산할 때 어떤 함수를 사용하는지 확인해보았을 때
GetTickCount()
QueryPerformanceCounter()
함수를 사용하는 것으로 보아 두 함수를 Target으로 후킹을 실시해보도록 한다.
Dll Injection 방식으로 실습을 해보았다.
double deltaTime = 1.0;
_tGetTickCount GTC = nullptr;
DWORD GTC_BaseTime = 0, GTC_OffsetTime = 0;
_tQueryPerformanceCounter QPC = nullptr;
LARGE_INTEGER QPC_BaseTime = LARGE_INTEGER(), QPC_OffsetTime = LARGE_INTEGER();
GTC = &GetTickCount;
GTC_BaseTime = GTC();
GTC_OffsetTime = GTC_BaseTime;
QPC = &QueryPerformanceCounter;
QPC(&QPC_BaseTime);
QPC_OffsetTime.QuadPart = QPC_BaseTime.QuadPart;
우선 Win32 Api 함수를 후킹 하기 위해 두 함수의 포인터를 가져와주었다.
DWORD WINAPI hGetTickCount()
{
return GTC_OffsetTime + ((GTC() - GTC_BaseTime) * deltaTime);
}
BOOL WINAPI hQueryPerformanceCounter(LARGE_INTEGER* lpPerformanceCount)
{
LARGE_INTEGER x;
QPC(&x);
lpPerformanceCount->QuadPart = QPC_OffsetTime.QuadPart + ((x.QuadPart - QPC_BaseTime.QuadPart) * deltaTime);
return TRUE;
}
시간함수의 리턴 값을 조작하기 위하여 original로 반환되는 시간 값에 * deltaTime를
연산을 해줌으로써 시간 값이 배속이 될 수 있도록 작성한다.
deltaTime 변수의 데이터를 바꿔줌에 따라 오르는 속도가 차이 나는 것을 확인할 수 있다.
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)GTC, hGetTickCount);
DetourAttach(&(PVOID&)QPC, hQueryPerformanceCounter);
DetourTransactionCommit();
detours.h를 참조하여 Api함수에 내 Jmp 코드를 설치하여 두 함수가 호출될 때 MyCode로 넘어오게 한다.
GetTickCount() , QueryPerformanceCounter() 함수에 내 Hooking 코드가 설치된 것을 확인할 수 있다.
'마치며'
이처럼 스피드핵을 직접 구현해 보면서 스피드핵을 구현하기 위해선 몇 가지 방법이 존재하지만
그중 하나인 Time 관련 함수를 조작하여 스피드핵이 구현 가능하다는 것을 알 수 있었다.
스피드핵을 탐지하는 방법은 여러 가지가 있겠지만 대표적인 방법으론
서버에서 패킷이 오는 Term을 체크 후 비정상적이라면 스피드핵으로 판별하는 방법이 있을 것이고
클라이언트 내에선 시간의 변화를 체크하는 방법과 Api 후킹을 방지하기 위해
CheckSum 검사를 수행하여 Api 후킹이 되었는지 탐지하는 방법이 있겠다.
'Reversing > GameHacking' 카테고리의 다른 글
GameHacking 4. 에임봇 핵의 동작원리에 대해 (0) | 2023.08.17 |
---|---|
GameHacking 3. ESP 핵의 동작원리에 대해 (5) | 2023.07.19 |
GameHacking 2. WallHack의 동작원리 와 사례 (5) | 2023.07.17 |
GameHacking 1. 게임 핵의 동작 원리 와 사례 (10) | 2023.07.17 |