이번 문제는 register의 구조에 대해 먼저 파악해야한다.
기존에 문제들은 레지스터의 모든 비트를 다 활용하여 문제를 풀어왔다.
하지만 이번엔 한 레지스터의 특정 byte만을 사용하여 풀기 위해 <1>의 사진을 참고해야 한다.
우리가 사용하던 rax는 MSB ~ LSB 즉, Most Significate Bit ~ Lesat Significant Bit로 이루어져 있다.
쉽게 말하면 가장 높은 위치의 데이터 ~ 가장 낮은 위치의 데이터이다.
위와 같이 이름이 붙은 이유는 말그대로 가장 중요하기에 덜 변화가 생기고, 덜 중요하기에 많은 변화가 생기기 때문이다.
가령 MSB는 일반적으로 부호형에 쓰인다.
부호가 자주 바뀐다고 생각해보면 값의 변화에 매우 치명적이기에 덜 바뀌어야한다.
LSB의 경우, checksum 등으로 쓰인다.
자주바뀌어도 MSB보다 덜 무방하기 때문이다.
RAX를 뜯어 보면 하위 32 bit는 EAX, EAX의 하위 16bit는 AX, AX의 상위 8bit는 ah, 하위 8bit는 al로 이루어져 있다.
이를 인지하고 문제를 보자.
mov instruction하나만으로 값을 세팅하라고 한다.
간단히 다음과 같이 짜주면 풀린다.
.global _start
.section .text
_start:
mov $0x42, %ah
다음문제를 보자.
이번엔 이전 문제에서 배웠던 mod연산과 register에 대해 인지하고 있다는 전제가 필요하며 추가적인 정보를 알려준다.
요런식으로 나와있는데 한번 읽어보고 뭔소리인가 싶었다 처음엔...
해석해보자면, 만약 y가 2의 거듭제곱이라면 (y = 2^n), x % y의 결과는 x의 하위 n 비트와 같다는 말이다. 즉, x % 256이면 결과는 x의 하위 8비트와 같으며, x % 65536이면 결과는 x의 하위 16비트와 같다.
더 자세히 설명해보자면, 이는 2의 거듭제곱으로 나눌 때 발생하는 특이한 상황인데, 예를 들어 "256(2^8)로 나누는 경우, 나머지는 항상 8비트 이하의 값이 된다"는 것은 나머지는 항상 나누는 수보다 크지 않다는 개념을 적용하여 생각해보면 매우 쉽다.
상기의 연산 방법이 일반적인 나머지 연산에 비해 빠르다고 한다.
일반적으로 나머지 연산은 단순한 나눗셈보다 더 많은 하드웨어 리소스를 소비한다고 하는데... 아마 이전에 Assembly crash에서 볼 수 있듯 레지스터의 사용이나 명령어의 수가 늘어나기에 나오는 말 같다. 하지만, 상기의 방법은 간단한 명령만으로 처리되기에 효율적이며 성능상의 이점을 가지고 있다.
위의 내용을 인지하고, 문제를 접근해보자.
mov연산만을 사용하라고 한다.
처음엔 대체 어떻게 mov 만을 사용할지 감이 안왔는데, 우선 아래의 사진을 봐야한다.
좀 더 세부적인 레지스터의 사진이다.
상기에서 언급한대로 자신의 하위비트보다 클 수 없으므로 하위비트가 나머지가 된다. 그렇기에 그 하위 비트의 값을 세팅해주면된다.
그렇기에 코드는 아래와 같다.
.global _start
.section .text
_start:
mov %dil, %al
mov %si, %bx
mov %dil, %al : rdi의 하위 8비트를 al 레지스터로 복사한다. %dil은 rdi 레지스터의 하위 8비트를 가리키는 것이다
mov %si, %bx : rsi의 하위 16비트를 bx레지스터로 복사한다. %si는 rsi레지스터의 하위 16비트를 가리키는 것이다.
다음 문제를 위해 인지할 점은 1byte는 8bit라는 것만 알고 있으면 된다.
그리고서 양쪽으로 shift해준 후에 RAX에 삽입해주면 풀리는 문제이다.
코드는 아래와 같다.
.global _start
.section .text
_start:
mov %rdi, %rax
shl $24, %rax
shr $56, %rax
그러면 쨘!
'pwn.college' 카테고리의 다른 글
Introduction to ARM - level 1 ~ (0) | 2024.03.03 |
---|---|
Read file in Linux (0) | 2023.12.04 |
HTTP 요청 보내기 (0) | 2023.12.03 |