أداة strace (اختصار لـ System Call Trace) هي واحدة من أهم وأقوى أدوات التحليل الديناميكي (Dynamic Analysis) وتشخيص الأخطاء في أنظمة Linux. إذا كانت أداة ltrace التي شرحناها سابقاً تراقب ما يطلبه البرنامج من المكتبات (Library Space)، فإن strace تذهب إلى مستوى أعمق وأقرب إلى قلب نظام التشغيل؛ إنها تراقب وتتبع نداءات النظام (System Calls) والإشارات (Signals) المتبادلة بين البرنامج ونواة نظام التشغيل (Linux Kernel).

لفهم هذه الأداة بشكل صحيح، يجب أن نتخيل نظام التشغيل مقسوماً إلى عالمين:

عندما يحتاج البرنامج في الـ User Space إلى القيام بأي عملية تتضمن العتاد—مثل قراءة ملف من القرص، أو طباعة نص على الشاشة، أو فتح اتصال عبر الشبكة—فإنه لا يستطيع فعل ذلك بنفسه، بل يجب عليه طرق باب النواة وطلب ذلك منها عبر ما يسمى System Call (أو Syscall). هنا تحديداً تقف أداة strace لتسجيل كل نداء يخرج من البرنامج إلى النواة.

كيف تعمل أداة strace تحت الغطاء؟

تعتمد strace على نداء نظام خاص جداً في Linux يسمى ptrace (Process Trace).

  1. عند تشغيل برنامج ما تحت مظلة strace، تقوم الأداة بربط نفسها بالبرنامج (Target Process).
  2. في كل مرة يصل فيها البرنامج إلى تعليمات برمجية تطلب syscall (مثل الانتقال من الـ User Mode إلى الـ Kernel Mode)، تقوم النواة بإيقاف البرنامج مؤقتاً وإرسال إشارة إلى strace.
  3. تقرأ strace مسجلات المعالج (CPU Registers) لتتعرف على رقم الـ Syscall والمعاملات (Arguments) الممررة له، وتطبعها لك على الشاشة (في مخرج الأخطاء القياسي stderr).
  4. بعد الطباعة، تسمح للبرنامج بمتابعة التنفيذ حتى ينتهي الـ Syscall، فتتوقف مرة أخرى لتسجيل القيمة المسترجعة (Return Value) أو رمز الخطأ إن وجد.

لماذا تعتبر الأداة جوهرية في اختبار الاختراق والتحليل؟

تمنحك strace القدرة على فهم تصرفات أي برنامج غامض أو برمجية خبيثة بالكامل دون الحاجة لرؤية سطر كود واحد، لأن البرنامج مهما حاول إخفاء كوده أو تشفيره (Obfuscation)، فإنه في النهاية مجبر على التعامل مع نظام التشغيل عبر الـ Syscalls ليفعل أي شيء مفيد. من خلالها يمكنك معرفة:

تشريح مخرجات الأمر (Anatomy of strace Output)

مخرجات strace تتبع دائماً تنسيقاً ثابتاً: اسم النداء، ثم المعاملات بين قوسين، ثم علامة التساوي = تليها القيمة المسترجعة. انظر إلى هذا السطر كمثال:

openat(AT_FDCWD, "/etc/passwd", O_RDONLY) = 3