| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | |||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 12 | 13 | 14 | 15 | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 |
| 26 | 27 | 28 | 29 | 30 |
- 리버싱
- pe format
- __fastcall
- 함수 호출 규약
- RVA
- rev
- Programmers
- 리치헤더
- CodeEngn
- x32
- Dos Stub
- x64
- 32bit
- 파이썬
- __stdcall
- Python
- image section header
- ABI
- 프로그래머스
- stack frame
- __vectorcall
- Image dos header
- __cdecl
- Reversing
- crackme
- 코드엔진
- Rich Header
- 실행파일
- 크랙미
- Calling Convention
- Today
- Total
kj0on
[Definition] MS-DOS Stub Program 본문
1. DOS Stub

IMAGE_DOS_HEADER의 e_lfanew 필드는 PE 시그니처 "PE\0\0"가 시작되는 오프셋을 가리키므로 윈도우로더는 DOS Stub 전체를 건너뛰고 곧바로 IMAGE_NT_HEADERS를 읽는다.

DOS Stub 영역은 크게 “This program cannot be run in DOS mode.” 문구를 띄우고 프로그램을 종료하는 MS-DOS Stub Program과 컴파일러, 링커 빌드 정보가 숨겨져 있는 Rich Header 두 부분으로 구성된다.
2. MS-DOS Stub Program
2-1. 작업환경

우선 MS-DOS Stub Program 부터 살펴본다. 해당 기능을 하는 부분은 위와 같다.

HxD 또는 010Editor를 사용해서 MS-DOS Stub Program의 영역의 값만 그대로 복사해서 새 HEX파일을 만들어 준다.

DOS Stub은 PE Format이 등장하기 전의 16비트 DOS 환경을 위한 코드이므로 이를 올바르게 디코딩하고 분석하기 위해서는 IDA를 16bit 아키텍처로 설정하여 열어야 한다.

비교적 간단한 코드를 확인할 수 있다. 전체 코드를 확인했으니 이제 하나씩 분석할 차례다.
2-2. 코드 분석
2-2-1. 전체 코드
# code
push cs
pop ds
mov dx, 0Eh
mov ah, 9
int 21h
mov ax, 4C01h
int 21h
# data
db 54h
db 'his program cannot be run in DOS mode.', 0Dh, 0Dh, 0Ah
db '$', 0
2-2-2. 세그먼트 초기화
push cs
pop ds
CS를 스택에 넣고 다시 pop해서 CS와 DS를 동기화 해준다. 이런 코드가 있는 이유는 MS-DOS Stub Program 안의 문자열은 CS 안에 있기 때문이다. CS를 DS와 같게 맞춰 문자열 데이터를 읽기 위해 위 코드를 사용한다. 16bit 인텔 CPU에서는 mov ds, cs 같은 세그먼트 간 직접 이동을 금지한다. 허용되는 방법은 두 가지로 레지스터를 경유 하거나 스택을 경유해야 한다. DOS Stub Program에서는 스택을 경유하는 방법을 사용했다.
2-2-3. 문자열 주소
mov dx, 0Eh
DX에는 문자열의 오프셋(0x0E)이 들어간다. DOS에서는 포인터를 DS:DX 형식으로 사용하기 때문에 앞서 DS를 CS와 동일하게 맞춰준 것이다. 이 설정 덕분에 DX는 내부의 문자열을 정확히 가리킬 수 있다.

실제 문자열 오프셋이 0x0E인 것을 확인할 수 있다.
2-2-4. 문자열 출력
mov ah, 9
int 21h
API를 호출해 문자열을 출력하는 부분이다. DOS API는 https://en.wikipedia.org/wiki/DOS_API에서 확인이 가능하다.
| 09h | Display string | 1.0+ |
DOS 에서는 API를 호출할 때 AH의 번호를 통해 기능을 선택한다. 0x09의 의미는 Display string로 문자열을 출력하는 기능이다.
| 21h | Main DOS API | 1.0+ | Implemented in DOS kernel |
int 0x21은 DOS API를 호출하라는 의미를 가진다. AH 레지스터에 넣어 둔 기능 코드를 보고 원하는 일을 해준다. 결과적으로 DS:DX가 가리키는 문자열을 화면에 출력하라는 기능을 한다. 문자열의 끝은 '$'로 구분한다.
2-2-5. 종료
mov ax, 4C01h
int 21h
AX에 값을 넣는데 그 이유는 일부 API는 인자가 필요하기 때문이다. 이때 0x01을 사용한다. AH는 기능 코드가 들어가고 AL에서는 API에서 사용될 인자인 0x01을 넣고 있는 것이다.
| 4Ch | Terminate with return code | 2.0+ |
AH 0x4C에 해당하는 기능은 프로그램을 종료하고 AL을 반환하라는 일을 해준다. 따라서 int 0x21을 하는 순간 0x01을 반환하고 프로그램은 종료된다.
2-2-6. 문자열
# data
db 54h
db 'his program cannot be run in DOS mode.', 0Dh, 0Dh, 0Ah
db '$', 0
"This program cannot be run in DOS mode." 이후 0x0D, 0x0D, 0x0A가 나타나는데 이는 줄 바꿈(0x0D)과 커서 이동(0x0A)을 의미하며 출력 후 화면을 정리하고 다음 줄로 이동하기 위해 사용된다. 그 뒤에 나오는 '$' 문자는 DOS API에서 문자열의 끝을 나타내는 종료 기호로 해석되기 때문에 DOS는 해당 문자열을 '$' 직전까지 출력한 뒤 중단한다.
3. 파일
'Reversing > Definition' 카테고리의 다른 글
| [Definition] Rich Header (3) | 2025.07.05 |
|---|---|
| [Definition] 64비트 윈도우 실행 파일 구조 (PE+ Format) (0) | 2025.07.04 |
| [Definition] 32비트 윈도우 실행 파일 구조 (PE Format) (2) | 2025.07.03 |
| [Definition] COFF (Common Object File Format) (1) | 2025.07.01 |
| [Definition] 엔디언 (Endianness) (0) | 2025.06.29 |