
# C와 libmodbus로 작성된 멀티스레드 Modbus/TCP 탐지 스캐너.
libmodbus를 사용하여 Modbus/TCP 서비스를 감지하는 멀티스레드 C 스캐너입니다.
이 스캐너는 TCP 포트 502가 열려 있는 것만으로 판단하지 않습니다. 대신 Modbus/TCP 연결을 수립하고 애플리케이션 계층 Modbus 요청을 전송합니다. 유효한 Modbus 응답이 Modbus 서비스 존재 여부를 판단하는 주요 지표로 사용됩니다.
Modbus는 PLC, RTU, HMI, SCADA 시스템, 센서, 계량기 및 기타 산업용 장치에서 일반적으로 사용되는 산업용 통신 프로토콜입니다.
Modbus/TCP는 TCP를 통해 Modbus 애플리케이션 프로토콜을 전송합니다.
표준 Modbus/TCP 포트는 다음과 같습니다:
TCP/502
일반적인 통신 흐름은 다음과 같습니다:
스캐너
|
| TCP 연결 → 502
|
| Modbus/TCP 요청
v
Modbus 장치
|
| Modbus/TCP 응답
v
스캐너
연결 직후 배너를 제공하는 프로토콜과 달리, Modbus/TCP는 일반적으로 장치가 애플리케이션 계층 응답을 생성하기 전에 클라이언트가 유효한 Modbus 요청을 전송해야 합니다.
스캐너는 두 단계로 감지를 수행합니다.
스캐너는 다음 주소로 TCP 연결을 시도합니다:
<대상>:502
연결을 수립할 수 없으면 해당 대상은 Modbus/TCP에 응답하지 않는 것으로 처리됩니다.
그러나 TCP/502 포트가 열려 있는 것 자체만으로는 Modbus의 충분한 증거로 간주되지 않습니다.
연결 후 스캐너는 libmodbus를 사용하여 Modbus 요청을 전송합니다.
기본 프로브는 다음과 같습니다:
modbus_read_input_registers(ctx, 0, 1, ®);
이것은 다음 Modbus 기능 코드를 생성합니다:
0x04 - 입력 레지스터 읽기
요청은 주소 0에서 시작하는 입력 레지스터 하나를 대상에 요청합니다.
대상이 유효한 Modbus 응답을 반환하면 스캐너는 서비스가 감지된 것으로 간주합니다.
Modbus/TCP 패킷은 다음으로 구성됩니다:
+----------------------+----------------------+
| MBAP 헤더 | PDU |
+----------------------+----------------------+
MBAP 헤더:
+------------------+
| 트랜잭션 ID | 2바이트
| 프로토콜 ID | 2바이트
| 길이 | 2바이트
| 유닛 식별자 | 1바이트
+------------------+
PDU:
+------------------+
| 기능 코드 | 1바이트
| 데이터 | N바이트
+------------------+
MBAP 헤더는 Modbus/TCP에 고유합니다.
스캐너의 첫 번째 프로브는 기능 코드 0x04를 사용합니다.
대표적인 요청은 다음과 같습니다:
00 01 00 00 00 06 01 04 00 00 00 01
이를 분해하면:
00 01 트랜잭션 식별자
00 00 프로토콜 식별자
00 06 길이
01 유닛 식별자
04 기능 코드
00 00 시작 주소
00 01 수량
00 01
트랜잭션을 식별합니다.
트랜잭션 식별자는 일반적으로 Modbus 클라이언트 라이브러리에서 관리되므로 값은 달라질 수 있습니다.
00 00
값 0은 Modbus를 식별합니다.
00 06
길이 필드 다음에 오는 바이트 수를 지정합니다.
01
대상 Modbus 유닛을 식별합니다.
04
기능 코드 0x04는 다음을 의미합니다:
입력 레지스터 읽기
00 00
스캐너는 레지스터 주소 0에서 시작합니다.
00 01
스캐너는 레지스터 하나를 요청합니다.
요청에 대한 성공적인 응답에는 기능 코드 0x04와 요청된 레지스터 데이터가 포함됩니다.
대표적인 응답은 다음과 같을 수 있습니다:
00 01 00 00 00 05 01 04 02 00 00
이를 분해하면:
00 01 트랜잭션 식별자
00 00 프로토콜 식별자
00 05 길이
01 유닛 식별자
04 기능 코드
02 바이트 수
00 00 레지스터 값
감지에 중요한 부분은 대상이 Modbus 요청을 성공적으로 처리하고 유효한 Modbus 애플리케이션 계층 응답을 반환하는 것입니다.
실제 레지스터 값은 장치에 따라 다릅니다.
단순히 다음을 확인하는 것만으로는:
TCP/502 = OPEN
서비스가 Modbus라는 것을 반드시 증명하지는 않습니다.
포트 번호는 관례입니다. 다른 애플리케이션이 TCP/502에서 수신 대기할 수 있으며, Modbus 장치도 구성에 따라 다르게 동작할 수 있습니다.
따라서 스캐너는 다음을 사용합니다:
TCP 연결 가능성
+
Modbus 프로토콜 응답
=
Modbus 감지
이렇게 하면 단순한 포트 스캔보다 애플리케이션 계층 감지가 더 의미 있게 됩니다.
일부 장치는 레지스터 구성이나 지원되는 기능 코드 때문에 초기 0x04 요청에 응답하지 않을 수 있습니다.
따라서 스캐너는 첫 번째 요청이 실패하면 두 번째 요청을 시도합니다:
modbus_read_bits(ctx, 0, 1, bits);
이것은 다음 기능 코드를 사용합니다:
0x01 - 코일 읽기
대표적인 요청은 다음과 같습니다:
00 02 00 00 00 06 01 01 00 00 00 01
분해:
00 02 트랜잭션 식별자
00 00 프로토콜 식별자
00 06 길이
01 유닛 식별자
01 기능 코드
00 00 시작 주소
00 01 수량
스캐너는 두 Modbus 작업 중 하나라도 성공적인 응답을 받으면 대상을 감지된 것으로 간주합니다.
대상 IP
|
v
TCP 연결
포트 502
|
+------+------+
| |
실패 연결됨
| |
v v
무시 기능 0x04
|
+------+------+
| |
유효 실패
| |
v v
MODBUS 발견 기능 0x01
|
+------+------+
| |
유효 실패
| |
v v
MODBUS 발견 감지 없음
스캐너는 프로토콜 프레임을 수동으로 구성하는 대신 libmodbus를 사용하여 Modbus/TCP 패킷을 구성하고 구문 분석합니다.
기본 작업은 다음과 같습니다:
modbus_read_input_registers(ctx, 0, 1, ®);
이것이 실패하면:
modbus_read_bits(ctx, 0, 1, bits);
그런 다음 연결이 닫히고 libmodbus 컨텍스트가 해제됩니다.
이렇게 하면 프로토콜 처리는 Modbus 라이브러리 내부에 유지되고 스캐너는 다음을 처리합니다:
스캐너는 짧은 연결 및 응답 타임아웃을 사용합니다:
#define TIMEOUT_SEC 2
이렇게 하면 단일 도달 불가능하거나 응답하지 않는 호스트가 작업자를 과도하게 오래 차단하는 것을 방지할 수 있습니다.
산업용 네트워크에는 상대적으로 느린 응답을 가진 장치가 포함될 수 있으므로 환경에 따라 타임아웃 값을 조정해야 할 수 있습니다.
대상은 여러 작업자 스레드에 분산됩니다.
예를 들어:
스레드 1 → 대상 1–64
스레드 2 → 대상 65–128
스레드 3 → 대상 129–192
스레드 4 → 대상 193–254
각 작업자는 독립적으로 Modbus/TCP 감지를 시도합니다.
이를 통해 각 대상을 순차적으로 기다리는 대신 여러 호스트를 동시에 테스트할 수 있습니다.
긍정적인 결과는 대상이 스캐너가 이해하는 Modbus 요청에 성공적으로 응답했음을 의미합니다.
다음을 반드시 식별하는 것은 아닙니다:
이러한 것은 별도의 핑거프린팅 또는 평가 작업입니다.
이 스캐너는 주로 Modbus/TCP 서비스 감지 도구입니다.
감지 방법은 의도적으로 보수적입니다.
장치가 Modbus를 지원하더라도 다음 경우에는 감지에 실패할 수 있습니다:
따라서:
응답 없음 ≠ 확실히 Modbus가 아님
이는 스캐너가 시도한 프로브를 사용하여 성공적인 응답을 얻을 수 없었음을 의미합니다.
필요한 종속성을 설치하고 다음으로 컴파일합니다:
make
또는 직접:
gcc -Wall -Wextra -O2 -o modbus modbus.c -lmodbus -lpthread
실행:
./modbus -i 192.168.1.0 -s /24 -t 10 -o results.txt
예시:
[+] Modbus 감지됨: 192.168.1.20:502
[+] Modbus 감지됨: 192.168.1.42:502
[+] 스캔됨: 254 | 발견됨: 2 Modbus
[+] 결과가 results.txt에 저장됨
이 스캐너는 TCP 포트 감지에만 의존하지 않고 실제 프로토콜 상호 작용을 수행하여 Modbus/TCP 서비스를 감지합니다.
감지 프로세스는 다음과 같습니다:
TCP/502에 연결
↓
Modbus 기능 코드 0x04 전송
↓
유효한 Modbus 응답 수신?
↓
예 → Modbus 감지됨
|
아니요
↓
Modbus 기능 코드 0x01 전송
↓
유효한 Modbus 응답 수신?
↓
예 → Modbus 감지됨
|
아니요
↓
감지 없음
핵심 원칙은 간단합니다:
포트만이 아니라 프로토콜을 감지하십시오.