מניעת העתקת תוכנה באופן בלתי חוקי


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

קיימות טכנוקות רבות למניעת הגנת תוכנה, פריצה (hacking) של תוכנה וביצוע הינדוס לאחור (reverse engineering) של קובץ התוכנה. לא ניתן לאכוף מערכת רישוי לתוכנה כאשר ניתן בקלות לעקוף מערכת זו על ידי הינדוס לאחור. לכן נעשה שימוש בטכניקות של אובפוסקציה (Obfuscation).

תהליך האובפוסקציה כרוך בשינוי קוד התוכנה באופן שיקשה על הבנתו. תהליך זה מבוצע בשתי רמות: רמת קוד המקור ורמת קובץ הריצה של התוכנה.

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

בשנת 2013 פרסמתי מאמר בנוגע להצפנת מחרוזות בתוכנה לצורך אובפוסקציה (זכה בפרס ראשון כמאמר הטוב ביותר ב-++C באותו חודש). במאמר מובא קוד מקור פרי פיתוח צוות הפיתוח שלנו אשר במסגרתו נעשה שימוש בהצפנת AES 256.

ראשית, אציין כי מאמר זה מתמקד בתוכנה כתובה ב-C /C++ ולא בשפות אחרות או בטכנולוגיות DOT NET אשר באופן טבעי אינן מוגנות וקיימים כלים להקשחתם.

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

כדוגמה לקוד לפני ואחרי, מובאת באתר שלהם הדוגמה הבאה:

לפני ביצוע התהליך קוד המקור נראה כך:

 

for (i=0; i < M.length; i++){
   // Adjust position of clock hands
   var ML=(ns)?document.layers['nsMinutes'+i]:ieMinutes[i].style;
   ML.top=y[i]+HandY+(i*HandHeight)*Math.sin(min)+scrll;
   ML.left=x[i]+HandX+(i*HandWidth)*Math.cos(min);
 }

לאחר התהליך הוא ייראה כך:

for(O79=0;O79<l6x.length;O79++){var O63=(l70)?document.layers["nsM
\151\156u\164\145s"+O79]:ieMinutes[O79].style;O63.top=l61[O79]+O76+(O79*O75)
*Math.sin(O51)+l73;O63.left=l75[O79]+l77+(O79*l76)*Math.cos(O51);}

במהלך תהליך זה נתמכות הפעולות הבאות, כל אחת תורמת את חלקה להפיכת הקוד לבלתי ניתן להבנה:

  • Output encoding in ASCII, European ASCII, or UNICODE
  • No changes to the your C++ compilation or execution procedurs or environment
  • User definable list of preserved names
  • Predefined list of reserved identifiers for C++ standard libraries provided
  • Can preserve most preprocessor conditionals and macro calls in obfuscated source
  • Option to neatly format C++ source code to aid development before obfuscation.
  • Output encoding in ASCII, European ASCII, or UNICODE
  • Command line and GUI interfaces

 לעומת זאת, ברמה הבינארית של קובץ הריצה של התוכנה, התהליך מתבצע בשתי צורות עיקריות:

1. ביצוע שינויים ברמה הבינארית ועם זאת מבלי לפגוש במבנה של הקובץ (משום שפגיעה משמעותית במבנה הקובץ תהפוך אותו ללא קריא למערכת ההפעלה).

2. שימוש ב-Loader

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

הדרך השניה מבוססת על הצפנת קובץ הריצה כולו, והפעלתו על ידי תוכנה קטנה הטוענת את המידע המוצפן בזמן ריצה, פותחת את ההצפנה ומריצה אותו. שיטה זו מסורבלת ומקשה על עידכונים, דיבוג  ותחזוקה. ובנוסף עלולה להביא לחסימה על ידי רוב האנטי וירוסים המזהים סוג כזה של הפעלה כמאפיין לנוזקות למינהן; אם בוחנים את אופן פעולה של Loader, הוא משמש כ”סוס טרויאני” אשר עם הפעלתה, פותח ושולף מתוכו את התוכנה האמיתית. סוג כזה של פעולה מתאים לנוזקות המסוות את ייעודן האמיתי אולם ככל שמדובר בתוכנה לגיטימית, תוכנה כזו תיחסם בשל אותה תבנית פעולה. מצד שני, ברמה של הגנה, שיטה זו יעילה ביותר שכן היא מאפשרת הצפנה של מרבית התוכנה. (תמיד מדובר בהצפנה של “מרבית” ולא של “כל” התכונה, זאת משום שללא החלק הלא מוצפן, לא תתפאשר הרצת התוכנה. צלילה למבנה ה-PE (המבנה אשר עומד מאחורי כל תוכנה שתרוץ ברגע שתופעל בלחיצה כפולה), מתואר במאמרים רבים כדוגמת מאמר זה.

קיימות מספר שיטות אשר שימוש בהן עשוי להקשיח את התוכנה ולהקשות על הינדוס לאחור שלה:

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

לדוגמה

GetProcAddress(hModule,reinterpret_cast<const char*>(reinterpret_cast<int>(szName)

בנוסף נעשה שימוש בטכניקות המקשות על הפעלת כלי דיבוג (Debuggers) ואלה יפורטו להלן:

  1. בדיקות תזמון של ריצת קטעי קוד, מתוך הנחה שאם אלה רצים כאשר במקביל מופעל debugger, זמן הריצה יהיה ארוך יותר.
  2. בדיקת קיומם של debuggers ידועים לפי שם התהליך (process) שלהם.
  3. שימוש בחתימת קוד / חתימה דיגטלית אחרת של קטעי תוכנה, ואימות חתימה זו בזמן ריצה על מנת להבטיח שלא הוחלפו.

 

לדוגמה, אם התוכנה עושה שימוש ב-DLL, הוא ייחתם דיגיטלית בחתימת קוד (Code Signing Certificate). לאחר מכן, בזמן ריצה, תאומת החתימה (כמובן לא על ידי ה-DLL עצמו).

לאחרונה פיתחתי כלי סיוע לחתימת קוד וניתן להוריד כלי זה כאן.

בנוסף, למיקרוסופט יש ספריה לחתימה ואימות חתימה וניתן לקרוא עליה כאן.

תיאור זה הנו על קצה המזלג וניתן לקרוא עוד (באנגלית) בבלוג של Secured Globe, Inc ובבלוג של מערכת הגנת התוכנה שלנו.

מיכאל האפרתי Michael Haephrati

Secured Globe, Inc.

 

Advertisements

One comment on “מניעת העתקת תוכנה באופן בלתי חוקי

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s