Post

MetaData-Modification

MetaData-Modification

What is it?

Three separate Rust programs demonstrating where shellcode can live inside a compiled binary — each placement choice has different memory characteristics, permissions at runtime, and detection profiles. A fourth variant shows loading shellcode from the binary’s resource section instead of embedding it in data sections.

How it works

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
Placement 1: .data section (mutable static)

  static mut DATA: [u8; 272] = [ 0xFC, 0x48, ... ];

  Location: .data section of the PE on disk
  Runtime:  .data is loaded RW (read-write) by default
            Must call VirtualProtect to make executable
  Visibility: shellcode bytes appear in .data in IDA/PE tools
  Address:   &DATA → a writable memory address


Placement 2: .rdata section (immutable static)

  static RDATA: [u8; 272] = [ 0xFC, 0x48, ... ];

  Location: .rdata section (read-only data)
  Runtime:  .rdata is loaded RO (read-only) by default
            Must call VirtualProtect to make writable+executable
  Visibility: shellcode bytes appear in .rdata
  Note: slightly less suspicious than .data (constant-looking data)


Placement 3: .text section (link_section attribute)

  #[no_mangle]
  #[link_section = ".text"]
  static TEXT_SECTION: [u8; 272] = [ 0xFC, 0x48, ... ];

  Location: .text section alongside actual compiled code
  Runtime:  .text is already RX (read-execute) — no VirtualProtect needed
            Shellcode can execute directly from .text
  Stealthier: executable memory with a file backing (the binary itself)
              Not anonymous private allocation — looks like legitimate code
  Caveat: .text content is compared against file on disk by memory scanners


Placement 4: .rsrc section (resource embedding)

  FindResourceW(null_module,
    MAKEINTRESOURCEW(1337),
    RT_RCDATA)
  → hResourceInfo

  LoadResource(null_module, hResourceInfo) → hLoadedResource
  LockResource(hLoadedResource) → resource_ptr (raw pointer to .rsrc data)
  SizeofResource(null_module, hResourceInfo) → resource_size

  resource_ptr:  shellcode lives in .rsrc section
  Advantage:     many static scanners skip resource sections
                 or only scan known resource types (icons, strings)
                 Custom RT_RCDATA with ID 1337 is obscure


Comparison:
  Section  │ Default perms │ VirtualProtect needed │ Detectability
  .data    │ RW            │ Yes (add X)           │ High (obvious shellcode bytes)
  .rdata   │ RO            │ Yes (add W+X)         │ High
  .text    │ RX            │ No                    │ Medium (file-backed, looks like code)
  .rsrc    │ RO            │ Yes (add W+X)         │ Lower (often skipped by scanners)

The .text placement is the most operationally interesting — shellcode embedded alongside compiled code inherits the section’s execute permission without needing a VirtualProtect call. The memory region is backed by the binary itself (not anonymous private memory), which bypasses the common “executable anonymous region” detection heuristic. The downside is that disk-vs-memory comparison tools (PE-sieve) will flag the mismatch between what’s in .text on disk and what’s actually there at runtime.

demo.c

1
2
3
4
5
#include <stdio.h>

int main() {
	printf("[+] This is Metadata Modification Demo");
}

resource.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//
// Microsoft Visual C++ generated include file.
// Used by MetaData-Modification.rc
//
#define IDR_ACCELERATOR1                101
#define IDI_ICON1                       102
#define IDI_ICON2                       103

// Next default values for new objects
// 
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE        104
#define _APS_NEXT_COMMAND_VALUE         40002
#define _APS_NEXT_CONTROL_VALUE         1001
#define _APS_NEXT_SYMED_VALUE           101
#endif
#endif

This post is licensed under CC BY 4.0 by the author.