kj0on

[Definition] MS-DOS Stub Program 본문

Reversing/Definition

[Definition] MS-DOS Stub Program

kj0on 2025. 7. 4. 20:10
목차 접기

1. DOS Stub

[이미지1] DOS Stub

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

 

[이미지2] DOS Stub(Detail)

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


2. MS-DOS Stub Program

 

2-1. 작업환경

[이미지3] MS-DOS Stub Program

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

 

[이미지4] MS-DOS Stub Program

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

 

[이미지5] IDA

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

 

 

[이미지6] MS-DOS Stub Program

비교적 간단한 코드를 확인할 수 있다. 전체 코드를 확인했으니 이제 하나씩 분석할 차례다.


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는 내부의 문자열을 정확히 가리킬 수 있다.

 

[이미지7] MS-DOS Stub Program

 

실제 문자열 오프셋이 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. 파일

MS-DOS_Stub_Program
0.00MB