취약점분석/Reversing

[Reversing] Hooking - 1 (DLL,IAT 이론)

poiri3r 2025. 7. 5. 14:32

안녕하세요. 굉장히 오랜만에 포스팅을 작성하는 것 같은 기분이네요.

공부에 소홀했던 건 아니고, CTF 문제 풀이랑 대회 예선 문제를 복습을 했었는데 블로그에 쓰기에는 좀 애매했던 것 같습니다.

이번에 후킹에 관해서 포스팅을 작성할 것이고, 본격적으로 후킹에 대해 쓰기 전에 후킹에 대한 기본적인 개론과 DLL과 IAT란 무엇인지 먼저 알아보는 시간을 가져보겠습니다.

 

후킹

후킹이란 원래 함수나 동작이 호출될 때 내가 정의한 코드가 먼저 또는 대신 실행되도록 가로채는 기법입니다.

간단하게 그림으로 그려서 설명드리겠습니다.

이런식으로 원하는 함수 흐름에서 가로채서 내가 원하는 코드를 실행시키거나 원래 코드를 대체할수 있습니다.

후킹을 거는 지점이 어디냐에 따라 후킹의 종류가 나뉘는데, 대표적으로 IAT 후킹, EAT 후킹, Inline 후킹 등이 있습니다.

포스팅을 하면서 IAT후킹과 API후킹에 대해 알아볼건데 오늘은 그 전에 IAT란 무엇인지, dll이란 무엇인지 살펴보겠습니다.

 

DLL(Dynamic Link Library)

DLL이란 WIndows 운영체제에서 사용하는 공유 라이브러리 파일로 .dll의 확장자를 가집니다. 쉽게 말해 여러 프로그램 혹은 특정 하나의 프로그램을 위해 사용하는 함수나 자원을 따로 빼서 저장해 둔 파일입니다.

dll은 함수와 클래스 리소스 3가지로 내부가 구성되며, 다음과 같은 장점을 가집니다.

  1. 프로그램 실행 도중 필요한 시점에 dll로드 가능
  2. 메모리 절약과 관리가 용이
  3. dll만 파일만 교체하면 프로그램 전체를 수정하지 않아도 기능을 추가하거나 버그를 수정할 수 있음
  4. 게임에서 플러그인을 통한 확장 기능을 별도로 추가 가능

제가 20살때 했던 스타듀밸리라는 게임이 있는데요, 단순한 농장 게임이지만, 게임 모드를 추가로 다운받으면 할 수 있는 행동들이 늘어나거나 간단하게는 NPC의 초상화가 바뀌는 기능이 있었습니다.

이러한 게임 모드 확장은 dll을 통해 이루어지며 원하는 형식으로 dll을 수정한 뒤 게임에서 특정 프로그램의 도움을 받아 기존 dll을 내가 원하는 dll로 교체하는 방식입니다.

자세하게는 dll injection기법이 있는데, 저도 아직 잘 모르는 부분이라 다음에 더 자세히 알아보고 포스팅 해보도록 하겠습니다.

dll은 이름 그대로 동적 로딩 방식이기 때문에 컴파일 시점에 실행 파일에 함수를 복사하는 것이 아니고, 컴파일시 생성된 IAT에 함수 주소가 런타임에 채워져 이를 통해 호출되기 때문에 최적화에 용이합니다.

 

제일 대표적으로 user32.dll이 있습니다. 

user32.dll은 윈도우 운영체제에서의 사용자 인터페이스 관련 기능을 담당하며, 흔히 접하는 MessageBox나 CreateWindowEx등의 함수를 제공합니다. 한번 PE베어를 실행해서 dll을 살펴보겠습니다.

먼저 4D5A라는 구조를 보았을 때 PE파일 구조라는 것을 알 수 있습니다.

그 다음으로는  user32.dll의 외부함수테이블(export table)을 확인해보겠습니다.

등등 .. 저희에게 나름 친숙한 함수 이름이 많이 보입니다.

user32.dll은 고수준 dll이기 때문에 내부적으로 더 저수준인 ntdll.dll에 의존하고 있습니다.

그래서 user32.dll의 내부함수테이블(import table)을 확인해보면

win32u.dll(*user32.dll과 gdi32.dll이 하던 시스템 호출 역할을 분리해서 담당하는 저수준 dll)이나 ntdll.dll(시스템 콜을 수행가능한 유저모드 dll)에서 함수를 가져와서 사용하는 것을 알 수 있습니다.

dll을 직접 열어서 확인해보겠습니다.

IDA를 관리자 권한으로 실행해서 C:\Windows\System32\user32.dll을 호출해 주었고,

import와 export도 pe베어로 봤을때와 같습니다.

대표적인 함수인 messagebox를 디컴파일해서 분석해보겠습니다.

이런식으로 나오게 됩니다.

사실 dll을 분석하는게 정말 쉽지 않은 작업인 것 같아서 ,, 저희의 목적에 부합하지도 않고요, 그래도 이렇게 dll을 열어서 확인해보는 작업은 유의미한 것 같습니다.

찾아보니까 MessageBoxA는 그 자체로 메세지 박스를 띄우는게 아니라 안에 있는 MessageBoxTimeoutA를 통해 win32u.dll->NtUserMessageCall로 이어져서 사용이 된다고 하네요.

호출구조 계층에 관한 정보입니다. 다 하나하나 열어보려면 가능할 수 있을것 같지만 그건 다음에 해보도록 하겠습니다.

 

이렇게 열어보고 나니 dll이 어떤 식으로 구성되어있는지 더 확실하게 알게 된 느낌인 것 같습니다.

결론적으로 dll은 windows 실행 파일 형식(PE)중 하나이고, 여러 프로그램이  공유해서 쓸 수 있는 함수나 자원들을 모아둔 라이브러리이고, dll안에서도 하위 dll을 불러들어와 코드를 사용하는 방식으로 운영이 되고 있습니다.

 

이제 IAT에 대해 살펴보겠습니다.

 

IAT(Import Address Table)

저번에 PE 구조에 대해 포스팅할때 조금 알아봤었는데 오늘은 조금 더 자세하게 살펴보겠습니다.

IAT란 PE 실행 파일이 사용하는 외부 DLL 함수들의 실제 주소를 저장해두는 테이블입니다.

쉽게 말해 실행파일이 다른 DLL의 함수를 호출할 수 있도록 도와주는 중간 다리 역할을 합니다.

컴파일 시에는 함수 이름만 알고 주소를 모르는데, 그 주소를 IAT에 채워 두고, 그 주소를 통해 호출하는 방식입니다.

코드로 예를 들어 설명해보겠습니다.

#include <windows.h>

int main() {
    MessageBoxA(NULL, "Hello", "Title", MB_OK);
    return 0;
}

 

title이라는 제목에 내용은 hello이고 확인버튼 하나 있는 메세지 박스를 띄우는 간단한 코드입니다.

먼저 이 코드를 컴파일 할 때(EXE가 생성될 때), 실행파일 안에는 MessageBoxA라는 이름만 기록되고 주소는 저장되지 않습니다.

대신 IAT 슬롯을 만들고, 거기에 주소를 나중에 채우라고 예약해둡니다.

call [IAT_MessageBoxA]  ; ← 주소는 아직 비어 있음

 

해당 파일을 실행할 때(Windows 로더가 PE 로드할 때)

user32.dll을 메모리에 로딩하고, MessageBoxA의 실제 주소를 찾아서  이 값을 우리가 만든 실행파일 내부의 IAT슬롯에 기록해둡니다.

[IAT_MessageBoxA] = 0x77AE1230  ← 실제 함수 주소

 

그 뒤에 EXE는 MessageBoxA를 정상적으로 실행합니다.

 

이러한 방식은 컴파일시 주소가 고정되기 때문에 후킹으로 인한 취약점이 발생합니다.

단순히 call [주소] 만 바꾸어도 dll 대신에 저희가 원하는 코드나 dll을 실행시킬 수 있기 때문입니다.

일단은 이정도까지만 알아보도록 하겠습니다.

 

먼저 간단하게 구조를 살펴봤으니 다음 포스팅에서는 IAT후킹을 알아보고 실습할 수 있는 코드를 가져와보겠습니다.

읽어주셔서 감사합니다~