GAMEHACKING] Anti Cheat Bypass

노션으로 옮김·2020년 5월 10일
2

skills

목록 보기
31/37
post-thumbnail

개요

게임 분석중, 게임을 실행한 상태에서 디버거를 실행하니 다음과 같은 메시지가 나타났다.

게임 자체에서 치트를 방지하는 기능을 구현한 것 같았고, 이것을 우회해야 했다.

그 과정을 간단히 정리하기 위한 글이다.


환경

OS : Windows 10
Image : Microsoft Visual C++ ver 5.0/6.0 / x86 architecture
Type : 2D MMO RPG

코드 추적

프로그램은 Updater.exe가 먼저 실행된 후 Updater.exe가 게임 클라이언트를 fork하는 방식으로 실행된다.

게임 클라이언트가 실행되자마자 안티치트 기능을 수행하는 쓰레드가 생성되므로, 디버거를 바로 attach해서 확인할 수는 없었다.

생각한 방법으로는 process explorer를 이용해 게임 클라이언트를 suspend시킨 후에 디버거를 attach한다.
그 후 원하는 지점에 브레이크 포인트를 걸고 프로세스를 resume하여 코드를 분석한다.

나는 안티치트 코드를 추적하기 위해 MessageBox를 백트레이싱하였다.

앞서 말한 방법대로 게임 클라이언트를 suspend한 후에 x64dbg를 attach시킨다.

그리고 MessageBox에 브레이크 포인트를 설정하고 프로세스를 진행시키면, EIPMessageBox에서 중지되고 다음처럼 스택의 값을 확인할 수 있다.

ESP가 위치한 Caller의 코드를 따라가보면

MessageBox에 전달되는 상수값들로 인해, 이 코드 영역이 안티치트 기능을 수행하는 함수의 내부라는 것을 유추할 수 있었다.

코드 분석

코드 양이 방대하여 x64dbg로 분석하기는 힘들었다.
IDA로 로드하여 안티치트 코드를 확인했다.

다행히 머리가 아파지는 코드는 없었다.
다음처럼 실행중인 윈도우 정보를 가져와서

sub_404836 함수를 호출하여 윈도우 중 치팅 프로그램이 존재하는지 검사한다.
sub_404836에 전달되는 ESP+8는 바로 위에서 repne scasb를 이용해 구한 상수의 길이를 나타내며 ESP+4는 윈도우 정보, ESP는 검사할 치팅 프로그램의 이름이 저장된 상수값을 나타낸다.

검사하는 프로그램은 다양하다.

우회

방법은 두 가지가 있다.
GetWindow를 후킹하여 0을 반환시켜서 안티 치트 코드가 실행되지 않도록 하거나, 아니면 검사함수인 sub_404836을 후킹하고 -1을 반환시켜서 치팅 프로그램이 아닌 것처럼 속이는 방법이다.

frida를 이용하여 작성할 것이며, 첫 번째는 다음과 같은 코드로 구현 가능하다.

function hookByName(dllName, funcName, ctRet){
  Interceptor.attach(Module.findExportByName(dllName, funcName), {
    onEnter: function(args){
      //send('Hooked function is called [' + dllName + ' :: ' + funcName + ']');
    },
    onLeave: function(retval){
      //send('ret: ' + retval);
      retval.replace(ctRet);
      return retval;
    }
  });
}

hookByName('User32.DLL', 'GetWindow', 0);

다음은 검사를 우회시키는 후킹 코드이다.

Interceptor.attach(ptr(0x404836), {
  onEnter: function(args){
    send('Hooked function is called []');
  },
  onLeave: function(retval){
    send('ret: ' + retval);
    retval.replace(-1);
    return retval;
  }
});

하지만, 사용할 때에는 첫 번째 코드를 사용하는 것이 좋겠다.
GetWindow를 후킹하면 안티치트 함수의 코드가 실행되지 않고 종료되지만, sub_404836을 후킹할 경우 모든 코드가 실행되어 속도가 저하될 수있기 때문이다.

결과

위 스크립트를 로드하면 치트엔진이나 디버거를 실행해도 클라이언트가 종료되지 않는 것을 확인할 수 있다.

1개의 댓글

comment-user-thumbnail
2024년 2월 1일

질문이 있습니다.
디스코드 하시나요?
jeongsangin9697 친구추가 가능하실까요

답글 달기