orw 셸코드 char buf[0x30]; int fd = open("/tmp/flag", RD_ONLY, NULL); read(fd, buf, 0x30); write(1, buf, 0x30); syscall rax arg0 (rdi) arg1 (rsi) arg2 (rdx) read 0x00 unsigned int fd char *buf size_t count write 0x01 unsigned int fd const char *buf size_t count open 0x02 const char *filename int flags umode_t mode 1. int fd = open(“/tmp/flag”, O_RDONLY, NULL) syscall rax arg0 (rdi) arg1 (rsi) arg2 ..
0x0000000000401136 :endbr64 // 인텔 프로세서 관련 보안 기술 0x000000000040113a :push rbp // rbp 레지스터의 값을 스택에 push 0x000000000040113b :mov rbp,rsp // rsp의 값을 rbp에 대입 0x000000000040113e :lea rax,[rip+0xebf] # 0x402004 // [rip+0xebf]의 유효주소를 rax에 대입 0x0000000000401145 :mov rdi,rax // rax의 값을 rdi에 대입 0x0000000000401148 :mov eax,0x0 // 0x0을 eax에 대입 0x000000000040114d :call 0x401040 // printf 함수 호출 0x0000000000401..
gdb : 리눅스의 대표적인 디버거. 실습예제 // Name: debugee.c // Compile: gcc -o debugee debugee.c -no-pie #include int main(void) { int sum = 0; int val1 = 1; int val2 = 2; sum = val1 + val2; printf("1 + 2 = %d\n", sum); return 0; } gdb debugee로 디버깅 시작 $ gcc -o debugee debugee.c -no-pie $ gdb debugee 리눅스는 실행파일의 형식으로 ELF (Executable and Linkable Format)를 규정하고 있다. ELF는 크게 헤더 와 여러 섹션 들로 구성되어 있다. 헤더에는 실행에 필요한 여러 정보..
* 웜 : 감염된 컴퓨터 시스템에서 스스로를 복제하고 다른 컴퓨터로 복사본을 확산시킬 수 있는 악성 프로그램이다. 네트워크를 이용해 자신의 복사본을 다른 컴퓨터로 전송할 수 있으며, 때때로 자신의 복사본을 계속 만들어 하드 드라이브와 네트워크에 과부하를 주거나 대역폭과 같은 시스템 리소스를 고갈시킬 수 있다. 웜은 바이러스와 다르게 사람의 개입 없이 확산될 수 있는 자가 복제 프로그램이다.웜은 일단 시스템에 감염되면 스스로 새로운 감염원을 찾아 감염시킬 수 있다. * 웜의 감염 : 웜은 바이러스와 같이 호스트 프로그램이 필요하지 않기 때문에 다양한 운영 체제 취약점을 이용해 능동적으로 활용할 수 있다. 네트워크의 취점을 이용해 ActiveX, HTML 페이지에 숨어 있다가 사용자가 웹 페이지에 접속하면 ..
Opcode: 스택 * push val: val을 스택 최상단에 쌓음 연산 rsp -= 8 [rsp] = val * pop reg: 스택 최상단의 값을 꺼내서 reg에 대입 연산 rsp += 8 reg = [rsp-8] Opcode: 프로시저 컴퓨터 과학에서 프로시저(Procedure)는 특정 기능을 수행하는 코드 조각을 말한다. 프로시저를 사용하면 반복되는 연산을 프로시저 호출로 대체할 수 있어서 전체 코드의 크기를 줄일 수 있으며, 기능별로 코드 조각에 이름을 붙일 수 있게 되어 코드의 가독성을 크게 높일 수 있다. 프로시저를 부르는 행위를 호출(Call)이라고 부르며, 프로시저에서 돌아오는 것을 반환(Return)이라고 부른다. 프로시저를 호출할 때는 프로시저를 실행하고 나서 원래의 실행 흐름으로 ..
스택 영역 메모리의 스택 영역은 함수의 호출과 관계되는 지역 변수 및 매개변수가 저장되는 영역이다. 스택 영역은 함수의 호출과 함께 할당되며, 함수의 호출이 완료되면 소멸한다. 스택 프레임 (Stack Frame) 함수가 호출될 때 스택에는 함수의 매개변수, 함수 호출이 끝난 뒤 돌아갈 반환 주소값, 함수 내부 지역 변수가 저장된다. 이렇게 스택 영역에 차례대로 저장되는 함수의 호출 정보를 스택 프레임(Stack Frame)이라고 한다. 이러한 스택 프레임을 통해 함수의 호출이 모두 끝난 뒤에, 해당 함수가 호출되기 이전 상태로 되돌아갈 수 있다. 스택 프레임의 동작 방식 int main(void) { func1(); // func1() 호출 return 0; } void func1() { func2()..
레지스터(Register) : 특정한 목적으로 외부 정보를 일시적으로 기억하는 장치. 데이터를 읽고 쓰는 기능이 매우 빠르며, 중앙 처리 장치(CPU) 안에 사용된다. 1. 프로그램 카운터 (PC, Program Counter) : 프로그램 카운터 또는 명령어 포인터(IP, Instruction Pointer)는 메모리에서 가져올 명령어의 주소, 즉 메모리에서 읽어드릴 명령어의 주소를 저장한다. 2. 명령어 레지스터 (IR, Instruction Register) : 메모리에서 읽어 드린 해설할 명령어를 저장하는 레지스터이다. 3. 메모리 주소 레지스터 (MAR, Memory Address Register) : 메모리의 주소를 저장하는 레지스터이다. CPU가 읽어들이고자 하는 주소 값을 주소 버스로 보낼..
스택(Stack)이란? 쌓아놓은 더미라는 뜻. 데이터를 바닥에서부터 쌓아 올리는 구조. 스택에서 데이터 입/출력은 오로지 스택의 꼭대기에서만 이루어진다. 스택의 맨 아래에 있는 데이터를 꺼내려면 그 위에 있는 데이터를 모두 걷어내야 한다. 이처럼 스택은 가장 마지막에 들어간 데이터가 제일 먼저 나오는 LIFO(Last In - First Out : 후입선출) 형태를 띤다. 요소의 삽입과 삭제가 한쪽 끝에서만 이루어지는 것이 스택의 특징이다. 스택의 연산은 Push, Pop이 있다. Push 함수는 스택에 데이터를 추가한다. // 삽입 void push(StackType *S, element e) { if (is_full(S)) printf("Overflow\n"); else { S->top++;// to..