[ << ALL_FEED ]

Деобфусцируем имена функций .NET вручную

Ещё в группе «Общее»

Деобфусцируем имена функций .NET вручную 🙌

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

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

Откроем бинарь в dnSpy и увидим следующую картину (скриншот 1).

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

>  de4dotex .\sample.bin -vvCode language: plaintext (plaintext)


Результат на скриншоте 2.

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

🐍Попробуем сделать это на питоне, используя связку dnfile и dncil, набросав код для сбора обфусцированных имен функций и полей (скриншот 3).

Теперь необходимо написать логику по патчингу имен непосредственно в бинаре. Однако, есть момент, связанный с тем, что…такой функциональности у dncil нет.

Перепишем то же самое на C#, позаимствовав dnlib.dll у de4dot, дабы не страдать с самостоятельной ее сборкой. А чтобы не путаться среди кучи меню Visual Studio, просто приведем .csproj к следующему виду (требуется .Net 4.8 и его SDK):

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net48</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
  <LangVersion>10.0</LangVersion>
    <Nullable>enable</Nullable>
    <OutputType>Exe</OutputType>
  </PropertyGroup>
  <ItemGroup>
    <Reference Include="dnlib">
      <HintPath>dnlib.dll</HintPath>
    </Reference>
  </ItemGroup>
</Project>Code language: plaintext (plaintext)


Заведем класс Utils, с двумя функциями — проверкой валидности имени и формированием нового имени (скриншот 4). Наконец, опишем основную логику по переименованию типов, методов, свойств, полей и событий классов (скриншот 5). Результат прогона программы представлен на скриншоте 6.

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

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

👀 Резюмируя вышеописанное: dncil — удобен, если требуется кроссплатформенность и отсутствует потребность в модификации данных. Таковой, например, является задача поиска конструктора, заполняющего конфигурацию ВПО.

В альтернативном случае можно сразу обращаться к dnlib или инструментам на его основе.

Happy reversing!


#TI #reverse #malware #tip
@ptescalator

Ещё от ti_author

Ещё от ti_author

Ещё в группе «Общее»