Jekyll2022-09-11T13:28:23+00:00https://void-stack.github.io/feed.xmlVoid’s BlogDedicated to programming, reverse engineering and general hacking.void-stackAnalysing the Process Environment Block2022-09-10T00:00:00+00:002022-09-10T00:00:00+00:00https://void-stack.github.io/blog/post-Exploring%20PEB<p><code class="language-plaintext highlighter-rouge">The Process Environment Block</code> is a critical structure in the Windows OS, most of its fields are not intended to be used by other than the operating system. It contains data structures that apply across a whole process and is stored in user-mode memory, which makes it accessible for the corresponding process. The structure contains valuable information about the running process, including:</p>
<ul>
<li>whether the process is being debugged or not</li>
<li>which modules are loaded into memory</li>
<li>the command line used to invoke the process</li>
</ul>
<h2 id="installation-of-windbg-microsoft-store">Installation of WinDbg (Microsoft Store)</h2>
<p>Download and install WinDbg, then attach it to the running process as the example I will be using <code class="language-plaintext highlighter-rouge">notepad.exe</code>.</p>
<p><img src="/assets/images/windbg.png" alt="WINDBG" /></p>
<p>Navigate to your installation directory, and open <code class="language-plaintext highlighter-rouge">WinDbg.exe</code>.<br />
On the File menu, choose <code class="language-plaintext highlighter-rouge">1) Open Executable</code> or <code class="language-plaintext highlighter-rouge">2) Attach to process</code>.</p>
<p><code class="language-plaintext highlighter-rouge">1)</code> In the Open Executable dialog box, navigate to the folder that contains <code class="language-plaintext highlighter-rouge">notepad.exe</code> (typically, C:\Windows\System32). For the File name, enter notepad.exe. Select Open.</p>
<p><code class="language-plaintext highlighter-rouge">2)</code> In the second option just pick the running process in our case it’s <code class="language-plaintext highlighter-rouge">notepad.exe</code>.</p>
<p><img src="/assets/images/attach.png" alt="ATTACH" /></p>
<p><img src="/assets/images/windbg_preview.png" alt="PREVIEW" /></p>
<p>You should end up with something like this, near the bottom of the WinDbg window, in the command line, enter these commands.</p>
<h2 id="overview-of-peb-structure">Overview of PEB structure</h2>
<p>First, based on MSDN documentation the <a href="https://docs.microsoft.com/en-us/windows/win32/api/winternl/ns-winternl-peb">PEB structure</a></p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">typedef</span> <span class="k">struct</span> <span class="nc">_PEB</span> <span class="p">{</span>
<span class="n">BYTE</span> <span class="n">Reserved1</span><span class="p">[</span><span class="mi">2</span><span class="p">];</span>
<span class="n">BYTE</span> <span class="n">BeingDebugged</span><span class="p">;</span>
<span class="n">BYTE</span> <span class="n">Reserved2</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>
<span class="n">PVOID</span> <span class="n">Reserved3</span><span class="p">[</span><span class="mi">2</span><span class="p">];</span>
<span class="n">PPEB_LDR_DATA</span> <span class="n">Ldr</span><span class="p">;</span>
<span class="n">PRTL_USER_PROCESS_PARAMETERS</span> <span class="n">ProcessParameters</span><span class="p">;</span>
<span class="n">PVOID</span> <span class="n">Reserved4</span><span class="p">[</span><span class="mi">3</span><span class="p">];</span>
<span class="n">PVOID</span> <span class="n">AtlThunkSListPtr</span><span class="p">;</span>
<span class="n">PVOID</span> <span class="n">Reserved5</span><span class="p">;</span>
<span class="n">ULONG</span> <span class="n">Reserved6</span><span class="p">;</span>
<span class="n">PVOID</span> <span class="n">Reserved7</span><span class="p">;</span>
<span class="n">ULONG</span> <span class="n">Reserved8</span><span class="p">;</span>
<span class="n">ULONG</span> <span class="n">AtlThunkSListPtr32</span><span class="p">;</span>
<span class="n">PVOID</span> <span class="n">Reserved9</span><span class="p">[</span><span class="mi">45</span><span class="p">];</span>
<span class="n">BYTE</span> <span class="n">Reserved10</span><span class="p">[</span><span class="mi">96</span><span class="p">];</span>
<span class="n">PPS_POST_PROCESS_INIT_ROUTINE</span> <span class="n">PostProcessInitRoutine</span><span class="p">;</span>
<span class="n">BYTE</span> <span class="n">Reserved11</span><span class="p">[</span><span class="mi">128</span><span class="p">];</span>
<span class="n">PVOID</span> <span class="n">Reserved12</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>
<span class="n">ULONG</span> <span class="n">SessionId</span><span class="p">;</span>
<span class="p">}</span> <span class="n">PEB</span><span class="p">,</span> <span class="o">*</span><span class="n">PPEB</span><span class="p">;</span>
</code></pre></div></div>
<p>The <code class="language-plaintext highlighter-rouge">PEB</code> isn’t fully documented, so you must use <code class="language-plaintext highlighter-rouge">WinDbg</code> to see its full structure or use sites like <a href="https://www.nirsoft.net/kernel_struct/vista/PEB.html">!NirSoft</a>.</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">typedef</span> <span class="k">struct</span> <span class="nc">_PEB</span>
<span class="p">{</span>
<span class="n">UCHAR</span> <span class="n">InheritedAddressSpace</span><span class="p">;</span>
<span class="n">UCHAR</span> <span class="n">ReadImageFileExecOptions</span><span class="p">;</span>
<span class="n">UCHAR</span> <span class="n">BeingDebugged</span><span class="p">;</span>
<span class="n">UCHAR</span> <span class="n">BitField</span><span class="p">;</span>
<span class="n">ULONG</span> <span class="n">ImageUsesLargePages</span><span class="o">:</span> <span class="mi">1</span><span class="p">;</span>
<span class="n">ULONG</span> <span class="n">IsProtectedProcess</span><span class="o">:</span> <span class="mi">1</span><span class="p">;</span>
<span class="n">ULONG</span> <span class="n">IsLegacyProcess</span><span class="o">:</span> <span class="mi">1</span><span class="p">;</span>
<span class="n">ULONG</span> <span class="n">IsImageDynamicallyRelocated</span><span class="o">:</span> <span class="mi">1</span><span class="p">;</span>
<span class="n">ULONG</span> <span class="n">SpareBits</span><span class="o">:</span> <span class="mi">4</span><span class="p">;</span>
<span class="n">PVOID</span> <span class="n">Mutant</span><span class="p">;</span>
<span class="n">PVOID</span> <span class="n">ImageBaseAddress</span><span class="p">;</span>
<span class="n">PPEB_LDR_DATA</span> <span class="n">Ldr</span><span class="p">;</span>
<span class="n">PRTL_USER_PROCESS_PARAMETERS</span> <span class="n">ProcessParameters</span><span class="p">;</span>
<span class="n">PVOID</span> <span class="n">SubSystemData</span><span class="p">;</span>
<span class="n">PVOID</span> <span class="n">ProcessHeap</span><span class="p">;</span>
<span class="n">PRTL_CRITICAL_SECTION</span> <span class="n">FastPebLock</span><span class="p">;</span>
<span class="n">PVOID</span> <span class="n">AtlThunkSListPtr</span><span class="p">;</span>
<span class="n">PVOID</span> <span class="n">IFEOKey</span><span class="p">;</span>
<span class="n">ULONG</span> <span class="n">CrossProcessFlags</span><span class="p">;</span>
<span class="n">ULONG</span> <span class="n">ProcessInJob</span><span class="o">:</span> <span class="mi">1</span><span class="p">;</span>
<span class="n">ULONG</span> <span class="n">ProcessInitializing</span><span class="o">:</span> <span class="mi">1</span><span class="p">;</span>
<span class="n">ULONG</span> <span class="n">ReservedBits0</span><span class="o">:</span> <span class="mi">30</span><span class="p">;</span>
<span class="k">union</span>
<span class="p">{</span>
<span class="n">PVOID</span> <span class="n">KernelCallbackTable</span><span class="p">;</span>
<span class="n">PVOID</span> <span class="n">UserSharedInfoPtr</span><span class="p">;</span>
<span class="p">};</span>
<span class="n">ULONG</span> <span class="n">SystemReserved</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>
<span class="n">ULONG</span> <span class="n">SpareUlong</span><span class="p">;</span>
<span class="n">PPEB_FREE_BLOCK</span> <span class="n">FreeList</span><span class="p">;</span>
<span class="n">ULONG</span> <span class="n">TlsExpansionCounter</span><span class="p">;</span>
<span class="n">PVOID</span> <span class="n">TlsBitmap</span><span class="p">;</span>
<span class="n">ULONG</span> <span class="n">TlsBitmapBits</span><span class="p">[</span><span class="mi">2</span><span class="p">];</span>
<span class="n">PVOID</span> <span class="n">ReadOnlySharedMemoryBase</span><span class="p">;</span>
<span class="n">PVOID</span> <span class="n">HotpatchInformation</span><span class="p">;</span>
<span class="n">VOID</span> <span class="o">*</span> <span class="o">*</span> <span class="n">ReadOnlyStaticServerData</span><span class="p">;</span>
<span class="n">PVOID</span> <span class="n">AnsiCodePageData</span><span class="p">;</span>
<span class="n">PVOID</span> <span class="n">OemCodePageData</span><span class="p">;</span>
<span class="n">PVOID</span> <span class="n">UnicodeCaseTableData</span><span class="p">;</span>
<span class="n">ULONG</span> <span class="n">NumberOfProcessors</span><span class="p">;</span>
<span class="n">ULONG</span> <span class="n">NtGlobalFlag</span><span class="p">;</span>
<span class="n">LARGE_INTEGER</span> <span class="n">CriticalSectionTimeout</span><span class="p">;</span>
<span class="n">ULONG</span> <span class="n">HeapSegmentReserve</span><span class="p">;</span>
<span class="n">ULONG</span> <span class="n">HeapSegmentCommit</span><span class="p">;</span>
<span class="n">ULONG</span> <span class="n">HeapDeCommitTotalFreeThreshold</span><span class="p">;</span>
<span class="n">ULONG</span> <span class="n">HeapDeCommitFreeBlockThreshold</span><span class="p">;</span>
<span class="n">ULONG</span> <span class="n">NumberOfHeaps</span><span class="p">;</span>
<span class="n">ULONG</span> <span class="n">MaximumNumberOfHeaps</span><span class="p">;</span>
<span class="n">VOID</span> <span class="o">*</span> <span class="o">*</span> <span class="n">ProcessHeaps</span><span class="p">;</span>
<span class="n">PVOID</span> <span class="n">GdiSharedHandleTable</span><span class="p">;</span>
<span class="n">PVOID</span> <span class="n">ProcessStarterHelper</span><span class="p">;</span>
<span class="n">ULONG</span> <span class="n">GdiDCAttributeList</span><span class="p">;</span>
<span class="n">PRTL_CRITICAL_SECTION</span> <span class="n">LoaderLock</span><span class="p">;</span>
<span class="n">ULONG</span> <span class="n">OSMajorVersion</span><span class="p">;</span>
<span class="n">ULONG</span> <span class="n">OSMinorVersion</span><span class="p">;</span>
<span class="n">WORD</span> <span class="n">OSBuildNumber</span><span class="p">;</span>
<span class="n">WORD</span> <span class="n">OSCSDVersion</span><span class="p">;</span>
<span class="n">ULONG</span> <span class="n">OSPlatformId</span><span class="p">;</span>
<span class="n">ULONG</span> <span class="n">ImageSubsystem</span><span class="p">;</span>
<span class="n">ULONG</span> <span class="n">ImageSubsystemMajorVersion</span><span class="p">;</span>
<span class="n">ULONG</span> <span class="n">ImageSubsystemMinorVersion</span><span class="p">;</span>
<span class="n">ULONG</span> <span class="n">ImageProcessAffinityMask</span><span class="p">;</span>
<span class="n">ULONG</span> <span class="n">GdiHandleBuffer</span><span class="p">[</span><span class="mi">34</span><span class="p">];</span>
<span class="n">PVOID</span> <span class="n">PostProcessInitRoutine</span><span class="p">;</span>
<span class="n">PVOID</span> <span class="n">TlsExpansionBitmap</span><span class="p">;</span>
<span class="n">ULONG</span> <span class="n">TlsExpansionBitmapBits</span><span class="p">[</span><span class="mi">32</span><span class="p">];</span>
<span class="n">ULONG</span> <span class="n">SessionId</span><span class="p">;</span>
<span class="n">ULARGE_INTEGER</span> <span class="n">AppCompatFlags</span><span class="p">;</span>
<span class="n">ULARGE_INTEGER</span> <span class="n">AppCompatFlagsUser</span><span class="p">;</span>
<span class="n">PVOID</span> <span class="n">pShimData</span><span class="p">;</span>
<span class="n">PVOID</span> <span class="n">AppCompatInfo</span><span class="p">;</span>
<span class="n">UNICODE_STRING</span> <span class="n">CSDVersion</span><span class="p">;</span>
<span class="n">_ACTIVATION_CONTEXT_DATA</span> <span class="o">*</span> <span class="n">ActivationContextData</span><span class="p">;</span>
<span class="n">_ASSEMBLY_STORAGE_MAP</span> <span class="o">*</span> <span class="n">ProcessAssemblyStorageMap</span><span class="p">;</span>
<span class="n">_ACTIVATION_CONTEXT_DATA</span> <span class="o">*</span> <span class="n">SystemDefaultActivationContextData</span><span class="p">;</span>
<span class="n">_ASSEMBLY_STORAGE_MAP</span> <span class="o">*</span> <span class="n">SystemAssemblyStorageMap</span><span class="p">;</span>
<span class="n">ULONG</span> <span class="n">MinimumStackCommit</span><span class="p">;</span>
<span class="n">_FLS_CALLBACK_INFO</span> <span class="o">*</span> <span class="n">FlsCallback</span><span class="p">;</span>
<span class="n">LIST_ENTRY</span> <span class="n">FlsListHead</span><span class="p">;</span>
<span class="n">PVOID</span> <span class="n">FlsBitmap</span><span class="p">;</span>
<span class="n">ULONG</span> <span class="n">FlsBitmapBits</span><span class="p">[</span><span class="mi">4</span><span class="p">];</span>
<span class="n">ULONG</span> <span class="n">FlsHighIndex</span><span class="p">;</span>
<span class="n">PVOID</span> <span class="n">WerRegistrationData</span><span class="p">;</span>
<span class="n">PVOID</span> <span class="n">WerShipAssertPtr</span><span class="p">;</span>
<span class="p">}</span> <span class="n">PEB</span><span class="p">,</span> <span class="o">*</span><span class="n">PPEB</span><span class="p">;</span>
</code></pre></div></div>
<h2 id="usage-and-useful-commands-when-exploring-the-peb">Usage and useful commands when exploring the PEB.</h2>
<p>Dump _PEB structure: <code class="language-plaintext highlighter-rouge">dt ntdll!_PEB</code>.<br />
“dt” stands for “Display Type” and can be used to display information about a specific data-type</p>
<p><img src="/assets/images/peb.png" alt="PEB" /></p>
<p>PEB address of the process: <code class="language-plaintext highlighter-rouge">r $peb</code>.</p>
<p><img src="/assets/images/peb_addr.png" alt="PEB_Addr" /></p>
<p>The _PEB structure can now be overlaid on the memory pointed to by the <code class="language-plaintext highlighter-rouge">$peb</code> to see what values the structure members are holding/pointing to: <code class="language-plaintext highlighter-rouge">dt ntdll!_PEB @$peb</code>.</p>
<p><img src="/assets/images/PEB_overview.png" alt="PEB_overview" /></p>
<h3 id="beingdebugged">BeingDebugged</h3>
<p><code class="language-plaintext highlighter-rouge">+0x002 BeingDebugged : 0x1 ''</code></p>
<p>The most obvious flag to identify is whether a debugger is attached to the process or not. By reading the variable directly from memory instead of using usual suspects like <code class="language-plaintext highlighter-rouge">NtQueryInformationProcess</code> or <code class="language-plaintext highlighter-rouge">IsDebuggerPresent</code>, malware can prevent noisy WINAPI calls. This makes it harder to spot this technique.</p>
<h3 id="ldr-getting-a-list-of-loaded-modules">Ldr (Getting a list of loaded modules)</h3>
<p><code class="language-plaintext highlighter-rouge">+0x018 Ldr : 0x00007ffd5ed1a4c0 _PEB_LDR_DATA</code></p>
<p>Is one of the most important fields in the PEB. This is a pointer to a structure that contains information about the process’s loaded modules, and to the Head node of a doubly-linked list.<br />
The linked list can help us find the addresses of structures that represent the loaded DLLs.</p>
<p>We can get <code class="language-plaintext highlighter-rouge">InMemoryOrderModuleList</code> by <code class="language-plaintext highlighter-rouge">dt _PEB_LDR_DATA 0x00007ffd5ed1a4c0</code></p>
<p><img src="/assets/images/inmemory1.png" alt="inmodule" /></p>
<p>Or more fancy way <code class="language-plaintext highlighter-rouge">dt _peb @$peb Ldr->InMemoryOrderModuleList</code></p>
<p><img src="/assets/images/inmodule.png" alt="inmodule" /></p>
<p>Go go over linked list we can use <code class="language-plaintext highlighter-rouge">!list -x "dt _LDR_DATA_TABLE_ENTRY FullDllName->Buffer" 0x00000257b19a4210</code> where <code class="language-plaintext highlighter-rouge">0x00000257b19a4210</code> is our <code class="language-plaintext highlighter-rouge">InMemoryOrderModuleList</code>.</p>
<p><img src="/assets/images/list.png" alt="list" /></p>
<h3 id="imagebaseaddress">ImageBaseAddress</h3>
<p><code class="language-plaintext highlighter-rouge">+0x010 ImageBaseAddress : 0x00007ff7f45b0000 Void</code></p>
<p>Is it actually the valid address of the executable image in process memory we can try to inspect it using our PEB dump<br />
<code class="language-plaintext highlighter-rouge">db 0x00007ff7f45b0000 L100</code></p>
<p><img src="/assets/images/imagebase.png" alt="PEB_overview" /></p>
<h3 id="processparameters">ProcessParameters</h3>
<p>Is a pointer to <code class="language-plaintext highlighter-rouge">RTL_USER_PROCESS_PARAMETERS</code> structure. To inspect it we are going to find <code class="language-plaintext highlighter-rouge">ProcessParameters</code> address.</p>
<p><code class="language-plaintext highlighter-rouge">dt _peb @$peb ProcessParameters</code></p>
<p><img src="/assets/images/params_1.png" alt="Params1" /></p>
<p>Now we can dump it using <code class="language-plaintext highlighter-rouge">dt _RTL_USER_PROCESS_PARAMETERS 0x00000257b19a37b0</code></p>
<p><img src="/assets/images/params.png" alt="Params" /></p>
<p>Or we can forget about all of the above and just use: <code class="language-plaintext highlighter-rouge">!peb</code></p>
<p><img src="/assets/images/peb!.png" alt="PEB!" /></p>
<h2 id="how-the-process-environment-block-peb-is-actually-found">How the Process Environment Block (PEB) is actually found.</h2>
<p>On the user mode basis of a <code class="language-plaintext highlighter-rouge">32-bit window</code>, the <code class="language-plaintext highlighter-rouge">FS</code> register points to a structure called a <code class="language-plaintext highlighter-rouge">Thread Environment Block (TEB)</code> or <code class="language-plaintext highlighter-rouge">Thread Information Block (TIB)</code>. This structure stores information about the currently running thread. This is mainly used because information can be obtained without calling API functions. Note that the <code class="language-plaintext highlighter-rouge">FS</code> register points to the first address of the <code class="language-plaintext highlighter-rouge">TEB</code>, so you can add values by position to access the desired fields. In the <code class="language-plaintext highlighter-rouge">x64 environment</code>, the <code class="language-plaintext highlighter-rouge">GS</code> register is used instead of the <code class="language-plaintext highlighter-rouge">FS</code> register.</p>
<h3 id="teb-structure-for-x86x64">TEB Structure for x86/x64</h3>
<p><img src="/assets/images/teb.png" alt="teb!" /></p>
<p>The <code class="language-plaintext highlighter-rouge">PEB</code> can be found at <code class="language-plaintext highlighter-rouge">fs:[0x30]</code> in the <code class="language-plaintext highlighter-rouge">Thread Environment Block (TEB)</code>/<code class="language-plaintext highlighter-rouge">Thread Information Block (TIB)</code> for x86 processes as well as at <code class="language-plaintext highlighter-rouge">gs:[0x60]</code> for x64 processes.</p>
<h3 id="x64-asm">x64 ASM</h3>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">GetPEB</span> <span class="n">proc</span>
<span class="n">mov</span> <span class="n">rax</span><span class="p">,</span> <span class="n">qword</span> <span class="n">ptr</span> <span class="n">gs</span><span class="o">:</span><span class="p">[</span><span class="mx">00000060h</span><span class="p">]</span> <span class="c1">// move PEB from TEB into rax (64 bit process gs : [0x60]);</span>
<span class="n">ret</span> <span class="c1">// return rax</span>
<span class="n">GetPEB</span> <span class="n">endp</span>
</code></pre></div></div>
<h3 id="x86-asm">x86 ASM</h3>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">__declspec</span><span class="p">(</span><span class="kr">naked</span><span class="p">)</span> <span class="n">PEB</span><span class="o">*</span> <span class="kr">__stdcall</span> <span class="nf">get_peb</span><span class="p">()</span>
<span class="p">{</span>
<span class="kr">__asm</span> <span class="n">mov</span> <span class="n">eax</span><span class="p">,</span> <span class="n">dword</span> <span class="n">ptr</span> <span class="n">fs</span> <span class="o">:</span> <span class="p">[</span><span class="mh">0x30</span><span class="p">]</span> <span class="p">;</span> <span class="c1">// move PEB from TEB into eax (32 bit process fs : [0x30])</span>
<span class="kr">__asm</span> <span class="n">ret</span><span class="p">;</span> <span class="c1">// return eax</span>
<span class="p">}</span>
</code></pre></div></div>
<p>You do not need to use <code class="language-plaintext highlighter-rouge">ASM</code> for this, you can use intrinsic functions like so:<br />
<code class="language-plaintext highlighter-rouge">__readfsdword</code>/<code class="language-plaintext highlighter-rouge">__readgsqword</code> are compiler intrinsic functions that will generate more optimized code, there is no reason to use inline assembly. Inline assembly is not even supported by Microsoft’s compilers for 64-bit targets.</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">PEB</span> <span class="o">*</span><span class="nf">GetPeb</span><span class="p">()</span>
<span class="p">{</span>
<span class="cp">#ifdef _M_X64
</span> <span class="k">return</span> <span class="k">reinterpret_cast</span><span class="o"><</span><span class="n">PEB</span><span class="o">*></span><span class="p">(</span><span class="n">__readgsqword</span><span class="p">(</span><span class="mh">0x60</span><span class="p">));</span>
<span class="cp">#elif _M_IX86
</span> <span class="k">return</span> <span class="k">reinterpret_cast</span><span class="o"><</span><span class="n">PEB</span><span class="o">*></span><span class="p">(</span><span class="n">__readfsdword</span><span class="p">(</span><span class="mh">0x30</span><span class="p">));</span>
<span class="cp">#else
</span> <span class="cp">#error "PEB Architecture Unsupported"
#endif
</span><span class="p">}</span>
</code></pre></div></div>
<h3 id="support-non-arm-systems">Support non-ARM systems</h3>
<p>Structure defined inside <code class="language-plaintext highlighter-rouge">winnt.h</code>. It’s the staring point for the algorithm. It includes self-referencing field - Self pointer, offset of which is used on <code class="language-plaintext highlighter-rouge">non-ARM systems</code> to read <code class="language-plaintext highlighter-rouge">Thread Environment Block</code> data.</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">typedef</span> <span class="k">struct</span> <span class="nc">_NT_TIB</span> <span class="p">{</span>
<span class="k">struct</span> <span class="nc">_EXCEPTION_REGISTRATION_RECORD</span> <span class="o">*</span><span class="n">ExceptionList</span><span class="p">;</span>
<span class="n">PVOID</span> <span class="n">StackBase</span><span class="p">;</span>
<span class="n">PVOID</span> <span class="n">StackLimit</span><span class="p">;</span>
<span class="n">PVOID</span> <span class="n">SubSystemTib</span><span class="p">;</span>
<span class="cp">#if defined(_MSC_EXTENSIONS)
</span> <span class="k">union</span> <span class="p">{</span>
<span class="n">PVOID</span> <span class="n">FiberData</span><span class="p">;</span>
<span class="n">DWORD</span> <span class="n">Version</span><span class="p">;</span>
<span class="p">};</span>
<span class="cp">#else
</span> <span class="n">PVOID</span> <span class="n">FiberData</span><span class="p">;</span>
<span class="cp">#endif
</span> <span class="n">PVOID</span> <span class="n">ArbitraryUserPointer</span><span class="p">;</span>
<span class="k">struct</span> <span class="nc">_NT_TIB</span> <span class="o">*</span><span class="n">Self</span><span class="p">;</span>
<span class="p">}</span> <span class="n">NT_TIB</span><span class="p">;</span>
<span class="k">typedef</span> <span class="n">NT_TIB</span> <span class="o">*</span><span class="n">PNT_TIB</span><span class="p">;</span>
</code></pre></div></div>
<p>After the executable is loaded by the Windows PE loader and before the thread starts running, <code class="language-plaintext highlighter-rouge">TEB</code> is saved to <code class="language-plaintext highlighter-rouge">fs(x86)</code> or <code class="language-plaintext highlighter-rouge">gs(x64)</code> processor register. <code class="language-plaintext highlighter-rouge">ARM</code> systems use different technique which utilize coprocessors scheme (it’s unclear whether the coprocessor is real hardware component or emulated). Self field of <code class="language-plaintext highlighter-rouge">NT_TIB</code> is the <code class="language-plaintext highlighter-rouge">TEB</code> pointer for the current thread.</p>
<p>Even not officially documented, this behavior is observed on/for all available Windows operating systems with NT kernel.</p>
<p>Acquiring pointer to the <code class="language-plaintext highlighter-rouge">TEB</code> is done using Microsoft specific compiler intrinsics:</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include <winnt.h>
#include <winternl.h>
</span>
<span class="cp">#if defined(_M_X64) // x64
</span> <span class="k">auto</span> <span class="n">pTeb</span> <span class="o">=</span> <span class="k">reinterpret_cast</span><span class="o"><</span><span class="n">PTEB</span><span class="o">></span><span class="p">(</span><span class="n">__readgsqword</span><span class="p">(</span><span class="k">reinterpret_cast</span><span class="o"><</span><span class="n">DWORD</span><span class="o">></span><span class="p">(</span><span class="o">&</span><span class="k">static_cast</span><span class="o"><</span><span class="n">NT_TIB</span><span class="o">*></span><span class="p">(</span><span class="nb">nullptr</span><span class="p">)</span><span class="o">-></span><span class="n">Self</span><span class="p">)));</span>
<span class="cp">#elif defined(_M_ARM) // ARM
</span> <span class="k">auto</span> <span class="n">pTeb</span> <span class="o">=</span> <span class="k">reinterpret_cast</span><span class="o"><</span><span class="n">PTEB</span><span class="o">></span><span class="p">(</span><span class="n">_MoveFromCoprocessor</span><span class="p">(</span><span class="mi">15</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">13</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">));</span> <span class="c1">// CP15_TPIDRURW</span>
<span class="cp">#else // x86
</span> <span class="k">auto</span> <span class="n">pTeb</span> <span class="o">=</span> <span class="k">reinterpret_cast</span><span class="o"><</span><span class="n">PTEB</span><span class="o">></span><span class="p">(</span><span class="n">__readfsdword</span><span class="p">(</span><span class="k">reinterpret_cast</span><span class="o"><</span><span class="n">DWORD</span><span class="o">></span><span class="p">(</span><span class="o">&</span><span class="k">static_cast</span><span class="o"><</span><span class="n">NT_TIB</span><span class="o">*></span><span class="p">(</span><span class="nb">nullptr</span><span class="p">)</span><span class="o">-></span><span class="n">Self</span><span class="p">)));</span>
<span class="cp">#endif
</span></code></pre></div></div>
<p>Among others, one of the fields inside the <code class="language-plaintext highlighter-rouge">TEB</code> is pointer to the <code class="language-plaintext highlighter-rouge">PEB (Process Environment Block)</code>.</p>
<h2 id="access-teb-the-windows-way">Access TEB the Windows way</h2>
<p>User-mode code can easily find its own process’s <code class="language-plaintext highlighter-rouge">PEB</code>, albeit only by using undocumented or semi-documented behavior. While a thread executes in user mode, its <code class="language-plaintext highlighter-rouge">fs</code> or <code class="language-plaintext highlighter-rouge">gs</code> register, for 32-bit and 64-bit code respectively, addresses the thread’s TEB. That structure’s <code class="language-plaintext highlighter-rouge">ProcessEnvironmentBlock</code> member holds the address of the current process’s <code class="language-plaintext highlighter-rouge">PEB</code>. In NTDLL version 5.1 and higher, this simple work is available more neatly as an exported function, named <code class="language-plaintext highlighter-rouge">RtlGetCurrentPeb</code>, but it too is undocumented. Its implementation is something very like</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">PEB</span> <span class="o">*</span><span class="nf">RtlGetCurrentPeb</span><span class="p">(</span><span class="n">VOID</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">return</span> <span class="n">NtCurrentTeb</span><span class="p">()</span><span class="o">-></span><span class="n">ProcessEnvironmentBlock</span><span class="p">;</span>
<span class="p">}</span>
<span class="c1">// For its own low-level user-mode programming, Microsoft has long had a macro or inlined </span>
<span class="c1">// routine, apparently named NtCurrentPeb, which reads directly from fs or gs, e.g.</span>
<span class="n">PEB</span> <span class="o">*</span><span class="nf">NtCurrentPeb</span> <span class="p">(</span><span class="n">VOID</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">return</span> <span class="p">(</span><span class="n">PEB</span> <span class="o">*</span><span class="p">)</span> <span class="n">__readfsdword</span> <span class="p">(</span><span class="n">FIELD_OFFSET</span> <span class="p">(</span><span class="n">TEB</span><span class="p">,</span> <span class="n">ProcessEnvironmentBlock</span><span class="p">));</span>
<span class="p">}</span>
</code></pre></div></div>
<p>To use <code class="language-plaintext highlighter-rouge">NtCurrentTeb()</code> without Windows header files declare the function prototype and link against <code class="language-plaintext highlighter-rouge">ntdll.dll</code>.</p>
<h2 id="whats-next">What’s next?</h2>
<p>In second part we’ll put the described how to manually write functions like <code class="language-plaintext highlighter-rouge">IsDebuggerPresent</code> or <code class="language-plaintext highlighter-rouge">GetModuleHandle</code> to see how a program can parse the <code class="language-plaintext highlighter-rouge">PEB</code> to recover <code class="language-plaintext highlighter-rouge">Kernel32.dll</code> address, and then load any other library. Not a single import is needed!</p>void-stackThe Process Environment Block is a critical structure in the Windows OS, most of its fields are not intended to be used by other than the operating system. It contains data structures that apply across a whole process and is stored in user-mode memory, which makes it accessible for the corresponding process. The structure contains valuable information about the running process, including: whether the process is being debugged or not which modules are loaded into memory the command line used to invoke the processVMUnprotect Call Hijacker for VMP: Part 12022-03-19T00:00:00+00:002022-03-19T00:00:00+00:00https://void-stack.github.io/blog/post-VMUnprotect-PART1<h1 id="hello-fellow-readers">Hello fellow readers!</h1>
<p>This is my exploration of <a href="https://vmpsoft.com">VMProtect</a> security. It’s well-known Software Protection with a lot of features, the main ones are code mutation and virtualization. I will talk about all of those in future posts, but now I will focus on virtualization.</p>
<p><img src="https://raw.githubusercontent.com/void-stack/VMUnprotect/main/docs/show.gif" alt="Showcase" /></p>
<h2 id="about-virtualization-and-design-approach">About Virtualization and design approach.</h2>
<p>VMUnprotect is a project engaged in hunting virtualized VMProtect methods. It makes use of <a href="https://github.com/pardeike/Harmony">Harmony</a> to dynamically read <strong>VMP</strong> behavior. Currently only supports method administration. Works on <strong>VMProtect 3.5.1</strong> (Latest) and few versions back.</p>
<blockquote>
<p>As VMProtect describes it on their’s website. Code virtualization is the next step in software protection. Most protection systems encrypt the code and then decrypt it at the application’s startup. VMProtect doesn’t decrypt the code at all! Instead, the encrypted code runs on a virtual CPU that is markedly different from generic x86 and x64 CPUs as the command set is different for each protected file.</p>
</blockquote>
<p>But we’re not devirtualizing code at all. What we are doing is done dynamically!</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Author: Washi (https://github.com/Washi1337 - https://rtn-team.cc/)</span>
<span class="k">using</span> <span class="nn">System</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">System.Collections</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">System.Linq</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">System.Reflection</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">HarmonyLib</span><span class="p">;</span>
<span class="k">namespace</span> <span class="nn">ConsoleApplication4</span>
<span class="p">{</span>
<span class="k">internal</span> <span class="k">class</span> <span class="nc">Program</span>
<span class="p">{</span>
<span class="k">private</span> <span class="k">static</span> <span class="n">FieldInfo</span> <span class="n">_stackField</span><span class="p">;</span>
<span class="k">private</span> <span class="k">static</span> <span class="n">FieldInfo</span> <span class="n">_pcField</span><span class="p">;</span>
<span class="k">public</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">Main</span><span class="p">(</span><span class="kt">string</span><span class="p">[]</span> <span class="n">args</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">assembly</span> <span class="p">=</span> <span class="n">Assembly</span><span class="p">.</span><span class="nf">LoadFile</span><span class="p">(</span><span class="s">@"awesome.vmp_nodbg.exe"</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">harmony</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">Harmony</span><span class="p">(</span><span class="s">"com.example.patch"</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">vmType</span> <span class="p">=</span> <span class="n">assembly</span><span class="p">.</span><span class="nf">GetType</span><span class="p">(</span><span class="s">"4775349C"</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">readMethod</span> <span class="p">=</span> <span class="n">vmType</span><span class="p">.</span><span class="nf">GetMethod</span><span class="p">(</span><span class="s">"15154B6D"</span><span class="p">,</span> <span class="n">BindingFlags</span><span class="p">.</span><span class="n">Instance</span> <span class="p">|</span> <span class="n">BindingFlags</span><span class="p">.</span><span class="n">NonPublic</span><span class="p">);</span>
<span class="n">_stackField</span> <span class="p">=</span> <span class="n">vmType</span><span class="p">.</span><span class="nf">GetField</span><span class="p">(</span><span class="s">"6BAE5C1B"</span><span class="p">,</span> <span class="n">BindingFlags</span><span class="p">.</span><span class="n">Instance</span> <span class="p">|</span> <span class="n">BindingFlags</span><span class="p">.</span><span class="n">NonPublic</span><span class="p">);</span>
<span class="n">_pcField</span> <span class="p">=</span> <span class="n">vmType</span><span class="p">.</span><span class="nf">GetField</span><span class="p">(</span><span class="s">"58392466"</span><span class="p">,</span> <span class="n">BindingFlags</span><span class="p">.</span><span class="n">Instance</span> <span class="p">|</span> <span class="n">BindingFlags</span><span class="p">.</span><span class="n">NonPublic</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">prefixMethod</span> <span class="p">=</span> <span class="k">typeof</span><span class="p">(</span><span class="n">Program</span><span class="p">).</span><span class="nf">GetMethod</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">ReadBytePrefix</span><span class="p">),</span> <span class="n">BindingFlags</span><span class="p">.</span><span class="n">Static</span> <span class="p">|</span> <span class="n">BindingFlags</span><span class="p">.</span><span class="n">Public</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">postfixMethod</span> <span class="p">=</span> <span class="k">typeof</span><span class="p">(</span><span class="n">Program</span><span class="p">).</span><span class="nf">GetMethod</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">ReadBytePostfix</span><span class="p">),</span> <span class="n">BindingFlags</span><span class="p">.</span><span class="n">Static</span> <span class="p">|</span> <span class="n">BindingFlags</span><span class="p">.</span><span class="n">Public</span><span class="p">);</span>
<span class="n">harmony</span><span class="p">.</span><span class="nf">Patch</span><span class="p">(</span><span class="n">readMethod</span><span class="p">,</span> <span class="k">new</span> <span class="nf">HarmonyMethod</span><span class="p">(</span><span class="n">prefixMethod</span><span class="p">),</span> <span class="k">new</span> <span class="nf">HarmonyMethod</span><span class="p">(</span><span class="n">postfixMethod</span><span class="p">));</span>
<span class="kt">var</span> <span class="n">invokeMethod</span> <span class="p">=</span> <span class="k">typeof</span><span class="p">(</span><span class="kt">object</span><span class="p">).</span><span class="n">Assembly</span>
<span class="p">.</span><span class="nf">GetType</span><span class="p">(</span><span class="s">"System.Reflection.RuntimeMethodInfo"</span><span class="p">)</span>
<span class="p">.</span><span class="nf">GetMethod</span><span class="p">(</span><span class="s">"UnsafeInvokeInternal"</span><span class="p">,</span> <span class="n">BindingFlags</span><span class="p">.</span><span class="n">NonPublic</span> <span class="p">|</span> <span class="n">BindingFlags</span><span class="p">.</span><span class="n">Instance</span><span class="p">);</span>
<span class="n">prefixMethod</span> <span class="p">=</span> <span class="k">typeof</span><span class="p">(</span><span class="n">Program</span><span class="p">).</span><span class="nf">GetMethod</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">InvokePrefix</span><span class="p">),</span> <span class="n">BindingFlags</span><span class="p">.</span><span class="n">Static</span> <span class="p">|</span> <span class="n">BindingFlags</span><span class="p">.</span><span class="n">Public</span><span class="p">);</span>
<span class="n">postfixMethod</span> <span class="p">=</span> <span class="k">typeof</span><span class="p">(</span><span class="n">Program</span><span class="p">).</span><span class="nf">GetMethod</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">InvokePostfix</span><span class="p">),</span> <span class="n">BindingFlags</span><span class="p">.</span><span class="n">Static</span> <span class="p">|</span> <span class="n">BindingFlags</span><span class="p">.</span><span class="n">Public</span><span class="p">);</span>
<span class="n">harmony</span><span class="p">.</span><span class="nf">Patch</span><span class="p">(</span><span class="n">invokeMethod</span><span class="p">,</span> <span class="k">new</span> <span class="nf">HarmonyMethod</span><span class="p">(</span><span class="n">prefixMethod</span><span class="p">),</span> <span class="k">new</span> <span class="nf">HarmonyMethod</span><span class="p">(</span><span class="n">postfixMethod</span><span class="p">));</span>
<span class="n">assembly</span><span class="p">.</span><span class="n">EntryPoint</span><span class="p">.</span><span class="nf">Invoke</span><span class="p">(</span><span class="k">null</span><span class="p">,</span> <span class="k">null</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">private</span> <span class="k">static</span> <span class="kt">string</span> <span class="nf">FormatObject</span><span class="p">(</span><span class="kt">object</span> <span class="n">obj</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">try</span>
<span class="p">{</span>
<span class="k">switch</span> <span class="p">(</span><span class="n">obj</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">case</span> <span class="k">null</span><span class="p">:</span>
<span class="k">return</span> <span class="s">"null"</span><span class="p">;</span>
<span class="k">case</span> <span class="kt">string</span> <span class="n">x</span><span class="p">:</span>
<span class="k">return</span> <span class="s">$"\"</span><span class="p">{</span><span class="n">x</span><span class="p">}</span><span class="s">\""</span><span class="p">;</span>
<span class="k">case</span> <span class="n">IEnumerable</span> <span class="n">enumerable</span><span class="p">:</span>
<span class="k">return</span>
<span class="s">$"</span><span class="p">{</span><span class="n">obj</span><span class="p">.</span><span class="nf">GetType</span><span class="p">().</span><span class="n">Name</span><span class="p">}</span><span class="s"> </span><span class="p">{</span><span class="kt">string</span><span class="p">.</span><span class="nf">Join</span><span class="p">(</span><span class="s">", "</span><span class="p">,</span> <span class="n">enumerable</span><span class="p">.</span><span class="n">Cast</span><span class="p"><</span><span class="kt">object</span><span class="p">>().</span><span class="nf">Select</span><span class="p">(</span><span class="n">FormatObject</span><span class="p">))}</span><span class="s">"</span><span class="p">;</span>
<span class="k">case</span> <span class="p">{</span> <span class="p">}</span> <span class="n">o</span> <span class="n">when</span> <span class="n">o</span><span class="p">.</span><span class="nf">GetType</span><span class="p">().</span><span class="n">Name</span> <span class="p">==</span> <span class="s">"0FE23521"</span><span class="p">:</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">field</span> <span class="p">=</span> <span class="n">o</span><span class="p">.</span><span class="nf">GetType</span><span class="p">().</span><span class="nf">GetField</span><span class="p">(</span><span class="s">"5BE47E90"</span><span class="p">,</span> <span class="n">BindingFlags</span><span class="p">.</span><span class="n">Instance</span> <span class="p">|</span> <span class="n">BindingFlags</span><span class="p">.</span><span class="n">NonPublic</span><span class="p">);</span>
<span class="k">return</span> <span class="nf">FormatObject</span><span class="p">(</span><span class="n">field</span><span class="p">.</span><span class="nf">GetValue</span><span class="p">(</span><span class="n">o</span><span class="p">));</span>
<span class="p">}</span>
<span class="k">case</span> <span class="p">{</span> <span class="p">}</span> <span class="n">o</span> <span class="n">when</span> <span class="n">o</span><span class="p">.</span><span class="nf">GetType</span><span class="p">().</span><span class="n">Name</span> <span class="p">==</span> <span class="s">"6F9B56A3"</span><span class="p">:</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">field</span> <span class="p">=</span> <span class="n">o</span><span class="p">.</span><span class="nf">GetType</span><span class="p">().</span><span class="nf">GetField</span><span class="p">(</span><span class="s">"1B4E1C53"</span><span class="p">,</span> <span class="n">BindingFlags</span><span class="p">.</span><span class="n">Instance</span> <span class="p">|</span> <span class="n">BindingFlags</span><span class="p">.</span><span class="n">NonPublic</span><span class="p">);</span>
<span class="k">return</span> <span class="nf">FormatObject</span><span class="p">(</span><span class="n">field</span><span class="p">.</span><span class="nf">GetValue</span><span class="p">(</span><span class="n">o</span><span class="p">));</span>
<span class="p">}</span>
<span class="k">default</span><span class="p">:</span>
<span class="k">return</span> <span class="n">obj</span><span class="p">.</span><span class="nf">ToString</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">catch</span> <span class="p">(</span><span class="n">Exception</span> <span class="n">ex</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">return</span> <span class="s">"???"</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">ReadBytePrefix</span><span class="p">(</span><span class="kt">object</span> <span class="n">__instance</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">Console</span><span class="p">.</span><span class="nf">Write</span><span class="p">(</span><span class="s">"{0:X8} ({0}): "</span><span class="p">,</span> <span class="n">_pcField</span><span class="p">.</span><span class="nf">GetValue</span><span class="p">(</span><span class="n">__instance</span><span class="p">));</span>
<span class="kt">var</span> <span class="n">stackContents</span> <span class="p">=</span> <span class="p">((</span><span class="n">IEnumerable</span><span class="p">)</span> <span class="n">_stackField</span><span class="p">.</span><span class="nf">GetValue</span><span class="p">(</span><span class="n">__instance</span><span class="p">))</span>
<span class="p">.</span><span class="n">Cast</span><span class="p"><</span><span class="kt">object</span><span class="p">>()</span>
<span class="p">.</span><span class="nf">Reverse</span><span class="p">()</span>
<span class="p">.</span><span class="nf">ToArray</span><span class="p">();</span>
<span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="nf">FormatObject</span><span class="p">(</span><span class="n">stackContents</span><span class="p">));</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">ReadBytePostfix</span><span class="p">()</span>
<span class="p">{</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">InvokePrefix</span><span class="p">(</span><span class="kt">object</span> <span class="n">__instance</span><span class="p">,</span> <span class="kt">object</span> <span class="n">obj</span><span class="p">,</span> <span class="kt">object</span><span class="p">[]</span> <span class="n">parameters</span><span class="p">,</span> <span class="kt">object</span><span class="p">[]</span> <span class="n">arguments</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">method</span> <span class="p">=</span> <span class="p">(</span><span class="n">MethodBase</span><span class="p">)</span> <span class="n">__instance</span><span class="p">;</span>
<span class="kt">string</span> <span class="n">returnType</span> <span class="p">=</span> <span class="n">method</span> <span class="k">is</span> <span class="n">MethodInfo</span> <span class="n">info</span> <span class="p">?</span> <span class="n">info</span><span class="p">.</span><span class="n">ReturnType</span><span class="p">.</span><span class="n">FullName</span> <span class="p">:</span> <span class="s">"System.Object"</span><span class="p">;</span>
<span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="s">$"--- call to </span><span class="p">{</span><span class="n">returnType</span><span class="p">}</span><span class="s"> </span><span class="p">{</span><span class="n">method</span><span class="p">.</span><span class="n">DeclaringType</span><span class="p">}</span><span class="s">::</span><span class="p">{</span><span class="n">method</span><span class="p">.</span><span class="n">Name</span><span class="p">}</span><span class="s">(</span><span class="p">{</span><span class="kt">string</span><span class="p">.</span><span class="nf">Join</span><span class="p">(</span><span class="s">", "</span><span class="p">,</span> <span class="n">method</span><span class="p">.</span><span class="nf">GetParameters</span><span class="p">().</span><span class="n">Cast</span><span class="p"><</span><span class="kt">object</span><span class="p">>())}</span><span class="s">)"</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">arguments</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span> <span class="n">i</span> <span class="p"><</span> <span class="n">arguments</span><span class="p">.</span><span class="n">Length</span><span class="p">;</span> <span class="n">i</span><span class="p">++)</span>
<span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="s">$"--- </span><span class="p">{</span><span class="n">i</span><span class="p">}</span><span class="s">: </span><span class="p">{</span><span class="nf">FormatObject</span><span class="p">(</span><span class="n">arguments</span><span class="p">[</span><span class="n">i</span><span class="p">])}</span><span class="s">"</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">InvokePostfix</span><span class="p">(</span><span class="kt">object</span> <span class="n">__instance</span><span class="p">,</span> <span class="k">ref</span> <span class="kt">object</span> <span class="n">__result</span><span class="p">,</span> <span class="kt">object</span> <span class="n">obj</span><span class="p">,</span> <span class="kt">object</span><span class="p">[]</span> <span class="n">parameters</span><span class="p">,</span> <span class="kt">object</span><span class="p">[]</span> <span class="n">arguments</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="s">"--- Resulted in "</span> <span class="p">+</span> <span class="nf">FormatObject</span><span class="p">(</span><span class="n">__result</span><span class="p">));</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p><img src="/assets/images/washi.png" alt="Washi" /></p>
<p>This piece of code might look complicated at first, but this is what inspired me to make VMUP. When we look at <strong>Washi</strong> notes from <a href="https://forum.tuts4you.com/topic/42437-vmprotect-v3501213/">Tuts4You</a> and we look at sample ourselves in <a href="https://github.com/dnSpyEx/dnSpy">DnspyEx</a> which is a Revival of the well-known .NET debugger and assembly editor, dnSpy.</p>
<p><img src="/assets/images/dnspy1.png" alt="dnspy" /></p>
<p>We can see that methods are empty. This is part of VMProtect protection which can be defeated by placing a breakpoint in <code class="language-plaintext highlighter-rouge">cctor</code> (right-click on the module and Go to <code class="language-plaintext highlighter-rouge"><Module>. cctor</code>) and debugging the application. <strong>I also made a tool that does that for you <a href="https://github.com/void-stack/VMUnprotect.Dumper">VMProtect.Dumper</a></strong>.</p>
<p><strong>(If you can’t see Modules)</strong><br />
<img src="/assets/images/dnspy3.png" alt="dnspy3" /></p>
<p><img src="/assets/images/dnspy2.png" alt="dnspy1" /></p>
<p><img src="/assets/images/dnspy4.png" alt="dnspy4" /></p>
<p>Voila! We can see juicy code now and a part that Validates password isn’t virtualized LOL! It’s <br />
only protected by delegates and mutation. This isn’t the point of this article to clean those but Washi made some notes that we can use to explore VM (VMP always injects their VM because they virtualize most of their features for example Anti Debug that is running before main in <code class="language-plaintext highlighter-rouge"><Module>. cctor</code>).</p>
<p>If we press <code class="language-plaintext highlighter-rouge">Ctrl + D</code> and type <code class="language-plaintext highlighter-rouge">0x04000048</code> we now now this is <strong>virtual program counter</strong>. Same goes for <code class="language-plaintext highlighter-rouge">0x0400004A</code> - <strong>stack</strong>. Previous harmony script performs a VM trace that dumps the program counter, stack contents, and calls.</p>
<h2 id="whats-next">What’s next?</h2>
<p>In Part 2 we’ll put the described how my older approach was made and how current works.</p>void-stackHello fellow readers! This is my exploration of VMProtect security. It’s well-known Software Protection with a lot of features, the main ones are code mutation and virtualization. I will talk about all of those in future posts, but now I will focus on virtualization.VMUnprotect Call Hijacker for VMP: Part 22022-03-19T00:00:00+00:002022-03-19T00:00:00+00:00https://void-stack.github.io/blog/post-VMUnprotect-PART2<h2 id="now-what-if-we-make-an-program-that-does-everything-for-us">Now what if… we make an program that does everything for us!</h2>
<p>At first I made my approach that tries to search for function <code class="language-plaintext highlighter-rouge">0x06000153</code> in this sample. Which appears to be invoking functions called in virtualized methods.</p>
<p><img src="/assets/images/genious.jpg" alt="genious" /></p>
<p><img src="/assets/images/dnspy5.png" alt="dnspy4" /></p>
<p>And replace this call with my own middle man invoke. This can be achieved by transpiler from Harmony. Which was my older method.</p>
<h2 id="my-old-approach-vmprotectdumpertranspilercs">My old approach <a href="https://github.com/void-stack/VMUnprotect/blob/main/VMUP/VMUnprotect.Runtime/Hooks/Methods/VmProtectDumperTranspiler.cs">VmProtectDumperTranspiler.cs</a></h2>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">/// <summary>A transpiler that replaces all occurrences of a given method with another with additional Ldarg_1 instruction</summary></span>
<span class="c1">/// <param name="instructions">The enumeration of <see cref="T:HarmonyLib.CodeInstruction" /> to act on</param></span>
<span class="c1">/// <param name="from">Method to search for</param></span>
<span class="c1">/// <param name="to">Method to replace with</param></span>
<span class="c1">/// <returns>Modified enumeration of <see cref="T:HarmonyLib.CodeInstruction" /></returns></span>
<span class="k">private</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">ReplaceVmpInvoke</span><span class="p">(</span><span class="k">ref</span> <span class="n">IEnumerable</span> <span class="p"><</span> <span class="n">CodeInstruction</span> <span class="p">></span> <span class="n">instructions</span><span class="p">,</span> <span class="n">MethodBase</span> <span class="n">@from</span><span class="p">,</span> <span class="n">MethodBase</span> <span class="n">to</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">((</span><span class="kt">object</span><span class="p">)</span> <span class="k">from</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span> <span class="k">throw</span> <span class="k">new</span> <span class="nf">ArgumentException</span><span class="p">(</span><span class="s">"Unexpected null argument"</span><span class="p">,</span> <span class="k">nameof</span><span class="p">(</span><span class="k">from</span><span class="p">));</span>
<span class="k">if</span> <span class="p">((</span><span class="kt">object</span><span class="p">)</span> <span class="n">to</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span> <span class="k">throw</span> <span class="k">new</span> <span class="nf">ArgumentException</span><span class="p">(</span><span class="s">"Unexpected null argument"</span><span class="p">,</span> <span class="k">nameof</span><span class="p">(</span><span class="n">to</span><span class="p">));</span>
<span class="kt">var</span> <span class="n">code</span> <span class="p">=</span> <span class="k">new</span> <span class="n">List</span> <span class="p"><</span> <span class="n">CodeInstruction</span> <span class="p">></span> <span class="p">(</span><span class="n">instructions</span><span class="p">);</span>
<span class="k">for</span> <span class="p">(</span><span class="kt">var</span> <span class="n">x</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span> <span class="n">x</span> <span class="p"><</span> <span class="n">code</span><span class="p">.</span><span class="n">Count</span><span class="p">;</span> <span class="n">x</span><span class="p">++)</span> <span class="p">{</span>
<span class="kt">var</span> <span class="n">ins</span> <span class="p">=</span> <span class="n">code</span><span class="p">[</span><span class="n">x</span><span class="p">];</span>
<span class="k">if</span> <span class="p">(</span><span class="n">ins</span><span class="p">.</span><span class="n">operand</span> <span class="k">as</span> <span class="n">MethodBase</span> <span class="p">!=</span> <span class="k">from</span><span class="p">)</span> <span class="k">continue</span><span class="p">;</span>
<span class="c1">// replace callvirt Invoke with our debug invoke.</span>
<span class="n">ins</span><span class="p">.</span><span class="n">opcode</span> <span class="p">=</span> <span class="n">OpCodes</span><span class="p">.</span><span class="n">Callvirt</span><span class="p">;</span>
<span class="n">ins</span><span class="p">.</span><span class="n">operand</span> <span class="p">=</span> <span class="n">to</span><span class="p">;</span>
<span class="c1">// insert additional Ldarg_1 which corresponds to MethodBase of invoked function.</span>
<span class="c1">// TODO: Improve this, can be easily broken by obfuscation or future VMP updates</span>
<span class="n">code</span><span class="p">.</span><span class="nf">Insert</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="k">new</span> <span class="nf">CodeInstruction</span><span class="p">(</span><span class="n">OpCodes</span><span class="p">.</span><span class="n">Ldarg_1</span><span class="p">));</span>
<span class="n">Logger</span><span class="p">.</span><span class="nf">Info</span><span class="p">(</span><span class="s">"Replaced with custom Invoke and injected MethodBase argument at {0}."</span><span class="p">,</span> <span class="n">x</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="c1">/// <summary>A transpiler that alters instructions that calls specific method</summary></span>
<span class="c1">/// <param name="instructions">The enumeration of <see cref="T:HarmonyLib.CodeInstruction" /> to act on</param></span>
<span class="c1">/// <returns>Modified enumeration of <see cref="T:HarmonyLib.CodeInstruction" /></returns></span>
<span class="k">public</span> <span class="k">static</span> <span class="n">IEnumerable</span> <span class="p"><</span> <span class="n">CodeInstruction</span> <span class="p">></span> <span class="nf">Transpiler</span><span class="p">(</span><span class="n">IEnumerable</span> <span class="p"><</span> <span class="n">CodeInstruction</span> <span class="p">></span> <span class="n">instructions</span><span class="p">)</span> <span class="p">{</span>
<span class="n">Logger</span><span class="p">.</span><span class="nf">Debug</span><span class="p">(</span><span class="s">"VMP Function Handler Transpiler"</span><span class="p">);</span>
<span class="c1">// Newer version</span>
<span class="nf">ReplaceVmpInvoke</span><span class="p">(</span><span class="k">ref</span> <span class="n">instructions</span><span class="p">,</span> <span class="n">AccessTools</span><span class="p">.</span><span class="nf">Method</span><span class="p">(</span><span class="k">typeof</span> <span class="p">(</span><span class="n">MethodBase</span><span class="p">),</span> <span class="s">"Invoke"</span><span class="p">,</span> <span class="k">new</span> <span class="p">[]</span> <span class="p">{</span>
<span class="k">typeof</span> <span class="p">(</span><span class="kt">object</span><span class="p">),</span> <span class="k">typeof</span> <span class="p">(</span><span class="n">BindingFlags</span><span class="p">),</span> <span class="k">typeof</span> <span class="p">(</span><span class="n">Binder</span><span class="p">),</span> <span class="k">typeof</span> <span class="p">(</span><span class="kt">object</span><span class="p">[]),</span>
<span class="k">typeof</span> <span class="p">(</span><span class="n">CultureInfo</span><span class="p">)</span>
<span class="p">}),</span> <span class="n">AccessTools</span><span class="p">.</span><span class="nf">Method</span><span class="p">(</span><span class="k">typeof</span> <span class="p">(</span><span class="n">VmProtectDumperTranspiler</span><span class="p">),</span> <span class="k">nameof</span><span class="p">(</span><span class="n">HookedInvoke</span><span class="p">)));</span>
<span class="c1">// Older version</span>
<span class="nf">ReplaceVmpInvoke</span><span class="p">(</span><span class="k">ref</span> <span class="n">instructions</span><span class="p">,</span>
<span class="n">AccessTools</span><span class="p">.</span><span class="nf">Method</span><span class="p">(</span><span class="k">typeof</span> <span class="p">(</span><span class="n">MethodBase</span><span class="p">),</span> <span class="s">"Invoke"</span><span class="p">,</span> <span class="k">new</span> <span class="p">[]</span> <span class="p">{</span>
<span class="k">typeof</span> <span class="p">(</span><span class="kt">object</span><span class="p">),</span> <span class="k">typeof</span> <span class="p">(</span><span class="kt">object</span><span class="p">[])</span>
<span class="p">}),</span>
<span class="n">AccessTools</span><span class="p">.</span><span class="nf">Method</span><span class="p">(</span><span class="k">typeof</span> <span class="p">(</span><span class="n">VmProtectDumperTranspiler</span><span class="p">),</span> <span class="k">nameof</span><span class="p">(</span><span class="n">HookedInvokeOld</span><span class="p">)));</span>
<span class="k">return</span> <span class="n">instructions</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>And this worked just fine, but it wasn’t stable so I didn’t bother with it and just did same as Washi.</p>
<hr />
<p>How Harmony works</p>
<p>Where other patch libraries simply allow you to replace the original method, <code class="language-plaintext highlighter-rouge">Harmony</code> goes one step further and gives you:</p>
<ul>
<li>A way to keep the original method intact</li>
<li>Execute your code before and/or after the original method</li>
<li>Modify the original with IL code processors</li>
<li>Multiple Harmony patches co-exist and don’t conflict with each other</li>
</ul>
<p><code class="language-plaintext highlighter-rouge">Prefix</code> - is a method that is executed before the original method. It is commonly used to:</p>
<ul>
<li>access and edit the arguments of the original method</li>
<li>set the result of the original method</li>
<li>skip the original method and prefixes that alter its input/result</li>
<li>set custom state that can be recalled in the postfix</li>
</ul>
<p><code class="language-plaintext highlighter-rouge">Postfix</code> is a method that is executed after the original method. It is commonly used to:</p>
<ul>
<li>read or change the result of the original method</li>
<li>access the arguments of the original method</li>
<li>make sure your code is always executed</li>
<li>read custom state from the prefix</li>
</ul>
<p><code class="language-plaintext highlighter-rouge">Transpiler</code> is not a patch method that is executed at runtime when the Original method is called. Instead, you can see it more as a post-compiler stage that can alter the source code of the original method. Except that at runtime, it’s not C# but IL code that you change.</p>
<p><a href="https://harmony.pardeike.net/articles/intro.html">Resources</a></p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">invokeMethod</span> <span class="p">=</span> <span class="k">typeof</span> <span class="p">(</span><span class="kt">object</span><span class="p">).</span><span class="n">Assembly</span>
<span class="p">.</span><span class="nf">GetType</span><span class="p">(</span><span class="s">"System.Reflection.RuntimeMethodInfo"</span><span class="p">)</span>
<span class="p">.</span><span class="nf">GetMethod</span><span class="p">(</span><span class="s">"UnsafeInvokeInternal"</span><span class="p">,</span> <span class="n">BindingFlags</span><span class="p">.</span><span class="n">NonPublic</span> <span class="p">|</span> <span class="n">BindingFlags</span><span class="p">.</span><span class="n">Instance</span><span class="p">);</span>
<span class="n">prefixMethod</span> <span class="p">=</span> <span class="k">typeof</span> <span class="p">(</span><span class="n">Program</span><span class="p">).</span><span class="nf">GetMethod</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">InvokePrefix</span><span class="p">),</span> <span class="n">BindingFlags</span><span class="p">.</span><span class="n">Static</span> <span class="p">|</span> <span class="n">BindingFlags</span><span class="p">.</span><span class="n">Public</span><span class="p">);</span>
<span class="n">postfixMethod</span> <span class="p">=</span> <span class="k">typeof</span> <span class="p">(</span><span class="n">Program</span><span class="p">).</span><span class="nf">GetMethod</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">InvokePostfix</span><span class="p">),</span> <span class="n">BindingFlags</span><span class="p">.</span><span class="n">Static</span> <span class="p">|</span> <span class="n">BindingFlags</span><span class="p">.</span><span class="n">Public</span><span class="p">);</span>
<span class="n">harmony</span><span class="p">.</span><span class="nf">Patch</span><span class="p">(</span><span class="n">invokeMethod</span><span class="p">,</span> <span class="k">new</span> <span class="nf">HarmonyMethod</span><span class="p">(</span><span class="n">prefixMethod</span><span class="p">),</span> <span class="k">new</span> <span class="nf">HarmonyMethod</span><span class="p">(</span><span class="n">postfixMethod</span><span class="p">));</span>
<span class="k">public</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">InvokePrefix</span><span class="p">(</span><span class="kt">object</span> <span class="n">__instance</span><span class="p">,</span> <span class="kt">object</span> <span class="n">obj</span><span class="p">,</span> <span class="kt">object</span><span class="p">[]</span> <span class="n">parameters</span><span class="p">,</span> <span class="kt">object</span><span class="p">[]</span> <span class="n">arguments</span><span class="p">)</span> <span class="p">{</span>
<span class="kt">var</span> <span class="n">method</span> <span class="p">=</span> <span class="p">(</span><span class="n">MethodBase</span><span class="p">)</span> <span class="n">__instance</span><span class="p">;</span>
<span class="kt">string</span> <span class="n">returnType</span> <span class="p">=</span> <span class="n">method</span> <span class="k">is</span> <span class="n">MethodInfo</span> <span class="n">info</span> <span class="p">?</span> <span class="n">info</span><span class="p">.</span><span class="n">ReturnType</span><span class="p">.</span><span class="n">FullName</span> <span class="p">:</span> <span class="s">"System.Object"</span><span class="p">;</span>
<span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="s">$"--- call to </span><span class="p">{</span><span class="n">returnType</span><span class="p">}</span><span class="s"> </span><span class="p">{</span><span class="n">method</span><span class="p">.</span><span class="n">DeclaringType</span><span class="p">}</span><span class="s">::</span><span class="p">{</span><span class="n">method</span><span class="p">.</span><span class="n">Name</span><span class="p">}</span><span class="s">(</span><span class="p">{</span><span class="kt">string</span><span class="p">.</span><span class="nf">Join</span><span class="p">(</span><span class="s">", "</span><span class="p">,</span> <span class="n">method</span><span class="p">.</span><span class="nf">GetParameters</span><span class="p">().</span><span class="n">Cast</span><span class="p"><</span><span class="kt">object</span><span class="p">>())}</span><span class="s">)"</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">arguments</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span> <span class="p">{</span>
<span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span> <span class="n">i</span> <span class="p"><</span> <span class="n">arguments</span><span class="p">.</span><span class="n">Length</span><span class="p">;</span> <span class="n">i</span><span class="p">++)</span>
<span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="s">$"--- </span><span class="p">{</span><span class="n">i</span><span class="p">}</span><span class="s">: </span><span class="p">{</span><span class="nf">FormatObject</span><span class="p">(</span><span class="n">arguments</span><span class="p">[</span><span class="n">i</span><span class="p">])}</span><span class="s">"</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">InvokePostfix</span><span class="p">(</span><span class="kt">object</span> <span class="n">__instance</span><span class="p">,</span> <span class="k">ref</span> <span class="kt">object</span> <span class="n">__result</span><span class="p">,</span> <span class="kt">object</span> <span class="n">obj</span><span class="p">,</span> <span class="kt">object</span><span class="p">[]</span> <span class="n">parameters</span><span class="p">,</span> <span class="kt">object</span><span class="p">[]</span> <span class="n">arguments</span><span class="p">)</span> <span class="p">{</span>
<span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="s">"--- Resulted in "</span> <span class="p">+</span> <span class="nf">FormatObject</span><span class="p">(</span><span class="n">__result</span><span class="p">));</span>
<span class="p">}</span>
</code></pre></div></div>
<h2 id="current-approach-vmprotectdumperunsafeinvoke">Current approach <a href="https://github.com/void-stack/VMUnprotect/blob/main/VMUP/VMUnprotect.Runtime/Hooks/Methods/VmProtectDumperUnsafeInvoke.cs">VmProtectDumperUnsafeInvoke</a></h2>
<p>Since we would be logging all functions called by the assembly, I’ve added an additional check to make sure the call is coming from VMProtect Call Handler.</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Check if this invoke is coming from VMP Handler</span>
<span class="kt">var</span> <span class="n">isVmpFunction</span> <span class="p">=</span> <span class="n">structure</span> <span class="k">is</span> <span class="p">{}</span> <span class="p">&&</span> <span class="k">new</span> <span class="nf">StackTrace</span><span class="p">().</span><span class="nf">GetFrame</span><span class="p">(</span><span class="m">3</span><span class="p">).</span><span class="nf">GetMethod</span><span class="p">().</span><span class="n">MetadataToken</span> <span class="p">==</span>
<span class="n">structure</span><span class="p">.</span><span class="n">FunctionHandler</span><span class="p">.</span><span class="n">MDToken</span><span class="p">.</span><span class="nf">ToInt32</span><span class="p">();</span>
<span class="k">if</span> <span class="p">(!</span><span class="n">isVmpFunction</span><span class="p">)</span>
<span class="k">return</span> <span class="k">true</span><span class="p">;</span>
</code></pre></div></div>
<p>This works same besides that we have additional features like:</p>
<ul>
<li><a href="https://github.com/void-stack/VMUnprotect/blob/main/VMUP/VMUnprotect.Runtime/Hooks/Methods/AntiDebug/DebugIsAttachedPatch.cs">DebugIsAttachedPatch</a></li>
<li><a href="https://github.com/void-stack/VMUnprotect/blob/main/VMUP/VMUnprotect.Runtime/Hooks/Methods/AntiDebug/DebugIsLoggingPatch.cs">DebugIsLoggingPatch</a></li>
<li><a href="https://github.com/void-stack/VMUnprotect/blob/main/VMUP/VMUnprotect.Runtime/Hooks/Methods/AntiDebug/NtQueryInformationProcessPatch.cs">NtQueryInformationProcessPatch</a></li>
</ul>
<p>Whole source code on Github: <a href="https://github.com/void-stack/VMUnprotect/">VMUnprotect</a></p>void-stackNow what if… we make an program that does everything for us! At first I made my approach that tries to search for function 0x06000153 in this sample. Which appears to be invoking functions called in virtualized methods.