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



목요일, 3월 30, 2017



믿고 듣는 아이유~ :D

이번 노래도 제대로 취향저격이네요~ (*-_-*)

음원차트를 휩쓸고 있는 중... ㅋ








아이유(IU) - 밤편지

이 밤 그날의 반딧불을
당신의 창 가까이 보낼게요
음 사랑한다는 말이에요

나 우리의 첫 입맞춤을 떠올려
그럼 언제든 눈을 감고
음 가장 먼 곳으로 가요

난 파도가 머물던
모래 위에 적힌 글씨처럼
그대가 멀리
사라져 버릴 것 같아
늘 그리워 그리워

여기 내 마음속에
모든 말을
다 꺼내어 줄 순 없지만
사랑한다는 말이에요

어떻게 나에게
그대란 행운이 온 걸까
지금 우리 함께 있다면
아 얼마나 좋을까요

난 파도가 머물던
모래 위에 적힌 글씨처럼
그대가 멀리
사라져 버릴 것 같아
또 그리워 더 그리워

나의 일기장 안에
모든 말을
다 꺼내어 줄 순 없지만
사랑한다는 말

이 밤 그날의 반딧불을
당신의
창 가까이 띄울게요
음 좋은 꿈 이길 바라요



일요일, 3월 26, 2017



일전에 Visual Studio 에서 Intel Pin 프로젝트를 설정하는 방법을 올린 적이 있습니다.

이번에는 응용차원에서 Pin 을 활용하는 방법을 올려봅니다. @_@

주 업무분야가 '게임보안' 인만큼 '게임 해킹툴 분석' 측면으로 접근해봤습니다... ^^;;

Pin 을 이용한 메모리 조작 분석


캐릭터의 공격력을 높이기 위해 '공격 데미지 값' 이라는 데이터를 조작하거나...

캐릭터가 받는 데미지를 없애기 위해 '데미지 처리 로직' 이라는 코드를 조작하거나...

게임 해킹툴이 게임 치팅을 위해 가장 많이 사용하는 방식 중 하나가 '메모리 조작' 입니다.


'메모리 조작' 은 조작하는 방식에 따라 아래와 같이 크게 두 종류로 나눌 수 있습니다.

- 게임 프로세스 외부의 다른 프로세스에서 WriteProcessMemory 로 조작.

- 게임 프로세스 내부에 DLL 을 인젝션 시켜서 직접 값을 조작.


여기서는 DLL 을 인젝션 시켜서 직접 값을 조작하는 방식을 대상으로

Pin 을 활용해보도록 하겠습니다.

테스트 편의를 위해 Sample.exe 와 SampleDll.dll 을 간단하게 구현했습니다.

[ Sample.zip 다운로드 ]


- Sample.exe : 게임 프로세스

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

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

DLL 이 로드된 후, 'F1' 키를 누르면~ SampleDll.dll 이 Sample.exe 의 메모리를 조작합니다.
 
Sample.exe 실행

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

게임 해킹툴이 메모리 조작 시 자주 사용하는 형태입니다.

SampleDll.dll 의 메모리 조작 코드 (소스코드)
 참고로 hModule 은 Sample.exe 프로세스의 베이스 주소입니다.
 
SampleDll.dll 의 메모리 조작 코드 (디스어셈블 코드)
우리의 목표는 SampleDll.dll 에서 Sample.exe 의 메모리를 0x90 으로 조작하는 노란 박스의 코드를...

Pin 을 이용해서 찾아내는 겁니다. :)

핵심 API 는 "INS_MemoryOperandIsWritten" 입니다.

메모리 쓰기가 발생하는 경우 이 함수의 리턴값이 TRUE 가 됩니다.

"MOV", "AND", "SUB" 등의 명령으로 메모리 주소에 값이 써지는 경우는 물론...

"PUSH", "CALL" 등의 명령으로 스택 메모리에 값이 써지는 경우도 포함됩니다. @_@;;;

이 함수를 잘 이용하면 DLL 에서 게임 프로세스의 메모리를 조작하는 코드를 찾을 수 있습니다.

아래는 Pin Tool 예제 코드입니다


// MemTrace.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_MemWrite(VOID *ip, string &MemWrite, VOID *addr)
{
    UINT32 target = UINT32(addr);

    if ((target >= SampleBaseAddr) && 
        (target < (SampleBaseAddr + SampleMappedSize))) {
        TraceLog << MemWrite << endl;
    }
}

VOID Instruction(INS ins, VOID *v)
{
    ADDRINT Address = INS_Address(ins);

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

        UINT32 memOperands = INS_MemoryOperandCount(ins);

        for (UINT32 memOp = 0; memOp < memOperands; memOp++) {
            if (INS_MemoryOperandIsWritten(ins, memOp)) {
                string MemWrite = "- eip: " + hexstr(Address) + 
                    "   [WriteMem]  " + INS_Disassemble(ins);

                INS_InsertPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)Log_MemWrite,
                    IARG_INST_PTR, 
                    IARG_PTR, new string(MemWrite), 
                    IARG_MEMORYOP_EA, memOp, 
                    IARG_END);
            }
        }
    }
}

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

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

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

    IMG_AddInstrumentFunction(ImageLoad, NULL);
    INS_AddInstrumentFunction(Instruction, NULL);

    PIN_AddFiniFunction(Fini, NULL);

    PIN_StartProgram();

    return 0;
}

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

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

MemTrace.dll 에서 남긴 로그

SampleDll.dll 에서 메모리 조작을 하는 코드가 깔끔하게(?) 로그 파일에 기록되었습니다~ :)


마치며

일반적으로 Pin 으로 프로그램을 실행시키면 그냥 실행시키는 것보다 속도가 느립니다.

게다가 Instrumentation 하는 범위가 넓을 수록... 로깅 위치가 많을 수록...

엄~~~청나게 느려집니다. -_-;;;;;;

Instrumentation 범위 조절과 로깅 위치 조절만 하더라도 실행 속도를 올릴 수 있으니...

적절하게 필터링을 해서 쓰는 걸로~ :)


5년 전에 회사에서 이것저것 시도하다 한계에 부딪혔던걸...

지금 올리네요... -_-;;;;;




카테고리

가장 많이 본 글

통계

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