
# ماسح كشف Modbus/TCP متعدد الخيوط مكتوب بلغة C باستخدام libmodbus.
ماسح C متعدد الخيوط لكشف خدمات Modbus/TCP باستخدام libmodbus.
لا يعتمد الماسح فقط على فتح منفذ TCP 502. بدلاً من ذلك، يقوم بإنشاء اتصال Modbus/TCP وإرسال طلب Modbus على مستوى طبقة التطبيق. تُستخدم استجابة Modbus الصالحة كمؤشر أساسي على وجود خدمة Modbus.
Modbus هو بروتوكول اتصالات صناعي يُستخدم بشكل شائع بواسطة PLCs وRTUs وHMIs وأنظمة SCADA وأجهزة الاستشعار والعدادات والأجهزة الصناعية الأخرى.
ينقل Modbus/TCP بروتوكول تطبيق Modbus عبر TCP.
منفذ Modbus/TCP القياسي هو:
TCP/502
تدفق الاتصال النموذجي هو:
Scanner
|
| TCP connection → 502
|
| Modbus/TCP request
v
Modbus Device
|
| Modbus/TCP response
v
Scanner
على عكس البروتوكولات التي توفر لافتة (banner) فور الاتصال، يتطلب Modbus/TCP عمومًا أن يرسل العميل طلب Modbus صالحًا قبل أن ينتج الجهاز استجابة على مستوى طبقة التطبيق.
يقوم الماسح بالكشف على مرحلتين.
يحاول الماسح إنشاء اتصال TCP إلى:
<target>:502
إذا تعذر إنشاء الاتصال، يُعتبر الهدف غير مستجيب لـ Modbus/TCP.
ومع ذلك، فإن فتح منفذ TCP/502 بحد ذاته لا يُعتبر دليلاً كافياً على وجود Modbus.
بعد الاتصال، يرسل الماسح طلب Modbus باستخدام libmodbus.
الفحص الأساسي هو:
modbus_read_input_registers(ctx, 0, 1, ®);
يُنتج هذا رمز دالة Modbus:
0x04 - Read Input Registers
يطلب الطلب من الهدف سجل إدخال واحد يبدأ من العنوان 0.
إذا أعاد الهدف استجابة Modbus صالحة، يعتبر الماسح أن الخدمة مكتشفة.
تتكون حزمة Modbus/TCP من:
+----------------------+----------------------+
| MBAP Header | PDU |
+----------------------+----------------------+
MBAP Header:
+------------------+
| Transaction ID | 2 bytes
| Protocol ID | 2 bytes
| Length | 2 bytes
| Unit Identifier | 1 byte
+------------------+
PDU:
+------------------+
| Function Code | 1 byte
| Data | N bytes
+------------------+
رأس MBAP خاص بـ Modbus/TCP.
يستخدم الفحص الأول للماسح رمز الدالة 0x04.
طلب تمثيلي هو:
00 01 00 00 00 06 01 04 00 00 00 01
تقسيم هذا الطلب:
00 01 Transaction Identifier
00 00 Protocol Identifier
00 06 Length
01 Unit Identifier
04 Function Code
00 00 Starting Address
00 01 Quantity
00 01
يحدد المعاملة.
يمكن أن تختلف القيمة لأن معرّف المعاملة يُدار عادةً بواسطة مكتبة عميل Modbus.
00 00
قيمة 0 تحدد Modbus.
00 06
يحدد عدد البايتات التالية لحقل الطول.
01
يحدد وحدة Modbus المستهدفة.
04
رمز الدالة 0x04 يعني:
Read Input Registers
00 00
يبدأ الماسح من عنوان السجل 0.
00 01
يطلب الماسح سجلاً واحدًا.
تحتوي الاستجابة الناجحة للطلب على رمز الدالة 0x04 وبيانات السجل المطلوبة.
استجابة تمثيلية قد تبدو كالتالي:
00 01 00 00 00 05 01 04 02 00 00
تقسيمها:
00 01 Transaction Identifier
00 00 Protocol Identifier
00 05 Length
01 Unit Identifier
04 Function Code
02 Byte Count
00 00 Register Value
الجزء المهم للكشف هو أن الهدف يعالج طلب Modbus بنجاح ويعيد استجابة Modbus صالحة على مستوى طبقة التطبيق.
قيمة السجل الفعلية تعتمد على الجهاز.
مجرد التحقق من:
TCP/502 = OPEN
لا يثبت بالضرورة أن الخدمة هي Modbus.
أرقام المنافذ هي اصطلاحات. يمكن لتطبيق مختلف الاستماع على TCP/502، وقد يتصرف جهاز Modbus بشكل مختلف اعتمادًا على تكوينه.
لذلك يستخدم الماسح:
TCP connectivity
+
Modbus protocol response
=
Modbus detection
هذا يجعل الكشف على مستوى طبقة التطبيق أكثر معنى من مجرد فحص المنافذ.
قد لا تستجيب بعض الأجهزة لطلب 0x04 الأولي بسبب تكوين سجلاتها أو رموز الدوال المدعومة.
لذلك يحاول الماسح طلبًا ثانيًا إذا فشل الأول:
modbus_read_bits(ctx, 0, 1, bits);
يستخدم هذا رمز الدالة:
0x01 - Read Coils
طلب تمثيلي هو:
00 02 00 00 00 06 01 01 00 00 00 01
التقسيم:
00 02 Transaction Identifier
00 00 Protocol Identifier
00 06 Length
01 Unit Identifier
01 Function Code
00 00 Starting Address
00 01 Quantity
يعتبر الماسح الهدف مكتشفًا عندما تتلقى أي من عمليتي Modbus استجابة ناجحة.
Target IP
|
v
TCP connection
port 502
|
+------+------+
| |
Failed Connected
| |
v v
Ignore Function 0x04
|
+------+------+
| |
Valid Failed
| |
v v
MODBUS FOUND Function 0x01
|
+------+------+
| |
Valid Failed
| |
v v
MODBUS FOUND No detection
يستخدم الماسح libmodbus لبناء وتحليل حزم Modbus/TCP بدلاً من بناء إطارات البروتوكول يدويًا.
العملية الأساسية هي:
modbus_read_input_registers(ctx, 0, 1, ®);
إذا فشلت هذه:
modbus_read_bits(ctx, 0, 1, bits);
ثم يُغلق الاتصال ويُحرر سياق libmodbus.
هذا يُبقي معالجة البروتوكول داخل مكتبة Modbus بينما يتعامل الماسح مع:
يستخدم الماسح مهلات زمنية قصيرة للاتصال والاستجابة:
#define TIMEOUT_SEC 2
هذا يمنع مضيفًا واحدًا غير قابل للوصول أو غير مستجيب من حجب عامل (worker) لفترة زمنية مفرطة.
يمكن أن تحتوي الشبكات الصناعية على أجهزة ذات استجابات بطيئة نسبيًا، لذلك قد تحتاج قيم المهلة إلى التعديل اعتمادًا على البيئة.
يتم تقسيم الأهداف بين عدة خيوط عاملة.
على سبيل المثال:
Thread 1 → targets 1–64
Thread 2 → targets 65–128
Thread 3 → targets 129–192
Thread 4 → targets 193–254
يحاول كل عامل بشكل مستقل كشف Modbus/TCP.
هذا يسمح باختبار مضيفين متعددين بشكل متزامن بدلاً من الانتظار لكل هدف بالتسلسل.
النتيجة الإيجابية تعني أن الهدف استجاب بنجاح لطلب Modbus يفهمه الماسح.
لا تحدد بالضرورة:
تلك مهام منفصلة لتحديد البصمة (fingerprinting) أو التقييم.
الماسح هو في الأساس أداة كشف خدمة Modbus/TCP.
طريقة الكشف متحفظة عمدًا.
قد يكون الجهاز قادرًا على Modbus لكنه يفشل في الكشف إذا:
لذلك:
No response ≠ Definitively not 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 detected: 192.168.1.20:502
[+] Modbus detected: 192.168.1.42:502
[+] Scanned: 254 | Found: 2 Modbus
[+] Results saved to: results.txt
يكتشف الماسح خدمات Modbus/TCP من خلال إجراء تفاعل فعلي مع البروتوكول بدلاً من الاعتماد حصريًا على كشف منفذ TCP.
عملية الكشف هي:
Connect to TCP/502
↓
Send Modbus Function Code 0x04
↓
Receive valid Modbus response?
↓
YES → Modbus detected
|
NO
↓
Send Modbus Function Code 0x01
↓
Receive valid Modbus response?
↓
YES → Modbus detected
|
NO
↓
No detection
المبدأ الأساسي بسيط:
اكتشف البروتوكول، وليس المنفذ فقط.