P01NT
0x04 الأساسيات 05/19

سلاسل الهروب

سلاسل الهروب والحرف المنهي null (0x00): كيف تخزن النصوص فعلياً ولماذا تنتهي النصوص داخل الـ binaries بصفر.

· 3 دقائق قراءة · 467 كلمة
المحتويات

بسم الله الرحمن الرحيم.

في هذا المقال سنتعرف على سلاسل الهروب (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 وحدها تنشئ سطراً جديداً.

تمرين عملي

  1. اكتب برنامجاً يطبع A بثلاث طرق: مباشرة، بـ \101، وبـ \x41 — وتأكد أن الناتج متطابق.
  2. افتح الملف القابل للتنفيذ الناتج بـ HxD وابحث عن قيمة 41 المخزنة — ستجد أن الحرف انتهى في الملف كقيمة فعلية، لأن سلاسل الهروب تُعالَج أثناء الترجمة وليست نصاً يبقى كما هو.
  3. اطبع النص Hello\0World و Hello World ولاحظ الفرق في نهاية القراءة — هذا هو سلوك النصوص المنتهية بـ null.

تذكير: يجب التطبيق العملي لكل السلاسل. لا تخف من عدم حفظها — فمع الممارسة العملية ستشعر بسهولتها، فهي لا تتطلب إلا تكراراً بسيطاً. وفقكم الله.