ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 어셈블리어(Assembly)의 기초와 8086 프로세서
    Basic knowledge/시스템(Pwn) 2018. 11. 27. 07:00

    어셈블리를 하기 위한 기초 지식

     

    1. 하드웨어

    1) CPU 

    컴퓨터에서 구성 단위 중 기억, 연산, 제어의 3대 기능을 종합하는 장치인 Central Processing Unit(중앙 처리 장치)의 줄임말

    메모리에 있는 내용을 읽고, 쓰며 데이터를 메모리와 각 레지스터로 보내는 역할

    - 하나의 프로세서는 12~14개의 레지스터가 있고, CPU의 연산, 논리 장치는 숫자와 기호에 관한 연산자를 인식

    - 클럭 속도, IPC, 코어 수에 따라서 CPU의 성능이 결정됩니다.

     

    2) RAM

    - 사용자가 자유롭게 내용을 읽고 쓰고 지울수 있는 기억장치 이며, ROM과 함께 컴퓨터의 주기억 장치 역할

    - 각 셀들은 숫자 값을 포함하고 주소가 정해지는 형식이며 프로그램에서는 메모리라고 불리는 것들은 RAM을 의미


    2. 8086 Memory Architecture

       

     

    기본적으로 커널은 64byte영역에 자리를 잡지만 오늘날에는 그보다 더큰 영역을 사용합니다. 

    몇 비트의 시스템이냐에 따라서 CPU가 한번에 처리할수 있는 데이터의 범위가 정해져 있습니다.

    32bit 시스템에서는 0 ~ 2^32(제곱)-1 의 범위 만큼 주소를 할당 할 수 있습니다.

    64bit 시스템에서는 0 ~ 2^64(제곱)-1 의 범위 만큼 주소를 할당 할 수 있는것 입니다.


    운영 체제 에서 하나의 프로세스를 실행 시키게 되면 프로세스를 segment라는 단위로 묶어서 가용 메모리 영역에 저장 시키게 됩니다.

    위의 사진의 구조를 보면 3개의 segment로 나뉘어 진것을 볼수 있는데

    각각의 segment 사이에는 이용가능한 공간(Available Space)가 존재하게 됩니다.

    segment 내부로 들어가 보면 Stack segment, Data segment, Code segment 가 있는 것을 알 수 있습니다.

    하나의 시스템에는 최대 16,383개의 segment가 들어가 있고 하나의 segment에는 최대 2^32(제곱) byte의 크기를 가질 수 있습니다.


    1. Data segment

    Data segment에는 프로그램이 실행될 때 사용되는 데이터(전역 변수)가 담기는 부분입니다.

    data segment는 4개로 나뉘어서 구성되는데 

    - 현재 모듈의 data structure

    - 상위 레벨로 부터 받아들이는 데이터 모듈

    - 동적 생성 데이터

    - 다른 프로그램과 공유하는 공유 데이터


    2. Stack segment

    Stack segment는 현재 수행되고 있는 handler, task, program이 저장되는 데이터 영역으로

    우리가 사용하는 버퍼가 바로 이 Stack segment에 저장되게 됩니다. 

    Stack은 처음 생성 될때 필요한 크기만큼 만들어지고 프로세스의 명령에 의해 데이터를 저장하는 과정을 거치는데

    이를 SP(Stack Pointer)이라고 합니다. (SP는 나중에 어셈블리어를 통한 코드를 해석할때 매우 중요한 역할을 합니다.)

    Stack에 데이터를 저장하고 읽어 들이는 과정은 PUSH와 POP instruction에 의해서 수행된다.


    3. Code segment

    Code segment는 시스템이 알아 들을수 있는 명령어, 즉, instruction들이 들어있다.

    instruction을 실행 하면서 분기와 점프, 시스템 호출과 같은 행동을 하게 되는데 분기와 점프는 메모리 상의 주소를 지정해줘야 합니다.

    하지만 segment는 자신이 메모리 내에서 어디에 위치하는지 정확히 지정할 수가 없습니다. 


    그래서 segment는 logical address를 사용하는데 실제 메모리 상의 주소인 physical address를 구하는데 중요한 역할을 합니다.

    위의 사진에 있는 segment selector을 통해서 자신의 시작주소인 offset을 알 수 있는데 

    physical address = logical address + offset 을 통해 구할 수 있습니다.



    3. 8086 CPU 레지스터 구조


    레지스터(register)란?

    - CPU는 빠르게 읽고 써야 하는 데이터 이기 때문에 CPU 내부에 존재하는 메모리를 사용해야 하는데 해당하는 메모리를 일컫는다.


    레지스터의 종류 :

    1. 범용 레지스터(General-Purpose register)

    - 논리 연산, 수리 연산에 사용되는 피연산자, 주소를 계산하는데 사용되는 피연산자 이며, 주소가 들어있는 레지스터

    2. 세그먼트 레지스터(segment register)

    - code segment, data segment, stack segment 가 가르키는 주소가 들어있는 레지스터

    3. 플래그 레지스터(Program status and control register)

    - 프로그램의 현재 상태나 조건등을 검사하는데 사용되는 플래그들이 들어있는 레지스터

    4. 인스트럭션 포인터(instruction pointer)

    - 다음 수행해야 하는 명령어(instruction)가 있는 메모리 주소가 들어있는 레지스터 


    일반적인 레지스터의 구성


    범용 레지스터(General-Purpose register)


    - 프로그래머가 임의로 조작이 가능한 레지스터

    - 4개의 32bit 변수가 있다고 보면 되는데 16bit 시절에는 AX, BX, CX, DX 라고 불렸으나 32bit 시스템으로 전환이 되면서 앞에 Extend를 의미하는 E가 붙게 되면서 EAX, EBX, ECX, EDX라고 불리게 되었다.

    - EAX, EBX, ECX, EDX 레지스터를 자유롭게 사용하여 나중에는 기계어 코드를 읽고 편하게 이해하기 위해서 사용한다.


    EAX - 덧셈, 곱셈, 나눗셈 같은 연산 수행을 하고나서 그 반환값이 저장 (피연산자와 연산 결과의 저장소)

    EBX - 메모리 주소를 저장 할 때 쓰인다 (DS segment안의 데이터를 가리키는 포인터)

    ECX - 반복문 돌릴때 반복 카운터로 쓰인다 (문자열 처리나 루프를 위한 카운터)

    EDX - EAX 서포트로 주로 쓰이는데, 곱셈, 나눗셈 연산 할 때 서포트로 쓰인다 (I/O 포인터)


    ESI -  데이터를 조작하거나 복사할때 데이터의 주소가 저장 됩니다 (DS 레지스터가 가리키는 data segment 내의 어느 데이터를 가리키는 포인터)

    EDI - 데이터를 복사할 때 목적지 주소가 저장 됩니다 (ES 레지스터가 가리키는 data segment 내의 어느 데이터를 가리키는 포인터)

    ESP - 스택 프레임에서 스택의 가장 마지막 주소가 저장됩니다 (SS 레지스터가 가리키는 stack segment의 맨 꼭대기를 가리키는 포인터)

    EBP - 스택 프레임에서 스택의 시작 주소가 저장 됩니다 (SS 레지스터가 가리키는 스택 상의 한 데이터를 가리키는 포인터)


    세그먼트 레지스터(Segment register)


    - CS 레지스터 : code segment

    - DS, ES, FS, GS 레지스터 : data segment

    - SS 레지스터 : stack segment



    플래그 레지스터(Program status and control register)

    - 상태 플래그, 컨트롤 플래그, 시스템 플래그들의 집합이다. 

    - 각 레지스터 bit마다 의미를 가지고 있고 1또는 0의 값을 가지며 On/Off 혹은 True/False를 표시합니다.

    - 1, 3, 5, 15, 22~31번 비트는 예약되어 있어서 소프트웨어에 의해 조작할 수없게 되어있다.


    - Status flags 와 System flags 로 나뉘어져 있다.


    Status flags

    - CF(carry flag) : 연산을 수행하면 서 carry 혹은 borrow가 발생하면 1이 된다.

    - PF(Parity flag) : 연산 결과 최하위 바이트의 값이 1이 짝수 일 경우에 1이 된다. 패리티 체크할 때 사용

    - AF(Adjust flag) : 연산 결과 carry나 borrow가 3bit 이상 발생할 경우 1이 된다.

    - ZF(Zero flag) : 결과가 zero임을 가리킨다. if문  같은 조건문이 만족될 때 set 된다.

    - SF(Sign flag) : 이것은 연산 결과 최상위 비트의 값과 같다. Signed 변수의 경우 양수이면 0, 음수이면 1이된다.

    - OF(Overflow flag) : 정수형 결과값이 너무 큰 양수이거나 너무 작은 음수여서 데이터 타입에 모두 들어가지 않을 경우 1이된다.

    - DF(Direction flag) : 문자열 처리에 있어서 1일 경우 문자열 처리 instruction이 자동으로 감소, 0일 경우 자동으로 증가.


    System flags

    - IF(Interrupt enable flag) : 프로세서 에게 mask한 interrupt에 응답할수 있게 하려면 1을 준다.

    - TF(Trap flag) : 디버깅을 할 때 single-step을 가능하게 하려면 1을 준다.

    - IOPL(I/O privilege level field) : 현재 수행 중인 프로세스 혹은 task의 권한 레벨을 가리킨다.

    - NT(Nested task flag) : Interrupt의 chain을 제어한다. 1이 되면 이전 실행 task와 현재 task가 연결 되어 있음을 나타낸다.

    - RF(Resume flag) : Exception debug 하기 위해 프로세서의 응답을 제어한다.

    - VM(Virtual-8086 mode flag) : Virtual-8086 모드를 사용 하려면 1을 준다.

    - AC(Alignment check flag) : 이비트와 CR0 레지스터의 AM비트가 set 되어 있으면 메모리 레퍼런스의 체크가 가능

    - VIF(Virtual interrupt flag) : IF flag의 가상 이미지 이다. VIP flag와 결합 시켜 사용

    - VIP(Virtual interrupt pending flag) : 인터럽트가 pending(경쟁 상태) 되었음을 가리킨다.

    - ID(Identification flag) : CPUID instruction을 지원하는 CPU인지 나타낸다.



    flag는 깃발의 의미로 올라가면 1(On), 내려가면 0(Off)로 이해하시면 됩니다.


    4. 어셈 블리어 명령어 정리


     명령어

    예제 

    설명 

     push

     push %eax

     eax의 값을 스택에 저장 

    pop

     pop %eax

     스택 가장 상위에 있는 값을 꺼내서 eax에 저장

    mov

     mov %eax, %evx

     메모리나 레지스터의 값을 옮길때 사용 

    lea

     leal(%esi), %ecx 

     %esi의 주소값을 %ecx에 옮긴다. 

    inc 

     inc %eax

     %eax의 값을 1증가 시킨다 

    dec 

     dec %eax 

     %eax의 값을 1감소 시킨다

    add 

     add %eax, %ebx 

     레지스터나 메모리의 값을 더할때 쓰인다 

    sub 

     sub %eax, %ebx 

     레지스터나 메모리의 값을 뺄때 쓰인다 

    call 

     call proc 

     프로시저를 호출한다 

    ret 

     ret 

     호출했던 바로 다음 지점으로 이동 

    cmp 

     cmp %eax, %ebx 

     레지스터와 레지스터 값을 비교 

    jmp 

     jmp proc 

     특정한 곳으로 분기 

    int 

     int $0x80 

     OS에 할당된 인터럽트 영역을 system call 

    nop 

     nop

     아무 동작도 하지 않는다 


    'Basic knowledge > 시스템(Pwn)' 카테고리의 다른 글

    시스템 호출(System Call)  (0) 2018.11.26

    댓글

Designed by Tistory.