Skip to content

Malware Analysis

xwings edited this page Jul 6, 2025 · 2 revisions

Malware Analysis with Qiling

Qiling Framework is a powerful tool for malware analysis. Its sandboxed emulation environment allows you to safely execute and inspect malicious code, while its hooking capabilities provide deep visibility into the malware's behavior.

Key Advantages for Malware Analysis

  • Safety: Malware is executed within a secure sandbox, isolated from the host system. It cannot infect your machine.
  • Environment Spoofing: You can easily modify the emulated environment to trick malware. For example, you can change the system time, fake registry keys, or alter API responses to trigger specific behaviors.
  • Dynamic Analysis: Observe the malware as it runs. See what files it tries to access, what network connections it attempts, and what system changes it makes.
  • Deobfuscation and Unpacking: Many malware samples are packed or obfuscated. You can use Qiling to run the malware until it unpacks itself in memory, and then dump the clean, deobfuscated code for further analysis.
  • Cross-Platform Analysis: Analyze Windows malware on a Linux machine, or IoT malware on a Windows machine, without needing to set up multiple virtual machines.

Common Malware Analysis Techniques

1. API and Syscall Monitoring

The most common first step is to monitor the malware's interactions with the operating system.

Example: Logging all syscalls

from qiling import Qiling
from qiling.const import QL_VERBOSE

if __name__ == "__main__":
    # Run a Windows malware sample
    ql = Qiling(['malware.exe'], 'path/to/rootfs/x86_windows', verbose=QL_VERBOSE.DEFAULT)
    ql.run()

This will print every syscall the malware makes, along with its parameters. This can reveal its intent, such as trying to delete files, create registry keys, or connect to a C2 server.

2. Hooking Critical Functions

You can hook specific functions to gain more context or to control the malware's execution.

Example: Intercepting file creation

def on_createfile(ql, address, params):
    filename = params['lpFileName']
    print(f"Malware is attempting to create or open file: {filename}")

    # You could even block the action
    # ql.reg.eax = 0xFFFFFFFF # Return INVALID_HANDLE_VALUE
    # ql.emu_stop()

# Hook CreateFileW in kernel32.dll
ql.os.set_api("CreateFileW", on_createfile, 'kernel32.dll')

3. Dumping Unpacked Memory

If a sample is packed, you can use Qiling to let it unpack itself and then dump the unpacked code.

Technique:

  1. Identify a location in the code that is likely to be executed after the unpacking is complete. A good candidate is the first instruction of a newly allocated and executable memory region.
  2. Set a hook at that location.
  3. When the hook is hit, dump the entire process memory or specific regions of interest.

Example:

def dump_memory(ql):
    print("Unpacking likely complete. Dumping memory...")
    # Find the memory region containing the original entry point (OEP)
    # This requires some heuristics or manual analysis
    unpacked_region = ql.mem.get_map_containing(ql.reg.eip)
    if unpacked_region:
        start, end, perms, label = unpacked_region
        unpacked_code = ql.mem.read(start, end - start)
        with open("unpacked_binary.bin", "wb") as f:
            f.write(unpacked_code)
        print(f"Dumped {len(unpacked_code)} bytes to unpacked_binary.bin")
    ql.emu_stop()

# Assume we found the OEP to be at 0x401500
ql.hook_address(dump_memory, 0x401500)
ql.run()

4. Analyzing Shellcode

Qiling is ideal for analyzing shellcode, which often expects a very specific environment.

from qiling import Qiling
from qiling.const import QL_ARCH, QL_OS

with open("shellcode.bin", "rb") as f:
    shellcode = f.read()

# Emulate the shellcode in a Windows environment
ql = Qiling(shellcode=shellcode, archtype=QL_ARCH.X86, ostype=QL_OS.WINDOWS)

# You can pre-populate memory or registers that the shellcode might need
# For example, set up a fake API address resolver

ql.run()

By combining these techniques, you can build a powerful and automated malware analysis pipeline with Qiling.

Example: Detecting Process Creation

Many malware families try to launch other processes or inject code into existing ones. Hooking process creation APIs is a fundamental technique for detecting this behavior.

Here is a script that hooks CreateProcessA to monitor for new processes.

Qiling Script:

from qiling import Qiling
from qiling.const import QL_VERBOSE
from qiling.os.windows.api import hook_api

@hook_api("CreateProcessA", "kernel32.dll")
def hook_createprocessa(ql: Qiling, address: int, params: dict):
    # Get the name of the application to be launched
    app_name = params.get("lpApplicationName")
    cmd_line = params.get("lpCommandLine")

    print(f"\n[!] Hooked CreateProcessA! Malware is trying to launch:")
    if app_name:
        print(f"    Application: {app_name}")
    if cmd_line:
        print(f"    Command Line: {cmd_line}")

    # We can block this action by returning 0 (failure)
    ql.reg.eax = 0
    ql.emu_stop()
    return 0

if __name__ == "__main__":
    # Assume 'malware.exe' is the sample we are analyzing
    executable_path = 'C:\\malware.exe'
    rootfs_path = 'path/to/your/rootfs/x86_windows'

    ql = Qiling([executable_path], rootfs_path, verbose=QL_VERBOSE.OFF)

    print("[*] Starting malware analysis...")
    ql.run()
    print("[*] Analysis finished.")

Analysis

  • This script will immediately detect if the malware attempts to call CreateProcessA.
  • The hook intercepts the call before the new process is created, giving the analyst full control.
  • By printing the lpApplicationName and lpCommandLine parameters, we can see exactly what the malware is trying to execute.
  • This technique can be extended to analyze process injection (using CreateRemoteThread) or other common persistence mechanisms.
Clone this wiki locally