Notice
Recent Posts
Recent Comments
Link
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
Tags more
Archives
Today
Total
관리 메뉴

난 정말 최고야 멋있어

[게임 해킹] 스피드핵 만들기 본문

카테고리 없음

[게임 해킹] 스피드핵 만들기

n00bh4cker 2020. 1. 11. 11:30

스피드핵을 만들기 위해서는 우선 스피드핵의 원리를 짚고 넘어갈 필요가 있다

원리를 초보도 이해할수 있도록 위에 그림을 그려보았다

이 정도면 아무래도 모두가 한눈에 쏙 이해하지 않을까 싶다

 

우리의 대상 게임은 추억의 게임인 레바의 모험!!! 공식홈페이지에서 받아주자

http://www.reva.kr/start

 

게임하기 - 레바의모험

 

www.reva.kr

 

 

시간 관련함수로는 크게 GetTickCount와 QueryPerformanceCounter , timeGetTime 등등이 있는데..

(설마 rdtsc를 사용하진 않을꺼라고 본다 ㅋㅋ)

브포를 걸고 확인해 보면 보다 싶이... GetTickCount 류에는 아무런 반응도 없지만 QueryPerformanceCounter와 timeGetTime에는 반응을 아주 잘하는것을 볼 수 있다.

 

일단 샘플로 작동원리를 확인하기 위해서 코드를 간단히 짜보았다..

후킹따위는 없지만, 자체적으로 후킹을 시뮬레이션한다

 

#include <iostream>
#include <Windows.h>

using namespace std;
int main()
{
    float delta = 0.0001;
    LARGE_INTEGER li;
    static LARGE_INTEGER hook;
    while (true)
    {
        system("cls");
        QueryPerformanceCounter(&li);

        if (hook.QuadPart == 0)
            hook.QuadPart = li.QuadPart;
        li.QuadPart = hook.QuadPart + (LONGLONG)(delta * (li.QuadPart - hook.QuadPart));
        cout << li.QuadPart << endl;
    }
    return 0;
}

 

delta 변수를 바꿔줌에 따라서 속도가 오르는 속도가 확실히 차이 난다는것을 알 수 있다.

그럼 이제 본격적으로 DLL코드를 작성해보자

 

일단 detours를 인클루드 해주고..

원본 함수 주소를 GetProcAddress 함수를 이용해서 얻어와 전역변수로 저장을 했다

보통 typedef 함수포인터로 따로 만들고 그러던데 나는 귀찮아서 그냥 함수포인터만 썼다

auto _qfc = (BOOL (WINAPI*)(LARGE_INTEGER*))GetProcAddress(GetModuleHandle(L"kernel32.dll"), "QueryPerformanceCounter");
auto _tgt = (DWORD(WINAPI*)())GetProcAddress(GetModuleHandle(L"kernel32.dll"), "timeGetTime");

QueryPerformance와 timeGetTime 모두를 가져온건 절대로 처음에 QueryPerformanceCounter만 후킹했을때 스피드핵이 정상적으로 작동하지 않아서가 아니다

 

또 전역변수로 스피드핵 비율과, 예비 주황이들을 선언 해주었다

float delta = 10.0f;
static LARGE_INTEGER saved_qfc;
static DWORD saved_tgt;

이제 DllMain을 손대보자

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        DisableThreadLibraryCalls(hModule);
        DetourTransactionBegin();
        DetourUpdateThread(GetCurrentThread());
        DetourAttach((PVOID*)&_qfc, qfchook);
        DetourAttach((PVOID*)&_tgt, tgthook);
        DetourTransactionCommit();
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

DLL_PROCESS_DETACH 에는 귀찮아서 아무것도 안썼다

tgthook 과 qfchook은 후킹할 함수다

 

BOOL WINAPI qfchook(LARGE_INTEGER* time)
{
    if (saved_qfc.QuadPart == 0)
        _qfc(&saved_qfc);
    BOOL result = _qfc(time);
    time->QuadPart = saved_qfc.QuadPart + delta * (time->QuadPart - saved_qfc.QuadPart);
    return result;
}

DWORD WINAPI tgthook()
{
    if (saved_tgt == 0)
        saved_tgt = _tgt();
    return saved_tgt + delta * (_tgt() - saved_tgt);
}

처음의 후킹 시뮬레이션 코드랑 비슷하게 짜보았다

내가 자주하는 실수인데 함수 호출 규약을 꼭 맞춰줘야 한다 안맞춰주면 무수한 에러의 요청이??

x86의 경우 WINAPI 는 웬만해선 __stdcall 이고 일반적인 함수는 __cdecl 인경우도 많다

대충 ret으로 끝나면 cdecl , ret 04 이런식으로 끝나면 stdcall (그래도 혹시 모르니 스택 정리를 누가 하는지 보는게 제일 확실하긴 하다)

 

 

음.. 이제 시연해보자

 

 

마지막에 안타깝게 죽었긴 한데 간단한 스피드핵 구현이 된 것을 알 수 있다