✕ סגור 
צור קשר
תודה על ההתעניינות .

Thank you! Your submission has been received!

Oops! Something went wrong while submitting the form

הגיע הזמן לרדת למחתרת – על ערפול קוד (Obfuscation)

רן בר-זיק
|
קלה
|
Apr 30, 2019
alt="facebook"alt="linkedin"להרשמה לניוזלטר


לצערי, בעקבות חגיגות חוק הצנזורה גיליתי בורות מפתיעה משהו בקרב מפתחי ווב בכל הנוגע למונחים בסיסיים. בסדרת המאמרים הזו, על ערפול, ערבול, הצפנות וקריפטוגרפיה בסיסית אני הולך לכסות את המידע הזה שרלוונטי לכל מפתח שהוא שרוצה לעסוק באבטחה.


דוגמאות הקוד הן ב-JavaScript, מתוך הבנה שמדובר בשפת תכנות הווב הפופולרית בעולם, אבל בגדול? גם אם אתם לא מכירים את השפה הזו, תוכלו להבין מעולה את המאמר. מדובר בקוד מאוד פשוט להבנה - פשוט תתייחסו אליו כ pseudo-code.


ערפול היא טכניקה פשוטה ביותר שנועדה להסתיר את קוד המקור של התוכנה. מה זאת אומרת? יש לי קוד מקור של תוכנה, לצורך העניין ג’אווהסקריפט. אם אני רוצה להגן על התוכנה שלי או על חלקים ממנה, ערפול יכול מאוד לסייע לי בעניין הזה. ערפול בעצם לוקח את הקוד והופך אותו למשהו לא קריא. נדגים?


מתחילים


בואו ונניח שעמלתי מאוד וכתבתי את הקוד המדהים הבא:


function myFunction() {
 console.log('Hello world!');
}
myFunction();


מה הקוד הזה עושה? לא צריך להיות שועל ג’אווהסקרפיט כדי להבין שהוא מדפיס Hello World לקונסולה. נניח ואני כן רוצה שהוא יעבוד אצל הלקוח, אבל אני לא רוצה שכל אחד יוכל להעתיק אותו. כלומר אני רוצה לערפל אותו. מה אני עושה?


• ניקח את התוכנה ונהפוך אותה למחרוזת טקסט.
• את מחרוזת הטקסט אני ממיר ל base_64
• את מחרוזת הטקסט אני שם באתר ומריץ אותה עם eval.


איך זה נראה? קודם כל, אני הופך את התוכנה שלי למחרוזת טקסט ארוכה. למשל:


const source = 'function myFunction() { console.log(\'Hello world!\');} myFunction();';


התוצאה, היא טקסט מאוד מג’וברש שנראה ככה:


'ZnVuY3Rpb24gbXlGdW5jdGlvbigpIHsgY29uc29sZS5sb2coJ0hlbGxvIHdvcmxkIScpO30gbXlGdW5jdGlvbigpOw=='


אני לוקח ומריץ אותה. איך? מכניס את התוצאה לתוך פונקציית decode ל-base64 ומריץ eval על הכל. בדיוק ככה:


const productionCode = 'ZnVuY3Rpb24gbXlGdW5jdGlvbigpIHsgY29uc29sZS5sb2coJ0hlbGxvIHdvcmxkIScpO30gbXlGdW5jdGlvbigpOw==';
eval(window.atob(productionCode));


ומי שרוצה להשתעשע – יכול עם ה-codepen הזה:


זהו ערפול קלאסי, כלומר הקוד שהלקוח רואה לא כולל בתוכו שום פונקציונליות, אם אני אסתכל על הקוד הזה אני פשוט לא אצליח להבין אותו ממבט ראשון - יש מצב שבשני כן.

const productionCode = 'ZnVuY3Rpb24gbXlGdW5jdGlvbigpIHsgY29uc29sZS5sb2coJ0hlbGxvIHdvcmxkIScpO30gbXlGdW5jdGlvbigpOw==';
eval(window.atob(productionCode));


אבל כמובן שמדובר בגישה מאוד נאיבית לערפול. אם מישהו ירצה לפצלח את הערפול, הוא יוכל לבחון את הקוד, להעתיק את מחרוזת הטקסט ולעשות לה base64_decode. אפשר לקחת את כל העניין הזה לשלב הבא. למשל, אפשר לקחת את שמות הפונקציות ולשנות אותן למחרוזת טקסט רנדומלית. למשל, לעשות משהו כזה:


const rsajdf = [console.log];
function jhsjkaskjas() {
 rsajdf[0]('Hello world!');
}
jhsjkaskjas();
ורק אחר כך לקחת את הטקסט ולהכניס אותו ל base64. זה הופך את הקוד לפחות קריא משמעותית! ישנן עוד כמה שיטות כאלו שיכולות להפוך את הקוד למשהו מהמם. שימו לב למשל לקוד המדהים הזה:
var _0x3547 = ['\x4b\x4d\x52\x63\x57'];
(function (_0x2d8f05, _0x4b81bb) {
   var _0x4d74cb = function (_0x32719f) {
       while (--_0x32719f) {
           _0x2d8f05['push'](_0x2d8f05['shift']());
       }
   };
   _0x4d74cb(++_0x4b81bb);
}(_0x3547, 0x184));
var _0xef72 = function (_0x3c4159, _0x224e76) {
   _0x3c4159 = _0x3c4159 - 0x0;
   var _0x39e262 = _0x3547[_0x3c4159];
   return _0x39e262;
};
function myFunction() {
   var _0x2a5c66 = {};
   _0x2a5c66[_0xef72('0x0')] = '\x48\x65\x6c\x6c\x6f\x20\x77\x6f\x72\x6c\x64\x21';
   console['\x6c\x6f\x67'](_0x2a5c66[_0xef72('0x0')]);
}
myFunction();


הדבר המהמם הזה הוא אותו קודם מסכן שכתבתי קודם, אך מעורפל באמצעות JavaScript Obfuscator Tool – מודול של ג׳אווהסקריפט שעושה ערפול בכמה שיטות. לא מאמינים? הדביקו אותו בקונסולה שלכם ותראו מה קורה. חדי העין יוכלו לנסות לפצח את הקוד. הם יצליחו. כי בסופו של דבר זה קוד שרץ על גבי הקליינט ועם כל המשחקים שאנחנו יכולים לשחק, ומישהו יכול לפצח את זה (ויש גם כלים שעוזרים בזה).


אבל, וזה אבל גדול – אף אחד לא יוכל לקחת את הקוד הזה ולמכור אותו הלאה, לפחות בלי מאמץ משמעותי לפרק אותו. יהיה מאוד קשה לקחת חלקים מהקוד ולהפיץ אותם הלאה.


לסיכום


ישנן לא מעט טכניקות ערפול שחלק מהן מאוד מחוכמות. לכל שפה שהיא. אבל צריך לזכור שכל ערפול, גם הטוב ביותר האפשרי, לא ימנע מהאקר זדוני להבין מה קורה בקוד שלך. אם בקוד הג׳אווהסקריפט שלכם יש קוד שלא צריך לצאת לצד הלקוח ומכיל פרטים שונים שמוטב שהאקרים לא ידעו אותם – ערפול הוא לא הגנה, כי כל ערפול ניתן לפיצוח.


חשוב גם לזכור שערפול שונה ממיניפקציה ואגרגציה (תהליכים שנקראים uglify) – מטרת התהליכים האלו לכווץ ולייעל את הקוד. תהליך ערפול בדרך כלל מנפח את הקוד, כך שלא מומלץ להשתמש בו בסביבת פרודקשן. מתי כן? אך ורק אם אתם מוכרים את הקוד וחוששים שהקונה יעתיק חלק מהפונקציונליות וימכור אותה הלאה.


מאת: רן בן זיק, מתכנת מומחה ועיתונאי טכנולוגי

רוצים להתעדכן בתכנים נוספים בנושאי ענן וטכנולוגיות מתקדמות? הירשמו עכשיו לניוזלטר שלנו ותמיד תישארו בעניינים > להרשמה


לצערי, בעקבות חגיגות חוק הצנזורה גיליתי בורות מפתיעה משהו בקרב מפתחי ווב בכל הנוגע למונחים בסיסיים. בסדרת המאמרים הזו, על ערפול, ערבול, הצפנות וקריפטוגרפיה בסיסית אני הולך לכסות את המידע הזה שרלוונטי לכל מפתח שהוא שרוצה לעסוק באבטחה.


דוגמאות הקוד הן ב-JavaScript, מתוך הבנה שמדובר בשפת תכנות הווב הפופולרית בעולם, אבל בגדול? גם אם אתם לא מכירים את השפה הזו, תוכלו להבין מעולה את המאמר. מדובר בקוד מאוד פשוט להבנה - פשוט תתייחסו אליו כ pseudo-code.


ערפול היא טכניקה פשוטה ביותר שנועדה להסתיר את קוד המקור של התוכנה. מה זאת אומרת? יש לי קוד מקור של תוכנה, לצורך העניין ג’אווהסקריפט. אם אני רוצה להגן על התוכנה שלי או על חלקים ממנה, ערפול יכול מאוד לסייע לי בעניין הזה. ערפול בעצם לוקח את הקוד והופך אותו למשהו לא קריא. נדגים?


מתחילים


בואו ונניח שעמלתי מאוד וכתבתי את הקוד המדהים הבא:


function myFunction() {
 console.log('Hello world!');
}
myFunction();


מה הקוד הזה עושה? לא צריך להיות שועל ג’אווהסקרפיט כדי להבין שהוא מדפיס Hello World לקונסולה. נניח ואני כן רוצה שהוא יעבוד אצל הלקוח, אבל אני לא רוצה שכל אחד יוכל להעתיק אותו. כלומר אני רוצה לערפל אותו. מה אני עושה?


• ניקח את התוכנה ונהפוך אותה למחרוזת טקסט.
• את מחרוזת הטקסט אני ממיר ל base_64
• את מחרוזת הטקסט אני שם באתר ומריץ אותה עם eval.


איך זה נראה? קודם כל, אני הופך את התוכנה שלי למחרוזת טקסט ארוכה. למשל:


const source = 'function myFunction() { console.log(\'Hello world!\');} myFunction();';


התוצאה, היא טקסט מאוד מג’וברש שנראה ככה:


'ZnVuY3Rpb24gbXlGdW5jdGlvbigpIHsgY29uc29sZS5sb2coJ0hlbGxvIHdvcmxkIScpO30gbXlGdW5jdGlvbigpOw=='


אני לוקח ומריץ אותה. איך? מכניס את התוצאה לתוך פונקציית decode ל-base64 ומריץ eval על הכל. בדיוק ככה:


const productionCode = 'ZnVuY3Rpb24gbXlGdW5jdGlvbigpIHsgY29uc29sZS5sb2coJ0hlbGxvIHdvcmxkIScpO30gbXlGdW5jdGlvbigpOw==';
eval(window.atob(productionCode));


ומי שרוצה להשתעשע – יכול עם ה-codepen הזה:


זהו ערפול קלאסי, כלומר הקוד שהלקוח רואה לא כולל בתוכו שום פונקציונליות, אם אני אסתכל על הקוד הזה אני פשוט לא אצליח להבין אותו ממבט ראשון - יש מצב שבשני כן.

const productionCode = 'ZnVuY3Rpb24gbXlGdW5jdGlvbigpIHsgY29uc29sZS5sb2coJ0hlbGxvIHdvcmxkIScpO30gbXlGdW5jdGlvbigpOw==';
eval(window.atob(productionCode));


אבל כמובן שמדובר בגישה מאוד נאיבית לערפול. אם מישהו ירצה לפצלח את הערפול, הוא יוכל לבחון את הקוד, להעתיק את מחרוזת הטקסט ולעשות לה base64_decode. אפשר לקחת את כל העניין הזה לשלב הבא. למשל, אפשר לקחת את שמות הפונקציות ולשנות אותן למחרוזת טקסט רנדומלית. למשל, לעשות משהו כזה:


const rsajdf = [console.log];
function jhsjkaskjas() {
 rsajdf[0]('Hello world!');
}
jhsjkaskjas();
ורק אחר כך לקחת את הטקסט ולהכניס אותו ל base64. זה הופך את הקוד לפחות קריא משמעותית! ישנן עוד כמה שיטות כאלו שיכולות להפוך את הקוד למשהו מהמם. שימו לב למשל לקוד המדהים הזה:
var _0x3547 = ['\x4b\x4d\x52\x63\x57'];
(function (_0x2d8f05, _0x4b81bb) {
   var _0x4d74cb = function (_0x32719f) {
       while (--_0x32719f) {
           _0x2d8f05['push'](_0x2d8f05['shift']());
       }
   };
   _0x4d74cb(++_0x4b81bb);
}(_0x3547, 0x184));
var _0xef72 = function (_0x3c4159, _0x224e76) {
   _0x3c4159 = _0x3c4159 - 0x0;
   var _0x39e262 = _0x3547[_0x3c4159];
   return _0x39e262;
};
function myFunction() {
   var _0x2a5c66 = {};
   _0x2a5c66[_0xef72('0x0')] = '\x48\x65\x6c\x6c\x6f\x20\x77\x6f\x72\x6c\x64\x21';
   console['\x6c\x6f\x67'](_0x2a5c66[_0xef72('0x0')]);
}
myFunction();


הדבר המהמם הזה הוא אותו קודם מסכן שכתבתי קודם, אך מעורפל באמצעות JavaScript Obfuscator Tool – מודול של ג׳אווהסקריפט שעושה ערפול בכמה שיטות. לא מאמינים? הדביקו אותו בקונסולה שלכם ותראו מה קורה. חדי העין יוכלו לנסות לפצח את הקוד. הם יצליחו. כי בסופו של דבר זה קוד שרץ על גבי הקליינט ועם כל המשחקים שאנחנו יכולים לשחק, ומישהו יכול לפצח את זה (ויש גם כלים שעוזרים בזה).


אבל, וזה אבל גדול – אף אחד לא יוכל לקחת את הקוד הזה ולמכור אותו הלאה, לפחות בלי מאמץ משמעותי לפרק אותו. יהיה מאוד קשה לקחת חלקים מהקוד ולהפיץ אותם הלאה.


לסיכום


ישנן לא מעט טכניקות ערפול שחלק מהן מאוד מחוכמות. לכל שפה שהיא. אבל צריך לזכור שכל ערפול, גם הטוב ביותר האפשרי, לא ימנע מהאקר זדוני להבין מה קורה בקוד שלך. אם בקוד הג׳אווהסקריפט שלכם יש קוד שלא צריך לצאת לצד הלקוח ומכיל פרטים שונים שמוטב שהאקרים לא ידעו אותם – ערפול הוא לא הגנה, כי כל ערפול ניתן לפיצוח.


חשוב גם לזכור שערפול שונה ממיניפקציה ואגרגציה (תהליכים שנקראים uglify) – מטרת התהליכים האלו לכווץ ולייעל את הקוד. תהליך ערפול בדרך כלל מנפח את הקוד, כך שלא מומלץ להשתמש בו בסביבת פרודקשן. מתי כן? אך ורק אם אתם מוכרים את הקוד וחוששים שהקונה יעתיק חלק מהפונקציונליות וימכור אותה הלאה.


מאת: רן בן זיק, מתכנת מומחה ועיתונאי טכנולוגי

רוצים להתעדכן בתכנים נוספים בנושאי ענן וטכנולוגיות מתקדמות? הירשמו עכשיו לניוזלטר שלנו ותמיד תישארו בעניינים > להרשמה

Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.
רן בר-זיק
בואו נעבוד ביחד
צרו קשר