
أداة تتبّع مبنية على LLVM لتتبع التلوث الشامل، وتحليل تدفق البيانات، والتتبّع.
PolyTracker هي أداة أُنشئت في الأصل من أجل التعليق المعجمي الآلي والتنقل في المُحلِّلات (Automated Lexical Annotation and Navigation of Parsers)، وهو اختصار عكسي صِيغ لغرض وحيد هو الإشارة إليها باسم The ALAN Parsers Project. ومع ذلك، فقد تطوّرت لتصبح أداةً متعددة الأغراض لتنفيذ تحليل تدفق البيانات وتدفق التحكم في البرامج بكفاءة. PolyTracker هي تمريرة LLVM (pass) تُجهّز البرامج لتتبّع أيّ بايتات من ملف الإدخال تعمل عليها أيّ دوال. تُخرج قاعدة بيانات تحتوي على معلومات تدفق البيانات، بالإضافة إلى أثر تنفيذ وقت التشغيل (runtime trace). كما توفر PolyTracker مكتبة Python للتفاعل مع مخرجاتها وتحليلها، بالإضافة إلى بيئة Python تفاعلية (REPL).
يمكن استخدام PolyTracker بالتزامن مع PolyFile لتحديد الغرض الدلالي للدوال في المُحلِّل تلقائيًا. كما تتضمن ميزة تجريبية قادرة على توليد قواعد نحوية خالية من السياق (context free grammar) تمثل اللغة التي يقبلها المُحلِّل.
على عكس بدائل التجهيز الديناميكي مثل Taintgrind، تفرض PolyTracker عبئًا أدائيًا لا يُذكر على جميع المدخلات تقريبًا، وهي قادرة على تتبّع كل بايت من المدخلات في الوقت نفسه. بدأت PolyTracker كفرع (fork) من LLVM DataFlowSanitizer وتستلهم الكثير من Angora Fuzzer. غير أنها، على عكس نظام Angora، قادرة على تتبّع مصدر (provenance) التلوث بالكامل. في فبراير 2021، أضاف LLVM DataFlowSanitizer ميزة جديدة لتتبّع مصدر التلوث تُسمى تتبّع الأصل (origin tracking). ومع ذلك، فهو قادر على تتبّع 16 تلوثًا كحد أقصى في المرة الواحدة، بينما يمكن لـ PolyTracker تتبّع ما يصل إلى 231-1.
يُعد ملف README هذا دليل الاستخدام العام لتثبيت PolyTracker وتجميع/تجهيز الملفات التنفيذية. للتفاعل البرمجي مع PolyTracker أو توسيعها عبر واجهة Python البرمجية (API)، وكذلك للتفاعل مع آثار التنفيذ الناتجة عن الشيفرة المُجهَّزة، راجع توثيق Python.
يتم التحكم في PolyTracker عبر سكربت Python يُسمى polytracker. يمكنك تثبيته عن طريق تشغيل
pip3 install polytracker
تتطلب PolyTracker بيئة نظام محددة جدًا لكي تعمل، لذلك من المرجح أن يشغّلها جميع المستخدمين تقريبًا في بيئة حاويات (containerized). لحسن الحظ، يجعل polytracker ذلك سهلًا. كل ما عليك فعله هو تثبيت docker، ثم تشغيل:
polytracker docker pull
و
polytracker docker run
يقوم الأمر الأخير بتركيب (mount) دليل العمل الحالي داخل حاوية Docker الخاصة بـ PolyTracker، ويتيح لك بناء وتشغيل البرامج المُجهَّزة.
يحتوي سكربت التحكم polytracker — الذي يمكنك تشغيله من نظام المضيف أو من داخل حاوية Docker — على مجموعة متنوعة من الأوامر، سواء لتجهيز البرامج أو لتحليل الملفات الناتجة (artifacts). على سبيل المثال، يمكنك استكشاف تدفقات البيانات في التنفيذ، وإعادة بناء مخطط تدفق التحكم (control flow graph) للبرنامج المُجهَّز، وحتى استخراج قواعد نحوية خالية من السياق تطابق المدخلات التي يقبلها البرنامج. يمكنك استكشاف هذه الأوامر عن طريق تشغيل
polytracker --help
يعمل سكربت polytracker أيضًا كبيئة REPL إذا شُغِّل دون وسائط سطر أوامر:
$ polytracker
PolyTracker (4.0.0)
https://github.com/trailofbits/polytracker
Type "help" or "commands"
>>> commands
تأتي PolyTracker أيضًا مع أمر build. يتيح هذا الأمر للمستخدم تشغيل أي أمر بناء في بيئة مُجهَّزة بـ Blight. سينتج عن ذلك ملف blight_journal.jsonl يسجّل جميع الأوامر التي نُفِّذت أثناء البناء. إذا كان لديك هدف C/C++، يمكنك تجهيزه عن طريق استدعاء polytracker build وتمرير أمر البناء الخاص بك:
polytracker build gcc -g -o my_binary my_source.c
لتجهيز هدف بناء، استخدم الأمر instrument-targets. افتراضيًا، سيستخدم الأمر ملف blight_journal.jsonl الموجود في دليل العمل الحالي لبناء نسخة مُجهَّزة من هدف البناء. سيتم بناء هدف البناء المُجهَّز باستخدام نفس العلامات (flags) التي استُخدمت في هدف البناء الأصلي.
polytracker instrument-targets my_binary
يدعم أمر build أيضًا برامج أكثر تعقيدًا تستخدم نظام بناء مثل autotiools أو CMake:
polytracker build cmake .. -DCMAKE_BUILD_TYPE=Release
polytracker build ninja
# or
polytracker build ./configure
polytracker build make
ثم شغّل instrument-targets على أي من أهداف البناء:
polytracker instrument-targets a.bin b.so
عندها سيكون a.instrumented.bin وb.instrumented.so هما النسختان المُجهَّزتان. راجع ملفات Dockerfile في دليل examples للحصول على أمثلة حول كيفية تجهيز برامج من العالم الحقيقي.
سيكتب البرنامج المُجهَّز مخرجاته إلى المسار المحدد في POLYDB، أو إلى polytracker.tdag إذا لم يُحدَّد. هذا ملف ثنائي يمكن التعامل معه عن طريق تشغيل:
from polytracker import PolyTrackerTrace, taint_dag
trace = PolyTrackerTrace.load("polytracker.tdag")
tdfile = trace.tdfile
first_node = list(tdfile.nodes)[0]
print(f"First node affects control flow: {first_node.affects_control_flow}")
# Operate on all Range nodes
for index, node in enumerate(tdfile.nodes):
if isinstance(node, taint_dag.TDRangeNode):
print(f"Node {index}: first {node.first}, last {node.last}")
# Access taint forest
tdforest = trace.taint_forest
n1 = tdforest.get_node(1)
print(
f"Forest node {n1.label}. Parent labels: {n1.parent_labels}, "
f"source: {n1.source.path if n1.source is not None else None}, "
f"affects control flow: {n1.affected_control_flow}"
)
يمكنك أيضًا تشغيل ملف تنفيذي مُجهَّز مباشرةً من بيئة REPL:
$ polytracker
PolyTracker (4.0.0)
https://github.com/trailofbits/polytracker
Type "help" or "commands"
>>> trace = run_trace("path_to_binary", "path_to_input_file")
سيقوم هذا تلقائيًا بتشغيل الملف التنفيذي المُجهَّز في حاوية Docker، إذا لزم الأمر.
⚠️ إذا كنت تشغّل PolyTracker داخل Docker أو جهاز افتراضي (VM): يمكن أن تكون PolyTracker بطيئة جدًا عند تشغيلها في بيئة افتراضية إذا كان ملف الإدخال أو — بشكل خاص — قاعدة بيانات الإخراج موجودين في دليل تم تعيينه (mapped) أو تركيبه (mounted) من نظام التشغيل المضيف. وينطبق هذا بشكل خاص عند تشغيل PolyTracker في Docker من مضيف macOS. الحل هو كتابة قاعدة البيانات إلى مسار داخل الحاوية/الجهاز الافتراضي ثم نسخها إلى النظام المضيف في النهاية.
توثيق واجهة Python البرمجية (API) متاح هنا.
في وقت التشغيل، يبحث تجهيز PolyTracker عن عدد من معاملات التكوين المحددة عبر متغيرات البيئة. يتيح ذلك تعديل معاملات التجهيز دون الحاجة إلى إعادة تجميع الملف التنفيذي.
يقبل PolyTracker معاملات التكوين في شكل متغيرات بيئة لتجنب إعادة تجميع البرامج المستهدفة. مجموعة متغيرات البيئة الحالية التي يدعمها PolyTracker هي:
POLYDB: A path to which to save the output database (default is polytracker.tdag)
WLLVM_ARTIFACT_STORE: Provides a path to an existing directory to store artifact/manifest for all build targets
POLYTRACKER_TAINT_ARGV: Set to '1' to use argv as a taint source.
POLYTRACKER_STDIN_SOURCE: Set to '1' to use stdin as a taint source.
POLYTRACKER_STDOUT_SINK: Set to '1' to use stdout as a taint sink.
POLYTRACKER_STDERR_SINK: Set to '1' to use stderr as a taint sink.
سيقوم Polytracker بتعيين معاملات التكوين الخاصة به بالترتيب التالي: