대외활동 및 팀플/빡공팟(P4C) 시스템 해킹 트랙 4기

[빡공팟 4기] 6주차 과제: 어셈블리어로 구구단 구현하기/c로 더블 링크드 리스트 구현하기

EYEN 2022. 5. 29. 23:48

#1 어셈블리어로 구구단 구현하기

1. 컴파일 과정

1)전처리-hello.c->hello.i
필요한 헤더파일들을 불러옴
2)컴파일-hello.i->hello.s
고급 언어를 저급언어로 바꿈
3)어셈블-hello.s->hello.o
어셈블리어를 기계어로 바꾸어 오브젝트 파일 생성
4)링크-hello.0->hello.exe
여러 오브젝트 파일들끼리, 오브젝트 파일과 라이브러리를 합침


2. 파일 생성

nano 파일명.s
vi 파일명.s

3. 목적파일로 만들고 링킹하기

nasm -f elf54 -o 파일명.o 파일명.s
gcc -o 파일명 파일명.o

4. memory segment 구조

1) stack: 지역변수를 포함한 함수에 대한 정보들을 포함한다. 여기서 취약점이 제일 많이 나온다. 버퍼오버플로우같ㅇ느 공격을 시도해볼 수 있다.
2) heap: 여기는 동적으로 할당된 변수가 저장
3) bss: 프로그램에서 사용될 변수들이 실제로 위치하는 영역이고, 그 변수들은 초기화되지 않음
4) data: 초기화된 변수
5) test: 시스템이 알아듣는 기계어로 변환된 소스코드
*main함수 실행했을 때 스택 프레임

버퍼
변수 c
RBP(base pointer)
여기서부터 스택이 쌓일 것이다.
RET(return 주소)

5. 구현하기

global main, _start
section .bss
buffer: resb 128 ;입력받은 값 저장할 변수
res: resb 10 ;곱 결과를 저장할 변수
increase: resb 10 ;입력 값에 곱하는 증가 값을 저장할 변수

section .data ;출력할 문자 초기화
fmt: db '%d', 0 
equal: db '=',0 
mul: db '*', 0
end: db 10, 0

section .text ;실행할 코드 저장되는 영역
        extern printf ;c의 표준 라이브러리 함수 사용
        extern scanf
        extern exit

global main: gcc -o~~할 때 링커에게 보여질 수 있게 하는 부분
exetern:c 표준 라이브러리 호출

multi:
        push rbp 
        mov rbp,rsp
        xor rax, rax 	 	;rax=0
        xor rbx, rbx 	 	;rbx=0
        inc rax		     	;rax++
        inc rbx  	     	;rbx++

_loop: ;반복문 구성하기
        mov rcx, 9   	  	;rcx에 9 전달
        cmp rbx, rcx		;rbx랑 9랑 비교
        jg _end 		;rbx가 더 크면 _end로
        mov rax, rbx 	 	;rax에 rbx값전달
        mov rdi,[buffer] 	;rdi포인터에 입력받은 값
        mul rdi 		;rax*rdi
        mov [increase],rbx 	;increase에 rbx값 저장
        mov [res], rax 		;res에 rax값 저장
        call print_line 
        inc rbx 			;rbx+1
        jmp _loop 			;_loop로 이동

_end:
        leave
        ret

print_line:
        push rbp 
        mov rbp, rsp
        mov rsi, [buffer] 
        mov rdi, fmt 
        mov rax, 0
        call printf  		;printf("%d", buffer)
        mov rdi, mul 
        mov rax, 0 
        call printf  		;printf("*")
        mov rsi, [increase]
        mov rdi, fmt 
        mov rax, 0
        call printf  		;printf("%d", increase)
        mov rdi, equal 
        mov rax,0 
        call printf  		;printf("=")
        mov rsi, [res]
        mov rdi, fmt
        mov rax, 0
        call printf  		;printf("%d", res)
        mov rdi, end
        mov rax,0 
        call printf  		;printf("\n")
        leave
        ret 

main: 
_start:
        push rbp 
        mov rsi, buffer  	;rsi에 buffer주소값 rsi->buffer
        mov rdi, fmt  		;rdi에 fmt("%d") 주소값
        mov rax, 0  		;system call
        call scanf  		;입력 받기
        call multi  		;multi 함수 호출
        call exit  		;exit 함수 호출
        pop rbp 
        ret

push a:스택에 a값을 넣음
pop a:스택에 있는 a값을 뺌
mov a,b: b값을 a에 넣음
lea a,[b]: b주소를 a에 넣음
add,sub:더하기 빼기, 더하고 빼는 숫자를 정할 수 있음
inc,dec: 1더하기 빼기
mul:곱하기
cmp:compare 값 비교하기
jmp:jump 특정위치로 건너 뛰기
call:함수 호출

*system call table

https://chromium.googlesource.com/chromiumos/docs/+/master/constants/syscalls.md

#2. c언어로 더블 링크드 리스트 구현하기

1. 더블 링크드 리스트란

기존은 싱글 링크드 리스트의 단점을 보완하여 포인터가 양방향으로 있는 자료구조. 탐색할 때 용이하다.
예를 들어 탐색 시 100개의 노드 중 99번째에 찾는 노드가 있을 때 싱글 링크드 리스트는 맨 처음부터 99번째까지 거쳐야하는데 더블 링크드 리스트는 100번째부터 거꾸로 찾을 수 있어서 시간 단축이 된다.

2. 구현 절차

1) 다음 노드를 가리키는 포인터, 이전 노드를 가리키는 포인터
2) 맨 앞, 맨 뒤에 노드 추가하기
3) 중간에 노드 끼워넣기
4) 노드 삭제하기

-구체적으로

//노드 추가
//current->new, new->next/ current<-new, new<-next 포인터를 만드는 과정임

Current->Next->Prev=newNode;  //new<-next
newNode->Prev=Current;        //current<-new
newNode->Next=Current->Next;  //new->next
Current->Next=newNode;        //current->new
//노드 삭제


    //맨 앞에 있을 때
    if(*head==remove){ //
        *head=remove->Next; //head를 next로 바꿈
    }
    //리무브가 다음 링크가 있을 때
    if(remove->Next !=NULL){		
        remove->Next->Prev =remove->Prev;
    }
    //리무브가 전 링크가 있을 때
    if(remove->Prev!=NULL){
        remove->Prev->Next =remove->Next;
    }
    deleteNode(remove);
}

3. 구현하기

#include <stdio.h>
#include <stdlib.h>

typedef struct listNode{ 
    int Data;
    struct listNode* Next; 
    struct listNode* Prev; 
}Node;

//노드 생성
Node* createNode(int data){ //노드 만들기
    Node* newNode =(Node*)malloc(sizeof(Node)); //노드만큼의 메모리

    newNode->Data=data; //변수들 초기화
    newNode->Next=NULL; //새 노드의 다음 노드는 비어있음.
    newNode->Prev=NULL; //새 노드의 이전 노드는 비어있음.

    return newNode; 
}

//노드 소멸
void deleteNode(Node* Node){ //노드 삭제하기
    free(Node); //메모리에서 없앰
}

Node* getNodeAt(Node* head, int index){ //몇 번째 인덱스의 노드를 가져옴
    Node*horse= head; 
    int count=0;

    while(horse!=NULL){ //다음 노드가 없을 때까지, 마지막 노드까지
        if(count++ ==index){
            return horse;
        }
        horse = horse->Next; //못찾으면 그냥 다음
    }
    reutrn NULL;//못찾으면 null
}

int countNode(Node* head){ //리스트에 노드 몇개인지
    int count=0;
    Node* horse=head;//시작점으로

    while(horse!=NULL){ 
        horse=horse->Next;
        count++;
    }
    return count;
}


//맨 앞, 맨 뒤에 노드 추가
void addNode(Node** head, Node* newNode){ //끝에 노드 추가
//리스트가 없을 때
    if (*head == NULL){
        *head =newNode;
    }
//리스트가 있을 때
    else{
        Node* horse=(*head);

        while(horse->Next !=NULL){
            horse=horse->Next; //맨 마지막 노드 찾는중
        }
        horse->Next = newNode;//새노드 생성
        newNode->Prev=horse;// 전 노드랑 연결
    }
}

//중간에 노드 끼워넣기
void insertNode(Node* Current, Node* newNode){ 
//맨 앞
    if(Current->Prev ==NULL &&Current->Next == NULL){
        Current->Next =newNode;
        newNode->Prev=Current;

    } //맨 앞 아님
        //맨 뒤
        if(Current->Next ==NULL){
            Current->Next =newNode; //노드 생성
            newNode->Prev =Current; //노드 이전거랑 연결
        }
        //꼬리 아님=>중간 2개
        else{//current->new, new->next/ current<-new, new<-next 포인터를 만드는 과정임
            Current->Next->Prev=newNode;//노드 생성
            newNode->Prev=Current;//이전 거랑 연결
            newNode->Next=Current->Next; // 이후 거랑 연결
            Current->Next=newNode;//
        }
}

//노드 삭제
void removeNode (Node** head,Node* remove){ //노드 추가

    //맨 앞에 있을 때
    if(*head==remove){ //
        *head=remove->Next; //head를 next로 바꿈
    }
    //리무브가 다음 링크가 있을 때
    if(remove->Next !=NULL){
        remove->Next->Prev =remove->Prev;//노드1->노드2->노드2이전=노드1->노드1이전
    }
    //리무브가 전 링크가 있을 때
    if(remove->Prev!=NULL){
        remove->Prev->Next =remove->Next;
    }
    deleteNode(remove);
}



참고
더블 링크드 리스트 다함께 C언어로 코딩 해봐요 - by Gunny (Korean Ver.) - YouTube
[C] 더블 링크드 리스트, 이중 연결 (Do.. : 네이버블로그 (naver.com)
시스템 해킹 강좌 1강 - 칼리 리눅스(Kali Linux) 실습 환경 구축하기 (System Hacking Tutorial 2017 #1) - YouTube
어셈블리로 구구단 짜기(nasm) (tistory.com)