Как сделать листинг программы c

Обновлено: 06.07.2024

Публикации на околокомпьютерную тематику нередко сопровождаются фрагментами программ, макросами и прочими листингами, содержащими текст на каком-нибудь языке программирования. Так уж сложилось, что для оформления листингов программ используется моноширинный шрифт, то есть шрифт, каждый символ которого имеет одинаковую ширину. В операционной системе Windows включен моноширинный шрифт Courier New Cyr, но вы можете применять и другие.

Для оформления листинга ничто не мешает в текстовом документе выделить часть текста, а затем изменить шрифт. Этому и будет посвящена новая статья цикла, посвященная макросам Microsoft Office. Заметим, что процедура оформления программ может быть решена тремя способами: с помощью соответствующих настроек панелей инструментов или создания макроса. Первый способ достаточно прост, однако не обеспечивает должной функциональности, два другие способа оформления документа подразумевают использование макросов на Visual Basic for Application.

Запись макроса для форматирования текста
Существуют и другие способы форматирования фрагмента текста как листинга программы. Они подразумевают применение макросов. Word, равно как и другие приложения Microsoft Office, позволяют запоминать любые команды меню и панелей инструментов в виде макроса. По своей сути, созданный макрос мало отличается от кнопки панели инструментов, но, быть может, он покажется вам более удобным.
1. Выберите в меню команду Сервис — Макрос — Начать Запись.
2. В появившемся окне задайте имя макроса, а также способ его последующего вызова. Word позволяет связать макрос с панелью инструментов или с функциональными клавишами.
3. В режиме записи вам следует указать шрифт Courier New, а затем щелкнуть по кнопке Остановить запись.
4. Никаких внешних изменений с программой Word не произойдет, но если вы нажмете клавиши Alt-F11, а затем раскроете созданный вами макрос, то на экране появится программа на Visual Basic for Application.
5. Дальнейшие шаги по форматированию документа вам уже известны: вы выделяете фрагмент текста и щелкаете по кнопке панели инструментов или нажимаете горячую клавишу, шрифт текста автоматически изменяется.


Рис. 2. В режиме записи макроса вы можете указать название макроса, клавишу или кнопку панели инструментов, которая исполняет макрос, а также при необходимости задать описание макроса. Непосредственно во время записи Word запоминает все используемые вами команды и преобразует их в соответствующие операторы языка Visual Basic for Application.

Что будет содержать программа
Следует заметить, что генерируемый Word макрос напрямую зависит от ваших действий. Если вы в режим записи макроса установите шрифт Courier New посредством панели инструментов, то в макросе появится программа, состоящая всего из двух строчек (см. рис. 3).
Но если вы воспользуетесь командой меню Формат — Шрифт и укажите в диалоговом окне шрифт Courier New, размер шрифта 10, а также какие-то дополнительные опции, то Word запомнит все измененные параметры шрифта и запишет их в виде макроса, представленного на рис. 4.


Рис. 4. В том случае, если вы, создавая макрос, использовали диалоговое окно для форматирования шрифта, Word запомнит все измененные параметры и добавит их в программу.

Как ввести текст программы
Поскольку задача была решена двумя способами, программа получилась довольно большой. Вы можете попробовать применять и тот, и другой способ, но впоследствии отказаться от одного варианта в пользу другого. В этом случае размеры программы сократятся вдвое.
При вводе используйте стандартную последовательность, то есть сначала создайте в шаблоне Normal.DOT новый модуль, а затем в нем определяйте процедуры. При добавлении макроса к шаблону Normal.dot, вы делаете его доступным в любых документах. Если это не желательно, создайте обычный документ, введите в него соответствующие процедуры, а затем сохраните его как шаблон. При желании вы также можете определить новую панель инструментов и связать ее с соответствующими процедурами модуля.

Другие применения макросов
Идеи, заложенные в макросе, не обязательно использовать только для форматирования листингов программ. Предложенные алгоритмы прекрасно подойдут и для выделения дат в тексте по истории чего-либо или для выделения названий компаний и фирм, их сотрудников в отчете по итогам работы за квартал, финансовый год и так далее. Словом, предложенные программы позволяют выделять любые фрагменты текста нужным вам способом — главное, составить список слов и определить способы их форматирования.
Тексты макросов приводятся в листинге
— Модуль в документе Doc1 предназначен для форматирования текста программ, подготавливаемых для книг, журнальных статей, рефератов или каких-то иных целей.
— При этом в тексте выполняются следующие преобразования: устанавливается гарнитура Courier New и все ключевые слова форматируются полужирным начертанием.
— Программа чрезвычайно проста и имеет одно проблему: если в комментариях или в строковых выражениях используются зарезервированные слова, они тоже выделяются полужирным.
— Более детальный анализ текста программ средствами Visual Basic for Application затруднен из-за невысокой производительности работы.
— WordInKeyWords — функция возвращает True, если указанное слово содержится в массиве KeyWords.
— ConvertingMethod1 — преобразование в тексте путем перебора каждого слова.
— JavaModuleMethod1 — подготовка для преобразования программ на Java.
— DelphiModuleMethod1 — подготовка для преобразования программ на Delphi.
— ConvertingMethod2 — преобразование в тексте при помощи объектов Find, Replacement.
— JavaModuleMethod2 — подготовка для преобразования программ на Java.
— DelphiModuleMethod2— подготовка для преобразования программ на Delphi.

Function WordInKeyWords(aWord As String) As Boolean
WordInKeyWords = False

For I = LBound(KeyWords) To UBound(KeyWords)
If LCase(Trim(KeyWords(I))) = LCase(Trim(aWord)) Then WordInKeyWords = True: Exit Function
Next
End Function

Sub ConvertingMethod1()
— процедура выполняет преобразование указанных в массиве KeyWords слов.
— При этом последовательно перебираются слова текста — такой способ очень долог.
On Error Resume Next ' необязательная строка, поскольку в процедуре отсутствуют инструкции, которые могут привести к ошибкам.
Dim MyRange As Range
Set MyRange = Selection.Range
MyRange.Font.Name = "Courier New"
MyRange.Font.Size = 8
For I = 1 To MyRange.Words.Count
If WordInKeyWords(MyRange.Words(I)) Then
MyRange.Words(I).Bold = True
End If
Next I
End Sub

Sub JavaModuleMethod1()
' подготавливает массив KeyWords для программ на Java и вызывает процедуру ConvertingVeryOld
KeyWords = Array("abstract", "boolean", "break", "byte", "byvalue", "case", "catch", "char", "class", "const", "continue", "default", "do", "double", "else", "extends", "false", "final", "finally", "float", "for", "goto", "if", "implements", "import", "instanceof", "int", "interface", "long", "native", "new", "null", "package", "private", "protected", "public", "return", "short", "static", "super", "switch", "synchrinized", "this", "threadsafe", "throw", "throws", "transient", "true", "try", "void", "while")
Application.ScreenUpdating = False
ConvertingMethod1
Application.ScreenUpdating = True
Application.ScreenRefresh
End Sub

Sub DelphiModuleMethod1()
' подготавливает массив KeyWords для программ на Java и вызывает процедуру ConvertingVeryOld
KeyWords = Array("and", "array", "as", "asm", "begin", "case", "class", "const", "constructor", "destructor", "dispinterface", "div", "do", "downto", "else", "end", "except", "exports", "file", "finalization", "finally", "for", "function", "goto", "if", "implementation", "in", "inherited", "initialization", "inline", "interface", "is", "Label", "library", "Mod", "nil", "not", "object", "of", "or", "out", "packed", "procedure", "program", "property", "raise", "record", "repeat", "resourcestring", "set", "shl", "shr", "string", "then", "threadvar", "to", "try", "type", "unit", "until", "uses", "var", "while", "with", "xor")
Application.ScreenUpdating = False
ConvertingMethod1
Application.ScreenUpdating = True
Application.ScreenRefresh
End Sub

Sub ConvertingMethod2()
— процедура выполняет преобразование указанных в массиве KeyWords слов.
— При этом используются объекты Find, Replacement для контекстной замены, поскольку это наиболее быстрый способ для обработки текста
On Error Resume Next ' необязательная строка, поскольку в процедуре отсутствуют инструкции, которые могут привести к ошибкам
Dim MyRange As Range
Set MyRange = Selection.Range
MyRange.Font.Name = "Courier New"
MyRange.Font.Size = 8
For I = LBound(KeyWords) To UBound(KeyWords)
MyRange.Find.Text = KeyWords(I)
MyRange.Find.Replacement.Text = KeyWords(I)
MyRange.Find.Replacement.Font.Bold = True
MyRange.Find.Execute Replace:=wdReplaceAll, Format:=True, MatchWholeWord:=True
Next I
End Sub

Sub JavaModuleMethod2()
' подготавливает массив KeyWords для программ на Java и вызывает процедуру Converting
KeyWords = Array("abstract", "boolean", "break", "byte", "byvalue", "case", "catch", "char", "class", "const", "continue", "default", "do", "double", "else", "extends", "false", "final", "finally", "float", "for", "goto", "if", "implements", "import", "instanceof", "int", "interface", "long", "native", "new", "null", "package", "private", "protected", "public", "return", "short", "static", "super", "switch", "synchrinized", "this", "threadsafe", "throw", "throws", "transient", "true", "try", "void", "while")
Application.ScreenUpdating = False
ConvertingMethod2
Application.ScreenUpdating = True
Application.ScreenRefresh
End Sub

Sub DelphiModuleMethod2()
' подготавливает массив KeyWords для программ на Delphi и вызывает процедуру Converting
KeyWords = Array("and", "array", "as", "asm", "begin", "case", "class", "const", "constructor", "destructor", "dispinterface", "div", "do", "downto", "else", "end", "except", "exports", "file", "finalization", "finally", "for", "function", "goto", "if", "implementation", "in", "inherited", "initialization", "inline", "interface", "is", "Label", "library", "Mod", "nil", "not", "object", "of", "or", "out", "packed", "procedure", "program", "property", "raise", "record", "repeat", "resourcestring", "set", "shl", "shr", "string", "then", "threadvar", "to", "try", "type", "unit", "until", "uses", "var", "while", "with", "xor")
Application.ScreenUpdating = False
ConvertingMethod2
Application.ScreenUpdating = True
Application.ScreenRefresh
End Sub

Сергей Лосев

Компьютерная газета. Статья была опубликована в номере 47 за 1999 год в рубрике программирование :: разное

MAKEFILE И КОМПИЛЯЦИЯ ПРОГРАММЫ

Сначала создадим на диске папку, где будут находиться файлы вашего проекта.

Запустим редактор программиста Programmers Notepad [WinAVR]. В меню редактора выберем File -> New -> C/C++ и напишем программу на языке Си.


Сохраним листинг программы в предварительно созданной нами папке в файле с именем "my_test.c" (каждый проект лучше сохранять в отдельной папке). Имя файла может быть любым без пробелов и иметь расширение ".c" .

В WinAVR исходный текст программы компилируется при помощи утилиты make.exe, которая находится в папке WinAVR\utils\bin. Make.exe контролирует генерацию исполняемых файлов из исходного кода программы. Для управления работой этой утилиты используют make-файлы. Make-файл сообщает компилятору, какие команды запускать, какие файлы компилировать и линковать, какой выходной код генерировать и т. д.

После установки WinAVR в папке WinAVR\sample можно найти шаблон с именем Makefile, который нужно скопировать в папку с проектом и уже там редактировать.

Внимание: Makefile и компилируемый файл (в нашем случае my_test.c ) должны находиться в одной папке.

Откроем Makefile в редакторе Programmers Notepad и отредактируем несколько важных для компилятора инструкций.

Во-первых, обязательно нужно указать, для какого типа микроконтроллера мы хотим получить выходной код. Найдем следующие строки:

Первая строка - комментарий, а во второй вместо atmega128 пишем тот микроконтроллер, который нас интересует (например, atmega8, attiny2313, attiny26).

Частота тактирования микроконтроллера в герцах определяется в строках:

Вместо 8000000 напишем 1000000, что будет составлять 1 мегагерц (1 МГц).
Должно получиться так:

Имя проекта, а соответственно и имя исходного файла с функцией main и выходные файлы с расширениями hex и cof, определяется в следующих строках:

Здесь вместо testpp пишем нужное имя проекта (в нашем случае my_test ).

После знака "равно" пишем $(TARGET).c, чтобы получилось

Стираем запись после знака "равно". Должно получиться:

В разделе Optimization level проверяем уровень оптимизации. Можно оставить все как есть (s - оптимизирует выходной файл по размеру).

После этого, немного ниже, ищем раздел:

В дальнейшем в статьях раздела "Шаг за шагом" мы будем опираться на вариант программатора USBASP.

Программатор USBASP использует USB-порт.

Вы можете использовать более удобный шаблон Makefile, в котором часто изменяемые опции вынесены в начало файла. В простейшем случае для использования этого Makefile'а достаточно скопировать его в папку с проектом и изменить, если потребуется, строки в разделе "ОСНОВНЫЕ ИНСТРУКЦИИ".

Кроме того, в состав пакета WinAVR входит утилита MFile , которая помогает правильно составить или отредактировать Makefile. Запустить утилиту можно через меню "Пуск -> Программы -> WinAVR -> MFile [WinAVR]"

Откройте в редакторе Programmers Notepad исходный текст программы my_test.c, в меню выберете Tools -> [WinAVR] Make All. Команда Make All выполняет компиляцию исходного кода программы и в случае отсутствия ошибок генерирует файл, который можно прошивать в микроконтроллер AVR.

А в папке вашего проекта должны появиться следующие файлы:

Самым главным из этих файлов для нас будет файл my_test.hex. В нем хранится шестнадцатиричный код для загрузки в память программ (Flash ROM) микроконтроллера.

В файле my_test.eep хранится шестнадцатиричный код для загрузки в энергонезависимую память данных (EEPROM).

Следует помнить, что после каждого изменения кода программа должна быть перекомпилирована, т.е. в редакторе Programmers Notepad выполнено Tools -> [WinAVR] Make All.

Файл листинга — это очень полезная вещь. Он позволяет увидеть работу компилятора FASM как на ладони: что генерирует каждая строка исходного кода, сколько байт занимают машинные команды, какие значения присваиваются переменным. Листинг может помочь при отладке сложных программ. Также он пригодится начинающим изучать ассемблер.

Сначала необходимо скомпилировать программу — генератор листинга, которая поставляется вместе с FASM. Сделать это очень просто. Нужно открыть файл C:\FASM\TOOLS\WIN32\LISTING.ASM (у меня FASM находится в папке C:\FASM, у вас может быть по-другому) и скомпилировать его (пункт меню Run->Compile). Полученный исполняемый файл (LISTING.EXE) можно для удобства поместить в папку C:\FASM.

Если запустить этот файл из командной строки, то он сообщит способ своего использования:


Обязательными параметрами являются имена входного и выходного файлов. В качестве входного файла должен быть указан специальный файл с информацией об ассемблировании. Опция -a добавляет в листинг адреса. Опция -b позволяет ограничить максимальное количество символов в строке. Она полезна, если вы не хотите мучаться с горизонтальной прокруткой при просмотре листинга 🙂

В качестве примера создадим листинг для программы Hello, world! из части 6 учебного курса:

use16 ;Генерировать 16-битный код org 100h ;Программа начинается с адреса 100h mov dx,hello ;В DX адрес строки. mov ah,9 ;Номер функции DOS. int 21h ;Обращение к функции DOS. mov ax,4C00h ;\ int 21h ;/ Завершение программы ;------------------------------------------------------- hello db 'Hello, world!$'

Запускать LISTING.EXE каждый раз вручную неудобно, поэтому лучше создать для этих целей bat-файл. Примерно такой:

C:\FASM\LISTING.EXE -a hello.fas hello.lst

Запустив это файл, мы сгенерируем листинг. Файл листинга — это текстовый файл, его можно просмотреть любым редактором (например, Блокнотом). Внутри файла мы увидим следующее:

[0000000000000000] use16 ;Генерировать 16-битный код org 100h ;Программа начинается с адреса 100h 00000000: [0000000000000100] BA 0C 01 mov dx,hello ;В DX адрес строки. 00000003: [0000000000000103] B4 09 mov ah,9 ;Номер функции DOS. 00000005: [0000000000000105] CD 21 int 21h ;Обращение к функции DOS. 00000007: [0000000000000107] B8 00 4C mov ax,4C00h ;\ 0000000A: [000000000000010A] CD 21 int 21h ;/ Завершение программы ;------------------------------------------------------- 0000000C: [000000000000010C] 48 65 6C 6C 6F 2C 20 77 6F 72 6C 64 21 24 hello db 'Hello, world!$'

Первый столбец показывает смещение, по которому записываются байты в исполняемый файл. Второй столбец — это адреса, по которым данные будут размещаться в памяти во время выполнения программы. Далее идут собственно данные, то есть коды команд, начальные значения переменных и констант, коды символов строк, — в таком виде, в каком они пишутся в файл. После данных мы видим те же самые строки, что в исходнике. Они повторяются в листинге. Для некоторых строк в файл ничего не генерируется (например, для директивы org 100h).

Технология .NET готовится отпраздновать свой юбилей. За это время было написано множество коммерческих программ (и малвари в том числе), но как только дело доходит до того, чтобы заглянуть внутрь p-кода на предмет "отломать" пару ненужных байт, выясняется, что достойных хакерских инструментов нет, и судя по всему, не появится, поэтому приходится использовать то, что есть, хакерствуя в весьма стесненных обстоятельствах, словно шахтеры в забое!

Отказ от ответственности

Стандартное отречение: вся информация, предоставленная ниже, преследует исключительно благие цели (анализ вредоносного программного обеспечения, например) и мыщъх не несет никакой ответственности (ни явной, ни предполагаемой) за любой возможный ущерб или потерянную выгоду от ее использования.

Что нам понадобится

Microsoft Visual Studio

Рисунок 1. Отсюда можно бесплатно скачать последнюю версию Microsoft Visual Studio.

Реализация платформы .NET

Пишем свой первый crackme

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 off, hacker!" );
>
>

Листинг 1. Исходный текст программы n2k_crackme_01h.cs.

В Mono вместо csc.exe используется файл mcs/mcs.bat, но независимо от способа сборки, мы получаем n2k_crackme_01h.exe, готовый к непосредственному запуску, после которого нас спросят пароль и если мы введем его неверно - пошлют на хрен.

Компилятор Cи++, входящий в состав Microsoft Visual Studio 2008, умеет транслировать программы не только в машинный, но и в байт-код, позволяя нам использовать все прелести .NET платформы из привычных плюсов (трансляция "чистых" Си программ в байт-код все еще не поддерживается).

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" );
>

Компиляция осуществляется путем указания ключа /CLR в командной строке компилятора CL.EXE (рядом с которым можно указать ключ /Ox для форсирования максимальной оптимизации):

Первые эксперименты

Загружаем подопытный n2k_crackme_01h.exe в HIEW, дважды давим на для перевода редактора в дизассемблерный режим, жмем и попадаем в точку входа, где красуется команда jmp _CorExeMain ; mscoree.dll (см. рис. 3). Это и есть весь машинный код, который только есть (простите за каламбур).

.NET сборка

Дальнейшее расследование показывает, что jmp находится в самом конце секции .text, за которой располагаются секции ресурсов и перемещаемых элементов, а выше - байт-код виртуальной машины, просматривая который в hex-mode, мы обнаружим все текстовые строки (и пароль в том числе!) записанные в формате Unicode, причем перед строкой находится байт, определяющий длину строки. Узнав оригинальный пароль, мы, конечно, без труда смогли бы "взломать" crackme, однако редкая программа хранит пароли открытым текстом, да и неинтересно это.

Внешний вид .NET-сборки

Техника дизассемблирования

Загружаем n2k_crackme_01h.exe в IDA Pro и видим (см. рис. 5), что ничего ужасного в CIL-коде нет. Напоминает байт-код виртуальной Java-машины. IDA Pro не только создает перекрестные ссылки, но даже показывает опкоды и расставляет комментарии к командам, чтобы не было нужды каждый раз заглядывать в справочник (ECMA-335/Partition III/CIL Instruction Set).

Консольная версия IDA

Впрочем, чтобы заставить дизассемблер быть более дружелюбным к хакеру, необходимо выполнить следующие действия: в меню "Options" выбрать пункт "Text representation", там указать количество байт для отображения опкода ("Number of opcode bytes") - шести хватит вполне, а в разделе "Line prefixes" сбросить все галочки, кроме "Function offsets", после чего вновь возвратиться в меню "Options", зайти в "Comments" и взвести "Display auto comments" для автоматического отображения комментариев ко всем инструкциям (впрочем, при наличии некоторого опыта работы с CIL-кодом этого можно и не делать).

Поклонники графической версии IDA Pro могут задействовать графы (см. рис. 6), упрощающие (на самом деле - усложняющие) понимание структуры программы, но тут уж как говорится - на вкус и цвет все фломастеры разные. Лично мыщъх никогда не пользовался графами и другим не советует.

Графическая версия IDA

А теперь посмотрим, на что способен штатный дизассемблер от Microsoft, по умолчанию расположенный в каталоге C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\ и зовущийся ilasm.exe. Загружаем в него n2k_crackme_01h.exe и. хм, в общем-то, довольно неплохая картина получилась (см. рис. 7), а навигация по классам выполнена даже лучше, чем в IDA Pro, причем намного лучше (примечание: чтобы ildasm.exe отображал опкоды инструкций, необходимо в меню View взвести галочку "Show bytes")

Штатный дизассемблер

Рисунок 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).

Листинг 5. Результат работы штатного дизассемблера ildasm.exe.

Логично - чтобы заставить программу воспринимать все пароли как правильные, двухбайтовый условный переход brtrue.s IL_0031 необходимо заменить на пару однобайтовых команд nop (опкод - 00h, а вовсе не 90h как на x86). Или же. заменить brtrue.s IL_0031 на brFALSE.s IL_0031, тогда любой неправильный пароль будет восприниматься как правильный и, соответственно, наоборот. Открыв ECMA-335, мы узнаем, что инструкция brfalse.s имеет опкод 2Ch - и это все, что нам необходимо знать для взлома программы.

Дизассемблирование Cи++ сборки

Длинные имена методов класса (сокращенные для экономии бумаги), конечно, на первых порах вызывают шевеление волос на голове, но потом к ним быстро привыкаешь, автоматически "вычленяя" привычные "позывные" типа printf, gets, etc, однако структура кода далека от совершенства и на его анализ уходит намного больше времени, что, кстати говоря, представляет собой не такой уж "тупой" защитный прием от начинающих хакеров. Просто компилируем свои Си++ программы с ключом /CLR и хрен кто их взломает.

Техника патча

Так, где там наш HIEW?! Готов ко взлому или. еще не готов? Как нам определить местоположение байта, который мы собрались захачить? Ведь виртуальные адреса в контексте CIL-кода вообще неуместны!

Воспользуемся дедовским способом и поищем последовательность байт (сигнатуру), обитающую в окрестностях целевой команды. В данном случае это может быть 2Dh 0Dh 72h 2F 00h 00h 70h 28h (об обратном порядке байт не забываем, да? ildasm автоматически "нормализует" аргументы команд, IDA Pro - нет, показывая их такими, какие они есть - наименее значимый байт располагается по младшему адресу).

Короче, вбиваем заданную последовательность в поиск и убедившись в том, что данное вхождение - единственное, переводим HIEW в режим записи по , заменяем 2Dh на 2Ch (см. рис. 8), сохраняем изменения в файле по и выходим.

Поиск сигнатуры

Рисунок 8. Поиск сигнатуры в HIEW'е и bit-hack (исправление "неправильного" байта на "правильный").

Запускаем хакнутый файл и. о чудо. Он работает. Теперь любой, наугад взятый пароль - например, "123456" воспринимается как правильный (см. рис. 9). Конечно, если программа снабжена цифровым сертификатом подлинности или использует механизм контроля целостности собственного кода, этот номер уже не пройдет, но. ведь надо же с чего-то начинать ломать!

Хакнутая программа

Рисунок 9. Хакнутая программа любой пароль воспринимает как правильный.

Техника отладки

Спору нет, дизассемблер - весьма популярный инструмент для исследования программ. Популярный, но не единственный и во многих случаях отладчик оказывается намного более предпочтительным. Вместо того, чтобы гадать - какое значение имеет переменная в данной точке (в дизассемблере), гораздо практичнее заглянуть в нее отладчиком.

Расследование показало, что штатному .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 (или нажимаем ), в появившемся окне "Dump options" (см. рис. 10) оставляем все галочки в состоянии по умолчанию. Главное, чтобы была взведена галочка "Dump IL Code", после чего нажимаем и вводим имя файла для дампа - например, "cracked".

Дамп двоичной .NET-сборки

Берем штатный ассемблер и собираем файл следующим образом:

Листинг 7. Ассемблирование сдампленного файла штатным ассемблером.

На диске образуются файлы cracked.exe и cracked.pdb, готовые к загрузке в отладчик (что примечательно - отладочная информация непосредственно в сам исполняемый файл не записывается, что очень и очень хорошо, иначе нам пришлось бы потом убирать ее оттуда или мириться с увеличением размера поломанного exe, что вряд ли входит в наши планы).

Ок, набираем в командной строке "$mdbg.exe cracked.exe" и. оказываемся в консольном окне отладчика, автоматически останавливающегося на первой команде функции Main, передавая нам бразды правления. А что такого крутого и хорошего мы можем сделать?!

Начнем с просмотра окрестностей, за что отвечает команда "show" или ее более короткий алиас "sh", результат работы которого выглядит так (см. листинг 8):

Листинг 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).

Листинг 9. Сеанс работы с отладчиком mdbg.exe (команды, вводимые хакером, выделены полужирным шрифтом).

Ниже, для наглядности тот же самый сеанс работы с отладчиком продемонстрирован в графическом виде (см. рис. 11):

Сеанс работы с отладчиком

Рисунок 11. Сеанс работы с отладчиком mdbg.exe "как он есть".

Если кому-то религия запрещает использовать консоль, что ж - к его услугам Dotnet IL Editor - бесплатный IL-отладчик с GUI-интерфейсом (см. рис. 12), однако mdbg.exe мыщъх'у как-то больше по душе, да к тому же под него расширения всякие можно писать.

Dotnet IL Editor

Рисунок 12. Dotnet IL Editor - IL-отладчик с GUI-интерфейсом.

Заключение

Мыщъх надеется, что данная статья обеспечит хороший старт, ну а остальное - дело времени, техники и бесчисленных экспериментов!

Коллекция .NET crackmes

Основные команды отладчика mdbg.exe

  • ?, help:
    вывод встроенной справки, "help команда" - подробная справка по команде;

Читайте также: