리틀엔디안(Little-endian)과 빅엔디안(Big-endian)이해하기
오늘은 패킷 분석과 조금은 다른 이야기를 꺼내볼까 한다. 머 그렇다고 패킷 분석과는
동떨어진 내용은 아니다. 분석을 하다보면 필요한 내용이기 때문이다. 앞으로 계속
여러가지 내용을 소개하는데 있어, '바이트 오더(Byte Order)' 를 설명할 필요가 있을거 같아
잠깐 짚고 넘어가볼까 한다.
바이트오더 하면 떠오르는게 리틀 엔디안(Little Endian) 과 빅 엔디안(Big Endian) 이다.
프로그램이나 리버싱 과정에서 헷갈리기도 하는 부분이다.
우선 리틀 엔디안은 주로 인텔(Intel)프로세스 계열에서 사용하는 바이트 오더 이다.
메모리 시작 주소가 하위 바이트부터 기록된다는 것이고 그 반대로 빅 엔디안은
메모리 시작 주소에 상위 바이트부터 기록된다. 주로 UNIX 시스템인 RISC 프로세서
계열에서 사용하는 바이트 오더이다. 이렇게 메모리에 저장하는 방식이 차이가 있다보니
가끔 혼돈 스럽기도 하다. 다음 도표는 메모리기 기록되는 것을 쉽게 이해할 수 있도록 기술되어 있다.
[도표] 레지스터와 메모리 위치 매핑 관계 , 출처 : 위키피디아(www.wikipedia.org)
우리가 패킷분석때 많이 보게되는 네트워크 프로토콜은 기본적으로 빅 엔디안 표현이다.
빅 엔디안을 표현하면 아래와 같다.
increasing addresses → | |||||
... | 0Ah | 0Bh | 0Ch | 0Dh | ... |
[출처] 위키피디아
0x0A 는 메모리 하위 주소에 위치하게 되고 차례로 0x0B , 0x0C, 0x0D 가 온다.
읽는 순서는 왼쪽 -> 오른쪽 순서로 읽으면 되므로 사람이 보기에는 가장 편한 방식이다.
다음 리틀 엔디안은
increasing addresses → | |||||
... | 0Dh | 0Ch | 0Bh | 0Ah | ... |
[출처] 위키피디아
빅 엔디안 과 반대로 0x0D 가 메모리 하위 주소에 오게된다. 상위바이트로 올라가면서
차례로 나머지 값이 들어간다. 리틀 엔디안 또는 빅 엔디안에 따라 받아 들이는 쪽에서
처리를 잘못하게 되면 엉뚱한 형태가 되므로 주의가 필요하다. 예를 들어, 취약점 등을
리버싱 하는 과정에서 해당 값 들이 기록되어 있는 형태를 제대로 이해할 필요가 있다.
일단 여기서는 쉽게 요약 정리하면,
빅 엔디안값은 왼쪽-> 오른쪽 순서로 읽고, 리틀 엔디안값은 반대로 오른쪽->왼쪽 순서로
읽으면 된다는 점이다. 그리고 네트워크 상에서 표준으로 이용되는 프로토콜은
네트워크 바이트 오더인 빅 엔디안으로 생각하자.
복잡한게 싫다면 이것만 알고 있으면 된다.
참고로 다음은 리틀/빅 엔디안을 이용하는 시스템이다.
[리틀 엔디안]
- Linux on x86, x64, Alpha and Itanium
- Mac OS X on x86, x64
- OpenVMS on VAX, Alpha and Itanium
- Solaris on x86, x64, PowerPC
- Tru64 UNIX on Alpha
- Windows on x86, x64 and Itanium
[빅 엔디안]
- AIX on POWER
- AmigaOS on PowerPC and 680x0
- HP-UX on Itanium and PA-RISC
- Linux on MIPS, SPARC, PA-RISC, POWER, PowerPC, 680x0, ESA/390, and z/Architecture
- Mac OS on PowerPC and 680x0
- Mac OS X on PowerPC
- MVS and DOS/VSE on ESA/390, and z/VSE and z/OS on z/Architecture
- Solaris on SPARC
우리가 주로 이용하는 시스템은 인텔 기반의 리눅스와 윈도우이므로 리틀 엔디안 방식이다. 단, 네트워크를 통해 전송되는 것은 빅 엔디안이다.
C#에서 엔디안 변경
less than 1 minute read
C#에서 네트워크 통신을 할게 있어서 바이트오더를 빅엔디안으로 해주려다가 알게 된게 있어서 정리한다.
일단 바이트오더링을 하기 위해 리틀엔디안-빅엔디안의 변환이 필요한데 C#에는 이를 지원하는 메서드가 이미 있었다.
http://msdn.microsoft.com/en-us/library/fw3e4a0f 에 있는 HostToNetworkOrder 와 NetworkToHostOrder 라는 메서드인데 이상한건 이 메서드들이 int16, int32, int64만 지원한다는 것이다. 난 uint16, uint32를 변경해야했기에 아무리 해봐도 이 메서드를 통해서는 바이트오더를 변경할 수 없었다. 강제로 형변환도 해봤지만 데이터가 잘못 들어가기만 했다.
구글을 한참 뒤져서 스택오버플로우에서 답을 찾았다.
http://stackoverflow.com/questions/11232594/c-sharp-reversed-ushort
위 링크의 리플처럼 다음의 코드를 사용하면 된다.
var arr = new byte[1];
arr = BitConverter.GetBytes(total_length);
Array.Reverse(arr);
arr.CopyTo(buffer, offset);
offset += Marshal.SizeOf(total_length);
원리는 바이트배열을 선언하고 비트컨버터를 통해 바이트를 구한다음 Array.Reverse()를 통해 바이트를 거꾸로 하는 것이다. 한마디로 바이트오더링을 직접 구현한 것이라고 보면 될 것 같다.
여튼 이 코드를 통해 테스트해보니 정상작동함을 확인했다.
'개발자 > Computer Science' 카테고리의 다른 글
CS관련 지식 정리 (0) | 2020.04.15 |
---|