바이트 오더링

Etc

0 views

1. 개요 및 정의

1.1 한 줄 요약

  • 책을 읽을 때 왼쪽에서 오른쪽으로 읽는 문화권(영어, 한국어)과 오른쪽에서 왼쪽으로 읽는 문화권(아랍어)이 있듯이, 컴퓨터가 데이터(숫자)를 메모리에 기록할 때 앞쪽 바이트부터 쓸지 뒤쪽 바이트부터 쓸지 결정하는 규칙이다.

1.2 공식 정의

  • 바이트 오더링(Byte Ordering)은 2 바이트 이상의 크기를 갖는 멀티 바이트 데이터를 메모리에 연속적으로 저장할 때의 바이트 정렬 방식을 의미한다.
    • 이를 엔디안(Endianness)이라고도 부른다.

참고: 바이트 오더링은 비트(Bit)의 순서가 아닌 바이트(Byte) 단위의 순서를 제어하는 규칙이다.

2. 동작 원리

  • 데이터 0x01234567 (4 Bytes)을 메모리에 저장하는 상황을 가정하여 내부 동작을 설명한다.

2.1 주요 개념: MSB와 LSB (Byte Level)

image.png
  • 바이트 오더링을 이해하기 위해서는 비트가 아닌 바이트 관점의 MSB와 LSB를 명확히 해야 한다.
    • MSB (Most Significant Byte): 가장 큰 자릿수의 바이트 (왼쪽 끝, 0x01)
    • LSB (Least Significant Byte): 가장 작은 자릿수의 바이트 (오른쪽 끝, 0x67)

2.2 방식 비교: 빅 엔디안 vs 리틀 엔디안

구분빅 엔디안 (Big Endian)리틀 엔디안 (Little Endian)
저장 순서MSB부터 낮은 주소에 저장LSB부터 낮은 주소에 저장
직관성사람이 숫자를 읽는 순서와 동일함사람이 읽기에 역순이라 직관적이지 않음
주요 사용네트워크 프로토콜, SPARC, RISC 일부Intel x86, x86-64 (대부분의 PC/서버)
연산 장점대소 비교가 빠름 (큰 자릿수부터 비교)산술 연산이 빠름 (캐리 처리가 쉬움)

2.3 메모리 적재 예시

  • 32비트 정수 0x01234567을 메모리 주소 0x1000에 저장할 때의 차이는 다음과 같다.
  1. 빅 엔디안 (Big Endian)

    1. 낮은 주소(0x1000)에 가장 큰 바이트(0x01)가 먼저 들어간다.
    Address   |  Value
    ------------------
    0x1000    |  0x01  (MSB)
    0x1001    |  0x23
    0x1002    |  0x45
    0x1003    |  0x67  (LSB)
    
  2. 리틀 엔디안 (Little Endian)

    1. 낮은 주소(0x1000)에 가장 작은 바이트(0x67)가 먼저 들어간다.
    Address   |  Value
    ------------------
    0x1000    |  0x67  (LSB)
    0x1001    |  0x45
    0x1002    |  0x23
    0x1003    |  0x01  (MSB)
    

3. 사용법 및 구문 (Syntax)

  • C언어를 통해 문자열과 정수형 데이터가 메모리에 저장되는 차이를 확인함으로써 리틀 엔디안의 특징을 파악할 수 있다.

3.1 문자열 vs 정수형 데이터 저장 차이

  • 문자열(String)
    • 1 바이트 크기의 문자(char) 배열이다.
    • 1 바이트 단위 데이터이므로 엔디안의 영향을 받지 않고 순서 그대로 저장된다.
  • 정수(Integer)
    • 4 바이트(32비트) 등의 멀티 바이트 데이터이므로, x86 아키텍처에서는 리틀 엔디안 방식으로 역순 저장된다.

3.2 검증 코드 (C Language)

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

int main(void) {
    // 1. 문자열 "ABCD" (ASCII: 0x41, 0x42, 0x43, 0x44)
    // 문자열은 1바이트 배열이므로 엔디안의 영향을 받지 않음
    char *str = "ABCD"; 
    puts(str); // 출력: ABCD
    
    // 메모리 덤프 가정: 
    // 낮은 주소 -> [0x41][0x42][0x43][0x44] -> 높은 주소

    // 2. 정수 0x41424344
    // 4바이트 정수는 리틀 엔디안에 의해 바이트 역순으로 저장됨
    unsigned int num = 0x41424344;
    printf("Integer Output: %x\n", num); // 출력: 41424344 (CPU가 읽어서 다시 정렬해 보여줌)

    // 실제 메모리에 저장된 바이트 확인 (포인터 캐스팅 이용)
    unsigned char *ptr = (unsigned char *)&num;
    
    printf("Memory Dump: ");
    for(int i = 0; i < 4; i++) {
        printf("0x%x ", ptr[i]);
    }
    // 출력 결과: 0x44 0x43 0x42 0x41
    // 설명: LSB인 0x44가 가장 낮은 인덱스(주소)에 저장됨
    
    return 0;
}

4. 기타

4.1 시스템 해킹에서 페이로드 구성

  • 만약 RET를 덮어쓰려고 할 때 아키텍쳐가 어떤 엔디언 방식을 사용하는지 보고 작성해야한다.
  • 상황:
    • 리턴 주소를 0x08048320으로 덮어씌워야 한다.
  • 작성:
    • 대상 시스템이 리틀 엔디안(x86)이라면, 페이로드는 \x20\x83\x04\x08 순서로 작성해야 한다.
  • 실수:
    • 만약 \x08\x04\x83\x20 그대로 입력하면 엉뚱한 주소로 점프하여 공격에 실패(Segmentation Fault)한다.

Loading comments...