본문 바로가기

2. Reversing (리버싱)/2) 개념 정리

[2025.05.24] 리버싱난다_6주차 활동

참고 강의 - 유튜브 Fin 리버싱 강의

Reloc 섹션 제거

EXE는 원래 재배치가 필요 없었는데 Windows에 ASLR 기능이 도입되면서 주소가 자꾸 바뀌면서 필요해졌음

Hex Editor 사용

  1. reloc 제거
    • 영역 중에서 실제로 동작하는 부분을 지우는 게 1번 나머지를 NULL값으로 채우는 게 2번
    • 실질적인 영역은 섹션헤더에서 PointerToRawData부터 끝까지
  2. 나머지 부분 reloc 섹션헤더 채우기(NULL값/16진수 00으로)
  3. FILE HEADER 수정
    • NumberOfSections 수정 ← 섹션 개수를 나타냄
      • reloc을 삭제해서 섹션 개수 하나가 줄었으므로 값을 바꿔줌
      • ex) 9 → 8
  4. OPTIONAL HEADER 수정
    • SizeOfImage ← 메모리에서 로드되는 파일의 크기
      • reloc 값을 포함한 파일의 크기라서 reloc 만큼을 빼줘야 함
        • SizeOfImage - SizeOfRawData 해서 저장
        • 리틀엔디안으로 저장

ASPack

: 윈도우 실행 파일 크기를 70%까지 줄일 수 있는 파일 패킹 프로그램

OEP(original entry point) 위치 찾기

ret/retn == pop → jump

(jump 하려면 주소여야 함)

ret 전에 push 해놓은 값이 OEP인 걸 알 수 있음

인라인 패치(Inline Patch)

= 인라인 코드 패치(Inline Code Patch)

: 실행 압축이나 암호화된 파일을 패치할 때 사용되는 코드 인젝션

인라인 코드 패치(Inline Code Patch)는 프로그램에서 내가 수정하고 싶은 코드를 수정하기 번거로울 때 코드 케이브(Code Cave)라고 하는 것을 통해 수정함

코드 케이브(Code Cave)는 간단히 스크립트

원래는 디코딩 루프를 통해 jmp OEP를 통해 OEP를 하는데

코드

케이브는 jmp OEP 대신 jmp Code Cave 후 cmp OEP 해주는 것

일반적인 코드 패치와 인라인 패치 차이점

인라인 패치 : 파일 메모리만 가능, 파일에서는 코드케이브를 한 번만 하지만 메모리에서는 실행할 때마다 해야되고 Indirect 에 인라인 패치 가능, 얘는 특정 빈공간을 찾아야 됨

일반적인 코드 패치 : 파일에서만 가능하고 횟수는 1번만 하면 됨. 그리고 원하는 곳에 패치 가능

Window 메세지 후킹

[ Hook ]

hook 는 갈고리, 낚시바늘이라는 뜻으로 원하는 것을 낚아 채고 싶을 때 사용하는 도구

OS - APP - USER 사이의 중간에 오고가는 정보를 낚아챌 수 있다는 것

→ 사용자 몰래 정보를 후킹해서 조작 및 엿볼 수 있음

[ 메세지 훅 ]

  • Windows OS는 GUI환경을 제공하고, 이는 Event Driven 방식으로 동작
  • 키보드, 마우스를 이용하여 메뉴 선택이나 x 선택 등 위치 이름 등의 정보를 후킹 가능
  • → 이런 작업들이 모두 이벤트이기 때문에 이벤트가 발생하면 OS는 미리 정의된 메세지를 해당 응용 프로그램에 띄워줌
  • 키보드를 입력할 때도 OS로부터 응용프로그램으로 메세지가 이동함. 이런 메세지를 낚아 채는 행동을 메세지 훅이라고 함

훅 체인 : 같은 키보드 메세지 훅이라도 여러 개 동시 설치 가능. 이러한 훅을 순서대로 호출하는 것

Windows OS에서 기본 기능으로 메세지 훅을 제공함.

→ 대표적인 프로그램으로 MS Visual Studio에서 제공하는 SPY++

[ SetWindowsHookEx() ]

: 후킹하는 걸 도와주는 함수

HHOOK SetWindowsHookEx(
    int idHook,         // hook type
    HOOKPROC lpfn,        // hook procedure
    HINSTANCE hMod,        // hook procedure가 속해있는 dll 핸들
    DWORD dwThreadID        // hook을 걸고 싶은 thread의 ID (0은 global hook)
);
  • SetWindowsHookEx() API를 이용해 훅을 설치하면 어떤 프로세스에서 메세지가 발생했을 때 OS가 해당 DLL 파일을 해당 프로세스에 강제로 injection하고 hook procedure를 호출함
  • 특정 이벤트가 발생하면 호출하도록 지정해놓은 함수인 콜백 함수 중 하나
  • dwThreadId에 0값을 주고 호출하면 글로벌 훅이 설치 됨 → 실행되는 모든 파일에 영향을 끼치게 됨

키보드 후킹

https://maple19out.tistory.com/35

/*** HookMain.cpp ***/
#include <stdio.h>
#include <conio.h>
#include <Windows.h>

#define DEF_DLL_NAME "KeyHook.dll"
#define DEF_HOOKSTART "HookStart"
#define DEF_HOOKSTOP "HookStop"

typedef void(*PFN_HOOKSTART)();
typedef void(*PFN_HOOKSTOP)();

void main() {
    HMODULE hDll=NULL;
    PFN_HOOKSTART HookStart=NULL;
    PFN_HOOKSTOP HookStop=NULL;
    char ch=0;

    //KeyHook.dll 로딩
    //핸들에 대한 접근자를 리턴
    //핸들은 리소스에 접근할 수 있는 값 정도..?
    hDll = LoadLibraryA(DEF_DLL_NAME);

    //export 함수 주소 얻기
    HookStart = (PFN_HOOKSTART)GetProcAddress(hDll, DEF_HOOKSTART);
    HookStop = (PFN_HOOKSTOP)GetProcAddress(hDll, DEF_HOOKSTOP);

    //후킹 시작
    HookStart();

    //'q'가 입력으로 들어올 때까지 대기
    printf("press 'q' to quit!\n");
    while(_getch() != 'q');

    //후킹 종료
    HookStop();

    //KeyHook.dll 언로딩
    FreeLibrary(hDll);
}

/*** KeyHook.cpp ***/
#include <stdio.h>
#include <Windows.h>

#define DEF_PROCESS_NAME "notepad.exe"

HINSTANCE g_hInstance=NULL;
HHOOK g_hHook=NULL;
HWND g_hWnd=NULL;

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpvReserved) {
    switch(dwReason) {
    case DLL_PROCESS_ATTACH:
        g_hInstance=hinstDLL;
        break;

    case DLL_PROCESS_DETACH:
        break;
    }

    return TRUE;
}

LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {
    char szPath[MAX_PATH]={0, };
    char *p=NULL;

    if(nCode>=0) {
        //31-th bit=> press, 1st bit=> release
        if(!(lParam & 0x80000000)) {
            //process의 경로를 알아낸다.
            GetModuleFileNameA(NULL, szPath, MAX_PATH);
            //경로로부터 프로세스 name 파싱
            p = strrchr(szPath, '\\');

            //현재 프로세스가 notepad.exe라면,
            //응용 프로그램으로 메시지를 전달하지 않는다.
            //키보드로 값을 입력 하지 못하도록 하는 거라고 보면 된다
            //여기 다양한 응용 가능
            if(!_stricmp(p+1, DEF_PROCESS_NAME))
                return 1;
        }
    }

    //일반적인 경우에는 CallNextHookEx()를 호출하여
    //응용 프로그램으로 메세지를 전달한다.
    return CallNextHookEx(g_hHook, nCode, wParam, lParam);
}

#ifdef __cplusplus
extern "C" {
#endif
    __declspec(dllexport) void HookStart() {
        g_hHook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, g_hInstance, 0);
    }
    __declspec(dllexport) void HookStop() {
        if(g_hHook) {
            UnhookWindowsHookEx(g_hHook);
            g_hHook=NULL;
        }
    }
#ifdef __cplusplus
}
#endif

후킹으로 프로그램을 다룰 수 있다 !

PE파일 끝 → UPack → 인라인 패치 → Win32 API → DLL 인젝션