
عادةً ما يتم تخزين الصور كملفات ثنائية ، وملف Javascript هو في الأساس نص عادي. يجب أن يتبع كلا النوعين من الملفات القواعد الخاصة بهما: تحتوي الصور على تنسيق ملف معين يقوم بترميز البيانات بطريقة معينة. لكي تكون ملفات Javascript قابلة للتنفيذ ، يجب أن تتبع صيغة محددة. تساءلت: هل من الممكن إنشاء ملف صورة يكون بناء جملة جافا سكريبت صالحًا بحيث يمكن تنفيذه؟
قبل متابعة القراءة ، أوصي بشدة باستكشاف رمل الكود هذا مع نتائج تجاربي:
https://codesandbox.io/s/executable-gif-8yq0j؟file=/index.html
إذا كنت ترغب في عرض الصورة واستكشافها بنفسك ، إذن يمكنك تحميل البرنامج من هنا:
https://executable-gif.glitch.me/image.gif
اختيار نوع الصورة الصحيح
لسوء الحظ ، تحتوي الصور على الكثير من البيانات الثنائية التي ، عند تفسيرها على أنها Javascript ، ستؤدي إلى حدوث خطأ. لذا كانت فكرتي الأولى هي: ماذا لو وضعت كل بيانات الصورة في تعليق كبير ، شيء من هذا القبيل:
/*ALL OF THE BINARY IMAGE DATA*/
سيكون هذا ملف جافا سكريبت صالحًا. ومع ذلك ، يجب أن تبدأ ملفات الصور بتسلسل محدد من البايت ، رأس ملف خاص بتنسيق الصورة. على سبيل المثال ، يجب أن تبدأ ملفات PNG دائمًا بتسلسل البايت 89 50 4E 47 0D 0A 1A 0A . إذا بدأت الصورة بـ
/*، فإن الملف لم يعد ملف صورة.
قادني عنوان الملف هذا إلى الفكرة التالية: ماذا لو استخدمنا تسلسل البايت هذا كاسم متغير وخصصنا له قيمة سلسلة طويلة:
PNG=`ALL OF THE BINARY IMAGE DATA`;
نستخدم سلاسل القوالب بدلاً من السلاسل العادية ،
"أو 'لأن البيانات الثنائية يمكن أن تحتوي على فواصل أسطر ، وأن سلاسل القوالب تعمل بشكل أفضل معها.
لسوء الحظ ، تحتوي معظم تسلسلات البايت في رؤوس ملفات الصور على أحرف غير قابلة للطباعة لا يمكن استخدامها في أسماء المتغيرات. ولكن هناك تنسيق واحد يمكننا استخدامه: GIF. تبدو كتلة رأس GIF مثل 47 49 46 38 39 61 ، والتي تم تحويلها بسهولة إلى سلسلة ASCII GIF89a - اسم متغير صالح تمامًا!
اختيار حجم الصورة الصحيح
الآن وقد وجدنا تنسيقًا للصورة يبدأ باسم متغير صالحًا ، نحتاج إلى إضافة أحرف التساوي و backtick. لذلك ، ستكون البايتات الأربعة التالية من الملف: 3D 09 60 04

البايت الأول من الصورة
بتنسيق GIF ، تحدد البايتات الأربعة بعد الرأس أبعاد الصورة. نحتاج أن نلائمهم ثلاثي الأبعاد (علامة التساوي) و 60 (اللصق الخلفي ، فتح خط). يستخدم GIF القليل من الترتيب الداخلي ، لذا فإن الحرفين الثاني والرابع لهما تأثير كبير على أحجام الصور. يجب أن تكون صغيرة بقدر الإمكان بحيث لا تكون الصورة بعرض وعالي عشرات الآلاف من البكسل. وبالتالي ، نحتاج إلى تخزين بايت ثلاثي الأبعاد كبير و 60 بايت على الأقل أهمية.
يجب أن يكون البايت الثاني من عرض الصورة مسافة بيضاء صالحة ، لأنها ستكون مسافة بين علامة التساوي وبداية السطر
GIF89a= `...... من الجدير بالذكر أيضًا أن رمز الحرف السداسي العشري يجب أن يكون صغيرًا قدر الإمكان ، وإلا ستكون الصورة ضخمة.
أصغر حرف مسافة بيضاء هو 09 (حرف جدولة أفقي). إنه يعطينا عرض الصورة الثلاثية الأبعاد 09 ، وهو 2365 باللغة endian الصغيرة ؛ أوسع بقليل مما أريد ، لكن لا يزال مقبولًا تمامًا.
بالنسبة للبايت الثاني من الارتفاع ، يمكنك اختيار قيمة تعطي نسبة عرض إلى ارتفاع جيدة. اخترت 04 ، وهو ما يعطينا ارتفاع 60 04 ، أو 1120 بكسل.
وضع البرنامج النصي في الملف
حتى الآن ، لا يفعل ملف GIF القابل للتنفيذ أي شيء تقريبًا. إنه ببساطة يعين
GIF89aسلسلة طويلة للمتغير العام . نريد أن يحدث شيء مثير للاهتمام! تُستخدم معظم البيانات الموجودة داخل GIF لترميز الصورة ، لذلك إذا حاولنا إدخال Javascript هناك ، فمن المحتمل أن تكون الصورة مشوهة بشدة. لكن لسبب ما ، يحتوي تنسيق GIF على شيء يسمى ملحق التعليق . هذا مكان لتخزين البيانات الوصفية التي لم يتم تفسيرها بواسطة وحدة فك ترميز GIF - المكان المثالي لمنطق Javascript الخاص بنا.
تم العثور على امتداد التعليق هذا مباشرة بعد مخطط ألوان GIF. نظرًا لأنه يمكننا وضع أي محتوى هناك ، يمكننا بسهولة إغلاق خط GIF89a، قم بإضافة كل Javascript ثم ابدأ مقطع تعليق متعدد الأسطر بحيث لا تؤثر بقية الصورة على محلل Javascript.
في النهاية ، قد يبدو ملفنا كالتالي:
GIF89a= ` BINARY COLOR TABLE DATA ... COMMENT BLOCK:
`;alert("Javascript!");/*
REST OF THE IMAGE */
ومع ذلك ، هناك قيود صغيرة: على الرغم من أن كتلة التعليق نفسها يمكن أن تكون بأي حجم ، إلا أنها تتكون من عدة كتل فرعية ، والحد الأقصى لحجم كل منها هو 255. هناك بايت واحد بين الكتل الفرعية يحدد طول الكتلة الفرعية التالية. لذلك ، لتناسب نص كبير هناك ، يجب تقسيمه إلى أجزاء صغيرة ، شيء من هذا القبيل:
alert('Javascript');/*0x4A*/console.log('another subblock');/*0x1F*/...
الرموز السداسية العشرية في التعليقات هي بايتات تحدد حجم الكتلة الفرعية التالية. إنها ليست خاصة بـ Javascript ، ولكنها مطلوبة لتنسيق ملف GIF. لتجنب التدخل في بقية الكود ، يجب وضعهم في التعليقات. كتبت نصًا صغيرًا يعالج أجزاء البرنامج النصي ويضيفها إلى ملف الصورة:
https://gist.github.com/SebastianStamm/c2433819cb9e2e5af84df0904aa43cb8
تنظيف البيانات الثنائية
الآن بعد أن أصبح لدينا الهيكل الأساسي ، نحتاج إلى التأكد من أن بيانات الصورة الثنائية لا تفسد بناء جملة الكود. كما ذكرنا في القسم السابق ، تم تقسيم الملف إلى ثلاثة أقسام: الأول هو التخصيص لمتغير GIF89a ، والثاني هو كود Javascript ، والثالث هو تعليق متعدد الأسطر.
دعنا نلقي نظرة على الجزء الأول حول تخصيص قيمة لمتغير:
GIF89a= ` BINARY DATA `;
إذا كانت البيانات الثنائية تحتوي على حرف
`أو مجموعة من الأحرف ${، فحينئذٍ لدينا مشكلة ، لأنها إما ستنهي سلسلة النمط أو تنشئ تعبيرًا غير صالح. الإصلاح بسيط للغاية: فقط قم بتغيير البيانات الثنائية! على سبيل المثال ، بدلاً من الحرف `(الرمز الست عشري 60 ) ، يمكنك استخدام حرف a(الرمز الست عشري 61 ). نظرًا لأن هذا الجزء من الملف يحتوي على لوحة ألوان ، فسيؤدي ذلك إلى تغييرات طفيفة في بعض الألوان ، على سبيل المثال ، استخدام لون #286148بدلاً من #286048. من غير المحتمل أن يلاحظ أي شخص الفرق.
التعامل مع التشويه
في نهاية كود Javascript ، قمنا بفتح تعليق متعدد الأسطر بحيث لا تؤثر بيانات الصورة الثنائية على تحليل Javascript:
alert("Script done");/*BINARY IMAGE DATA ...
إذا كانت بيانات الصورة تحتوي على سلسلة من الأحرف
*/، سينتهي التعليق قبل الأوان ، مما يجعل ملف Javascript غير صالح. هنا مرة أخرى ، يمكننا تغيير أحد الحرفين يدويًا بحيث لا ينهيان التعليق. ومع ذلك ، بما أننا الآن في قسم الصورة المشفرة ، ستكون النتيجة صورة تالفة ، على سبيل المثال:

صورة تالفة
في أسوأ الحالات ، قد لا يتم عرض الصورة على الإطلاق. من خلال اختيار البت المراد قلبه بعناية ، تمكنت من تقليل التشويه. لحسن الحظ ، لم يكن هناك سوى حالات قليلة من التوليفات الضارة
*/. لا تزال هناك تشوهات طفيفة في الصورة النهائية ، على سبيل المثال ، في الجزء السفلي من سطر "Valid Javascript File" ، ولكن بشكل عام أنا سعيد جدًا بالنتيجة.
الانتهاء من الملف
لقد تركنا العملية الأخيرة - إكمال الملف. يجب أن ينتهي الملف بـ 00 3 بايت بايت ، لذلك نحتاج إلى إنهاء التعليق مبكرًا. نظرًا لأن هذه هي نهاية الملف وأي ضرر محتمل سيكون خفيًا ، فقد أنهيت للتو تعليق الحظر وأضفت تعليقًا من سطر واحد حتى لا تتسبب نهاية الملف في حدوث مشكلات في التحليل:
/* BINARY DATA*/// 00 3B
إقناع المتصفح بتنفيذ الصورة
الآن ، بعد كل هذا ، لدينا أخيرًا ملف عبارة عن صورة وملف Javascript صالح. ومع ذلك ، نحتاج إلى التغلب على العقبة الأخيرة: إذا قمنا بتحميل صورة إلى الخادم وحاولنا استخدامها في علامة
script، فسنحصل على الأرجح على خطأ مشابه:
رفض تنفيذ البرنامج النصي من " http: // localhost: 8080 / image.gif " لأن نوع MIME الخاص به ('image / gif') غير قابل للتنفيذ. [التخلي عن تنفيذ البرنامج النصي من " http: // localhost: 8080 / image.gif " لأن نوع MIME الخاص به غير قابل للتنفيذ.]
أي أن المتصفح يقول بحق: "هذه صورة ، لن أقوم بتنفيذها!" وفي معظم الحالات ، هذا مناسب تمامًا. لكننا ما زلنا نريد تحقيقه. الحل ببساطة هو عدم إخبار المتصفح أن هذه صورة. لهذا ، كتبت خادمًا صغيرًا يخدم صورة بدون معلومات رأس.
بدون معلومات نوع MIME من الرأس ، لا يعرف المتصفح أنها صورة ويفعل بالضبط ما هو أفضل في السياق: اجعلها كصورة في علامة ،
<img>أو نفذها كـ Javascript في علامة <script>.
لكن ... لماذا كل هذا؟
أنا لم أحسبها بنفسي بعد. مثل هذه المهمة هي عملية إحماء جيدة للعقل ، ولكن إذا كنت تستطيع التفكير في موقف يمكن أن تكون مفيدة فيه حقًا ، فأخبرني بذلك!
إعلان
خوادم للمطورين تدور حول الخوادم الافتراضية من شركتنا.
منذ فترة طويلة ، كنا نستخدم محركات أقراص خوادم سريعة حصرية من Intel ولا نوفر على الأجهزة - فقط المعدات ذات العلامات التجارية وأحدث الحلول في السوق لتقديم الخدمات.
