⚡ 쉘코드 아키텍처와 어셈블리 엔지니어링 (Shellcode Engineering)

⚙️ x86_64 execve("/bin/sh", NULL, NULL) 분석
Hex Opcode Assembly Instruction 작동 및 레지스터 설정
🔒 쉘코드 제작 시 3대 핵심 제약과 원리

1. Null Byte (\x00) 완벽 제거 원리

strcpy(), gets(), sprintf() 등 취약한 C 문자열 함수는 \x00을 문자열의 끝(Null Terminator)으로 인식하고 복사를 즉시 중단함. 따라서 mov $0, %eax (기계어: b8 00 00 00 00) 대신 xor %eax, %eax (기계어: 31 c0)를 사용하여 널 바이트를 완전 제거함.

2. 위치 독립성 (Position-Independent Code)

공격 대상 프로세스의 스택 주소는 ASLR이나 환경 변수에 따라 계속 변할 수 있음. 따라서 하드코딩된 절대 주소를 일체 사용하지 않고, push %rbx를 통해 스택에 문자열을 직접 구성한 뒤 mov %rsp, %rdi로 현재 스택 주소를 참조하는 위치 독립적 테크닉을 구사함.

3. 문자열 리틀 엔디언 역순 푸시 (Little-Endian)

"/bin/sh"는 7바이트이므로 8바이트 정렬을 맞추기 위해 슬래시를 하나 더 붙여 "/bin//sh" (8바이트)를 만듦. 리눅스는 리틀 엔디언이므로 메모리 역순인 0x68732f2f6e69622f ("hs//nib/") 값으로 레지스터에 적재한 뒤 스택에 PUSH함.

💡 시스템 콜 규약 요약:
• Syscall Number: RAX = 59 (0x3b)
• 1st Arg (Filename): RDI = "/bin//sh" 포인터
• 2nd Arg (Argv): RSI = ["/bin//sh", NULL] 배열 포인터
• 3rd Arg (Envp): RDX = NULL (0)