STM32 보드를 개발자의 관점으로 공부해보기위해 오늘 처음으로 온보드 LED 를 점등해 보았다. 취미로써 여러가지 가능성에 대한 빌견과 재미를 위해 공부중이다. 여러 보드 중 STM32 는 실제로 쓰이는 드론부터 의료기기의 블루투스 혈압계(직접 뜯어봄;) 등 임베디드분야의 가장 많이쓰이는 Microprocessor 일것이다. 어떤 특별한 인사이트나 내부원리를 깨달을때가 있다면 여기에 작업일지처럼 정리해볼 봐야겠다. 위의 실습보드는 STM32F4704VE ( F4 시리즈 ) 로 직접제작하신 보드인데 여러 기초적인 모듈과 커넥터가 같이 포함되어있어 초보자에게 유용할것같다. 혼자 CubeIDE 코딩중인데 보드가 너무이쁘고 감성적이어서 저녁에 즐겁게 코딩하는중.
랩 구성과 하드웨어 설정 : Intel NUC (CSR4.0 dongle) <-> acer notebook
구성목표는 두 기기에서 간단한 동글을 이용한 블루투스 통신이 파이썬으로 가능한지 눈으로 확인하고, 리눅스툴의 사용에 익숙해지고, 자료가 부족하기때문에 시행착오 성공예 등을 기록해두는것이다. 추후에는 덧붙여 scapy 나 wireshark 등의 패킷분석 및 역공학 연구를 위한 환경을 만드는것을 목표로한다. IoT 기기에는 streaming-based 인 RFCOMM 이 아니라 packet-based 인 L2CAP 가 주로 사용될 것이기때문에 이를 지원하는 리눅스 기반에서 테스트하였다.
미니pc에 다이소 CSR4.0 블루투스 동글을 꽃고 노트북의 내장 블루투스 5.1 로 구성하였다.
각각에 pybluez 와 dependencies 를 설치한다.
기본설치후 example 이 제대로 동작하지않아 웹서치를 한 결과,
각 우분투의 ubuntu 의 bluetoothd 를 --compat (-C) 으로 실행하고 권한설정을 같이 해야 잘 동작하며,
device 를 클라이언트만으로 사용하는게 아닌, 기기 탐색과 접속을 가능하게하려면
Page(connect), Inquery(discovery) SCAN 기능을 hciconfig 에서 활성화 해야한다.
아래 명령을 통해 블루투스 장치명과 MAC 주소를 확인합니다. $ hcitool dev Devices: hci0 00:1A:7D:DA:71:13
아래 명령을 통해 블루투스 장치인 hci0의 스캔을 허용할 수 있습니다. # Enable Page and Inquiry scan # 이후 hciconfig 시 UP RUNNING 옆에 PSCAN ISCAN 표시가 생깁니다. $ sudo hciconfig hci0 piscan
bluetoothctl 명령어를 통해 블루투스 장치를 제어할 수 있습니다. $ bluetoothctl [NEW] Controller 18:1D:EA:36:DA:89 hhk7734 [default] Agent registered [bluetooth]# help
이후 다음과같이 iPhone 에서 미니pc 의 블루투스 컨트롤러가 탐색되어 나타난 것을 확인 할 수 있었다.
NUC 의 CSR4.0 이 탐색된 모습
코드 실습
두기기간의 통신을 확인하기 위해 코드를 실행해보았다. python 없이 간단히 하길원하면 l2ping 을 사용해보자.
pybluez 홈페이지의 L2CAP 예제를 조금 수정하였다.
기능은 간단하게 서버는 접속을 기다리며 클라이언트는 접속후 데이터를 보내면 서버가 echo 를 하는 방식이다.
아래는 서버쪽(NUC)의 코드이고 hciconfig 에서 PSCAN ISCAN 을 확인후 실행하면 반응없이 접속을 기다리는 상태가된다.
$ python l2cap-server.py
import bluetooth
server_sock = bluetooth.BluetoothSocket(bluetooth.L2CAP)
port = 0x1001
server_sock.bind(("", port))
server_sock.listen(1)
#uuid = "94f39d29-7d6d-437d-973b-fba39e49d4ef"
#bluetooth.advertise_service(server_sock, "SampleServerL2CAP",
# service_id=uuid, service_classes = [uuid])
client_sock, address = server_sock.accept()
print("Accepted connection from", address)
data = client_sock.recv(1024).decode('utf-8')
print("Data received: ", data)
while data:
client_sock.send("Echo To " + data)
data = client_sock.recv(1024).decode('utf-8')
print("Data received: ", data)
client_sock.close()
server_sock.close()
아래는 클라이언트(노트북) 쪽의 코드이고 hcitool scan 을 통해 미니pc의 블루트스가 탐색됨을 한번 더 확인 한 후,
확인한 주소로 코드를 실행하였다.
$ python3 l2cap-client.py 00:1A:7D:DA:71:03
import sys
import bluetooth
sock = bluetooth.BluetoothSocket(bluetooth.L2CAP)
if len(sys.argv) < 2:
print("Usage: l2capclient.py <addr>")
sys.exit(2)
bt_addr = sys.argv[1]
port = 0x1001
print("Trying to connect to {} on PSM 0x{:02x}...".format(bt_addr, port))
sock.connect((bt_addr, port))
print("Connected. Type something...")
while True:
data = input()
if not data:
break
sock.send(data)
data = sock.recv(1024).decode('utf-8')
print("Data received:", data)
sock.close()
접속이 되면 입력이 가능한 상태가 되고, Hello IoT World! 를 입력해보았다.
서버인 미니pc에서 내가 입력한 문자가 출력되고 노트북에서 Echo 응답을 확인 할 수 있었다!
왼쪽(NUC), 오른쪽(NOTEBOOK) 에서 pybluez 로 블루트스 통신을 성공한 모습
TROUBLE SHOOTING
< BLE 설치시 /usr/bin/ld: cannot find -lboost_python-py34 > # gattlib 가 python 3.4 버전의 dynamic library 를 찾으면서 오류. 링크를 만든다.
cd /usr/lib/x86_64-linux-gnu/ ls -al libboost_* sudo ln -s libboost_python38.so libboost_python-py34.so
< bluetooth.btcommon.BluetoothError: no advertisable device> 위 블루투스 컨트롤러 확인. hciconfig 후 PSCAN ISCAN 가 있는지 확인한다. $ sudo hciconfig hci0 piscan
< bluetooth.btcommon.BluetoothError: [Errno 2] No such file or directory > 위 bluetooth.service 변경 부분 확인. 블루투스 데몬을 compatibility mode 로 실행해야한다.
< bluetooth.btcommon.BluetoothError: [Errno 13] Permission denied > 위 SDP 참조. bluetoothd 를 --compat (-C) 로 실행할때 생성되는 파일인 /var/run/sdp 의 퍼미션을 조정해야한다.
1. Searching, browsing SDP services by nearby devices
( 휴대폰이나 헤드셋 등이 어떤 서비스를 제공하는지?
classic 은 SDP server 의 service record 에 목록을 저장하고 BLE 에서는 GATT Server.)
2. Local Machine 의 SDP service 기본 설정
1.
# sdptool browse [BD_ADDR/local/None]
# sdptool search [preset string/UUID]
# sdptool search SP (Serial Port)
# sdptool search OPUSH (OBEX Object Push)
# sdptool search 0x1101
Preset string 목록은 sdptool -h.
2.
# sdptool add <predefined name>
# sdptool del <handle>
주변의 iPhone 6s 에 대한 sdp service
hcidump
sudo apt-get install -y bluez-hcidump
low-level debugging 을 위해 모든 블루투스 패킷을 보여줄 수 있다.
어떻게 connection 이 일어나고 또는 어느단계에서 실패하는지 탐구하는데 중요한 툴이다.
root 권한 필요.
# hcidump <no argument> ( local 컴퓨터와 adapter 사이의 패킷 )
# hcidump -X
예제) 내 컴퓨터가 adapter 에게 주변의 접속가능한 장치가 있는지 스캔하는 명령을 내리는 low-level 패킷을 출력해보자. local-term1 $ hcidump local-term2 $ hcitool scan
두 터미널을 열고 각각 입력하면 1번 터미널에서
HCI sniffer - Bluetooth packet analyzer ver 5.53 device: hci0 snap_len: 1500 filter: 0xffffffffffffffff > HCI Event: Command Status (0x0f) plen 4 Inquiry (0x01|0x0001) status 0x00 ncmd 2 > HCI Event: Extended Inquiry Result (0x2f) plen 255 bdaddr 00:1A:7D:DA:71:03 mode 1 clkoffset 0x3b01 class 0x0c0104 rssi -70 Complete local name: 'link9-desktop' TX power level: 20 Unknown type 0x10 with 8 bytes data Complete service classes: 0x1800 0x1801 0x110e 0x110c 0x110b 0x110a 0x1112 0x1108 > HCI Event: Inquiry Complete (0x01) plen 1 status 0x00 > HCI Event: Command Status (0x0f) plen 4 Remote Name Request (0x01|0x0019) status 0x00 ncmd 1 > HCI Event: Remote Name Req Complete (0x07) plen 255 status 0x00 bdaddr 00:1A:7D:DA:71:03 name 'link9-desktop'
진한 부분까지 출력된 상태로 대기하다가, 2번 터미널에서
Scanning ... 00:1A:7D:DA:71:03 link9-desktop
device 이름출력과 함께 종료되며, 1번 터미널의 연한부분의 나머지 부분이 출력되었다.
일반적으로 controller 는 커맨드를 받으면 Command Status 를 바로 보내는데, task 를 시작했음을 알려서 비 동기적으로 host 가 다른일을 할 수 있도록 하는 메커니즘이다. hcitool scan 은 2번의 커맨드를 어댑터에 내리는것으로 보이며 두번의 Command Status 와 중간에 Result, 마지막에 complete 이벤트를 받는다.
hcitool scan 은 2번째 커맨드의 응답으로 Remote Name Req Complete 이벤트를 받아 포함된 bdaddr 과 name 들을 모두 출력하고 종료하는것으로 보인다.
원하는 프로토콜만 필터링을 할 수 있다. man hcidump 를 참고하자.
l2ping
each packet ( L2CAP packet ) 을 주고받음. L2CAP 통신을 테스트하기에 유용하다.
# extract the firmware to images from the compressed file $ python3 ./sources/extractor/extractor.py -b Netgear -sql 127.0.0.1 -np -nk "D6000_V1.0.0.41_1.0.1_FW.zip"
optional arguments: -h, --help show this help message and exit -sql SQL Hostname of SQL server -nf Disable extraction of root filesystem (may decrease extraction time) -nk Disable extraction of kernel (may decrease extraction time) -np Disable parallel operation (may increase extraction time) -b BRAND Brand of the firmware image
# identify the firmware's architecture and store in the FIRMADYNE DB
$ ./scripts/getArch.sh ./images/1.tar.gz
# store information in the DB from the extracted image and generate a QEMU image
$ ./scripts/tar2db.py -i 1 -f ./images/1.tar.gz
$ sudo ./scripts/makeImage.sh 1
# network
$ ./scripts/inferNetwork.sh 1
# begin the emulation
$ ./scratch/1/run.sh
Backdooring Firmware
OpenWrt toolchain ( firmware complier for SoC routers based on MIPS processors )
sudo apt install binutils bzip2 diff find flex gawk gcc-6+ getopt grep install libc-dev libz-dev make4.1+ perl python3.6+ rsync subversion unzip which git clone https://github.com/openwrt/openwrt cd openwrt ./scripts/feeds update -a ./scripts/feeds install -a menuconfig make toolchain/install
# to capture vcan0 packets # after install, select <Yes> for non-superusers ( or sudo dpkg-reconfigure wireshark-common ) sudo usermod -a userid -G wireshark
wget https://github.com/greatscottgadgets/libbtbb/archive/2020-12-R1.tar.gz -O libbtbb-2020-12-R1.tar.gz tar -xf libbtbb-2020-12-R1.tar.gz cd libbtbb-2020-12-R1 mkdir build cd build cmake .. make sudo make install sudo ldconfig
wget https://github.com/greatscottgadgets/ubertooth/releases/download/2020-12-R1/ubertooth-2020-12-R1.tar.xz tar -xf ubertooth-2020-12-R1.tar.xz cd ubertooth-2020-12-R1/host mkdir build cd build cmake .. make sudo make install sudo ldconfig
TROUBLE SHOOTING WIreshark 설정을 했음에도 LE LL 프로토콜, ADV 패킷만 보이고 ATT 패킷이없다.
1. 최신업데이트 bluetooth packet 을 decode 하기위해서는 libbtbb 이 필요하다. 나의 경우에는 Firmware 2020 + apt install ubertooth (2018버전) 에서 문제 생겨 최신버전과 libbtbb 를 모두 같이 빌드설치후 해결되었다.
2. -A 37,38,39 채널변경 3. 안테나 문제
Android Phone Developer Modes + Wireshark
따로 스니퍼 하드웨어를 가지고있지 않아도 안드로이드 폰의 개발자기능을 패킷스니퍼로 사용할 수 있다.
안드로이드폰의 개발자 모드를 활성화후 Bluetooth HCI snoop log 를 활성화 하면
모든 블루투스 패킷이 캡쳐되며 개발자 모드의 세팅된 버퍼의 크기내에서 log 기록이 남겨지고
USB debugging 을 활성화하여 log 를 pc로 추출하여 Wireshark 로 읽어들일 수 있다.
$ adb pull <path> 로 가져오면된다. ($ adb pull /data/misc/bluetooth/logs/btsnoop_hci.log)
루팅하지않은경우의 방법
나는 redmi 10 note 를 사용하였는데 bt_stack.conf 에 경로설정은 없었고 루팅 후 /data/misc/bluetooth/logs/btsnoop_hci.log 파일을 얻을 수 있었으나, 루팅하지않아 접근 불가능한경우 직접 파일을 노출하는것이아니라 버그리포트를 다운로드하여 로그를 제공한다.
# re-install scapy in https://github.com/secdev/scapy/ git clone https://github.com/secdev/scapy.git cd scapy sudo python setup.py install
cd docs make html cd ..
# sudo blesuite scan
설치되었으나 정상적으로 동작하지않음.
다른 동글로 다시 시도해 볼예정.
ImportError: No module named Crypto.Cipher pycrypto 의 문제인데 requirements 를 설치할때 sudo 를 붙여주거나 easy_install 로 해결.
Car Hacking : CAN
CAN via OBD-II Hardware : USB2CAN + Macchina M2 / or CL1000 Communication for CAN packets : SocketCAN, can-utils Virtual CAN interface : vcan OBD-II Simulator : ICSim Wireshark
Replay Attack > candump+canplayer or SavvyCAN
ICSim
Instrument Cluster Simulator
# https://github.com/zombieCraig/ICSim sudo apt install libsdl2-dev libsdl2-image-dev sudo apt install can-utils git clone https://github.com/zombieCraig/ICSim cd ICSim make ./setup_vcan.sh ifconfig vcan0
# Running the dashboard
./icsim vcan0
./controls vcan0
vcan
Setting virtual CAN interface / setup_vacn.sh
# load kernel module sudo modprobe can sudo modprobe vcan lsmod | grep can
# set up virtual interface sudo ip link add dev vcan0 type vcan sudo ip link set up vcan0
# verify ifconfig vcan0
can-utils
# cansniffer cansend candump canplayer cangen
# cangen
$ cangen vcan0
$ wireshark & # select vcan0
# candump
$ candump -a vcan0 # live dump with ascii
$ candump -l vcan0 # log candump-<date>.log to replay attack
candump with ascii -a
# cansniffer - all ID monitor to see change in bytes in CAN
cansniffer -c vcan0
filtering arbitration ID -000000 +000000 +ID
b # binary mode
# canplayer
$ canplayer -I canfile.log # replay attack
# cansend
$ cansend interface frame
# dividing and narrowing packets to find Aribitration ID
$ wc -l candump.log
split -l <count> candump.log frame_
SavvyCAN
Without qtserialbus ( and ICSim ), Just Real car, you can download easy use prebuild version.
It works with Linux distributions like Ubuntu and Debian with no additional driver installation. If the driver is correctly loaded, CAN interface should be seen when issuing the command sudo ip link.
Set can0 interface speed to 125 Kbps: sudo ip link set can0 up type can bitrate 125000 sample-point 0.875
Set to can0 to “steady” state (INFO led): sudo ip link set can0 up
To bring down interface (STAT led): sudo ip link set can0 down
To get more information about configuration options type: sudo ip link set can0 type can help
LOGIN 인증 프로그래밍 : STM32CUBEIDE ( Arduino 로 하는 방법도 가능 )
과정
개발의 과정) STM32CubeIDE 로 Login 구현하기
해킹의 과정) OpenOCD 설치, 펌웨어 다운로드, gdb 로 로그인 우회
먼저 UART 입출력을 위한 FT232RL과 디버깅지원을 위한 ST사의 ST-LINK 를 연결하였다.
SWD의 핀은 (3.3V GND IO CLK) 4가지를 각각 같은곳으로 연결하면 되므로 어렵지않다.
STM32F103C8T8 - ST-LINK V2 / FT232RL 을 PC 에 연결한 모습
다음 STM32CubeIDE 를 설치하고 그림과 같이 핀을 세팅한다. 코딩을 하는 부분 외에 칩셋을 세팅하는 화면을 Device Control Tool 이라고 하는데, 나는 아래 목록을 세팅하였다. 이부분은 개발과정에 해당되므로 자세한 사항은 유투브나 다른블로그를 참조하면 좋을것이다.
Pinout View 에서 PB12 -> GPIO_OUTPUT ( LED 점등을 위한 핀 )
RCC 에서 HSE -> Crystal/Ceramic ... ( 클럭을 위한것, 옵션 )
SYS 에서 Debug -> Serial Wire ( 디버깅 지원을 위해 필수 )
USART1 에서 Mode -> Asynchronous ( UART 를 위한 필수, Flow Control 은 하지않음 )
저장하면 MX_GPIO_Init(); MX_USART1_UART_Init(); 와 같은 초기화 코드들이 자동으로 추가되고 프로그래밍을 하기위한 준비가 될것이다. main.c 내부에 while 구문을 다음과 같이 프로그래밍 하였다.
UART 통신을 위한 함수는 HAL_UART_Transmit / HAL_UART_Receive 이고
LED 점등을 위한 함수는 HAL_GPIO_TogglePin 이다.
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
uint8_t rc = 0;
static uint8_t i = 0;
// 처음 실행할 경우 Login 메세지 출력.
if (login_msg == 1) {
HAL_UART_Transmit(&huart1, (uint8_t*)"\rLogin : ", 9, 1000);
login_msg = 0;
}
// UART 포트로 한문자씩 RX 전송받아 TX 로 출력하며 LED 를 깜빡인다.
if(HAL_UART_Receive(&huart1, (uint8_t *)&rc, 1, 1000)==HAL_OK) {
HAL_UART_Transmit(&huart1, (uint8_t *)&rc, 1, 1000);
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
HAL_Delay(100);
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
}
// 전송한 문자열에 리턴값을 포함할때까지 버퍼에 문자열을 저장한다.
// 리턴값이 들어오면 널문자를 추가하고 문자열을 패스워드와 비교한다.
if (rc != 0) {
if(rc != '\r' && rc != '\n') {
buf_passwd[i++] = rc;
if(i >= 32) i = 32 - 1;
}
else {
HAL_UART_Transmit(&huart1, (uint8_t *)"\n", 1, 1000);
buf_passwd[i] = '\0';
if (strcmp((const char *)buf_passwd, "hardwarehacker") == 0) {
HAL_UART_Transmit(&huart1, (uint8_t *)"Access Granted!\n", 16, 1000);
break;
} else {
HAL_UART_Transmit(&huart1, (uint8_t *)"Access Denied.\n", 15, 1000);
}
i = 0;
login_msg = 1;
}
}
/* USER CODE END 3 */
}
이 코드가 하는일은 간단하다. login_msg 가 1일때 "Login : " 을 띄운후,
rc 에 한 문자열씩 입력될 때마다 LED 를 깜빡이고, 그 문자열이 \n 또는 \r 이 아닐때 버퍼에 저장한다.
엔터를 입력하면 그 값을 strcmp 로 패스워드와 비교하여 일치하는지에따라 결과를 출력하는 것이다 :)
인증프로그램을 올린후 실행한 화면
컴파일하여 올린후 Workspace 에 가보면 다음과같은 bin, elf 바이너리가 생성되어있다.
Workspace 디렉토리
OpenOCD 를 설치하고 ( 이부분은 생략하였으나 다른 자료를 참고 ) OpenOCD 서버를 실행하면 telnet 과 gdb 를 사용할 수 있는 상태가 된다. 먼저 telnet 을 실행하여 보드의 초기화와 halt 하고, 펌웨어를 덤프 할 수 있다.
디버깅중 실수하여 원하는 breakpoint 지점으로 다시 새롭게 시작하려면 다시 reset init - halt 이후 다시 continue 하면 될 것이다.
지금은 예제이므로 실행파일을 SYMBOL 을 가져다 쓰기위해 .ELF 파일을 GDB 에 로드할 것이지만 실제로는 여러 함수의 심볼을 보기는 어려울 것이다.
보드 HALT 명령어와 펌웨어 덤프
gdb 서버를 통해 halt 되어있는 보드에 디버거를 연결한다.
workspace dir $ gdb-multiarch -q --eval-command="target remote localhost 3333: simple-login.elf
main() 에 breakpoint 를 걸고 10개의 명령어씩을 확인하도록 display 설정을 해주었다.
이후 함수들의 심볼을 확인해보았다. 대부분의 HAL 관련함수, strcmp, standard C 함수들도 보인다.
main() 과 HAL 함수들strcmp() 가 호출됨을 확인
문자열을 비교하는것이므로 strcmp 를 타겟으로 하면 좋을것이다. continue 한후 UART 가 연결된 터미널에 test 를 입력한 후 continue 해보았더니 strcmp 에 breakpoint 가 걸렸고, 함수 인자를 확인해 보기위해 r0, r1 을 확인해보았다. (arm 프로세서는 인자들을 보통 r1-r4 레지스터에 저장한다. )
간단한 리버싱 실습과정
의외로 쉽게 패스워드를 확인 할 수 있었고, finish 를 통해 빠져나와보면 r0 와 0 을 비교하여 점프하는 구문이 있는데, reversing 에 조금만 익숙하다면 MOV, CMP, BNE 이 세가지 조합은 위에서 코딩한 if (strcmp(arg1, arg2) ... 와 비슷한 점프 구문임을 예상할 수 있을 것이다.
임의로 입력한 패스워드로 우회한 모습
strcmp 는 두 문자열이 같을때 0을 리턴하므로 r0 레지스터에 0을 넣고 continue 하면 성공! 틀린패스워드이지만 통과되었다.
직접 만들어보니 많은 공부가 된 것 같다. 개인적인 기록이고 문자로 모든부분을 남겨둘 수 없어 OpenOCD 설치나 보드의 여러 환경 세팅과정의 많은 부분을 생략하였다. 직접 똑같이 따라하기 어려울 수 있으나, 디테일한 내용은 쉽게 검색할 수 있으니 참고하면 될 것이다. 세팅과정은 다음에 따로 정리 하려고 한다.
UART (Universal Asynchronous Receiver Transmitter) 는 가장 심플한 시리얼 프로토콜이고 IoT device 에 접근을 얻는데 가장 기초적인 방법이다. 벤더사들은 이를 디버깅목적으로 제공하고 가장 기본이 되는 인터페이스 이다.
UART 만으로 완벽한 접근과 디버깅을 할 수는 없겠지만 다음에 살펴볼 SWD, JTAG 등의 인터페이스로 동적디버깅이 가능한 경우에도 입출력의 기본이 되므로 먼저 살펴보아야 할 것이다.
집에서 사용하지 않는 국내 유명 라우터를 먼저 열어보았다.
칩에 보이는 문자열은 작지만 RTL8812BRH .. , 그리고 오른쪽 8핀의 칩에 WINBOND 25Q64JVSIQ 로 보이는 문자열이있다.
아무것도 모른채 검색해보니 무선통신칩과, 플래시메모리(주로 8, 16핀)이며 Datasheet도 구할 수 있다!
플레시모리칩은 사진을 자세히 보면 한쪽 구석에 1번핀을 표시하기위해 작은 점이 찍혀있으며, 펌웨어나 다른 중요한 정보를 담고있기도하다. 하지만 이번글에서는 바로 왼쪽에 보이는 UART 를 확인하고 이용해 볼 것이다.
놀랍게도 가운데에 뚜렷하게 4개의핀이 바로보여 당혹스러웠는데 아무런 라벨이 없지만 UART핀으로 보인다.
UART 핀을 확인하는 방법은 크게 두가지가있는데,
1. 멀티미터(저항, 전압 등을 계측하는 장치)
2. USB Logic Analyzer (saleae 사의 Logic 프로그램을 이용
UART 의 경우는 간단한 첫번째 방법으로 충분히 알 수 있으므로 멀티미터를 이용 해 볼 것이다 :)
UART 핀 확인 과정은 (공개되지않은 정보) PCB에서 UART 포트위치를 확인하고 4개의 핀 (GND, RX, TX, VCC) 중 어느것인지 알아낸후에, USB-TTL cable 등을 통해 연결하여 PC 에서 시리얼정보를 전송받는 것이다. (GND, RX, TX 세가지면 된다!)
아무정보도 없기때문에 전원을 연결하지않은 상태에서 무작정 멀티미터를 가지고 여기저기 대어보다가, Continuous test 모드로 두고 (물결표시, 사운드 아이콘이 그려져있고 저항이거의 없는 연결일 경우에 삐 소리를 냄) 둔후에 전원근처에 검은선, 빨강선을 각핀에 대어보았다. 가장 왼쪽의 핀에서 소리가 울렸고 GND를 찾아냈다.
다음엔 RX, TX 를 찾기위해 전원을 켠후에 전압측정모드에서 각 핀을 대어보았는데, 두번째 핀에서 3.3V 에서 일정함을 보였고, 세번째 핀에서는 3.3V -> 2.xV -> 3.3V 과같이 3.3V 에서 감소했다가 다시 올라오는 패턴을 보였다. 영상이나 간단한 공부를 했다면 두번째가 RX, 세번째가 TX 임을 알 것이다.
위 부분이 가장 재밌는 부분이고 글보다 아래 유투브 영상을보거나 직접해보면 아주 쉬우니 실습 해보길 바란다 :)
USB TTL 케이블 (FTDI 사의 FT232RL칩) 을 3핀만 다음과같이 연결했다. (RX, TX 를 교차해서 연결해야한다.)
검정색 : UART의 GND <-> FT232RL의 GND
파랑색 : UART의 RX(두번째) <-> FT232RL의 TX
노랑색 : UART의 TX(세번째) <-> FT232RL의 RX
기대를 가지고 리눅스에서 usb 장치가 연결되었는지 확인후에, 방금 꽃은 디바이스를 확인하기위해 새로생긴 dev내의 파일을 역순으로 정렬하였고, /dev/ttyUSB0 임을확인했다. ( sudo dmsg 로 정확히 확인 해 볼 수도 있다. )
가장쉽고 간편한 GTKTerm 을 이용했는데, 여기서 프로토콜에 대해 간단한 설정이 필요하다.
115200-8-N-1 은 115200의 Baud rates 를 사용한다는의미이고 8개의 비트가 데이터로보내지며 그뒤에 parity bit 를 사용하지않고 (N) stop bit 는 1개가 온다는 의미이다.
Baud Rates 가 다를경우 깨지는 문자열 출력
UART 는 비동기 통신이므로 baud rates 가 서로 맞아야하는데 많이 쓰이는 것은 정해져있다.
115200, 9600, 38400 ... 을 시도한후에 다음과같이 성공했다!
디버그 메세지가뜬다. DRAM 크기가 64MB 이고 커널은 리눅스 3.1.90 버전인데 압축을 푼후 DRAM에올려서 부팅하는 과정인 것 같아보인다. 혹시나 하여 CTRL-C 시그널을 보내봤으나, 쉘은 떨어지지않고 Firmware not found 라는 메세지만 나왔다.
펌웨어 버전이 10.090 인것으로 보이며, 중간에 흥미로운 부분이있었는데, magic key 를 누르면 숨겨진 메뉴가 뜬다고 한다. 웹검색결과 xiag 인것같지만 내 라우터는 통하지 않았다.
펌웨어는 제조사에서 다운로드할수있으니 다운로드후 binwalk 로 바이너리 내부를 추출해보았는데,
3번째 구간에 filesystem 이 존재하는것으로 보이고, 이후 software reverse engineering 을 통하여 더 분석하여 magic key 도 알아낼 수 있을 것이다. :)