De4dot как пользоваться
Перейти к содержимому

De4dot как пользоваться

  • автор:

De4dot как пользоваться

Здравствуйте! Экспериментирую с различными обфускаторами, чтобы защитить свой код от повторного использования. Основная задача — сделать анализ с целью повторного использования настолько трудоемким, чтобы дешевле было написать свой код, а не использовать мой. Уточню — не преследую цель сделать анализ НЕвозможным,- просто, максимально усложнить! Пока остановился на SmartAssembly (версии 6). Деобфусцировал с помощью de4dot. Результат оценивал в Reflector. В связи с этим есть ряд вопросов. В вопросах подразумевается, что анализируемый exe или dll был ранее обфусцирован SmartAssembly.

Вопросы:
1. Можно ли с помощью какого либо метода (деобфускация, создание дампа процесса, отладка или что либо другое) без значительных трудозатрат восстановить исходный код (можно без имен переменных) internal и private функций с условием, что они не вызываются из public функций? Если можно, то как?
2. Аналогичный вопрос по поводу исходных имен параметров функций и локальных переменных, используемых в internal и private функциях.
3. Какой обфускатор посоветуете использовать вместо SmartAssembly (только чтобы лицензия была не дороже 150-200$)?

Несколько наблюдений (исходя из моих экспериментов):
1. De4dot не восстанавливает имена локальных переменных после SmartAssembly (только переименовывает исходя из их типов [Ссылки могут видеть только зарегистрированные и активированные пользователи] для облегчения анализа). А вот структуру кода нормально восстанавливает. Еще восстанавливает имена параметров публичных функций.
2. internal и private функций я не нашел [Ссылки могут видеть только зарегистрированные и активированные пользователи] в восстановленном с помощью De4dot файле. Причем, их код не находится даже если вызываешь прямо из него (из кода internal или private функции) public функцию [Ссылки могут видеть только зарегистрированные и активированные пользователи] (в то время как ее вызов из публик функции виден [Ссылки могут видеть только зарегистрированные и активированные пользователи] и [Ссылки могут видеть только зарегистрированные и активированные пользователи])
3. Однако если приватная функция вызывается публичной, то ее можно обнаружить [Ссылки могут видеть только зарегистрированные и активированные пользователи] и распознать структуру .

25.05.2015, 14:07

я использую Appfuscator, регаем каждые 14 дней новую почту и пользуемся пробной версией, которая никак не ограничивает конечный результат, или ILProtector, тоже не плохой обфускатор, Det4Dot не снимет его
Ну а для защиты можете сделать некий лаунчер, который будет воссоздавать саму программу, код которой будет у вас на сервере.

Вот гляньте работу AppFuscator
[Ссылки могут видеть только зарегистрированные и активированные пользователи] — обфусцированная программа(накляпал за 5 мин, показывает скорость работы циклов)

исходный код
using System;
using System.Threading;
using System.Diagnostics;

namespace ConsoleApplication1
internal class Program
static int Count = 100000000;

static void DWhile()
int TestInt = 0;
Stopwatch sw = new Stopwatch();
sw.Start();
do TestInt++; while (TestInt sw.Stop();
float DoWhileTick = sw.ElapsedTicks;
float DoWhileMs = sw.ElapsedMilliseconds;
Console.WriteLine(«Do_WhileTick = \tDo_WhileMs = «, DoWhileTick, DoWhileMs);
>

static void WhileD()
int TestInt = 0;
Stopwatch sw = new Stopwatch();
sw.Start();
while (TestInt sw.Stop();
float WhileDoTick = sw.ElapsedTicks;
float WhileDoMs = sw.ElapsedMilliseconds;
Console.WriteLine(«While_DoTick = \tWhile_DoMs = «, WhileDoTick, WhileDoMs);
>

static void For()

Stopwatch sw = new Stopwatch();
int TestInt = 0;
sw.Start();
for (int i = 0; i TestInt++;
sw.Stop();
float ForTick = sw.ElapsedTicks;
float ForMs = sw.ElapsedMilliseconds;
Console.WriteLine(«ForTick = \tForMs = «, ForTick, ForMs);
>

static void Foreach()
Stopwatch sw = new Stopwatch();
int TestInt = 0;
sw.Start();
byte[] bt = new byte[Count];
foreach (byte b in bt)
TestInt++;
sw.Stop();
float ForeachTick = sw.ElapsedTicks;
float ForeachMs = sw.ElapsedMilliseconds;
Console.WriteLine(«ForeachTick = \tForeachMs = «, ForeachTick, ForeachMs);

static Thread[] threads;
public static void Main()
threads = new Thread[4];
threads[0] = new Thread(DWhile);
threads[1] = new Thread(WhileD);
threads[2] = new Thread(For);
threads[3] = new Thread(Foreach);
foreach (Thread t in threads)
t.Start();
Console.ReadLine();
>
>
>

31.05.2015, 00:20

Appfuscator, .Net Reactor, .SmartAssembly. всё это снимается, да, сложно, но, снимается.
Откуда я знаю? Опыт.
Вывод: писать что-то своё. Что? Ну сейчас видел реализации так называемого «облачного» кода.
Сериализируется функция, записывается в облако, из облака десериализируется и вызывается. Можно вытянуть код, но если прицепить к этому ещё пару проверок, то желание что-то крякать — отпадает.

31.05.2015, 20:07

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

31.05.2015, 23:17

Nickitee, ну все в этом мире, что можно собрать, то можно и разобрать. Вопрос лишь в ценности затраченного времениКонечно можно, но когда стоит вопрос о ценности, то эти защиты отходят на 2 план.

19.06.2015, 14:56
видел реализации так называемого «облачного» кода.
А можете ссылочки на примеры скинуть?
19.06.2015, 15:24

А можете ссылочки на примеры скинуть?
Сериализация/Десериализация пробейте в гугле, а облаком может быть любое хранилище данных

19.06.2015, 16:26

Сериализация/Десериализация пробейте в гугле
Аа понял) Была тут задумка сделать нечто такое:
Вин форм проект связывается с ASP MVC(сервер) и передает ему некоторые данные, на стороне сервера данные обрабатываются и возвращается некий Action. Вот только интересно на сколько будет хромать быстродействие и можно ли вообще так делать?) А если можно, то где можно покурить мануалы на эту тему?

21.06.2015, 14:24

Вин форм проект связывается с ASP MVC(сервер) и передает ему некоторые данные, на стороне сервера данные обрабатываются и возвращается некий Action. Вот только интересно на сколько будет хромать быстродействие и можно ли вообще так делать?)
да можно, по такому принципу у меня все работает, на быстродействии это никак не сказывается ибо время нужно затратить только при запуске программы, чтобы от сервера получить данные и достроить программу, в остальном же она работает как и всегда. Как все это передавать, спросите вы — смотрите темы в интернете по созданию чатов на уровне сокетов, а дальше уже от сервера сможете передавать клиенту любые данные.

21.06.2015, 16:48

да можно, по такому принципу у меня все работает, на быстродействии это никак не сказывается ибо время нужно затратить только при запуске программы, чтобы от сервера получить данные и достроить программу, в остальном же она работает как и всегда. Как все это передавать, спросите вы — смотрите темы в интернете по созданию чатов на уровне сокетов, а дальше уже от сервера сможете передавать клиенту любые данные.
Про сокеты я информацию нагуглю, но может вы посоветуете что то для новичков(никогда с ними не работал). И в каком виде хранить функции которые будут встраиваться в клиент на самом сервере?

22.06.2015, 14:56

И в каком виде хранить функции которые будут встраиваться в клиент на самом сервере?
смотря какая сериализация, если бинарная то в bin, если Xml-сериализация, то собственно в xml. В результате все равно передаете массив байт, а дальше уже с ним работаете

22.06.2015, 16:20

В результате все равно передаете массив байт, а дальше уже с ним работаете
Погуглил про сокеты, во всех материалах говорилось что для закрытия канала нужно указать сокету что данные переданы в полном объеме, например так. if (data.IndexOf(«») > -1)
Console.WriteLine(«Сервер завершил соединение с клиентом.»);
break;
>
handler.Shutdown(SocketShutdown.Both);
handler.Close();
>
Где передаем вручную или дописываем его автоматически к строке(в случае чата), а как быть с функцией?

22.06.2015, 19:09

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

Powered by vBulletin
Copyright © 2023 vBulletin Solutions, Inc. Перевод: zCarot
G-gaMe! Team production

De4ot [ Мануал на русском ]

На форуме работает ручное одобрение пользователей. Это значит, что, если Ваша причина регистрации не соответствует тематике форума, а также Вы используете временную почту, Ваша учётная запись будет отклонена без возможности повторной регистрации. В дальнейшем — пожизненная блокировка обоих аккаунтов за создание мультиаккаунта.

Мы обновили Tor зеркало до v3!
Для входа используйте следующий url: darkv3nw2. bzad.onion/

Мы вновь вернули telegram чат форуму, вступайте, общайтесь, задавайте любые вопросы как администрации, так и пользователям!
Ссылка: https://t.me/chat_dark_time

Вы используете устаревший браузер. Этот и другие сайты могут отображаться в нём некорректно.
Вам необходимо обновить браузер или попробовать использовать другой.

Moden
Участник
Moden
Участник

20 Окт 2020 3 2

Привет всем .
Много кто ищет как пользоваться известной программой de4ot .
На GitHub есть мануал , но проблема в том что он на английском .
Поэтому я решил сэкономить ваше время и перевести весь мануал .
Буду благодарен если прокомментируете эту тему и оставите реакцию .
Сам мануал
================================================================================================
Описание
===========

de4dot — это деобфускатор и распаковщик .NET с открытым
исходным кодом (GPLv3), написанный на C #. Он будет изо всех сил стараться
восстановить запакованную и запутанную сборку почти до исходной сборки. Большая
часть обфускации может быть полностью восстановлена (например, строковое шифрование),
но переименование символа невозможно восстановить, поскольку исходные имена (обычно) не являются частью запутанной сборки.

Он использует [dnlib] (

Пожалуйста, Вход или Регистрация для просмотра содержимого URL-адресов!

) для чтения и записи сборок,
поэтому убедитесь, что вы его получили, иначе он не будет компилироваться.

Получите двоичные файлы с сервера сборки [! [] (

Пожалуйста, Вход или Регистрация для просмотра содержимого URL-адресов!
Пожалуйста, Вход или Регистрация для просмотра содержимого URL-адресов!

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

Вместо этого попробуйте обновить de4dot самостоятельно. Это намного проще,
чем вы думаете. Если вы не можете, поищите в Интернете, и вы найдете пару форумов,
где вы можете задать свой вопрос.

Вот псевдослучайный список того, что он будет делать в зависимости от того,
какой обфускатор использовался для обфускации сборки:

* Встроенные методы. Некоторые обфускаторы перемещают небольшие части метода
в другой статический метод и вызывают его.
* Расшифровывать строки статически или динамически
* Расшифровать другие константы. Некоторые обфускаторы могут также шифровать другие константы, такие как все целые числа, все двойные числа и т. Д.
* Расшифровывать методы статически или динамически
* Убрать прокси-методы. Многие обфускаторы заменяют большинство / все инструкции вызова вызовом делегата. Этот делегат,
в свою очередь, вызывает настоящий метод.
* Переименовать символы. Несмотря на то, что большинство символов невозможно восстановить, он переименует их в строки,
удобочитаемые человеком. Тем не менее, иногда некоторые оригинальные имена можно восстановить.
* Девиртуализация виртуализированного кода
* Расшифровать ресурсы. Многие обфускаторы имеют возможность шифровать ресурсы .NET.
* Расшифровать встроенные файлы. Многие обфускаторы имеют возможность встраивать и, возможно, шифровать / сжимать другие сборки.
* Удалить код обнаружения несанкционированного доступа
* Удалить код анти-отладки
* Деобфускация потока управления. Многие обфускаторы модифицируют код IL так, что он выглядит как спагетти-код, что очень затрудняет понимание кода.
* Восстановить поля класса. Некоторые обфускаторы могут перемещать поля из одного класса в другой, созданный обфускатором.
* Преобразование PE exe в .NET exe. Некоторые обфускаторы оборачивают сборку .NET внутри Win32 PE, поэтому декомпилятор .NET не может прочитать файл.
* Удаляет большинство / все ненужные классы, добавленные обфускатором.
* Исправляет некоторые ошибки peverify. Многие из обфускаторов содержат ошибки и по ошибке создают непроверяемый код.
* Восстановить типы параметров и полей метода

* Agile.NET (также известный как CliSecure)
* Babel.NET
* CodeFort
* CodeVeil
* CodeWall
* Криптообфускатор
* DeepSea Obfuscator
* Dotfuscator
* .NET Reactor
* Eazfuscator.NET
* Goliath.NET
* ILProtector
* MaxtoCode
* МПРЕСС
* Рыться
* Skater.NET
* SmartAssembly
* Spices.Net
* Ксенокод

Некоторые из вышеперечисленных обфускаторов используются редко (например, Goliath.NET),
поэтому они прошли гораздо меньше испытаний. Помогите мне, сообщая об обнаруженных вами ошибках или проблемах.

Иногда обфусцированная сборка и все ее зависимости загружаются в память для выполнения. Используйте
безопасную среду песочницы, если вы подозреваете, что сборка или сборки являются вредоносными.

Даже если текущая версия de4dot не загружает определенную сборку в память для выполнения, будущая
версия может.

Перетащите файл (ы) на de4dot.exe и подождите несколько секунд.

Если было запутано более одной сборки, весьма вероятно, что вам придется деобфускировать их все одновременно,
если вы не отключите переименование символов. Причина в том, что если сборка A имеет ссылку на класс C в сборке B,
и вы переименовываете символы только в сборке B, тогда класс C можно переименовать, например, в. Class0, но ссылка в
сборке A по-прежнему ссылается на класс с именем C в сборке B. Если вы деобфускируете обе сборки одновременно,
все ссылки также будут обновлены.

Следующая командная строка деобфускирует все сборки, которые были запутаны поддерживаемым обфускатором,
и сохранит сборки в `c: \ output`

de4dot -r c: \ ввод -ru -ro c: \ вывод

`-r` означает рекурсивный поиск. `-ru` означает, что он должен игнорировать неизвестные файлы. `-ro` означает,
что выходные файлы должны быть помещены в следующий каталог. Обычно вы сначала копируете `c: \ input` в` c: \ output`,
а затем запускаете команду. Таким образом,
все файлы будут находиться в c: \ output, даже не сборки и необработанные сборки. Когда de4dot закончит,
вы просто дважды щелкните основную сборку в `c: \ output`, и она,
надеюсь, должна запуститься.

Используйте опцию `-d` для обнаружения обфускатора без деобфускации какой-либо сборки.

Найдите все сборки .NET и обнаружите обфускатор. Если это неподдерживаемый обфускатор или он не запутан, он напечатает «Неизвестный обфускатор».

de4dot -d -r c: \ input

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

de4dot -d -r c: \ input -ru

Обфускатор
—————-
Иногда, в редких случаях, вам может понадобиться сохранить токены метаданных.
Используйте —preserve-tokens или —preserve-table. Также рассмотрите возможность использования `—keep-types`,
поскольку он не удалит какие-либо типы и методы, добавленные обфускатором. Еще одна полезная опция — `—dont-create-params`. Если используется,
средство переименования не будет создавать строки Param для параметров метода, у которых нет строки Param. Таким образом,
таблица ParamPtr не будет добавлена в ваши сборки. В Peverify есть ошибка,
но она не поддерживается (вы увидите много «ошибок»).

Кучи #Strings, #US и #Blob также можно сохранить,
используя соответственно `—preserve-strings`,` —preserve-us` и `—preserve-blob`. Из этих трех `—preserve-us` является наиболее полезным,
поскольку инструкция` ldstr` и `module.ResolveString ()` напрямую ссылаются на кучу #US.

`—preserve-sig-data` следует использовать, если обфускатор добавляет дополнительные данные в конце подписей,
которые он использует для своих собственных целей, например. в качестве ключей дешифрования. Confuser — это один из обфускаторов, который это делает.

`—preserve-tokens` сохраняет все важные токены, но также включает` —preserve-us`, `—preserve-blob` и` —preserve-sig-data`.

Если он определяется как неизвестный (неподдерживаемый) обфускатор (или если вы вызываете его с помощью `-p un`),
все токены сохраняются, включая кучу #US и любые дополнительные данные в конце подписей. Кроме того, не удаляются никакие типы, поля или методы обфускатора.

Сохраните все важные токены, #US, #Blob, дополнительные данные сигнатуры.

de4dot —preserve-tokens file1.dll

Сохраните все важные токены, #US, #Blob, дополнительные данные sig и не удаляйте типы / поля, добавленные обфускатором

de4dot —keep-types —preserve-tokens file1.dll

Сохраните все важные токены, #US, #Blob, дополнительные данные sig и не создавайте лишние строки Param, чтобы предотвратить создание таблицы ParamPtr.

de4dot —dont-create-params —preserve-tokens file1.dll

Сохраните все важные токены, кроме токенов Param.

de4dot —preserve-table all, -pd file1.dll

Хотя de4dot поддерживает множество обфускаторов, некоторые из них не поддерживаются.
Чтобы расшифровать строки, вам сначала нужно выяснить, какой метод или методы расшифровывают строки.
Чтобы получить токен метода этих дешифраторов строк, вы можете использовать ILDASM с включенной опцией «показать токены метаданных».
Токен метода — это 32-битное число, которое начинается с 06, например. 06012345.

Эта команда загрузит сборку file1.dll в память путем вызова ʻAssembly.Load () `.
Когда он обнаруживает вызовы двух дешифраторов строк (06012345 и 060ABCDE), он вызывает их,
создавая динамический метод, и сохраняет результат (расшифрованную строку). Вызов дешифратора строк будет удален,
и расшифрованная строка будет на своем месте.

de4dot file1.dll — делегат strtyp —strtok 06012345 —strtok 060ABCDE

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

Принудительное обнаружение определенного обфускатора
——————————————

de4dot не идеален. Если ему не удается обнаружить обфускатор, вы можете использовать опцию `-p`, чтобы заставить его предположить, что он был им запутан.

Принудительная сборка SmartAssembly

de4dot file1.dll -p sa

Принудительно использовать неподдерживаемый обфускатор

de4dot file1.dll -p un

Для других типов обфускаторов см. Экран справки.

de4dot -d file1.dll file2.dll file3.dll

Сохранение токенов метаданных

Переименование символов не так просто, как переименование A в B, когда задействовано отражение.
de4dot в настоящее время не поддерживает переименование XAML, поэтому, если вы подозреваете, что он использует WPF (или если это приложение Silverlight),
вам следует отключить переименование, если сборка не запускается.

de4dot —dont-rename file1.dll file2.dll

`—keep-names` также может использоваться для указания` de4dot` не переименовывать определенные символы, например. «не переименовывать поля».

Переименуйте все, что нужно переименовать, кроме свойств, событий и методов.

de4dot —keep-names pem file1.dll

Использование другого регулярного выражения переименования
——————————

Регулярных выражений по умолчанию должно быть достаточно, за исключением, возможно, того,
которое используется при обнаружении неподдерживаемого обфускатора. Чтобы увидеть все регулярные выражения по умолчанию,
запустите de4dot без аргументов, и он перечислит все параметры и все значения по умолчанию.

Например, в настоящее время следующее регулярное выражение по умолчанию используется при обнаружении Dotfuscator.

Как видите, это не одно регулярное выражение, а несколько. Каждый из них разделяется символом `&`, и каждое регулярное выражение может быть отменено,
используя перед ним символ `!`. Чтобы показать это более наглядно, используются следующие регулярные выражения:

Чтобы изменить регулярное выражение (а), вы должны знать краткое имя типа обфускатора (см. Экран справки).
Например. это `sa`, если это SmartAssembly, и ʻun`, если это неподдерживаемый / неизвестный обфускатор.
Используемый параметр — `—TYPE-name` (например,` —sa-name` для SmartAssembly и `—un-name` для неизвестных / неподдерживаемых обфускаторов):

de4dot —un-name «^ [a-zA-Z] \ w * $» file1.dll

Запустите `de4dot` без аргументов, и он покажет все варианты.

Разбираем обфусцированный CrackMe на C#

Имеется файл CrackMe, при запуске которого предлагается ввести ключ лицензии:

Исходя из подсказок после неправильного ввода ключа, можно понять, что в пароле должно быть обязательно 8 цифр, то есть от 00000000 до 99999999, на данном этапе можно переходить к коду программы, точнее тому что получится достать из .exe

Если просто открыть программу в .net Reflector, мы увидим следующее:

Это последствия обфускции, работать с таким кодом можно, но достаточно проблематично, поэтому воспользуемся небезызвестным de4dot, который имеет встроенные алгоритмы деобфускации (основанные на известных обфускаторах, от кастомных это дело не поможет)

Ну и сменим инструмент просмотра кода на бесплатный dotPeek, он несколько удобней чем Reflector, но не позволяет изменять код программы. Впрочем на данном этапе, мы хотим узнать алгоритм верификации пароля, а не обойти его, но в конце статьи я покажу, как можно изменить проверку, и входить с практически любым паролем.

Открываем почищенный de4dot файл CrackMe в dotPeek, и видим следующее

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

«Nope. A license key consists of 8 numbers, e.g. 31628594 or 71439532!»

которую мы видели при первом запуске программы находится в открытом виде, по ней мы и нашли нужное место кода с проверками пароля.

Логика работы:

В бесконечном цикле while, консоль CrackMe принимает данные от пользователя, передает в функцию smethod_0, возвращаемым значением которой является bool, который равен true если пароль верен, и false если нет.

При этом if(! инвертирует это значение, и в случае с возвращенным false мы получаем вывод о неверном пароле,
Console.WriteLine(«Nope. A license key consists of 8 numbers, e.g. 31628594 or 71439532!»);
А в случае true переходим в else, где посредствам оператора break выходим из бесконечного цикла, и переходим к удивленному вопросу автора CrackMe

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

В целом никакой сложной математики тут нет, пробежимся по коду:

В функцию передается строковое значение полученное из пользовательского ввода консоли, проверяется на длину, и если она не равна 8 символам, то сразу же возвращает false, ибо такой пароль точно не подходит вне зависимости от его содержания.

Далее, в try выполняется преобразование строки в числовое значение int, а если же оно содержит любые символы кроме цифр, то выполняются действия в операторе catch, которые так же возвращают false, честно сказать не знаю, зачем использовался goto, вместо return false, может автор так хотел запутать пользователя, либо как-то так код деобфусцируется, но имеем, то что имеем.

Далее если это число, и оно длинной в 8 цифр, переходим к основным проверкам, которые выглядят так:

Всего нашему паролю предстоит пройти 4 проверки, каждая из них использует smethod_1, в котором происходит выборка подстроки из строки, со сдвигом указанным в int_0, и возвращается из этого метода, всегда одна цифра, так как вторым аргументом Substring, всегда будет 1.

Теперь, понимая как это работает, можно составить условия на все 4 проверки:

Все число должно делится на первую цифру числа без остатка
✦ Сумма значений 3 цифры и 6 цифры числа = значению 2 цифры
4 цифра * на 8 цифру должна делится на 2 без остатка
7 цифра — 6 цифра = 1 цифре версии установленного .net framework (В нашем случае это будет 4)

Ну а теперь надо лишь заставить эти методы работать в нашу пользу.
Немного модифицируем изначальные методы, для работы с Paraller.For, ибо предстоит 90 миллионов комбинаций паролей перебрать, и это будет в разы быстрее, на многоядерном компьютере. (13 секунд, против 89 при использовании обычного For, на моем ноутбуке)

И я намеренно упускаю, первые 10 миллионов паролей от 00000000 до 09999999, дабы не подставлять нули вперед значения строки, нашу задачу это никоим образом не обесценит, просто полученное количество возможных паролей, будет немного меньше возможного. Но нам то нужен всего 1, не так ли?

Вот код, который у меня получился, он запишет все возможные пароли в txt файл.
Я не профессиональный программист, это просто мое хобби, так же как и реверс инжиниринг, так что за реализацию сразу прощу прощения, если есть что добавить, прошу об этом написать, мне и самому будет интересно узнать.

using System; using System.Diagnostics; using System.IO; using System.Threading.Tasks; namespace ConsoleApp10 < internal class Program < internal static int nfmV; internal static string allPwd; private static void Main(string[] args) < nfmW = smethod_1(Environment.Version.ToString(), 0); Console.WriteLine("Начат парсинг подходящих паролей"); Stopwatch stw = new Stopwatch(); stw.Start(); Parallel.For(10000000, 99999999, smethod_0); stw.Stop(); Console.WriteLine($"Закончено за: сек."); using (StreamWriter sw = new StreamWriter("paswds.txt")) < sw.Write(allPwd); >Console.ReadLine(); > private static void smethod_0(int x, ParallelLoopState pls) < string string_0 = Convert.ToString(x); bool flag = false; int num = -1; try < num = int.Parse(string_0); >catch < flag = false; >try < flag = num % smethod_1(string_0, 0) == 0 && (smethod_1(string_0, 2) + smethod_1(string_0, 5) == smethod_1(string_0, 1) && (smethod_1(string_0, 3) * smethod_1(string_0, 7) % 2 == 0 && smethod_1(string_0, 6) - smethod_1(string_0, 5) == nfmW)); >catch < flag = false; >if (flag) < allPwd += $"\n"; > > private static int smethod_1(string string_0, int int_0) => int.Parse(string_0.Substring(int_0, 1)); > > 

В результате получаем долгожданный результат, и удивление автора, как же мы все таки это сделали?!

Ну и напоследок покажу, как можно без всяких «сложных» преобразований получить доступ к этой программе, но в этом случае нам понадобиться вводить неправильные пароли.

Для этого мы будем использовать уже знакомый нам .net Reflector с плагином Reflexil, который позволяет делать изменения в IL коде, с последующей пересборокой .exe

Нужно найти в коде строку How did you got that?! и идущий перед ней опкод изменить с brtrue.s на brfalse.s

Тем самым изменить поведения оператора IF, теперь он будет считать все неправильные пароли верными и наоборот

На этом у меня все, спасибо, что дочитали.

P.S.: Сайт с CrackMe, если решите попрактиковаться: линк

Гайд [.NET C#] Учимся создавать деобфускатор

Но если ради интереса, то можно)
Всем привет. В этой статье я хочу рассказать, как можно написать свой деобфускатор для .NET(на подобии de4dot, но до него еще очень и очень далеко?, кстати, не обновленный не сможет расшифровать строки). Моя задача – объяснить принцип создания деобфускации. В данном гайде я не буду полностью создавать на него деобфускатор(сегодня вы очень часто будете встречать это слово, извиняюсь за тавтологию). Это ооооочень просто, но касается только расшифровки строк.

Для примера, возьму обфускатор последней версии .NET Reactor 6.3.0.0 (на эту версию еще нет полноценного деобфускатора и стандартный de4dot не работает, нужно обновлять)

В данном гайде я напишу только расшифровку строк . Дальше пробуйте сами, кто заинтересовался. Может выложу еще что-то интересное.

Начнем, пожалуй. Для начала, создадим консольное приложение, и реализуем простейший драг-н-дроп:

if (args.Length == 0) < Console.WriteLine("Drag and drop file"); Thread.Sleep(2000); Environment.Exit(1); >string pathFile = args[0];

Далее загружаем сборку дважды, в 1-ом случае мне удобно работать с библиотекой DNLIB(3.3.2)
Почему? Потому что стандартная библиотека System.Reflection очень часто не видит обфусцированные классы-типы.

ModuleDef moduleDef = ModuleDefMD.Load(pathFile); // Для работы с библиотекой Dnlib, загружаем сборку и будем работать с ней в дальнейшем Assembly assemblyDef = Assembly.LoadFile(pathFile); // Позволяет Invoke'ать методы и получать значения(часто используется для вызова точки входа, чтобы распаковать приложение) MethodInfo methodInfo = (MethodInfo)assemblyDef.EntryPoint; // Вызов точки входа, но я не использую напрямую эту переменную, нужна только для быстрого доступа и передача аргументов в другие функции StringDecrypt stringDecrypt = new StringDecrypt(ref moduleDef, ref methodInfo); // Наш класс-расшифровщик, который мы сейчас будем реализовывать moduleDef.Write(Path.GetDirectoryName(args[0]) + "\\" + Path.GetFileNameWithoutExtension(args[0]) + "_strCleaned" + Path.GetExtension(args[0])); // Сохранение пропатченного файла

Немного теории:
.NET Reactor реализует обфускацию строк таким образом: генерируется алгоритм запутывания строк, для этого алгоритма генерируется аналогичный для РАСШИФРОВКИ, но в тело нашего метода, где используется строка, вместо нее подставляется некоторое значение(назовем его seed), и по нему расшифровывается строка. Для ясности приведу картинку:

Видно как раз метод расшифровки(он очень большой, поэтому разбирать я его даже не буду), и виден наш seed для каждой строки он естественно разный.
Теперь нам нужно узнать, где находится строка. Представим, что у нас нет исходной версии кода(ДО), и мы не знаем, где должна быть строка подставлена в чистом виде. Для этого я сделал такую сигнатуру: ищем инструкцию Ldc -> ЕСЛИ СЛЕДУЮЩАЯ ПОСЛЕ НЕЕ CALL-инструкция с операндом-методом с возвращающим значение String, и входящим параметром Int32 -> то на этом месте происходит подстановка строки.(всё, что я сейчас написал, проанализируйте с картинкой выше и сопоставьте все условия).
В MSIL-листинге: Опкоды слева : Операнды справа
Теперь приступим к реализации класса StringDecrypt

public class StringDecrypt < private ModuleDef moduleDef < get; >private MethodInfo methodInfo < get; >public StringDecrypt(ref ModuleDef moduleDef, ref MethodInfo methodInfo) // Конструктор, инициализируем поля < this.moduleDef = moduleDef; this.methodInfo = methodInfo; Decrypt(); >void Decrypt() // Основной метод расшифровки < foreach (var typeDef in moduleDef.Types) // Проходим по каждому ТИПУ нашего модуля < foreach (var methodDef in typeDef.Methods) // Проходим по каждому МЕТОДУ нашего ТИПА < if (methodDef.Body == null) continue; // Проверка на пустой метод(обычно, анти-тампер удаляет тело, но не каждый анти-тампер) for (int i = 0; i < methodDef.Body.Instructions.Count(); i++) // Цикл-проход по нашим инструкциям МЕТОДА < if (methodDef.Body.Instructions[i].IsLdcI4() && methodDef.Body.Instructions[i + 1].OpCode.Name == "call") // Вот сравнение ОпКода с семейством Ldc и последующей инструкции call < dynamic operand_call = methodDef.Body.Instructions[i + 1].Operand; // Почему dynamic? Потому что иногда возвращаются разные типы с одинаковой реализацией, поэтому будем получать эксепшены для статического типа(очень полезная вещь, но злоупотреблять ею не стоит) if (operand_call.ReturnType.TypeName == "String" && operand_call.Parameters[0].Type.TypeName == "Int32") // Вот проверка нашего операнда на возвращаемый тип и тип аргумента < dynamic operand_ldc = methodDef.Body.Instructions[i].Operand; // Получаем seed string decrypt_string = InvokeDecryptMethod(operand_ldc, operand_call.Module.Name, operand_call.DeclaringType2.Name, operand_call.Name.String); // ВЫЗЫВАЕМ МЕТОД РАСШИФРОВКИ, который возвращает нам уже расшифрованную строку methodDef.Body.Instructions[i].OpCode = OpCodes.Nop; // Далее меняем IL-код. Ненужный нам уже Ldc опкод меняем на nop methodDef.Body.Instructions[i + 1] = new Instruction(OpCodes.Ldstr, decrypt_string); // Следующую инструкцию, в которой вызывался бы метод расшифровки(call) заменяем на Ldstr с операндом нашей новой расшифрованной строки. methodDef.Body.OptimizeBranches(); // Оптимизация всей условий, свитчей, "впаивание" наших IL-инструкций в тело метода. methodDef.Body.SimplifyBranches(); // Упрощение инструкций(br.s ->br) > > > > > > string InvokeDecryptMethod(int seed, string moduleName, string typeName, string methodName) // Сам метод-Invoke нашего метода-дешифратора < string decryptedString; var module = methodInfo.Module.Assembly.GetModule(moduleName); foreach (var typein module.GetTypes()) // Проход по типам в поисках нашего метода-дешифратора(усложненный вариант) < if (type.Name == typeName) // Если тип соответствует названием типу, который нам нужен, то проходим дальше < foreach (var methodType in type.GetRuntimeMethods()) // Проход по методам найденного ранее НУЖНОГО нам типа < if (methodType.Name == methodName) // Если наш метод найден, то . < decryptedString = (string)methodType.Invoke(null, new object[] < seed >); // .. просто вызываем его, первый параметр null - он вам не нужен, а вот вторым параметром нужно передать аргумент, в данном случае это наш seed return decryptedString; // Возвращаем нашу расшифрованную строку > > > > return "NULL"; // Заглушка > >

Давайте испытаем. Просто drag’n’dropаем наш обфусцированный файл на наше приложение, и видим:

Если вы думаете, что дальше — легче, просьба покинуть помещение) Нет, дальше еще хуже.
Данный расшифровщик работает ТОЛЬКО с настройкой обфускатора: «String obfuscation», если будут настройки миксоваться — у вас ничего не получится, т.к. будут использоваться методы обфускации «покруче».
Исходник:

Пожалуйста, авторизуйтесь для просмотра ссылки.

Всем спасибо! Если у вас есть аргументированная критика, предложения, вопросы, рад буду всё выслушать.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *