[ 리버싱 / 프로그래밍 / 음악 / 게임 / 그 외... ]



수요일, 4월 19, 2017



스타크래프트 클래식 1.18

"스타크래프트" 를 열렬히 좋아하는건 아니지만~

중학생 시절 PC방 가서 밤샘도 해보고, 모뎀으로 친구와 멀티플레이를 해본...

나름의 소소한 기억들이 있어서 그런지 "스타크래프트 리마스터" 의 소식이 반가웠습니다.


덕분에 클래식 버전은 1.18 로 업데이트 되면서 무료 배포로 딱~!!!

[ 스타크래프트 클래식 설치파일 다운로드 ]


추억의 화면

오랜만에 에피소드 진행하면서~ 스토리 다시 한 번 되새겨 봐야겠어요~ :)

리마스터가 나오면 이 모든걸 "한글"로 즐길 수가 있겠죠...? @_@

얼른 나오길....





화요일, 4월 11, 2017



지난번에 올린 Pin 을 이용한 메모리 조작 분석에 이어서 ~

이번에도 '게임 해킹툴 분석' 측면으로 접근해보려 합니다 :)

물론 응용하기에 따라 다른 쪽으로 이용도 가능하겠지만요.. ^^;;; 

Pin 을 이용한 비정상 함수 호출 분석


게임 내부의 함수들은 게임이 진행되는 중에 게임에서 호출하는 것이 일반적입니다.

FPS 게임에서 캐릭터가 죽는 경우를 예를 들어봅시다.

게임 내부적으로 무기 데미지 / 캐릭터 체력 / 착탄 부위 등 이것저것 계산을 해서

조건을 만족하는 경우에 게임이 Kill 함수를 호출하는 것이 정상적인 흐름입니다.


만약 이 Kill 함수가 게임이 아닌 다른 곳에서 호출되면 어떻게 될까요...? @_@

게임 진행과 상관없이 캐릭터가 죽겠죠... -_-;;;

이런 식으로 게임 해킹툴이 게임 내부 함수를 호출하는 것을 '비정상 함수 호출' 이라고 합니다.


Pin 을 이용해서 인젝션 된 DLL 이 대상 프로세스의 함수를 호출하는 것을 분석해봅시다.

테스트 샘플 구성은 '메모리 조작 분석' 과 동일합니다.

[ Sample.zip 다운로드 ]


- Sample.exe : 게임 프로세스

- SampleDll.dll : 게임 프로세스에 인젝션되는 게임 해킹툴

Sample.exe 가 실행될 때 SampleDll.dll 을 로드하고

DLL 이 로드된 후, 'F2' 키를 누르면~ SampleDll.dll 이 Sample.exe 의 함수를 호출합니다.

Sample.exe 실행

'F2' 키를 눌렀을 때... 실행되는 SampleDll.dll 의 코드는 아래와 같습니다.

SampleDll.dll 의 비정상 함수 호출 코드 (소스코드)
참고로 lpFunc 는 프로세스 베이스 주소 + 0x1000 의 값으로 고정해두었습니다.

이 코드를 디버거로 보면 아래와 같은 디스어셈블 코드가 나옵니다.

SampleDll.dll 의 비정상 함수 호출 코드 (디스어셈블 코드)
노란 박스 안의 저 "CALL" 명령으로 시작되는 코드를 Pin 으로 잡아내면 되겠죠~? :)


핵심 API 는 "INS_IsCall" 입니다.

CALL 명령이 나오면 이 API 의 리턴값이 TRUE 가 됩니다.

아래는 Pin tool 예제 코드입니다.


// CallTrace.cpp

#include "pin.H"

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

ofstream TraceLog;

UINT32 SampleBaseAddr = 0;
UINT32 SampleMappedSize = 0;
UINT32 DllBaseAddr = 0;
UINT32 DllMappedSize = 0;

//-------------------------------------------------------------------
INT32 Usage()
{

    return -1;
}

VOID Fini(INT32 code, VOID *v)
{
    TraceLog << endl << "#eof..." << endl;

    if (TraceLog.is_open()) TraceLog.close();
}

VOID ImageLoad(IMG img, VOID *v)
{
    // 메인 프로세스 : Sample.exe
    if (IMG_IsMainExecutable(img) == TRUE) {
        SampleBaseAddr = IMG_StartAddress(img);
        SampleMappedSize = IMG_SizeMapped(img);
        TraceLog << "* Process Name : " << IMG_Name(img) << endl;
        TraceLog << "  StartAddress : " << hexstr(SampleBaseAddr) 
            << ", MappedSize : " << hexstr(SampleMappedSize) << endl;
    }

    // SampleDll.dll
    if (IMG_Name(img).find("SampleDll.dll") != string::npos) {
        DllBaseAddr = IMG_StartAddress(img);
        DllMappedSize = IMG_SizeMapped(img);
        TraceLog << "* Sample Dll : " << IMG_Name(img) << endl;
        TraceLog << "  StartAddress : " << hexstr(DllBaseAddr)
            << ", MappedSize : " << hexstr(DllMappedSize) << endl;
    }
}

VOID Log_Call(string &CallFunc, ADDRINT target)
{
    if ((target >= SampleBaseAddr) && 
        (target < (SampleBaseAddr + SampleMappedSize))) {
        TraceLog << CallFunc + " [ Target : " + hexstr(target) + " ]" << endl;
    }
}

VOID Trace(TRACE trace, VOID *v)
{
    for (BBL bbl = TRACE_BblHead(trace); BBL_Valid(bbl); bbl = BBL_Next(bbl))
    {
        INS tail = BBL_InsTail(bbl);
        ADDRINT Address = INS_Address(tail);

        if ((Address >= DllBaseAddr) &&
            (Address <= (DllBaseAddr + DllMappedSize))) {

            if (INS_IsCall(tail))
            {
                string CallFunc = "- eip: " + hexstr(Address) +
                    "   [CallFunc]  " + INS_Disassemble(tail);

                INS_InsertPredicatedCall(tail, IPOINT_BEFORE, AFUNPTR(Log_Call),
                    IARG_PTR, new string(CallFunc),
                    IARG_BRANCH_TARGET_ADDR,
                    IARG_END);
            }
        }
    }
}

//-------------------------------------------------------------------
int main(int argc, char *argv[])
{
    PIN_InitSymbols();

    if (PIN_Init(argc, argv)) return Usage();

    TraceLog.open("CallTrace_Log.txt", ofstream::out);
    TraceLog << "### Call Trace Log ###" << endl << endl;

    IMG_AddInstrumentFunction(ImageLoad, NULL);
    TRACE_AddInstrumentFunction(Trace, NULL);

    PIN_AddFiniFunction(Fini, NULL);

    PIN_StartProgram();

    return 0;
}


빌드해서 생성된 CallTrace.dll 을 이용해보면~

Sample.exe 실행 (with Pin - CallTrace.dll)

CallTrace.dll 에서 남긴 로그

이번에도 역시 SampleDll.dll 에서 비정상 함수 호출을 하는 코드가 로그 파일에 제대로 기록되었네요~ :)

마치며

Pin 을 이용해서 '메모리 조작 분석' 과 '비정상 함수 호출 분석' 을 분석하는 방법을 살펴봤는데요.

기능별로 설명(?)하기 위해 MemTrace / CallTrace 로 나눴지만...

잘 조립하면 하나의 DLL 로 합칠 수도 있습니다 :)


실제 게임에 적용하기 위해서는 이것저것 고려해야 될 사항들과 장벽들이 많지만... @_@;;

Pin 을 공부하시는 분들께 조금이나마 도움이 되었으면 좋겠네요~~ :)





카테고리

가장 많이 본 글

통계

Copyright © XeroNic(HS) BLOG | Powered by Blogger
Design by WP Lift | Blogger Template by NewBloggerThemes.com