<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://kzhong-sec.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://kzhong-sec.github.io/" rel="alternate" type="text/html" /><updated>2025-09-22T22:42:49+10:00</updated><id>https://kzhong-sec.github.io/feed.xml</id><title type="html">Kevin Johnson’s Security Blog</title><subtitle>Welcome to my blog, where I will be posting things I am doing related to malware analysis and reverse engineering.</subtitle><entry><title type="html">BlackMatter Ransomware Analysis</title><link href="https://kzhong-sec.github.io/2025/09/09/Blackmatter-analysis-main.html" rel="alternate" type="text/html" title="BlackMatter Ransomware Analysis" /><published>2025-09-09T00:00:00+10:00</published><updated>2025-09-09T00:00:00+10:00</updated><id>https://kzhong-sec.github.io/2025/09/09/Blackmatter-analysis-main</id><content type="html" xml:base="https://kzhong-sec.github.io/2025/09/09/Blackmatter-analysis-main.html"><![CDATA[<h1 id="blackmatter-ransomware-analysis">BlackMatter Ransomware Analysis</h1>

<h2 id="table-of-contents">Table of Contents</h2>

<ul>
  <li><a href="#overview">Overview</a></li>
  <li><a href="#configuration-security-and-extraction">Configuration security and extraction</a>
    <ul>
      <li><a href="#main-configuration-automated-extraction">Main configuration automated extraction</a></li>
      <li><a href="#other-encrypted-and-encoded-items">Other encrypted and encoded items</a></li>
    </ul>
  </li>
  <li><a href="#sample-functionality">Sample Functionality</a>
    <ul>
      <li><a href="#1-api-resolution">1. API Resolution</a></li>
      <li><a href="#2-configuration-loading--privilege-escalation">2. Configuration Loading &amp; Privilege Escalation</a></li>
      <li><a href="#3-cli-parsing--dispatch">3. CLI Parsing &amp; Dispatch</a>
        <ul>
          <li><a href="#try-lateral-movement-via-network-shares">Try lateral movement via network shares</a></li>
          <li><a href="#try-lateral-movement-via-gpo">Try lateral movement via GPO</a></li>
          <li><a href="#loaded-eraser-executable">Loaded eraser executable</a></li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

<h2 id="overview">Overview</h2>

<p>This is my analysis of a BlackMatter sample I pulled from MalwareBazaar which focuses on the malware’s configuration, some of its functionality and how I approached analysing it.</p>

<p>SHA256: <code class="language-plaintext highlighter-rouge">374f9df39b92ccccae8a9b747e606aebe0ddaf117f8f6450052efb5160c99368</code></p>

<p>First Seen In The Wild: <em>2025-08-13 07:05:26 UTC</em></p>

<p>Loaded Files Sha256:</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">63c8efca0f52ebea1b3b2305e17580402f797a90611b3507fab6fffa7f700383</code></li>
  <li><code class="language-plaintext highlighter-rouge">d641ad955ef4cff5f0239072b3990d47e17b9840e07fd5feea93c372147313c5</code></li>
  <li><code class="language-plaintext highlighter-rouge">185f6d6bf0ddcd39f253413f28c0d12f46a82e663bdf6287cb73a362a33c91e7</code></li>
</ul>

<p>All scripts I utilised during my analysis are available on my Github <a href="https://github.com/Kzhong-sec/Blackmatter-scripts/tree/master">here</a>.</p>
<h2 id="configuration-security-and-extraction">Configuration security and extraction</h2>

<h3 id="main-configuration-automated-extraction">Main configuration automated extraction</h3>

<p>The main configuration is encrypted with a custom stream cipher and also compressed using Aplib. 
Some parts of the configuration are still encrypted or encoded even after this, and they are decrypted on the fly instead of all at once.</p>

<p>The custom decryptor uses the key as a seed for a PRNG (deterministic) function that produces 8 bytes of a keystream at a time. 
Once the keystream is used up, the resulting subkeys are fed back into the PRNG function. 
A portion of this PRNG function is inside shellcode that the file loads, presumably to hide the constants it uses.</p>

<p><img src="/assets/BlackMatter/cust_decrypt.png" alt="Custom Decryptor" />
<img src="/assets/BlackMatter/prng.png" alt="prng" /></p>

<p>In addition to decrypting the main configuration, this was frequently used for decryption of other pieces of data.</p>

<p>For the extractor I decided to just copy out the assembly code and assemble/compile it as a DLL so I could call from Python. It was sort of annoying to emulate it with Unicorn given that the PRNG generator was in shellcode and also this allowed me to patch the assembly slightly. The key was actually embedded as a global within the encryption function, however I patched it so that it could be passed in as an argument to the function, thus allowing the decryptor to be much more modular for different samples.</p>

<p><em>You can use the Create ASM file utility from IDA to do this. You just need to modify the assembly so that the syntax matches the assembler you use - I used FASM</em></p>

<p><img src="/assets/BlackMatter/fasm.png" alt="fasm" /></p>

<p><em>As the DLL function is made with raw assembly Python aficionados might notice how odd it looks to utilise an immutable type (bytes) in what appears to be a pass by reference, as Python will typically do a copy on modification with immutable objects and its ‘pass by assignment’ model. Here is an amusing test I did.</em></p>

<p><img src="/assets/BlackMatter/same_object.png" alt="fasm" /></p>

<p>The configuration is then Aplib decompressed, so I grabbed a decompression routine from <a href="https://github.com/snemes/aplib/blob/master/src/aplib.py">here</a> - Credit <em>snemes</em></p>

<p>Following this the configuration flags used by the sample will be resolved, however some parts are still base64 encoded. It stores an array of index values, which are used to index into the configuration which references the base64 strings.</p>

<p>For the automated extraction of the configuration I relied on the fact that there was a ‘.pdata’ section with the layout.</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">struct</span> <span class="n">config</span><span class="p">{</span>
<span class="n">BYTE</span> <span class="n">key</span><span class="p">[</span><span class="mi">8</span><span class="p">]</span>
<span class="n">DWORD</span> <span class="n">size</span>
<span class="n">BYTE</span> <span class="n">encBuffer</span><span class="p">[]</span>
<span class="p">}</span>
</code></pre></div></div>

<p>I made the following C struct for an approximation of the configuration.</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">struct</span> <span class="n">struct_425120</span>
<span class="p">{</span>
  <span class="kt">char</span> <span class="n">rsa_pub</span> <span class="n">key</span><span class="p">[</span><span class="mi">128</span><span class="p">]</span>
  <span class="kt">char</span> <span class="n">something_with_c2</span> <span class="n">something</span><span class="p">[</span><span class="mi">32</span><span class="p">]</span>
  <span class="kt">char</span> <span class="n">unk0_conf_flag</span><span class="p">;</span>
  <span class="kt">char</span> <span class="n">replace_with_random_file_name_conf_flag</span><span class="p">;</span>
  <span class="kt">char</span> <span class="n">find_domain_admins_conf_flag</span><span class="p">;</span>
  <span class="kt">char</span> <span class="n">skip_hidden_files_conf_flag</span><span class="p">;</span>
  <span class="kt">char</span> <span class="n">check_Russian_language_conf_flag</span><span class="p">;</span>
  <span class="kt">char</span> <span class="n">encrypt_local_files_conf_flag</span><span class="p">;</span>
  <span class="kt">char</span> <span class="n">encrypt_network_shares_conf_flag</span><span class="p">;</span>
  <span class="kt">char</span> <span class="n">kills_processes_within_config_hashes_conf_flag</span><span class="p">;</span>
  <span class="kt">char</span> <span class="n">kill_services_within_service_hashes_conf_flag</span><span class="p">;</span>
  <span class="kt">char</span> <span class="n">check_run_once_mutex_conf_flag</span><span class="p">;</span>
  <span class="kt">char</span> <span class="n">print_ransom_note_on_printer_conf_flag</span><span class="p">;</span>
  <span class="kt">char</span> <span class="n">set_ransom_wallpaper_conf_flag</span><span class="p">;</span>
  <span class="kt">char</span> <span class="n">set_default_icon_conf_flag</span><span class="p">;</span>
  <span class="kt">char</span> <span class="n">contact_c2_conf_flag</span><span class="p">;</span>
  <span class="kt">char</span> <span class="n">load_worker_for_secure_erase_conf__flag</span><span class="p">;</span>
  <span class="kt">char</span> <span class="n">delete_services_inline_hashes_conf_flag</span><span class="p">;</span>
  <span class="kt">char</span> <span class="n">load_worker_overwrite_all_data_on_disk_conf_flag</span><span class="p">;</span>
  <span class="kt">char</span> <span class="n">try_lateral_movement_via_network_shares_conf_flag</span><span class="p">;</span>
  <span class="kt">char</span> <span class="n">try_lateral_movement_via_GPO_conf_flag</span><span class="p">;</span>
  <span class="kt">char</span> <span class="n">push_GPO_updates_immediately_conf_flag</span><span class="p">;</span>
  <span class="kt">char</span> <span class="n">load_worker_shutdown_system_conf_flag</span><span class="p">;</span>
  <span class="kt">char</span> <span class="n">disable_delete_logging_conf_flag</span><span class="p">;</span>
  <span class="kt">char</span> <span class="o">*</span><span class="n">b64_decoded_hash_whitelisted_directories</span><span class="p">;</span>
  <span class="kt">char</span> <span class="o">*</span><span class="n">b64_decoded_hash_whitelisted_filename</span><span class="p">;</span>
  <span class="kt">char</span> <span class="o">*</span><span class="n">b64_decoded_hash_whitelisted_file_extensions</span><span class="p">;</span>
  <span class="kt">char</span> <span class="o">*</span><span class="n">b64_decoded_hashed_computer_names</span><span class="p">;</span>
  <span class="kt">wchar_t</span> <span class="o">*</span><span class="n">b64_decoded_processes_to_kill_string_list</span><span class="p">;</span>
  <span class="kt">char</span> <span class="o">*</span><span class="n">b64_services_strings</span><span class="p">;</span>
  <span class="kt">char</span> <span class="o">*</span><span class="n">b64_c2_domains_53</span><span class="p">;</span>
  <span class="kt">char</span> <span class="o">*</span><span class="n">b64_decoded_default_credentials_for_brute_force_54</span><span class="p">;</span>
  <span class="kt">char</span> <span class="o">*</span><span class="n">b64_decoded_ransom_note_54</span><span class="p">;</span>
<span class="p">};</span>
</code></pre></div></div>

<p><em>main class of extractor</em></p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="kn">import</span> <span class="n">ctypes</span>
<span class="kn">import</span> <span class="n">struct</span>
<span class="kn">import</span> <span class="n">os</span>
<span class="kn">import</span> <span class="n">base64</span>

<span class="kn">import</span> <span class="n">pefile</span>
<span class="kn">from</span> <span class="n">.</span> <span class="kn">import</span> <span class="n">aplib</span>

<span class="k">class</span> <span class="nc">BlackMatterDecryptor</span><span class="p">():</span>
    <span class="sh">"""</span><span class="s">
    Decryptor and parser for BlackMatter ransomware samples.

    Usage:

    1. Automatic key &amp; config extraction:
       - The first 8 bytes of the pdata section are used as the key.
       - The bytes following that are used as the config data.
       - Simply call `decrypt_config()` then `extract_all()` after creating an instance.

    2. Manual key &amp; config supply:
       - Pass `key` and `config_va` in the constructor if the config is stored differently.
       - Then call `decrypt_config()`.

    3. Accessing only the custom decryptor:
       - Pass in a key value set the `config_va` argument to 0, to use `cust_decrypt_wrapper()` or `cust_decrypt()` directly.
       - You can also attempt to extract the key and config VA via `extract_from_section_at()`.
    </span><span class="sh">"""</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">sampleFpathAbsolute</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">key</span><span class="p">:</span><span class="nb">bytes</span> <span class="o">=</span> <span class="bp">None</span><span class="p">,</span> <span class="n">config_va</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span><span class="bp">None</span><span class="p">):</span>
        <span class="n">self</span><span class="p">.</span><span class="n">pe</span> <span class="o">=</span> <span class="n">pefile</span><span class="p">.</span><span class="nc">PE</span><span class="p">(</span><span class="n">sampleFpathAbsolute</span><span class="p">)</span>

        <span class="n">self</span><span class="p">.</span><span class="n">data</span> <span class="o">=</span> <span class="n">self</span><span class="p">.</span><span class="n">pe</span><span class="p">.</span><span class="n">__data__</span>
        
        <span class="k">try</span><span class="p">:</span>
            <span class="n">self</span><span class="p">.</span><span class="n">key</span> <span class="o">=</span> <span class="n">key</span> <span class="k">if</span> <span class="n">key</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span> <span class="k">else</span> <span class="n">self</span><span class="p">.</span><span class="nf">extract_key</span><span class="p">()</span>
        <span class="k">except</span> <span class="nb">LookupError</span><span class="p">:</span>
            <span class="n">self</span><span class="p">.</span><span class="n">key</span> <span class="o">=</span> <span class="bp">None</span>
            <span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">Warning: Could not automatically extract the key.</span><span class="se">\n</span><span class="s">Please provide it manually to use decryption functions.</span><span class="se">\n</span><span class="s">Other functionality is still available.</span><span class="sh">"</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">config_va</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span>
            <span class="n">self</span><span class="p">.</span><span class="n">config_va</span> <span class="o">=</span> <span class="n">self</span><span class="p">.</span><span class="nf">get_segment_va</span><span class="p">(</span><span class="sa">b</span><span class="sh">'</span><span class="s">.pdata</span><span class="sh">'</span><span class="p">)</span> <span class="o">+</span> <span class="mi">12</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">self</span><span class="p">.</span><span class="n">config_va</span> <span class="o">=</span> <span class="n">config_va</span>

        <span class="n">self</span><span class="p">.</span><span class="n">decrypted_main_config</span> <span class="o">=</span> <span class="bp">None</span>
        <span class="n">self</span><span class="p">.</span><span class="n">b64_decoded</span> <span class="o">=</span> <span class="bp">None</span>
        <span class="n">self</span><span class="p">.</span><span class="n">conflig_flags</span> <span class="o">=</span> <span class="bp">None</span>

        <span class="c1">#char *enc[in, out - encrypts in place] , int32 size_in_bytes, char* key_buffer
</span>        <span class="c1">#in the actual assembly, the keybuffer is hardcoded into the function, I modified it a bit so you could pass it in as an argument
</span>        <span class="n">script_dir</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="nf">dirname</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="nf">realpath</span><span class="p">(</span><span class="n">__file__</span><span class="p">))</span>
        <span class="n">dll_path</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="n">script_dir</span><span class="p">,</span> <span class="sh">"</span><span class="s">decrypt.dll</span><span class="sh">"</span><span class="p">)</span>
        <span class="n">bmatter_decrypt</span> <span class="o">=</span> <span class="n">ctypes</span><span class="p">.</span><span class="nc">WinDLL</span><span class="p">(</span><span class="n">dll_path</span><span class="p">)</span>
        <span class="n">self</span><span class="p">.</span><span class="n">decryptor</span> <span class="o">=</span> <span class="n">bmatter_decrypt</span><span class="p">.</span><span class="n">bmatter_decrypt</span>

    <span class="k">def</span> <span class="nf">extract_key</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">segment_name_with_config</span><span class="p">:</span> <span class="nb">bytes</span> <span class="o">=</span> <span class="sa">b</span><span class="sh">'</span><span class="s">.pdata</span><span class="sh">'</span><span class="p">):</span>
        <span class="n">va</span> <span class="o">=</span> <span class="n">self</span><span class="p">.</span><span class="nf">get_segment_va</span><span class="p">(</span><span class="n">segment_name_with_config</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">self</span><span class="p">.</span><span class="nf">get_bytes_at</span><span class="p">(</span><span class="n">va</span><span class="p">,</span> <span class="mi">8</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">get_bytes_at</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">va</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">size</span><span class="p">:</span> <span class="nb">int</span><span class="p">):</span>
        <span class="n">rva</span> <span class="o">=</span> <span class="n">va</span> <span class="o">-</span> <span class="n">self</span><span class="p">.</span><span class="n">pe</span><span class="p">.</span><span class="n">OPTIONAL_HEADER</span><span class="p">.</span><span class="n">ImageBase</span>
        <span class="n">file_offset</span> <span class="o">=</span> <span class="n">self</span><span class="p">.</span><span class="n">pe</span><span class="p">.</span><span class="nf">get_offset_from_rva</span><span class="p">(</span><span class="n">rva</span><span class="p">)</span>
    
        <span class="k">return</span> <span class="n">self</span><span class="p">.</span><span class="n">data</span><span class="p">[</span><span class="n">file_offset</span><span class="p">:</span><span class="n">file_offset</span> <span class="o">+</span> <span class="n">size</span><span class="p">]</span>

    <span class="k">def</span> <span class="nf">cust_decrypt</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">enc_buffer</span><span class="p">:</span> <span class="nb">bytes</span><span class="p">,</span> <span class="n">size</span><span class="p">:</span> <span class="nb">int</span><span class="p">):</span>
        <span class="n">self</span><span class="p">.</span><span class="nf">decryptor</span><span class="p">(</span><span class="n">enc_buffer</span><span class="p">,</span> <span class="n">size</span><span class="p">,</span> <span class="n">self</span><span class="p">.</span><span class="n">key</span><span class="p">)</span>
        <span class="n">decrypted</span> <span class="o">=</span> <span class="n">enc_buffer</span>

        <span class="k">return</span> <span class="n">decrypted</span>
    
    <span class="k">def</span> <span class="nf">extract_from_section_at</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">segment_name</span><span class="p">:</span> <span class="nb">bytes</span><span class="p">):</span>
        <span class="n">self</span><span class="p">.</span><span class="n">config_va</span> <span class="o">=</span> <span class="n">self</span><span class="p">.</span><span class="nf">get_segment_va</span><span class="p">(</span><span class="n">segment_name</span><span class="p">)</span> <span class="o">+</span> <span class="mi">12</span>
        <span class="n">self</span><span class="p">.</span><span class="n">key</span> <span class="o">=</span> <span class="n">self</span><span class="p">.</span><span class="nf">extract_key</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">segment_name</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">get_segment_va</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">name</span><span class="p">:</span> <span class="nb">bytes</span><span class="p">):</span>
        <span class="n">va</span> <span class="o">=</span> <span class="bp">None</span>

        <span class="k">for</span> <span class="n">section</span> <span class="ow">in</span> <span class="n">self</span><span class="p">.</span><span class="n">pe</span><span class="p">.</span><span class="n">sections</span><span class="p">:</span>
            <span class="k">if</span> <span class="n">section</span><span class="p">.</span><span class="n">Name</span><span class="p">.</span><span class="nf">strip</span><span class="p">(</span><span class="sa">b</span><span class="sh">'</span><span class="se">\x00</span><span class="sh">'</span><span class="p">)</span> <span class="o">==</span> <span class="n">name</span><span class="p">:</span>
                <span class="n">va</span> <span class="o">=</span> <span class="n">self</span><span class="p">.</span><span class="n">pe</span><span class="p">.</span><span class="n">OPTIONAL_HEADER</span><span class="p">.</span><span class="n">ImageBase</span> <span class="o">+</span> <span class="n">section</span><span class="p">.</span><span class="n">VirtualAddress</span>
                <span class="k">break</span>
        <span class="k">if</span> <span class="n">va</span><span class="p">:</span>
            <span class="k">return</span> <span class="n">va</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">error_message</span> <span class="o">=</span> <span class="sa">f</span><span class="sh">"</span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s"> segment not found in the PE file</span><span class="sh">"</span>
            <span class="k">for</span> <span class="n">section</span> <span class="ow">in</span> <span class="n">self</span><span class="p">.</span><span class="n">pe</span><span class="p">.</span><span class="n">sections</span><span class="p">:</span>
                <span class="k">if</span> <span class="n">name</span> <span class="ow">in</span> <span class="n">section</span><span class="p">.</span><span class="n">Name</span><span class="p">.</span><span class="nf">strip</span><span class="p">(</span><span class="sa">b</span><span class="sh">'</span><span class="se">\x00</span><span class="sh">'</span><span class="p">):</span>
                    <span class="n">error_message</span> <span class="o">+=</span> <span class="sa">f</span><span class="sh">"</span><span class="se">\n</span><span class="s">Did you mean </span><span class="si">{</span><span class="n">section</span><span class="p">.</span><span class="n">Name</span><span class="p">.</span><span class="nf">strip</span><span class="p">(</span><span class="sa">b</span><span class="sh">'</span><span class="se">\x00</span><span class="sh">'</span><span class="p">)</span><span class="si">}</span><span class="s">?</span><span class="sh">"</span>
            <span class="k">raise</span> <span class="nc">LookupError</span><span class="p">(</span><span class="n">error_message</span><span class="p">)</span>
        
    <span class="k">def</span> <span class="nf">cust_decrypt_wrapper</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">address_of_encrypted</span><span class="p">:</span> <span class="nb">int</span><span class="p">):</span>
        <span class="sh">"""</span><span class="s">
        This is for when the sample uses the wrapper function for its custom decryptor. It passes the encrypted buffer as an offset, and the prior dword is the size.
        The adress should be the encrypted buffer address, not the address where the size is stored, as that is how it</span><span class="sh">'</span><span class="s">s called within the sample
        </span><span class="sh">"""</span>
        <span class="n">size</span> <span class="o">=</span> <span class="n">struct</span><span class="p">.</span><span class="nf">unpack</span><span class="p">(</span><span class="sh">"</span><span class="s">&lt;I</span><span class="sh">"</span><span class="p">,</span> <span class="n">self</span><span class="p">.</span><span class="nf">get_bytes_at</span><span class="p">(</span><span class="n">address_of_encrypted</span> <span class="o">-</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">4</span><span class="p">))[</span><span class="mi">0</span><span class="p">]</span>
        <span class="n">enc_buffer</span> <span class="o">=</span> <span class="n">self</span><span class="p">.</span><span class="nf">get_bytes_at</span><span class="p">(</span><span class="n">address_of_encrypted</span><span class="p">,</span> <span class="n">size</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">self</span><span class="p">.</span><span class="nf">cust_decrypt</span><span class="p">(</span><span class="n">enc_buffer</span><span class="p">,</span> <span class="n">size</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">decrypt_config</span><span class="p">(</span><span class="n">self</span><span class="p">):</span>
        <span class="sh">"""</span><span class="s">
        The sample I was analyzing stored it</span><span class="sh">'</span><span class="s">s config in a segment called b</span><span class="sh">'</span><span class="s">.pdata</span><span class="sh">'</span><span class="s">, with specific offsets for the keys, sizes and config data. Will need to adjust the default args if it does not do this.
        </span><span class="sh">"""</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="n">self</span><span class="p">.</span><span class="n">config_va</span><span class="p">:</span>
            <span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">Must apply the config_va attribute!</span><span class="sh">"</span><span class="p">)</span>
            <span class="k">return</span>
        <span class="n">self</span><span class="p">.</span><span class="n">decrypted_main_config</span> <span class="o">=</span> <span class="n">aplib</span><span class="p">.</span><span class="nf">aplib_decompress</span><span class="p">(</span><span class="n">self</span><span class="p">.</span><span class="nf">cust_decrypt_wrapper</span><span class="p">(</span><span class="n">self</span><span class="p">.</span><span class="n">config_va</span><span class="p">))</span>
        <span class="k">return</span> <span class="n">self</span><span class="p">.</span><span class="n">decrypted_main_config</span>
    
    <span class="k">def</span> <span class="nf">extract_public_rsa</span><span class="p">(</span><span class="n">self</span><span class="p">):</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="n">self</span><span class="p">.</span><span class="n">config_va</span><span class="p">:</span>
            <span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">Must apply the config_va attribute!</span><span class="sh">"</span><span class="p">)</span>
            <span class="k">return</span>
        <span class="n">self</span><span class="p">.</span><span class="n">rsa</span> <span class="o">=</span> <span class="p">{</span><span class="sh">"</span><span class="s">RSA Public</span><span class="sh">"</span> <span class="p">:</span> <span class="n">self</span><span class="p">.</span><span class="n">decrypted_main_config</span><span class="p">[:</span><span class="mi">128</span><span class="p">].</span><span class="nf">hex</span><span class="p">()}</span>
        <span class="k">return</span> <span class="n">self</span><span class="p">.</span><span class="n">rsa</span>


    <span class="k">def</span> <span class="nf">extract_config_flags</span><span class="p">(</span><span class="n">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">dict</span><span class="p">:</span>
        <span class="k">if</span> <span class="n">self</span><span class="p">.</span><span class="n">decrypted_main_config</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span>
            <span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">Configuration must be decrypted first</span><span class="sh">"</span><span class="p">)</span>
            <span class="k">return</span> <span class="bp">None</span>
        <span class="c1">#config_flags_offset = 160
</span>        <span class="n">config_flags</span> <span class="o">=</span> <span class="p">{</span>
            <span class="sh">'</span><span class="s">unk1</span><span class="sh">'</span> <span class="p">:</span> <span class="n">self</span><span class="p">.</span><span class="n">decrypted_main_config</span><span class="p">[</span><span class="mi">160</span><span class="p">],</span>
            <span class="sh">'</span><span class="s">Replace with random file name</span><span class="sh">'</span> <span class="p">:</span> <span class="n">self</span><span class="p">.</span><span class="n">decrypted_main_config</span><span class="p">[</span><span class="mi">161</span><span class="p">],</span>
            <span class="sh">'</span><span class="s">Find Domain Admins</span><span class="sh">'</span> <span class="p">:</span> <span class="n">self</span><span class="p">.</span><span class="n">decrypted_main_config</span><span class="p">[</span><span class="mi">162</span><span class="p">],</span>
            <span class="sh">'</span><span class="s">Skip hidden files</span><span class="sh">'</span> <span class="p">:</span> <span class="n">self</span><span class="p">.</span><span class="n">decrypted_main_config</span><span class="p">[</span><span class="mi">163</span><span class="p">],</span>
            <span class="sh">'</span><span class="s">Check for Russian Keyboard Layout</span><span class="sh">'</span> <span class="p">:</span> <span class="n">self</span><span class="p">.</span><span class="n">decrypted_main_config</span><span class="p">[</span><span class="mi">164</span><span class="p">],</span>
            <span class="sh">'</span><span class="s">Encrypt local files</span><span class="sh">'</span> <span class="p">:</span> <span class="n">self</span><span class="p">.</span><span class="n">decrypted_main_config</span><span class="p">[</span><span class="mi">165</span><span class="p">],</span>
            <span class="sh">'</span><span class="s">Encrypt network shares</span><span class="sh">'</span> <span class="p">:</span> <span class="n">self</span><span class="p">.</span><span class="n">decrypted_main_config</span><span class="p">[</span><span class="mi">166</span><span class="p">],</span>
            <span class="sh">'</span><span class="s">Kill processes within config process hashes</span><span class="sh">'</span> <span class="p">:</span> <span class="n">self</span><span class="p">.</span><span class="n">decrypted_main_config</span><span class="p">[</span><span class="mi">167</span><span class="p">],</span>
            <span class="sh">'</span><span class="s">Kill services within config services hashes</span><span class="sh">'</span> <span class="p">:</span> <span class="n">self</span><span class="p">.</span><span class="n">decrypted_main_config</span><span class="p">[</span><span class="mi">168</span><span class="p">],</span>
            <span class="sh">'</span><span class="s">Load worker executable for secure self erase</span><span class="sh">'</span> <span class="p">:</span> <span class="n">self</span><span class="p">.</span><span class="n">decrypted_main_config</span><span class="p">[</span><span class="mi">169</span><span class="p">],</span>
            <span class="sh">'</span><span class="s">Deploy ransom notes on printer</span><span class="sh">'</span> <span class="p">:</span> <span class="n">self</span><span class="p">.</span><span class="n">decrypted_main_config</span><span class="p">[</span><span class="mi">170</span><span class="p">],</span>
            <span class="sh">'</span><span class="s">Create ransom wallpaper</span><span class="sh">'</span> <span class="p">:</span> <span class="n">self</span><span class="p">.</span><span class="n">decrypted_main_config</span><span class="p">[</span><span class="mi">171</span><span class="p">],</span>
            <span class="sh">'</span><span class="s">Set BlackMatter default icon</span><span class="sh">'</span> <span class="p">:</span> <span class="n">self</span><span class="p">.</span><span class="n">decrypted_main_config</span><span class="p">[</span><span class="mi">172</span><span class="p">],</span>
            <span class="sh">'</span><span class="s">Contact C2</span><span class="sh">'</span> <span class="p">:</span> <span class="n">self</span><span class="p">.</span><span class="n">decrypted_main_config</span><span class="p">[</span><span class="mi">173</span><span class="p">],</span>
            <span class="sh">'</span><span class="s">Load worker executable for secure self erase</span><span class="sh">'</span> <span class="p">:</span> <span class="n">self</span><span class="p">.</span><span class="n">decrypted_main_config</span><span class="p">[</span><span class="mi">174</span><span class="p">],</span>
            <span class="sh">'</span><span class="s">Kill services from inline hashes</span><span class="sh">'</span> <span class="p">:</span> <span class="n">self</span><span class="p">.</span><span class="n">decrypted_main_config</span><span class="p">[</span><span class="mi">175</span><span class="p">],</span>
            <span class="sh">'</span><span class="s">Load worker to overwrite all data on disk</span><span class="sh">'</span> <span class="p">:</span> <span class="n">self</span><span class="p">.</span><span class="n">decrypted_main_config</span><span class="p">[</span><span class="mi">176</span><span class="p">],</span>
            <span class="sh">'</span><span class="s">Try lateral movement via network shares</span><span class="sh">'</span> <span class="p">:</span> <span class="n">self</span><span class="p">.</span><span class="n">decrypted_main_config</span><span class="p">[</span><span class="mi">177</span><span class="p">],</span>
            <span class="sh">'</span><span class="s">Try lateral movement via GPO</span><span class="sh">'</span> <span class="p">:</span> <span class="n">self</span><span class="p">.</span><span class="n">decrypted_main_config</span><span class="p">[</span><span class="mi">178</span><span class="p">],</span>
            <span class="sh">'</span><span class="s">Push GPO updates immediately</span><span class="sh">'</span> <span class="p">:</span> <span class="n">self</span><span class="p">.</span><span class="n">decrypted_main_config</span><span class="p">[</span><span class="mi">179</span><span class="p">],</span>
            <span class="sh">'</span><span class="s">Load worker to shutdown system</span><span class="sh">'</span> <span class="p">:</span> <span class="n">self</span><span class="p">.</span><span class="n">decrypted_main_config</span><span class="p">[</span><span class="mi">180</span><span class="p">],</span>
            <span class="sh">'</span><span class="s">Disable and delete event logs</span><span class="sh">'</span> <span class="p">:</span>  <span class="n">self</span><span class="p">.</span><span class="n">decrypted_main_config</span><span class="p">[</span><span class="mi">181</span><span class="p">],</span>
            <span class="sh">'</span><span class="s">unk8</span><span class="sh">'</span> <span class="p">:</span> <span class="n">self</span><span class="p">.</span><span class="n">decrypted_main_config</span><span class="p">[</span><span class="mi">182</span><span class="p">],</span>
            <span class="p">}</span>
        <span class="n">self</span><span class="p">.</span><span class="n">conflig_flags</span> <span class="o">=</span> <span class="n">config_flags</span>
        <span class="k">return</span> <span class="n">config_flags</span>


    <span class="k">def</span> <span class="nf">decode_base64_strings</span><span class="p">(</span><span class="n">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">dict</span><span class="p">:</span>
        <span class="sh">"""</span><span class="s">
        Returns the dword offset from the decrypted configuration that referenced the base 64 string and the base64 string in a list of tuples.
        </span><span class="sh">"""</span>
        <span class="k">if</span> <span class="n">self</span><span class="p">.</span><span class="n">decrypted_main_config</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span>
            <span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">Configuration must be decrypted first</span><span class="sh">"</span><span class="p">)</span>
            <span class="k">return</span> <span class="bp">None</span>
        <span class="n">b64_conf_start</span> <span class="o">=</span> <span class="mi">184</span>
        <span class="n">array_of_b64_str_idx_size</span> <span class="o">=</span> <span class="mi">10</span>
        
        <span class="n">configDwordOffset_b64Decoded</span> <span class="o">=</span> <span class="p">[]</span>
        <span class="k">for</span> <span class="n">b64_idx</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="n">b64_conf_start</span><span class="p">,</span> <span class="p">(</span><span class="n">b64_conf_start</span><span class="o">+</span><span class="n">array_of_b64_str_idx_size</span><span class="o">*</span><span class="mi">4</span><span class="p">),</span> <span class="mi">4</span><span class="p">):</span>
            <span class="n">offset</span> <span class="o">=</span> <span class="n">struct</span><span class="p">.</span><span class="nf">unpack</span><span class="p">(</span><span class="sh">"</span><span class="s">&lt;I</span><span class="sh">"</span><span class="p">,</span> <span class="n">self</span><span class="p">.</span><span class="n">decrypted_main_config</span><span class="p">[</span><span class="n">b64_idx</span><span class="p">:</span><span class="n">b64_idx</span><span class="o">+</span><span class="mi">4</span><span class="p">])[</span><span class="mi">0</span><span class="p">]</span>
            <span class="k">if</span> <span class="n">offset</span><span class="p">:</span>
                <span class="n">offset</span> <span class="o">+=</span> <span class="mi">184</span> <span class="c1"># The indexes are at config base + 184
</span>                <span class="n">decoded_b64</span> <span class="o">=</span> <span class="n">base64</span><span class="p">.</span><span class="nf">b64decode</span><span class="p">(</span><span class="n">self</span><span class="p">.</span><span class="n">decrypted_main_config</span><span class="p">[</span><span class="n">offset</span><span class="p">:])</span>
                <span class="n">configDwordOffset_b64Decoded</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">decoded_b64</span><span class="p">)</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="n">configDwordOffset_b64Decoded</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>


        <span class="c1"># whitelisted directory hashes
</span>        <span class="k">if</span> <span class="n">configDwordOffset_b64Decoded</span><span class="p">[</span><span class="mi">0</span><span class="p">]:</span>
            <span class="n">configDwordOffset_b64Decoded</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="nf">hex</span><span class="p">(</span><span class="n">item</span><span class="p">)</span> <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">self</span><span class="p">.</span><span class="nf">_raw_hashlist_to_hashes</span><span class="p">(</span><span class="n">configDwordOffset_b64Decoded</span><span class="p">[</span><span class="mi">0</span><span class="p">])]</span>

        <span class="c1">#whitelisted filename hashes
</span>        <span class="k">if</span> <span class="n">configDwordOffset_b64Decoded</span><span class="p">[</span><span class="mi">1</span><span class="p">]:</span>
            <span class="n">configDwordOffset_b64Decoded</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="nf">hex</span><span class="p">(</span><span class="n">item</span><span class="p">)</span> <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">self</span><span class="p">.</span><span class="nf">_raw_hashlist_to_hashes</span><span class="p">(</span><span class="n">configDwordOffset_b64Decoded</span><span class="p">[</span><span class="mi">1</span><span class="p">])]</span>

        <span class="c1">#whitelisted file extension hashes
</span>        <span class="k">if</span> <span class="n">configDwordOffset_b64Decoded</span><span class="p">[</span><span class="mi">2</span><span class="p">]:</span>
            <span class="n">configDwordOffset_b64Decoded</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="nf">hex</span><span class="p">(</span><span class="n">item</span><span class="p">)</span> <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">self</span><span class="p">.</span><span class="nf">_raw_hashlist_to_hashes</span><span class="p">(</span><span class="n">configDwordOffset_b64Decoded</span><span class="p">[</span><span class="mi">2</span><span class="p">])]</span>

        <span class="c1"># computers whitelisted from rebooting in safemode
</span>        <span class="k">if</span> <span class="n">configDwordOffset_b64Decoded</span><span class="p">[</span><span class="mi">3</span><span class="p">]:</span>
            <span class="n">configDwordOffset_b64Decoded</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="nf">hex</span><span class="p">(</span><span class="n">item</span><span class="p">)</span> <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">self</span><span class="p">.</span><span class="nf">_raw_hashlist_to_hashes</span><span class="p">(</span><span class="n">configDwordOffset_b64Decoded</span><span class="p">[</span><span class="mi">3</span><span class="p">])]</span>


        <span class="c1"># I don't know what 4 is, the array element didn't exist in the sample I looked at.
</span>
        <span class="c1"># processes to kill
</span>        <span class="k">if</span> <span class="n">configDwordOffset_b64Decoded</span><span class="p">[</span><span class="mi">5</span><span class="p">]:</span>
            <span class="n">configDwordOffset_b64Decoded</span><span class="p">[</span><span class="mi">5</span><span class="p">]</span> <span class="o">=</span> <span class="n">self</span><span class="p">.</span><span class="nf">_extract_unicode</span><span class="p">(</span><span class="n">configDwordOffset_b64Decoded</span><span class="p">[</span><span class="mi">5</span><span class="p">])</span>
   
        <span class="k">if</span> <span class="n">configDwordOffset_b64Decoded</span><span class="p">[</span><span class="mi">6</span><span class="p">]:</span>
            <span class="n">configDwordOffset_b64Decoded</span><span class="p">[</span><span class="mi">6</span><span class="p">]</span> <span class="o">=</span> <span class="n">self</span><span class="p">.</span><span class="nf">_extract_unicode</span><span class="p">(</span><span class="n">configDwordOffset_b64Decoded</span><span class="p">[</span><span class="mi">6</span><span class="p">])</span>

        <span class="c1"># C2 domains
</span>        <span class="k">if</span> <span class="n">configDwordOffset_b64Decoded</span><span class="p">[</span><span class="mi">7</span><span class="p">]:</span>
            <span class="n">configDwordOffset_b64Decoded</span><span class="p">[</span><span class="mi">7</span><span class="p">]</span> <span class="o">=</span> <span class="sh">"</span><span class="s">Extraction method unknown for this element</span><span class="sh">"</span>


        <span class="c1"># Credentials for brute force
</span>        <span class="k">if</span> <span class="n">configDwordOffset_b64Decoded</span><span class="p">[</span><span class="mi">8</span><span class="p">]:</span>
            <span class="n">configDwordOffset_b64Decoded</span><span class="p">[</span><span class="mi">8</span><span class="p">]</span> <span class="o">=</span> <span class="n">self</span><span class="p">.</span><span class="nf">cust_decrypt</span><span class="p">(</span><span class="n">configDwordOffset_b64Decoded</span><span class="p">[</span><span class="mi">8</span><span class="p">],</span> <span class="nf">len</span><span class="p">(</span><span class="n">configDwordOffset_b64Decoded</span><span class="p">[</span><span class="mi">8</span><span class="p">])).</span><span class="nf">decode</span><span class="p">(</span><span class="sh">'</span><span class="s">utf-16</span><span class="sh">'</span><span class="p">)</span>

        
        <span class="c1"># ransom note
</span>        <span class="k">if</span> <span class="n">configDwordOffset_b64Decoded</span><span class="p">[</span><span class="mi">9</span><span class="p">]:</span>
            <span class="n">configDwordOffset_b64Decoded</span><span class="p">[</span><span class="mi">9</span><span class="p">]</span> <span class="o">=</span> <span class="n">self</span><span class="p">.</span><span class="nf">cust_decrypt</span><span class="p">(</span><span class="n">configDwordOffset_b64Decoded</span><span class="p">[</span><span class="mi">9</span><span class="p">],</span> <span class="nf">len</span><span class="p">(</span><span class="n">configDwordOffset_b64Decoded</span><span class="p">[</span><span class="mi">9</span><span class="p">])).</span><span class="nf">decode</span><span class="p">()</span>

        <span class="n">not_present_string</span> <span class="o">=</span> <span class="sh">"</span><span class="s">Not present in sample</span><span class="sh">"</span>

        <span class="n">configDwordOffset_b64Decoded</span> <span class="o">=</span> <span class="p">[</span><span class="n">item</span> <span class="k">if</span> <span class="n">item</span> <span class="k">else</span> <span class="n">not_present_string</span> <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">configDwordOffset_b64Decoded</span><span class="p">]</span>
    
        <span class="n">decoded</span> <span class="o">=</span> <span class="p">{</span><span class="sh">'</span><span class="s">Hashes of whitelisted directories</span><span class="sh">'</span><span class="p">:</span> <span class="n">configDwordOffset_b64Decoded</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span>
                   <span class="sh">'</span><span class="s">Hashes of whitelisted files</span><span class="sh">'</span> <span class="p">:</span> <span class="n">configDwordOffset_b64Decoded</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span>
                   <span class="sh">'</span><span class="s">Hashes of whitelisted file extensions</span><span class="sh">'</span> <span class="p">:</span> <span class="n">configDwordOffset_b64Decoded</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span>
                   <span class="sh">'</span><span class="s">Hashes of computer names to not reboot in Safe Mode</span><span class="sh">'</span> <span class="p">:</span> <span class="n">configDwordOffset_b64Decoded</span><span class="p">[</span><span class="mi">3</span><span class="p">],</span>
                   <span class="sh">'</span><span class="s">Processes to kill</span><span class="sh">'</span> <span class="p">:</span> <span class="n">configDwordOffset_b64Decoded</span><span class="p">[</span><span class="mi">5</span><span class="p">],</span>
                   <span class="sh">'</span><span class="s">Services to kill</span><span class="sh">'</span> <span class="p">:</span> <span class="n">configDwordOffset_b64Decoded</span><span class="p">[</span><span class="mi">6</span><span class="p">],</span>
                   <span class="sh">'</span><span class="s">C2 Domains</span><span class="sh">'</span> <span class="p">:</span> <span class="n">configDwordOffset_b64Decoded</span><span class="p">[</span><span class="mi">7</span><span class="p">],</span>
                   <span class="sh">'</span><span class="s">Credentials for brute force</span><span class="sh">'</span> <span class="p">:</span> <span class="n">configDwordOffset_b64Decoded</span><span class="p">[</span><span class="mi">8</span><span class="p">],</span>
                   <span class="sh">'</span><span class="s">Ransom Note</span><span class="sh">'</span> <span class="p">:</span> <span class="n">configDwordOffset_b64Decoded</span><span class="p">[</span><span class="mi">9</span><span class="p">]</span>
                   <span class="p">}</span>

        <span class="n">self</span><span class="p">.</span><span class="n">b64_decoded</span> <span class="o">=</span> <span class="n">decoded</span>        
        <span class="k">return</span> <span class="n">decoded</span>    

    
    <span class="k">def</span> <span class="nf">extract_all</span><span class="p">(</span><span class="n">self</span><span class="p">):</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="n">self</span><span class="p">.</span><span class="n">b64_decoded</span><span class="p">:</span>
            <span class="n">self</span><span class="p">.</span><span class="nf">decode_base64_strings</span><span class="p">()</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="n">self</span><span class="p">.</span><span class="n">conflig_flags</span><span class="p">:</span>
            <span class="n">self</span><span class="p">.</span><span class="nf">extract_config_flags</span><span class="p">()</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="n">self</span><span class="p">.</span><span class="nf">extract_public_rsa</span><span class="p">():</span>
            <span class="n">self</span><span class="p">.</span><span class="nf">extract_public_rsa</span><span class="p">()</span>
        <span class="n">self</span><span class="p">.</span><span class="n">extracted_all</span> <span class="o">=</span> <span class="n">self</span><span class="p">.</span><span class="n">rsa</span> <span class="o">|</span> <span class="n">self</span><span class="p">.</span><span class="n">conflig_flags</span> <span class="o">|</span> <span class="n">self</span><span class="p">.</span><span class="n">b64_decoded</span>
        <span class="k">return</span> <span class="n">self</span><span class="p">.</span><span class="n">extracted_all</span>
        


    <span class="k">def</span> <span class="nf">_raw_hashlist_to_hashes</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">hashlist</span><span class="p">:</span> <span class="nb">bytes</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">list</span><span class="p">[</span><span class="nb">int</span><span class="p">]:</span>
        <span class="n">hashes</span> <span class="o">=</span> <span class="p">[</span><span class="n">hashlist</span><span class="p">[</span><span class="n">i</span><span class="p">:</span><span class="n">i</span><span class="o">+</span><span class="mi">4</span><span class="p">]</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nf">len</span><span class="p">(</span><span class="n">hashlist</span><span class="p">),</span> <span class="mi">4</span><span class="p">)]</span>
        <span class="n">hashes</span> <span class="o">=</span> <span class="p">[</span><span class="n">struct</span><span class="p">.</span><span class="nf">unpack</span><span class="p">(</span><span class="sh">"</span><span class="s">&lt;I</span><span class="sh">"</span><span class="p">,</span> <span class="nb">hash</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span> <span class="k">for</span> <span class="nb">hash</span> <span class="ow">in</span> <span class="n">hashes</span><span class="p">]</span>
        <span class="n">hashes</span> <span class="o">=</span> <span class="p">[</span><span class="nb">hash</span> <span class="k">for</span> <span class="nb">hash</span> <span class="ow">in</span> <span class="n">hashes</span> <span class="k">if</span> <span class="nb">hash</span><span class="p">]</span>
        <span class="k">return</span> <span class="n">hashes</span>
    
    <span class="k">def</span> <span class="nf">_extract_unicode</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">data</span><span class="p">:</span> <span class="nb">bytes</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">list</span><span class="p">[</span><span class="nb">str</span><span class="p">]:</span>
        <span class="n">chunks</span> <span class="o">=</span> <span class="p">[]</span>
        <span class="n">current</span> <span class="o">=</span> <span class="p">[]</span>
        <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nf">len</span><span class="p">(</span><span class="n">data</span><span class="p">),</span> <span class="mi">2</span><span class="p">):</span>  <span class="c1"># UTF-16 uses 2 bytes per char
</span>            <span class="k">try</span><span class="p">:</span>
                <span class="n">char</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="n">i</span><span class="p">:</span><span class="n">i</span><span class="o">+</span><span class="mi">2</span><span class="p">].</span><span class="nf">decode</span><span class="p">(</span><span class="sh">'</span><span class="s">utf-16</span><span class="sh">'</span><span class="p">)</span>
                <span class="n">current</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">char</span><span class="p">)</span>
            <span class="k">except</span> <span class="nb">UnicodeDecodeError</span><span class="p">:</span>
                <span class="k">if</span> <span class="n">current</span><span class="p">:</span>
                    <span class="n">chunks</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="sh">''</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="n">current</span><span class="p">))</span>
                    <span class="n">current</span> <span class="o">=</span> <span class="p">[]</span>

        <span class="k">if</span> <span class="n">current</span><span class="p">:</span>
            <span class="n">chunks</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="sh">''</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="n">current</span><span class="p">))</span>
        <span class="n">strings_list</span> <span class="o">=</span> <span class="p">[</span><span class="n">s</span> <span class="k">for</span> <span class="n">s</span> <span class="ow">in</span> <span class="n">chunks</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nf">split</span><span class="p">(</span><span class="sh">'</span><span class="se">\x00</span><span class="sh">'</span><span class="p">)</span> <span class="k">if</span> <span class="n">s</span><span class="p">]</span>
        <span class="k">return</span> <span class="n">strings_list</span>
</code></pre></div></div>

<p><em>output</em></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>{
    "RSA Public": "2f536b62fcda35a2a22a8ed1d6b8baff81a37a32abd39e0af2301024fd6e1ad116ddb3925bfbe7482a340dd2ed2edd7e62e00f6e17f38dd6a3e3fddf81695b7ecaba1cf5d0c4a3595a94ac395ed7ed87fb107670df1a8c2d32663c18a39b89cbf309599ac104a816d680845bb2d1f1df789310c65c15d5b49d7eec3d03386d61",
    "unk1": 1,
    "Replace with random file name": 0,
    "Find Domain Admins": 1,
    "Skip hidden files": 0,
    "Check for Russian Keyboard Layout": 0,
    "Encrypt local files": 1,
    "Encrypt network shares": 1,
    "Kill processes within config process hashes": 1,
    "Kill services within config services hashes": 1,
    "Load worker executable for secure self erase": 1,
    "Deploy ransom notes on printer": 1,
    "Create ransom wallpaper": 1,
    "Set BlackMatter default icon": 1,
    "Contact C2": 0,
    "Kill services from inline hashes": 1,
    "Load worker to overwrite all data on disk": 0,
    "Try lateral movement via network shares": 0,
    "Try lateral movement via GPO": 1,
    "Push GPO updates immediately": 1,
    "Load worker to shutdown system": 0,
    "Disable and delete event logs": 1,
    "unk8": 1,
    "Hashes of whitelisted directories": [
        "0x30a212d",
        "0x8cf281cd",
        "0x267078f5",
        "0x26687e35",
        "0xe3426cd7",
        "0xe1a63bc0",
        "0x36004e4e",
        "0xab086595",
        "0x2e75e394",
        "0xae018eae",
        "0x4c4b25d4",
        "0x7f07935",
        "0x6b66f975",
        "0xb7ea3892",
        "0x5366e694",
        "0xcd1b589b",
        "0x5cde3a7b",
        "0xba22623b",
        "0xef3a37b3",
        "0xcc72be18",
        "0x86ccaa15",
        "0x3907099b",
        "0xf00cae96",
        "0xfcc8ab56",
        "0x82d2a252",
        "0x846bec00",
        "0xdb975937",
        "0xc23aa6f5",
        "0x85aa57e4",
        "0xcbe2aa35",
        "0xc8cef7d1",
        "0x6b6b1a7",
        "0xb0cad2f3"
    ],
    "Hashes of whitelisted files": [
        "0x86ccaa15",
        "0x3907099b",
        "0xf00cae96",
        "0xfcc8ab56",
        "0x82d2a252",
        "0x846bec00",
        "0xdb975937",
        "0xc23aa6f5",
        "0x85aa57e4",
        "0xcbe2aa35",
        "0xc8cef7d1",
        "0x6b6b1a7",
        "0xb0cad2f3"
    ],
    "Hashes of whitelisted file extensions": [
        "0x67b00e00",
        "0xc5b01900",
        "0xc5481b80",
        "0xc7a01840",
        "0xc7701a40",
        "0xc9101840",
        "0xc9201b40",
        "0xc9681bc0",
        "0xc9601c00",
        "0xc9901d40",
        "0xa1fccbfe",
        "0x4aba94f1",
        "0x4ae29631",
        "0x64e29771",
        "0xcb601b00",
        "0xcbb01c80",
        "0xcd281e00",
        "0xd3801b00",
        "0xd56018c0",
        "0xc99eab80",
        "0xd57818c0",
        "0xd59818c0",
        "0xd5c01900",
        "0xdb301900",
        "0xdb581b80",
        "0xdd201bc0",
        "0xdd081c00",
        "0xdd181cc0",
        "0xdd801cc0",
        "0x4a6bb7db",
        "0xdda81cc0",
        "0xdf981b00",
        "0x4cca7837",
        "0xe1c018c0",
        "0xe3301c80",
        "0xe1881cc0",
        "0xe7681bc0",
        "0xe7801d00",
        "0xe99018c0",
        "0xe9981a00",
        "0xe9601c00",
        "0xe9981e40",
        "0xcd2e9b7a",
        "0xaf16c593",
        "0xf1c01c00",
        "0xe15ed8c0",
        "0xd9c81940",
        "0xd3081d00",
        "0xdd481cc0",
        "0xe3101900",
        "0x446a3f92"
    ],
    "Hashes of computer names to not reboot in Safe Mode": [
        "0xe3a72c79"
    ],
    "Processes to kill": [
        "sql",
        "oracle",
        "ocssd",
        "dbsnmp",
        "synctime",
        "agntsvc",
        "isqlplussvc",
        "xfssvccon",
        "mydesktopservice",
        "ocautoupds",
        "encsvc",
        "firefox",
        "tbirdconfig",
        "mydesktopqos",
        "ocomm",
        "dbeng50",
        "sqbcoreservice",
        "excel",
        "infopath",
        "msaccess",
        "mspub",
        "onenote",
        "outlook",
        "powerpnt",
        "steam",
        "thebat",
        "thunderbird",
        "visio",
        "winword",
        "wordpad",
        "notepad",
        "calc",
        "wuauclt",
        "onedrive"
    ],
    "Services to kill": [
        "vss",
        "sql",
        "svc$",
        "memtas",
        "mepocs",
        "msexchange",
        "sophos",
        "veeam",
        "backup",
        "GxVss",
        "GxBlr",
        "GxFWD",
        "GxCVD",
        "GxCIMgr"
    ],
    "C2 Domains": "Not present in sample",
    "Credentials for brute force": "ad.lab:Qwerty!\u0000Administrator:123QWEqwe!@#\u0000Admin2:P@ssw0rd\u0000Administrator:P@ssw0rd\u0000Administrator:Qwerty!\u0000Administrator:123QWEqwe\u0000Administrator:123QWEqweqwe\u0000\u0000",
    "Ransom Note": "\r\nPersonal ID : [redacted]\r\n\r\n-----&gt; Your data is stolen and encrypted.\r\nIf you don't pay the ransom, the data will be published on our TOR darknet sites.\r\nThe sooner you pay the ransom, the sooner your company will be safe.\r\n\r\n-----&gt; What guarantees are that we won't fool you?\r\nWe are not a politically motivated group and we want nothing more than money.\r\nIf you pay, we will provide you with decryption software and destroy the stolen data.\r\nAfter you pay the ransom, you will quickly restore your systems and make even more money.\r\nTreat this situation simply as a paid training for your system administrators, because it is due to your corporate network not being properly configured that we were able to attack you.\r\nOur pentest services should be paid just like you pay the salaries of your system administrators. Get over it and pay for it.\r\nIf we don't give you a decryptor or delete your data after you pay, no one will pay us in the future.\r\n\r\n-----&gt; You need to contact us via TOX or email\r\n\r\nTOX_ID: [redacted]\r\nYou can contact us using Tox messenger without registration and SMS https://tox.chat/download.html. \r\n\tUsing Tox messenger, we will never know your real name, it means your privacy is guaranteed.\r\n\t\r\nemail: recovery_systems@mailum.com\r\n\r\nWrite to chat your personal ID (on 
the top of message)\r\n\r\n-----&gt; Warning! Don't delete or modify encrypted files, it will lead to problems with decryption of files!\r\n-----&gt; Don't go to the police or the FBI for help. They won't help you.\r\nThe police will try to prohibit you from paying the ransom in any way.\r\nThe first thing they will tell you is that there's no guarantee to decrypt your files and remove stolen files.\r\nThis is not true, we can do a test decryption before paying and your data will be guaranteed to be removed because it's a matter of our reputation.\r\nPaying the ransom to us is 
much cheaper and more profitable than paying fines and legal fees.\r\nThe police and the FBI don't care what losses you suffer as a result of our attack, and we'll help you get rid of all your problems for a modest sum of money.\r\nIf you're worried that someone will trace your bank transfers, you can easily buy cryptocurrency for cash, thus leaving no digital trail that someone from your company paid our ransom.\r\nThe police and FBI won't be able to stop lawsuits from your customers for leaking personal and private information.\r\nThe police and FBI won't protect you from repeated attacks. \r\n\r\n-----&gt; For those who have cyber insurance against ransomware attacks.\r\nInsurance companies require you to keep your insurance information secret.\r\nIn most cases, we find this information and download it."
}
</code></pre></div></div>
<p>Running the hashes through Hashdb produced the following:</p>

<p><strong>Whitelisted directories</strong></p>
<ul>
  <li>$recycle.bin</li>
  <li>config.msi</li>
  <li>$windows.~bt</li>
  <li>$windows.~ws</li>
  <li>windows</li>
  <li>boot</li>
  <li>program files (x86)</li>
  <li>programdata</li>
  <li>system volume information</li>
  <li>tor browser</li>
  <li>windows.old</li>
  <li>intel</li>
  <li>msocache</li>
  <li>perflogs</li>
  <li>x64dbg</li>
  <li>public</li>
  <li>default</li>
  <li>microsoft</li>
</ul>

<p><strong>Whitelisted files</strong></p>
<ul>
  <li>autorun.inf</li>
  <li>boot.ini</li>
  <li>bootfont.bin</li>
  <li>bootsect.bak</li>
  <li>desktop.ini</li>
  <li>iconcache.db</li>
  <li>ntldr</li>
  <li>ntuser.dat</li>
  <li>ntuser.dat.log</li>
  <li>ntuser.ini</li>
  <li>thumbs.db</li>
  <li>d3d9caps.dat</li>
</ul>

<p><strong>Whitelisted extensions</strong></p>
<ul>
  <li>386</li>
  <li>adv</li>
  <li>ani</li>
  <li>bat</li>
  <li>bin</li>
  <li>cab</li>
  <li>cmd</li>
  <li>com</li>
  <li>cpl</li>
  <li>cur</li>
  <li>deskthemepack</li>
  <li>diagcab</li>
  <li>diagcfg</li>
  <li>diagpkg</li>
  <li>dll</li>
  <li>drv</li>
  <li>exe</li>
  <li>hlp</li>
  <li>icl</li>
  <li>icns</li>
  <li>ico</li>
  <li>ics</li>
  <li>idx</li>
  <li>ldf</li>
  <li>lnk</li>
  <li>mod</li>
  <li>mpa</li>
  <li>msc</li>
  <li>msp</li>
  <li>msstyles</li>
  <li>ns5</li>
  <li>nls</li>
  <li>nomedia</li>
  <li>ocx</li>
  <li>prf</li>
  <li>ps1</li>
  <li>rom</li>
  <li>rtp</li>
  <li>tc2</li>
  <li>th3</li>
  <li>spl</li>
  <li>sys</li>
  <li>theme</li>
  <li>themepack</li>
  <li>wpx</li>
  <li>lock</li>
  <li>key</li>
  <li>hta</li>
  <li>msi</li>
  <li>pdb</li>
  <li>search-ms</li>
</ul>

<h3 id="other-encrypted-and-encoded-items">Other encrypted and encoded items</h3>

<p>The sample also utilised stack strings that were passed into a central function and xor’ed and not’ed.</p>

<p><img src="/assets/BlackMatter/stack_strings.png" alt="fasm" /></p>

<p>I made a script with the new IDA domain API for this.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">ida_domain</span>
<span class="kn">import</span> <span class="n">struct</span>
<span class="kn">import</span> <span class="n">string</span>

<span class="n">db</span> <span class="o">=</span> <span class="n">ida_domain</span><span class="p">.</span><span class="nc">Database</span><span class="p">()</span>

<span class="k">def</span> <span class="nf">extract_utf</span><span class="p">(</span><span class="n">data</span><span class="p">:</span> <span class="nb">bytes</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="n">decoded</span> <span class="o">=</span> <span class="n">data</span><span class="p">.</span><span class="nf">decode</span><span class="p">(</span><span class="sh">'</span><span class="s">utf-8</span><span class="sh">'</span><span class="p">)</span>
    <span class="k">except</span> <span class="nb">UnicodeDecodeError</span><span class="p">:</span>
        <span class="k">try</span><span class="p">:</span>
            <span class="n">decoded</span> <span class="o">=</span> <span class="n">data</span><span class="p">.</span><span class="nf">decode</span><span class="p">(</span><span class="sh">'</span><span class="s">utf-16</span><span class="sh">'</span><span class="p">)</span>
        <span class="k">except</span> <span class="nb">UnicodeDecodeError</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">None</span>
    <span class="k">if</span> <span class="nf">all</span><span class="p">(</span><span class="n">c</span> <span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="n">string</span><span class="p">.</span><span class="n">printable</span><span class="p">):</span>  <span class="c1"># All printable ASCII
</span>        <span class="n">decoded</span> <span class="o">=</span> <span class="sh">""</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="n">c</span> <span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="n">decoded</span> <span class="k">if</span> <span class="mi">32</span> <span class="o">&lt;=</span> <span class="nf">ord</span><span class="p">(</span><span class="n">c</span><span class="p">)</span> <span class="o">&lt;=</span> <span class="mi">126</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">decoded</span>
    <span class="k">else</span><span class="p">:</span> 
        <span class="k">return</span> <span class="bp">None</span>
        
<span class="k">def</span> <span class="nf">transform</span><span class="p">(</span><span class="n">data</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="nb">int</span><span class="p">],</span> <span class="n">xor_key</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">list</span><span class="p">[</span><span class="nb">int</span><span class="p">]:</span>
    <span class="c1"># data is a list of 32-bit integers
</span>    <span class="n">result</span> <span class="o">=</span> <span class="p">[]</span>
    <span class="k">for</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">data</span><span class="p">:</span>
        <span class="n">value</span> <span class="o">^=</span> <span class="n">xor_key</span>  <span class="o">&amp;</span> <span class="mh">0xFFFFFFFF</span> <span class="c1"># XOR
</span>        <span class="n">value</span> <span class="o">=</span> <span class="o">~</span><span class="n">value</span> <span class="o">&amp;</span> <span class="mh">0xFFFFFFFF</span>  <span class="c1"># Bitwise NOT, keep 32-bit
</span>        <span class="n">result</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">result</span>

<span class="k">def</span> <span class="nf">get_callers</span><span class="p">(</span><span class="n">func_ea</span><span class="p">):</span>
    <span class="k">return</span> <span class="p">[</span><span class="n">caller</span><span class="p">.</span><span class="n">frm</span> <span class="k">for</span> <span class="n">caller</span> <span class="ow">in</span> <span class="n">db</span><span class="p">.</span><span class="n">xrefs</span><span class="p">.</span><span class="nf">get_calls_to</span><span class="p">(</span><span class="n">func_ea</span><span class="p">)]</span>

<span class="k">def</span> <span class="nf">get_stack_string</span><span class="p">(</span><span class="n">caller</span><span class="p">):</span>
    <span class="n">size_address</span> <span class="o">=</span> <span class="n">db</span><span class="p">.</span><span class="n">heads</span><span class="p">.</span><span class="nf">get_prev</span><span class="p">(</span><span class="n">db</span><span class="p">.</span><span class="n">heads</span><span class="p">.</span><span class="nf">get_prev</span><span class="p">(</span><span class="n">caller</span><span class="p">))</span>
    <span class="n">size_insn</span> <span class="o">=</span> <span class="n">db</span><span class="p">.</span><span class="n">instructions</span><span class="p">.</span><span class="nf">get_at</span><span class="p">(</span><span class="n">size_address</span><span class="p">)</span>
    <span class="n">size</span> <span class="o">=</span> <span class="n">db</span><span class="p">.</span><span class="n">instructions</span><span class="p">.</span><span class="nf">get_operand</span><span class="p">(</span><span class="n">size_insn</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
    <span class="n">size</span> <span class="o">=</span> <span class="n">size</span><span class="p">.</span><span class="nf">get_value</span><span class="p">()</span>
    
    <span class="n">dwords</span> <span class="o">=</span> <span class="p">[]</span>
    <span class="n">cur_address</span> <span class="o">=</span> <span class="n">size_address</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span>
        <span class="k">while</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">size</span><span class="p">:</span>
            <span class="n">i</span> <span class="o">+=</span> <span class="mi">1</span>
            <span class="n">cur_address</span> <span class="o">=</span> <span class="n">db</span><span class="p">.</span><span class="n">heads</span><span class="p">.</span><span class="nf">get_prev</span><span class="p">(</span><span class="n">cur_address</span><span class="p">)</span>
            <span class="n">dword_insn</span> <span class="o">=</span> <span class="n">db</span><span class="p">.</span><span class="n">instructions</span><span class="p">.</span><span class="nf">get_at</span><span class="p">(</span><span class="n">cur_address</span><span class="p">)</span>
            <span class="k">if</span> <span class="n">db</span><span class="p">.</span><span class="n">instructions</span><span class="p">.</span><span class="nf">get_mnemonic</span><span class="p">(</span><span class="n">dword_insn</span><span class="p">)</span> <span class="o">!=</span> <span class="sh">"</span><span class="s">mov</span><span class="sh">"</span><span class="p">:</span>
                <span class="n">i</span> <span class="o">-=</span> <span class="mi">1</span>
                <span class="k">continue</span>
            <span class="n">dword</span> <span class="o">=</span> <span class="n">db</span><span class="p">.</span><span class="n">instructions</span><span class="p">.</span><span class="nf">get_operand</span><span class="p">(</span><span class="n">dword_insn</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
            <span class="n">dword</span> <span class="o">=</span> <span class="p">(</span><span class="n">dword</span><span class="p">.</span><span class="nf">get_value</span><span class="p">()</span> <span class="o">&amp;</span> <span class="mh">0xffffffff</span><span class="p">)</span>
            <span class="n">dwords</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">dword</span><span class="p">)</span>
            <span class="c1">#print(hex(dword))
</span>        <span class="c1">#print(hex(size_address))
</span>    <span class="nf">except </span><span class="p">(</span><span class="nb">AttributeError</span><span class="p">,</span> <span class="nb">TypeError</span><span class="p">):</span>
        <span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">"</span><span class="s">Unresolved Stack string at </span><span class="si">{</span><span class="nf">hex</span><span class="p">(</span><span class="n">size_address</span><span class="p">)</span><span class="si">}</span><span class="sh">"</span><span class="p">)</span>
        <span class="k">return</span> <span class="bp">None</span>
    
    <span class="k">return</span> <span class="n">dwords</span>

<span class="k">def</span> <span class="nf">resolve_stack_strings</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">xor_key</span><span class="p">):</span>
        <span class="k">if</span> <span class="n">dwords</span> <span class="p">:</span><span class="o">=</span> <span class="nf">get_stack_string</span><span class="p">(</span><span class="n">caller</span><span class="p">):</span>
            <span class="n">transformed</span> <span class="o">=</span> <span class="nf">transform</span><span class="p">(</span><span class="n">dwords</span><span class="p">,</span> <span class="n">xor_key</span><span class="p">)</span>
            <span class="n">stack_string</span> <span class="o">=</span> <span class="sa">b</span><span class="sh">''</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="n">struct</span><span class="p">.</span><span class="nf">pack</span><span class="p">(</span><span class="sh">"</span><span class="s">&gt;I</span><span class="sh">"</span><span class="p">,</span> <span class="n">dword</span><span class="p">)</span> <span class="k">for</span> <span class="n">dword</span> <span class="ow">in</span> <span class="n">transformed</span><span class="p">)</span>
            <span class="n">stack_string</span> <span class="o">=</span> <span class="n">stack_string</span><span class="p">[::</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
            <span class="k">if</span> <span class="n">resolved</span> <span class="p">:</span><span class="o">=</span> <span class="nf">extract_utf</span><span class="p">(</span><span class="n">stack_string</span><span class="p">):</span>
                <span class="k">return</span> <span class="n">resolved</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="k">return</span> <span class="nf">str</span><span class="p">(</span><span class="n">stack_string</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
    <span class="n">callers</span> <span class="o">=</span> <span class="nf">get_callers</span><span class="p">(</span><span class="mh">0x401250</span><span class="p">)</span>
    <span class="k">for</span> <span class="n">caller</span> <span class="ow">in</span> <span class="n">callers</span><span class="p">:</span>
        <span class="n">resolved</span> <span class="o">=</span> <span class="nf">resolve_stack_strings</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="mh">0x4803BFC7</span><span class="p">)</span>
        <span class="n">db</span><span class="p">.</span><span class="n">comments</span><span class="p">.</span><span class="nf">set</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">resolved</span><span class="p">)</span>
        <span class="c1">#print(resolved)
</span>    
<span class="nf">main</span><span class="p">()</span>
</code></pre></div></div>

<p>And the custom decryptor as well as Aplib was frequently used for other data, so similar to above I just got x-refs with IDA and resolved them.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">blackmatterdecryptor</span> <span class="kn">import</span> <span class="n">BlackMatterDecryptor</span>
<span class="kn">from</span> <span class="n">blackmatterdecryptor</span> <span class="kn">import</span> <span class="n">aplib</span>
<span class="kn">import</span> <span class="n">pickle</span>
<span class="kn">import</span> <span class="n">string</span>

<span class="n">callers</span> <span class="o">=</span> <span class="p">[</span><span class="mi">4305144</span><span class="p">,</span> <span class="mi">4305882</span><span class="p">,</span> <span class="mi">4335988</span><span class="p">,</span> <span class="mi">4307122</span><span class="p">,</span> <span class="mi">4307484</span><span class="p">,</span> <span class="mi">4312960</span><span class="p">,</span> <span class="mi">4335632</span><span class="p">,</span> <span class="mi">4312714</span><span class="p">,</span> <span class="mi">4313456</span><span class="p">,</span> <span class="mi">4313660</span><span class="p">,</span> <span class="mi">4327551</span><span class="p">,</span> <span class="mi">4334552</span><span class="p">,</span> <span class="mi">4327531</span><span class="p">,</span> <span class="mi">4327551</span><span class="p">,</span> <span class="mi">4327691</span><span class="p">,</span> <span class="mi">4327803</span><span class="p">,</span> <span class="mi">4327837</span><span class="p">,</span> <span class="mi">4335241</span><span class="p">,</span> <span class="mi">4327913</span><span class="p">,</span> <span class="mi">4328116</span><span class="p">,</span> <span class="mi">4328220</span><span class="p">,</span> <span class="mi">4328116</span><span class="p">,</span> <span class="mi">4335988</span><span class="p">,</span> <span class="mi">4328248</span><span class="p">,</span> <span class="mi">4333426</span><span class="p">,</span> <span class="mi">4334552</span><span class="p">,</span> <span class="mi">4334552</span><span class="p">,</span> <span class="mi">4334552</span><span class="p">,</span> <span class="mi">4335241</span><span class="p">,</span> <span class="mi">4335632</span><span class="p">,</span> <span class="mi">4335988</span><span class="p">,</span> <span class="mi">4337037</span><span class="p">,</span> <span class="mi">4336487</span><span class="p">,</span> <span class="mi">4337743</span><span class="p">]</span>

<span class="n">fpath</span> <span class="o">=</span> <span class="sa">r</span><span class="sh">"</span><span class="s">C:\Users\Kevin\Desktop\Samples\Blackmatter\374f9df39b92ccccae8a9b747e606aebe0ddaf117f8f6450052efb5160c99368\374f9df39b92ccccae8a9b747e606aebe0ddaf117f8f6450052efb5160c99368.bin</span><span class="sh">"</span>


<span class="k">def</span> <span class="nf">write_pickle</span><span class="p">(</span><span class="n">data</span><span class="p">):</span>
    <span class="k">with</span> <span class="nf">open</span><span class="p">(</span><span class="sh">"</span><span class="s">decrypted_addr.pkl</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">wb</span><span class="sh">"</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
        <span class="n">pickle</span><span class="p">.</span><span class="nf">dump</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">f</span><span class="p">)</span>


<span class="k">def</span> <span class="nf">extract_utf</span><span class="p">(</span><span class="n">data</span><span class="p">:</span> <span class="nb">bytes</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="n">decoded</span> <span class="o">=</span> <span class="n">data</span><span class="p">.</span><span class="nf">decode</span><span class="p">(</span><span class="sh">'</span><span class="s">utf-8</span><span class="sh">'</span><span class="p">)</span>
    <span class="k">except</span> <span class="nb">UnicodeDecodeError</span><span class="p">:</span>
        <span class="k">try</span><span class="p">:</span>
            <span class="n">decoded</span> <span class="o">=</span> <span class="n">data</span><span class="p">.</span><span class="nf">decode</span><span class="p">(</span><span class="sh">'</span><span class="s">utf-16</span><span class="sh">'</span><span class="p">)</span>
        <span class="k">except</span> <span class="nb">UnicodeDecodeError</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">None</span>
    <span class="k">if</span> <span class="nf">all</span><span class="p">(</span><span class="n">c</span> <span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="n">string</span><span class="p">.</span><span class="n">printable</span><span class="p">):</span>  <span class="c1"># All printable ASCII
</span>        <span class="n">decoded</span> <span class="o">=</span> <span class="sh">""</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="n">c</span> <span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="n">decoded</span> <span class="k">if</span> <span class="mi">32</span> <span class="o">&lt;=</span> <span class="nf">ord</span><span class="p">(</span><span class="n">c</span><span class="p">)</span> <span class="o">&lt;=</span> <span class="mi">126</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">decoded</span>
    <span class="k">else</span><span class="p">:</span> 
        <span class="k">return</span> <span class="bp">None</span>

<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
    <span class="n">bm</span> <span class="o">=</span> <span class="nc">BlackMatterDecryptor</span><span class="p">(</span><span class="n">fpath</span><span class="p">)</span>
    <span class="n">bm</span><span class="p">.</span><span class="nf">decrypt_config</span><span class="p">()</span>

    <span class="n">decrypted_list</span> <span class="o">=</span> <span class="p">[</span><span class="n">bm</span><span class="p">.</span><span class="nf">cust_decrypt_wrapper</span><span class="p">(</span><span class="n">caller</span><span class="p">)</span> <span class="k">for</span> <span class="n">caller</span> <span class="ow">in</span> <span class="n">callers</span><span class="p">]</span>

    <span class="n">extracted_all</span> <span class="o">=</span> <span class="p">[]</span>
    <span class="n">addr_decrypted</span> <span class="o">=</span> <span class="nf">zip</span><span class="p">(</span><span class="n">callers</span><span class="p">,</span> <span class="n">decrypted_list</span><span class="p">,</span> <span class="n">strict</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>

    <span class="k">for</span> <span class="n">addr</span><span class="p">,</span> <span class="n">dec</span> <span class="ow">in</span> <span class="n">addr_decrypted</span><span class="p">:</span>
        <span class="k">if</span> <span class="n">extracted_utf</span> <span class="p">:</span><span class="o">=</span> <span class="nf">extract_utf</span><span class="p">(</span><span class="n">dec</span><span class="p">):</span>
            <span class="n">extracted_all</span><span class="p">.</span><span class="nf">append</span><span class="p">((</span><span class="n">addr</span><span class="p">,</span> <span class="n">extracted_utf</span><span class="p">))</span>
            <span class="k">continue</span>
        
        <span class="n">decompressed</span> <span class="o">=</span> <span class="n">aplib</span><span class="p">.</span><span class="nf">aplib_decompress</span><span class="p">(</span><span class="n">dec</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">decompressed_utf</span> <span class="p">:</span><span class="o">=</span> <span class="nf">extract_utf</span><span class="p">(</span><span class="n">decompressed</span><span class="p">):</span>
            <span class="n">extracted_all</span><span class="p">.</span><span class="nf">append</span><span class="p">((</span><span class="n">addr</span><span class="p">,</span> <span class="n">decompressed_utf</span><span class="p">))</span>
    

    <span class="n">seen</span> <span class="o">=</span> <span class="nf">set</span><span class="p">()</span>
    <span class="n">extracted_unique</span> <span class="o">=</span> <span class="p">[]</span>
    <span class="k">for</span> <span class="n">addr</span><span class="p">,</span> <span class="n">val</span> <span class="ow">in</span> <span class="n">extracted_all</span><span class="p">:</span>
        <span class="k">if</span> <span class="n">val</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">seen</span><span class="p">:</span>
            <span class="n">seen</span><span class="p">.</span><span class="nf">add</span><span class="p">(</span><span class="n">val</span><span class="p">)</span>
            <span class="n">extracted_unique</span><span class="p">.</span><span class="nf">append</span><span class="p">((</span><span class="n">addr</span><span class="p">,</span> <span class="n">val</span><span class="p">))</span>
    <span class="k">return</span> <span class="n">extracted_unique</span>

<span class="n">data</span> <span class="o">=</span> <span class="nf">main</span><span class="p">()</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">data</span><span class="p">:</span>
    <span class="nf">print</span><span class="p">({</span><span class="n">i</span><span class="p">[</span><span class="mi">1</span><span class="p">]})</span>
    <span class="c1">#write_pickle(data)
</span></code></pre></div></div>

<p>This is a set of the strings I extracted from the sample.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
LDAP://CN=Computers,
Policy\Status
LDAP://CN=%s,CN=Policies,CN=System,DC=%s,DC=%s
office
Mailbox
AUTHORITY\SYSTEM
-psex
SOFTWARE\Microsoft\Windows\CurrentVersion\WINEVT\Channels
NT\CurrentVersion
NetworkShares.xml
Consolas
.bmp
ChannelAccess
%s
New
WallPaper
dllhost.exe
Registry.pol
WallpaperStyle
Panel\International
ADMIN$
displayName
%TempDir%
sLanguage
FROM
\\%s\
Panel\Desktop
WQL
%04d-%02d-%02d
%s=%s
distinguishedName
-k
LocaleName
SELECT
2621892
-gspd
%02X
*
Software\Microsoft\Windows\CurrentVersion\Group
Elevation:Administrator!new:{3E5FC7F9-9A51-4367-9063-A120244FBEC7}
LDAP://%s/DC=%s,DC=%s
LDAP://CN=Policies,CN=System,%s
-wall
\\.\pipe\{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}
Win32_ShadowCopy.ID='%s'
SOFTWARE\Microsoft\Windows
LDAP://rootDSE
-safe
Times
%.8x%.8x%.8x%.8x%
Program
\*.dll
LocalServiceNetworkRestrictedd
Enabled
%s.README.txt
{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}
gPCMachineExtensionNames
hScreen
Global\%.8x%.8x%.8x%.8x
drv
WinSta0\Default
dNSHostName
\\%s.%s\
GPT.INI
[General]Version=%sdisplayName=%s
NT
Files
\\.\pipe\%s
Services.xml
Preferences
%sADMIN$\Temp
LDAP://DC=%s,DC=%s
SYSTEM\CurrentControlSet\Services\EventLog
%u.%u
__ProviderArchitecture
\\%s\sysvol\%s\scripts\
ID
-pass
LocalServiceNetworkRestricted
POST
EventLog
{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}
Control
SOFTWARE\%s
comment.cmtx
LDAP://%s
IPC$
%02d:%02d:%02d
versionNumber
-gdel
WINSPOOL
Z:\
%sADMIN$\Temp\%s.exe
ExchangeInstallPath
Win32_ShadowCopy
ROOT\CIMV2
%spipe\%s
Roman
%s_IPC$
onenote
ProductName
gPCUserExtensionNames
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
ScheduledTasks
Files.xml
SystemRoot%%\Temp\%s.exe
%%SystemRoot%%\Temp\%s.exe
defaultNamingContext
                               LockBit BlackAll your important files are stolen and encrypted!    You must find %s file                    and follow the instruction!
H
&lt;?xml version="1.0" encoding="utf-8"?&gt;&lt;NetworkShareSettings clsid="{520870D8-A6E7-47e8-A8D8-E6A4E76EAEC2}"&gt;&lt;NetShare clsid="{2888C5E7-94FC-4739-90AA-2C1536D68BC0}" image="2" name="%%ComputerName%%_D" changed="%s" uid="%s"&gt;&lt;Properties action="U" name="%%ComputerName%%_D" path="D:" comment="" allRegular="0" allHidden="0" allAdminDrive="0" limitUsers="NO_CHANGE" abe="NO_CHANGE"/&gt;&lt;/NetShare&gt;&lt;NetShare clsid="{2888C5E7-94FC-4739-90AA-2C1536D68BC0}" image="2" name="%%ComputerName%%_E" changed="%s" uid="%s"&gt;&lt;Properties action="U" name="%%ComputerName%%_E" path="E:" comment="" allRegular="0" allHidden="0" allAdminDrive="0" limitUsers="NO_CHANGE" abe="NO_CHANGE"/&gt;&lt;/NetShare&gt;&lt;NetShare clsid="{2888C5E7-94FC-4739-90AA-2C1536D68BC0}" image="2" name="%%ComputerName%%_F" changed="%s" uid="%s"&gt;&lt;Properties action="U" name="%%ComputerName%%_F" path="F:" comment="" allRegular="0" allHidden="0" allAdminDrive="0" limitUsers="NO_CHANGE" abe="NO_CHANGE"/&gt;&lt;/NetShare&gt;&lt;NetShare clsid="{2888C5E7-94FC-4739-90AA-2C1536D68BC0}" image="2" name="%%ComputerName%%_G" changed="%s" uid="%s"&gt;&lt;Properties action="U" name="%%ComputerName%%_G" path="G:" comment="" allRegular="0" 
allHidden="0" allAdminDrive="0" limitUsers="NO_CHANGE" abe="NO_CHANGE"/&gt;&lt;/NetShare&gt;&lt;NetShare clsid="{2888C5E7-94FC-4739-90AA-2C1536D68BC0}" image="2" name="%%ComputerName%%_H" changed="%s" uid="%s"&gt;&lt;Properties action="U" name="%%ComputerName%%_H" path="H:" comment="" allRegular="0" allHidden="0" allAdminDrive="0" limitUsers="NO_CHANGE" abe="NO_CHANGE"/&gt;&lt;/NetShare&gt;&lt;NetShare clsid="{2888C5E7-94FC-4739-90AA-2C1536D68BC0}" image="2" name="%%ComputerName%%_I" changed="%s" uid="%s"&gt;&lt;Properties action="U" name="%%ComputerName%%_I" path="I:" comment="" allRegular="0" allHidden="0" allAdminDrive="0" limitUsers="NO_CHANGE" abe="NO_CHANGE"/&gt;&lt;/NetShare&gt;&lt;NetShare clsid="{2888C5E7-94FC-4739-90AA-2C1536D68BC0}" image="2" name="%%ComputerName%%_J" changed="%s" uid="%s"&gt;&lt;Properties action="U" name="%%ComputerName%%_J" path="J:" comment="" allRegular="0" allHidden="0" allAdminDrive="0" limitUsers="NO_CHANGE" abe="NO_CHANGE"/&gt;&lt;/NetShare&gt;&lt;NetShare clsid="{2888C5E7-94FC-4739-90AA-2C1536D68BC0}" image="2" name="%%ComputerName%%_K" changed="%s" uid="%s"&gt;&lt;Properties action="U" name="%%ComputerName%%_K" path="K:" comment="" allRegular="0" allHidden="0" allAdminDrive="0" limitUsers="NO_CHANGE" abe="NO_CHANGE"/&gt;&lt;/NetShare&gt;&lt;NetShare clsid="{2888C5E7-94FC-4739-90AA-2C1536D68BC0}" image="2" name="%%ComputerName%%_L" changed="%s" uid="%s"&gt;&lt;Properties action="U" name="%%ComputerName%%_L" path="L:" comment="" allRegular="0" allHidden="0" allAdminDrive="0" limitUsers="NO_CHANGE" abe="NO_CHANGE"/&gt;&lt;/NetShare&gt;&lt;NetShare clsid="{2888C5E7-94FC-4739-90AA-2C1536D68BC0}" image="2" name="%%ComputerName%%_M" changed="%s" uid="%s"&gt;&lt;Properties action="U" name="%%ComputerName%%_M" path="M:" comment="" allRegular="0" allHidden="0" allAdminDrive="0" limitUsers="NO_CHANGE" abe="NO_CHANGE"/&gt;&lt;/NetShare&gt;&lt;NetShare clsid="{2888C5E7-94FC-4739-90AA-2C1536D68BC0}" image="2" name="%%ComputerName%%_N" changed="%s" uid="%s"&gt;&lt;Properties action="U" name="%%ComputerName%%_N" path="N:" comment="" allRegular="0" allHidden="0" allAdminDrive="0" limitUsers="NO_CHANGE" abe="NO_CHANGE"/&gt;&lt;/NetShare&gt;&lt;NetShare clsid="{2888C5E7-94FC-4739-90AA-2C1536D68BC0}" image="2" name="%%ComputerName%%_O" changed="%s" uid="%s"&gt;&lt;Properties action="U" name="%%ComputerName%%_O" path="O:" comment="" allRegular="0" allHidden="0" allAdminDrive="0" limitUsers="NO_CHANGE" abe="NO_CHANGE"/&gt;&lt;/NetShare&gt;&lt;NetShare clsid="{2888C5E7-94FC-4739-90AA-2C1536D68BC0}" image="2" name="%%ComputerName%%_P" changed="%s" uid="%s"&gt;&lt;Properties action="U" name="%%ComputerName%%_P" path="P:" comment="" allRegular="0" allHidden="0" allAdminDrive="0" limitUsers="NO_CHANGE" abe="NO_CHANGE"/&gt;&lt;/NetShare&gt;&lt;NetShare clsid="{2888C5E7-94FC-4739-90AA-2C1536D68BC0}" image="2" name="%%ComputerName%%_Q" changed="%s" uid="%s"&gt;&lt;Properties action="U" name="%%ComputerName%%_Q" path="Q:" comment="" allRegular="0" allHidden="0" allAdminDrive="0" limitUsers="NO_CHANGE" abe="NO_CHANGE"/&gt;&lt;/NetShare&gt;&lt;NetShare clsid="{2888C5E7-94FC-4739-90AA-2C1536D68BC0}" image="2" name="%%ComputerName%%_R" changed="%s" uid="%s"&gt;&lt;Properties action="U" name="%%ComputerName%%_R" path="R:" comment="" allRegular="0" allHidden="0" allAdminDrive="0" limitUsers="NO_CHANGE" abe="NO_CHANGE"/&gt;&lt;/NetShare&gt;&lt;NetShare clsid="{2888C5E7-94FC-4739-90AA-2C1536D68BC0}" image="2" name="%%ComputerName%%_S" changed="%s" uid="%s"&gt;&lt;Properties action="U" name="%%ComputerName%%_S" path="S:" comment="" allRegular="0" allHidden="0" allAdminDrive="0" limitUsers="NO_CHANGE" abe="NO_CHANGE"/&gt;&lt;/NetShare&gt;&lt;NetShare clsid="{2888C5E7-94FC-4739-90AA-2C1536D68BC0}" image="2" name="%%ComputerName%%_T" changed="%s" uid="%s"&gt;&lt;Properties action="U" name="%%ComputerName%%_T" path="T:" comment="" allRegular="0" allHidden="0" allAdminDrive="0" limitUsers="NO_CHANGE" abe="NO_CHANGE"/&gt;&lt;/NetShare&gt;&lt;NetShare clsid="{2888C5E7-94FC-4739-90AA-2C1536D68BC0}" image="2" name="%%ComputerName%%_U" changed="%s" uid="%s"&gt;&lt;Properties action="U" name="%%ComputerName%%_U" path="U:" comment="" allRegular="0" allHidden="0" allAdminDrive="0" limitUsers="NO_CHANGE" abe="NO_CHANGE"/&gt;&lt;/NetShare&gt;&lt;NetShare clsid="{2888C5E7-94FC-4739-90AA-2C1536D68BC0}" image="2" name="%%ComputerName%%_V" changed="%s" uid="%s"&gt;&lt;Properties action="U" name="%%ComputerName%%_V" path="V:" comment="" allRegular="0" allHidden="0" allAdminDrive="0" limitUsers="NO_CHANGE" abe="NO_CHANGE"/&gt;&lt;/NetShare&gt;&lt;NetShare clsid="{2888C5E7-94FC-4739-90AA-2C1536D68BC0}" image="2" name="%%ComputerName%%_W" changed="%s" uid="%s"&gt;&lt;Properties action="U" name="%%ComputerName%%_W" path="W:" comment="" allRegular="0" allHidden="0" allAdminDrive="0" limitUsers="NO_CHANGE" abe="NO_CHANGE"/&gt;&lt;/NetShare&gt;&lt;NetShare clsid="{2888C5E7-94FC-4739-90AA-2C1536D68BC0}" image="2" name="%%ComputerName%%_X" changed="%s" uid="%s"&gt;&lt;Properties action="U" name="%%ComputerName%%_X" path="X:" comment="" allRegular="0" allHidden="0" allAdminDrive="0" limitUsers="NO_CHANGE" abe="NO_CHANGE"/&gt;&lt;/NetShare&gt;&lt;NetShare clsid="{2888C5E7-94FC-4739-90AA-2C1536D68BC0}" image="2" name="%%ComputerName%%_Y" changed="%s" uid="%s"&gt;&lt;Properties action="U" name="%%ComputerName%%_Y" path="Y:" comment="" allRegular="0" allHidden="0" allAdminDrive="0" limitUsers="NO_CHANGE" abe="NO_CHANGE"/&gt;&lt;/NetShare&gt;&lt;NetShare clsid="{2888C5E7-94FC-4739-90AA-2C1536D68BC0}" image="2" name="%%ComputerName%%_Z" changed="%s" uid="%s"&gt;&lt;Properties action="U" name="%%ComputerName%%_Z" path="Z:" comment="" allRegular="0" allHidden="0" allAdminDrive="0" limitUsers="NO_CHANGE" abe="NO_CHANGE"/&gt;&lt;/NetShare&gt;&lt;/NetworkShareSettings&gt;        
LockBit Black RansomwareYour data are stolen and encryptedThe data will be published on TOR websitehttp://[redacted].onionand http://lockbitapt.uz if you do not pay the ransomYou can contact us and decrypt one file for free on these TOR siteshttp://[redacted].onionhttp://[redacted].onionhttp://lockbitsupp.uzDecryption ID: %s
{"disk_name":"%s","disk_size":"%u","free_size":"%u"}
&lt;?xml version='1.0' encoding='utf-8'?&gt;&lt;policyComments xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" revision="1.0" schemaVersion="1.0" xmlns="http://www.microsoft.com/GroupPolicy/CommentDefinitions"&gt;  &lt;policyNamespaces&gt;    &lt;using prefix="ns0" namespace="Microsoft.Policies.GroupPolicy"&gt;&lt;/using&gt;    &lt;using prefix="ns1" namespace="Microsoft.Policies.SmartScreen"&gt;&lt;/using&gt;    &lt;using prefix="ns2" namespace="Microsoft.Policies.WindowsDefender"&gt;&lt;/using&gt;    &lt;using prefix="ns3" namespace="Microsoft.Policies.WindowsFirewall"&gt;&lt;/using&gt;  &lt;/policyNamespaces&gt;  &lt;comments&gt;    &lt;admTemplate&gt;&lt;/admTemplate&gt;  &lt;/comments&gt;  &lt;resources minRequiredRevision="1.0"&gt;    &lt;stringTable&gt;&lt;/stringTable&gt;  &lt;/resources&gt;&lt;/policyComments&gt;
"host_hostname":"%s","host_user":"%s","host_os":"%s","host_domain":"%s","host_arch":"%s","host_lang":"%s",%s
Accept: */*Connection: keep-aliveAccept-Encoding: gzip, deflate, brContent-Type: text/plain
{"bot_version":"%s","bot_id":"%s","bot_company":"%.8x%.8x%.8x%.8x%",%s}
SOFTWARE\Policies\Microsoft\Windows\OOBE
&lt;?xml version="1.0" encoding="utf-8"?&gt;&lt;ScheduledTasks clsid="{CC63F200-7309-4ba0-B154-A71CD118DBCC}"&gt;&lt;TaskV2 clsid="{D8896631-B747-47a7-84A6-C155337F3BC8}" name="%s" image="2" changed="%s" uid="%s"&gt;&lt;Properties action="U" name="%s" runAs="%s" logonType="InteractiveToken"&gt;&lt;Task version="1.2"&gt;&lt;RegistrationInfo&gt;&lt;Author&gt;%s&lt;/Author&gt;&lt;Description&gt;&lt;/Description&gt;&lt;/RegistrationInfo&gt;&lt;Principals&gt;&lt;Principal id="Author"&gt;&lt;UserId&gt;%s&lt;/UserId&gt;&lt;LogonType&gt;InteractiveToken&lt;/LogonType&gt;&lt;RunLevel&gt;HighestAvailable&lt;/RunLevel&gt;&lt;/Principal&gt;&lt;/Principals&gt;&lt;Settings&gt;&lt;IdleSettings&gt;&lt;Duration&gt;PT10M&lt;/Duration&gt;&lt;WaitTimeout&gt;PT1H&lt;/WaitTimeout&gt;&lt;StopOnIdleEnd&gt;false&lt;/StopOnIdleEnd&gt;&lt;RestartOnIdle&gt;false&lt;/RestartOnIdle&gt;&lt;/IdleSettings&gt;&lt;MultipleInstancesPolicy&gt;IgnoreNew&lt;/MultipleInstancesPolicy&gt;&lt;DisallowStartIfOnBatteries&gt;false&lt;/DisallowStartIfOnBatteries&gt;&lt;StopIfGoingOnBatteries&gt;false&lt;/StopIfGoingOnBatteries&gt;&lt;AllowHardTerminate&gt;true&lt;/AllowHardTerminate&gt;&lt;AllowStartOnDemand&gt;true&lt;/AllowStartOnDemand&gt;&lt;Enabled&gt;true&lt;/Enabled&gt;&lt;Hidden&gt;false&lt;/Hidden&gt;&lt;ExecutionTimeLimit&gt;P3D&lt;/ExecutionTimeLimit&gt;&lt;Priority&gt;7&lt;/Priority&gt;&lt;/Settings&gt;&lt;Triggers&gt;&lt;RegistrationTrigger&gt;&lt;Enabled&gt;true&lt;/Enabled&gt;&lt;/RegistrationTrigger&gt;&lt;/Triggers&gt;&lt;Actions Context="Author"&gt;&lt;Exec&gt;&lt;Command&gt;%s&lt;/Command&gt;&lt;Arguments&gt;%s&lt;/Arguments&gt;&lt;/Exec&gt;&lt;/Actions&gt;&lt;/Task&gt;&lt;/Properties&gt;&lt;/TaskV2&gt;&lt;/ScheduledTasks&gt;
SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon
AutoAdminLogon
DefaultUserName
PReg[SOFTWARE\Policies\Microsoft\Windows\System;GroupPolicyRefreshTimeDC;;;][SOFTWARE\Policies\Microsoft\Windows\System;GroupPolicyRefreshTimeOffsetDC;;;][SOFTWARE\Policies\Microsoft\Windows\System;GroupPolicyRefreshTime;;;][SOFTWARE\Policies\Microsoft\Windows\System;GroupPolicyRefreshTimeOffset;;;][SOFTWARE\Policies\Microsoft\Windows\System;EnableSmartScreen;;;][SOFTWARE\Policies\Microsoft\Windows\System;**del.ShellSmartScreenLevel;;; ][SOFTWARE\Policies\Microsoft\Windows Defender;DisableAntiSpyware;;;][SOFTWARE\Policies\Microsoft\Windows Defender;DisableRoutinelyTakingAction;;;][SOFTWARE\Policies\Microsoft\Windows Defender\Real-Time Protection;DisableRealtimeMonitoring;;;][SOFTWARE\Policies\Microsoft\Windows Defender\Real-Time Protection;DisableBehaviorMonitoring;;;][SOFTWARE\Policies\Microsoft\Windows Defender\Spynet;SubmitSamplesConsent;;;][SOFTWARE\Policies\Microsoft\Windows Defender\Spynet;SpynetReporting;;;][SOFTWARE\Policies\Microsoft\WindowsFirewall\DomainProfile;EnableFirewall;;;][SOFTWARE\Policies\Microsoft\WindowsFirewall\StandardProfile;EnableFirewall;;;]
DefaultPassword
SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce
%s -pass %s
powershell Get-ADComputer -filter * -Searchbase '%s' | Foreach-Object { Invoke-GPUpdate -computer $_.name -force -RandomDelayInMinutes 0}
[{00000000-0000-0000-0000-000000000000}{BFCBBEB0-9DF4-4C0C-A728-434EA66A0373}{CC5746A9-9B74-4BE5-AE2E-64379C86E0E4}][{35378EAC-683F-11D2-A89A-00C04FBBCFA2}{D02B1F72-3407-48AE-BA88-E8213C6761F1}][{6A4C88C6-C502-4F74-8F60-2CB23EDC24E2}{BFCBBEB0-9DF4-4C0C-A728-434EA66A0373}][{91FBB303-0CD5-4055-BF42-E512A681B325}{CC5746A9-9B74-4BE5-AE2E-64379C86E0E4}]
[{00000000-0000-0000-0000-000000000000}{3BAE7E51-E3F4-41D0-853D-9BB9FD47605F}{CAB54552-DEEA-4691-817E-ED4A4D1AFC72}][{7150F9BF-48AD-4DA4-A49C-29EF4A8369BA}{3BAE7E51-E3F4-41D0-853D-9BB9FD47605F}][{AADCED64-746C-4633-A97C-D61349046527}{CAB54552-DEEA-4691-817E-ED4A4D1AFC72}]

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

<hr />

<h2 id="sample-functionality">Sample Functionality</h2>

<p>The sample neatly organizes its functions into three main sections:</p>

<h3 id="1-api-resolution">1. API Resolution</h3>
<p>To load in the libraries it wanted it enumerated the system 32 folder for all DLLs and hashed their names. This allowed it to only store DLL hashes instead of having to include any strings.
<img src="/assets/BlackMatter/dll_enumeration.png" alt="fasm" /></p>

<p>It also utilised KUSER_SHARED_DATA to retrieve the System32 path which I thought was novel.</p>

<p><img src="/assets/BlackMatter/kuser.png" alt="fasm" /></p>

<p>For the API resolution the sample did a fairly standard PEB walk. It did use  mixed boolean arithmetic to try and conceal constants, however I barely even noticed it as the decompiler folded it away.
<img src="/assets/BlackMatter/api_hashing.png" alt="fasm" /></p>

<p>I noticed the sample frequently used a custom ABI which was causing IDA to have undefined variables. The ABI had no volatile registers beyond eax.</p>

<p><em>Can see edx’s value being saved, although IDA has identified this as std_call in which edx is volatile.</em>
<img src="/assets/BlackMatter/cust_abi.png" alt="fasm" />
<em>Specifying the function signature <code class="language-plaintext highlighter-rouge">__spoils&lt;eax&gt;</code> cleaned up the decompilation a lot.</em></p>

<p>What was highly interesting was how it attempts to conceal the addresses of the resolved APIs. Once an address was resolved, instead of storing the address directly, it would be encrypted with 1 of 5 randomly chosen functions, and code would be injected that resolved the address. The key used for decryption was injected directly as an operand. Thus calls would have to go through this injected code.</p>

<p><em>This union of structs I generated shows the code generation in action.</em></p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#pragma pack(push, 1)
</span><span class="k">struct</span> <span class="n">bmatter_xor_rot</span> <span class="p">{</span>
    <span class="n">BYTE</span> <span class="n">mov_opcode</span><span class="p">;</span>
    <span class="n">DWORD</span> <span class="n">api_addr_modified</span><span class="p">;</span>
    <span class="n">WORD</span> <span class="n">r_left_or_right_opcode</span><span class="p">;</span>
    <span class="n">BYTE</span> <span class="n">rotate_amount</span><span class="p">;</span>
    <span class="n">BYTE</span> <span class="n">xor_opcode</span><span class="p">;</span>
    <span class="n">DWORD</span> <span class="n">xor_key</span><span class="p">;</span>
    <span class="n">WORD</span> <span class="n">jmp_eax</span><span class="p">;</span>
<span class="p">};</span>
<span class="cp">#pragma pack(pop)
</span>
<span class="cp">#pragma pack(push, 1)
</span><span class="k">struct</span> <span class="n">bmatter_rot</span> <span class="p">{</span>
    <span class="n">BYTE</span> <span class="n">none</span><span class="p">;</span>
    <span class="n">DWORD</span> <span class="n">api_addr_modified</span><span class="p">;</span>
    <span class="n">WORD</span> <span class="n">r_left_or_right_opcode</span><span class="p">;</span>
    <span class="n">BYTE</span> <span class="n">rotate_amount</span><span class="p">;</span>
    <span class="n">WORD</span> <span class="n">jmp_eax</span><span class="p">;</span>
<span class="p">};</span>
<span class="cp">#pragma pack(pop)
</span>
<span class="cp">#pragma pack(push, 1)
</span><span class="k">struct</span> <span class="n">bmatter_IAT_xor</span> <span class="p">{</span>
    <span class="n">BYTE</span> <span class="n">none</span><span class="p">;</span>
    <span class="n">DWORD</span> <span class="n">api_addr_modified</span><span class="p">;</span>
    <span class="n">BYTE</span> <span class="n">xor_opcode</span><span class="p">;</span>
    <span class="n">DWORD</span> <span class="n">xor_key</span><span class="p">;</span>
    <span class="n">WORD</span> <span class="n">jmp_eax</span><span class="p">;</span>
<span class="p">};</span>
<span class="cp">#pragma pack(pop)
</span>
<span class="k">union</span> <span class="n">bmatter_IAT</span> <span class="p">{</span>
    <span class="k">struct</span> <span class="n">bmatter_xor_rot</span> <span class="o">*</span><span class="n">xor_rot</span><span class="p">;</span>
    <span class="k">struct</span> <span class="n">bmatter_rot</span> <span class="o">*</span><span class="n">rot</span><span class="p">;</span>
    <span class="k">struct</span> <span class="n">bmatter_xor</span> <span class="o">*</span><span class="n">xor</span><span class="p">;</span>
<span class="p">};</span>

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

<p><img src="/assets/BlackMatter/address_enc.png" alt="fasm" /></p>

<p><em>How the code looks disassembled after generation</em></p>

<p><img src="/assets/BlackMatter/code_inj_disasm.png" alt="fasm" /></p>

<p>It also loaded some shellcode for its custom encryption function and utilised the same address encryption to conceal its address.</p>

<p>However it is still quite easy to resolve it statically, but would make resolving these addresses within a debugger or dynamically complicated.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">EA_HASH_ARG_START</span> <span class="o">=</span> <span class="mh">0x004063ED</span>
<span class="n">EA_HASH_ARG_END</span> <span class="o">=</span> <span class="mh">0x00406524</span>
<span class="n">STEP_BETWEEN_ARGS</span> <span class="o">=</span> <span class="mi">17</span>
<span class="n">XOR_KEY</span> <span class="o">=</span> <span class="mh">0x4803BFC7</span>
<span class="n">ALGORITHM</span> <span class="o">=</span> <span class="sh">'</span><span class="s">ror13_add</span><span class="sh">'</span>
<span class="n">API_HASH_LIST_END_MARKER</span> <span class="o">=</span> <span class="mh">0xCCCCCCCC</span>
<span class="kn">from</span> <span class="n">ida_domain</span> <span class="kn">import</span> <span class="o">*</span>
<span class="kn">import</span> <span class="n">idaapi</span>
<span class="kn">import</span> <span class="n">requests</span>
<span class="kn">import</span> <span class="n">time</span>
<span class="n">db</span> <span class="o">=</span> <span class="nc">Database</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">get_func_operands</span><span class="p">(</span><span class="n">arg_start</span><span class="p">,</span> <span class="n">arg_end</span><span class="p">,</span> <span class="n">step_between_args</span><span class="p">):</span>
    <span class="n">insn_ea</span> <span class="o">=</span> <span class="nf">list</span><span class="p">(</span><span class="nf">range</span><span class="p">(</span><span class="n">arg_start</span><span class="p">,</span> <span class="n">arg_end</span><span class="p">,</span> <span class="n">step_between_args</span><span class="p">))</span>
    <span class="n">operands</span> <span class="o">=</span> <span class="p">[</span><span class="n">idaapi</span><span class="p">.</span><span class="nf">get_dword</span><span class="p">(</span><span class="n">operand</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="k">for</span> <span class="n">operand</span> <span class="ow">in</span> <span class="n">insn_ea</span><span class="p">]</span> <span class="c1">#+1 negates the push instruction, just retrieves the operand
</span>    <span class="k">return</span> <span class="n">operands</span>

<span class="k">def</span> <span class="nf">bmatter_retrieve_hashes</span><span class="p">(</span><span class="n">ea_hash_arg_start</span><span class="p">,</span> <span class="n">ea_hash_arg_end</span><span class="p">)</span><span class="o">-&gt;</span><span class="nb">tuple</span><span class="p">[</span><span class="nb">list</span><span class="p">[</span><span class="nb">int</span><span class="p">],</span> <span class="nb">list</span><span class="p">[</span><span class="nb">list</span><span class="p">]]:</span>
    <span class="c1"># retrieving addresses of code that push a hash struct to the function
</span>    <span class="n">operands</span> <span class="o">=</span> <span class="nf">get_func_operands</span><span class="p">(</span><span class="n">ea_hash_arg_start</span><span class="p">,</span> <span class="n">ea_hash_arg_end</span><span class="p">,</span> <span class="n">STEP_BETWEEN_ARGS</span><span class="p">)</span>
    <span class="n">dll_hashes</span> <span class="o">=</span> <span class="p">[</span><span class="n">idaapi</span><span class="p">.</span><span class="nf">get_dword</span><span class="p">(</span><span class="n">dll_hash</span><span class="p">)</span> <span class="k">for</span> <span class="n">dll_hash</span> <span class="ow">in</span> <span class="n">operands</span><span class="p">]</span>
    <span class="n">dword</span> <span class="o">=</span> <span class="mi">4</span>
    <span class="n">api_hashes</span> <span class="o">=</span> <span class="p">[]</span>
    <span class="k">for</span> <span class="n">api_hashes_per_dll</span> <span class="ow">in</span> <span class="n">operands</span><span class="p">:</span>
        <span class="n">hashes_ea</span> <span class="o">=</span> <span class="n">api_hashes_per_dll</span> <span class="o">+</span> <span class="n">dword</span>
        <span class="n">cur_dll_api_hashes</span> <span class="o">=</span> <span class="p">[]</span>
        <span class="nf">while </span><span class="p">(</span><span class="n">api_hash</span> <span class="p">:</span><span class="o">=</span> <span class="n">idaapi</span><span class="p">.</span><span class="nf">get_dword</span><span class="p">(</span><span class="n">hashes_ea</span><span class="p">))</span> <span class="o">!=</span> <span class="n">API_HASH_LIST_END_MARKER</span><span class="p">:</span>
            <span class="n">cur_dll_api_hashes</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">api_hash</span><span class="p">)</span>
            <span class="n">hashes_ea</span> <span class="o">+=</span> <span class="n">dword</span>
        <span class="n">api_hashes</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">cur_dll_api_hashes</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">dll_hashes</span><span class="p">,</span> <span class="n">api_hashes</span>   <span class="c1"># first member is dll hash, second member is API hash
</span><span class="k">def</span> <span class="nf">resolve_api_hash</span><span class="p">(</span><span class="nb">hash</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">algorithm</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="n">ALGORITHM</span><span class="p">,</span> <span class="n">xor</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="bp">None</span><span class="p">):</span>
    <span class="k">if</span> <span class="n">xor</span><span class="p">:</span>
        <span class="n">xor</span> <span class="o">=</span> <span class="nf">str</span><span class="p">(</span><span class="n">xor</span><span class="p">)</span>
        <span class="n">hashdb_api</span> <span class="o">=</span> <span class="sa">f</span><span class="sh">'</span><span class="s">https://hashdb.openanalysis.net/hash/</span><span class="si">{</span><span class="n">algorithm</span><span class="si">}</span><span class="s">/</span><span class="si">{</span><span class="nb">hash</span><span class="si">}</span><span class="s">/</span><span class="si">{</span><span class="n">xor</span><span class="si">}</span><span class="sh">'</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="n">hashdb_api</span> <span class="o">=</span> <span class="sa">f</span><span class="sh">'</span><span class="s">https://hashdb.openanalysis.net/hash/</span><span class="si">{</span><span class="n">algorithm</span><span class="si">}</span><span class="s">/</span><span class="si">{</span><span class="nb">hash</span><span class="si">}</span><span class="sh">'</span>
    
        
    <span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
        <span class="n">response</span> <span class="o">=</span> <span class="n">requests</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="n">hashdb_api</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">response</span><span class="p">.</span><span class="n">status_code</span> <span class="o">==</span> <span class="mi">429</span><span class="p">:</span>
            <span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">Getting rate limited</span><span class="sh">"</span><span class="p">)</span>
            <span class="n">time</span><span class="p">.</span><span class="nf">sleep</span><span class="p">(</span><span class="mi">60</span><span class="p">)</span>
            <span class="k">continue</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">data</span> <span class="o">=</span> <span class="n">response</span><span class="p">.</span><span class="nf">json</span><span class="p">()</span>
        
        <span class="n">hashes</span> <span class="o">=</span> <span class="n">data</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="sh">'</span><span class="s">hashes</span><span class="sh">'</span><span class="p">,</span> <span class="p">[])</span>
        <span class="k">if</span> <span class="n">hashes</span><span class="p">:</span>
            <span class="n">first_hash</span> <span class="o">=</span> <span class="n">hashes</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
            <span class="n">string_data</span> <span class="o">=</span> <span class="n">first_hash</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="sh">'</span><span class="s">string</span><span class="sh">'</span><span class="p">)</span>
            <span class="k">if</span> <span class="n">string_data</span><span class="p">:</span>
                <span class="n">string</span> <span class="o">=</span> <span class="n">string_data</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="sh">'</span><span class="s">string</span><span class="sh">'</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">string</span>
        
<span class="k">def</span> <span class="nf">retrieve_resolved_out_base</span><span class="p">(</span><span class="n">ea_out_arg_start</span><span class="p">,</span> <span class="n">ea_out_arg_end</span><span class="p">):</span>
    <span class="n">out_addrs</span> <span class="o">=</span> <span class="nf">get_func_operands</span><span class="p">(</span><span class="n">ea_out_arg_start</span><span class="p">,</span> <span class="n">ea_out_arg_end</span><span class="p">,</span> <span class="n">STEP_BETWEEN_ARGS</span><span class="p">)</span>
    <span class="n">out_addrs</span> <span class="o">=</span> <span class="p">[</span><span class="n">out</span><span class="o">+</span><span class="mi">4</span> <span class="k">for</span> <span class="n">out</span> <span class="ow">in</span> <span class="n">out_addrs</span><span class="p">]</span>
    <span class="k">return</span> <span class="n">out_addrs</span>

<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
    <span class="n">_</span><span class="p">,</span> <span class="n">api_hashes</span> <span class="o">=</span> <span class="nf">bmatter_retrieve_hashes</span><span class="p">(</span><span class="n">EA_HASH_ARG_START</span><span class="p">,</span> <span class="n">EA_HASH_ARG_END</span><span class="p">)</span>
    <span class="n">resolved_out_base</span> <span class="o">=</span> <span class="nf">retrieve_resolved_out_base</span><span class="p">(</span><span class="n">EA_HASH_ARG_START</span><span class="o">+</span><span class="mi">5</span><span class="p">,</span> <span class="n">EA_HASH_ARG_END</span><span class="o">+</span><span class="mi">5</span><span class="p">)</span> <span class="c1"># out arg is pushed right after hashes, in a 5 byte instruction
</span>    
    <span class="k">for</span> <span class="n">apis_for_dll</span><span class="p">,</span> <span class="n">hash_list</span> <span class="ow">in</span> <span class="nf">enumerate</span><span class="p">(</span><span class="n">api_hashes</span><span class="p">):</span>
        <span class="k">for</span> <span class="n">offset</span><span class="p">,</span> <span class="nb">hash</span> <span class="ow">in</span> <span class="nf">enumerate</span><span class="p">(</span><span class="n">hash_list</span><span class="p">):</span>
            <span class="n">api_name</span> <span class="o">=</span> <span class="nf">resolve_api_hash</span><span class="p">(</span><span class="nb">hash</span><span class="p">,</span> <span class="n">ALGORITHM</span><span class="p">,</span> <span class="n">XOR_KEY</span><span class="p">)</span>
            <span class="k">if</span> <span class="n">api_name</span><span class="p">:</span>
                <span class="n">db</span><span class="p">.</span><span class="n">names</span><span class="p">.</span><span class="nf">force_name</span><span class="p">(</span><span class="n">resolved_out_base</span><span class="p">[</span><span class="n">apis_for_dll</span><span class="p">]</span><span class="o">+</span><span class="p">(</span><span class="n">offset</span><span class="o">*</span><span class="mi">4</span><span class="p">),</span> <span class="n">api_name</span><span class="p">)</span>
                <span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">'</span><span class="si">{</span><span class="n">api_name</span><span class="si">}</span><span class="s"> at </span><span class="si">{</span><span class="nf">hex</span><span class="p">(</span><span class="n">resolved_out_base</span><span class="p">[</span><span class="n">apis_for_dll</span><span class="p">]</span><span class="o">+</span><span class="n">offset</span><span class="o">*</span><span class="mi">4</span><span class="p">)</span><span class="si">}</span><span class="sh">'</span><span class="p">)</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">"</span><span class="s">unable to resolve hash: </span><span class="si">{</span><span class="nf">hex</span><span class="p">(</span><span class="nb">hash</span><span class="p">)</span><span class="si">}</span><span class="s">, at </span><span class="si">{</span><span class="nf">hex</span><span class="p">(</span><span class="n">resolved_out_base</span><span class="p">[</span><span class="n">apis_for_dll</span><span class="p">]</span><span class="o">+</span><span class="p">(</span><span class="n">offset</span><span class="o">*</span><span class="mi">4</span><span class="p">))</span><span class="si">}</span><span class="sh">"</span><span class="p">)</span>
<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="sh">"</span><span class="s">__main__</span><span class="sh">"</span><span class="p">:</span>
    <span class="nf">main</span><span class="p">()</span>

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

<h3 id="2-configuration-loading--privilege-escalation">2. Configuration Loading &amp; Privilege Escalation</h3>

<p>After the resolution of the APIs was complete it moved onto its next section, which I named <code class="language-plaintext highlighter-rouge">load_config_elevate_privileges()</code></p>

<p>It loaded its config as I detailed <a href="#main-configuration-automated-extraction">here</a>.</p>

<p>Then depending on the configuration flags present, performed a variety of functions to try and escalate privileges.
<img src="/assets/BlackMatter/load_escalate_overview.png" alt="load_escalate_overview" /></p>

<p>If it detected the primary token did not have admin privileges but belonged to the admin group it would execute a UAC bypass and restart
<img src="/assets/BlackMatter/uac_bypass.png" alt="uac_bypass" />
<em>Nice post about the technique here - https://medium.com/malware-bistro/cracking-the-code-privilege-escalation-tactics-used-by-lockbit3-0-d24b48337b35</em></p>

<p>It loops through an array of privilege constants to try and enable all privileges it has available. The privilege constants are supposedly a LUID type, which is local to a machine and should be retrieved via the API <em>LookupPrivilegeValueA</em> so interesting the constants are hardcoded
<img src="/assets/BlackMatter/enable_privs.png" alt="enable_privs" /></p>

<p>If it is not running under SYSTEM it attempts to duplicates explorer’s token.</p>

<p><img src="/assets/BlackMatter/explorer_token.png" alt="enable_privs" /></p>

<p><em>Nothing too fancy</em></p>

<p><img src="/assets/BlackMatter/duplicate_token.png" alt="duplicate_token" /></p>

<p>If it cannot duplicate explorer’s token but it is running under Admin it will try to steal the token of a privileged svchost instance. It loops through the _SYSTEM_PROCESS_INFORMATION entries until it finds a process Image that matches the hash of svchost.exe. If this instance is sufficiently privileged it breaks out of the loop.</p>

<p><img src="/assets/BlackMatter/find_svc.png" alt="find_svc" /></p>

<p>If successful and if the svchost instance is 64 bit it will decrypt two shellcode payloads and store them in allocated memory. The first one is actually 64 bit code, which is intended to be injected into svchost to retrieve its token. In the buffer the main process write/patches in its own PID and target process handle (the one that is received from NtDuplicateObject) into the shellcode. These values be used by the shellcode as the argument for the TargetProcessHandle when it makes its call to NtDuplicateObject to duplicate the token.
Then it will decrypt the second shellcode payload which is 32 bit, and patches in the address of the 64 bit shellcode. From there it will execute the 32 bit shellcode, which will utilise the provided address to locate the 64 bit shellcode and inject into the remote process (SvcHost).</p>

<p><em>The arguments will be patched into the shellcode here</em>
<img src="/assets/BlackMatter/64_bit_inj.png" alt="64_bit_inj" /></p>

<p>This 64 bit shellcode duplicate SvcHosts process token.</p>

<p><em>Apis from the shellcode</em></p>

<p><img src="/assets/BlackMatter/shellcode_apis.png" alt="shellcode_apis" /></p>

<p>If the svchost instance is 32 bit, 32 bit shellcode is directly injected into svchost and the main process’s PID and target handle is patched into it.</p>

<p><em>Patching occurring here</em>
<img src="/assets/BlackMatter/patching.png" alt="patching" /></p>

<p>If the <em>find_domain_admins_conf_flag</em> flag is specified it will use the following default credentials to attempt to authenticate to an account.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ad.lab:Qwerty!
Administrator:123QWEqwe!@#
Admin2:P@ssw0rd
Administrator:P@ssw0rd
Administrator:Qwerty!
Administrator:123QWEqwe
Administrator:123QWEqweqwe
</code></pre></div></div>
<p><img src="/assets/BlackMatter/try_logon.png" alt="try_logon" /></p>

<p>It will then decrypt a .ico file and write it to disk in the ProgramData folder.
<img src="/assets/BlackMatter/decrypt_ico.png" alt="decrypt_ico" /></p>

<p>It will then set it as the value for the DefaultIcon registry key.
<img src="/assets/BlackMatter/default_icon_key.png" alt="default_icon_key" /></p>

<p><em>image shown here</em>
<img src="/assets/BlackMatter/ico.png" alt="default_icon_key" /></p>

<p>Finally it will initialise the encryption keys it will use.</p>

<p><img src="/assets/BlackMatter/enc_init.png" alt="enc_init" /></p>

<p>A symmetric random key is generated locally and then a copy is made which is encrypted by the public RSA key. This is later appended to the files to allow for decryption to occur. Then the original version of the symmetric key gets encrypted via <em>rtlEncryptMemory()</em>, which is decrypted on the fly when it is needed for file encryption. This is to reduce the risk of it being exposed in memory.
Regarding the the symmetric key algorithm it is apparently  a custom ChaCha20 algorithm - Chuong Dong has a great post discussing it <a href="https://chuongdong.com/reverse%20engineering/2021/09/05/BlackMatterRansomware/">here</a> during his analysis of a 2021 BlackMatter sample.
After the randomly generated initial ChaCha matrix is produced the final random bytes of the matrix has arithmetic performed on it such that it produces a number within the size of the matrix. This randomly generated value acts as an index in which the first DWORD of the RSA key is inserted into.
<img src="/assets/BlackMatter/random_index.png" alt="random_index" /></p>

<p><em>logic reimplemented in Python</em></p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">idx</span> <span class="o">=</span> <span class="mh">0x07F1CC1</span> <span class="c1"># final 3 random bytes of matrix in little endian
</span>
<span class="n">edx</span> <span class="o">=</span> <span class="p">(</span><span class="n">idx</span> <span class="o">*</span> <span class="mh">0x8088405</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xffffffff</span>
<span class="n">edx</span> <span class="o">=</span> <span class="p">(</span><span class="n">edx</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xffffffff</span>
<span class="n">edx</span> <span class="o">=</span> <span class="p">(</span><span class="n">edx</span> <span class="o">*</span> <span class="mi">120</span><span class="p">)</span><span class="c1"># &amp; 0xff00000000
</span><span class="n">edx</span> <span class="o">=</span> <span class="n">edx</span> <span class="o">&gt;&gt;</span> <span class="mi">32</span>
<span class="nf">print</span><span class="p">(</span><span class="nf">hex</span><span class="p">(</span><span class="n">edx</span><span class="p">))</span>
</code></pre></div></div>
<h3 id="3-cli-parsing--dispatch">3. CLI Parsing &amp; Dispatch</h3>

<p>Finally, it will enter a function I have named <em>parse_cli_and_dispatch()</em></p>

<p>The sample hashes its command line arguments and then enters different functions depending on the result. I ran my extracted strings through the hashing algorithm and found it can be be run with the following commandline arguments.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>-path
-pass
-safe
-wall
-gspd
-psex
-gdel
</code></pre></div></div>

<p><img src="/assets/BlackMatter/check_cli.png" alt="check_cli" />
<img src="/assets/BlackMatter/check_cli_p2.png" alt="check_cli_p2" /></p>

<p>There is one command line argument I did not manage to resolve.</p>

<p><code class="language-plaintext highlighter-rouge">-pass</code> is meant to be supplied by a hands on keyboard operator. A Domain Administrators credentials should be passed as an argument. Due to the presence of this argument, whenever this sample laterally moves or restarts instances of itself, it always makes sure to make a copy of its command line arguments to pass to the new instances.</p>

<p><code class="language-plaintext highlighter-rouge">-psex</code> is not provided by a commandline operator, rather it is determined by the configuration flags. If the configuration flag <em>try_lateral_movement_via_network_shares_conf_flag</em> is present and it manages to gain Domain Admin credentials (either via <code class="language-plaintext highlighter-rouge">-pass</code> or via the default credentials it attempted), it will restart an instance of itself with this commandline.</p>

<p><code class="language-plaintext highlighter-rouge">-gspd</code> is similar however it is determined by the <em>try_lateral_movement_via_GPO_conf_flag</em>.</p>

<p><code class="language-plaintext highlighter-rouge">-wall</code> is again determined by a configuration flag <em>deploy_ransom_notes_on_printer_and_wallpaper_conf_flag</em> and it will restart itself with this command to dispatch the associated functions for creating a wallpaper and enumerating printers.</p>

<p><code class="language-plaintext highlighter-rouge">-path</code> is meant to be supplied by an operator to specify a directory to be encrypted I believe.</p>

<p>The sample will start new instances of itself with <code class="language-plaintext highlighter-rouge">-safe</code> if it detects it is being run outside of normal boot.</p>

<p>The function dispatched from the CLI argument I could not resolve leads to <code class="language-plaintext highlighter-rouge">-gdel</code> being passed the new instance.</p>

<p>If no command line argument is supplied it will generate a mutex name from hashing its public RSA key. If this has already been created by a prior instance it will either exit, or load and dispatch a child process to securely erase its current image from the disk. Otherwise it will create the mutex itself.
<img src="/assets/BlackMatter/run_once.png" alt="run_once" /></p>

<p>If no command line is supplied as mentioned it will start of by checking if it has managed to acquire any Domain Admin credentials and which configuration flags have been supplied.
<img src="/assets/BlackMatter/initial_check.png" alt="initial_check" /></p>

<h3 id="try-lateral-movement-via-network-shares">Try lateral movement via network shares</h3>

<p>First I will discuss the <em>try_lateral_movement_via_network_shares_conf_flag</em> case.
It will restart itself with the commandline <code class="language-plaintext highlighter-rouge">-psex</code> (if it also managed to breach a Domain Admin).
Once the new instance reaches the <em>parse_cli_and_dispatch()</em> function it will enter <em>if_psex()</em>. First it will create a named pipe derived from its public RSA key. Then it will enter <em>psex_main()</em>.</p>

<p>It will then create a named pipe derived from its computer name. It also duplicates a handle to this pipe into explorer or LSASS which may be a trick to keep the handle from closing - https://f3real.github.io/duplicatehandle.html
<img src="/assets/BlackMatter/make_computer_name_pipe.png" alt="make_computer_name_pipe" /></p>

<p><img src="/assets/BlackMatter/overview_lateral.png" alt="overview_lateral" /></p>

<p>Then it generate a list of the DnsHostName of all the Domain Controllers and computers in the domain.
<img src="/assets/BlackMatter/enum_domain.png" alt="enum_domain" /></p>

<p>It will generate the following strings.</p>

<p><img src="/assets/BlackMatter/strings1.png" alt="strings1" />
<img src="/assets/BlackMatter/strings2.png" alt="strings2" /></p>

<p>With the acquired computer names it will check which devices it can connect to via the API <em>WNetAddConnection2A()</em> specifying the ADMIN$ share and IPC$ share of the target computer.
<img src="/assets/BlackMatter/more_shares.png" alt="more_shares" />
<img src="/assets/BlackMatter/wnet.png" alt="wnet" /></p>

<p>If this succeeds it will hash the computer names it has acquired to generate a hex string, which it uses as a fingerprint for a variety of strings. It will create the string <code class="language-plaintext highlighter-rouge">{computer_name}ADMIN$\Temp</code> and make this directory on the Admin shares of the enumerated computers. Then it will get its own image path and call <em>CopyFileW()</em> with <code class="language-plaintext highlighter-rouge">{computer_name}\ADMIN$\Temp\{dcNameFingerprint}_IPC$.exe</code> outlined as the target destination, effectively copying itself into the admin share of the enumerated computers.</p>

<p>It will then call <em>CreateServiceW()</em> with the binary path <code class="language-plaintext highlighter-rouge">%%SystemRoot%%\Temp\{computer_name}_IPC$.exe -k LocalServiceNetworkRestricted [-pass {breached_creds}]</code> to execute the copied instance.</p>

<p><img src="/assets/BlackMatter/move_lateral_shares.png" alt="move_lateral_shares" /></p>

<p>Then it will create the name pipe <code class="language-plaintext highlighter-rouge">{computer_name}\\pipe\{computer_name_fingerprint}_IPC$</code>, and copy its own CLI into it. The newly infected computers will be able to retrieve this the named pipe is derived via a hash of their computer name. This is presumably to allow breached credentials to propagate to the newly infected computers.</p>

<p>The copied instances will register the <em>retrieve_data_from_fingerprint_share_wrap()</em> function as their service main, which just copies out the data/cli from the shared buffer. 
<img src="/assets/BlackMatter/register_service_main.png" alt="register_service_main" /></p>

<h3 id="try-lateral-movement-via-gpo">Try lateral movement via GPO</h3>

<p>If the <em>try_lateral_movement_via_GPO_conf_flag</em> flag is set and it has acquired Domain Admin credentials it will restart itself with the command line argument <code class="language-plaintext highlighter-rouge">-gspd</code>. Once the dispatching function is reached, it will start off by copying its command line into a named pipe derived from the public RSA key.
<img src="/assets/BlackMatter/gspd_overview.png" alt="gspd_overview" /></p>

<p>It will enumerate the Domains policies container for a DistinguishedName that matches something derived from its Public RSA key.
<img src="/assets/BlackMatter/enum_gpo.png" alt="gspd_overview" /></p>

<p>If it does not already exist, it will then retrieves the IID <em>IGroupPolicyObject</em> as well as the current domain name, then dispatches a variety of functions to create the group policy object and create policies for it.</p>

<p><img src="/assets/BlackMatter/create_gpo_overview.png" alt="create_gpo_overview" /></p>

<p><em>I used the following powershell commands to enumerate the Windows SDK for the interface names associated with RIIDs</em>
<code class="language-plaintext highlighter-rouge">C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\um&gt; Select-String -Path *.h -Pattern [Pattern] -Context 5,5</code></p>

<p>It uses this to create new group policy object with the display name set as the global fingerprint, and links it to the current Domain.</p>

<p><img src="/assets/BlackMatter/link_gpo.png" alt="link_gpo" /></p>

<p>It then associates attributes the group policy object. Googling the group policy IDs shows it relates to allowing administrative templates, files and scheduled tasks to run without restriction.</p>

<p><img src="/assets/BlackMatter/set_info.png" alt="set_info" /></p>

<p><img src="/assets/BlackMatter/set_info2.png" alt="set_info2" /></p>

<p>It basically does a bunch more stuff with initliasing the GPO object.
It configures a services.xml which outlines to disable various services. Disabling these services prevents sensitive files from being locked when attempting to encrypt them.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;NTServices clsid="{2CFB484A-4E96-4b5d-A0B6-093D2F91E6AE}"&gt;
        &lt;NTService clsid="{AB6F0B67-341F-4e51-92F9-005FBFBA1A43}" name="SQLPBDMS" image="4" changed="%s" uid="%s" disabled="0"&gt;&lt;Properties startupType="DISABLED" serviceName="SQLPBDMS" serviceAction="STOP" timeout="30"/&gt;&lt;/NTService&gt;  
        &lt;NTService clsid="{AB6F0B67-341F-4e51-92F9-005FBFBA1A43}" name="SQLPBENGINE" image="4" changed="%s" uid="%s" 
disabled="0"&gt;&lt;Properties startupType="DISABLED" serviceName="SQLPBENGINE" serviceAction="STOP" timeout="30"/&gt;&lt;/NTService&gt;
        &lt;NTService clsid="{AB6F0B67-341F-4e51-92F9-005FBFBA1A43}" name="MSSQLFDLauncher" image="4" changed="%s" uid="%s" userContext="0" removePolicy="0" disabled="0"&gt;&lt;Properties startupType="DISABLED" serviceName="MSSQLFDLauncher" serviceAction="STOP" timeout="30"/&gt;&lt;/NTService&gt;
        &lt;NTService clsid="{AB6F0B67-341F-4e51-92F9-005FBFBA1A43}" name="SQLSERVERAGENT" image="4" changed="%s" uid="%s" disabled="0"&gt;&lt;Properties startupType="DISABLED" serviceName="SQLSERVERAGENT" serviceAction="STOP" timeout="30"/&gt;&lt;/NTService&gt;
        &lt;NTService clsid="{AB6F0B67-341F-4e51-92F9-005FBFBA1A43}" name="MSSQLServerOLAPService" image="4" changed="%s" uid="%s" disabled="0"&gt;&lt;Properties startupType="DISABLED" serviceName="MSSQLServerOLAPService" serviceAction="STOP" 
timeout="30"/&gt;&lt;/NTService&gt;
        &lt;NTService clsid="{AB6F0B67-341F-4e51-92F9-005FBFBA1A43}" name="SSASTELEMETRY" image="4" changed="%s" uid="%s" disabled="0"&gt;&lt;Properties startupType="DISABLED" serviceName="SSASTELEMETRY" serviceAction="STOP" timeout="30"/&gt;&lt;/NTService&gt;
        &lt;NTService clsid="{AB6F0B67-341F-4e51-92F9-005FBFBA1A43}" name="SQLBrowser" image="4" changed="%s" uid="%s" disabled="0"&gt;&lt;Properties startupType="DISABLED" serviceName="SQLBrowser" serviceAction="STOP" timeout="30"/&gt;&lt;/NTService&gt;
        &lt;NTService clsid="{AB6F0B67-341F-4e51-92F9-005FBFBA1A43}" name="SQL Server Distributed Replay Client" image="4" changed="%s" uid="%s" disabled="0"&gt;&lt;Properties startupType="DISABLED" serviceName="SQL Server Distributed Replay Client" serviceAction="STOP" timeout="30"/&gt;&lt;/NTService&gt;
        &lt;NTService clsid="{AB6F0B67-341F-4e51-92F9-005FBFBA1A43}" name="SQL Server Distributed Replay Controller" image="4" changed="%s" uid="%s" disabled="0"&gt;&lt;Properties startupType="DISABLED" serviceName="SQL Server Distributed Replay Controller" serviceAction="STOP" timeout="30"/&gt;&lt;/NTService&gt;
        &lt;NTService clsid="{AB6F0B67-341F-4e51-92F9-005FBFBA1A43}" name="MsDtsServer150" image="4" changed="%s" uid="%s" disabled="0"&gt;&lt;Properties startupType="DISABLED" serviceName="MsDtsServer150" serviceAction="STOP" timeout="30"/&gt;&lt;/NTService&gt;
        &lt;NTService clsid="{AB6F0B67-341F-4e51-92F9-005FBFBA1A43}" name="SSISTELEMETRY150" image="4" changed="%s" uid="%s" disabled="0"&gt;&lt;Properties startupType="DISABLED" serviceName="SSISTELEMETRY150" serviceAction="STOP" timeout="30"/&gt;&lt;/NTService&gt;
        &lt;NTService clsid="{AB6F0B67-341F-4e51-92F9-005FBFBA1A43}" name="SSISScaleOutMaster150" image="4" changed="%s" uid="%s" disabled="0"&gt;&lt;Properties startupType="DISABLED" serviceName="SSISScaleOutMaster150" serviceAction="STOP" timeout="30"/&gt;&lt;/NTService&gt;
        &lt;NTService clsid="{AB6F0B67-341F-4e51-92F9-005FBFBA1A43}" name="SSISScaleOutWorker150" image="4" changed="%s" uid="%s" disabled="0"&gt;&lt;Properties startupType="DISABLED" serviceName="SSISScaleOutWorker150" serviceAction="STOP" timeout="30"/&gt;&lt;/NTService&gt;
        &lt;NTService clsid="{AB6F0B67-341F-4e51-92F9-005FBFBA1A43}" name="MSSQLLaunchpad" image="4" changed="%s" uid="%s" disabled="0"&gt;&lt;Properties startupType="DISABLED" serviceName="MSSQLLaunchpad" serviceAction="STOP" timeout="30"/&gt;&lt;/NTService&gt;
        &lt;NTService clsid="{AB6F0B67-341F-4e51-92F9-005FBFBA1A43}" name="SQLWriter" image="4" changed="%s" uid="%s" disabled="0"&gt;&lt;Properties startupType="DISABLED" serviceName="SQLWriter" serviceAction="STOP" timeout="30"/&gt;&lt;/NTService&gt;        &lt;NTService clsid="{AB6F0B67-341F-4e51-92F9-005FBFBA1A43}" name="SQLTELEMETRY" image="4" changed="%s" uid="%s" disabled="0"&gt;&lt;Properties startupType="DISABLED" serviceName="SQLTELEMETRY" serviceAction="STOP" timeout="30"/&gt;&lt;/NTService&gt;
        &lt;NTService clsid="{AB6F0B67-341F-4e51-92F9-005FBFBA1A43}" name="MSSQLSERVER" image="4" changed="%s" uid="%s" 
disabled="0"&gt;&lt;Properties startupType="DISABLED" serviceName="MSSQLSERVER" serviceAction="STOP" timeout="60"/&gt;&lt;/NTService&gt;
&lt;/NTServices&gt;
</code></pre></div></div>

<p>It then copies itself into the domain controllers SYSVOL scripts directory. This is how it spreads to the other machines as it subsequently creates a scheduled task so that other computers download it from the SYSVOL path and execute it.
<img src="/assets/BlackMatter/copy__sysvol.png" alt="copy__sysvol" /></p>

<p>It then creates the configuration file <code class="language-plaintext highlighter-rouge">{GpoSysPath}\Preferences\files.xml</code> for the GPO object with the values</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;Files clsid="{215B2E53-57CE-475c-80FE-9EEC14635851}"&gt;
        &lt;File clsid="{50BE44C8-567A-4ed1-B1D0-9234FE1F38AF}" name="%s" status="%s" image="2" bypassErrors="1" changed="%s" uid="%s"&gt;
        &lt;Properties action="U" fromPath="%s" targetPath="%s" readOnly="0" archive="1" hidden="0" suppress="0"/&gt;      
        &lt;/File&gt;
&lt;/Files&gt;

</code></pre></div></div>
<p>The format specifiers are filled out as such:
<img src="/assets/BlackMatter/format_specs.png" alt="format_specs" /></p>

<p>Which gets the victims to download the file from the infected DCs SYSVOL scripts directory, into their temp directory.</p>

<p>Then it finally creates the scheduled tasks configuration file <code class="language-plaintext highlighter-rouge">{GpoSysPath}\Preferences\ScheduledTasks\ScheduledTasks.xml</code>
<img src="/assets/BlackMatter/sched_task.png" alt="sched_task" /></p>

<p>So when the scheduled task is run it gets the victims to download the file into their temp directory and then run it as SYSTEM with a copy of the original CLI.</p>

<p>That fully completes the GPO object and now it just needs to be pushed to the victims.</p>

<p>If the <em>push_GPO_updates_immediately_conf_flag</em> flag is set it will run powershell with the command <code class="language-plaintext highlighter-rouge">powershell Get-ADComputer -filter * -Searchbase '%s' | Foreach-Object { Invoke-GPUpdate -computer $_.name -force -RandomDelayInMinutes 0}</code>.
It will build the string to retrieve the Domains default naming context for the above command.</p>

<p><img src="/assets/BlackMatter/powershell.png" alt="powershell" /></p>

<p>Otherwise it will just wait for policy to go out naturally.</p>

<p>It will then create the registering key <code class="language-plaintext highlighter-rouge">Software\Microsoft\Windows\CurrentVersion\Group Policy\Status\{RSA_fingerprint}</code> if it does not yet exist.</p>

<p><img src="/assets/BlackMatter/reg_key.png" alt="reg_key" /></p>

<p>Then if a configuration flag is set it will use <em>OpenDSGPO()</em> and <em>GetMachineName()</em> with the GPO object.
<img src="/assets/BlackMatter/get_machine_name.png" alt="get_machine_name" /></p>

<p>With the retrieved name it will copy the following executable <code class="language-plaintext highlighter-rouge">d641ad955ef4cff5f0239072b3990d47e17b9840e07fd5feea93c372147313c5</code> into the network share <code class="language-plaintext highlighter-rouge">{machine_name}\ADMIN$\Temp\{machine_name_fingerprint_IPC$}.exe</code> and start it as a service. It basically uses the same workflow as the <em>lateral movement via network shares path</em> to do this. This action will also be taken when the <code class="language-plaintext highlighter-rouge">-gdel</code> command line argument is specified. I’m not entirely sure about this section but I think this would be executed on the remote machines and this copies an executable which performs a secure deletion of the main image on the original device.
<img src="/assets/BlackMatter/network_share_gdel.png" alt="network_share_gdel" /></p>

<h3 id="loaded-eraser-executable">Loaded eraser executable</h3>
<p>Sha256 from psuedo-unmapping it: <code class="language-plaintext highlighter-rouge">185f6d6bf0ddcd39f253413f28c0d12f46a82e663bdf6287cb73a362a33c91e7</code></p>

<p>Available at Malshare here: https://malshare.com/sample.php?action=detail&amp;hash=185f6d6bf0ddcd39f253413f28c0d12f46a82e663bdf6287cb73a362a33c91e7</p>

<p>Following the encryption of the files it will then potentially load an executable that aims to delete the ransomware binary.
<img src="/assets/BlackMatter/loader.png" alt="loader" /></p>

<p><em>This screenshot shows a brief overview of the encryption workflow, which I did not explore here due to length.</em>
<img src="/assets/BlackMatter/enc_overviewp1.png" alt="enc_overviewp1" />
<img src="/assets/BlackMatter/enc_overviewp2.png" alt="enc_overviewp2" /></p>

<p>The loading function will create a file on disk in the ProgramData folder with a name from <em>GetTempFileNameW()</em> and writes an encrypted executable to this path. Only the text segment is encrypted, and it has valid PE headers. It is then loaded into memory via <em>CreateProcess()</em> with the suspended flag, and then the payload is decrypted in memory.
<img src="/assets/BlackMatter/create_sus.png" alt="create_sus" /></p>

<p><img src="/assets/BlackMatter/loaded_decrypt.png" alt="loaded_decrypt" /></p>

<p>The process/ main thread is then resumed and a named pipe is set up with this process, which is derived via a hash of its executable file contents on disk.</p>

<p><img src="/assets/BlackMatter/resume.png" alt="resume" /></p>

<p>This named pipe has the following content.</p>
<pre><code class="language-C">struct NamedPipeBufferFormat
{
  DWORD IsDc;
  DWORD do_system_shutdown;
  DWORD overwite_all_data_disk;
  DWORD secure_erase_main_image;
  DWORD hDuplicatedMainProcess;
  char main_image_name[520];
};
</code></pre>
<p>In which the options <em>do_system_shutdown</em>, <em>overwite_all_data_disk</em> and <em>secure_erase_main_image</em> originate from configuration flags.</p>

<p>The loaded process utilises a TLS callback to perform API resolution via hashing and also scrambles all the function pointers in the same manner the main binary did <a href="#1-api-resolution">here</a>, including its own native functions. For the API hashing it uses the hash derived from the DLL as an xor key for the API name hash. This seed usage makes it more challenging to utilise a hash database such as hashdb.
<img src="/assets/BlackMatter/api_hash_combine.png" alt="api_hash_combine" /></p>

<p>So I just resolved it in x64dbg, utilising the command breakpoint:
<code class="language-plaintext highlighter-rouge">log "caller = 0x{[esp + 0x20]}:{label@eax}"</code>
<img src="/assets/BlackMatter/x64dbg_cmd.png" alt="x64dbg_cmd" /></p>

<p><img src="/assets/BlackMatter/x64dbg_output.png" alt="x64dbg_output" /></p>

<p>Since it also modifed the pointers to a variety of its own function pointers I had to create a Vtable struct and have my IDA setup with a pane for viewing the vtable struct at all times.
<img src="/assets/BlackMatter/ugly.png" alt="ugly" /></p>

<p>The sample also implements an interesting anti-debug trick. It patches the entry point of the <em>DbgUiRemoteBreakin()</em> with the first 32 bytes of the function that is performing the patch. This would presumably cause any debug attach events to crash. It seems an appropriate anti-debug method given the large amount of I/O operations this process performs (thus giving ample time to attach a debugger), attaching to it while it’s running would not be the worst method to unpack this sample.</p>

<p><img src="/assets/BlackMatter/dbg_ui.png" alt="dbg_ui" /></p>

<p><em>bytes that would be patched into the entry point of DbgUiRemoteBreakin()</em>
<img src="/assets/BlackMatter/new_entry.png" alt="new_entry" /></p>

<p>Once the TLS callback finishes and the main thread starts it will generate a hash of its disk content so it can access the named pipe, which provides it arguments on which functions to perform.
<img src="/assets/BlackMatter/hash_self.png" alt="hash_self" />
<img src="/assets/BlackMatter/connect_pipe.png" alt="connect_pipe" /></p>

<p>It then waits for the main process to finish via <em>WaitForSingleObject()</em>, with the handle to the process retrieved from the named pipe.</p>

<p><em>overview of main procedures</em></p>

<p><img src="/assets/BlackMatter/overview_eraser.png" alt="overview_eraser" /></p>

<p>If the secure erase of the main image flag is set, it will retrieve the main image name via the name pipe. Then it will open a handle to the file with <em>FILE_FLAG_WRITE_THROUGH</em> (specifies operations go straight to disk with no caching) and write randomly generated bytes backwards and forwards into the file in a loop. this aims to make the original file unrecoverable through digital forensic tools.</p>

<p><img src="/assets/BlackMatter/secure_erase.png" alt="secure_erase" /></p>

<p>If a sharing access error occurs it will register the image as a RmResource so that it can terminate the service or process accessing the image.
<img src="/assets/BlackMatter/registeRM.png" alt="registeRM" /></p>

<p>If the <em>overwrite all data on disk flag</em> is set it will initialise a thread pool with twice number of processors x2 + 1 threads. These threads sit in a waiting state until they are manually dispatched later by <em>PostQueuedCompletionStatus()</em>.
<img src="/assets/BlackMatter/thread_pool.png" alt="thread_pool" /></p>

<p>It then gets a list of all the fixed drives and removable drives on the system.
<img src="/assets/BlackMatter/get_drive_p1.png" alt="get_drive_p1" />
<img src="/assets/BlackMatter/get_drive_p2.png" alt="get_drive_p2" /></p>

<p>For each drive it retrieves it will convert the drive path to an UNC extended path (\\?\) and appends 6 random characters, and uses this to create a directory (\\?\{drive_letter}\{random}.</p>

<p>Then for each drive it will create a thread to execute a function which ultimately dispatches a the thread in the worker pool from earlier.
<img src="/assets/BlackMatter/create_thread_.png" alt="create_thread_" /></p>

<p>It creates a temp file in the newly created directory and calculates info about the space available on the disk. Then it registers the file with the IOCompletion port from earlier. It will create an Overlapped structure with randomly generated bytes and then manually dispatches a thread from the worker thread pool via a call to <em>PostQueuedCompletionStatus()</em> and passes in the overlapped structure containing the randomly generated bytes.
<img src="/assets/BlackMatter/postQueue.png" alt="postQueue" /></p>

<p>The dispatched thread will fill up the temporary file until a <em>ERROR_DISK_FULL</em> error is reached.
<img src="/assets/BlackMatter/disk_full.png" alt="disk_full" />.</p>

<p>I assume this done in case there are any orphan files on the drive, which could essentially act as backups for sensitive data that the ransomware encrypted.</p>

<p>Following this, the executable will always delete its image. However if it is given the flag to shutdown the system (presumably so it can be restarted with safe mode for the -safe command line actions), it will use a trick to schedule itself for deletion via calling <em>MoveFileExW(curFileShortPath, 0, MOVEFILE_DELAY_UNTIL_REBOOT)</em>. This will copy itself into a non existant path on reboot, then it calls <em>NtShutdownSystem()</em>. However it will avoid doing this is the named pipe arguments indicate that it is running as a Domain Controller.</p>

<p>Otherwise it will just delete itself via the cmd command <code class="language-plaintext highlighter-rouge">/C DEL /F /Q "cur_image" &gt;&gt; NUL</code>.</p>

<p><img src="/assets/BlackMatter/self_delete_.png" alt="self_delete_" />.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[BlackMatter Ransomware Analysis]]></summary></entry><entry><title type="html">Z2A Challenge #3 – Oski Stealer String Decryption</title><link href="https://kzhong-sec.github.io/2025/06/12/z2a-challenge-3-oski-string-decryption.html" rel="alternate" type="text/html" title="Z2A Challenge #3 – Oski Stealer String Decryption" /><published>2025-06-12T00:00:00+10:00</published><updated>2025-06-12T00:00:00+10:00</updated><id>https://kzhong-sec.github.io/2025/06/12/z2a-challenge-3-oski-string-decryption</id><content type="html" xml:base="https://kzhong-sec.github.io/2025/06/12/z2a-challenge-3-oski-string-decryption.html"><![CDATA[<p>This is my belated write-up for Zero 2 Automated's Challenge #3 – Oski Stealer String Decryption.</p>

<p>The goal was to develop an automated string decryptor for the final payload. The sample is initially packed with a .NET packer which is why I was interested in this challenge as I wanted to get more reps with .NET samples.</p>

<p>First Stage SHA256: 707adf85c61f5029e14aa27791010f2959e70c0fee182fe968d2eb7f2991797b</p>

<h2>Unpacking the .NET Sample</h2>

<p><img src="/assets/z2a-challenge-3-oski-string-decryption/die_initial_sample.png" style="width: 90%;" /></p>

<p>Initial triage showed it uses a known obfuscator, so I started by trying to run it through de4dot, which successfully produced a cleaned version.</p>

<p>With .NET samples, I usually start by looking at cross-references to the <b>Assembly</b> class, since many samples use this to load additional payloads. Given that this sample is packed, it's definitely worth checking out.</p>

<p><img src="/assets/z2a-challenge-3-oski-string-decryption/assembly_cross_references.png" style="width: 90%;" /></p>

<p>Looking at references to assembly, there are four calls to methods from the class from non-library/runtime code.</p>

<p>The most interesting one is a method I’ve named <b>Load_byte_array()</b>, which is just a wrapper around AppDomain.CurrentDomain.Load().</p>

<p><img src="/assets/z2a-challenge-3-oski-string-decryption/load_byte_array.png" style="width: 70%;" /></p>

<p>Looking at the references to <b>Load_byte_array()</b> shows a method I named <b>retrieve_and_dec_rsrc()</b> as it can clearly be seen getting the resource <b>BayesMe</b>, then calling a decryption function on the resource.</p>

<p><img src="/assets/z2a-challenge-3-oski-string-decryption/retrieve_and_dec_rsrc.png" style="width: 100%;" /></p>

<p>This seemed like a good chance to dynamically retrieve the decrypted resource, so I set a breakpoint after the call to the decryption function, then dumped the local variable <i>array</i> that held the result.</p>

<p><img src="/assets/z2a-challenge-3-oski-string-decryption/mz_magic.png" style="width: 70%;" /></p>

<p>This appeared to be a valid executable file as the MZ magic was seen.</p>

<p>Stepping out of the method showed immediate call to <b>Invoke()</b> and <b>Run()</b>, verifying it is not a dummy file and is actually invoked.</p>

<p><img src="/assets/z2a-challenge-3-oski-string-decryption/invoke_and_run.png" style="width: 90%;" /></p>

<p>The local variables debugging Window showed that the <i>methodInfo</i> variable is a reference to the method <b>EhgUZIvRw()</b>.</p>

<p><img src="/assets/z2a-challenge-3-oski-string-decryption/method_info_debug.png" style="width: 80%;" /></p>

<p>Searching for this method showed it belongs to the loaded assembly <b>FuncAttribute.dll</b></p>

<p><img src="/assets/z2a-challenge-3-oski-string-decryption/func_attribute_method.png" style="width: 90%;" /></p>

<p>This assembly looked decently obfuscated as well, so I tried running it through de4dot. It was not recognised as a known obfuscator so I skipped cleaning and just analysed it as-is.</p>

<p><img src="/assets/z2a-challenge-3-oski-string-decryption/de4dot_unregonised.png" style="width: 70%;" /></p>

<p>A quick look inside the methods it calls show that this method appears to load another assembly and invoke a method from it.</p>

<p><img src="/assets/z2a-challenge-3-oski-string-decryption/loading_additional_stage.png" style="width: 100%;" /></p>

<p>I set breakpoints on the Invoke and AssemblyLoad methods and ran the sample. 
This showed it loading another assembly and calling the method <b>fQRwCeWyVS()</b> from it.</p>

<p><img src="/assets/z2a-challenge-3-oski-string-decryption/method_fQRwCeWyVS.png" style="width: 70%;" /></p>

<p>I dumped the binary and ran it through de4dot — which detected it as a <b>Reactor</b> protected sample, which it managed to successfully clean.</p>

<p><img src="/assets/z2a-challenge-3-oski-string-decryption/reactor_cleaned.png" style="width: 70%;" /></p>

<p>To make dynamic analysis easier, I ran the sample again and overwrote the variable passed to LoadAssembly with the cleaned de4dot sample. I did this by opening the cleaned sample in CyberChef and running the recipe '<i>to hex</i>'. Then in the debugging context I opened the <i>array</i> variable in the memory view and pasted over it.</p>

<p>This made the decompilation a lot cleaner:</p>

<p><i>Cleaned</i></p>

<p><img src="/assets/z2a-challenge-3-oski-string-decryption/cleaned.png" style="width: 90%;" /></p>

<p>vs</p>

<p><i>Original</i></p>

<p><img src="/assets/z2a-challenge-3-oski-string-decryption/original.png" style="width: 90%;" /></p>

<p>This now showed the call to Invoke targeting the method <b>smethod_10()</b></p>

<p><img src="/assets/z2a-challenge-3-oski-string-decryption/method_smethod10.png" style="width: 90%;" /></p>

<p>I did some basic markup and which showed this sample had variety of functionalities, however it would use hardcoded flags to determine which components to actually execute.</p>

<p><img src="/assets/z2a-challenge-3-oski-string-decryption/functionality_overview.png" style="width: 90%;" /></p>

<p>These flags are set by the Class constructor /cctor.</p>

<p><img src="/assets/z2a-challenge-3-oski-string-decryption/cctor.png" style="width: 90%;" /></p>

<p>Stepping through the program shows that this specific sample calls <b>find_and_inject_process()</b>.</p>

<p>This method uses unmanaged code to retrieve Win APIs to make the injection possible.</p>

<p><img src="/assets/z2a-challenge-3-oski-string-decryption/retrieving_unmanaged_code.png" style="width: 90%;" /></p>

<p>Of most interest within this method is the call to WriteProcessMemory, as the variable <i>byte_1</i> will contain a buffer that is injected into the victim process.  
By setting a breakpoint on WriteProcessMemory, I saw that the buffer being injected is a C++ compiled executable, which is presumably the final payload.</p>

<p><img src="/assets/z2a-challenge-3-oski-string-decryption/write_process_mem.png" style="width: 80%;" /></p>

<h2>Final Payload and String Extraction</h2>

<h3>Finding the Decryption Function</h3>

<p>I began analysis by taking a quick look in PeStudio. This showed what appeared to be a large amount of encrypted strings in the <i>.rdata</i> section.</p>

<p><img src="/assets/z2a-challenge-3-oski-string-decryption/pestudio_rdata.png" style="width: 80%;" /></p>

<p>Since the goal is to decrypt the strings, I started by going to the <i>.rdata</i> section in IDA and finding cross references to the strings.</p>

<p>The encrypted strings can easily be identified in IDA.</p>

<p><img src="/assets/z2a-challenge-3-oski-string-decryption/ida_rdata.png" style="width: 80%;" /></p>

<p>It looks like they are all passed to a central decryption function <b>decrypt_strings()</b>.</p>

<p><img src="/assets/z2a-challenge-3-oski-string-decryption/decrypt_strings_xrefs.png" style="width: 80%;" /></p>

<p>Although not the point of the challenge I did develop an IDA debugging script to immediately resolve all the strings, with no real reverse engineering required.</p>

<p><img src="/assets/z2a-challenge-3-oski-string-decryption/resolved_debugging.png" style="width: 90%;" /></p>

<h3>Analyzing the Decryption Function</h3>

<p>Back to the actual challenge.</p>

<p>The encrypted strings look to be base64 encoded, however inputting them into a base64 decoder did not return anything legible.  
My initial hunch was that this could be a custom base64 encoding so I took a quick look around to try and find a modified base64 index string.</p>

<p><img src="/assets/z2a-challenge-3-oski-string-decryption/base64_index_string.png" style="width: 70%;" /></p>

<p>It does appear the sample uses a standard base64 index string, so this isn’t a custom variant. (The string above is referenced as a global within the decryption function).</p>

<p>Looking deeper into the decryption function, showed lots of functions relating to C++ std::string handling such as small string optimization operations.</p>

<p>As such I create a C++ std::string struct in IDA to help analyze this.</p>

<p><img src="/assets/z2a-challenge-3-oski-string-decryption/ida_struct_std_string.png" style="width: 70%;" /></p>

<p>This made the analysis of this function much easier, and the decryption flow became much clearer. The function base64-decodes the string, then passes it to another function that I initially labelled <b>looks_like_decryption()</b>.</p>

<p><img src="/assets/z2a-challenge-3-oski-string-decryption/decryption_function_annotated.png" style="width: 90%;" /></p>

<p>After taking a closer look at <b>looks_like_decryption()</b>, it was unmistakable as RC4. I should have looked closer earlier, as that would have saved me from reversing all the std::string handling.</p>

<p><img src="/assets/z2a-challenge-3-oski-string-decryption/rc4.png" style="width: 90%;" /></p>

<p>I verified my analysis with Cyberchef.</p>

<p><img src="/assets/z2a-challenge-3-oski-string-decryption/cyberchef_verification_1.png" style="width: 100%;" /></p>

<p><img src="/assets/z2a-challenge-3-oski-string-decryption/cyberchef_verification_2.png" style="width: 100%;" /></p>

<h2>Automating String Extraction</h2>

<p>I moved on to writing a script that would extract and decrypt the strings automatically.  
From my analysis:</p>

<ul>
    <li>The RC4 key is an 18-byte ASCII string containing only digits.</li>
    <li>The decryption function is the most-called function in the binary.</li>
</ul>

<p>With this it might be possible to develop regex to extract the RC4 key, and extract the encrypted strings by retrieving all the arguments to the most called function in the binary. This should be able to run headlessly with IDA, however I could not try it as I only have IDA home.</p>

<p>With some proof of concept code I can successfully extract the RC4 key from this sample with regex.</p>

<p><img src="/assets/z2a-challenge-3-oski-string-decryption/poc_regex.png" style="width: 90%;" /></p>

<p>I can also identify the decryption function by using IDA to retrieve the function with the highest cross reference count.</p>

<p><img src="/assets/z2a-challenge-3-oski-string-decryption/poc_func_extract.png" style="width: 90%;" /></p>

<p>The final developed script can be seen working below, and should be able to be integrated into a fully automated workflow.</p>

<p><img src="/assets/z2a-challenge-3-oski-string-decryption/final_script.png" style="width: 100%;" /></p>

<p>The actual code is shown below:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">pefile</span>
<span class="kn">from</span> <span class="n">binascii</span> <span class="kn">import</span> <span class="o">*</span>
<span class="kn">import</span> <span class="n">re</span>
<span class="kn">import</span> <span class="n">base64</span>
<span class="kn">from</span> <span class="n">Crypto.Cipher</span> <span class="kn">import</span> <span class="n">ARC4</span>

<span class="k">def</span> <span class="nf">retrive_rdata</span><span class="p">(</span><span class="n">fpath</span><span class="p">):</span>
    <span class="n">oski</span> <span class="o">=</span> <span class="n">pefile</span><span class="p">.</span><span class="nc">PE</span><span class="p">(</span><span class="n">fpath</span><span class="p">)</span>
    <span class="k">for</span> <span class="n">section</span> <span class="ow">in</span> <span class="n">oski</span><span class="p">.</span><span class="n">sections</span><span class="p">:</span>
        <span class="k">if</span> <span class="sa">b</span><span class="sh">'</span><span class="s">.rdata</span><span class="sh">'</span> <span class="ow">in</span> <span class="n">section</span><span class="p">.</span><span class="n">Name</span><span class="p">:</span>
            <span class="n">oski_rdata</span> <span class="o">=</span> <span class="n">section</span><span class="p">.</span><span class="nf">get_data</span><span class="p">()</span>
            <span class="k">break</span>
            
    <span class="k">return</span> <span class="n">oski_rdata</span>
<span class="k">def</span> <span class="nf">extract_rc4_key</span><span class="p">(</span><span class="n">rdata</span><span class="p">):</span>
    <span class="n">matches</span> <span class="o">=</span> <span class="n">re</span><span class="p">.</span><span class="nf">findall</span><span class="p">(</span><span class="sa">rb</span><span class="sh">'</span><span class="s">[0-9]{12,32}\x00</span><span class="sh">'</span><span class="p">,</span> <span class="n">rdata</span><span class="p">)</span>
    
    <span class="k">if</span> <span class="nf">len</span><span class="p">(</span><span class="n">matches</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">1</span><span class="p">:</span>
        <span class="nf">print</span><span class="p">(</span><span class="sh">'</span><span class="s">Unsuccessful extracting key</span><span class="sh">'</span><span class="p">)</span>
        <span class="k">return</span> <span class="bp">None</span>
        
    <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="n">matches</span><span class="p">:</span>
        <span class="nf">return </span><span class="p">(</span><span class="n">m</span><span class="p">[:</span><span class="o">-</span><span class="mi">1</span><span class="p">].</span><span class="nf">decode</span><span class="p">())</span>

<span class="k">def</span> <span class="nf">get_most_called_func</span><span class="p">():</span>
    <span class="n">functionCount</span> <span class="o">=</span> <span class="p">[]</span>
    <span class="k">for</span> <span class="n">func</span> <span class="ow">in</span> <span class="nc">Functions</span><span class="p">():</span>
        <span class="n">xref_count</span> <span class="o">=</span> <span class="mi">0</span>
        <span class="k">for</span> <span class="n">xref</span> <span class="ow">in</span> <span class="nc">XrefsTo</span><span class="p">(</span><span class="n">func</span><span class="p">):</span>
            <span class="n">xref_count</span> <span class="o">+=</span> <span class="mi">1</span>
        <span class="n">functionCount</span><span class="p">.</span><span class="nf">append</span><span class="p">((</span><span class="n">func</span><span class="p">,</span> <span class="n">xref_count</span><span class="p">))</span>
        
    <span class="n">funcs_sorted</span> <span class="o">=</span> <span class="p">(</span><span class="nf">sorted</span><span class="p">(</span><span class="n">functionCount</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">item</span><span class="p">:</span> <span class="n">item</span><span class="p">[</span><span class="mi">1</span><span class="p">]))</span>
    <span class="n">most_called</span> <span class="o">=</span> <span class="n">funcs_sorted</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">:]</span>
    <span class="k">return</span> <span class="n">most_called</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span>

<span class="k">def</span> <span class="nf">b64_decode_rc4_decrypt</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">enc_string</span><span class="p">):</span>
    <span class="n">key_bytes</span> <span class="o">=</span> <span class="n">key</span><span class="p">.</span><span class="nf">encode</span><span class="p">(</span><span class="sh">'</span><span class="s">utf-8</span><span class="sh">'</span><span class="p">)</span>
    <span class="n">encrypted_bytes</span> <span class="o">=</span> <span class="n">base64</span><span class="p">.</span><span class="nf">b64decode</span><span class="p">(</span><span class="n">enc_string</span><span class="p">)</span>
    <span class="n">cipher</span> <span class="o">=</span> <span class="n">ARC4</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">key_bytes</span><span class="p">)</span>
    <span class="n">decrypted_bytes</span> <span class="o">=</span> <span class="n">cipher</span><span class="p">.</span><span class="nf">decrypt</span><span class="p">(</span><span class="n">encrypted_bytes</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">decrypted_bytes</span><span class="p">.</span><span class="nf">decode</span><span class="p">(</span><span class="sh">'</span><span class="s">utf-8</span><span class="sh">'</span><span class="p">,</span> <span class="n">errors</span><span class="o">=</span><span class="sh">'</span><span class="s">replace</span><span class="sh">'</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
    <span class="n">fpath</span> <span class="o">=</span> <span class="sa">r</span><span class="sh">"</span><span class="s">C:\Users\Kevin\Desktop\Samples\z2a challenge oski final payload\oski_final_payload.bin</span><span class="sh">"</span>
    
    <span class="n">rdata</span> <span class="o">=</span> <span class="nf">retrive_rdata</span><span class="p">(</span><span class="n">fpath</span><span class="p">)</span>
    
    <span class="n">rc4_key</span> <span class="o">=</span> <span class="nf">extract_rc4_key</span><span class="p">(</span><span class="n">rdata</span><span class="p">)</span>
    
    <span class="n">decrypt_strings_func_ea</span> <span class="o">=</span> <span class="nf">get_most_called_func</span><span class="p">()</span>
    
    <span class="n">enc_strings</span> <span class="o">=</span> <span class="p">[]</span>
    <span class="k">for</span> <span class="n">xref</span> <span class="ow">in</span> <span class="nc">CodeRefsTo</span><span class="p">(</span><span class="n">decrypt_strings_func_ea</span><span class="p">,</span> <span class="mi">0</span><span class="p">):</span>
        <span class="n">arg_insn</span> <span class="o">=</span> <span class="n">idc</span><span class="p">.</span><span class="nf">prev_head</span><span class="p">(</span><span class="n">xref</span><span class="p">)</span>
        <span class="n">enc_str_ea</span> <span class="o">=</span> <span class="nf">get_operand_value</span><span class="p">(</span><span class="n">arg_insn</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
        <span class="n">enc_str</span> <span class="o">=</span> <span class="n">ida_bytes</span><span class="p">.</span><span class="nf">get_strlit_contents</span><span class="p">(</span><span class="n">enc_str_ea</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="n">ida_nalt</span><span class="p">.</span><span class="n">STRTYPE_C</span><span class="p">,</span> <span class="mi">0</span><span class="p">).</span><span class="nf">decode</span><span class="p">(</span><span class="sh">'</span><span class="s">utf-8</span><span class="sh">'</span><span class="p">)</span>
        <span class="nf">print</span><span class="p">(</span><span class="nf">b64_decode_rc4_decrypt</span><span class="p">(</span><span class="n">rc4_key</span><span class="p">,</span> <span class="n">enc_str</span><span class="p">))</span>
        
<span class="nf">main</span><span class="p">()</span>

</code></pre></div></div>]]></content><author><name></name></author><summary type="html"><![CDATA[This is my belated write-up for Zero 2 Automated's Challenge #3 – Oski Stealer String Decryption.]]></summary></entry><entry><title type="html">Emotet Configuration Extraction</title><link href="https://kzhong-sec.github.io/2025/05/07/emotet-config-extraction.html" rel="alternate" type="text/html" title="Emotet Configuration Extraction" /><published>2025-05-07T00:00:00+10:00</published><updated>2025-05-07T00:00:00+10:00</updated><id>https://kzhong-sec.github.io/2025/05/07/emotet-config-extraction</id><content type="html" xml:base="https://kzhong-sec.github.io/2025/05/07/emotet-config-extraction.html"><![CDATA[<h1>Overview</h1>
<p>
This post is a write-up of an OALabs exercise in which the goal was to retrieve the C2 configuration from an unpacked Emotet sample, as a way to practice using emulation.
</p>
<p>
I am pretty sure the idea was to emulate the configuration de-obfuscation routine, but I also tried to utilise emulation to resolve the API hashing in the sample and had some interesting results.
</p>

<h2>Sample</h2>
<p>
<b>SHA256</b>: C688E079A16B3345C83A285AC2AE8DD48680298085421C225680F26CEAE73EB7
</p>
<p>
<b>First Seen On VirusTotal</b>: 2022-05-13
</p>
<p>
<b>Family</b>: Emotet
</p>

<h2>Identifying Win APIs</h2>
<p>
Since the goal was to extract the C2 configuration, this implies the sample must include some kind of networking functionality.
</p>
<p>
My approach to find the config data was to look at all the code surrounding network API calls, then I could trace the arguments provided to these and hopefully find the configuration info.
</p>
<p>
Looking at the imports for this sample, it did not contain a single import. This is a clear sign that this sample utilises API hashing, or at the very least walks the Export table of each module it is retrieving functions from.
</p>
<p><i>
(For those unfamiliar, a module loaded into a processes memory space will expose the functions it exports through an export table. Although this is typically intended to be used by the Windows loader or APIs such as GetProcAddress, it can be manually parsed, as a stealthy technique to resolve imports)
</i></p>
<p>
So to find the API hashing function I decided to hunt for references to the TEB, as this is required to access the PEB, which is often used to find the base address of modules that have been loaded in processes memory space. As such I used the script below to scan all the assembly instructions to see if it contained 'gs' (If this was a 32 bit sample I would use 'fs').
</p>
<p><i>
(The gs/fs segment register of all threads will contain a pointer to the TEB)
</i></p>
<p>
Another option would be to do this dynamically (which would likely be quicker as well), by setting breakpoints on a variety of networking APIs and running the sample, but I wanted to try statically reversing the API resolution function.

</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">idautils</span>

<span class="k">def</span> <span class="nf">operand_is_gs</span><span class="p">(</span><span class="n">op1</span><span class="p">,</span> <span class="n">op2</span><span class="p">):</span>
    <span class="nf">if </span><span class="p">(</span><span class="sh">"</span><span class="s">gs</span><span class="sh">"</span> <span class="ow">in</span> <span class="n">op1</span> <span class="ow">or</span> <span class="sh">"</span><span class="s">GS</span><span class="sh">"</span> <span class="ow">in</span> <span class="n">op1</span><span class="p">)</span> <span class="ow">or</span> <span class="p">(</span><span class="sh">"</span><span class="s">gs</span><span class="sh">"</span> <span class="ow">in</span> <span class="n">op2</span> <span class="ow">or</span> <span class="sh">"</span><span class="s">GS</span><span class="sh">"</span> <span class="ow">in</span> <span class="n">op2</span><span class="p">):</span>
        <span class="k">return</span> <span class="bp">True</span>
    <span class="k">return</span> <span class="bp">False</span>

<span class="k">def</span> <span class="nf">find_gs</span><span class="p">():</span>
    <span class="k">for</span> <span class="n">func_ea</span> <span class="ow">in</span> <span class="n">idautils</span><span class="p">.</span><span class="nc">Functions</span><span class="p">():</span>
        <span class="k">for</span> <span class="n">head</span> <span class="ow">in</span> <span class="n">idautils</span><span class="p">.</span><span class="nc">Heads</span><span class="p">(</span><span class="n">func_ea</span><span class="p">,</span> <span class="n">idc</span><span class="p">.</span><span class="nf">get_func_attr</span><span class="p">(</span><span class="n">func_ea</span><span class="p">,</span> <span class="n">idc</span><span class="p">.</span><span class="n">FUNCATTR_END</span><span class="p">)):</span>
            <span class="k">if</span> <span class="ow">not</span> <span class="n">idc</span><span class="p">.</span><span class="nf">is_code</span><span class="p">(</span><span class="n">idc</span><span class="p">.</span><span class="nf">get_full_flags</span><span class="p">(</span><span class="n">head</span><span class="p">)):</span>
                <span class="k">continue</span>
            <span class="n">first_op</span> <span class="o">=</span> <span class="nf">print_operand</span><span class="p">(</span><span class="n">head</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
            <span class="n">second_op</span> <span class="o">=</span> <span class="nf">print_operand</span><span class="p">(</span><span class="n">head</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
            <span class="k">if</span> <span class="n">first_op</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
                <span class="k">continue</span>
            <span class="k">if</span> <span class="nf">operand_is_gs</span><span class="p">(</span><span class="n">first_op</span><span class="p">,</span> <span class="n">second_op</span><span class="p">)</span> <span class="o">==</span> <span class="bp">True</span><span class="p">:</span>
                <span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">"</span><span class="si">{</span><span class="nf">hex</span><span class="p">(</span><span class="n">head</span><span class="p">)</span><span class="si">}</span><span class="s">: </span><span class="si">{</span><span class="nc">GetDisasm</span><span class="p">(</span><span class="n">head</span><span class="p">)</span><span class="si">}</span><span class="sh">"</span><span class="p">)</span>

<span class="nf">find_gs</span><span class="p">()</span>
</code></pre></div></div>

<p>
    Which showed one reference:
</p>
<p><img src="/assets/emotet-config-extraction/peb.png" style="width: 90%;" /></p>

<p>
    Back tracing this function, I got to this function - Looking at the cross references to it, it is called 108 times, with a variety of arguments that looked like hash values.
</p>
<p><img src="/assets/emotet-config-extraction/api_resolve_wrapper.png" style="width: 90%;" />
<img src="/assets/emotet-config-extraction/dll_resolution.png" style="width: 90%;" />
<img src="/assets/emotet-config-extraction/api_hash_xref.png" style="width: 90%;" /></p>
<p>
    Looking into the hashing algorithm used for the DLL names, it did not look too complex, and as such almost certainly a custom algorithm. 
    <i>
    (A standard hashing algorithm will typically look much more complex, such that it can be properly cryptographically secure).
    </i>
</p>

<p><img src="/assets/emotet-config-extraction/dll_hashing.png" style="width: 90%;" /></p>

<p>
    The hashing function for hashing the API names is a separate custom hashing function (to the one used for the DLL names).
</p>
<p><img src="/assets/emotet-config-extraction/api_hashing.png" style="width: 90%;" /></p>

<p>But first I need to retrieve all hashes provided to the function, which I used the following script to acquire.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">idautils</span>

<span class="k">def</span> <span class="nf">get_paramter</span><span class="p">(</span><span class="n">all_dll_api_pairs</span><span class="p">):</span>
    <span class="k">for</span> <span class="n">xref</span> <span class="ow">in</span> <span class="n">idautils</span><span class="p">.</span><span class="nc">XrefsTo</span><span class="p">(</span><span class="mh">0x00007FF9B6F73D70</span><span class="p">):</span> <span class="c1"># api_resolve_wrapper_func
</span>        <span class="n">xref</span> <span class="o">=</span> <span class="n">xref</span><span class="p">.</span><span class="n">frm</span>
        <span class="n">addr</span> <span class="o">=</span> <span class="nf">str</span><span class="p">(</span><span class="nf">hex</span><span class="p">(</span><span class="n">xref</span><span class="p">))</span>
        <span class="n">dll_api_pair_dict</span> <span class="o">=</span> <span class="p">{</span><span class="sh">'</span><span class="s">address</span><span class="sh">'</span> <span class="p">:</span> <span class="n">addr</span><span class="p">}</span>
        <span class="n">counter</span> <span class="o">=</span> <span class="mi">25</span>
        <span class="n">prev_instruct</span> <span class="o">=</span> <span class="n">idaapi</span><span class="p">.</span><span class="nf">prev_head</span><span class="p">(</span><span class="n">xref</span><span class="p">,</span> <span class="mi">25</span><span class="p">)</span>
        <span class="k">while</span> <span class="n">counter</span> <span class="o">&gt;=</span> <span class="mi">0</span><span class="p">:</span> <span class="c1"># the instruction moving the hash value into the register, is not a consistent offset from the call the api hash wrapper, so have to loop back for a while
</span>            <span class="n">counter</span> <span class="o">-=</span> <span class="mi">1</span>
            <span class="n">mnemonic</span> <span class="o">=</span> <span class="nf">print_insn_mnem</span><span class="p">(</span><span class="n">prev_instruct</span><span class="p">)</span>
            <span class="k">if</span> <span class="n">mnemonic</span> <span class="o">!=</span> <span class="sh">'</span><span class="s">mov</span><span class="sh">'</span><span class="p">:</span>
                <span class="n">prev_instruct</span> <span class="o">=</span> <span class="n">idaapi</span><span class="p">.</span><span class="nf">prev_head</span><span class="p">(</span><span class="n">prev_instruct</span><span class="p">,</span> <span class="mi">25</span><span class="p">)</span>
                <span class="k">continue</span>
            <span class="n">first_operand</span> <span class="o">=</span> <span class="nf">print_operand</span><span class="p">(</span><span class="n">prev_instruct</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
            <span class="k">if</span> <span class="n">first_operand</span> <span class="o">!=</span> <span class="sh">"</span><span class="s">edx</span><span class="sh">"</span> <span class="ow">and</span> <span class="n">first_operand</span> <span class="o">!=</span> <span class="sh">"</span><span class="s">rdx</span><span class="sh">"</span> <span class="ow">and</span> <span class="n">first_operand</span> <span class="o">!=</span> <span class="sh">"</span><span class="s">ecx</span><span class="sh">"</span> <span class="ow">and</span> <span class="n">first_operand</span> <span class="o">!=</span> <span class="sh">"</span><span class="s">rcx</span><span class="sh">"</span><span class="p">:</span>
                <span class="n">prev_instruct</span> <span class="o">=</span> <span class="n">idaapi</span><span class="p">.</span><span class="nf">prev_head</span><span class="p">(</span><span class="n">prev_instruct</span><span class="p">,</span> <span class="mi">25</span><span class="p">)</span>
                <span class="k">continue</span>
            <span class="k">if</span> <span class="n">first_operand</span> <span class="o">==</span> <span class="sh">'</span><span class="s">ecx</span><span class="sh">'</span> <span class="ow">or</span> <span class="n">first_operand</span> <span class="o">==</span> <span class="sh">'</span><span class="s">rcx</span><span class="sh">'</span><span class="p">:</span>
                <span class="n">instruction</span> <span class="o">=</span> <span class="n">idaapi</span><span class="p">.</span><span class="nf">insn_t</span><span class="p">()</span>
                <span class="n">idaapi</span><span class="p">.</span><span class="nf">decode_insn</span><span class="p">(</span><span class="n">instruction</span> <span class="p">,</span> <span class="n">prev_instruct</span><span class="p">)</span>
                <span class="n">dll_name_hash</span> <span class="o">=</span> <span class="n">instruction</span><span class="p">.</span><span class="n">Op2</span><span class="p">.</span><span class="n">value</span>
                <span class="k">if</span> <span class="sh">'</span><span class="s">dll_hash</span><span class="sh">'</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">dll_api_pair_dict</span><span class="p">:</span>
                    <span class="n">dll_api_pair_dict</span><span class="p">[</span><span class="sh">'</span><span class="s">dll_hash</span><span class="sh">'</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">dll_name_hash</span> <span class="o">&amp;</span> <span class="mh">0xffffffff</span><span class="p">)</span>
                <span class="n">prev_instruct</span> <span class="o">=</span> <span class="n">idaapi</span><span class="p">.</span><span class="nf">prev_head</span><span class="p">(</span><span class="n">prev_instruct</span><span class="p">,</span> <span class="mi">25</span><span class="p">)</span>
            <span class="k">if</span> <span class="n">first_operand</span> <span class="o">==</span> <span class="sh">'</span><span class="s">rdx</span><span class="sh">'</span> <span class="ow">or</span> <span class="n">first_operand</span> <span class="o">==</span> <span class="sh">'</span><span class="s">edx</span><span class="sh">'</span><span class="p">:</span>
                <span class="n">instruction</span> <span class="o">=</span> <span class="n">idaapi</span><span class="p">.</span><span class="nf">insn_t</span><span class="p">()</span>
                <span class="n">idaapi</span><span class="p">.</span><span class="nf">decode_insn</span><span class="p">(</span><span class="n">instruction</span> <span class="p">,</span> <span class="n">prev_instruct</span><span class="p">)</span>
                <span class="n">win_api_hash</span> <span class="o">=</span> <span class="n">instruction</span><span class="p">.</span><span class="n">Op2</span><span class="p">.</span><span class="n">value</span>
                <span class="k">if</span> <span class="sh">'</span><span class="s">win_api_hash</span><span class="sh">'</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">dll_api_pair_dict</span><span class="p">:</span>
                    <span class="n">dll_api_pair_dict</span><span class="p">[</span><span class="sh">'</span><span class="s">win_api_hash</span><span class="sh">'</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">win_api_hash</span> <span class="o">&amp;</span> <span class="mh">0xffffffff</span><span class="p">)</span>
                <span class="n">prev_instruct</span> <span class="o">=</span> <span class="n">idaapi</span><span class="p">.</span><span class="nf">prev_head</span><span class="p">(</span><span class="n">prev_instruct</span><span class="p">,</span> <span class="mi">25</span><span class="p">)</span>
            <span class="k">if</span> <span class="nf">len</span><span class="p">(</span><span class="n">dll_api_pair_dict</span><span class="p">)</span> <span class="o">==</span> <span class="mi">3</span><span class="p">:</span>
                <span class="n">all_dll_api_pairs</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">dll_api_pair_dict</span><span class="p">)</span>
                <span class="k">break</span>

<span class="n">all_dll_api_pairs</span> <span class="o">=</span> <span class="p">[]</span>
<span class="nf">get_paramter</span><span class="p">(</span><span class="n">all_dll_api_pairs</span><span class="p">)</span>
<span class="nf">print</span><span class="p">(</span><span class="n">all_dll_api_pairs</span><span class="p">)</span>
</code></pre></div></div>

<p>
    With this I now have a list of all the hashes, and the location they were called from.
</p>

<p>
    The standard approach to resolve these hashes would either be to use HashDB, or re-implement the hashing function and brute force them with them with a API wordlist.
</p>

<p>
    But I wanted to try something different - I wanted to emulate the entire wrapper function (including the export table walking etc, and extract the DLL names and API names), through Dumpulator.
</p>

<p>
    This would mean I would not need to get a wordlist to perform a brute force, I could just plug in the hashes I acquired and that should be enough, however, spoilers—it only sort of worked.
</p>

<p>
    To do this I needed to do some additional reverse engineering, to figure out where I want to hook, and what registers or memory locations I want to read. As such I marked up this function a bit more.
</p>

<p><img src="/assets/emotet-config-extraction/marked_up.png" style="width: 90%;" /></p>

<p>
    After marking up the decompiled output, I want to correlate it with the assembly code and see if I can easily retrieve the index into the export name table.
</p>

<p>
    The disassembled code shows a loop, in which an export name table entry is passed into the function <b>win_api_hashing_func</b>, and if the calculated hash matches the hash provided by the argument, it will exit the loop.
</p>

<p>
    To use emulation to resolve this, I have to extract the export table entry passed into <b>win_api_hashing_func</b> each loop, and hopefully when it exits, the most recent value we have extracted will be the API of interest.
</p>

<p>
    The easiest way for this I found was reading the contents of the rcx register at the address <b>0x07FF9B6F791C4</b> in <b>win_api_hashing_func</b> as it is directly reading from the export name table at this address.
</p>

<p><img src="/assets/emotet-config-extraction/hashing_func.png" style="width: 90%;" /></p>

<p>
    This can be done by hooking Dumpulator through its Unicorn underpinning, and retrieving a pointer to the string each loop. Once the emulation instance finishes the retrieved value should be the most recent export name table entry, hopefully pointing to the API name string. (Not sure if you are meant to do this as the unicorn instance is labelled as a private attribute, but it worked).
</p>

<p>
    To do this all that is needed is a MiniDump of the process, at whatever process execution state we want it to be in. Then the sample should be rebased in IDA such that the Virtual Addresses match up, allowing the use of the Virtual addresses in IDA to help set up the emulation instance. From here the Dumpulator instance can allocate memory, write to memory and set up register values. 
</p>

<p>
    For this function the hash arguments are provided through the <b>rcx</b> and <b>rdx</b> registers, so we just have to initalise these registers with the hashes in our dumpulator instance, and then plug in the address of the start of the function.
</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">dumpulator</span> <span class="kn">import</span> <span class="o">*</span>
<span class="kn">from</span> <span class="n">unicorn</span> <span class="kn">import</span> <span class="o">*</span>
<span class="kn">from</span> <span class="n">unicorn.x86_const</span> <span class="kn">import</span> <span class="o">*</span>
<span class="kn">import</span> <span class="n">struct</span>


<span class="n">hashed_api_int</span> <span class="o">=</span> <span class="p">[{</span><span class="sh">'</span><span class="s">address</span><span class="sh">'</span><span class="p">:</span> <span class="sh">'</span><span class="s">0x7ff9b6f7118a</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">win_api_hash</span><span class="sh">'</span><span class="p">:</span> <span class="mi">2496187760</span><span class="p">,</span> <span class="sh">'</span><span class="s">dll_hash</span><span class="sh">'</span><span class="p">:</span> <span class="mi">2657936269</span><span class="p">},</span> <span class="p">{</span><span class="sh">'</span><span class="s">address</span><span class="sh">'</span><span class="p">:</span> <span class="sh">'</span><span class="s">0x7ff9b6f713a8</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">dll_hash</span><span class="sh">'</span><span class="p">:</span> <span class="mi">2657936269</span><span class="p">,</span> <span class="sh">'</span><span class="s">win_api_hash</span><span class="sh">'</span><span class="p">:</span> <span class="mi">326862382</span><span class="p">}]</span> <span class="c1">#... Cut down for brevity
</span><span class="n">resolved_win_apis</span> <span class="o">=</span> <span class="p">[]</span>


<span class="k">def</span> <span class="nf">hook_code</span><span class="p">(</span><span class="n">uc</span><span class="p">,</span> <span class="n">address</span><span class="p">,</span> <span class="n">size</span><span class="p">,</span> <span class="n">user_data</span><span class="p">):</span>
    <span class="n">dp</span> <span class="o">=</span> <span class="n">user_data</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
    
    <span class="n">resolved_dict</span> <span class="o">=</span> <span class="n">user_data</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
    <span class="k">if</span> <span class="n">address</span> <span class="o">==</span> <span class="mh">0x07FF9B6F791C4</span><span class="p">:</span> <span class="c1"># Instruction after rcx gets loaded with pointer from entry in export name table
</span>        <span class="n">user_data</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">dp</span><span class="p">.</span><span class="n">regs</span><span class="p">.</span><span class="n">rcx</span>
    
    <span class="k">if</span> <span class="n">address</span> <span class="o">==</span> <span class="mh">0x07FF9B6F74A66</span><span class="p">:</span>
        <span class="n">out</span> <span class="o">=</span> <span class="n">dp</span><span class="p">.</span><span class="nf">read</span><span class="p">(</span><span class="n">dp</span><span class="p">.</span><span class="n">regs</span><span class="p">.</span><span class="n">rbx</span> <span class="o">+</span> <span class="mi">48</span> <span class="o">+</span> <span class="mi">24</span> <span class="o">+</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">8</span><span class="p">)</span>
        <span class="c1"># + 48 = DllBase, + 24 = FullDLLName, + 8 = wchar* (A unicode string struct will have a wide_char* at 8 bytes from its base)
</span>        <span class="n">out</span> <span class="o">=</span> <span class="n">struct</span><span class="p">.</span><span class="nf">unpack</span><span class="p">(</span><span class="sh">"</span><span class="s">Q</span><span class="sh">"</span><span class="p">,</span> <span class="n">out</span><span class="p">)</span>
        <span class="n">out</span> <span class="o">=</span> <span class="n">out</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
        <span class="n">dll_name</span> <span class="o">=</span> <span class="n">dp</span><span class="p">.</span><span class="nf">read_str</span><span class="p">(</span><span class="n">out</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="sh">"</span><span class="s">utf-16</span><span class="sh">"</span><span class="p">)</span>
        <span class="n">resolved_dict</span><span class="p">[</span><span class="sh">'</span><span class="s">dll</span><span class="sh">'</span><span class="p">]</span> <span class="o">=</span> <span class="n">dll_name</span>

<span class="k">def</span> <span class="nf">extract_name</span><span class="p">(</span><span class="n">dll_hash</span><span class="p">,</span> <span class="n">func_hash</span><span class="p">,</span> <span class="n">xref_address</span><span class="p">):</span>
    <span class="n">resolved_dict</span> <span class="o">=</span> <span class="p">{}</span>
    <span class="n">export_name_tab_ptr</span> <span class="o">=</span> <span class="p">[</span><span class="bp">None</span><span class="p">]</span>
    <span class="n">dp</span> <span class="o">=</span> <span class="nc">Dumpulator</span><span class="p">(</span><span class="sa">r</span><span class="sh">"</span><span class="s">C:\Users\Kevin\Desktop\Emotet\emotet.dmp</span><span class="sh">"</span><span class="p">,</span> <span class="n">quiet</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
    <span class="n">dp</span><span class="p">.</span><span class="n">_uc</span><span class="p">.</span><span class="nf">hook_add</span><span class="p">(</span><span class="n">UC_HOOK_CODE</span><span class="p">,</span> <span class="n">hook_code</span><span class="p">,</span> <span class="n">user_data</span> <span class="o">=</span> <span class="p">[</span><span class="n">dp</span><span class="p">,</span> <span class="n">resolved_dict</span><span class="p">,</span> <span class="n">export_name_tab_ptr</span><span class="p">])</span>
    <span class="n">dp</span><span class="p">.</span><span class="n">regs</span><span class="p">.</span><span class="n">rcx</span> <span class="o">=</span> <span class="n">dll_hash</span>
    <span class="n">dp</span><span class="p">.</span><span class="n">regs</span><span class="p">.</span><span class="n">rdx</span> <span class="o">=</span> <span class="n">func_hash</span> 
    <span class="n">start_VA</span> <span class="o">=</span> <span class="mh">0x07FF9B6F73D70</span>
    <span class="n">end_VA</span> <span class="o">=</span> <span class="mh">0x07FF9B6F8E22B</span>
    <span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">starting</span><span class="sh">"</span><span class="p">)</span>
    <span class="n">dp</span><span class="p">.</span><span class="nf">start</span><span class="p">(</span><span class="n">start_VA</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="n">end_VA</span><span class="p">)</span>
    <span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">finished</span><span class="sh">"</span><span class="p">)</span>
    <span class="nf">print</span><span class="p">(</span><span class="n">export_name_tab_ptr</span><span class="p">)</span>
    <span class="n">func_name</span> <span class="o">=</span> <span class="n">dp</span><span class="p">.</span><span class="nf">read_str</span><span class="p">(</span><span class="n">export_name_tab_ptr</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">encoding</span><span class="o">=</span><span class="sh">'</span><span class="s">utf-8</span><span class="sh">'</span><span class="p">)</span>
    <span class="n">resolved_dict</span><span class="p">[</span><span class="sh">'</span><span class="s">win_api</span><span class="sh">'</span><span class="p">]</span> <span class="o">=</span> <span class="n">func_name</span>
    <span class="n">resolved_dict</span><span class="p">[</span><span class="sh">'</span><span class="s">xref_address</span><span class="sh">'</span><span class="p">]</span> <span class="o">=</span> <span class="n">xref_address</span>
    <span class="n">resolved_win_apis</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">resolved_dict</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
    <span class="k">for</span> <span class="nb">dict</span> <span class="ow">in</span> <span class="n">hashed_api_int</span><span class="p">:</span>
        <span class="n">func_hash</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">[</span><span class="sh">'</span><span class="s">win_api_hash</span><span class="sh">'</span><span class="p">]</span>
        <span class="n">dll_hash</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">[</span><span class="sh">'</span><span class="s">dll_hash</span><span class="sh">'</span><span class="p">]</span>
        <span class="n">xref_addr</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">[</span><span class="sh">'</span><span class="s">address</span><span class="sh">'</span><span class="p">]</span>
        <span class="k">try</span><span class="p">:</span>
            <span class="nf">extract_name</span><span class="p">(</span><span class="n">dll_hash</span><span class="p">,</span> <span class="n">func_hash</span><span class="p">,</span> <span class="n">xref_addr</span><span class="p">)</span>
        <span class="k">except</span><span class="p">:</span>
            <span class="k">pass</span>
    <span class="nf">print</span><span class="p">(</span><span class="n">resolved_win_apis</span><span class="p">)</span>
    
<span class="nf">main</span><span class="p">()</span>
</code></pre></div></div>
<p>
    An issue with this approach is that if the emulation instance can not successfully resolve the hash, then we also cannot retrieve it. This is what occurred here as it only extracted the APIs from kernel32.dll and ntdll.dl, however I counted around 5 unique DLL name hashes provided to the hashing function. 
</p>

<p><i>
    (Once I extracted the modules later, I noted that these modules were not loaded in the process in the MiniDump instance - The sample would likely make a call to LoadLibrary to load these modules before attempting to retrieve their functions. - This fact likely makes attempting to resolve API hashing in this manner unreliable. Taking a MiniDump after the calls to LoadLibrary might allow this technique to work for all APIs.)
</i></p>

<p>
    results from the emulation routine <i>(I also extracted the dll name, which is technically unnecessary)</i>:
</p>

<p><img src="/assets/emotet-config-extraction/hashing_results.png" style="width: 80%;" /></p>

<p>
    So with this I decided to use <b>HashDB</b> to resolve the functions. 
</p>

<p>
    In the API resolution function I can see the hashed value of the API will be XOR'ed with <b>0x19A3CCB86</b>, thus using a key to help conceal the hash value. However that is easily thwarted by setting it as the XOR key in the HashDB IDA plugin
</p>

<p><img src="/assets/emotet-config-extraction/xor_key.png" style="width: 50%;" /></p>

<p>
    This allows us to do call HashDB's 'Hunt Algorithm' with any of the hashes we acquired earlier. If the hashing algorithm is in HashDB's database as well as the string that the hash resolves to, HashDB Hunt Algorithm will return the hashing algorithm in use.
</p>

<p>
    If the hashing algorithm was not in HashDB's database, an option would be to write the algorithm and upload it to them, which would provide access to their large string database.
    However the algorithm hunt returned an algorithm named 'emotet', so I am now ready to resolve all the APIs.
</p>

<p>
    Their API outlines the following format when retrieving strings from an algorithm using an xor key.
</p>

<p><i>
    https://hashdb.openanalysis.net/hash/{algorithm}/{hash}/{xor}
</i></p>

<p>
    So I used the following script to resolve all the hashes.
</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">requests</span>
<span class="kn">import</span> <span class="n">time</span>

<span class="n">hashed_api_int</span> <span class="o">=</span> <span class="p">[{</span><span class="sh">'</span><span class="s">address</span><span class="sh">'</span><span class="p">:</span> <span class="sh">'</span><span class="s">0x7ff9b6f7118a</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">win_api_hash</span><span class="sh">'</span><span class="p">:</span> <span class="mi">2496187760</span><span class="p">,</span> <span class="sh">'</span><span class="s">dll_hash</span><span class="sh">'</span><span class="p">:</span> <span class="mi">2657936269</span><span class="p">},</span> <span class="p">{</span><span class="sh">'</span><span class="s">address</span><span class="sh">'</span><span class="p">:</span> <span class="sh">'</span><span class="s">0x7ff9b6f713a8</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">dll_hash</span><span class="sh">'</span><span class="p">:</span> <span class="mi">2657936269</span><span class="p">,</span> <span class="sh">'</span><span class="s">win_api_hash</span><span class="sh">'</span><span class="p">:</span> <span class="mi">326862382</span><span class="p">}]</span> <span class="c1"># ... Cutdown for brevity
</span>
<span class="n">resolved_apis</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">unresolved_list</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">unresolved_count</span> <span class="o">=</span> <span class="mi">0</span>

<span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">hashed_api_int</span><span class="p">:</span>
    <span class="n">hash_val</span> <span class="o">=</span> <span class="n">item</span><span class="p">[</span><span class="sh">'</span><span class="s">win_api_hash</span><span class="sh">'</span><span class="p">]</span>
    <span class="n">address</span> <span class="o">=</span> <span class="n">item</span><span class="p">[</span><span class="sh">'</span><span class="s">address</span><span class="sh">'</span><span class="p">]</span>
    <span class="n">url_hashdb</span> <span class="o">=</span> <span class="sa">f</span><span class="sh">'</span><span class="s">https://hashdb.openanalysis.net/hash/emotet/</span><span class="si">{</span><span class="n">hash_val</span><span class="si">}</span><span class="s">/430162822</span><span class="sh">'</span>
    <span class="n">response</span> <span class="o">=</span> <span class="n">requests</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="n">url_hashdb</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">response</span><span class="p">.</span><span class="n">status_code</span> <span class="o">==</span> <span class="mi">429</span><span class="p">:</span>
        <span class="n">time</span><span class="p">.</span><span class="nf">sleep</span><span class="p">(</span><span class="mi">60</span><span class="p">)</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="n">data</span> <span class="o">=</span> <span class="n">response</span><span class="p">.</span><span class="nf">json</span><span class="p">()</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="n">api</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="sh">"</span><span class="s">hashes</span><span class="sh">"</span><span class="p">]</span>
        <span class="n">api</span> <span class="o">=</span> <span class="n">api</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
        <span class="n">api</span> <span class="o">=</span> <span class="n">api</span><span class="p">[</span><span class="sh">'</span><span class="s">string</span><span class="sh">'</span><span class="p">]</span>
        <span class="n">api</span> <span class="o">=</span> <span class="n">api</span><span class="p">[</span><span class="sh">'</span><span class="s">string</span><span class="sh">'</span><span class="p">]</span>
        <span class="nf">print</span><span class="p">(</span><span class="n">api</span><span class="p">)</span>
        <span class="n">resolved_apis</span><span class="p">.</span><span class="nf">append</span><span class="p">((</span><span class="n">address</span><span class="p">,</span> <span class="n">api</span><span class="p">))</span>
    <span class="k">except</span><span class="p">:</span>
        <span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">'</span><span class="s">unresolved: </span><span class="si">{</span><span class="n">hash_val</span><span class="si">}</span><span class="sh">'</span><span class="p">)</span>
        <span class="n">unresolved_count</span> <span class="o">+=</span> <span class="mi">1</span>
        <span class="k">continue</span>
        
<span class="nf">print</span><span class="p">(</span><span class="n">unresolved_count</span><span class="p">)</span>
<span class="nf">print</span><span class="p">(</span><span class="n">resolved_apis</span><span class="p">)</span>
</code></pre></div></div>

<p>
    After resolving the Win APIs, I investigated what was actually done with the retrieved function pointer. It appears that the retrieved API pointers get written to a global variable (.data section), however this appears to just be storing the pointer in a cache as there is no other xrefs to these addresses <i>(although it is possible they indexed into from a base address, in which they wouldn't show up as cross references)</i>.
</p>

<p>
    For each unique hash set that is passed to <b>win_api_hashing_func</b>, there is a specific wrapper function, which subsequently calls the resolved API. So when marking this up, it is important to actually label the wrapper function rather than the global variable.
</p>

<p>
    Thus I used the following script to rename all the functions.
</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="n">resolved_apis</span> <span class="o">=</span> <span class="p">[(</span><span class="sh">'</span><span class="s">0x7ff9b6f7118a</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">Process32NextW</span><span class="sh">'</span><span class="p">),</span> <span class="p">(</span><span class="sh">'</span><span class="s">0x7ff9b6f713a8</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">GetTempPathW</span><span class="sh">'</span><span class="p">)]</span> <span class="c1"># ... cutdown for brevity
</span><span class="n">apis_addr_int</span> <span class="o">=</span> <span class="p">[(</span><span class="nf">int</span><span class="p">(</span><span class="n">pair</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="mi">16</span><span class="p">),</span> <span class="n">pair</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="k">for</span> <span class="n">pair</span> <span class="ow">in</span> <span class="n">resolved_apis</span><span class="p">]</span> <span class="c1"># Converting addresses from strings to int values
</span>

<span class="k">def</span> <span class="nf">rename_funcs</span><span class="p">(</span><span class="n">addr_name</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="nb">tuple</span><span class="p">]):</span>
  <span class="k">for</span> <span class="n">pair</span> <span class="ow">in</span> <span class="n">addr_name</span><span class="p">:</span>
      <span class="n">address</span><span class="p">,</span> <span class="n">name</span> <span class="o">=</span> <span class="n">pair</span>
      
      <span class="n">func</span> <span class="o">=</span> <span class="n">idaapi</span><span class="p">.</span><span class="nf">get_func</span><span class="p">(</span><span class="n">address</span><span class="p">)</span>
      <span class="n">func_start</span> <span class="o">=</span> <span class="n">func</span><span class="p">.</span><span class="n">start_ea</span>
      <span class="nf">set_name</span><span class="p">(</span><span class="n">func_start</span><span class="p">,</span> <span class="n">name</span> <span class="o">+</span> <span class="sh">"</span><span class="s">_Wrapper</span><span class="sh">"</span><span class="p">)</span>
      
      <span class="n">address</span> <span class="o">=</span> <span class="nf">next_head</span><span class="p">(</span><span class="n">address</span><span class="p">)</span>
      <span class="n">instruction</span> <span class="o">=</span> <span class="nf">print_insn_mnem</span><span class="p">(</span><span class="n">address</span><span class="p">)</span>
      <span class="k">while</span> <span class="n">instruction</span> <span class="o">!=</span> <span class="sh">'</span><span class="s">jmp</span><span class="sh">'</span> <span class="ow">and</span> <span class="n">instruction</span> <span class="o">!=</span> <span class="sh">'</span><span class="s">call</span><span class="sh">'</span><span class="p">:</span> <span class="c1"># it either called or jumped to the API
</span>          <span class="n">address</span> <span class="o">=</span> <span class="nf">next_head</span><span class="p">(</span><span class="n">address</span><span class="p">)</span>
          <span class="n">instruction</span> <span class="o">=</span> <span class="nf">print_insn_mnem</span><span class="p">(</span><span class="n">address</span><span class="p">)</span>
      <span class="nf">print</span><span class="p">(</span><span class="nf">hex</span><span class="p">(</span><span class="n">address</span><span class="p">))</span>
      <span class="nf">set_cmt</span><span class="p">(</span><span class="n">address</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
<span class="nf">rename_funcs</span><span class="p">(</span><span class="n">apis_addr_int</span><span class="p">)</span>

<span class="nf">main</span><span class="p">()</span>
</code></pre></div></div>

<h2>Finding the config</h2>
<p>With the APIs resolved, I went back to my original strategy of looking for networking APIs in the hope that they reference the configuration data. I noted that GetProcAddress got resolved, indicating further runtime API resolution may occur, but since some networking functions did get resolved, I did not think it was prudent to investigate.</p>

<p><img src="/assets/emotet-config-extraction/internet_functions.png" style="width: 90%;" /></p>

<p>Of these functions, I think InternetConnectW is a good candidate to investigate as it's MSDN entry outlines it takes an argument <b>'lpszServerName'</b>:<i>
    "Pointer to a null-terminated string that specifies the host name of an Internet server. Alternately, the string can contain the IP number of the site, in ASCII dotted-decimal format (for example, 11.0.1.45)."
</i></p>

<p>So going to the wrapper function, I can see it receives an argument that is subsequently passed in as the argument 'lpszServerName' to InternetConnectW.</p>

<p><img src="/assets/emotet-config-extraction/connectW.png" style="width: 90%;" /></p>

<p>I backtracked this argument back a couple of function calls and identified that the original value originated from a global variable.</p>

<p><img src="/assets/emotet-config-extraction/arg_init.png" style="width: 90%;" /></p>

<p>The variable is not initialised at compile time, however it appears that the variable contains a pointer to a structure containing the C2 data, based on how it is being referenced. To identify when a value is assigned to it, I opened up the x-refs and jumped to the one item where it is being written to.</p>

<p><img src="/assets/emotet-config-extraction/xref.png" style="width: 70%;" /></p>

<p>-&gt;</p>

<p><img src="/assets/emotet-config-extraction/init_struct.png" style="width: 90%;" /></p>

<p>
A heap pointer is initialised and written to our global variable. Then, a subsequent function can be seen accessing the global, and writing the output of a sprintf call to the pointer's destination.
</p>

<p><img src="/assets/emotet-config-extraction/init_form.png" style="width: 90%;" /></p>

<p>Taking a look at the function that provides the format string, it appears to initialise a stack string for a decryption function <b>decrypt_stuff</b>. The decryption function was called 32 times, so I decided to locate all calls to this function and emulate them.</p>

<p><img src="/assets/emotet-config-extraction/format_str.png" style="width: 60%;" />
<img src="/assets/emotet-config-extraction/decrypt_stuff.png" style="width: 90%;" /></p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">idautils</span>

<span class="n">decryptor_callers</span> <span class="o">=</span> <span class="p">[]</span>

<span class="k">for</span> <span class="n">xref</span> <span class="ow">in</span> <span class="n">idautils</span><span class="p">.</span><span class="nc">XrefsTo</span><span class="p">(</span><span class="mh">0x07FF9B6F9ADB8</span><span class="p">):</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="n">calling_address</span> <span class="o">=</span> <span class="n">xref</span><span class="p">.</span><span class="n">frm</span>
        <span class="nf">print</span><span class="p">(</span><span class="nf">hex</span><span class="p">(</span><span class="n">calling_address</span><span class="p">))</span>
        <span class="n">func</span> <span class="o">=</span> <span class="n">idaapi</span><span class="p">.</span><span class="nf">get_func</span><span class="p">(</span><span class="n">calling_address</span><span class="p">)</span>
        <span class="n">func_start</span> <span class="o">=</span> <span class="n">func</span><span class="p">.</span><span class="n">start_ea</span>
        <span class="n">decryptor_callers</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">func_start</span><span class="p">)</span>
    <span class="k">except</span><span class="p">:</span>
        <span class="k">pass</span>
<span class="nf">print</span><span class="p">(</span><span class="n">decryptor_callers</span><span class="p">)</span>
</code></pre></div></div>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">dumpulator</span> <span class="kn">import</span> <span class="o">*</span>

<span class="n">callers</span> <span class="o">=</span> <span class="p">[</span><span class="mi">140710493230020</span><span class="p">,</span> <span class="mi">140710493231788</span><span class="p">]</span> <span class="c1"># ... Cutdown for brevity
</span>
<span class="n">string_and_caller</span> <span class="o">=</span> <span class="p">[]</span>

<span class="k">def</span> <span class="nf">rename_funcs</span><span class="p">(</span><span class="n">addr_name</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="nb">tuple</span><span class="p">]):</span>
    <span class="n">name_count</span> <span class="o">=</span> <span class="mi">0</span>
    <span class="k">for</span> <span class="n">pair</span> <span class="ow">in</span> <span class="n">addr_name</span><span class="p">:</span>
        <span class="n">address</span><span class="p">,</span> <span class="n">dec_string</span> <span class="o">=</span> <span class="n">pair</span>
        
        <span class="n">func</span> <span class="o">=</span> <span class="n">idaapi</span><span class="p">.</span><span class="nf">get_func</span><span class="p">(</span><span class="n">address</span><span class="p">)</span>
        <span class="n">func_start</span> <span class="o">=</span> <span class="n">func</span><span class="p">.</span><span class="n">start_ea</span>
        <span class="nf">set_name</span><span class="p">(</span><span class="n">func_start</span><span class="p">,</span> <span class="sh">'</span><span class="s">decrypts_string_</span><span class="sh">'</span> <span class="o">+</span> <span class="nf">str</span><span class="p">(</span><span class="n">name_count</span><span class="p">))</span> <span class="c1"># rename the function: decrypts_string_1, decrypts_string_2, etc
</span>        <span class="n">name_count</span> <span class="o">+=</span> <span class="mi">1</span>
        <span class="nf">set_cmt</span><span class="p">(</span><span class="n">address</span><span class="p">,</span> <span class="n">dec_string</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="c1"># comment the decrypted string at the function
</span>
<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
    <span class="k">for</span> <span class="n">caller</span> <span class="ow">in</span> <span class="n">callers</span><span class="p">:</span>
        <span class="k">try</span><span class="p">:</span>
            <span class="n">dp</span> <span class="o">=</span> <span class="nc">Dumpulator</span><span class="p">(</span><span class="sa">r</span><span class="sh">"</span><span class="s">C:\Users\Kevin\Desktop\Emotet\emotet.dmp</span><span class="sh">"</span><span class="p">,</span> <span class="n">quiet</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
            <span class="n">start_VA</span> <span class="o">=</span> <span class="n">caller</span>
            <span class="n">end_VA</span> <span class="o">=</span> <span class="mh">0x07FF9B6F9AF3C</span>
            <span class="n">dp</span><span class="p">.</span><span class="nf">start</span><span class="p">(</span><span class="n">start_VA</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="n">end_VA</span><span class="p">)</span>
            <span class="n">rax</span> <span class="o">=</span> <span class="n">dp</span><span class="p">.</span><span class="n">regs</span><span class="p">.</span><span class="n">rax</span>
            <span class="n">dec_string</span> <span class="o">=</span> <span class="n">dp</span><span class="p">.</span><span class="nf">read_str</span><span class="p">(</span><span class="n">rax</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="sh">'</span><span class="s">utf-16</span><span class="sh">'</span><span class="p">)</span>
            <span class="nf">print</span><span class="p">(</span><span class="n">dec_string</span><span class="p">)</span>
            <span class="n">string_and_caller</span><span class="p">.</span><span class="nf">append</span><span class="p">((</span><span class="n">caller</span><span class="p">,</span> <span class="n">dec_string</span><span class="p">))</span>
        <span class="k">except</span><span class="p">:</span>
            <span class="k">pass</span>
    <span class="nf">rename_funcs</span><span class="p">(</span><span class="n">string_and_caller</span><span class="p">)</span>

<span class="nf">main</span><span class="p">()</span>
</code></pre></div></div>

<p>This returned a variety of decrypted strings:</p>

<pre>
    ObjectLength
    SOFTWARE\Microsoft\Windows\CurrentVersion\Run
    %s%s.dll
    WinSta0\Default
    RNG
    AES
    %s\%s
    %s\*
    SHA256
    %s%s.exe
    %s\regsvr32.exe "%s\%s" %s
    HASH
    Microsoft Primitive Provider
    bcrypt.dll
    ECDH_P256
    Cookie: %s=%s
    shlwapi.dll
    shell32.dll
    ECCPUBLICBLOB
    Content-Type: multipart/form-data; boundary=%s
    wininet.dll
    ECDSA_P256
    %s\%s%x
    wtsapi32.dll
    POST
    %s\regsvr32.exe "%s" %s
    %s\regsvr32.exe "%s\%s"
    userenv.dll
    %u.%u.%u.%u
    crypt32.dll
    KeyDataBlob
</pre>

<p>The string that was returned for the format string was <b>"%u.%u.%u.%u"</b>. This is almost certainly a format string for an IP address, which confirms my belief that this struct used for C2 communication gets initialised here. As such, emulating this function should retrieve all the IPs. The script just needs to read the destination buffer pointer when it is passed in as an argument, then read from it after the call to sprintf is complete.</p>

<p>Again, I use Dumpulator and hook the underlying Unicorn instance to do this:</p>

<p><img src="/assets/emotet-config-extraction/dump_ip_hook.png" style="width: 90%;" /></p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">dumpulator</span> <span class="kn">import</span> <span class="o">*</span>
<span class="kn">from</span> <span class="n">unicorn</span> <span class="kn">import</span> <span class="o">*</span>
<span class="kn">from</span> <span class="n">unicorn.x86_const</span> <span class="kn">import</span> <span class="o">*</span>


<span class="n">dp</span> <span class="o">=</span> <span class="nc">Dumpulator</span><span class="p">(</span><span class="sa">r</span><span class="sh">"</span><span class="s">C:\Users\Kevin\Desktop\Emotet\emotet.dmp</span><span class="sh">"</span><span class="p">,</span> <span class="n">quiet</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>

<span class="n">start_VA</span> <span class="o">=</span> <span class="mh">0x07FF9B6F8B190</span>

<span class="n">end_VA</span> <span class="o">=</span> <span class="mh">0x07FF9B6F73BC8</span>


<span class="n">ip_buffer</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">found_ips</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">def</span> <span class="nf">hook_code</span><span class="p">(</span><span class="n">uc</span><span class="p">,</span> <span class="n">address</span><span class="p">,</span> <span class="n">size</span><span class="p">,</span> <span class="n">user_data</span><span class="p">):</span>
    <span class="n">dp</span> <span class="o">=</span> <span class="n">user_data</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
    
    <span class="k">if</span> <span class="n">address</span> <span class="o">==</span> <span class="mh">0x07FF9B6F7388A</span><span class="p">:</span>
        <span class="k">global</span> <span class="n">ip_buffer</span>
        <span class="n">ip_buffer</span> <span class="o">=</span> <span class="n">dp</span><span class="p">.</span><span class="n">regs</span><span class="p">.</span><span class="n">rcx</span>
    

    <span class="k">if</span> <span class="n">address</span> <span class="o">==</span> <span class="mh">0x07FF9B6F738F3</span><span class="p">:</span>
        <span class="n">found_ips</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">dp</span><span class="p">.</span><span class="nf">read_str</span><span class="p">(</span><span class="n">ip_buffer</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="sh">'</span><span class="s">utf-16</span><span class="sh">'</span><span class="p">))</span>

<span class="n">dp</span><span class="p">.</span><span class="n">_uc</span><span class="p">.</span><span class="nf">hook_add</span><span class="p">(</span><span class="n">UC_HOOK_CODE</span><span class="p">,</span> <span class="n">hook_code</span><span class="p">,</span> <span class="n">user_data</span> <span class="o">=</span> <span class="p">[</span><span class="n">dp</span><span class="p">])</span>

<span class="n">dp</span><span class="p">.</span><span class="nf">start</span><span class="p">(</span><span class="n">start_VA</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="n">end_VA</span><span class="p">)</span>

<span class="nf">print</span><span class="p">(</span><span class="n">found_ips</span><span class="p">)</span>
</code></pre></div></div>

<p>With that, all the IPs were retrieved:</p>

<pre style="word-wrap: break-word; white-space: pre-wrap;">
['63[.]142[.]250[.]212', '150[.]95[.]66[.]124', '91[.]207[.]28[.]33', '172[.]104[.]251[.]154', '107[.]182[.]225[.]142', '185[.]157[.]82[.]211', '149[.]56[.]131[.]28', '196[.]218[.]30[.]83', '158[.]69[.]222[.]101', '45[.]176[.]232[.]124', '58[.]227[.]42[.]236', '212[.]24[.]98[.]99', '159[.]65[.]88[.]10', '189[.]126[.]111[.]200', '94[.]23[.]45[.]86', '51[.]254[.]140[.]238', '1[.]234[.]2[.]232', '1[.]234[.]21[.]73', '206[.]189[.]28[.]199', '164[.]68[.]99[.]3', '153[.]126[.]146[.]25', '46[.]55[.]222[.]11', '167[.]99[.]115[.]35', '134[.]122[.]66[.]193', '203[.]114[.]109[.]124', '51[.]91[.]76[.]89', '185[.]4[.]135[.]165', '79[.]137[.]35[.]198', '185[.]8[.]212[.]130', '213[.]241[.]20[.]155', '82[.]165[.]152[.]127', '119[.]193[.]124[.]41', '103[.]75[.]201[.]2', '201[.]94[.]166[.]162', '212[.]237[.]17[.]99', '103[.]70[.]28[.]102', '131[.]100[.]24[.]231', '209[.]250[.]246[.]206', '102[.]222[.]215[.]74', '5[.]9[.]116[.]246', '129[.]232[.]188[.]93', '216[.]158[.]226[.]206', '173[.]212[.]193[.]249', '101[.]50[.]0[.]91', '197[.]242[.]150[.]244', '27[.]54[.]89[.]58', '163[.]44[.]196[.]120', '45[.]118[.]115[.]99', '51[.]91[.]7[.]5', '110[.]232[.]117[.]186', '103[.]43[.]46[.]182', '146[.]59[.]226[.]45', '72[.]15[.]201[.]15', '167[.]172[.]253[.]162', '209[.]126[.]98[.]206', '151[.]106[.]112[.]196', '183[.]111[.]227[.]137', '160[.]16[.]142[.]56', '209[.]97[.]163[.]214', '45[.]235[.]8[.]30', '188[.]44[.]20[.]25', '77[.]81[.]247[.]144', '103[.]132[.]242[.]26']
</pre>

<p>Although utilising the above code for an automated configuration extractor might prove difficult, so I decided to poke around a bit more in this function and see if there was an easy opportunity to develop automation. I found that the IP data was initialised through these functions <i>(initially the function pointers were placed in an array and called in a later function - these functions generated the data from literal/immediate values, rather than storing them as data.)</i></p>

<p><img src="/assets/emotet-config-extraction/automation.png" style="width: 90%;" /></p>

<p><i>Example of one of the functions:</i></p>

<p><img src="/assets/emotet-config-extraction/example_func.png" style="width: 90%;" /></p>

<p>The way this array of function pointers was set up provided a good opportunity to develop regex that could extract these function pointers, which could subsequently be emulated. I decided to emulate the functions with Unicorn instead of Dumpulator, as Unicorn would not require a MiniDump of the process for it to work. As these functions were self-contained (did not make calls out to further functions or read from any global variables), implementing them in Unicorn was not difficult. All that was needed was to initialise the registers rcx and rdx with out buffers.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">unicorn</span> <span class="kn">import</span> <span class="o">*</span>
<span class="kn">from</span> <span class="n">unicorn.x86_const</span> <span class="kn">import</span> <span class="o">*</span>
<span class="kn">import</span> <span class="n">struct</span>
<span class="kn">from</span> <span class="n">capstone</span> <span class="kn">import</span> <span class="o">*</span>
<span class="kn">import</span> <span class="n">pefile</span>
<span class="kn">import</span> <span class="n">re</span>
<span class="kn">import</span> <span class="n">ctypes</span>

<span class="n">ips</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">cap</span> <span class="o">=</span> <span class="nc">Cs</span><span class="p">(</span><span class="n">CS_ARCH_X86</span><span class="p">,</span> <span class="n">CS_MODE_64</span><span class="p">)</span>
<span class="n">ALLOCATION_CHUNK_SIZE</span> <span class="o">=</span> <span class="mh">0x1000</span>


<span class="k">def</span> <span class="nf">hook_code</span><span class="p">(</span><span class="n">uc</span><span class="p">,</span> <span class="n">address</span><span class="p">,</span> <span class="n">size</span><span class="p">,</span> <span class="n">user_data</span><span class="p">):</span>
    <span class="n">cur_code</span> <span class="o">=</span> <span class="n">uc</span><span class="p">.</span><span class="nf">mem_read</span><span class="p">(</span><span class="n">address</span><span class="p">,</span> <span class="n">size</span><span class="p">)</span>
    <span class="n">instructions</span> <span class="o">=</span> <span class="n">cap</span><span class="p">.</span><span class="nf">disasm</span><span class="p">(</span><span class="n">cur_code</span><span class="p">,</span> <span class="n">address</span><span class="p">)</span>
    <span class="k">for</span> <span class="n">instruction</span> <span class="ow">in</span> <span class="n">instructions</span><span class="p">:</span>
        <span class="c1">#print(f"{hex(instruction.address)}\t{instruction.mnemonic}\t{instruction.op_str}")
</span>        <span class="k">if</span> <span class="n">instruction</span><span class="p">.</span><span class="n">mnemonic</span> <span class="o">==</span> <span class="sh">'</span><span class="s">retn</span><span class="sh">'</span> <span class="ow">or</span> <span class="n">instruction</span><span class="p">.</span><span class="n">mnemonic</span> <span class="o">==</span> <span class="sh">'</span><span class="s">ret</span><span class="sh">'</span><span class="p">:</span>
            <span class="n">out</span> <span class="o">=</span> <span class="n">uc</span><span class="p">.</span><span class="nf">mem_read</span><span class="p">(</span><span class="mh">0x10000</span><span class="p">,</span> <span class="mi">4</span><span class="p">)</span>
            <span class="n">ip</span> <span class="o">=</span> <span class="sh">''</span>
            <span class="k">for</span> <span class="n">byte</span> <span class="ow">in</span> <span class="n">out</span><span class="p">:</span>
                <span class="n">ip</span> <span class="o">+=</span> <span class="nf">str</span><span class="p">(</span><span class="n">byte</span><span class="p">)</span>
                <span class="n">ip</span> <span class="o">+=</span> <span class="sh">'</span><span class="s">.</span><span class="sh">'</span>
            <span class="n">ip</span> <span class="o">=</span> <span class="n">ip</span><span class="p">[:</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
            <span class="n">ips</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">ip</span><span class="p">)</span>
            <span class="nf">print</span><span class="p">(</span><span class="n">ip</span><span class="p">)</span>
            <span class="n">uc</span><span class="p">.</span><span class="nf">emu_stop</span><span class="p">()</span>
        <span class="k">if</span> <span class="n">instruction</span><span class="p">.</span><span class="n">mnemonic</span> <span class="o">==</span> <span class="sh">'</span><span class="s">call</span><span class="sh">'</span><span class="p">:</span>
            <span class="n">uc</span><span class="p">.</span><span class="nf">emu_stop</span><span class="p">()</span>


<span class="k">def</span> <span class="nf">emulate_ip_resolver</span><span class="p">(</span><span class="n">code</span><span class="p">,</span> <span class="n">address</span><span class="p">):</span>
    <span class="n">uc</span> <span class="o">=</span> <span class="nc">Uc</span><span class="p">(</span><span class="n">UC_ARCH_X86</span><span class="p">,</span> <span class="n">UC_MODE_64</span><span class="p">)</span>
    <span class="n">uc</span><span class="p">.</span><span class="nf">hook_add</span><span class="p">(</span><span class="n">UC_HOOK_CODE</span><span class="p">,</span> <span class="n">hook_code</span><span class="p">)</span>
    <span class="n">uc</span><span class="p">.</span><span class="nf">mem_map</span><span class="p">(</span><span class="mh">0x10000</span><span class="p">,</span> <span class="mh">0x1000</span><span class="p">,</span> <span class="n">UC_PROT_ALL</span><span class="p">)</span>
    <span class="n">uc</span><span class="p">.</span><span class="nf">mem_map</span><span class="p">(</span><span class="mh">0x20000</span><span class="p">,</span> <span class="mh">0x1000</span><span class="p">,</span> <span class="n">UC_PROT_ALL</span><span class="p">)</span>
    <span class="n">uc</span><span class="p">.</span><span class="nf">reg_write</span><span class="p">(</span><span class="n">UC_X86_REG_RCX</span><span class="p">,</span> <span class="mh">0x10000</span><span class="p">)</span>
    <span class="n">uc</span><span class="p">.</span><span class="nf">reg_write</span><span class="p">(</span><span class="n">UC_X86_REG_RDX</span><span class="p">,</span> <span class="mh">0x20000</span><span class="p">)</span>

    <span class="nf">emulate_func</span><span class="p">(</span><span class="n">uc</span><span class="p">,</span> <span class="n">code</span><span class="p">,</span> <span class="n">address</span><span class="p">)</span>


<span class="k">def</span> <span class="nf">emulate_func</span><span class="p">(</span><span class="n">uc</span><span class="p">:</span> <span class="n">Uc</span><span class="p">,</span> <span class="n">code</span><span class="p">:</span> <span class="nb">bytes</span><span class="p">,</span> <span class="n">code_base_ptr</span><span class="p">:</span> <span class="nb">int</span><span class="p">):</span>
    <span class="c1"># Allocating memory for the code, and writing it
</span>    <span class="n">allocation_base</span> <span class="o">=</span> <span class="n">code_base_ptr</span> <span class="o">&amp;</span> <span class="mb">0b1111_1111_1111_1111_1111_1111_1111_1111_0000_0000_0000_0000</span>
    <span class="n">uc</span><span class="p">.</span><span class="nf">mem_map</span><span class="p">(</span><span class="n">allocation_base</span><span class="p">,</span> <span class="n">ALLOCATION_CHUNK_SIZE</span><span class="p">,</span> <span class="n">UC_PROT_ALL</span><span class="p">)</span>
    <span class="n">uc</span><span class="p">.</span><span class="nf">mem_write</span><span class="p">(</span><span class="n">allocation_base</span><span class="p">,</span> <span class="sa">b</span><span class="sh">'</span><span class="se">\x00</span><span class="sh">'</span> <span class="o">*</span> <span class="n">ALLOCATION_CHUNK_SIZE</span><span class="p">)</span>
    <span class="n">allocation_end</span> <span class="o">=</span> <span class="n">allocation_base</span> <span class="o">+</span> <span class="n">ALLOCATION_CHUNK_SIZE</span>
    <span class="c1"># Allocates more memory if the allocated memory is not enough for the function
</span>    <span class="n">code_len</span> <span class="o">=</span> <span class="nf">len</span><span class="p">(</span><span class="n">code</span><span class="p">)</span>
    <span class="nf">while </span><span class="p">(</span><span class="n">code_len</span> <span class="o">+</span> <span class="n">code_base_ptr</span><span class="p">)</span> <span class="o">&gt;</span> <span class="n">allocation_end</span><span class="p">:</span> 
        <span class="n">uc</span><span class="p">.</span><span class="nf">mem_map</span><span class="p">(</span><span class="n">allocation_end</span><span class="p">,</span> <span class="n">ALLOCATION_CHUNK_SIZE</span><span class="p">,</span> <span class="n">UC_PROT_ALL</span><span class="p">)</span>
        <span class="n">uc</span><span class="p">.</span><span class="nf">mem_write</span><span class="p">(</span><span class="n">allocation_end</span><span class="p">,</span> <span class="sa">b</span><span class="sh">'</span><span class="se">\x00</span><span class="sh">'</span> <span class="o">*</span> <span class="n">ALLOCATION_CHUNK_SIZE</span><span class="p">)</span>
        <span class="n">allocation_end</span> <span class="o">+=</span> <span class="n">ALLOCATION_CHUNK_SIZE</span>
    <span class="n">uc</span><span class="p">.</span><span class="nf">mem_write</span><span class="p">(</span><span class="n">code_base_ptr</span><span class="p">,</span> <span class="n">code</span><span class="p">)</span>

    <span class="n">STACK_SPACE</span> <span class="o">=</span> <span class="mh">0x2000</span>
    <span class="n">uc</span><span class="p">.</span><span class="nf">mem_map</span><span class="p">(</span><span class="n">STACK_SPACE</span><span class="p">,</span> <span class="n">ALLOCATION_CHUNK_SIZE</span><span class="p">,</span> <span class="n">UC_PROT_ALL</span><span class="p">)</span>
    <span class="n">uc</span><span class="p">.</span><span class="nf">mem_write</span><span class="p">(</span><span class="n">STACK_SPACE</span><span class="p">,</span> <span class="sa">b</span><span class="sh">'</span><span class="se">\x00</span><span class="sh">'</span> <span class="o">*</span> <span class="n">ALLOCATION_CHUNK_SIZE</span><span class="p">)</span>
    <span class="n">uc</span><span class="p">.</span><span class="nf">reg_write</span><span class="p">(</span><span class="n">UC_X86_REG_ESP</span><span class="p">,</span> <span class="n">STACK_SPACE</span> <span class="o">+</span> <span class="n">ALLOCATION_CHUNK_SIZE</span> <span class="o">//</span> <span class="mi">2</span><span class="p">)</span>
    
    <span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">Starting emulating main func</span><span class="sh">"</span><span class="p">)</span>
    <span class="n">uc</span><span class="p">.</span><span class="nf">emu_start</span><span class="p">(</span><span class="n">code_base_ptr</span><span class="p">,</span> <span class="n">code_base_ptr</span> <span class="o">+</span> <span class="nf">len</span><span class="p">(</span><span class="n">code</span><span class="p">),</span> <span class="n">timeout</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">count</span> <span class="o">=</span> <span class="mi">0</span><span class="p">)</span>
    <span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">Finished Emulating</span><span class="sh">"</span><span class="p">)</span>


<span class="k">def</span> <span class="nf">retrieve_func_addrs</span><span class="p">(</span><span class="n">pe</span><span class="p">):</span>
    <span class="n">image_base</span> <span class="o">=</span> <span class="n">pe</span><span class="p">.</span><span class="n">OPTIONAL_HEADER</span><span class="p">.</span><span class="n">ImageBase</span>
    <span class="k">for</span> <span class="n">section</span> <span class="ow">in</span> <span class="n">pe</span><span class="p">.</span><span class="n">sections</span><span class="p">:</span>
        <span class="k">if</span> <span class="sa">b</span><span class="sh">'</span><span class="s">.text</span><span class="sh">'</span> <span class="ow">in</span> <span class="n">section</span><span class="p">.</span><span class="n">Name</span><span class="p">:</span>
            <span class="n">emotet_content</span> <span class="o">=</span> <span class="n">section</span><span class="p">.</span><span class="nf">get_data</span><span class="p">()</span>
            <span class="n">text_rva</span> <span class="o">=</span> <span class="n">section</span><span class="p">.</span><span class="n">VirtualAddress</span>
    <span class="n">find_lea</span> <span class="o">=</span> <span class="n">re</span><span class="p">.</span><span class="nf">compile</span><span class="p">(</span><span class="sa">rb</span><span class="sh">'</span><span class="s">\x48\x8d\x05(.{4})\x48\x89</span><span class="sh">'</span><span class="p">)</span>
    <span class="n">matches</span> <span class="o">=</span> <span class="n">find_lea</span><span class="p">.</span><span class="nf">finditer</span><span class="p">(</span><span class="n">emotet_content</span><span class="p">)</span>

    <span class="n">func_addrs</span> <span class="o">=</span> <span class="p">[]</span>

    <span class="k">for</span> <span class="k">match</span> <span class="ow">in</span> <span class="n">matches</span><span class="p">:</span>
        <span class="n">offset</span> <span class="o">=</span> <span class="k">match</span><span class="p">.</span><span class="nf">group</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
        <span class="n">offset</span> <span class="o">=</span> <span class="n">struct</span><span class="p">.</span><span class="nf">unpack</span><span class="p">(</span><span class="sh">'</span><span class="s">&lt;I</span><span class="sh">'</span><span class="p">,</span> <span class="n">offset</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
        <span class="n">offset</span> <span class="o">=</span> <span class="n">ctypes</span><span class="p">.</span><span class="nf">c_int</span><span class="p">(</span><span class="n">offset</span><span class="p">).</span><span class="n">value</span>
        <span class="n">VA</span> <span class="o">=</span> <span class="k">match</span><span class="p">.</span><span class="nf">start</span><span class="p">()</span>
        <span class="n">VA</span> <span class="o">+=</span> <span class="n">text_rva</span> <span class="o">+</span> <span class="n">image_base</span>
        <span class="n">func_addr</span> <span class="o">=</span> <span class="n">VA</span> <span class="o">+</span> <span class="n">offset</span> <span class="o">+</span> <span class="mi">7</span>
        <span class="n">func_addrs</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">func_addr</span><span class="p">)</span>

    <span class="k">return</span> <span class="n">func_addrs</span>

<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
    <span class="n">pe</span> <span class="o">=</span> <span class="n">pefile</span><span class="p">.</span><span class="nc">PE</span><span class="p">(</span><span class="sa">r</span><span class="sh">"</span><span class="s">C:\Users\Kevin\Desktop\Emotet\emo_unpacked_1020000.bin</span><span class="sh">"</span><span class="p">)</span>
    <span class="n">image_base</span> <span class="o">=</span> <span class="n">pe</span><span class="p">.</span><span class="n">OPTIONAL_HEADER</span><span class="p">.</span><span class="n">ImageBase</span>

    <span class="n">func_addrs</span> <span class="o">=</span> <span class="nf">retrieve_func_addrs</span><span class="p">(</span><span class="n">pe</span><span class="p">)</span>
    <span class="n">func_code_list</span> <span class="o">=</span> <span class="p">(</span><span class="n">pe</span><span class="p">.</span><span class="nf">get_data</span><span class="p">(</span><span class="n">func_addr</span> <span class="o">-</span> <span class="n">image_base</span><span class="p">,</span> <span class="mh">0x1000</span><span class="p">)</span> <span class="k">for</span> <span class="n">func_addr</span> <span class="ow">in</span> <span class="n">func_addrs</span><span class="p">)</span>

    <span class="k">for</span> <span class="n">func_code</span> <span class="ow">in</span> <span class="n">func_code_list</span><span class="p">:</span>
        <span class="k">try</span><span class="p">:</span>
            <span class="nf">emulate_ip_resolver</span><span class="p">(</span><span class="n">func_code</span><span class="p">,</span> <span class="mh">0x40_000</span><span class="p">)</span>
            <span class="nf">print</span><span class="p">()</span>
        <span class="k">except</span><span class="p">:</span>
            <span class="k">pass</span>

    <span class="nf">print</span><span class="p">(</span><span class="n">ips</span><span class="p">)</span>

<span class="nf">main</span><span class="p">()</span>
    
</code></pre></div></div>

<p>Another option to extract the config data would be to use a debugger and hook the snwprintf calls.</p>

<p>Thank you for reading!</p>]]></content><author><name></name></author><summary type="html"><![CDATA[Overview This post is a write-up of an OALabs exercise in which the goal was to retrieve the C2 configuration from an unpacked Emotet sample, as a way to practice using emulation. I am pretty sure the idea was to emulate the configuration de-obfuscation routine, but I also tried to utilise emulation to resolve the API hashing in the sample and had some interesting results.]]></summary></entry></feed>