########################################################################################################
# Script: PowerDbgScriptSaveModule
#
# Parameters: [string] <$methodName>
# Name of the method from call stack.
#
# [string] <$directory>
# Directory where the module will be saved. Make sure this is a valid directory.
# Example: "c:\module"
#
# Purpose: Saves the module that has the method call provided as parameter into the directory provided as second
# parameter. After that, you can use a tool like .NET Reflector to decompile the code.
# This script makes the assumption that SOS.DLL extension is loaded.
#
# Changes History:
#
# Roberto Alexis Farah
# All my functions are provided "AS IS" with no warranties, and confer no rights.
########################################################################################################
param(
[string] $methodName = $(throw "Error! You must provide the method name."),
[string] $directory = $(throw "Error! You must provide the directory where the method will be saved.")
)
set-psdebug -strict
$ErrorActionPreference = "stop"
trap {"Error message: $_"}
write-Host "Extracting MethodDesc..." -foreground Green -background Black
# If you want you can create code to load SOS.DLL extension if necessary.
# Here I'm assuming this extension was already loaded.
Send-PowerDbgCommand("!name2ee *!$methodName")
# Extracts output from previous command.
Parse-PowerDbgNAME2EE
write-Host "Done!" -foreground Green -background Black
# Convert CSV file to Hash Table.
$output = @{}
$output = Convert-PowerDbgCSVtoHashTable
write-Host "MethodDesc = " $output["MethodDesc:"] -foreground Green -background Black
# If something goes wrong, stops execution and notifies user.
if($null -eq $output["MethodDesc:"])
{
throw "Couldn't retrieve MethodDesc!"
}
write-Host "Extracting Module..." -foreground Green -background Black
# Calls !dumpmd using the specific value we want.
Send-PowerDbgCommand("!dumpmd " + $output["MethodDesc:"])
# Extracts output from previous command.
Parse-PowerDbgDUMPMD
write-Host "Done!" -foreground Green -background Black
# Convert CSV file to Hash Table.
$output = @{}
$output = Convert-PowerDbgCSVtoHashTable
write-Host "Module = " $output["Module:"] -foreground Green -background Black
# If something goes wrong, stops execution and notifies user.
if($null -eq $output["Module:"])
{
throw "Couldn't retrieve Module!"
}
write-Host "Extracting Metadata start address..." -foreground Green -background Black
# Calls !dumpmodule using the module address.
Send-PowerDbgCommand("!DumpModule " + $output["Module:"])
# Now we need to get the base address...
# To do that we need a specific field from the previous command.
# The fields from SOS.DLL have differences between .NET Framework 2.0 and 1.1
Parse-PowerDbgDUMPMODULE
# Convert CSV file to Hash Table.
$output = @{}
$output = Convert-PowerDbgCSVtoHashTable
write-Host "Done!" -foreground Green -background Black
# We need to verify if the field is from SOS 2.0 or SOS 1.1
if($null -eq $output["MetaData starts at"])
{
write-Host "Metadata start address = " $output["MetaData start address:"] -foreground Green -background Black
}
else
{
write-Host "Metadata start address = " $output["MetaData starts at"] -foreground Green -background Black
}
# If something goes wrong, stops execution and notifies user.
if(($null -eq $output["MetaData starts at"]) -and ($null -eq $output["MetaData start address:"]) )
{
throw "Couldn't retrieve MetaData start address!"
}
# We need to verify if the field is from SOS 2.0 or SOS 1.1
if($null -eq $output["MetaData start address:"])
{
Send-PowerDbgCommand("!lmi " + $output["MetaData starts at"])
}
else
{
Send-PowerDbgCommand("!lmi " + $output["MetaData start address:"])
}
write-Host "Extracting base address..." -foreground Green -background Black
# Yet again we need the output from the previous command.
Parse-PowerDbgLMI
# Convert CSV file to Hash Table.
$output = @{}
$output = Convert-PowerDbgCSVtoHashTable
write-Host "Done!" -foreground Green -background Black
write-Host "Module to be saved = " $output["Image Name:"] -foreground Green -background Black
# If something goes wrong, stops execution and notifies user.
if($null -eq $output["Image Name:"])
{
throw "Couldn't retrieve Image Name!"
}
write-Host "Saving module " $output["Image Name:"] " into directory " $directory -foreground Green -background Black
# Finally we save the module now that we have the name of the module and its base address.
Send-PowerDbgCommand("!savemodule " + $output["Base Address:"] + " " + $directory + "\" + $output["Image Name:"])
$hasCommandSucceeded = Has-PowerDbgCommandSucceeded
if($false -eq $hasCommandSucceeded)
{
throw "Couldn't save module into the provided path!"
}
write-Host "Done!" -foreground Green -background Black
# Notifies user the script finished the execution.
Send-PowerDbgComment "PowerDbgScriptSaveModule was executed. See the PowerShell window for more information."