import random # 랜덤 데이터 생성에 필요하다.
from crc import Calculator, Crc32 # CRC 계산에 필요하다.
import subprocess # 외부 프로그램(reveng.exe)을 실행하기 위해 필요하다.
데이터 준비
messages = []
calculator = Calculator(Crc32.AUTOSAR)
n_message = 24
# print header
for i in range(12):
print(f'{i:2}', end=' ')
print('|', end=' ')
for i in range(12, 16):
print(f'{i:2}', end=' ')
print()
print('-' * 49)
# 실험용 메시지들을 생성한다.
for i in range(n_message):
# random data
data = bytearray(random.randbytes(11))
# alive counter
data.append(i % 256)
# crc
crc_autosar = calculator.checksum(data).to_bytes(4, 'little', signed=False)
for byte in crc_autosar:
data.append(byte)
# 메시지를 출력한다. CRC 부분과 나머지 부분을 구분하기 위해 '|'를 출력한다.
for byte in data[:12]:
print(f'{byte:02x}', end=' ')
print('|', end=' ')
for byte in data[12:]:
print(f'{byte:02x}', end=' ')
print()
messages.append(data)
print()
0 1 2 3 4 5 6 7 8 9 10 11 | 12 13 14 15
-------------------------------------------------
87 99 f2 63 f5 46 7f ae d4 d6 a7 00 | 54 a3 81 c1
0b e4 db f2 ee c9 3f 05 66 17 08 01 | c3 12 d5 19
88 58 71 a2 9f f4 c6 62 d4 ac f2 02 | 32 4d f6 62
b1 16 97 51 ed ee ca f8 74 89 60 03 | 65 69 ff 23
2e 1b 9a 68 c6 82 46 e2 48 08 e6 04 | a4 df ba 1b
93 26 31 6f 0c 55 cf 34 8f 73 95 05 | 88 82 7d 07
0b 59 23 10 43 51 72 cf aa 7c b4 06 | ca 75 1e c7
88 f3 5b cc 84 15 66 e8 62 81 75 07 | 0b 65 df 3d
77 3a 17 78 98 69 c9 44 96 83 98 08 | aa 5f f2 29
d9 91 9a 02 a5 ea 68 63 5b ee 21 09 | 00 65 a2 25
32 3b a9 88 8b 98 8d af eb c9 d9 0a | 88 04 ef 90
28 b6 a1 88 6f 02 3f 0a 36 fa 27 0b | 5e 71 8b 23
62 d3 72 ed 0d 11 b6 c3 75 c2 fb 0c | 49 6d ca a7
6f ce 4a 7b 1f 44 76 b2 05 67 49 0d | e2 38 de 0f
c2 88 d6 c7 e0 69 f9 96 26 f7 9c 0e | df 5e 0d 55
23 fd ff ff ba 18 42 01 4c 87 b7 0f | ea da 3a c4
d8 00 6e 8c 99 dc 6e 4e 3a 67 b8 10 | f8 64 c1 19
9b c8 be 7e 25 65 0f 4a c9 f6 f1 11 | 14 ee 39 91
26 1c d4 60 91 3f 5f 0a 87 59 d8 12 | 0e 1c b0 77
b6 36 f7 76 f2 9e 87 5f ae 63 37 13 | 29 6f b2 13
01 1a fa 5f 8f c0 15 35 2f a7 79 14 | 8f a7 29 c5
ae 95 5e b8 4c 09 e8 92 58 f6 9e 15 | 18 d9 78 b8
fa 60 f8 9b 5e 50 81 71 dc f2 8d 16 | 2f 9d dc 5b
e0 10 cb 9c 07 a8 23 20 23 c0 45 17 | 96 55 dd fb
CRC 알고리즘 리버스 엔지니어링
# CRC 알고리즘을 찾는데 사용할 샘플 데이터를 고른다.
n_sample = 4
samples = []
for i_sample in range(n_sample):
samples.append(messages[i_sample].hex())
# reveng.exe를 실행하기 위한 명령어를 준비한다.
command_line = ['reveng', '-w32', '-s', ] + samples
command_line
# print header
for i in range(12):
print(f'{i:2}', end=' ')
print('|', end=' ')
for i in range(12, 16):
print(f'{i:2}', end=' ')
print('|', end=' ')
for i in range(12, 16):
print(f'{i:2}', end=' ')
print()
print('-' * 63)
for data in messages:
# alive counter를 포함한 CRC 계산의 입력 부분이다.
data_str = data[:12].hex()
# reveng.exe를 실행하여 CRC를 계산한다.
# -m 옵션으로 정확하게 계산한다.
command_line = ['reveng', '-w32', '-c', '-m', model_name, data_str]
# command_line = ['reveng', '-w32', '-c', '-p', poly, '-i', init, message_str]
# 이 경우 -p, -i, 옵션으로 CRC 알고리즘을 정확하게 계산하지 못한다.
# 조사하지 않아서 이유는 모르겠다.
# 다른 경우에서는 -p, -i 옵션만으로도 계산 결과가 잘 맞았다.
# 상황에 따라 필요한대로 옵션을 사용하면 된다고 생각한다.
# reveng.exe를 실행하여 CRC를 계산한다.
with subprocess.Popen(command_line, stdout=subprocess.PIPE).stdout as reveng_proc:
model_crc = reveng_proc.read().strip()
# 결과를 출력한다.
for byte in data[:12]:
print(f'{byte:02x}', end=' ')
print('|', end=' ')
for byte in data[12:]:
print(f'{byte:02x}', end=' ')
print('|', end=' ')
_ = model_crc.decode('utf-8')
for byte in [_[i:i+2] for i in range(0, len(_), 2)]:
print(f'{byte}', end=' ')
crc_received = data[12:].hex()
crc_calculated = model_crc.decode('utf-8')
if crc_received == crc_calculated:
print(' 🟩')
else:
print(' 🟥')
0 1 2 3 4 5 6 7 8 9 10 11 | 12 13 14 15 | 12 13 14 15
---------------------------------------------------------------
87 99 f2 63 f5 46 7f ae d4 d6 a7 00 | 54 a3 81 c1 | 54 a3 81 c1 🟩
0b e4 db f2 ee c9 3f 05 66 17 08 01 | c3 12 d5 19 | c3 12 d5 19 🟩
88 58 71 a2 9f f4 c6 62 d4 ac f2 02 | 32 4d f6 62 | 32 4d f6 62 🟩
b1 16 97 51 ed ee ca f8 74 89 60 03 | 65 69 ff 23 | 65 69 ff 23 🟩
2e 1b 9a 68 c6 82 46 e2 48 08 e6 04 | a4 df ba 1b | a4 df ba 1b 🟩
93 26 31 6f 0c 55 cf 34 8f 73 95 05 | 88 82 7d 07 | 88 82 7d 07 🟩
0b 59 23 10 43 51 72 cf aa 7c b4 06 | ca 75 1e c7 | ca 75 1e c7 🟩
88 f3 5b cc 84 15 66 e8 62 81 75 07 | 0b 65 df 3d | 0b 65 df 3d 🟩
77 3a 17 78 98 69 c9 44 96 83 98 08 | aa 5f f2 29 | aa 5f f2 29 🟩
d9 91 9a 02 a5 ea 68 63 5b ee 21 09 | 00 65 a2 25 | 00 65 a2 25 🟩
32 3b a9 88 8b 98 8d af eb c9 d9 0a | 88 04 ef 90 | 88 04 ef 90 🟩
28 b6 a1 88 6f 02 3f 0a 36 fa 27 0b | 5e 71 8b 23 | 5e 71 8b 23 🟩
62 d3 72 ed 0d 11 b6 c3 75 c2 fb 0c | 49 6d ca a7 | 49 6d ca a7 🟩
6f ce 4a 7b 1f 44 76 b2 05 67 49 0d | e2 38 de 0f | e2 38 de 0f 🟩
c2 88 d6 c7 e0 69 f9 96 26 f7 9c 0e | df 5e 0d 55 | df 5e 0d 55 🟩
23 fd ff ff ba 18 42 01 4c 87 b7 0f | ea da 3a c4 | ea da 3a c4 🟩
d8 00 6e 8c 99 dc 6e 4e 3a 67 b8 10 | f8 64 c1 19 | f8 64 c1 19 🟩
9b c8 be 7e 25 65 0f 4a c9 f6 f1 11 | 14 ee 39 91 | 14 ee 39 91 🟩
26 1c d4 60 91 3f 5f 0a 87 59 d8 12 | 0e 1c b0 77 | 0e 1c b0 77 🟩
b6 36 f7 76 f2 9e 87 5f ae 63 37 13 | 29 6f b2 13 | 29 6f b2 13 🟩
01 1a fa 5f 8f c0 15 35 2f a7 79 14 | 8f a7 29 c5 | 8f a7 29 c5 🟩
ae 95 5e b8 4c 09 e8 92 58 f6 9e 15 | 18 d9 78 b8 | 18 d9 78 b8 🟩
fa 60 f8 9b 5e 50 81 71 dc f2 8d 16 | 2f 9d dc 5b | 2f 9d dc 5b 🟩
e0 10 cb 9c 07 a8 23 20 23 c0 45 17 | 96 55 dd fb | 96 55 dd fb 🟩
결론
리버스 엔지니어링으로 CRC 알고리즘을 찾는 것은 어렵지 않다.
CRC는 데이터에 결함에 결함 유무를 확인하는 용도에는 적합하지만 보안 강화를 위한 용도에는 적합하지 않다.