주어진 어셈블리 코드들은 모두 AT&T 문법으로 작성되어 있다. 이전에 정리했던 instructions는 intel 문법에 따른 어셈블리 코드들로, AT&T 문법에서는 intel 문법과 달리 오른쪽 operand에 값이 저장된다.
1번
.file "example1.c"
.section .rodata
.LC0:
.string "Hello world"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl $.LC0, %edi
movl $0, %eax
call printf
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.1) 4.8.4"
.section .note.GNU-stack,"",@progbits
- 따로 스택이 필요하지 않은 상황이라 스택을 할당하는 (sub rsp) 과정은 없는 것 같다.
- movl $.LC0, %edi : edi 레지스터에 LC0의 값 저장
#include <stdio.h>
int main(){
printf("Hello world");
return 0;
}
2번
.file "example2.c"
.section .rodata
.LC0:
.string "result : %d \n"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
#(1)
movl $10, -12(%rbp)
movl $20, -8(%rbp)
movl -8(%rbp), %eax
movl -12(%rbp), %edx
addl %edx, %eax
movl %eax, -4(%rbp)
#(2)
movl -8(%rbp), %eax
movl -12(%rbp), %edx
addl %edx, %eax
movl %eax, %esi
movl $.LC0, %edi
movl $0, %eax
call printf
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.1) 4.8.4"
.section .note.GNU-stack,"",@progbits
- subq $16, %rsp : rsp = rsp - 16, 즉 스택을 16byte만큼 할당한다.
레지스터(초기위치) | (1) | (2) |
---|---|---|
rbp | ||
rbp-4 | 30 (eax) | 30 |
rbp-8 | 20 |
20 (eax) |
rbp-12 | 10 (edx) | 10 (edx) |
rbp-16 |
(1)
- addl %edx, %eax : eax = eax + edx (저장된 값) → eax = 30
- movl %eax, -4(%rbp) : rbp-4의 위치에 eax값을 저장한다
(2)
- movl -8(%rbp), %eax movl -12(%rbp), %edx : [rbp-8]의 값 20 을 eax에 저장하고, [rbp-12]의 값 10을 edx에 저장한다
- addl %edx, %eax : eax = eax + edx = 30
- movl %eax, %esi : esi = eax, eax에 저장된 값(30)을 esi에 저장하고 이 값이 따로 스택 변수에 저장되지 않고 바로 printf 함수의 참조값으로 들어간다.
#include <stdio.h>
int main(){
int a = 10;
int b = 20;
int c = a+b;
printf("result : %d \n", a+b);
return 0;
}
[결과]
result : 30
3번
.file "example3.c"
.section .rodata
.LC0:
.string "a is 10"
.LC1:
.string "b is 10"
.LC2:
.string "b is 20"
.LC3:
.string "a=b"
.LC4:
.string "a!=b"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movl $10, -8(%rbp)
movl $20, -4(%rbp)
cmpl $10, -8(%rbp)
jne .L2
movl $.LC0, %edi # "a is 10"
call puts
.L2:
cmpl $10, -4(%rbp)
jne .L3
movl $.LC1, %edi # "b is 10"
call puts
jmp .L4
.L3:
cmpl $20, -4(%rbp)
jne .L4
movl $.LC2, %edi # "b is 20"
call puts
.L4:
movl -8(%rbp), %eax
cmpl -4(%rbp), %eax
jne .L5
movl $.LC3, %edi # "a=b"
call puts
jmp .L6
.L5:
movl $.LC4, %edi # "a!=b"
call puts
.L6:
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.1) 4.8.4"
.section .note.GNU-stack,"",@progbits
rbp | |
rbp-4 | 20 (b) |
rbp-8 | 10 (a) |
rbp-12 | |
rbp-16 |
- cmpl $10, -8(%rbp) jne .L2 : [rbp-8]의 값과 10을 비교하고 만약 같지 않은 경우(jne; jump if not equal) .L2로 점프
if ( a == 10 )
ㄴ puts(.LC0)
else 문을 따로 쓰지 않은 이유는 a가 10이 아닌 경우에는 바로 .L2로 점프하지만, a가 10인 경우에는 puts(LC0)를 하고 난 후 .L2 영역을 실행하기 때문이다. 정확히 알지 못하지만 어셈블리 코드의 흐름 상 영역을 편의상 나눠놨지만, 실제로는 쭉 이어지는 코드라고 생각했다.
- L2 영역
cmpl $10, -4(%rbp) # [rbp-4]의 값(20; b)와 10을 비교해서
jne .L3 # 같지않으면 L3영역으로 점프 / 같으면 바로 다음줄인 movl 명령
movl $.LC1, %edi # "b is 10" # edi 레지스터에 LC1의 값 "b is 10"을 저장하고
call puts # puts 함수를 호출 >> puts("b is 10")
jmp .L4 # L4 영역으로 점프
- L3 영역
cmpl $20, -4(%rbp) # [rbp-4]의 값(20; b)과 20을 비교해서
jne .L4 # 같지 않으면 L4로 점프 / 같으면 바로 다음줄 명령 실행
movl $.LC2, %edi # "b is 20" # edi 레지스터에 LC2의 값 "b is 20"을 저장하고
call puts # puts 함수를 호출 >> puts("b is 20")
- L4 영역
movl -8(%rbp), %eax # [rbp-8]의 값(10; a)을 eax 레지스터에 저장
cmpl -4(%rbp), %eax # [rbp-4]의 값(20; b)과 eax 레지스터에 저장된 값을 비교 >> a와 b의 값 비교
jne .L5 # a!=b 인 경우 L5로 점프
movl $.LC3, %edi # "a=b" # edi 레지스터에 LC3의 값 "a=b"를 저장하고
call puts # puts 함수를 호출 >> puts("a=b")
jmp .L6 # L6로 무조건 점프
- L5 영역
movl $.LC4, %edi # "a!=b" # a!=b인 경우 L5로 점프하고, edi 레지스터에 LC4의 값 "a!=b"를 저장
call puts # puts 함수 호출 >> puts("a!=b")
#include <stdio.h>
int main(){
int a = 10;
int b = 20;
//
if(a == 10)
puts("a is 10");
//.L2
if(b == 10)
puts("b is 10");
//.L3
else if(b == 20)
puts("b is 20");
if(a == b)
puts("a=b");
else
puts("a!=b");
return 0;
}
'Reversing > Reverse Engineering' 카테고리의 다른 글
매뉴얼 언패킹(MUP) 사례 - ESP Trick으로 OEP 찾기 (1) | 2021.05.18 |
---|---|
패킹과 언패킹 (0) | 2021.05.18 |
HelloWorld.exe (2) | 2021.04.01 |
Instruction (명령어) (0) | 2021.03.30 |
리버싱을 위한 기초 지식(구조) (0) | 2021.03.28 |