Различия

Здесь показаны различия между двумя версиями данной страницы.

Ссылка на это сравнение

articles:c [2017/09/05 02:55] (текущий)
Строка 1: Строка 1:
 +====== C#-diz ======
 +<​sub>​{{C#​-diz.odt|Original file}}</​sub>​
 +
 +====== дизассемблирование C# программам от A до Z ======
 +
 +крис касперски ака мыщъх, no-email
 +
 +**победоносное шествие ****.NET****-платформы по миру все продолжается и продолжается,​ а вменяемых руководств по взлому как-то не наблюдается… сегодня мы расскажем как дизассемблировать ****Visual Basic/​C#​ ****сборки ****(****включая ****C****и****++ ****программы откомпилированные в байт****-****код),​ как их патчить в ****hiew'​****е,​ вести отладку на уровне байт-кода,​ словном,​ заправим мозговые баки свежей порцией авиационного керосина,​ выведем двигатели на взлетный режим и дадим хороший старт, написав свой собственный ****crackme**** и тут же взломав его всеми доступными средствами**
 +
 +===== введение =====
 +
 +Технология .NET готовится отпраздновать свой юбилей. За это время было написано множество коммерческих программ (и малвари в том числе),​ но как только дело доходит до того, чтобы заглянуть внутрь p-кода на предмет "​отломать"​ пару ненужных байт, выясняется,​ что достойных хакерских инструментов нет, и, судя по всему, и не появится,​ поэтому,​ приходится использовать то, что есть, хакерствуя в весьма стесненных обстоятельствах,​ словно шахтеры в забое!
 +
 +===== >>>​ врезка отказ от ответственности =====
 +
 +**стандартное отречение:​ **//вся информация,​ предоставленная ниже, преследует исключительно благи цели (анализ вредоносного программного обеспечения,​ например) и мыщъх не несет никакой ответственности (ни явной, ни предполагаемой) за любой возможный ущерб или потерянную выгоду//​
 +
 +===== >>>​ врезка что нам понадобится =====
 +
 +  - **Visual Studio 2008 Express**:
 +    - последняя версия знаменитой "​студии"​ от MS, распространяющаяся бесплатно и включающая в себя все необходимое для полноценной работы:​ трансляторы Visual Basic, C#, а так же новый компилятор Cи++ способный транслировать Си++ программы в байт-код. на W2K устанавливаться категорически отказалась,​ на Server 2003 встала с полпинка (off-line install занимает 894 Мбайт в .iso-формате):​ __http://​www.microsoft.com/​express/​download/​__;​
 +{{c_Image_0.png?​553}}
 +
 +Рисунок 1 отсюда можно бесплатно скачать последнюю версию Microsoft Visual Studio
 +
 +  - **Mono 2.0 Beta for Windows**:
 +    - альтернативная реализация .NET от компании Novell, поддерживающая различные версии Linux и Windows, нормально встала на W2K, но потребовала MS Framework,​ кроме того комплект поставки неполный (в частности,​ нет дизассемблера),​ а откомпилированные сборки жутко тормозят,​ зато дистрибутив занимает 71 Мбайт:​ __http://​www.go-mono.com/​mono-downloads/​download.html__;​
 +{{c_Image_1.png?​553}}
 +
 +Рисунок 2 единственная (на данный момент) реализация платформы .NET вне Microsoft
 +
 +  - **Standard ECMA-335/​Common Language Infrastructure (CLI)/4th edition (June 2006)**:
 +    - полня версия европейского стандарта,​ описывающая архитектуру виртуальной машины,​ байт-код,​ структуру ассемблерных сборок,​ в общем, солидный 556-страничный документ из серии "​маст хэв"​ (на английском языке в формате pdf): __www.ecma-international.org/​publications/​standards/​Ecma-335.htm__ а вот прямая ссылка:​ __www.ecma-international.org/​publications/​files/​ECMA-ST/​Ecma-335.pdf__;​
 +  - **CIL Instruction Set**:
 +    - краткий справочник оп-кодов с "C# Online.NET free encyclopedia"​ – жутко неполный,​ но зато вполне удобный и не содержащий воды (на английском языке):​ __http://​en.csharp-online.net/​CIL_Instruction_Set__;​
 +  - **Введение в MSIL**:
 +    - цикл статей,​ от Кенни Керр, в переводе Aquila (одного из основателей WASM) — подробное описание архитектуры виртуальной машины и концепций языка C#, рекомендуемое к прочтению всеми начинающими хакерами (на русском языке):​ __http://​www.wasm.ru/​series.php?​sid=22__;​
 +  - **Common Intermediate Language**:
 +    - поверхностное описание CIL-языка (общего для всех языков платформы .NET) на Wikipedia со ссылками на кучу полезных ресурсов (на английском языке):​ __http://​en.wikipedia.org/​wiki/​Common_Intermediate_Language__;​
 +  - **Linking native C++ into C# applications**:​
 +    - любопытный пост на форуме,​ показывающий как вызывать Си++ модули из .NET-программ,​ образуя смесь управляемого и неуправляемого кода, высаживающую инструменты для анализа .NET-программ на измену (на английском языке):​ __blogs.msdn.com/​texblog/​archive/​2007/​04/​05/​linking-native-c-into-c-applications.aspx__;​
 +  - **Joel Pobar'​s CLR weblog**:
 +    - блог одного из ведущих разработчиков CLR, с тонной полезной инфы, раскрывающей многие недокументированные особенности (на английском языке):​ __http://​blogs.msdn.com/​joelpob____/​__;​
 +  - **ilasm.exe**:​
 +    - штатный .NET-ассемблер,​ входящий в комплект поставки MS VS и Mono: __C:​\WINDOWS\Microsoft.NET\Framework\v2.0.50727\ilasm.exe__;​
 +  - **ildasm.exe**:​
 +    - штатный (и весьма недурственный) .NET-дизассемблер,​ входящий в комплект поставки MS VS (в Mono ничего подобного не входит,​ ну или я не нашел):​ __C:​\Program Files\Microsoft SDKs\Windows\v6.0A\bin\ildasm.exe__;​
 +  - **Thottam R. Sriram blog**:
 +    - блог одного из ведущих разработчиков CLR, рассказывающий как пользоваться штатным ассемблером и дизассемблером для .NET сборок (на английском языке):​ __http://​blogs.msdn.com/​thottams/​archive/​2007/​02/​01/​using-ilasm-and-ildasm.aspx__;​
 +  - **IDA Pro**:​
 +    - основной хакерский дизассемблер,​ поддерживает .NET-сборки на весьма продвинутом уровне,​ хотя местами кое-где ошибается,​ не умеет дампить ресурсы и переваривает далеко не все нестандартные расширения. отладка .NET-программ так же не поддерживается,​ pdb-файлы не генерируются,​ и еще куча других недостатков,​ затрудняющих взлом и вынуждающих пользоваться ildasm/​ilasm:​ __http://​idapro.com__;​
 +  - **Decompiler.NET 2005 v2.0.0.230 by Jungle Creatures**:​
 +    - популярный коммерческий декомпилятор для .NET-программ,​ но по сравнению со штатным (и бесплатным!) ildasm'​ом он реально сосет, не говоря уже за IDA Pro: __http://​____www.junglecreatures.com__(официальное логово) www.wasm.ru/​baixado.php?​mode=tool&​id=366 (хакнутая версия);​
 +  - **Mdbg.exe**:​
 +    - штатный отладчик .NET-программ,​ входящий в комплект поставки MS VS и работающий на уровне байт-кода через стандартный ICorDebug-интерфейс,​ а потому требующий наличия символьной информации,​ в win32-mono мыщъх не нашел ничего подобного (может,​ плохо искал?​! как же мы без отладчика?​!):​ __C:​\Program Files\Microsoft SDKs\Windows\v6.0A\bin\Mdbg.exe__;​
 +  - **Dotnet IL Editor**:
 +    - бесплатный отладчик .NET-программ,​ работающий на уровне байт-кода через все тот же ICorDebug-интерфейс,​ требующий символьной информации. по уровню функциональности сопоставим с mdbg.exe, только если mdbg.exe — консоль,​ но subj уже имеет графическую оболочку,​ работать с которой чуть-чуть удобнее:​ __http://​sourceforge.net/​projects/​dile__;​
 +  - **Debugging IL**:
 +    - познавательная статья одного блоггера,​ разъясняющая все трудности отладки .NET-программ на уровне байт-кода и предлагающая некоторые "​обходные"​ решения для отладчики чужих программ без исходных текстов (на английском языке):​ __http://​blogs.msdn.com/​jmstall/​archive/​2004/​10/​03/​237137.aspx__;​
 +  - **ICorDebug Interface**:​
 +    - описание штатного интерфейса,​ встроенного в ядро платформы .NET, и предназначенного для отладки приложений на IL-уровне (на английском языке):​ __msdn2.microsoft.com/​en-us/​library/​ms230588.aspx__и __msdn2.microsoft.com/​en-us/​library/​ms404484.aspx__;​
 +  - **Code Protection**:​
 +    - бесплатный (но довольно мощный) протектор для .NET-программ от Microsoft, поддерживающий в том числе и среду mono (требует регистрации):​ __http://​www.microsoft.com/​SLPS/​Default.aspx__;​
 +  - **dotNet Protector**:​
 +    - монстроузный и навороченный .NET-протектор,​ ужасно тормозит и хочет денег: __http://​dotnetprotector.pvlog.com/​Downloads.aspx__;​
 +  - **how to unpack ****dotNet Protector****:​**
 +    - статья,​ посвященная распаковке dotNet Protector'​а (на английском языке):​ __http://​www.exetools.com/​forum/​showthread.php?​t=7968__;​
 +  - **YAP .Net**:
 +    - еще один протектор для .NET-программ,​ на этот раз бесплатный,​ но сильно сырой: __forum.vingrad.ru/​forum/​topic-186025.html__ и __sllh.net.ru/​download/​yapnet/​yapnet.php__;​
 +===== пишем свой первый crackme =====
 +
 +Глубоководное погружение в байт-код .NET-программ начинается! Пристегиваем ремни, проверяя все ли на месте и… запускаем Microsoft Visual Studio или… FAR + Colorer. Работать в IDE, конечно,​ удобнее (особенно начинающим,​ когда среда автоматически отображает список методов для каждого класса — и не надо постоянно лазить в справочники),​ однако,​ это порочный путь, абстрагирующий нас от машины и мы — хакеры старого поколения — предпочитаем консольные текстовые редакторы с подсветкой синтаксиса или… даже без таковой.
 +
 +Текст нашего первого crackme, написанного на C#, (который мы будем ломать всеми силами) в простейшем случае выглядит так (см. листинг 1). Это консольная программа,​ вручную набранная в текстовом редакторе. IDE пихает сюда много лишнего,​ затрудняющего понимание,​ однако,​ на скомпилированном коде это никак не отражается.
 +
 +using System;// использовать классы основной системной библиотеки
 +
 +class nezumi// имя класса - произвольно и может быть любым
 +
 +{
 +
 +static void Main()
 +
 +{
 +
 +string s;// объявляем переменную s типа строка
 +
 +
 +
 +// запрашиваем у пользователя пароль
 +
 +System.Console.Write("​enter password:"​);​
 +
 +s = System.Console.ReadLine();​
 +
 +
 +
 +if (s == "​nezumi"​)//​ сравниваем введенный пароль с эталонным
 +
 +System.Console.WriteLine("​hello,​ master!"​);​
 +
 +else
 +
 +System.Console.WriteLine("​fuck you, hacker!"​);​
 +
 +}
 +
 +}
 +
 +Листинг 1 исходный текст программы n2k_crackme_01h.cs
 +
 +В среде IDE сборка .NET-программ осуществляется клавишей <F6>, а из командой строки (при этом csc.exe должен находится в путях, чего не происходит при установке по умолчанию):​
 +
 +$csc.exe n2k_crackme_01h.cs
 +
 +Листинг 2 компиляция C#​-программы из командной строки
 +
 +В Mono вместо csc.exe используется файл mcs/​mcs.bat,​ но, независимо от способа сборки,​ мы получаем n2k_crackme_01h.exe,​ готовый к непосредственному запуску,​ после которого нас спросят пароль и, если мы введем его неверно — пошлют на хрен.
 +
 +===== >>>​ врезка .NET-программы на Си++ =====
 +
 +Компилятор Cи++, входящий в состав Microsoft Visual Studio 2008, умеет транслировать программы не только в машинный- но и в байт-код,​ позволяя нам использовать все прелести .NET платформы из привычных плюсов (трансляция "​чистых"​ Си программ в байт-код все еще не поддерживается).
 +
 +#include <​stdio.h>​
 +
 +#include <​string.h>​
 +
 +**using namespace System;​********//​ ****использовать классы основной системной библиотеки**
 +
 +void main()
 +
 +{
 +
 +char buf[0x666];
 +
 +printf("​enter password:"​);​gets(buf);​
 +
 +if (strcmp(buf,"​nezumi"​))
 +
 +printf("​fuck off, hacker!\n"​);​
 +
 +else
 +
 +printf("​hello,​ master!\n"​);​
 +
 +}
 +
 +Листинг 3 пример простейшей Cи++ программы,​ написанной с учетом специфики .NET
 +
 +Компиляция осуществляется путем указания ключа /CLR в командной строке компилятора CL.EXE (рядом с которым можно указать ключ /Ox для форсирования максимальной оптимизации):​
 +
 +$cl.exe /clr hello-clr.cpp
 +
 +Листинг 4 трансляция Си++ программы в .NET сборку из командной строки
 +
 +Полученный файл hello-clr.exe представляет собой смесь управляемого байт-кода с большим количеством вызовов неуправляемого машинного кода из различных библиотек (плюс, тянет за собой RTL, написанную на байт-коде),​ что позволяет сочетать достаточно высокую скорость выполнения с управляемостью и безопасностью,​ однако,​ "​чистые"​ C# сборки все-таки выигрывают как в размерах,​ так и в скорости. Чуть позже мы убедимся в этом самостоятельно,​ а пока же поверим мыщъх'​у на слово.
 +
 +===== первые эксперименты =====
 +
 +Загружаем подопытный n2k_crackme_01h.exe в HIEW, дважды давим на <​ENTER>​ для перевода редактора в дизассемблерный режим, жмем <F5> и попадаем в точку входа, где красуется команда **jmp _CorExeMain ;​ mscoree****.dll** (см. рис. 3). Это и есть _весь_ машинный код, который только есть (простите за каламбур).
 +
 +{{c_Image_2.png?​553}}
 +
 +Рисунок 3 так выглядит "​честная"​ .NET сборка в hex-редакторе
 +
 +Дальнейшее расследование показывает,​ что jmp находится в самом конце секции .text, за которой располагаются секции ресурсов и перемещаемых элементов,​ а выше — байт-код виртуальной машины,​ просматривая который в hex-mode, мы обнаружим все текстовые строки (и пароль в том числе!) записанные в формате Unicode, причем,​ перед строкой находится байт, определяющий длину строки. Узнав оригинальный пароль мы, конечно,​ без труда смогли бы "​взломать"​ crackme, однако,​ редкая программа хранит пароли открытым текстом,​ да и неинтересно это.
 +
 +Лучше загрузим в HIEW другой исполняемый файл, написанный на Си++ — hello-clr.exe. Он так же вызывает CorExeMain (см. рис. 4),​ но, в отличии от "​чистой"​ .NET сборки,​ написанной на C#, здесь присутствует большое количество "​переходников"​ к машинному коду — функциям strcmp, gets, printf, напрямую вызываемых из библиотеки MSVCR90.DLL,​ за что отвечает механизм P/Invoke, позволяющий создавать "​гибридные"​ программы,​ часть из которых транслируется "​живой"​ в машинный код, а часть — в интерпретируемый байт-код,​ что серьезно затрудняет взлом, однако,​ никакой P/Invoke нас не остановит! Но это будет потом, а сейчас мы покурим и загрузим .NET-сборку в нормальный дизассемблер.
 +
 +{{c_Image_3.png?​553}}
 +
 +Рисунок 4 внешний вид .NET-сборки,​ полученной путем трансляции Си++ программы
 +
 +===== техника дизассемблирование =====
 +
 +Загружаем n2k_crackme_01h.exe в IDA Pro и видим (см. рис. 5),​ что ничего ужасного в CIL-коде нет. Напоминает байт-код виртуальной Java-машины. IDA Pro не только создает перекрестные ссылки,​ но даже показывает опкоды и расставляет комментарии к командам,​ чтобы не было нужны каждый раз заглядывать в справочник (ECMA-335/​Partition III/​CIL Instruction Set).
 +
 +{{c_Image_4.png?​552}}
 +
 +Рисунок 5 консольная версия IDA Pro дизассемблирует .NET сборку
 +
 +Впрочем,​ чтобы заставить дизассемблер быть более дружелюбным к хакеру,​ необходимо выполнить следующие действия:​ в меню "​Options"​ выбрать пункт "Text representation",​ там указать количество байт для отображения опкода ("​Number of opcode bytes"​) — шести хватит вполне,​ а в разделе "Line prefixes"​сбросить все галочки,​ кроме "​Function offsets",​ после чего вновь возвратиться в меню "​Options",​ зайти в "​Comments"​и взвести "​Display auto comments"​для автоматического отображения комментариев ко всем инструкциям (впрочем,​ при наличии некоторого опыта работы с CIL-кодом это можно и не делать).
 +
 +Поклонники графической версии IDA Pro могут задействовать графы (см. рис. 6),​ упрощающие (на самом деле — усложняющие) понимание структуры программы,​ но тут уж как говориться,​ на вкус и цвет все фломастеры разные. Лично мыщъх никогда не пользовался графами и другим не советует.
 +
 +{{c_Image_5.png?​552}}
 +
 +Рисунок 6 графическая версия IDA Pro дизассемблирует .NET сборку
 +
 +А теперь посмотрим на что способен штатный дизассемблер от Microsoft, по умолчанию расположенный в каталоге C:​\WINDOWS\Microsoft.NET\Framework\v2.0.50727\ изовущийся ilasm.exe. Загружаем в него n2k_crackme_01h.exe и… хм, в общем-то довольно неплохая картина получилась (см. рис. 7),​ а навигация по классам выполнена даже лучше, чем в IDA Pro, причем _намного_ лучше (//​**примечание**////:​ чтобы ////​ildasm.exe ////​отображал опкоды инструкций,​ необходимо в меню ////View ////​взвести галочку ////"​Show bytes"//​)
 +
 +{{c_Image_6.png?​553}}
 +
 +Рисунок 7 штатный дизассемблер ildasm.exe за работой
 +
 +Теперь самое время исследовать дизассемблерный текст нашей программы (см листинг 5). Ну, тут все ясно без травы и даже без комментариев (особенно тем, кто знаком с виртуальными машинами со стековой организацией). Если опустить детали,​ то получается следующее:​ программа вызывает System.Console::​Write("​enter password"​),​ после чего считывает строку в переменную V_0 и вызывает функцию System.String::​Equality(V_0,​ "​nezumi"​) для провеки строк на соответствие и в случае их несовпадения на экран выводится строка "fuck off, hacker!",​ управление на которую передается машинной командой brtrue.s IL_0031 (с опкодом 2Dh 0Dh).
 +
 +.method private hidebysig static void Main(string[] args) cil managed
 +
 +// SIG: 00 01 01 1D 0E
 +
 +{
 +
 +.entrypoint
 +
 +// Method begins atRVA 0x2050
 +
 +// Code size61 (0x3d)
 +
 +.maxstack ​ 2
 +
 +.locals init (string V_0, bool V_1)
 +
 +IL_00: /* 00  |  */ nop
 +
 +IL_01: /* 72  | (70)000001 */ ldstr  "enter password:"​
 +
 +IL_06: /* 28  | (0A)000003 */ call  void [mscorlib]System.Console::​Write(string)
 +
 +IL_0b: /* 00  |  */ nop
 +
 +IL_0c: /* 28  | (0A)000004 */ call  string [mscorlib]System.Console::​ReadLine()
 +
 +IL_11: /* 0A  |  */ stloc.0
 +
 +IL_12: /* 06  |  */ ldloc.0
 +
 +IL_13: /* 72  | (70)000021 */ ldstr  "​nezumi"​
 +
 +IL_18: /* 28  | (0A)000005 */ call bool [mscorlib]System.String::​Equality(str,​str)
 +
 +IL_1d: /* 16  |  */ ldc.i4.0
 +
 +IL_1e: /* FE01|  */ ceq
 +
 +IL_20: /* 0B  |  */ stloc.1
 +
 +IL_21: /* 07  |  */ ldloc.1
 +
 +IL_22: /* 2D  | 0D  */ brtrue.s IL_0031
 +
 +IL_24: /* 72  | (70)00002F */ ldstr  "​hello,​ master!"​
 +
 +IL_29: /* 28  | (0A)000006 */ call  [mscorlib]System.Console::​WriteLine(str)
 +
 +IL_2e: /* 00  |  */ nop
 +
 +IL_2f: /* 2B  | 0B  */ br.s  IL_003c
 +
 +IL_31: /* 72  | (70)00004D */ ldstr  "fuck you, hacker!"​
 +
 +IL_36: /* 28  | (0A)000006 */ call  [mscorlib]System.Console::​WriteLine(str)
 +
 +IL_3b: /* 00  |  */ nop
 +
 +IL_3c: /* 2A  |  */ ret
 +
 +} // end of method nezumi::​Main
 +
 +Листинг 5 результат работы штатного дизассемблера ildasm.exe
 +
 +Логично,​ чтобы заставить программу воспринимать _все_ пароли как правильные,​ двухбайтовый условный переход brtrue.s IL_0031 необходимо заменить на пару однобайтовых команд nop (опкод — 00h, а вовсе не 90h как на x86). Или же… заменить brtrue.s IL_0031 на br**FALSE**.s IL_0031,​ тогда любой неправильный пароль будет восприниматься как правильный и, соответственно,​ наоборот. Открыв ECMA-335, мы узнаем,​ что инструкция brfalse.s имеет опкод 2Ch — и это все, что нам необходимо знать для взлома программы.
 +
 +===== >>>​ врезка дизассемблирование Cи++ сборки =====
 +
 +А теперь загрузим в ildasm.exe бинарную сборку,​ выданную Си++ компилятором с ключом /CLR,и посмотрим,​ чем она отличается от "​нормальной"​ .NET-сборки. Если забыть о том, что Си++ сборка тащит за собой весьма тяжеловесный RTL (в котором для нас нет ровным счетом ничего интересного) и сосредоточиться исключительно на функции main, то, можно обнаружить,​ что все не так уж и страшно (см. листинг 6).
 +
 +Длинные имена методов класса (сокращенные для экономии бумаги),​ конечно,​ на первых порах вызывают шевеление волос на голове,​ но потом к ним быстро привыкаешь,​ автоматически "​вычленяя"​ привычные "​позывные"​ типа printf, gets, etc, однако,​ структура кода далека от совершенства и на его анализ уходит намного больше времени,​ что, кстати говоря,​ представляет собой не такой уж "​тупой"​ защитный прием от начинающих хакеров. Просто компилируем свои Си++ программы с ключом /CLR и хрен кто их взломает.
 +
 +.method assembly static int32modopt([mscorlib]System.Runtime.CompilerServices.CallConvCdecl)
 +
 +main() cil managed
 +
 +{
 +
 +.vtentry 1 :1
 +
 +// Code size59 (0x3b)
 +
 +.maxstack2
 +
 +.locals (valuetype '<​CppImplementationDetails>'​.$ArrayType$$$BY0GGG@D V_0)
 +
 +IL_00: ldsflda ​ $ArrayType$
 +
 +IL_05: call  modopt([mscorlib]System.Runtime.CompilerServices.CallConvCdecl)printf(*)
 +
 +IL_0a: pop
 +
 +IL_0b: ldloca.s ​ V_0
 +
 +IL_0d: call  int8 gets(*)
 +
 +IL_12: pop
 +
 +IL_13: ldloca.s ​ V_0
 +
 +IL_15: ldsflda ​  ​$ArrayType$$
 +
 +IL_1a: call  modopt([mscorlib]System.Runtime.CompilerServices.CallConvCdecl) strcmp(,)
 +
 +IL_1f: brfalse.s ​ IL_002e
 +
 +IL_21: ldsflda ​ $ArrayType$
 +
 +IL_26: call  modopt([mscorlib]System.Runtime.CompilerServices.CallConvCdecl)printf(*)
 +
 +IL_2b: pop
 +
 +IL_2c: br.s  IL_0039
 +
 +IL_2e: ldsflda ​ $ArrayType$
 +
 +IL_33: call  modopt([mscorlib]System.Runtime.CompilerServices.CallConvCdecl)printf(*)
 +
 +IL_38: pop
 +
 +IL_39: ldc.i4.0
 +
 +IL_3a: ret
 +
 +} // end of method '​Global Functions'::​main
 +
 +Листинг 6 дизассемблирование .NET-сборки,​ полученной путем трансляции Си++ программы
 +
 +===== техника патча =====
 +
 +Так, где там наш HIEW?! Готов ко взлому или… еще не готов? Как нам определить местоположение байта, который мы собрались захачить?​ Ведь виртуальные адреса в контексте CIL-кода вообще неуместны!
 +
 +Воспользуемся дедовским способом и поищем последовательность байт (сигнатуру),​ обитающую в окрестностях целевой команды. В данном случае это может быть 2Dh 0Dh 72h 2F 00h 00h 70h 28h (об обратном порядке байт не забываем,​ да? ildasm автоматически "​нормализует"​ аргументы команд,​ IDA Pro —нет,​ показывая их такими,​ какие они есть — наименее значимый байт располагается по младшему адресу).
 +
 +Короче,​ вбиваем заданную последовательность в поиск и, убедившись,​ в том, что данное вхождение — единственное,​ переводим HIEW в режим записи по <F3>, заменяем 2Dh на 2Ch (см. рис. 8),​ сохраняем изменения в файле по <F9> и выходим.
 +
 +{{c_Image_7.png?​553}}
 +
 +Рисунок 8 поиск сигнатуры в HIEW'​е и bit-hack (исправление "​неправильного"​ байта на "​правильный"​)
 +
 +Запускаем хакнутый файл и… о чудо!!! Он работает!!! Теперь любой, наугад взятый пароль,​ например,​ "​123456"​ воспринимается как правильный (см. рис. 9). Конечно,​ если программа снабжена цифровым сертификатом подлинности или использует механизм контроля целостности собственного кода, этот номер уже не пройдет,​ но… ведь надо же с чего-то начинать ломать!
 +
 +{{c_Image_8.png?​399}}
 +
 +Рисунок 9 хакнутая программа любой пароль воспринимает как правильный
 +
 +===== техника отладки =====
 +
 +Спору нет — дизассемблер — весьма популярный инструмент для исследования программ. Популярный,​ но не единственный и во многих случаях отладчик оказывается намного более предпочтительным. Вместо того, чтобы гадать какое значение имеет переменная в данной точке (в дизассемблере),​ гораздо практичнее заглянуть в нее отладчиком.
 +
 +И вот тут выясняется довольно любопытная вещь. На уровне исходных текстов,​ Microsoft Visual Studio справляется с отладкой на ура, но готовые бинарные сборки,​ увы, _не_ поддерживает и для работы с ними необходимо использовать ICorDebug-интерфейс,​ встроенный в ядро платформы .NET и реализующий базовые отладочные возможности (установка точек останова,​ пошаговое исполнение и т. д.), предоставляя их в виде набора API-функций. Все .NET-отладчики,​ которые только видел мыщъх, являются достаточно тонкими обертками вокруг ICorDebug Interface, наследуя его худшие черты, а именно —невозможность отлаживать программы без символьной (отладочной) информации,​ автоматически удаляемой из всех Release-проектов. Выходит,​ что мы можем отлаживать только свои собственные программы?​! Нехорошо!!!
 +
 +Расследование показало,​ что штатному .NET отладчику (зовущемуся mdbg.exe, где "​m"​ – сокращение от managed, т. е. управляемый код) для нормальной работы вполне достаточно pdb-файла,​ вот только как этот файл получить?​ IDA Pro может подготовить map-файл,​ но готовых конверторов map2pdb в Сети что-то не наблюдается,​ а писать самому — лениво и непродуктивно.
 +
 +К счастью,​ существует весьма простой и элегантный путь. Дизассемблируем бинарную сборку штатной утилитой ildasm.exe, после чего ассемблируем ее заново штатным же транслятором ilasm.exe, не забыв указать "​волшебный"​ ключик /pdb для генерации отладочной информации. Поскольку,​ ildasm.exe поддерживает ресурсы и корректно их дампит,​ то предложенный способ работает в подавляющем большинстве случав,​ что мы сейчас и продемонстрируем.
 +
 +Запускаем ildasm.exe с настройками по умолчанию,​ загружаем в него n2k_crackme_01h.exe (ес-но, оригинальный,​ а не хакнутый),​ в меню File находим пункт Dump (или нажимаем <​CTRL-D>​),​ в появившемся окне "Dump options"​ (см. рис. 10) оставляем все галочки в состоянии по умолчанию. Главное,​ чтобы была взведена галочка "​Dump IL Code",​ после чего нажимаем <OK> и вводим имя файла для дампа, например,​ "​cracked"​
 +
 +{{c_Image_9.png?​399}}
 +
 +Рисунок 10 дамп двоичной .NET-сборки в ассемблерный файл штатным дизассемблером ildasm.exe
 +
 +По окончании дизассемблирования на диске образуются два файла — cracked.il с ассемблерным текстом программы и cracked.res – с ресурсами. Cracked.il представляет собой обыкновенный текстовой файл, который можно править в любом текстовом редакторе,​ при необходимости заменяя "​brtrue.s IL_0031"​на "​brfalse.s IL_0031",​ но сейчас нас в первую очередь интересует не патч, а отладка.
 +
 +Берем штатный ассемблер и собираем файл следующим образом:​
 +
 +$ilasm.exe cracked.il /pdb
 +
 +Листинг 7 ассемблирование сдампленного файла штатным ассемблером
 +
 +На диске образуются файлы cracked.exe и cracked.pdb,​ готовые к загрузке в отладчик (что примечательно — отладочная информация непосредственно в сам исполняемый файл _не_ записывается,​ что очень и очень хорошо,​ иначе нам пришлось бы потом оттирать ее оттуда или мириться с увеличением размера поломанного exe, что вряд ли входит в наши планы).
 +
 +ОК, набираем в командной строке "​$mdbg.exe cracked.exe"​ и… оказывается в консольном окне отладчика,​ автоматически останавливающегося на первой команде функции Main, передавая нам бразды правления. А что такого крутого и хорошего мы можем сделать?​!
 +
 +Начнем с просмотра окрестной,​ за что отвечает команда "​show"​ или ее более короткий алиас "​sh",​ результат работы которого выглядит так (см. листинг 8):​
 +
 +run cracked.exe#​ запущена бинарная сборка cracked.exe
 +
 +STOP: Breakpoint Hit# точка останова в функции main
 +
 +**43: IL_0000:​nop#​ ****следующая выполняемая команда**
 +
 +[p#:0, t#:0] mdbg> sh# просим отладчик показать окрестности кода по "​sh"​
 +
 +40.maxstack ​ 2
 +
 +41.locals init (string V_0, bool V_1)
 +
 +**43:​*IL_0000:​nop#​ ****команда выполняемая следующей**
 +
 +44IL_0001:​ldstr"​enter password:"​
 +
 +45IL_0006:​call[mscorlib]System.Console::​Write(string)
 +
 +[p#:0, t#:0] mdbg>
 +
 +Листинг 8 результат работы команды "​sh"​ показывающей IL-код
 +
 +Остальные команды отладчика можно найти во встроенной справке (вызываемой командой help) или же в одноименной врезке. Сейчас нас интересует не это. На интересует _техника_ работы с отладчиком. Ну техника,​ как техника. Никаких принципиальных отличий от x86 не появилось.
 +
 +Просматривая ассемблерный файл cracked.il,​находим команду "​IL_0020:​ stloc.1",​ стягивающую со стека результат сравнения двух строк, возвращенный функцией System.String::​op_Equality,​ за которой следует команда "​IL_0021:​ ldloc.1",​ загружающая полученное значение в локальную переменную V_1, в зависимости от содержимого которой команда "​IL_0022:​  brtrue.s IL_0031"​прыгает на метку IL_0031 (неверный пароль) или… не прыгает. Все ясно! Нам нужно установить точку останова на команде "​IL_0020:​ stloc.1",​ расположенной в 55'​ой строке файла cracked.il, ну а дальше мы уже сориентируется (см. листинг 9).
 +
 +$D:​\KPNC\C#>​mdbg cracked.exe#​ грузим бинарную сборку в отладчик
 +
 +//MDbg (Managed debugger) v3.5.21022.8 (RTM.021022-0800) started.//
 +
 +//Copyright (C) Microsoft Corporation. All rights reserved.//
 +
 +run cracked.exe#​ отладчик запускает бинарную сборку
 +
 +STOP: Breakpoint Hit# отладчик останавливается на main
 +
 +43: IL_0000: nop# окрестности функции main
 +
 +[p#:0, t#:0] mdbg>** b 55# ****брякаемся на строку 55**
 +
 +Breakpoint #1 bound (line 55 in cracked.il)#​ отладчик говорит,​ что с бряком все ОК
 +
 +[p#:0, t#:0] mdbg> **g********#​ ****продолжаем выполнение программы**
 +
 +enter password:​**password********#​ ****вводим в качестве пароля ****"​password"​**
 +
 +STOP: Breakpoint 1 Hit# !!! срабатывает наша точка останова
 +
 +55:IL_0020: stloc.1# мы брякнулись на команде stloc.1
 +
 +[p#:0, t#:0] mdbg> **p********#​ ****просим отладчик распечатать переменные**
 +
 +V_0="​password"#​ V_0 хранит введенный пароль
 +
 +V_1=False# V_1 содержит значение False
 +
 +args=array [0]# аргументы программы нам не интересны
 +
 +[p#:0, t#:0] mdbg> **n********#​ ****выполняем следующую команду**
 +
 +56: IL_0021: ldloc.1# следующая команда загружаем V_1
 +
 +[p#:0, t#:0] mdbg> **p# ****печатаем содержимое переменных еще раз**
 +
 +V_0="​password"#​ V_0 не изменилась
 +
 +V_1=True# V_1 _ИЗМЕНИЛАСЬ_ (вот где собака!!!)
 +
 +args=array [0]# -/-
 +
 +[p#:0, t#:0] mdbg>** set V_1=0# ****просим отладчик записать в ****V_1**** число 0**
 +
 +V_1=False# теперь V_1 вновь содержит False
 +
 +[p#:0, t#:0] mdbg> **n# ****выполняем следующую команду**
 +
 +57:IL_0022: brtrue.s IL_0031# а следующей команда у нас - ветвление!
 +
 +[p#:0, t#:0] mdbg> **n********#​ ****ну и куда это ветвление нас заведт?​!**
 +
 +59: IL_0024: ldstr "​hello,​ master!"#​ после изменения V_1 мы на верном пути!
 +
 +[p#:0, t#:0] mdbg> **g********#​ ****продолжаем выполнение программы**
 +
 +//hello, master!////////#​ ////​программа пишет ////"​hello,​ master!"//​
 +
 +STOP: Process Exited# процесс завершается
 +
 +mdbg> **q********#​ ****выходим из отладчика**
 +
 +Листинг 9 сеанс работы с отладчиком mdbg.exe (команды,​ вводимые хакером,​ выделены полужирным шрифтом)
 +
 +Ниже, для наглядности тот же самый сеанс работы с отладчиком продемонстрирован в графическом виде (см. рис. 11):​
 +
 +{{c_Image_10.png?​553}}
 +
 +Рисунок 11 сеанс работы с отладчиком mdbg.exe "​как он есть"​
 +
 +Если кому-то религия запрещает использовать консоль,​ что ж — к его услугам Dotnet IL Editor – бесплатный IL-отладчик с GUI-интерфейсом (см. рис. 12),​ однако,​ mdbg.exe мыщъх'​у как-то больше по душе, да к тому же под него расширения всякие можно писать.
 +
 +{{c_Image_11.png?​552}}
 +
 +Рисунок 12 Dotnet IL Editor – IL-отладчик с GUI-интерфейсом
 +
 +Впрочем,​ выбор отладчика непринципиален. Важна сама суть — техника исследования .NET-программ,​ которую мы только что и продемонстрировали.
 +
 +===== заключение =====
 +
 +Разумеется,​ в рамках одной-единственной статьи просто невозможно охватить все аспекты взлома .NET-программ. В частности,​ совершенно нетронутой осталась тема упаковщиков бинарных сборок и протекторов,​ распаковывать которые приходится руками,​ но это по любому тема отдельного большого разговора.
 +
 +А пока же имеет смысл потренироваться на простых несильно защищенных коммерческих программах (которые можно найти в Сети), малвари (взятой оттуда же) и crackme, залежи которых находятся на сайте www.crackmes.de (см. рис. 13) и где даже есть специальный раздел,​ посвященный исключительно платформе .NET.
 +
 +Мыщъх надеется,​ что данная статья обеспечит хороший старт, ну а остальное — дело времени,​ техники и бесчисленных экспериментов!
 +
 +{{c_Image_12.png?​553}}
 +
 +Рисунок 13 коллекция .NET crackmes на одноименном сайте
 +
 +===== >>>​ врезка основные команды отладчика mdbg.exe =====
 +
 +  - **?, help:**
 +    - вывод встроенной справки,​ "help команда"​ — подробная справка по команде;​
 +  - **a[ttach]:​**
 +    - подключение к активному .NET-процессу;​
 +  - **b[reak]****:​**
 +    - установка точки останова или отображение уже существующих;​
 +  - **ca[tch]****:​**
 +    - просмотр событий (evens), вызывающих останов отладчика;​
 +  - **conf[ig]****:​**
 +    - просмотр опций отладки/​конфигурирования отладчика;​
 +  - **del[ete]****:​**
 +    - удаление точки останова;​
 +  - **de[tach]****:​**
 +    - отключение от отлаживаемого .NET-процесса;​
 +  - **g[o]****:​**
 +    - продолжение работы программы;​
 +  - **n[ext]****:​**
 +    - Step Over;
 +  - **o[ut]****:​**
 +    - Steps Out;
 +  - **s[tep]****:​**
 +    - Step Into;
 +  - **p[rint]****:​**
 +    - вывод содержимого локальных переменных;​
 +  - **q[uit]****:​**
 +    - выход из программы;​
 +  - **r[un]****:​**
 +    - запуск программы под отладчиком;​
 +  - **set****:​**
 +    - изменение значение переменных;​
 +  - **setip:**
 +    - установка текущей выполняемой команды;​
 +  - **sh[ow]:**
 +    - показ окрестностей выполняемого кода;
 +===== >>>​ врезка терминологическое болото =====
 +
 +  - **.NET****:​**
 +    - древняя как мир идея 2х стадийной компиляции:​ сначала программа (написанная хоть на Java, хоть на Visual Basic, хоть на Cи++, хоть на C#, хоть на F#) транслируется в промежуточный байт-код,​ который окончательно транслируется в "​родно"​ двоичный код на конкретной целевой машине или же исполняется в режиме интерпретации;​
 +  - **CLR:**
 +    - Common Language Runtime ("​общая среда выполнения языков"​) – компонент Microsoft .NET Framework, включающий себя виртуальную машину и необходимые библиотеки;​
 +  - **CIL:**
 +    - Common Language Infrastructure ("​спецификация общеязыковой инфраструктуры"​),​ определяющая архитектуру исполнительной системы,​ базовые классы,​ синтаксис и мнемонику байт-кода;​
 +  - **MSIL:**
 +    - Microsoft Intermediate Language ("​промежуточный язык от Microsoft"​) —байт-код виртуальной .NET машины в реализации от Microsoft;
 +  - **IL:**
 +    - Intermediate Language ("​промежуточный язык"​) — байт-код,​ виртуальной .NET машины,​ стандартизованный в рамках ECMA-335;
 +