촉촉한초코칩

[DreamHack] Quiz: x86 Assembly 2, Quiz: x86 Assembly 3 본문

Study/System

[DreamHack] Quiz: x86 Assembly 2, Quiz: x86 Assembly 3

햄친구베이컨 2024. 3. 17. 22:25
Quiz: x86 Assembly 2

 

mov dl, BYTE PTR[rsi+rcx]
rsi + rcx = 0x400000
BYTE PTR[rsi+rcx] : rsi+rcx가 가리키는 주소에서 데이터를 1바이트 만큼 참조
dl = 0x67

xor dl, 0x30
dl = 0x57

mov BYTE PTR[rsi+rcx], dl
rsi+rcx = 0x400000
BYTE PTR[rsi+rcx] = 0x67
0x67에 dl을 넣는다는 뜻이므로 0x67값은 0x57이 된다.

inc rcx
rcx = 1

cmp rcx, 0x19
rcx의 값인 1과 0x19를 비교한다. 
rcx 값이 0x19보다 크면 다음 줄을 실행하고, 크지 않으면 다시 처음으로 돌아간다. (jmp 1)
16진수인 19를 10진수로 변환하면 25이므로 처음부터 종료될 때까지 총 26번 반복한다. 

 

파이썬 코드로 작성해보면 (^ 연산은 xor을 의미한다.)

memory = [0x67, 0x55, 0x5c, 0x53, 0x5f, 0x5d, 0x55, 0x10, 0x44,
          0x5f, 0x10, 0x51, 0x43, 0x43, 0x55, 0x5d, 0x52, 0x5c,
          0x49, 0x10, 0x47, 0x5f, 0x42, 0x5c, 0x54, 0x11, 0x00,
          0x00, 0x00, 0x00, 0x00, 0x00]

for i in range(26):
    memory[i] = memory[i]^0x30

for c in range(26):
    print(chr(memory[c]), end='')

정답 : Welcome to assembly world!

어셈블리 코드를 그대로 작성해보면 while문으로 반복해서 쓸 수 있다.

rcx = 0

memory = [0x67, 0x55, 0x5c, 0x53, 0x5f, 0x5d, 0x55, 0x10, 0x44,
          0x5f, 0x10, 0x51, 0x43, 0x43, 0x55, 0x5d, 0x52, 0x5c,
          0x49, 0x10, 0x47, 0x5f, 0x42, 0x5c, 0x54, 0x11, 0x00,
          0x00, 0x00, 0x00, 0x00, 0x00]


while(rcx < 26):
    dl = memory[0+rcx] #0x40000은 메모리 상에서 한 줄을 뜻하기 때문에 파이썬에서 배열로 사용하려면 0을 더해준다.
    dl^=0x30
    memory[0+rcx] = dl
    rcx+=1

for c in range(26):
    print(chr(memory[c]), end="")

 

Quiz: x86 Assembly 3

 

push rbp
스택 최상단에 rbp를 넣는다. (스택 프레임을 만드는 부분)

mov rbp, rsp
* rsp : 사용중인 스택의 위치를 가리키는 포인터
* rbp : 스택의 바닥을 가리키는 포인터
→ 스택 바닥을 가리키는 곳에 사용중인 스택 위치를 대입한다. 

mov esi, 0xf

mov rdi, 0x400500
rdi에 0x400500을 넣는다.

call 0x400497 <write_n>
write_n 함수 실행 

push rbp

mov rbp, rsp
* rsp : 사용중인 스택의 위치를 가리키는 포인터
* rbp : 스택의 바닥을 가리키는 포인터
→ 스택 바닥을 가리키는 곳에 사용중인 스택 위치를 대입한다. 

mov QWORD PTR[rbp-0x8], rdi
rdi를 rbp-0x8 위치에 8 바이트만큼 참조하여 대입한다. 
rdi = 0x400500
rbp-0x8 = 0x400500

mov DWORD PTR [rbp-0xc], esi
esi의 값 중 8바이트를 rbp-0xc에 대입한다.
esi = 0xf
rbp-0xc = 0xf

xor rdx, rdx
같은 값을 xor 연산하면 0이 나온다.
rdx = 0

mov edx, DWORD PTR[rbp-0xc]
rbp - 0xc = 0xf
edx = 0xf

mov rsi, QWORD PTR[rbp-0x8]
rbp - 0x8 = 0x400500
rsi = 0x400500

mov rdi, 0x1

mov rax, 0x1

syscall
rax값이 0x1이므로 write를 호출한다. 

syscall rax arg0 (rdi) arg1 (rsi) arg2 (rdx)
write 0x01 unsigned int fd
* 파일 디스크립터 지정

const char *buf 
* 해당 메모리에 위치한 값을 가리킨다.
size_t count
* 크기 

rax = 0x1 > syscall 호출 
rdi = 0x1 > 출력 
rsi = 0x400500 > 0x3037207964343372
rdx = 0xf > 0으로 초기화한 후 mov edx, DWORD PTR [rbp-0xc] 연산으로 edx 값은 0xf가 되었다. edx는 rdx의 하위 32비트이므로 0xf가 된다. 즉 크기는 10진수인 15 바이트가 된다. 
→ 0x400500에 있는 데이터 값을 15바이트 만큼 출력한다.

0x30 37 20 79 64 34 33 72 = [0x30, 0x37, 0x20, 0x79, 0x64, 0x34, 0x33, 0x72]
0x00 3f 36 75 62 33 64 20 = [0x00, 0x3f, 0x36, 0x75, 0x62, 0x33, 0x64]
15바이트를 채워야 하므로 다음 주소의 값도 사용한다. 

pop rbp

ret

 

파이썬 코드로 작성

memory = [0x30, 0x37, 0x20, 0x79, 0x64, 0x34, 0x33, 0x72,
        0x00, 0x3f, 0x36, 0x75, 0x62, 0x33, 0x64]

for c in range(15):
    print(chr(memory[c]), end='')

→ 07 yd43r?6ub3d
하지만 x86-64는 리틀 앤디안을 사용하기 때문에 거꾸로 읽어야 한다. 

07 yd43r → r35dy 07

?6ub3d →d3bu6?

합치면 r35dy 07 d3bu6? 이 된다. 

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

[Dreamhack] basic_exploitation_001  (0) 2024.03.31
[Dreamhack] basic_exploitation_000  (0) 2024.03.31
[Dreamhack] Return Address Overwrite  (1) 2024.03.31
Bomb Lab Phase 1-3  (0) 2024.03.24
시스템 스터디 정리  (0) 2024.03.17