برنامه های دات نتی چگونه کرک می شوند؟ چگونه می توان جلوی Crack شدن این نرم افزارها را گرفت؟ تمام کامپایلرهای مبتنی بر پلاتفرم دات نت، کد نوشته شده را پس از کامپایل به کدی با نام IL یا Intermediate Language که یک زبان میانی مانند زبان اسمبلی است تبدیل می کنند. این کد توسط کامپایلری به نام JIT یا Just In Time Compiler به کد ماشین تبدیل شده و سپس اجرا می شود.دلیل استفاده از کد IL امکان اجرای برنامه های نوشته شده مبتنی بر پلاتفرم .NET در سایر پلاتفرم ها مانند MAC و Linux قابل اجرا باشند. همین موضوع دست افراد رو برای کرک کردن برنامه های دات نت باز گذاشته.
در این مطلب قصد دارم به شما دو ابزاری که در این کار استفاده می شوند و البته توسط خود مایکروسافت نیز عرضه شدند آموزش بدم.از این دو ابزار برای استخراج کد IL از فایل های کامپایل شده و همچنین تبدیل مجدد کدهای IL به فایل های exe یا dll استفاده می شوند. برای ادامه کار برنامه ای در محیط کنسول می نویسیم که یک نام کاربری و کلمه عبور از کاربر دریافت کرده و در صورت صحیح بودن کلمه عبور پیغام مناسبی به کاربر نمایش می دهد. سپس با ابزارهای ذکر شده برنامه را کرک خواهیم کرد:
class Program { public static void Main() { Console.Write("Username: "); var username = Console.ReadLine(); Console.Write("Password: "); var password = Console.ReadLine(); if (username.ToLower().Equals("hossein") && password.Equals("ITPro")) { Console.WriteLine("Welcome to ITPro.ir!"); } else { Console.WriteLine("Oops! Username or Password is invalid!"); } Console.ReadKey(); } }
بعد از کامپایل کردن برنامه یک فایل اجرایی exe برای ما تولید می شود. در اینجا ما باید شرطی که در متد Main نوشتیم را جوری تغییر بدیم که برنامه با هر ورودی اجرا شود. در ابتدا به ابزار ildasm.exe نیاز داریم. برای اجرای این ابزار، کافیست Developer Command Prompt for VS2015 را اجرا کنید. در صورتی که از نسخه های پایین تر Visual Studio استفاده می کنید محیط Command Prompt مربوطه وجود دارد. پس از اجرا، در خط فرمان عبارت ildasm.exe را تایپ کرده و کلید enter را بزنید تا پنجره ildasm باز شود:
از منوی فایل گزینه Open را انتخاب کرده و سپس فایل exe ایجاد شده از پروژه کنسول نوشته شده را انتخاب کنید. این فایل در پوشه پروژه کنسول، پوشه bin\debug وجود دارد. پس از انتخاب فایل لیستی از محتویات فایل انتخابی برای شما نمایش داده می شود:
در این پنجره با دوبار کلیک کردن بر روی هر یک از بخش های نمایش داده شده، اطلاعاتی به شما نمایش داده می شود. برای مثال، با دوبار کلیک بر روی متد Main کدهای مربوط به این متد برای شما نمایش داده می شود:
کد IL ایجاد شده برای متد Main به صورت زیر است:
.method private hidebysig static void Main(string[] args) cil managed { .entrypoint // Code size 106 (0x6a) .maxstack 2 .locals init ([0] string username, [1] string password, [2] bool V_2) IL_0000: nop IL_0001: ldstr "Username: " IL_0006: call void [mscorlib]System.Console::Write(string) IL_000b: nop IL_000c: call string [mscorlib]System.Console::ReadLine() IL_0011: stloc.0 IL_0012: ldstr "Password: " IL_0017: call void [mscorlib]System.Console::Write(string) IL_001c: nop IL_001d: call string [mscorlib]System.Console::ReadLine() IL_0022: stloc.1 IL_0023: ldloc.0 IL_0024: callvirt instance string [mscorlib]System.String::ToLower() IL_0029: ldstr "hossein" IL_002e: callvirt instance bool [mscorlib]System.String::Equals(string) IL_0033: brfalse.s IL_0042 IL_0035: ldloc.1 IL_0036: ldstr "ITPro" IL_003b: callvirt instance bool [mscorlib]System.String::Equals(string) IL_0040: br.s IL_0043 IL_0042: ldc.i4.0 IL_0043: stloc.2 IL_0044: ldloc.2 IL_0045: brfalse.s IL_0056 IL_0047: nop IL_0048: ldstr "Welcome to ITPro.ir!" IL_004d: call void [mscorlib]System.Console::WriteLine(string) IL_0052: nop IL_0053: nop IL_0054: br.s IL_0063 IL_0056: nop IL_0057: ldstr "Oops! Username or Password is invalid!" IL_005c: call void [mscorlib]System.Console::WriteLine(string) IL_0061: nop IL_0062: nop IL_0063: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey() IL_0068: pop IL_0069: ret } // end of method Program::Main
برای درک کدهای IL، می بایست با زبان IL آشنا باشید. برای مرحله بعد می بایست از برنامه باز شده در ildasm خروجی بگیریم. برای اینکار ابتدا در یکی از درایو ها یک پوشه با نام Cracking Source ساخته، سپس از پنجره اصلی ildasm، از منوی فایل گزینه dump را انتخاب کرده، در پنجره Dump Options نیازی به تغییری نیست، بر روی دکمه OK کلیک کنید، در ادامه مسیر پوشه ای که ساختید را انتخاب کنید. بعد از اینکار یک فایل با پسوند il و یک فایل با پسوند res برای شما ساخته می شود. برای کرک کردن برنامه شما باید این فایل il را تغییر دهید. در داخل فایل به دنبال کد مربوط به متد Main گشته و قسمت مربوط به شرطی که نام کاربری و کلمه عبور بررسی می شود را تغییر می دهیم. کد مربوط به قسمت شرط برنامه به صورت زیر است:
IL_0042: ldc.i4.0 IL_0043: stloc.2 IL_0044: ldloc.2 IL_0045: brfalse.s IL_0056
در خط 45 ام، گفته می شود اگر شرط صحیح نبود، به خط 56 ام برو که پیغام مربوط به صحیح نبودن نام کاربری و کلمه عبور نمایش داده می شود. کافیست در خط 45 ام، عبارت brfalse.s را brtrue.s تغییر دهیم. یعنی اگر شرط صحیح بود به خط 56 ام برو. کد این بخش را به صورت زیر تغییر می دهیم:
IL_0042: ldc.i4.0 IL_0043: stloc.2 IL_0044: ldloc.2 IL_0045: brtrue.s IL_0056
فایل il تغییر داده شده را ذخیره می کنیم. حال باید از روی فایل تغییر داده شده مجدد یک فایل اجرایی ایجاد کنیم. برای اینکار باید از ابزار ilasm.exe استفاده کنیم. این ابزار برای ساختن اسمبلی های دات نت از روی فایل های il استفاده می شود. در همان محیط Developer Command Prompt به پوشه ای می رویم که فایل il را در آن dump کردیم. دستور زیر را در خط فرمان می نویسیم:
ilasm.exe source.il /exe
با این کار، یک فایل اجرایی با نام source.exe برای ما تولید می شود که همان فایل اجرایی ما است، با این تفاوت که این فایل کرک شده و حال با هر نام کاربری و کلمه عبوری (به جز نام کاربری Hossein و کلمه عبور ITPRO) می توان به سیستم وارد شد.
اما راهکار پیش گیری کرک شدن کدهای دات نت چیست؟ نمی توان راهکاری ارائه کرد که صد در صد جوابگو باشد، اما می توان بوسیله ابزارهایی که اصطلاحاً به آن ها Obfuscator گفته می شود، کاری کرد که کدهای IL به راحتی قابل فهم نبوده یا نتوان آن ها را با ابزارهایی مثل ildasm باز کرد. در یک مطلب جداگانه در مورد ابزارهای Obfuscator صحبت خواهیم کرد. امیدوارم که این مطلب مورد توجه شما قرار گرفته باشد.
سلام دوست عزیز، روشی که گفته شده فقط بر روی برنامه های دات نت جواب میده، شما کافیه فایل exe یا dll مورد نظر رو داشته باشید. پیغامی هم که دریافت می کنید به دو دلیل می تونه باشه:
سلام حتما باید فایل های پروزه رو داشته باشیم ؟
من فایل exe رو باز میکنم با ارور :
error : 'App.exe' has no valid CLR header and cannot be disassembled
مواجه میشم آیا همه برنامه ها رو میشه طبق روشی که گفتید بررسی کرد ؟
سلام
دوست عزیز چرا مطلب را در قالب یک پُست آموزشی و یا مقاله در همین سایت در دسترس عموم قرار نمی دین؟ چه نیازی به ارسال ایمیل هست؟
من پیشنهاد میکنم که ابزار Secure Team رو هم یه نگاهی بندازید. اگر هم مایل بودید لیستی از Obfuscator های موجود در اختیار داشته باشید، در این لینک این لیست قابل دسترسته.
بله درسته. منظور منم دقیقاً همین پاراگراف اولی هستش که شما پاسخ دادید( که البته شما کاملاترش کردین) ممنون.
موارد 3و2 را که فرمودید من تا حالا انجام دادم ولی برای تغییر CLR Header چطوری میتونم عمل کنم؟ آموزش ولینک خاصی توی سایت داره؟ یا باید با نرم افزار خاصی اینکار رو انجام بدم؟ در حال حاضر با نرم افزار Crypto Obfuscator برای این منظور کار میکنم ولی برای مورد 1 چیزی توی راهنمای اون ندیدم.
مبحث Strong Key که شما فرمودید کاربردش برای انتشار Assembly ها، قابلیت Versioning و نصب اسمبلی ها در GAC یا همون Global Assembly Cache هست. در حقیقت SNK ارتباطی به دسترسی به کلاس های internal اسمبلی نداره. موردی که شما بهش اشاره کردید، یعنی استفاده از InternalsVisibleToAttribute، یک Attribute در سطح اسمبلی هست که شما می تونید مشخص کنید که بخش های Internal داخل اسمبلی توسط کدام اسمبلی ها که بهشون Friend Assembly هم گفته میشه قابل دسترس باشند. حالا اگر اسمبلی مورد نظر شما توسط SNK به اصطلاح Sign شده باشه باید Fully Qualified Assembly Name به عنوان ورودی InternalsVisibleTo بنویسید، در غیر اینصورت تنها نام اسمبلی کفایت میکنه. پس در حقیقت الزامی به Sign کردن اسمبلی جهت استفاده در InternalsVisibleTo نیست. اما در مورد جلوگیری از محافظت کدها، مکانیزم Obfuscate کردن کدها به چند صورت انجام میشه:
اما نکته ای که وجود داره، تمامی روش های بالا بوسیله Reverse Engineering قابل بازگشته و همانطوری که در متن هم اشاره کردم، هیچ روش صد در صد مطمئنی برای حفاظت از کدها وجود نداره، همین چند وقت پیش بود که نیاز شدید به آخرین نسخه ابزار Janus داشتم و به خاطر عدم امکان خرید اون مجبور به کرک کردن اون شدم. با مکانیزم های مختلفی Obfuscation انجام شده بود، اما باز هم امکان کرک داشت. شما با کارهای ذکر شده تنها عمل کرک رو کند می کنید. ;)
سلام
دوست عزیز، سئوالی که در این زمینه (فی البداهه) به ذهنم رسید اینه که:
فرض کنید شما در دات نت و با زبان سی شارپ چند کامپوننت برای انجام کارهای خاص و سرعت بخشیدن به کارهای حرفه ای خود نوشته اید و تصمیم دارید آنها را در اختیار سایر برنامه نویسان نیز قرار دهید. همونطوریکه می دونید موقعی از یک اسمبلی به کلاسهای سایر اسمبلی های وابسته، دسترسی داریم که در سطح public یاشند و چنانچه بخواهیم از اسمبلی A به کلاس های سایر Assembly هایی که (تمام/یرخی از) کلاسهای آن در سطح Internal هستند، دسترسی داشته باشیم، باید یک کلید مشترک (StrongKey) در کامپیوتری که در حال Develop با آن هستیم تولید کرده و مانند تصویر زیر در بخش Signing از هر پروژه قرار داده و سپس در فایل AssemblyInfo نیز توسط کلاس ()InternalsVisibleTo که در فضای نامی System.Runtime.CompilerServices قرار دارد، (بترتیب و یکی یکی) نام اسمبلی هایی که قرار است از کلاسهای internal اسمبلی جاری، تغذیه شوند را به همراه Public Key (ازStronkKey ایی که روی سیستم خود تولید کرده ایم) بنویسیم و یا در اصل آدرس دهی میکنیم.
حال با توجه به ابزارهای مختلف جهت دسترسی به سورس کدهای مختلف از نرم افزارهایی که با دات نت نوشته اندو از طرفی اینکه اکثر برنامه نویسان همیشه ترس از دست دادن سورس کدهای ارزشمند خود را دارند، با توجه به سناریویی که خدمت تون عرض کردم، برای یک چنین اسمبلی هایی امکان Encrypt و ناخوانا کردن کدها توسط نرم افزارهای مختلف وجود ندارد، چرا که پس از آن، امکان دسترسی به کلاسهای Internal در سایر اسمبلی های وابسته را از دست میدهند.
سئوال اینجاست که:
برای یک چنین مواردی که نیاز به محافظت شدید از سورس کدها در مقابل افراد سود جو می باشد، شما چه پیشنهادی دارید؟