tmxklab
Window API 호출 흐름 본문
0. 목차
1. 커널 메모리 내용
2. 유저모드, 커널모드
3. Window API 호출 흐름
1. 커널 메모리 내용
커널 메모리는 OS와 장치 드라이버를 포함한다.
커널 메모리는 다음 주요 컴포넌트로 이루어져 있다.
① hal.dll
- 하드웨어 추상 레이어(HAL, Hardware Abstraction Layer)는 로드 가능한 커널 모듈 hal.dll에 구현되었으며, 다른 하드웨어 플랫폼(주로 칩셋)을 지원하는 함수를 구현하기 떄문에 HAL은 OS와 Hardware에서 분리한다.
- 주로 윈도우 실행 프로그램, 커널, 커널 모드 장치 드라이버에 서비스를 제공
- 커널 모드 장치 드라이버는 하드웨어와 상호작용하고자 하드웨어와 직접 통신하지 않고 hal.dll에서 익스포트한 함수를 호출
② ntoskrnl.exe
- 커널 이미지로 알려진 윈도우 OS의 핵심 컴포넌트다.
- ntoskrnl.exe는 익스큐티브(executive)와 커널(kernel)이라는 두 가지 유형의 기능을 제공
- 익스큐티브(executive) : 시스템 서비스 루틴이라는 함수를 구현하는데, 유저 모드 애플리케이션에서 제어된 메커니즘을 통해 호출할 수 있다. 또한, 익스큐티브는 메모리 관리자, IO관리자, 객체 관리자, 프로세스/스레드 관리자 등과 같은 주요 OS 컴포넌트를 구현한다.
- 커널(kernel) : 하위 수준의 운영 시스템 서비스를 구현하고 상위 수준의 서비스를 제공하고자 익스큐티브에서 구축한 일련의 루틴을 제공한다.
③ win32K.sys
- 커널 모드 드라이버는 UI와 그래픽 장치 인터페이스(GDI, Graphics Device Interface)서비스를 구현하며, 모니터와 같은 출력 장치에 그래픽을 랜더링하는데 사용한다.
- GUI 애플리케이션을 위한 함수를 노출한다.
2. 유저모드, 커널모드
유저 공간에서 실행되는 실행 파일과 dll은 커널 공간에 있는 것을 접근하지 못하고 하드웨어와 직접 상호작용을 할 수 없다. 반대로 커널(ntoskrnl.exe)과 디바이스 드라이버을 포함하는 커널 공간에서 실행되는 코드는 커널 모드로 알려진 상승된 권한으로 실행되며 유저 공간과 커널 공간 모두를 접근할 수 있다.
[참고로, 공간과 모드의 차이점은 공간(space)이 콘텐츠(data/code)가 저장되는 위치를 지정하는 데 반해, 모드(mode)는 애플리케이션의 명령어가 어떻게 실행될지 지정하는 실행 모드를 의미한다.]
그렇다면, 유저 모드 애플리케이션이 하드웨어와 직접 상호작용할 수 없는데 WriteFile API함수를 호출해
디스크에 파일을 작성할 수 있는 것인가?
유저 모드 애플리케이션이 호출하는 대부분의 API는 커널 익스큐티브(ntoskrnl.exe)에 구현된 시스템 서비스 루틴(함수)을 호출하고 최종적으로 하드웨어와 상호작용한다. 동일한 방법으로 GUI관련 API를 호출하는 모든 유저 모드 애플리케이션은 커널 공간에 있는 win32K.sys에서 노출한 함수를 호출한다.
위 그림에서 ntdll.dll은 유저 공간과 커널 공간 사이의 게이트웨이처럼 동작한다.
다음 절에서 윈도우 API호출 프로세스를 자세히 다뤄보도록 하자.
3. Window API 호출 흐름
윈도우 OS에서는 dll에서 구현한 API가 노출되도록 서비스를 제공하고 애플리케이션은 dll에 구현된 API를 호출하여 서비스를 이용한다. 그리고 API 함수 대부분은 ntoskrnl.exe의 시스템 서비스 루틴을 호출한다.
다음 그림은 애플리케이션이 WriteFile()을 호출했을 때 전체적인 API 호출 흐름을 나타낸다.
① 프로세스를 실행하면 윈도우 로더는 프로세스 실행 파일 이미지와 관련 dll을 메모리에 로드한다.
② 프로세스가 시작되면 메인 스레드가 생성되고 실행 코드를 메모리에서 읽어 실행을 시작한다.
(참고로, 코드를 실행하는 것은 프로세스가 아니라 스레드이다. 프로세스는 단지 스레드를 위한 컨테이너일 뿐이다.)
③ 생성된 스레드는 유저모드로 실행을 시작한다.
(프로세스는 필요한 경우 명시적으로 추가 스레드를 생성할 수 있다.)
④ 애플리케이션이 kernel32.dll에서 제공하는 WriteFile()를 호출한다.
⑤ 실행 제어를 WriteFile()으로 전환하고자 스레드는 WriteFile()의 메모리 주소를 찾는 작업을 진행한다.
(참고로 애플리케이션이 WriteFile()을 임포트한다면 IAT(Import Address Table)이라는 함수 포인터 테이블에서 주소를 찾을 수 있다. 이 테이블은 메모리에 있는 애플리케이션의 실행 파일 이미지에 위치하며 dll이 로드될 때 윈도우 로더가 함수 주소로 채운다. 또한, 애플리케이션은 LoadLibrary()를 통해 런타임 동안 dll을 로드하고 GetProcessAddress()를 이용해 로드한 dll안의 함수 주소를 파악할 수 있다. 하지만, 런타임 동안 dll을 로드하면 IAT에는 채워지지 않는다. 그래서 직접 함수 주소를 GetProcessAddress()를 통해서 구하고 IAT에 기록해야 한다.)
⑥ 스레드가 IAT 또는 런타임 동안 WriteFile()의 주소를 파악하면 kernel32.dll에 구현된 WriteFile()을 호출한다.
⑦ WriteFile()함수의 코드는 게이트웨이 dll인 ntdll.dll에서 노출한 함수 NtWriteFile()을 호출한다.
(ntdll.dll의 NtWriteFile()함수는 실제 구현된 것이 아니라 실제 구현되어 있는 동일한 이름의 함수 NtWriteFile()(시스템 서비스 루틴)는 ntoskrnl.exe에 존재한다. ntdll.dll의 NtWriteFile()은 단지 SYSENTER(x86), SYSCALL(x64)명령을 실행하는 스텁 루틴(stub routine)이다. 이 명령어는 코드를 커널 모드로 전환한다.)
⑧ 이제 커널 모드에서 실행 중인 스레드(접근 제한이 해제)는 ntoskrnl.exe에 구현된 실제 함수 NtWriteFile()의 주소를 찾아야 한다. 이를 위해 시스템 서비스 디스크립터 테이블(SSDT, System Service Descripter Table)이라는 커널 공간의 테이블을 참조해 NtWriteFile()의 주소를 파악한다.
⑨ 그런 다음 I/O관리자의 I/O함수를 요청하는 윈도우 익스큐티브(ntoskrnl.exe)의 실제 NtWriteFile()(시스템 서비스 루틴)을 호출한다.
⑩ 그러면 I/O관리자는 해당 커널 모드 장치 드라이버에 요청하고 커널 모드 장치 드라이버는 하드웨어와 접속하고자 HAL에서 노출한 루틴을 사용한다.
'OS > 03 Windows' 카테고리의 다른 글
I/O 관련 작업(Device Driver, I/O Manager) (2) | 2021.05.07 |
---|---|
윈도우 프로세스(프로세스 관련) (0) | 2021.04.28 |