Введение в .Net Cracking

Discussion in 'Реверсинг' started by 0x0c0de, 20 Feb 2008.

  1. 0x0c0de

    0x0c0de Elder - Старейшина

    Joined:
    25 May 2007
    Messages:
    441
    Likes Received:
    396
    Reputations:
    297
    [.Net Cracking]
    Жертва - DVD Cover Searcher. Это .Net приложение, отказывающееся работать без триал-ключа (или фул)

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

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

    Рабочее окно дизассемблера
    [​IMG]

    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
    [​IMG]
    У нас есть несколько вариантов действий. Запросить триал ключ, ввести рег данные, купить, выйти.

    Попробуем пропатчить проверку введенного ключа. Посмотрим какие методы использует 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]
    Вот и все… Вопросы по статье в пм
     
    #1 0x0c0de, 20 Feb 2008
    Last edited: 20 Feb 2008
    6 people like this.
  2. nerezus

    nerezus Banned

    Joined:
    12 Aug 2004
    Messages:
    3,191
    Likes Received:
    729
    Reputations:
    266
    По мне, так удобнее ковырять декомпилированный код в C#, к примеру, чем IL.
    А декомпилируется он спойкойно.

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

    0x0c0de Elder - Старейшина

    Joined:
    25 May 2007
    Messages:
    441
    Likes Received:
    396
    Reputations:
    297
    >> По мне, так удобнее ковырять декомпилированный код в C#, к примеру, чем IL.

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

    12usver12 Elder - Старейшина

    Joined:
    12 Dec 2007
    Messages:
    50
    Likes Received:
    9
    Reputations:
    0
    ето все хорошо а если прогу обработать obfuscator-ом ?
     
  5. 0x0c0de

    0x0c0de Elder - Старейшина

    Joined:
    25 May 2007
    Messages:
    441
    Likes Received:
    396
    Reputations:
    297
    >> если прогу обработать obfuscator-ом

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

    12usver12 Elder - Старейшина

    Joined:
    12 Dec 2007
    Messages:
    50
    Likes Received:
    9
    Reputations:
    0
    прикольная статья, но мало мальский здравомыслящий програмер, обработает прогу как минимум dotfuscator-ом...luts reflector весь код покажет - считай шо open-source, если его не обфусцировать.
     
  7. 12usver12

    12usver12 Elder - Старейшина

    Joined:
    12 Dec 2007
    Messages:
    50
    Likes Received:
    9
    Reputations:
    0
    будем ждать следующих статей...
     
  8. z01b

    z01b Муджахид

    Joined:
    5 Jan 2007
    Messages:
    494
    Likes Received:
    382
    Reputations:
    22
    то тогда плохо =)
     
    2 people like this.
  9. 12usver12

    12usver12 Elder - Старейшина

    Joined:
    12 Dec 2007
    Messages:
    50
    Likes Received:
    9
    Reputations:
    0
    впринципе не так все и плохо, обфускаторы
    изменяют только нназвание классов и методов и т.д. а их реализация все равно в открытом виде декомпилируется, например
    private void button1_Click(object sender, EventArgs e)
    {
    Messagebox.Show("Превед Античат");
    }

    на

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

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