rsp-∞

[DreamHack] System Hacking 로드맵 Quiz: x86 Assembly 2 본문

Write-ups/system

[DreamHack] System Hacking 로드맵 Quiz: x86 Assembly 2

portrait.kim 2024. 3. 16. 15:44
Q1. end로 점프하면 프로그램이 종료된다고 가정하자. 프로그램이 종료됐을 때, 0x400000 부터 0x400019까지의 데이터를 대응되는 아스키 문자로 변환하면 어느 문자열이 나오는가?
[Register]
rcx = 0
rdx = 0
rsi = 0x400000
=======================
[Memory]
0x400000 | 0x67 0x55 0x5c 0x53 0x5f 0x5d 0x55 0x10
0x400008 | 0x44 0x5f 0x10 0x51 0x43 0x43 0x55 0x5d
0x400010 | 0x52 0x5c 0x49 0x10 0x47 0x5f 0x42 0x5c
0x400018 | 0x54 0x11 0x00 0x00 0x00 0x00 0x00 0x00
=======================
[code]
1: mov dl, BYTE PTR[rsi+rcx]
2: xor dl, 0x30
3: mov BYTE PTR[rsi+rcx], dl
4: inc rcx
5: cmp rcx, 0x19
6: jg end
7: jmp 1

 

문제를 보고 코드를 해석하는 과정에서 몇 가지 어셈블리 함수의 의미부터 정확히 찾아보았다.

 

1. cmp : operand1(rcx)과 operand2(0x19)의 값을 비교한다.

2. jg end : cmp의 결과가 참(1)인 경우 정해진 주소값(end)으로 이동한다.

3. jmp 1 : 1번 코드로 이동한다.

 

end로 점프하여 프로그램이 종료되기 위한 조건은 결국 cmp에서 rcx의 값이 0x19보다 커야 한다는 것. code 부분에서 1번부터 차근차근 계산해 보았다.

 

1: mov dl, BYTE PTR[rsi+rcx]

 

BYTE PTR[rsi+rcx]에서 rsi+rcx의 주소값을 1바이트 참조하여 dl에 저장한다. 해당 주소값이 0x4이므로 대입되는 dl의 값은 결국 0x67이다.

 

2: xor dl, 0x30

-0x67과 0x30의 논리 연산이 필요하다. 16진수 67과 30을 이진수로 풀어 내어 배타적 논리합(XOR) 연산을 하면 16진수로 다시 변환하였을 때의 값이 0x57이 된다. dl에는 다시 0x57이 저장된다.

 

3: mov BYTE PTR[rsi+rcx], dl

BYTE PTR[rsi+rcx]에 dl의 값인 0x57이 저장된다.

 

4: inc rcx

중요한 부분이라고 생각했다. 프로그램이 종료되기 위해 충족되어야 하는 조건인 0x19보다 큰 rcx가 될 때까지 1~7번 코드가 반복된다. 첫 번째 루프에서 0x1 > 0x19는 거짓으로 값이 0이므로 jg end를 실행할 수 없다. 7번 코드로 넘어가 다시 1번부터 루프를 돌린다.

 

루프마다 1씩 커지는 0x1이 0x19보다 커지려면 십진수로 변환하였을 때 1(0x1)이 25(0x19)보다 커져야 한다. 즉 0x1이 26이 되기 위해서는 rcx가 0에서 시작하는 첫 번째 루프를 포함하여 총 26번 반복하면 된다. 

 

 

파이썬 코드를 작성하고 실행시킨 화면이다. 어셈블리 코드를 직관적으로 파이썬 형식에 맞추어 입력했다. memory에는 chr()함수를 사용하여 아스키 코드로 변환될 문제 속 16진수들을 모두 넣었다(파이썬에서 아스키 코드를 출력하기 위해 주소값이 필요할 것 같지는 않아서 이를 모두 생략하고 한꺼번에 몰아넣었다.)

 

dl은 나중에 저장된 값으로 아스키 코드를 찾아야 하기 때문에 처음부터 memory 안에 있는 값을 대입시켜 놓으려 했다. 첫 번째 루프에서는 dl = memory[rcx+0x0]으로 memory[0], 결국 0x67의 값을 가지고 있게 된다. 문제를 보고 풀이한 첫 번째 dl의 값과 일치한다. 어셈블리 코드에서는 0x40000의 주소값에서 0x67을 찾기 위해 rsi를 더하였으나 내가 memory 리스트를 작성하면서 이를 생략했기 때문에 리스트의 첫 번째 원소의 값을 갖기 위해 0x0을 더한다.

dl = dl^0x30 코드는 사전에 값을 받은 dl을 0x30과 배타적 논리합을 수행하게 한다. 이후에 rcx를 1 증가시킨다. break문이 실행되기 전까지 1씩 매 루프에서 증가한다.

 

처음에는 해당 루프를 26번 반복하기 위해 break문을 작성하는 과정에서

if rcx>26:

          break;

위와 같은 형식의 코드를 작성하였다. 그러나 코드를 실행하면

Welcome to assembly world!0

이라는 결과가 나왔는데, 이는 파이썬 리스트에서 첫 번째 원소에 부여되는 인덱스가 0이라는 사실을 잠시 간과해서였다. 이를 수정하기 위해

if rcx>25:

    break;

와 같은 형태로 코드를 수정하였다.

 

또한

for text in memory:
    print(chr(text), end='')

에서 chr() 함수는 정수 값을 아스키 코드로 변환시켜 준다. end=''는 기본적으로 print(string) 형태의 코드에서 문자를 출력한 뒤 줄 바꿈을 하기 때문에 줄 바꿈 없이 각 문자를 한 줄에 나열하기 위해 사용하였다.

 

이 결과로 위 파이썬 코드를 실행하면 Welcome to assembly world!라는 문자열이 출력된다.

'Write-ups > system' 카테고리의 다른 글

[DreamHack] Return Address Overwrite 쉘 획득하기  (0) 2024.03.30
[Bomb Lab] Phase_3  (0) 2024.03.23
[Bomb Lab] Phase_2  (0) 2024.03.23
[Bomb Lab] Phase_1  (0) 2024.03.23
[DreamHack] System Hacking 로드맵 Quiz: x86 Assembly 3  (0) 2024.03.16