Как узнать каким протектором защищена программа

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

К чему это я? А к тому, что данный продукт также защищен этим протектором (как и, например, VIP). Определить протектор не составляет проблемы, так как давно уже существует множество разнообразных программ, помогающих в данном деле: PeID, DotNet Id, ProtectionID и т.п. Соответственно, если проанализировать исполняемый файл с помощью ProtectionID, то он сразу же выдаст следующее:

Когда менять РЕЗИНУ?! Какая глубина протектора шин допустима? #авто #diy #своимируками #резина

Сразу открыть такой файл в рефлекторе не получится, ибо:

.NET Reactor builds a native code wall between potential hackers and your .NET assemblies by producing a file which cannot be understood directly as CIL. Because the CIL in your assembly is emitted intact only at run time or design time (in a form in which the source is completely inaccessible), no tool is capable of decompiling .NET Reactor protected assemblies.

Проблема решается довольно просто:
1. Запускаем программу.
2. Качаем какой-нибудь .NET-дампер (если нет желания с помощью отладчика копаться в памяти процесса).
3. Дампим часть памяти процесса.
4. …
5. PROFIT!

Я обычно использую .NET Generic Unpacker или DotNet Dumper. Интерфейс интуитивный, всё запросто дампится.
После того, как отработает дампер, получаем .exe и кучу библиотек (которые неплохо бы переименовать в их оригинальные имена. Если используете DotNet Dumper, то он всё за вас сделает). Для того, чтобы открыть исполняемый файл в Рефлекторе придется совершить ещё одно нехитрое действие, а именно — исправить заголовки. Сделать это можно двумя способами:
1. Погуглить мануал по распаковке .NET Reactor за авторством CodeRipper’a и сделать всё руками.
2. Воспользоваться этим фиксером от dx’a.

Но после открытия получившегося файла в рефлекторе мы увидим «пустые» методы в самых интересных местах:

Чтобы не вникать в особенности (я ужасный лентяй), обратимся к ещё одному полезному инструменту CodeRipper’a — Reactor Decryptor. Соответственно открываем программу в нём, деобфусцируем приложение, а уже потом обрабатываем его фиксером заголовков. Полученный файл можно спокойно открыть в рефлекторе и посмотреть код интересующего нас метода.

Единственная неприятность — строки в нечитабельном виде. Но и это не составляет проблемы, просто открываем файл в программе Simple Assembly Explorer, переходим к интересующему методу и используем встроенный деобфускатор. Перед нами

Как понять, когда протектор износился и шины пора менять


искомые строки:

Сопоставив строки и код несложно понять, что софт делает GET-запрос вида:
http://actualspam.ru/getAuth.php?key=******

И если в ответе сервера содержится строка true, и IP сервера 195.211.101.8, то софт успешно активируется. Всего в коде два метода с проверкой активации: в классе frmActivation и в классе frmMain.
Таким образом, «активировать» программу можно, например, перехватив вызовы winapi-функций connect и recv, или просто поправив нужные опкоды (править следует экзешник, полученный после деобфускации с помощью Reactor Decryptor, но до применения фиксера заголовков).
Опкоды правятся с помощью любого удобного HEX-редактора. Места, которые необходимо править, можно по-быстрому найти с помощью IDA. Вот одна из проверок на наличие строки true в ответе сервера (проверки можно найти, вбив 0xb4fc и 0xcba в поиск):

Далее переключаемся на вкладку HexView, копируем последовательность байт, вбиваем в поиск в HEX-редакторе и находим нужное место (наверное, можно как-то проще сделать). В данном случае можно поменять в обеих функциях проверки опкод 0x39 (brfalse) на 0x3A (brtrue) или забить часть кода NOP’ами, или ещё как-нибудь извернуться (список опкодов CIL).
Теперь программа активируется при вводе произвольного кода.

Конечно, в .NET Reactor есть разные опции защиты, но разбор содержимого защищенного файла обычно не составляет проблемы.
P.S. А вообще весь этот софт «рекламной» направленности — зло. По мне уж лучше продавцом в магазине работать (кем я и работаю) и смотреть South Park и прочие мультики.

Читайте также:
Как устанавливать программы на virtualbox

Автор Kaimi Опубликовано 7 ноября, 2010 17 ноября, 2010 Рубрики C#, Социальные сети Метки actualspampro, c++, CIL, ida, net reactor, reflector

Источник: kaimi.io

Введение в реверсинг

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

— Что такое PE сканнер ?

> Это софт, который поможет тебе, мой юный реверсер — определить на чём нарисована твоя » подопытная » программа ( в нашем случае — чит ), узнать, каким протектором она накрыта. Функций много, как и PE сканеров, перечислять всё не буду. Лично я — использую : » ExeInfo PE » и » Detect it Easy» ( DIE ) . Выглядят они как-то так :

Перетащив софт на форму » ExeInfo PE » мы можем увидеть :

Итак, в сканнере оказался исполняемый файл Темиды, накрытый Темидой. ( да, да,именно так ) Кратко пройдёмся по главному :
Надпись : » Image is 32bit executable » — означает, что файл по дефолту скомпилирован под 32 битные системы.
Чуть ниже мы видим две строки, взглянем на первую : » Themida/Winlicense v.2.x. ( NonSt. OEP code detector «dummy» )

сканер показал, что файл накрыт Темидой версии 2+, и указал на сайт ее производителя. Ниже мы можем увидеть следующие слова : » No Unpacker, ля-ля-ля » . Сканер говорит нам, что распаковать файл, накрытый темидой — невозможно. Он нас обманывает, но не об этом. Перенесём тот-же файл на форму » DIE » , и увидим :

Здесь — аналогичная картина, но указан компилятор программы. С PE Сканнерами мы разобрались, теперь давайте поговорим о декомпиляции чистых .net файлов. Для примера возьму рандомную программу-чит, множество которых мы можем найти на просторах ютуба.

Отлично. Сканер заявляет, что это .net файл, не накрытый каким-либо протектором. Теперь нам нужно его декомпилировать. Софта для декомпиляции .net файлов — много. Лично я использую » dnSpy «, что советую делать и вам.

Ниже я покажу, как с помощью него вытащить исходный код с данного файла. Открываем » dnSpy » , перетаскиваем туда наш файлик :

Вот и подъехали наши исходники. Как и предполагалось вместо «чита» нам подсунули обычный майнер криптовалют.

Теперь поговорим о файлах под протекторами. Протекторов наплодилось очень много, сейчас я расскажу о снятии некоторых. Если в сканнере мы видим, что файл накрыт одним из следующих протекторов :

  • Agile.NET (aka CliSecure)
  • Babel.NET
  • CodeFort
  • CodeVeil
  • CodeWall
  • CryptoObfuscator
  • DeepSea Obfuscator
  • Dotfuscator
  • .NET Reactor
  • Eazfuscator.NET
  • Goliath.NET
  • ILProtector
  • MaxtoCode
  • MPRESS
  • Rummage
  • Skater.NET
  • SmartAssembly
  • Spices.Net
  • Xenocode

Значит, нам поможет такая утилита, как » de4dot «, она проста, и очень эффективна. Мне лень искать файл под протектором/накрывать файл самому, так-что, я возьму старое изображение.
Собственно после того, как мы поставили » de4dot » , перетаскиваем обфусцированный файл на его ехешник ( de4dot’a ) , и видим :

Рядом с обфусцированным файлом создаётся уже чистый файл с приставкой » cleaned » , круто, протектор снят ( если он был один, перестрахуйтесь ). Пихаем файл в декомпилятор, и получаем долгожданные исходы.
—————————————————————————————————————————————————————————————————-
На этом всё, я дал вам базовые знания в сфере реверсинга .net файлов, рассказал о софте для работы. Этих знаний критически мало для взлома серьёзных приложений, если отклик будет хорошим — я напишу статью, в которой мы подробнее углубимся в эту тему. Всем удачи! Спасибо, что уделили время.

Источник: dzen.ru

Гайд [Reverse-Engineering] Анализ и сравнение VMProtect 2 с VMProtect 3 (x64)

Статья делится на две части: первая часть была сделана ещё в августе, вторая — сегодня вечером 🙂
Причина такому долгому простою послужила учёба и много-много прочей рутины, даже сейчас я не обладаю каким-либо большим запасом времени, поэтому я просто дополнил материал в статье, не могу сказать, что это полностью завершённая статья.

— Благодарности
За помощь в дополнительной и полезной информации я обязан нескольким источникам информации

back.engineering/17/05/2021/ t.me/battleyeblog (Сеня давал информацию о хендлерах и Control Flow) katyscode.wordpress.com/2021/01/23/reverse-engineering-adventures-vmprotect-control-flow-obfuscation-case-study-string-algorithm-cryptanalysis-in-honkai-impact-3rd/

— Предисловие
Во многих P2C проектах я видел, что люди в основном абузят слитую лицензию VMProtect 3.5 с билдом 1213, поэтому в некоторых моментах, где есть отличия я буду сравнивать две версии — 3.5 и 3.6.
Также весь дизассемблированный код, который я прикладываю будет в основном очищен от джанк-кода, исключениями выступают демонстрации джанк-кода в виртуальной машине.

Читайте также:
Программа которая играет по нотам на пианино

— Информация о протекторах
VMProtect 3.5 — билд 1213 (Слитая лицензия)
VMProtect 3.6 — билд 1406 (Слитая лицензия)

— Обработчики виртуальной машины

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

Входы в VM были статичны в том плане, что их можно было найти по паттерну и начиная с VMProtect 3.6 этот паттерн частично ломается. Частично, потому что в 3.6 можно всё ещё составить правильный паттерн для нахождения входов в VM Entry.

Сравним вход в VM у 3.5 и 3.6 версии:

VMProtect 3.5:

push 2A95E159 call 7FF6EA991D85
VMProtect 3.6:
00007FF760C7106B | PUSH R14 | 00007FF760C7106D | PUSH R15 | 00007FF760C7106F | CALL vmprotect36.vmp.7FF760C7570C | 00007FF760C7570C | PUSHFQ | 00007FF760C7570D | MOV R14,58AC28AC3F68476C | 00007FF760C75717 | ADD QWORD PTR SS:[RSP+8],FFFFFFFFBFFFEF8C | 00007FF760C75727 | MOV R15,6E740BAA45855371 | 00007FF760C75731 | JGE vmprotect36.vmp.7FF760C752E2 | 00007FF760C752E6 | MOV R14,QWORD PTR SS:[RSP+18] | 00007FF760C752EB | MOV QWORD PTR SS:[RSP+18],FFFFFFFFF60D74C5 | 00007FF760C752FD | CALL vmprotect36.vmp.7FF760C7108B | 00007FF760C7108B | CALL vmprotect36.vmp.7FF760C75302 | 00007FF760C75302 | PUSH R11 | 00007FF760C75304 | MOV R11,2D4D16365288609E | 00007FF760C7530E | MOVSX R11D,R11W | 00007FF760C75312 | MOV R15,QWORD PTR SS:[RSP+28] | 00007FF760C75317 | TEST R11D,E1508A5 | 00007FF760C7531E | JL vmprotect36.vmp.7FF760C7532C | 00007FF760C75333 | MOV R11,QWORD PTR SS:[RSP] | 00007FF760C75338 | CALL vmprotect36.vmp.7FF760C75881 |
Второй метод входа в VM для 3.6:
00007FF650C151F5 | MOV QWORD PTR SS:[RSP],FFFFFFFFF44BB4F8 | 00007FF650C151FE | CALL vmprotect36.vmp.7FF650C15269 | 00007FF650C15269 | PUSH 36241C98 | 00007FF650C1526E | CALL vmprotect36.vmp.7FF650C158BE | 00007FF650C158BE | MOV WORD PTR SS:[RSP+8],231E | 00007FF650C158C5 | PUSH R13 | 00007FF650C158C7 | CALL vmprotect36.vmp.7FF650C150D4 | 00007FF650C150D4 | PUSHFQ | 00007FF650C150D5 | MOV R13,QWORD PTR SS:[RSP+20] | 00007FF650C150DA | MOV R13,QWORD PTR SS:[RSP+10] | 00007FF650C150DF | AND WORD PTR SS:[RSP+20],289E | 00007FF650C150E6 | SUB WORD PTR SS:[RSP+20],4E | 00007FF650C150ED | JL vmprotect36.vmp.7FF650C150FC | 00007FF650C150F3 | ADD QWORD PTR SS:[RSP+8],FFFFFFFFBFFFA734 | 00007FF650C150FC | CMP QWORD PTR SS:[RSP+20],8B23C7D | 00007FF650C15105 | NOT WORD PTR SS:[RSP+20] | 00007FF650C1510A | PUSH QWORD PTR SS:[RSP] | 00007FF650C1510E | POPFQ | 00007FF650C1510F | LEA RSP,QWORD PTR SS:[RSP+30] | 00007FF650C15114 | CALL vmprotect36.vmp.7FF650CD2288 |

После перехода в VM Entry нас встречает декрипт адреса следующего блока с кодом, которому программа передаст управление. Естественно, всё это также будет окутано джанк-кодом.

00007FF6D1341DED | mov rdx, 7FF5912A0000 ; Вшивает результат (Base Address — Image Base) 00007FF6D1341E09 | mov r8, qword ptr ss:[rsp+90]

Для х64 двоичных файлов зашифрованный относительный виртуальный адрес всегда будет находится по адресу RSP+90, это так же относится и к 3.6 версии.

00007FF6D1341E16 | bswap r8d | Начало расшифровки адреса 00007FF6D1341E19 | sar al,cl | 00007FF6D1341E1B | sar di,58 | 00007FF6D1341E1F | xadd cx,bp | 00007FF6D1341E23 | neg r8d | 00007FF6D1341E26 | dec r8d | 00007FF6D1341E29 | rcl r10,E3 | 00007FF6D1341E2D | movsx di,sil | 00007FF6D1341E32 | sbb bpl,FA | 00007FF6D1341E36 | xor r8d,261F7AAB | 00007FF6D1341E3D | cmc | 00007FF6D1341E3E | ror r8d,1 |

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

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

00007FF6D1341E16 | add ebp, 2594586D ; Второй метод расшифровки адреса 00007FF6D1341E19 | neg ebp 00007FF6D1341E1B | inc ebp 00007FF6D1341E1F | rol ebp,1 00007FF6D1341E2D | add rbp, r10 ; Конец расшифровки 00007FF6D1341E45 | lea r8,qword ptr ds:[r8+rdx] | 00007FF6D1341E49 | bts ecx,r12d | 00007FF6D1341E52 | mov rax,100000000 | 00007FF6D1341E5F | lea r8,qword ptr ds:[r8+rax] | 00007FF6D1341E66 | sub rsp,180 | Выравнивание стека 00007FF6D1341E74 | and rsp,FFFFFFFFFFFFFFF0 |

У основного алгоритма тоже есть два метода расшифровки следующего хендлера

00007FF6D1341E7B | mov rdi,r8 | 00007FF6D1341E83 | mov r9,7FF5912A0000 | 00007FF6D1341E8D | ror r10b,26 | 00007FF6D1341E91 | sub rdi,r9 | 00007FF6D1341E94 | sbb ecx,50BC75E8 | 00007FF6D1341E9A | cmp r14b,69 | 00007FF6D1341E9E | sub r10b,cl | 00007FF6D1341EA1 | lea r10,qword ptr ds:[7FF6D1341EA1] | 00007FF6D1341EAF | mov ecx,dword ptr ds:[r8] | 00007FF6D1341EB6 | add r8,4 | 00007FF6D1341EBD | xor ecx,edi | 00007FF6D135082C | inc ecx | 00007FF6D1350833 | not ecx | 00007FF6D1350835 | bswap ecx | 00007FF6D1350837 | add ecx,7E0005C8 | 00007FF6D135083E | push rdi | 00007FF6D135083F | xor dword ptr ss:[rsp],ecx | 00007FF6D135084F | pop rdi | 00007FF6D1350850 | movsxd rcx,ecx |
Второй метод:
00007FF6EF52103D | mov r10d, dword ptr ds:[rdi] | 00007FF6EF58C876 | xor r10d, r11d | 00007FF6EF58C879 | neg r10d | 00007FF6EF58C87C | rol r10d, 1 | 00007FF6EF4CBDDF | add r10d,47BC214D | 00007FF6EF4CBDE7 | neg r10d | 00007FF6EF4C064A | not r10d | 00007FF6EF530B38 | dec r10d | 00007FF6EF530B3B | xor r10d,433320D7 | 00007FF6EF530B46 | sub r10d,29F1797C | 00007FF6EF530B55 | push r11 | 00007FF6EF530B62 | xor dword ptr ss:[rsp],r10d | 00007FF6EF530B6A | pop r11 | 00007FF6EF530B6C | movsxd r10,r10d |

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

Читайте также:
Составить блок схему и написать программу вычисления функции пользователя

Первый метод:

add r8, r10 ; Вычисляем адрес jmp r8 ; Прыгаем по адресу в R8
Второй метод:
add r10, rcx ; Вычисляем адрес push r10 ; Помещаем адрес в стек retп ; Передаем управление адресу, который положили в стек

— Обфускация смешанной булевой арифметики

Обфускация смешанной булевой арифметики — это метод для выполнения сохраняющего семантику преобразования из простого выражения в представление, которое в дальнейшем тяжело представить во время анализа. В дальнейшем я буду использовать аббревиатуру — MBA (Mixed-Boolean-Arithmetic Obfuscation).

Рассмотрим обфускацию по подробнее как раз на примере таргета под VMProtect.

— Инструкция Sub

Объясню вкратце начало обфускации: Берется первый операнд и инвертируется инструкцией NOT.

Думаю стоит разъяснить как именно работает эта инструкция на очень простом примере. Зачем? Дело в том, что информация об этой инструкции поможет нам понять принцип работы обфусцированного SUB и других ребилднутых по ходу статьи.

Инструкция NOT — это логическое отрицание одного единственного операнда, он инвертирует каждый бит операнда.

Представим число в RDX — 0x1337, в битах это будет представлено как 0001001100110111. И затем инструкция NOT инвертирует каждый бит, т.е. 0 в 1, а 1 в 0. И получим в результате мы
1110110011001000. А если перевести полученное значение в hex, то у нас получится — 0xECC8.

Возьмем за пример: 4183 — 2000, чтобы не путаться: 4183 — в hex это 0x1057, а 2000 — 0x7D0

Как я уже и сказал выше операнд, в котором хранится число 4183 будет инвертировано в 0xEFA8, но протектор за собой в регистр тащит и 0xFFFF, поэтому в результате получается 0xFFFFEFA8, к этому числу плюсуется уже нетронутая 2000.
После операции добавления мы получим 0x00000000FFFFF778, думаю вы уже догадались, что дальше будет делать протектор 🙂

Это почти, что конец ребилда. Число 0xFFFFF778 попадет под инструкцию NOT и мы получим в результате наше заветное число — 2183, в hex это будет 0x883.

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

mov r10, dwFirstOp mov rcx, dwSecondOp not r10 add r10, rcx not r10d mov dwFirstOp, r10

Во всех представленных инструкциях я так же буду показывать и сишный код, и вот код Sub:

DWORD VMProtect::Arithmetic::ManualSub( DWORD dwFirstOp, DWORD dwSecondOp )

— Инструкция Xor

Вспоминаем основы дискретной математики. Xor — операция исключающего ИЛИ. Сравниваются все биты двух операндов между собой, в результате 1 бит может записаться только в том случае, если сравниваемые биты не были равны друг другу. Пример:

Первый операнд Второй Результат 0 XOR 0 = 0 0 XOR 1 = 1 1 XOR 0 = 1 1 XOR 1 = 0

Теперь посмотри как VMProtect смог ребилднуть эту инструкцию.

Сам конец операции выглядит таким образом:

not edx not r11d and edx, r11d

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

1671833863323.png

До выполнения операции NOT на EDX и R11D хранились значения 0xFFFFE828 и 0x50. Если еще с первым числом понятно, что до этого над ним повторно выполнялась инструкция NOT, то с 0x50 ничего не понятно. Начинаем снова просматривать дизасм код.

И попадаем на следующий код:

invert_operands.png

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

0xFFFFE828.png

После and edx, r11d в регистр edx будет записано число FFFFE828, то самое число, которое мы встретили в конце операции ксора, в дальнейшем это значение будет хранится в указателе.

Теперь попробуем понять откуда взялось 0x50, первой мыслью у меня было, что это число было преобразовано после операции первого и второго операнда, оставалось только понять где именно это происходит. Чуть позже я нашел этот код и оказался прав, 0x50 получился в результате инструкции AND EDX, R11D. Где в EDX хранилось число 0x1057, а в R11D — 0x7D0.

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

mov edx, dwFirstOp mov r11, dwSecondOp mov eax, edx ; Резервируем первый операнд and edx, r11d ; Получаем третье число mov ecx, edx ; Пихаем третье число в ecx mov edx, eax ; Восстанавливаем первый операнд

Источник: yougame.biz

Рейтинг
( Пока оценок нет )
Загрузка ...
EFT-Soft.ru