or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

data-access.mddebug.mdhashing.mdimport-export.mdindex.mdmemory.mdordinal-lookups.mdpacker-detection.mdpe-parsing.mdresources.mdsections.md

memory.mddocs/

0

# Memory Layout and Relocations

1

2

Functions for memory mapping PE files and handling base relocations for different load addresses. These capabilities enable proper loading and execution of PE files at arbitrary memory locations.

3

4

## Capabilities

5

6

### Memory Mapping

7

8

Create memory-mapped representation of the PE file as it would appear when loaded.

9

10

```python { .api }

11

def get_memory_mapped_image(self, max_virtual_address=268435456, ImageBase=None):

12

"""

13

Get memory layout of PE file as it would appear when loaded.

14

15

Args:

16

max_virtual_address (int): Maximum virtual address to map (default: 256MB)

17

ImageBase (int, optional): Base address to use. If None, uses PE's ImageBase.

18

19

Returns:

20

bytes: Memory-mapped image data

21

22

Note:

23

This creates a complete memory layout with sections mapped to their

24

virtual addresses, filling gaps with zeros as needed.

25

"""

26

```

27

28

### Base Relocations

29

30

Handle relocations needed when PE is loaded at different base address.

31

32

```python { .api }

33

def relocate_image(self, new_ImageBase):

34

"""

35

Apply base relocations for new ImageBase address.

36

37

Args:

38

new_ImageBase (int): New base address for the image

39

40

Note:

41

Modifies the PE file data to update all absolute addresses

42

based on the new base address. Requires relocation table.

43

"""

44

45

def has_relocs(self):

46

"""

47

Check if PE file has relocation table.

48

49

Returns:

50

bool: True if file has base relocations

51

"""

52

53

def has_dynamic_relocs(self):

54

"""

55

Check if PE file has dynamic relocations.

56

57

Returns:

58

bool: True if file has dynamic relocations

59

"""

60

```

61

62

### Overlay Operations

63

64

Handle data appended beyond the standard PE structure.

65

66

```python { .api }

67

def get_overlay(self):

68

"""

69

Get overlay data appended to PE file.

70

71

Returns:

72

bytes: Overlay data, or None if no overlay present

73

74

Note:

75

Overlay is data appended beyond the PE file structure,

76

often used by installers or self-extracting archives.

77

"""

78

79

def get_overlay_data_start_offset(self):

80

"""

81

Get file offset where overlay data begins.

82

83

Returns:

84

int: File offset of overlay start, or None if no overlay

85

"""

86

87

def trim(self):

88

"""

89

Remove overlay data from PE file.

90

91

Note:

92

Removes any data beyond the PE file structure,

93

effectively stripping overlay data.

94

"""

95

```

96

97

### Relocation Parsing

98

99

Parse and analyze relocation directory entries.

100

101

```python { .api }

102

def parse_relocations_directory(self, rva, size):

103

"""

104

Parse base relocations directory.

105

106

Args:

107

rva (int): RVA of relocations directory

108

size (int): Size of relocations directory

109

110

Populates:

111

self.DIRECTORY_ENTRY_BASERELOC: List of BaseRelocationData objects

112

"""

113

```

114

115

## Usage Examples

116

117

### Memory Image Generation

118

119

```python

120

import pefile

121

122

with pefile.PE('executable.exe') as pe:

123

# Get memory-mapped image at original base address

124

memory_image = pe.get_memory_mapped_image()

125

126

print(f"Memory image size: {len(memory_image)} bytes")

127

print(f"Original ImageBase: 0x{pe.OPTIONAL_HEADER.ImageBase:08x}")

128

129

# Save memory image

130

with open('memory_image.bin', 'wb') as f:

131

f.write(memory_image)

132

133

# Get memory image at different base address

134

new_base = 0x10000000

135

relocated_image = pe.get_memory_mapped_image(ImageBase=new_base)

136

137

with open('relocated_image.bin', 'wb') as f:

138

f.write(relocated_image)

139

```

140

141

### Relocation Analysis

142

143

```python

144

import pefile

145

146

with pefile.PE('executable.exe') as pe:

147

# Check if file has relocations

148

if pe.has_relocs():

149

print("File has base relocations")

150

151

if hasattr(pe, 'DIRECTORY_ENTRY_BASERELOC'):

152

total_relocs = 0

153

154

print("\nRelocation Blocks:")

155

print("-" * 40)

156

157

for reloc_block in pe.DIRECTORY_ENTRY_BASERELOC:

158

base_rva = reloc_block.struct.VirtualAddress

159

block_size = reloc_block.struct.SizeOfBlock

160

num_entries = len(reloc_block.entries)

161

162

print(f"Base RVA: 0x{base_rva:08x}")

163

print(f"Block Size: {block_size}")

164

print(f"Entries: {num_entries}")

165

166

# Show first few relocations in block

167

for i, entry in enumerate(reloc_block.entries[:5]):

168

if entry.type != 0: # Skip padding entries

169

rva = base_rva + entry.rva

170

print(f" 0x{rva:08x}: Type {entry.type}")

171

172

if len(reloc_block.entries) > 5:

173

print(f" ... and {len(reloc_block.entries) - 5} more")

174

175

total_relocs += num_entries

176

print()

177

178

print(f"Total relocations: {total_relocs}")

179

else:

180

print("File has no base relocations")

181

182

# Check for dynamic relocations

183

if pe.has_dynamic_relocs():

184

print("File has dynamic relocations")

185

```

186

187

### Address Space Layout

188

189

```python

190

import pefile

191

192

def analyze_address_space(pe):

193

"""Analyze PE address space layout."""

194

print("Address Space Layout:")

195

print("-" * 50)

196

197

image_base = pe.OPTIONAL_HEADER.ImageBase

198

size_of_image = pe.OPTIONAL_HEADER.SizeOfImage

199

200

print(f"ImageBase: 0x{image_base:08x}")

201

print(f"Size of Image: 0x{size_of_image:08x}")

202

print(f"Address Range: 0x{image_base:08x} - 0x{image_base + size_of_image:08x}")

203

print()

204

205

print("Section Virtual Layout:")

206

print(f"{'Section':<10} {'VirtAddr':<12} {'VirtSize':<12} {'End Addr':<12}")

207

print("-" * 50)

208

209

for section in pe.sections:

210

name = section.Name.decode('utf-8').strip('\x00')

211

virt_addr = image_base + section.VirtualAddress

212

virt_size = section.VirtualSize

213

end_addr = virt_addr + virt_size

214

215

print(f"{name:<10} 0x{virt_addr:08x} 0x{virt_size:08x} 0x{end_addr:08x}")

216

217

# Usage

218

with pefile.PE('executable.exe') as pe:

219

analyze_address_space(pe)

220

```

221

222

### Image Relocation

223

224

```python

225

import pefile

226

227

# Load PE file

228

pe = pefile.PE('executable.exe')

229

230

# Check current base address

231

original_base = pe.OPTIONAL_HEADER.ImageBase

232

print(f"Original ImageBase: 0x{original_base:08x}")

233

234

# Check if relocation is possible

235

if pe.has_relocs():

236

print("File supports relocation")

237

238

# Relocate to new base address

239

new_base = 0x20000000

240

print(f"Relocating to: 0x{new_base:08x}")

241

242

pe.relocate_image(new_base)

243

244

# Verify the change

245

updated_base = pe.OPTIONAL_HEADER.ImageBase

246

print(f"Updated ImageBase: 0x{updated_base:08x}")

247

248

# Save relocated PE

249

pe.write('relocated_executable.exe')

250

print("Relocated executable saved")

251

252

else:

253

print("File does not support relocation (no relocation table)")

254

255

pe.close()

256

```

257

258

### Virtual to Physical Address Translation

259

260

```python

261

import pefile

262

263

with pefile.PE('executable.exe') as pe:

264

def virtual_to_physical(virtual_addr):

265

"""Convert virtual address to file offset."""

266

# Convert VA to RVA

267

image_base = pe.OPTIONAL_HEADER.ImageBase

268

rva = virtual_addr - image_base

269

270

# Convert RVA to file offset

271

file_offset = pe.get_offset_from_rva(rva)

272

return file_offset

273

274

def physical_to_virtual(file_offset):

275

"""Convert file offset to virtual address."""

276

# Convert file offset to RVA

277

rva = pe.get_rva_from_offset(file_offset)

278

if rva is not None:

279

# Convert RVA to VA

280

image_base = pe.OPTIONAL_HEADER.ImageBase

281

virtual_addr = image_base + rva

282

return virtual_addr

283

return None

284

285

# Example translations

286

entry_point_va = pe.OPTIONAL_HEADER.ImageBase + pe.OPTIONAL_HEADER.AddressOfEntryPoint

287

entry_point_offset = virtual_to_physical(entry_point_va)

288

289

print(f"Entry Point VA: 0x{entry_point_va:08x}")

290

print(f"Entry Point File Offset: 0x{entry_point_offset:08x}")

291

292

# Verify round-trip conversion

293

back_to_va = physical_to_virtual(entry_point_offset)

294

print(f"Round-trip VA: 0x{back_to_va:08x}")

295

```

296

297

### Memory Protection Analysis

298

299

```python

300

import pefile

301

302

def analyze_memory_protection(pe):

303

"""Analyze section memory protection characteristics."""

304

print("Memory Protection Analysis:")

305

print("-" * 60)

306

print(f"{'Section':<10} {'Protection':<15} {'Characteristics':<30}")

307

print("-" * 60)

308

309

for section in pe.sections:

310

name = section.Name.decode('utf-8').strip('\x00')

311

chars = section.Characteristics

312

313

# Determine protection flags

314

protection = []

315

if chars & 0x20000000: # IMAGE_SCN_MEM_EXECUTE

316

protection.append('X')

317

if chars & 0x40000000: # IMAGE_SCN_MEM_READ

318

protection.append('R')

319

if chars & 0x80000000: # IMAGE_SCN_MEM_WRITE

320

protection.append('W')

321

322

prot_str = ''.join(protection) if protection else 'None'

323

324

# Decode other characteristics

325

char_flags = []

326

if chars & 0x00000020: # IMAGE_SCN_CNT_CODE

327

char_flags.append('CODE')

328

if chars & 0x00000040: # IMAGE_SCN_CNT_INITIALIZED_DATA

329

char_flags.append('INIT_DATA')

330

if chars & 0x00000080: # IMAGE_SCN_CNT_UNINITIALIZED_DATA

331

char_flags.append('UNINIT_DATA')

332

if chars & 0x02000000: # IMAGE_SCN_MEM_DISCARDABLE

333

char_flags.append('DISCARDABLE')

334

if chars & 0x10000000: # IMAGE_SCN_MEM_SHARED

335

char_flags.append('SHARED')

336

337

char_str = ', '.join(char_flags[:3]) # Limit for display

338

339

print(f"{name:<10} {prot_str:<15} {char_str:<30}")

340

341

# Usage

342

with pefile.PE('executable.exe') as pe:

343

analyze_memory_protection(pe)

344

```