본문 바로가기
정보보안/Reversing

[Reversing] 데이터 구성 단위, Endian, 보수(Complement)

by Yoonsoo Park 2025. 3. 31.

데이터 구성 단위 

일반적으로 모든 디지털 시스템에서는 2진수(binary)를 사용해서 데이터를 저장하고 처리한다. 

즉, 2진수는 디지털 데이터의 최소 단위이며 bit 단위를 사용한다. 

 

하지만, 저장 장치(storage)의 용량이 증가하면서 메모리의 데이터 저장 최소 단위인 byte가 주로 사용되게 되었다. 

 

데이터 구성 단위는 다음과 같이 구성되어있다. nibble(1/2 byte, 4bit)과 word(2 byte, 16 bit)는 다소 어색할테니 기억해두자. 

 

 

16진수(hexadecimal)

모든 데이터를 2진수로 표현하면 비효율적이기에 2진수를 nibble(1/2 byte, 4bit) 단위로 묶어서 표현한다. 

 

16진수 구분 기호: 0x, x, $, &H, h 등

 

Big-Endian(BE) & Little Endian(LE)

바이트의 순서를 설명하는 용어이다. 

 

Big-Endian(BE): 가장 중요한 바이트(큰 쪽의 바이트)를 메모리의 낮은 주소부터 저장하는 방식

=> 네트워크 프로토콜에서 자주 사용된다

 

Little-Endian(LE): 가장 덜 중요한 바이트(작은 쪽의 바이트)를 메모리의 낮은 주부터 저장

=> x86 프로세스 등 많은 현대 컴퓨터 아키텍쳐에서 사용된다

 

0101 1010 0011 1100 1100 1010 1111 0001
이 값을 8비트(1바이트) 단위로 나누면 다음과 같습니다:

첫 번째 바이트: 0101 1010 → 0x5A

두 번째 바이트: 0011 1100 → 0x3C

세 번째 바이트: 1100 1010 → 0xCA

네 번째 바이트: 1111 0001 → 0xF1

아래 표는 빅 엔디안(Big-endian)과 리틀 엔디안(Little-endian) 방식으로 메모리에 저장했을 때의 바이트 순서를 나타냅니다.

메모리 주소 빅 엔디안 (BE) 리틀 엔디안 (LE)
0 0x5A 0xF1
1 0x3C 0xCA
2 0xCA 0x3C
3 0xF1 0x5A
빅 엔디안 (BE):
가장 중요한 바이트(0x5A)를 메모리의 가장 낮은 주소부터 저장합니다.
→ 최종 16진수 표현: 0x5A3CCAF1

리틀 엔디안 (LE):
가장 덜 중요한 바이트(0xF1)를 메모리의 가장 낮은 주소부터 저장합니다.
→ 최종 16진수 표현: 0xF1CA3C5A

=> 쉽게 말해 BE가 일반적으로 우리가 사용하는 방식, LE는 뒤쪽 바이트부터 낮은 메모리에 저장하는 방식

 

보수(Complement)

컴퓨터는 기본적으로 0양수만을 표현할 수 있는 2진수 체계를 사용한다. 그렇다면 뺄셈은?

 

뺄셈을 표현하기 위해 차용한 개념이 보수(complement)이다. 보수를 차용하여 뺄셈 연산을 계산함으로써 산술 논리 연산을 수행하는 ALU를 더 단순하게 설계하여 성능을 올릴 수 있다. 

 

보수란? '특정 숫자(2, 10 등) 특정 숫자를 채우게 하는데 필요한 수'이다. 

(특정 숫자 X에 Y를 더해서 각 자리마다 "자리올림(carry)"이 발생하게 만드는 경우 라고도 얘기한다)

예를 들자면, 4+6=10 이니까 4는 6에 대한 10의 보수라고 할 수 있다. 

 

보수의 특징은 N-1의 보수에 1을 더하면 N의 보수가 된다는 것이다. 

 

보수를 구하는 방법을 좀 정리해보자. 

 

2진수

1의 보수 = NOT 연산

2의 보수 = 1의 보수 + 1

0110 1100의 1의 보수와 2의 보수를 구하라

1001 0011 => 1의 보수
1001 0100 => 2의 보수 

 

8진수

7의 보수 = 8진수 숫자 각 자리 값을 7에서 뺸 값

8의 보수 = 자릿수만큼 8을 제곱한 수에서 8진수 숫자를 뺀 값 or 7의 보수 + 1

8진수 숫자 71의 7의 보수와 8의 보수를 구하라

77 - 71 = 6(8) => 71에 대한 7의 보수
100(8) - 71(8) = 7(8)
100(8)은 10진수 64

 

10진수 

9의 보수 = 숫자 각 자리 값을 9에서 뺸 값

10의 보수 = 자릿수만큼 10을 제곱한 수에서 숫자를 뺸 값 or 9의 보수

10진수 숫자 112에 대한 9의 보수와 10의 보수를 구하라

999 - 112 =  887 => 9의 보수
1000 - 112 = 888 => 10의 보수

 

다음과 같이 보수를 이해했다면, 보수를 이용한 뺄셈 연산을 알아보자.

 

컴퓨터에서 뺼셈을 하려는 경우는 빼려는 값의 보수를 취하고, 연산 결과에 자리 올림이 있는 경우 양수로 판단하고 가장 높은 자릿수를 절산하는 방식 또는 자리올림이 없는 경우 음수로 판단하고 결과값의 보수를 취하는 방식으로 해결할 수 있다. 

 

예를 들어,

 

10진수 연산의 경우,

90 - 33 = 90 + 67(33에 대한 10의 보수) = 157(2자리였는데, 자리올림(carry)이 발생 = 양수=> 최상위 자릿수 절산) = 57

90 - 95 = 90 + 5(5에 대한 10의 보수) = 95(자리올림 발생x => 음수 = 결과값의 보수를 취함) = -5

 

2진수 연산의 경우, X - Y = X + Y에 대한 2의 보수 

0110 1100 - 1100 1111 = 0110 1100 + 0011 0001(1의 보수+1 = 2의 보수) = 1001 1101(자리올림(carry) 없음 또는 최상위 비트가 1 => 음수) = 0110 0011(1의 보수 +1 = 2의 보수) = -99(signed)

 

낯선 개념이라 다소 헷갈리지만, 잘 기억해두자....