بسم الله الرحمن الرحيم.
في هذا المقال سنتعرف على سلاسل الهروب (Escape Sequences) وأهميتها واستخداماتها.
ما هي سلاسل الهروب؟
تُستخدم داخل النصوص للتعبير عن رموز خاصة أو للتحكم في تنسيق المخرجات. يتم تمثيلها بالشرطة المائلة العكسية (\) متبوعة بحرف أو أكثر. الغرض منها تسهيل تمثيل المحارف الخاصة التي يصعب كتابتها داخل سلسلة نصية حرفية (String Literal) — كالـ Tab أو السطر الجديد.
1. التحكم في التنسيق والمخرجات
\n — سطر جديد (Newline)
printf("Hello\nWorld");
الناتج:
Hello
World
\t — Tab
printf("Hello\tWorld");
الناتج:
Hello World
\r — العودة لبداية السطر
printf("Hello\rWorld");
ملاحظة: على ويندوز يُكتب السطر الجديد عادةً كزوج
\r\n(CRLF). هذا التمييز مهم في الـ RE عند تحليل ملفات النصوص والبروتوكولات.
\b — الرجوع خطوة للخلف (Backspace)
printf("Hello\bWorld");
الناتج: يعيد المؤشر فوق o الأخيرة فيُكتب مكانها W، فتظهر HellWorld.
2. إدراج الرموز الخاصة
\' — علامة التنصيص المفردة
printf("It\'s cool!");
\" — علامة التنصيص المزدوجة
printf("He said, \"Hello!\"");
\\ — الشرطة المائلة العكسية نفسها
printf("C:\\Windows\\System32");
3. إدراج الرموز بالأكواد العددية
\ooo — تمثيل الحرف بقيمته في النظام الثماني (Octal)
printf("\101");
\101بالأساس الثماني = 65 بالعشري = حرفA.
\xhh — تمثيل الحرف بقيمته في النظام السداسي عشر (Hexadecimal)
printf("\x41");
\x41= 65 = حرفA. النتيجتان متطابقتان — الفرق فقط في نظام العد.
4. الأهم لمجال الهندسة العكسية: \0 (الحرف المنهي Null)
char str[] = "Hello\0World";
printf("%s", str);
الناتج: Hello فقط — لأن printf يتوقف عند أول صفر.
لماذا هذا أهم مفهوم في المقال كله؟
النصوص في لغة C لا تخزن طولها — بل تنتهي بحرف null (0x00). أي أن أي سلسلة نصية تُقرأ حتى يُصادف صفر.
هذا يفسر لك:
- لماذا ترى في أي ملف PE عند فتحه بـ HxD النصوص تنتهي بـ
00 00.- لماذا تُطبع النصوص جزئياً إذا احتوت على
\0في منتصفها.- لماذا يتصرف محللو الـ binaries بحذر مع السلاسل — فالمحلل يستخرج النصوص المتتالية ويحدد نهايتها بوجود الصفر.
- لماذا تعمل سلاسل الاستغلالات (payloads) بعناية فائقة مع حدود النصوص — لأن التجاوز عليها هو أصل كثير من الثغرات (buffer overflow).
مثال شامل
#include <stdio.h>
int main() {
printf("Escape Sequences Demo:\n");
printf("Newline -> \\n\n");
printf("Tab -> \\t\tTabbed Text\n");
printf("Backslash -> \\\\\n");
printf("Double Quote -> \\\"Hello\\\"\n");
printf("Octal -> \\101\n");
printf("Hexadecimal -> \\x41\n");
return 0;
}
لاحظ في المثال: كتابة
\\nداخل النص تطبع الحروف\nحرفياً، بينما\nوحدها تنشئ سطراً جديداً.
تمرين عملي
- اكتب برنامجاً يطبع
Aبثلاث طرق: مباشرة، بـ\101، وبـ\x41— وتأكد أن الناتج متطابق. - افتح الملف القابل للتنفيذ الناتج بـ HxD وابحث عن قيمة
41المخزنة — ستجد أن الحرف انتهى في الملف كقيمة فعلية، لأن سلاسل الهروب تُعالَج أثناء الترجمة وليست نصاً يبقى كما هو. - اطبع النص
Hello\0WorldوHello Worldولاحظ الفرق في نهاية القراءة — هذا هو سلوك النصوص المنتهية بـ null.
تذكير: يجب التطبيق العملي لكل السلاسل. لا تخف من عدم حفظها — فمع الممارسة العملية ستشعر بسهولتها، فهي لا تتطلب إلا تكراراً بسيطاً. وفقكم الله.