Skip to content
isdnetworks
Go back

남의 장비를 역으로 읽기

현장에 설치된 장비를 개선해야 했다. 소스가 없고 만든 곳과 연락이 안 되며 장비는 돌고 있다. 그것이 유일한 자료다.

Table of contents

Open Table of contents

밖에서부터 봤다

안을 열기 전에 밖에서 관측할 수 있는 것을 다 봤다.

통신   무엇을 주고받는지 캡처한다
전원   소비 전력이 동작에 따라 달라져 언제 뭘 하는지 힌트가 된다
표시   LED 와 화면이 상태를 알려준다
시간   몇 초마다 무엇을 하는지 주기를 잰다

밖에서 알 수 있는 것이 생각보다 많았고 이것만으로 대략 어떤 상태들이 있고 어떤 순서로 도는지가 잡혔다. 그리고 이것은 장비를 안 건드린다.

펌웨어를 꺼냈다

밖에서 안 되는 부분이 남아서 펌웨어를 봤다. 읽어내는 방법이 몇 가지 있었는데 JTAG 같은 디버그 포트와 메모리 칩 직접 읽기다.

읽는 것만으로도 장비가 망가질 수 있어서 여분 장비로 먼저 했다. 현장 장비는 안 건드렸다.

문자열부터 봤다

펌웨어 이미지를 얻고 나서 hexdump 로 한 번 훑고 가장 먼저 한 것이 문자열 추출이었다.

$ strings firmware.bin | less

여기서 많이 나왔다.

오류 메시지 → 어떤 상황을 다루는지
명령 이름   → 어떤 기능이 있는지
버전 문자열 → 언제 빌드됐는지
경로       → 개발 환경의 흔적

분해하기 전에 strings 출력만으로 구조가 상당히 잡혔다.

다만 strings 는 네 글자 이상 이어지는 ASCII 구간만 내보내는 것이 기본이다. 두세 글자짜리 명령 이름이나 상태 코드는 그대로 두면 안 보이므로 -n 으로 기준을 낮춰 한 번 더 돌려야 했다.

알려진 패턴과 실험

이미지 안에서 알아볼 수 있는 조각을 찾았다. libc 함수의 특징적인 코드와 CRC-16 표 같은 상수 배열과 프로토콜 상수가 그것이다.

아는 것이 하나 보이면 그 주변이 풀린다. 체크섬 상수를 찾으니 그것을 쓰는 함수가 보이고 그 함수를 부르는 곳이 통신 처리부였다. objdump 로 훑으면서 memcpystrcmp 같은 호출을 찾는 것도 실마리가 됐다.

추측한 것을 확인하려면 실험이 필요했다. hexdump 로 바꿀 자리를 짚고 여분 장비에서 값을 넣어 동작을 봤다.

이 바이트가 주기 설정 같다 → 바꿔 보니 주기가 변함 ✓
이 값이 임계값 같다       → 바꿔도 변화 없음 ✗

틀린 추측이 절반이었다. 그래도 실험이 빠르니 여러 번 돌렸고 틀린 추측으로 현장 장비를 건드렸으면 그것이 멈췄을 것이다.

검증 — 세 부류로 나눈 문서

알아낸 주소와 뜻을 그때그때 적었다.

[확인됨]
  0x0400  주기 설정 (단위: 100ms)
  0x0404  재시도 횟수

[추측]
  0x0408  임계값? (바꿔도 관측 변화 없음 — 다른 조건 필요할 수도)

[모름]
  0x0410~0x04FF  용도 불명

0x0400 처럼 주소를 적고 세 부류로 나눈 것이 유용했다. 나중에 다시 볼 때 어디부터 파야 하는지 바로 알고 이 구분이 없으면 나중에 추측을 사실로 읽는다.

이 작업은 재미있어서 계속 파고 싶어지고 안 풀린 부분이 신경 쓰인다. 그런데 원래 목적은 특정 기능 하나를 개선하는 것이었다.

그 기능에 필요한 만큼만 알아내고 멈췄고 나머지는 문서에 모름으로 남겼다. 전부 이해하려 하면 끝이 없으니 필요한 만큼이 어디까지인지 정하고 시작하는 것이 나았다.

정리


Share this post on:

Previous Post
설정돼 있길래 되는 줄 알았다
Next Post
눌러도 아무 일이 없는 버튼이 있었다