Форум АНТИЧАТ

Форум АНТИЧАТ (https://forum.antichat.xyz/index.php)
-   Реверсинг (https://forum.antichat.xyz/forumdisplay.php?f=94)
-   -   Введение в .Net Cracking (https://forum.antichat.xyz/showthread.php?t=62258)

0x0c0de 20.02.2008 17:22

Введение в .Net Cracking
 
[.Net Cracking]
Жертва - DVD Cover Searcher. Это .Net приложение, отказывающееся работать без триал-ключа (или фул)

[Introduction]
Что нам потребуется при изучении .Net приложений?

1.MSIL Disassembler (есть в составе Net Framework SDK) – далее просто дизассемблер

Рабочее окно дизассемблера
http://www.pikucha.ru/2395/thumbnail/in_msil.JPG

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 метода, что очень удобно. Например

Код:

// Method begins at RVA 0x13e8cc

В hiew добавить к 13e8cc ImageBase (400000) и получим адрес начала метода. А дальше нужно искать искомую последовательность, которая подвергнется патчу.


[Исследуем]

Теперь загрузим программу в дизассемблер. Цель – убрать злое окно при загрузке.

NagScreen
http://www.pikucha.ru/2394/thumbnail/nag_screen.JPG
У нас есть несколько вариантов действий. Запросить триал ключ, ввести рег данные, купить, выйти.

Попробуем пропатчить проверку введенного ключа. Посмотрим какие методы использует frmKeyEntry. Нужный нам метод - cmdUnlock_Click

Код:

.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

Основной прыжок. Если он произойдет, то мы ввели верный ключ
Код:

  IL_0024:  /* 2D  | 2E              */ brtrue.s  IL_0054
Заменим его на противоположный – brfalse. Для этого нужно заменить байт 2d на 2с. После патча программа принимает любой ключ, но по-прежнему не дает нормально с собой работать. Это значит, что, скорее всего еще одна проверка будет при перезапуске. Искать ее очень лениво, в силу обилия методов и форм. Надо найти другой, более быстрый и удобный способ. А что если… вообще убрать окно About?
Попробуем подойти с другой стороны. Сначала появляется основное окно программы, а потом требующее ключ. Значит процедура создания окна About (оно же NagScreen) происходит в Main Form. Под подозрение попадают методы
frmMain_Load
frmMain_Shown

В первом нет ничего полезного, а второе уже более интересно..

Код:

.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, то

Код:

  IL_008f:  /* 45  | 02000000        */ switch    (
            /*      | 02000000        */            IL_009e,
            /*      | 14000000        */            IL_00b0)
  IL_009c:  /* 2B  | 24              */ br.s      IL_00c2

Сработает вторая ветка свитча. И нам придется ждать 20 секунд, пока включится кнопка OK. Это нам совсем не надо.. А выполняется по дефолту как раз первая ветка. Поэтому менять здесь что-либо бестолку. Посмотрим, что по смещению IL_009e

Код:


  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]
Вот и все… Вопросы по статье в пм

nerezus 20.02.2008 17:29

По мне, так удобнее ковырять декомпилированный код в C#, к примеру, чем IL.
А декомпилируется он спойкойно.

P.S. биндинг с локалхоста на * менял в toonel.net

0x0c0de 20.02.2008 18:22

>> По мне, так удобнее ковырять декомпилированный код в C#, к примеру, чем IL.

Дело вкуса. Можно и в с#, и в delphi и в vb.. Тогда юзать .Net Reflector - как универсальный декомпилятор. Пример работы с msil я привела.

12usver12 21.02.2008 00:59

ето все хорошо а если прогу обработать obfuscator-ом ?

0x0c0de 21.02.2008 08:57

>> если прогу обработать obfuscator-ом

тема отдельной статьи. если реверс обфусцированного .net кода интересен общественности, то напишу про него

12usver12 21.02.2008 10:58

прикольная статья, но мало мальский здравомыслящий програмер, обработает прогу как минимум dotfuscator-ом...luts reflector весь код покажет - считай шо open-source, если его не обфусцировать.

12usver12 21.02.2008 13:54

будем ждать следующих статей...

z01b 21.02.2008 19:10

Цитата:

Сообщение от 12usver12
ето все хорошо а если прогу обработать obfuscator-ом ?

то тогда плохо =)

12usver12 22.02.2008 16:12

Цитата:

Сообщение от z01b
то тогда плохо =)

впринципе не так все и плохо, обфускаторы
изменяют только нназвание классов и методов и т.д. а их реализация все равно в открытом виде декомпилируется, например
private void button1_Click(object sender, EventArgs e)
{
Messagebox.Show("Превед Античат");
}

на

private void M25(object sender, EventArgs e)
{
Messagebox.Show("Превед Античат");
}

так что ildasm и reflector в руки


Время: 02:05