소프트웨어 버그 헌팅 - 2 (어셈블리 기초 및 실습)

할때마다 까먹는 어셈블리


Remind

힙영역은 메모리 내에서 아래서 위로 쌓인다.
스택영역은 메모리 내에서 위에서 아래로 쌓인다.
(툴따라 스택을 아래에서 위로 표현하기도 하기때문에 헷갈리지 말 것)

함수 호출하고 돌아하는 프로세스는 중요하니까 한번 더 생각해볼 것
(프롤로그, 에필로그)

함수 호출 규약으로는 cdecl, stdcall, fastcall 3가지가 존재하며,
cdecl은 x86 환경에서 대부분 C 컴파일러가 쓰는 규약
stdcall은 MS가 자체적으로 만든 호출 규약, 작고 빠른 프로그램에 용이
fastcall은 함수에 전달하는 파라미터 일부를 스택 메모리가 아닌 레지스터로 전달

PUSH: 스택에 데이터 삽입, 자동으로 ESP를 4바이트 감소
POP : 스택에서 4바이트를 꺼내와 지정한 레지스터에 삽입, 자동으로 ESP 4바이트 증가
MOV : 복사, 레지스터 -> 레지스터, 메모리 <-> 레지스터, Immediate 값 -> 레지스터 or 메모리
LEA : 복사(Load Effective Address), 레지스터 연산 결과를 레지스터에 저장(not 포인터)
- MOV는 값을 로드하고(mov eax, [ebp+esp+4])
- LEA는 유효 주소를 로드한다 - lea eax, [ebp+esp+4]
CMP : 두 값을 비교하고 플래그 값만 바꾼다.
TEST : 논리 비교, test eax, eax(eax 값이 0 인경우 ZF=1), 보통 jcc랑 같이 쓰임
JNE : Jump not equal(ZF=0)
JE : Jump Equal(ZF=1)
JLE : Jump Less Equal(ZF=1 or SF<>OF)
CALL : 우선 다음 실행할 명령어 주소를 스택에 삽입한 뒤, EIP에 해당 주소를 옮긴 뒤 이동하는 방식
          외부함수를 사용할 때 반드시 해당 함수가 포함된 라이브러리를 liner에 함께 전달해야 함


칼리 리눅스에서 gdb를 이용하여 간단하게 어셈블리를 만들고, 실습 진행

소프트웨어 버그 헌팅 - 1에 쓴 칼리사용할 예정이며, 실행시키고 네트워크 설정을 NAT로 변경

GDB가 가벼워서 범용적으로 사용가능하나 가독성이 썩 좋지 않음. 그래서 페다를 사용할 것

[gdb 설치]
sudo apt-get update
sudo apt-get install gdb

[peda로 바꾸기]
git clone https://github.com/longld/peda.git ~/peda
echo "source ~/peda/peda.py" >> ~/.gdbinit

[nasm 설치]
sudo apt-get install nasm


[컴파일]
nasm -f elf [코드작성파일명] && ld -m elf_i386 -o [결과파일명] [파일명.o] --entry main
nasm -f elf push && ld -m elf_i386 -o push.b push.o --entry main


GDB 명령어

disas main : 메인 코드 보기
b* main : main에 BP(브레이크 포인트)
r : 실행
disas : 현재 코드 보기
ni : 다음 명령어 실행하기
c : 실행된 상태에서 지행
ex) b* main으로 BP1 잡고 B*main+20으로 Bp2 잡고 r 누르면 BP1가는데 거기서 C 누르면 C2까지감



mov 코드

global main
section .text
main:

push 10h
push 0x1234
mov ebx, esp
mov eax, dword [ebx]
mov dword [esp], 0x5678


위 코드대로 저장하고, 컴파일 이후 GDB [결과파일명] 으로 불러온다.

이후 b* main으로 BP를 잡아주고 r 한다.

 


main+2 - 현재 ESP에서 0x10를 넣고 ESP-4 바이트한다.

main+7 - 현재 ESP에서 0x1234를 넣고 ESP-4 바이트한다.

main+9 - EBX에 있는 값을 eax에 넣는다.

main+11 - 5678을 ESP에 넣는다.


add 코드

global main
section .text
main:
    mov eax, esp
    sub esp, 8
    mov [eax], dword 5
    mov [eax+4], dword 3
    sub [eax+4], dword 1
    add [eax+4], dword 2
    add esp, 8


 


main - ESP의 값을 EAX에 넣는다.

main+2 - ESP에서 8을 뺸다( 지역함수 크기 할당)

main+5 - 5를 eax에 넣는다.

main+11 - 3을 eax+4로 간다

main+18 -1을 뺀다

main+22 - EAX에 있는 값에 2를 더한다

main+26 - ESP에 +8 하여 다시 할당한 것을 회수한다(데이터는 남아있을걸?)


JMP 코드

global main
section .text

main:
    mov ecx, 0
    mov eax, ecx
    inc ecx
    cmp ecx, 255
    jne 0x8049007
    ret

 

main - ecx의 값을 0으로 만듬

main+5 - ecx의 값을 eax 넣음

main+7 - ecx의 값을 1 증가

main+8 - ecx와 0xff를 비교(같으면 ZF=1)

main+14 - ZF의 값이 1이면 넘어가고 0이면 main+7로 점프



+ Recent posts