[.Net Cracking] Жертва - DVD Cover Searcher. Это .Net приложение, отказывающееся работать без триал-ключа (или фул) [Introduction] Что нам потребуется при изучении .Net приложений? 1.MSIL Disassembler (есть в составе Net Framework SDK) – далее просто дизассемблер Рабочее окно дизассемблера 2. Хекс редактор, любой понравившийся Основные команды, нам нужные для понимания того, что нам выдал MSIL Disassembler. На эту тему есть неплохой материал (правда на английском). Почитать, интересующимся, можно здесь (MSIL Tutorial) http://www.codeguru.com/Csharp/.NET/net_general/il/article.php/c4635 По опкодам (просто мего находка) http://blogs.msdn.com/bluecollar/archive/2006/09/27/773065.aspx А опкоды будут необходимы для патча. Кое-что было на краклабе и tuts4you. Однако у меня возникло желание привести пример практический (и, главное, на русском), а не витать в теоретических абстракциях. Сокращенно (очень очень сокращенно) я привожу список команд, нам необходимых [Commands] Ldstr строка—загрузка строки в стек Call функция(аргументы)—вызов функции. Pop- эквивалентно одноименной команде ассемблера – выталкивание значения из стека ret—возврат из функции ldc.i4.n—загрузка 32-битной константы в стек stloc.n—загрузка значения из стека в переменную add—сложение двух чисел sub—вычитание mul- умножение br.s метка—безусловный переход по адресу _метка_ Перед исследованием стоит включить показ байтов команд в меню View->Show Bytes (должна стоять галочка). Это нам нужно для того, чтобы найти место патча в хекс-редакторе (я буду использовать hiew, так как привычка). Дизассемблер показывает rva метода, что очень удобно. Например Code: // Method begins at RVA 0x13e8cc В hiew добавить к 13e8cc ImageBase (400000) и получим адрес начала метода. А дальше нужно искать искомую последовательность, которая подвергнется патчу. [Исследуем] Теперь загрузим программу в дизассемблер. Цель – убрать злое окно при загрузке. NagScreen У нас есть несколько вариантов действий. Запросить триал ключ, ввести рег данные, купить, выйти. Попробуем пропатчить проверку введенного ключа. Посмотрим какие методы использует frmKeyEntry. Нужный нам метод - cmdUnlock_Click Code: .method private instance void cmdUnlock_Click(object sender, class [mscorlib]System.EventArgs e) cil managed // SIG: 20 02 01 1C 12 61 { // Method begins at RVA 0x131f84 // Code size 112 (0x70) .maxstack 6 IL_0000: /* 28 | (06)00000A */ call class DCSP.My.MyProject/MyForms DCSP.My.MyProject::get_Forms() IL_0005: /* 6F | (06)000010 */ callvirt instance class DCSP.frmMain DCSP.My.MyProject/MyForms::get_frmMain() IL_000a: /* 6F | (06)000293 */ callvirt instance class DCSP.Registration.clsRegistration DCSP.frmMain::get_clsReg() IL_000f: /* 02 | */ ldarg.0 IL_0010: /* 6F | (06)0000AE */ callvirt instance class [System.Windows.Forms]System.Windows.Forms.TextBox DCSP.frmKeyEntry::get_txtKey() IL_0015: /* 6F | (0A)000120 */ callvirt instance string [System.Windows.Forms]System.Windows.Forms.TextBox::get_Text() IL_001a: /* 6F | (0A)000121 */ callvirt instance string [mscorlib]System.String::Trim() IL_001f: /* 6F | (06)00003C */ callvirt instance bool DCSP.Registration.clsRegistration::Unlock(object) IL_0024: /* 2D | 2E */ brtrue.s IL_0054 IL_0026: /* 02 | */ ldarg.0 IL_0027: /* 72 | (70)000D16 */ ldstr "Invalid Serial Key. Please Try Again." IL_002c: /* 72 | (70)000CF4 */ ldstr "Serial Key Entry" IL_0031: /* 16 | */ ldc.i4.0 IL_0032: /* 1F | 40 */ ldc.i4.s 64 IL_0034: /* 16 | */ ldc.i4.0 IL_0035: /* 28 | (06)0003D1 */ call valuetype [System.Windows.Forms]System.Windows.Forms.DialogResult DCSP.modCenterDialog::Show(class [System.Windows.Forms]System.Windows.Forms.IWin32Window, string, string, valuetype [System.Windows.Forms]System.Windows.Forms.MessageBoxButtons, valuetype [System.Windows.Forms]System.Windows.Forms.MessageBoxIcon, valuetype [System.Windows.Forms]System.Windows.Forms.MessageBoxDefaultButton) IL_003a: /* 26 | */ pop IL_003b: /* 02 | */ ldarg.0 IL_003c: /* 6F | (06)0000AE */ callvirt instance class [System.Windows.Forms]System.Windows.Forms.TextBox DCSP.frmKeyEntry::get_txtKey() IL_0041: /* 6F | (0A)000122 */ callvirt instance void [System.Windows.Forms]System.Windows.Forms.TextBoxBase::SelectAll() IL_0046: /* 02 | */ ldarg.0 IL_0047: /* 6F | (06)0000AE */ callvirt instance class [System.Windows.Forms]System.Windows.Forms.TextBox DCSP.frmKeyEntry::get_txtKey() IL_004c: /* 6F | (0A)000123 */ callvirt instance bool [System.Windows.Forms]System.Windows.Forms.Control::Focus() IL_0051: /* 26 | */ pop IL_0052: /* 2B | 1B */ br.s IL_006f IL_0054: /* 02 | */ ldarg.0 IL_0055: /* 72 | (70)000D62 */ ldstr "Thank you for registering." IL_005a: /* 72 | (70)000CF4 */ ldstr "Serial Key Entry" IL_005f: /* 16 | */ ldc.i4.0 IL_0060: /* 1F | 40 */ ldc.i4.s 64 IL_0062: /* 16 | */ ldc.i4.0 IL_0063: /* 28 | (06)0003D1 */ call valuetype [System.Windows.Forms]System.Windows.Forms.DialogResult DCSP.modCenterDialog::Show(class [System.Windows.Forms]System.Windows.Forms.IWin32Window, string, string, valuetype [System.Windows.Forms]System.Windows.Forms.MessageBoxButtons, valuetype [System.Windows.Forms]System.Windows.Forms.MessageBoxIcon, valuetype [System.Windows.Forms]System.Windows.Forms.MessageBoxDefaultButton) IL_0068: /* 26 | */ pop IL_0069: /* 02 | */ ldarg.0 IL_006a: /* 6F | (0A)0000E0 */ callvirt instance void [System.Windows.Forms]System.Windows.Forms.Form::Close() IL_006f: /* 2A | */ ret } // end of method frmKeyEntry::cmdUnlock_Click Основной прыжок. Если он произойдет, то мы ввели верный ключ Code: IL_0024: /* 2D | 2E */ brtrue.s IL_0054 Заменим его на противоположный – brfalse. Для этого нужно заменить байт 2d на 2с. После патча программа принимает любой ключ, но по-прежнему не дает нормально с собой работать. Это значит, что, скорее всего еще одна проверка будет при перезапуске. Искать ее очень лениво, в силу обилия методов и форм. Надо найти другой, более быстрый и удобный способ. А что если… вообще убрать окно About? Попробуем подойти с другой стороны. Сначала появляется основное окно программы, а потом требующее ключ. Значит процедура создания окна About (оно же NagScreen) происходит в Main Form. Под подозрение попадают методы frmMain_Load frmMain_Shown В первом нет ничего полезного, а второе уже более интересно.. Code: .method private instance void frmMain_Shown(object sender, class [mscorlib]System.EventArgs e) cil managed // SIG: 20 02 01 1C 12 61 { // Method begins at RVA 0x13e368 … IL_0085: /* 6F | (06)000293 */ callvirt instance class DCSP.Registration.clsRegistration DCSP.frmMain::get_clsReg() IL_008a: /* 7B | (04)000015 */ ldfld valuetype DCSP.Registration.clsRegistration/enmRegistrationMode DCSP.Registration.clsRegistration::intRegistrationMode IL_008f: /* 45 | 02000000 */ switch ( /* | 02000000 */ IL_009e, /* | 14000000 */ IL_00b0) IL_009c: /* 2B | 24 */ br.s IL_00c2 IL_009e: /* 28 | (06)00000A */ call class DCSP.My.MyProject/MyForms DCSP.My.MyProject::get_Forms() IL_00a3: /* 6F | (06)00000C */ callvirt instance class DCSP.frmAbout DCSP.My.MyProject/MyForms::get_frmAbout() IL_00a8: /* 6F | (0A)0000E6 */ callvirt instance valuetype [System.Windows.Forms]System.Windows.Forms.DialogResult [System.Windows.Forms]System.Windows.Forms.Form::ShowDialog() IL_00ad: /* 26 | */ pop IL_00ae: /* 2B | 12 */ br.s IL_00c2 IL_00b0: /* 28 | (06)00000A */ call class DCSP.My.MyProject/MyForms DCSP.My.MyProject::get_Forms() IL_00b5: /* 6F | (06)00000C */ callvirt instance class DCSP.frmAbout DCSP.My.MyProject/MyForms::get_frmAbout() IL_00ba: /* 1F | 0A */ ldc.i4.s 10 IL_00bc: /* 6F | (06)000070 */ callvirt instance valuetype [System.Windows.Forms]System.Windows.Forms.DialogResult DCSP.frmAbout::ShowDialog(int32) … IL_0151: /* 2A | */ ret } // end of method frmMain::frmMain_Shown Хм.. RegistrationMode… Флаг регистрации. Значения, которые может принимать intRegistrationMode RM_EVALUATION = int32(0x00000001) RM_NONE = int32(0x00000000) RM_PREMIUM = int32(0x00000003) RM_PROFESSIONAL = int32(0x00000002) Если Evaluation, то Code: IL_008f: /* 45 | 02000000 */ switch ( /* | 02000000 */ IL_009e, /* | 14000000 */ IL_00b0) IL_009c: /* 2B | 24 */ br.s IL_00c2 Сработает вторая ветка свитча. И нам придется ждать 20 секунд, пока включится кнопка OK. Это нам совсем не надо.. А выполняется по дефолту как раз первая ветка. Поэтому менять здесь что-либо бестолку. Посмотрим, что по смещению IL_009e Code: IL_009e: /* 28 | (06)00000A */ call class DCSP.My.MyProject/MyForms DCSP.My.MyProject::get_Forms() IL_00a3: /* 6F | (06)00000C */ callvirt instance class DCSP.frmAbout DCSP.My.MyProject/MyForms::get_frmAbout() IL_00a8: /* 6F | (0A)0000E6 */ callvirt instance valuetype [System.Windows.Forms]System.Windows.Forms.DialogResult [System.Windows.Forms]System.Windows.Forms.Form::ShowDialog() IL_00ad: /* 26 | */ pop IL_00ae: /* 2B | 12 */ br.s IL_00c2 Вот и показ нашего About. Как вариант можно занопить три call, отвечающих за инициализацию и показ frmAbout. Опкод команды nop – 00h. Нет, я не ошиблась – именно 00h, а не 90h. В msil все не так, как в стандартном ассемблере. Попробуем так сделать.. Забьем нулями байты с 28h по 0Ah (не 0e6h! в хекс-редакторе байты будут идти в обратном порядке). Запускаем и… Программа падает.. Почему? Все дело, как оказалось в команде pop, которую я сразу не занопила. Pop чистит стек после передыдущих call. А их теперь нет! Значит программа будет работать неправильно. Перейдем в hiew по адресу, выданном msil disassembler и добьем инструкцию pop (байт 26h). Ура. Теперь программа работает как надо. И при запуске не выводится злого окна. Все функции работают. [Outro] Вот и все… Вопросы по статье в пм
По мне, так удобнее ковырять декомпилированный код в C#, к примеру, чем IL. А декомпилируется он спойкойно. P.S. биндинг с локалхоста на * менял в toonel.net
>> По мне, так удобнее ковырять декомпилированный код в C#, к примеру, чем IL. Дело вкуса. Можно и в с#, и в delphi и в vb.. Тогда юзать .Net Reflector - как универсальный декомпилятор. Пример работы с msil я привела.
>> если прогу обработать obfuscator-ом тема отдельной статьи. если реверс обфусцированного .net кода интересен общественности, то напишу про него
прикольная статья, но мало мальский здравомыслящий програмер, обработает прогу как минимум dotfuscator-ом...luts reflector весь код покажет - считай шо open-source, если его не обфусцировать.
впринципе не так все и плохо, обфускаторы изменяют только нназвание классов и методов и т.д. а их реализация все равно в открытом виде декомпилируется, например private void button1_Click(object sender, EventArgs e) { Messagebox.Show("Превед Античат"); } на private void M25(object sender, EventArgs e) { Messagebox.Show("Превед Античат"); } так что ildasm и reflector в руки