[PowerShell Script] Saving a Module from a .NET Method Call

This is my first script using the PowerDbg functions. It’s a good example of how to use PowerDbg to build your own scripts.

PowerDbgScriptSaveModule.ps1 is the PowerShell version of my Windbg script Save_Module.txt

Actually it does more than the previous version: it automatically saves the module that uses a specific method call. Then you just need to use .NET Reflector to decompile the code.

You can see this version is more powerful, easier to change, easier to improve, and easier to understand. Besides it has error handling!

When using PowerDbg scripts you can see the output from the PowerShell window; therefore, it’s easy to understand what the script is doing and the final result.

Remember, when using PowerDbg scripts, the WinDbg window has the row command processing and the PowerShell window has the output from the script. You should focus on the PowerShell window to get information that you may use in either reports or in e-mails to your customers. While other scripts may have copious amounts of information shown in the PowerShell window, this script doesn’t. It simply saves a module, so that’s why I chose it to be our first PowerDbg script.

Make sure to use the latest PowerDbg version.

 

The source code is actually indented. Copy and paste it to Word and save it as text file, then you can see the code using Notepad.

These are the screenshots:

 

 

.\PowerDbgScriptSaveModule "System.Threading.ExecutionContext.runTryCode" "c:\dumps"

 

 

 

 

 

 

 

This is the source code for PowerDbgScriptSaveModule.ps1:

 

 

########################################################################################################

# 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."

Comments

  • Anonymous
    September 10, 2007
    Hi Roberto, I have a general question on .Net and I thought you may have some ideas on how to solve this: Let say I have an app that I use try/catch to catch some system.exception such as division by zero. After catching this error, I could get the current stack frame from my app. Is there a way to dump the contents of all local vars (w/o var names) and params w/o using windbg (and SOS) and symbols. I tried to use reflection but seems there is not much I could do in reflection. If you could give me some ideas or link to some documents, I would appreciate that. Thanks

  • Anonymous
    September 10, 2007
    The comment has been removed

  • Anonymous
    September 10, 2007
    Attention! I just fixed two minor bugs:

  • The MetaData start address was not being displayed.
  • The !dumpmodule was replaced by !DumpModule because I had some problems with our internal SOS version. Please, make sure to use this updated version.
  • Anonymous
    September 11, 2007
    Hi Roberto, Thanks for the suggestopns. I did use stackframe to log as much info as possible, I think. But I would like to automatically dump at least params and some local vars (may be 1st nth ones)w/o having the catcher to do that. I am just wondering if there is a way to do dumping  if I have a stack frame and whether I can do follow those SOS commands ?? Thanks

  • Anonymous
    September 11, 2007
    The comment has been removed

  • Anonymous
    October 11, 2007
    You scripts are amazing! I´m waiting for the next PowerDbg script. Keep doing this great work! Joe

  • Anonymous
    December 24, 2007
    The comment has been removed

  • Anonymous
    February 03, 2009
    I’m very excited to present the new PowerDbg v5.0! There’s just one change, but it’s a HUGE change that

  • Anonymous
    March 19, 2009
    So, here we go again. This is a minor version with a few new cmdlets. These new cmdlets are those that

  • Anonymous
    April 29, 2009
    This version has two improvements and some scripts were changed to be compatible with this new version: