[Register]
rbx = 0x401A40
=================================
[Memory]
0x401a40 | 0x0000000012345678
0x401a48 | 0x0000000000C0FFEE
0x401a50 | 0x00000000DEADBEEF
0x401a58 | 0x00000000CAFEBABE
0x401a60 | 0x0000000087654321
=================================
[Code]
1: mov rax, [rbx+8]
2: lea rax, [rbx+8]
mov 는 두번째 인자의 값을 첫번째 인자에 대입하는 명령어이고, lea 는 두번째 인자의 주소값을 첫번째 인자에 대입한다.
따라서 code 1 까지 실행한 rax 의 값은 0x00000000COFFEE 이다.
이는 [rbx+8] = [0x401A48] 이기 때문이다.
같은 이유로 code 2 까지 실행하면 rax 에는 0x401A48 이 저장된다.
[Register]
rax = 0x31337
rbx = 0x555555554000
rcx = 0x2
=================================
[Memory]
0x555555554000| 0x0000000000000000
0x555555554008| 0x0000000000000001
0x555555554010| 0x0000000000000003
0x555555554018| 0x0000000000000005
0x555555554020| 0x000000000003133A
==================================
[Code]
1: add rax, [rbx+rcx*8]
2: add rcx, 2
3: sub rax, [rbx+rcx*8]
4: inc rax
code 1 에서 [rbx+rcx*8] 을 먼저 구해보면 다음과 같다.
rcx*8 = 0x2*8 = 0x10
[rbx+rcx*8] = 0x555555554000 + 0x10 = 0x555555554010
따라서 add rax, [rbx+rcx*8] 의 값은
add rax, [rbx+rcx*8] = 0x31337 + 0x0000000000000003 = 0x3133A
code 2 에서 rcx 가 2만큼 증가하여 0x4 가 된다.
code 3 에서의 결과는 아래와 같다.
sub rax, [rbx+rcx*8]
[rbx+rcx*8] = [rbx+0x4*8] = [rbx+0x20] = [0x555555554020] = 0x000000000003133A
==> rax == 0x3133A - 0x000000000003133A == 0
즉, code 3 까지 실행한 결과 rax = 0 이다.
마지막으로 code 4 에서 inc rax 를 한 결과는 1이므로 최종적으로 rax 에는 1이 저장된다.
[Register]
rax = 0xffffffff00000000
rbx = 0x00000000ffffffff
rcx = 0x123456789abcdef0
==================================
[Code]
1: and rax, rcx
2: and rbx, rcx
3: or rax, rbx
code 1에서 rax 의 결과는 아래와 같다.
and rax, rcx
==> 0xffffffff00000000 AND 0x123456789abcdef0
==> 0x1234567800000000
rax = 0x1234567800000000
code 2 에서 rbx 는 아래와 같다.
and rbx, rcx
==> 0x00000000ffffffff AND 0x123456789abcdef0
==> 0x000000009abcdef0
rbx = 0x000000009abcdef0
code 3 에서 rax 의 값은 아래와 같다.
or rax, rbx
==> 0x1234567800000000 OR 0x000000009abcdef0
==> 0x1234567800000000
rax = 0x123456789abcdef0
[Register]
rax = 0x35014541
rbx = 0xdeadbeef
==================================
[Code]
1: xor rax, rbx
2: xor rax, rbx
3: not eax
code 1 까지 실행한 rax 의 값은 다음과 같다.
xor rax, rbx
==> 0x35014541 XOR 0xdeadbeef
==> 0xebacfbae
rax = 0xebacfbae
XOR 연산부터는 복잡해서 사이트에서 했다;;
https://miniwebtool.com/ko/bitwise-calculator/?data_type=16&number1=0x35014541&number2=0xdeadbeef&operator=XOR
code 2 결과
xor rax, rbx
==> 0xebacfbae XOR 0xdeadbeef
==> 0x35014541
rax = 0x35014541
code 3 에서 eax가 rax의 하위 32비트 가리키므로 not eax 는 not rax 라고 생각할 수 있다.
not eax = not rax
==> not (0x35014541) == 0xcafebabe
rax = 0xcafebabe
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
먼저 code 1을 실행하기위해서 dl 레지스터에 대해 알아봤다.
위 사진에 의해서 dl == 0x00 이다
1: mov dl, BYTE PTR[rsi+rcx]
==> dl + BYTE PTR[0x400000 + 0]
==> dl + [0x4]
==> 0x0 + 0x67
==> 0x67
[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 2 를 실행한 결과는 다음과 같다.
2: xor dl, 0x30
==> 0x67 XOR 0x30
==> 0x57
dl = 0x57
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 3
3: mov BYTE PTR[rsi+rcx], dl
==> BYTE PTR[0x4] = 0x57
0x400000 | 0x57 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 0x70
code 4
4: inc rcx
rcx = 1
code 5
5: cmp rcx, 0x19
==> 0x1 CMP 0x19
ZF == 0
code 6
jg: Jump If A greater than B
6: jg end
==> if (0x10 > 0x19) true: end
==> if (0x10 > 0x19) false : code 7
code 7 에 도착하면 code 1 로 점프하여 처음부터 다시 해당 과정을 반복한다.
아래에는 해당 과정들을 회차별로 수행한 결과이다.
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]
// dl 에 [rsi+rcx] 대입
// dl 에 [0x400000] 대입
// dl = 0x67
2: xor dl, 0x30
// xor 0x67 0x30
// dl = 0x57
3: mov BYTE PTR[rsi+rcx], dl
// 0x400000 | 0x57
4: inc rcx
// rcx = 1
5: cmp rcx, 0x19
// 0x01, 0x19 비교
// 0x01 != 0x19 이므로 ZF = 0
6: jg end
// 0x10 > 0x19 일시 end 로 jump
// 그러나 False 이므로 Code 7 로 이동
7: jmp 1
// Code 1 로 점프
rcx = 1
rdx = 0
rsi = 0x400000
=======================
[Memory]
0x400000 | 0x57 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]
// dl 에 [0x400001] 대입
// dl = 0x55
2: xor dl, 0x30
// 0x55와 0x30 xor 연산
// dl = 0x65
3: mov BYTE PTR[rsi+rcx], dl
// 0x400001 | 0x65
4: inc rcx
// rcx = 2
5: cmp rcx, 0x19
// 0x2, 0x19 비교, 다르므로 ZF = 0
6: jg end
// 0x2 < 0x19 이므로 프로그램 종료 안함
// Code 7 로 이동
7: jmp 1
// Code 1로 이동
rcx = 0x2
rdx = 0
rsi = 0x400000
=======================
[Memory]
0x400000 | 0x57 0x65 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]
// dl 에 [rsi+rcx] 대입
// dl 에 [0x400002] 대입
// dl=0x5c
2: xor dl, 0x30
// 0x5c 와 0x30 xor 연산
// dl = 0x6c
3: mov BYTE PTR[rsi+rcx], dl
// 0x400002 | 0x6c
4: inc rcx
// rcx = 0x3
5: cmp rcx, 0x19
6: jg end
7: jmp 1
.
.
.
rcx = 0x19 일때까지 Code 1~ 7 반복 실행
rcx = 0x19
rdx = 0
rsi = 0x400000
=======================
[Memory]
0x400000 | 0x57 0x65 0x6c 0x63 0x6f 0x6d 0x65 0x20
0x400008 | 0x74 0x6f 0x20 0x61 0x73 0x73 0x65 0x6d
0x400010 | 0x62 0x6c 0x79 0x20 0x77 0x6f 0x72 0x6c
0x400018 | 0x64 0x11 0x00 0x00 0x00 0x00 0x00 0x00
=======================
[code]
1: mov dl, BYTE PTR[rsi+rcx]
// dl = [rsi+rcx]
// dl = [0x400019]
// dl = 0x11
2: xor dl, 0x30
// 0x11, 0x30의 xor 연산
// dl = 0x21
3: mov BYTE PTR[rsi+rcx], dl
// 0x400019 | 0x21
4: inc rcx
// rcx = 0x1a
5: cmp rcx, 0x19
// 0x1a > 0x19 이다
6: jg end
// 앞서 실행한 비교문에서 전자가 더 크기 때문에 프로그램 종료 !
rcx = 0x1a
rdx = 0
rsi = 0x400000
=======================
[Memory]
0x400000 | 0x57 0x65 0x6c 0x63 0x6f 0x6d 0x65 0x20
0x400008 | 0x74 0x6f 0x20 0x61 0x73 0x73 0x65 0x6d
0x400010 | 0x62 0x6c 0x79 0x20 0x77 0x6f 0x72 0x6c
0x400018 | 0x64 0x21 0x00 0x00 0x00 0x00 0x00 0x00
=======================
0x400000 ~ 0x400019 까지의 데이터를 ASCII 로 변경하면
[Code]
main:
push rbp
mov rbp, rsp
새로운 스택프레임 생성을 위해서 rsp 를 rpb 로 옮김
mov esi, 0xf
esi == 0xf (대입)
mov rdi, 0x400500
rdi == 0x400500 (대입)
call 0x400497 <write_n> // write_n 함수 호출
mov eax, 0x0
pop rbp
ret
일단 write_n 으로 이동한다
write_n:
push rbp
mov rbp, rsp
새로운 스택프레임 생성을 위해서 rsp 를 rpb 로 옮김
mov QWORD PTR [rbp-0x8],rdi
'rbp-0x8' 의 주소에 8byte 만큼 참조하여 rdi 대입
[rbp-0x8] == rdi == 0x400500
mov DWORD PTR [rbp-0xc],esi
'rbp-0xc' 의 주소에 4byte 만큼 참조하여 esi 대입
[rbp-0xc] == esi == 0xf
xor rdx, rdx // rdx 를 xor 연산
mov edx, DWORD PTR [rbp-0xc]
edx 에 'rbp-0xc' 의 주소에 있는 값을 4byte 만큼 참조하여 대입
edx == 0xf
mov rsi,QWORD PTR [rbp-0x8]
rsi == 'rbp-0x8'의 주소에 있는 값(8byte만큼 참조) == 0x400500
mov rdi, 0x1
rdi == 0x1
mov rax, 0x1
rax == 0x1
syscall
rax == 0x1 이기 때문에 write syscall 이 호출된다.
rdi == 0x1, rsi == 0x400500, edx == 0xf 이므로
커널이 write(0x1(stdout: 표준출력), 0x400500(출력할 데이터의 주소값), 0xf(문자열 길이)) 를 수행!
write 의 첫번째 arg0 은 ‘unsigned int fd’
즉,
0x400500 | 0x3037207964343372
-> 0x400500 | 0x30 0x37 0x20 0x79 0x64 0x34 0x33 0x72
-> (reverse)| 0x72 0x33 0x34 0x64 0x79 0x20 0x37 0x30
0x400508 | 0x003f367562336420
-> 0x400508 | 0x00 0x3f 0x36 0x75 0x62 0x33 0x64 0x20
-> (reverse)| 0x20 0x64 0x33 0x62 0x75 0x36 0x3f 0x00
이다. ASCII 코드로 변환하면, 다음과 같다
pop rbp
ret