Skip to content

Instantly share code, notes, and snippets.

@gamozolabs
Last active July 1, 2022 15:23
Show Gist options
  • Star 18 You must be signed in to star a gist
  • Fork 7 You must be signed in to fork a gist
  • Save gamozolabs/bade2ac5e69ce7af24a2f6b8c189721c to your computer and use it in GitHub Desktop.
Save gamozolabs/bade2ac5e69ce7af24a2f6b8c189721c to your computer and use it in GitHub Desktop.
IDA Python loader for /proc/pid/mem without debugging a process
import re, subprocess, idaapi, ida_segment, ida_kernwin
# To install this, simply put it in your ida_install/loaders folder and open
# a `/proc/<pid>/mem` file!
#
# You might need to set `echo 0 > /proc/sys/kernel/yama/ptrace_scope` if you
# want to be able to dump processes depending on your system configuration.
# Check if the file is supported by our loader
def accept_file(li, filename):
# Check if the filename is /proc/<pid>/mem, if so, we can handle it!
mch = re.match("/proc/(\d+)/mem", filename)
if not mch:
return 0
# We can handle this file!
return {'format': f"{filename} dump", 'processor': 'metapc'}
# Load the file into the database!
def load_file(li, neflags, fmt):
# Get the PID from the format
pid = int(re.match("/proc/(\d+)/mem dump", fmt).group(1))
# Ask the user about the bitness to use for segments
bitness = ida_kernwin.ask_buttons(
"64-bit", "32-bit", "Cancel", 0, "What bitness is this process?")
if bitness == -1:
# Cancelled
return 0
# Convert dialog selection to IDA's segment bitness values
if bitness == 1:
bitness = 2 # 64-bit
idaapi.get_inf_structure().lflags |= idaapi.LFLG_64BIT
elif bitness == 0:
bitness = 1 # 32-bit
# Open the maps file
seg = idaapi.segment_t()
with open(f"/proc/{pid}/maps") as fd:
# Go through each line in the map
for line in fd.readlines():
# Parse the /proc/<pid>/maps line, super quality regex
mch = re.match("([0-9a-f]+)-([0-9a-f]+) ([r-])([w-])([x-])[ps] [0-9a-f]+ [0-9a-f]+:[0-9a-f]+ \d+\s+(.*)", line)
start = int(mch.group(1), 16)
end = int(mch.group(2), 16)
r = mch.group(3) == "r"
w = mch.group(4) == "w"
x = mch.group(5) == "x"
name = mch.group(6)
# If this segment is usable in any way, add it to the database
if r or w or x:
# Mark things as code if they're executable
seg.start_ea = start
seg.end_ea = end
#seg.bitness = bitness
# Set up permissions
seg.perm = 0
if r:
seg.perm |= ida_segment.SEGPERM_READ
if w:
seg.perm |= ida_segment.SEGPERM_WRITE
if x:
seg.perm |= ida_segment.SEGPERM_EXEC
# Add the segment!
if x:
idaapi.add_segm_ex(seg, name, "CODE", 0)
else:
idaapi.add_segm_ex(seg, name, "DATA", 0)
idaapi.set_segm_addressing(idaapi.getseg(start), bitness)
# IDA's API doesn't like seeking negative
if start >= 0x8000000000000000:
print(f"Unsupported address range {start:x}-{end:x} "
"leaving uninitialized")
continue
# Seek to the data and read it
li.seek(start)
data = li.read(end - start)
# It's possible we failed to read certain areas, so only
# `put_bytes` if we actually got a valid result
if data:
# Write in the bytes
idaapi.put_bytes(start, data)
idaapi.load_plugin('hexx64')
# Loaded!
return 1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment