Skip to main content

The Hunt for the Elusive DLL Hijack: A Deep Dive into the Spotify Installer

Reverse engineering for bug bounties is a thrilling adventure, often leading down rabbit holes of code and unexpected discoveries. My recent journey involved the Spotify installer, a quest to uncover a potential DLL hijacking vulnerability. This post will walk you through the process, the tools, the roadblocks, and the ultimate conclusions, highlighting key lessons learned along the way.

Understanding DLL Hijacking: The Goal

At its core, DLL (Dynamic Link Library) hijacking is a common vulnerability where an application attempts to load a legitimate DLL, but a malicious one is loaded instead. This often happens because applications search for DLLs in a specific order (e.g., current directory first, then system directories). If a malicious DLL with the expected name is placed in an earlier search path, the application loads it, allowing an attacker to execute arbitrary code within the application's context.

Tools of the Trade

Our investigation relied on a suite of powerful tools:

  • Ghidra: For static analysis (disassembling and decompiling the binary).
  • Process Monitor (ProcMon): For dynamic analysis (observing file system and registry activity).
  • x64dbg: A powerful debugger for runtime analysis and setting breakpoints.
  • Visual Studio Code (VS Code) & Microsoft Visual C++ (MSVC) Compiler: For developing our Proof-of-Concept (PoC) DLL.

Phase 1: Static Analysis with Ghidra – The Initial Recon

I started by loading SpotifySetup.exe into Ghidra. My initial exploration took me into security_init_cookie, a function often related to exploit mitigations like Stack Canaries. While interesting, it led me to a more promising avenue: LoadLibraryExA calls.

LoadLibraryExA is a Windows API function used to load DLLs. Its third parameter, dwFlags, is critical for DLL hijacking.

  • A dwFlags value of 0x800 (equivalent to LOAD_LIBRARY_SEARCH_DEFAULT_DIRS) is considered secure, as it tells the system to search standard secure directories (like System32) before the application's current directory.
  • A dwFlags value of 0 (or 0x000, 0x0) implies a less secure search order, often including the current directory first, which is ripe for hijacking.

My deep dive into LoadLibraryExA references revealed a prime candidate at 140084e31. This particular call looked like:

C
hLibModule = LoadLibraryExA(local_60,(HANDLE)0x0,0)

The key here was the 0 flag – a potential red flag for DLL hijacking! What was local_60? Static analysis showed local_60 was dynamically assigned: local_60 = IMAGE_DOS_HEADER_140000000.e_magic + param_1[1];. This meant the DLL name was constructed at runtime, making dynamic analysis essential.

Phase 2: Dynamic Analysis with Process Monitor – Fishing for Clues

With a potential vulnerable function identified, Process Monitor became my best friend. I set filters to observe SpotifySetup.exe's file operations, specifically looking for CreateFile events with a Result of NAME NOT FOUND in the installer's current directory (my Downloads folder).

This revealed several DLLs that the installer sought but didn't initially find in its own directory:

  • Bcrypt.dll (my initial target)
  • profapi.dll
  • CRYPTBASE.DLL
  • TextShaping.dll
  • ncrypt.dll
  • NTASN1.dll
  • MSASN1.dll
  • DPAPI.DLL
  • winnlsres.dll

These "NAME NOT FOUND" results were exciting, suggesting that the installer might then fall back to loading these from less secure paths, creating an opportunity for a hijack.

Phase 3: Building a Proof-of-Concept (PoC) DLL

To confirm the hijack, I needed a malicious DLL that would signal its execution. My PoC was a simple C++ DLL (MaliciousBcryptDLL.cpp) that displayed a MessageBoxA pop-up in its DllMain function.

However, getting it to compile with MSVC in VS Code had its own set of challenges:

  1. cl.exe not found / Environment Variables: The MSVC compiler (cl.exe) wasn't in my system's PATH.
    • Fix: Always launch VS Code from the "Developer Command Prompt for VS 2022" (as administrator). This correctly sets all necessary environment variables.
  2. Path Quoting Issues & Linker Errors: My initial tasks.json struggled with spaces in file paths, leading to errors like unrecognized source file type and cannot open input file 'dllmain.cpp'.
    • Fix: While moving the project to a path without spaces is ideal, the tasks.json was refined to use escaped double quotes (\") around all paths in args and correctly order compiler arguments (source file before /link). The user32.lib library also needed to be explicitly linked for MessageBoxA.
  3. ASLR & Breakpoints: Setting breakpoints in x64dbg using static addresses resulted in errors due to ASLR.
    • Fix: Instead of bp 140084E31, use module-relative breakpoints: bp SpotifySetup.exe+84E31. This offsets the breakpoint from the executable's dynamically loaded base address.

Phase 4: Testing the PoC & The Twist

With the Bcrypt.dll compiled, I tried copying it (renamed to profapi.dll for one test, for example) into the Downloads folder alongside SpotifySetup.exe. My expectation was a glorious pop-up.

But... no pop-up.

Process Monitor also stopped showing "NAME NOT FOUND" for Bcrypt.dll or profapi.dll in the Downloads directory. This was a critical clue: it implied these DLLs were now being loaded securely before the potentially vulnerable fallback could occur.

Adding another twist, the Spotify installer explicitly prompted to run it "using a normal account and not admin." This meant debugging had to be done without administrator privileges, limiting the potential impact of any hijack.

Phase 5: Definitive Debugging with x64dbg – The Ultimate Answer

The only way to know for sure was to confirm if the vulnerable LoadLibraryExA call was ever actually reached.

  1. I launched x64dbg as a normal user (not as administrator).
  2. Opened SpotifySetup.exe.
  3. Set the module-relative breakpoint: bp SpotifySetup.exe+84E31.
  4. Ran the installer.

The Result: The breakpoint was NEVER HIT.

Conclusion: No Hijack Here (For This Path)

The debugger provided the definitive answer: the specific LoadLibraryExA call at SpotifySetup.exe+84E31 is never executed during the normal installation process. This means that, for this version of the Spotify installer and its execution flow, the identified vulnerable code path is not exploited. The installer likely manages to load all its necessary DLLs through secure methods (e.g., using LOAD_LIBRARY_SEARCH_DEFAULT_DIRS flags or explicit full paths) before ever falling back to the less secure search order that would allow a DLL hijack.

Key Takeaways from the Hunt

  • Static vs. Dynamic Analysis: Static analysis (Ghidra) gives you potential leads, but dynamic analysis (ProcMon, x64dbg) is crucial for confirming if those leads are actually reachable and exploitable in a live environment.
  • The Devil is in the Details: Flags (like 0x800 vs 0 in LoadLibraryExA), execution flow, and even environment privileges (admin vs. normal user) profoundly impact exploitability.
  • Debugging Challenges: Be prepared for ASLR, path quoting complexities, and compiler environment setups. It's a journey of continuous problem-solving.
  • Persistence Pays Off: Even when a specific vulnerability doesn't pan out, the process of investigating builds invaluable skills.

This journey, though not ending in a reported bug for Spotify, was a comprehensive exercise in understanding and applying reverse engineering and vulnerability research techniques. It's a testament to the iterative nature of security work – every attempted exploit teaches you something new.

Follow me at:
X - @HaqSec
Instagram - haq_sec

Comments

Popular posts from this blog

Malware Analysis: Dissecting a Golang Botnet - Part 1

Introduction In this post, I walk through the process of analyzing a Golang-based botnet sample — specifically a variant of FritzFrog , a peer-to-peer (P2P) botnet known for brute-forcing SSH servers and spreading laterally across networks. The goal here is to share my steps, tools, and insights while preparing for a cybersecurity analyst role.  🐸 1. Downloading the Malware Sample I began by grabbing the malware sample from Da2dalus’ excellent GitHub repository of real-world malware: URL: FritzFrog Sample on GitHub To fetch the raw binary into my WSL environment, I used: wget -O botnet_malware_IM https://github.com/Da2dalus/The-MALWARE-Repo/raw/refs/heads/master/Botnets/FritzFrog/001eb377f0452060012124cb214f658754c7488ccb82e23ec56b2f45a636c859 📤 2. Transferring the Malware to the Flare VM (Windows) My analysis environment was running inside a Windows VM using FLARE VM . Since the malware was downloaded via WSL, I needed a way to securely transfer it to the Windows VM. First, ...

Building my own write blocker

  Spoiler — It’s cheaper than buying one I was looking to buy a write blocker to do data recovery/forensics tasks but I quickly noticed that I was window shopping write blockers due to their cost. Some starting at £300, others that cost less were no longer being built or sold, maybe you could find a 2nd hand one with or without the wires. Most of these write blockers were industry standard, used by law enforcement but was it necessary for me to buy such an expensive write blocker….or is it possible to build my own….. So th e  research began, reading through articles, publications, and so on, and with the information gained, I felt that I could build my own write blocker. So what do I need: A Raspberry Pi A Linux distro. HDD/SSD to test the write blocker And to put the information I gained into practice Building the write blocker So, I brought a Raspberry Pi 4 Model B that came with a power supply, HDMI cables, 32GB SD card, a case, and some extras. ( https://www.okdo.com/c/pi-...

Notes from a Linux command line course

 Recently I took a course on Linux command line and shell scripting, below are the notes I took which I decided to write into a blog to refer to for future reference (there's no way I could remember all of this in a single sitting) 1. Kernel vs Shell OS has 3 layers: Application layer - User apps, Daemons Shell - Command line interface. Kernel - Hardware management, memory management, I/O Handler, CPU, process management. Closest layer to the hardware The kernel controls and mediates access to hardware, for example, it schedules and allocates system resources like memory, CPU, disk etc. The shell works as an interface to access the services provided by the OS. We can further breakdown the layers into the following: User space - If you run a for loop etc, you are in user space. But when you want to perform an operation such as, write to the disk, for example, save a file, then it needs to talk to the kernel space. As the application can't directly talk to the hardware. Kernel sp...