헥사 인코딩의 원리
페이지의 모든 문자는 하나 이상의 바이트로 저장됩니다. 헥사 인코딩은 그 바이트를 16진수로 다시 씁니다 — 바이트당 두 문자 — 그래서 특별한 도구 없이도 바이트 스트림을 읽을 수 있습니다.
- 텍스트를 바이트로 인코딩. UTF-8 모드는
new TextEncoder().encode(text)로 입력을 처리하여 바이트 값의Uint8Array를 반환합니다. Latin-1 모드는charCodeAt(0) & 0xFF로 각 코드 유닛의 하위 8비트를 가져옵니다. 이는 레거시 ISO-8859-1 코덱이 수행하는 변환과 동일합니다. - 각 바이트를 두 자리 헥사로 렌더링. 각 바이트는
byte.toString(16).padStart(2, "0")로 두 자리 헥사로 매핑됩니다. 대소문자 토글은 출력 문자를 대문자(A-F) 또는 소문자(a-f)로 선택합니다. - 묶음 및 접두사 적용. 묶음은 바이트 사이에 구분자를 삽입합니다: 단일 공백, 대시, 또는 4바이트마다 공백. 0x 접두사는 전체 문자열 앞에 한 번(없음 묶음) 또는 바이트마다(공백 묶음) 붙일 수 있어 C 배열과 바이너리 diff 도구가 기대하는 형식에 맞출 수 있습니다.
- 역방향 디코딩. Hex → 텍스트 모드는 입력에서 모든 공백, 대시,
0x접두사를 제거하고 나머지 문자를/^[0-9a-fA-F]+$/로 검증하며 홀수 길이 문자열은 거부합니다. 그런 다음 연속된 바이트 쌍에서Uint8Array를 재구성합니다. UTF-8 모드는new TextDecoder("utf-8", { fatal: true })로 배열을 디코딩하고, Latin-1 모드는 각 바이트를String.fromCharCode(b)로 매핑합니다. - 빠른 반복을 위한 실시간 모드. 실시간 모드는 기본적으로 켜져 있습니다. 키를 누를 때마다 150 ms 디바운스 재변환이 실행되어 변환 버튼을 누르지 않아도 붙여넣고 편집하면서 반대편 창이 업데이트되는 것을 볼 수 있습니다.
Hex 변환기를 사용하는 이유
- 바이너리 프로토콜 디버깅. Modbus, DNP3, CoAP 같은 와이어 포맷은 특정 바이트 오프셋에 헤더를 채워 넣습니다. 캡처된 프레임을 헥사로 읽으면 각 필드를 한눈에 파악할 수 있고, 같은 바이트를 ASCII로 뒤집으면 바이너리 프레이밍 안에 숨어 있는 평문 페이로드를 찾아낼 수 있습니다.
- 임베디드 펌웨어 작업. JTAG 및 SWD 프로브는 메모리 내용을 헥사로 보고합니다. 메모리 영역을 ASCII로 변환하면 파일 경로, 오류 메시지, 벤더 서명 같은 임베디드 문자열이 드러나 펌웨어의 어느 위치를 보고 있는지 파악하는 데 도움이 됩니다.
- 패킷 캡처 읽기. Wireshark와 tcpdump는 각 패킷을 왼쪽에 헥사, 오른쪽에 ASCII로 표시하는 바이트 창을 제공합니다. 여기서 변환하면 버그 리포트나 채팅 로그에서 헥사 블롭을 복사해 캡처 도구에 다시 가져오지 않고도 바이트가 실제로 무엇을 말하는지 읽을 수 있습니다.
- 바이트 수준 비교. 두 바이너리 파일을 비교하는 것은 어느 바이트가 변경되었는지 찾는 것으로 귀결됩니다. 두 쪽을 일관된 묶음으로 헥사로 변환하면 텍스트 편집기에서 diff가 정렬되어 내장 diff 도구가 변경된 바이트를 강조 표시할 수 있습니다.
주요 활용 사례
Hex ↔ ASCII 변환은 바이트 스트림이 단순한 텍스트 페이로드 이상일 때마다 리버스 엔지니어링, 보안, 임베디드 작업 전반에 걸쳐 등장합니다.
- 리버스 엔지니어링: strings 저항성 바이너리에서 헥사 덤프를 가져와 인쇄 가능한 ASCII로 디코딩되는 구간을 찾아내고, 그 문자열로 디스어셈블리의 위치를 파악합니다.
- 네트워크 포렌식: Wireshark에서 단일 패킷 페이로드를 헥사로 복사해 여기에 붙여넣고, 전체 캡처를 내보내지 않고도 애플리케이션 계층 텍스트를 읽습니다.
- 암호화 자료 처리: 키, IV, HMAC 태그는 헥사 문자열로 전달되는 경우가 많습니다. 바이트로 디코딩해 길이가 알고리즘과 일치하는지 확인합니다 — AES-128은 16바이트, AES-256은 32바이트.
예시 풀이
텍스트 → Hex, UTF-8, 소문자, 바이트마다 공백 묶음, 접두사 끄기를 선택하세요. Hi를 입력하면 출력은 48 69입니다. 접두사를 켜고 묶음을 없음으로 바꾸면 같은 입력이 0x4869로 렌더링됩니다. 이모지 😀를 입력하면 UTF-8 모드에서 f0 9f 98 80이 출력됩니다 — 코드 포인트 하나에 4바이트로, 이모지가 전송 크기를 늘리는 이유입니다. Hex → 텍스트로 전환하고 0x48-65-6C 6C 6F를 붙여넣으면 파서가 접두사, 대시, 공백을 제거하고 Hello를 재구성합니다.
FAQ
헥사 인코딩이란 무엇인가요?
헥사 인코딩(16진 인코딩)은 바이트 스트림을 16진수로 씁니다 — 바이트당 두 ASCII 문자. 각 헥사 자릿수는 4비트를 커버하므로 두 자릿수가 8비트 바이트 하나를 커버합니다. 알파벳은 0-9 다음 A-F(또는 a-f)로 이어지며 대소문자는 순전히 표현의 선택이고 디코더는 둘 다 수용합니다. 헥사는 프로토콜 명세서, 디버거 출력, 암호화 키에서 원시 바이트를 쓰는 표준 방식입니다 — 바이너리보다 두 배 압축적이고 텍스트에서 인쇄 불가 문자 문제를 피할 수 있기 때문입니다.
이모지가 헥사에서 4바이트가 되는 이유는 무엇인가요?
UTF-8은 가변 길이 인코딩입니다. ASCII 문자(U+0000~U+007F)는 1바이트, Latin-1 보충은 2바이트, 대부분의 BMP 코드 포인트는 3바이트, U+FFFF 이상 문자 — 대부분의 이모지 포함 — 는 4바이트를 차지합니다. 웃는 얼굴 😀는 U+1F600이고 F0 9F 98 80으로 인코딩됩니다. 고정 폭 바이트 뷰가 필요하다면 Latin-1로 전환하세요 — 단, Latin-1은 첫 256개 코드 포인트만 커버하므로 그 범위 밖의 문자는 라운드트립이 불가능합니다.
Latin-1 / ISO-8859-1을 지원하나요?
예. 텍스트 인코딩 옵션을 Latin-1 (ISO-8859-1)로 전환하세요. 인코딩은 각 JavaScript 코드 유닛의 하위 8비트(charCodeAt(0) & 0xFF)를 취합니다. 이는 레거시 단일 바이트 매핑과 일치합니다. 디코딩은 각 바이트에 String.fromCharCode(byte)를 사용합니다. 각 바이트가 정확히 하나의 문자에 해당하는 구형 Windows-1252 또는 유니코드 이전 시스템의 출력을 다룰 때 Latin-1을 사용하세요.
변환이 브라우저에서 이루어지나요?
예. 변환기는 단일 정적 페이지로 TextEncoder, TextDecoder, 소규모 파서를 실행합니다. 업로드도, API 호출도, 붙여넣은 내용에 대한 분석도 없습니다 — 사이트 전체에서 공유되는 표준 페이지 로드 지표만 있습니다. 여기서 보이는 헥사 바이트는 같은 입력에 대해 Node 스크립트나 Lambda 함수가 생성하는 것과 동일합니다.
Hex ↔ ASCII 변환은 바이너리 프로토콜이나 임베디드 펌웨어를 다루는 사람이 매일 여러 번 하는 작은 작업입니다. Node와 V8이 이미 제공하는 네이티브 인코더를 그대로 사용하는 브라우저 탭에서 처리하므로 빠르고 바이트 스트림은 기기 밖으로 나가지 않습니다.