A few weeks ago, during a laboratory with a customer, I found myself struggling to download the public symbol from a specific driver. Since driver is Kernel Mode if you get a User Mode dump from the application using the driver, you won’t be able to actually see and download the driver. If you have a Kernel dump, you can get the module and download the symbols, but it’s more work.

 

There are other approaches and tools, but during this lab a colleague from PFE recommended symchk.exe, which is part of Debugging Tools for Windows. It turned out to be the best approach for my needs; however, chances are I’ll forget the syntax and my customer, too. To avoid this problem, I decided to create a small script that acts as a wrapper for symchk.  To use it you have to pass 4 required parameters:

 

<Folder that Has the Modules> - Folder that has the modules (dlls/exes)

 

<Module Name or Mask> - You can use something like *.dll or the module name, like tcpip.dll.

 

<Folder To Save the Symbols>- Name for the folder that is going to store the symbols.

 

<Folder Where Debugging Tools For Windows is Installed>- Directory where Debugging tools for Windows was installed.

 

Usage:

 

Let’s suppose my dlls are in c:\test\dlls, my debugger is in c:\debuggers, and I want to save the public symbols for all dlls (*.dll) in c:\test\symbols.

Here is the command line:

 

.\GetPDBForModules "c:\test\dlls" "*.dll" "c:\test\symbols" "c:\debuggers"

 

 

Before - just our binaries:

 

 

 

 

Execution:

 

 

 

After execution - binaries, symbols and manifest file:

 

 

Source code for GetPDBForModules.PS1:

  

 

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

# Script:       GetPDBforModules.ps1

#

# Parameters:   <dirModules>     - Folder that has the modules (dlls)

#               <moduleName>     - You can use something like *.dll or the module name.

#               <outputDirName>  - Name for the folder that is going to store the symbols.

#               <dirForDbgTools> - Directory where Debugging tools for Windows was installed.

#

# Purpose:      Access the Microsoft public symbols and download the symbols for each module.

#

# Requirement:  Debugging Tools For Windows.

#

# Usage:        .\GetPDBforModules "c:\modules" "ntdll.dll" "c:\symbols" "c:\debuggers"

 #              .\GetPDBforModules "c:\modules" "*.dll" "c:\symbols" "c:\debuggers"

#

# Changes History: 

#

# Roberto Alexis Farah

# All my functions are provided "AS IS" with no warranties, and confer no rights.

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

param(

      [string] $dirModules     = $(throw "Error! You must provide the path which has the modules like: c:\modules"),

      [string] $moduleName     = $(throw "Error! You must provide the file name like: ntdll.dll or *.dll or *.exe"),

      [string] $outputDirName  = $(throw "Error! You must provide the path which is going to store the symbols, like: c:\symbols"),

      [string] $dirForDbgTools = $(throw "Error! You must provide the path for Debugging Toos For Windows.")

     )

set-psdebug -strict

$ErrorActionPreference = "stop"

trap {"Error message: $_"}

 

$tempFile = "Manifest.txt" # We use $outputDirName plus .txt to create the manifest text file.

 

$dirForDbgTools += "\symchk"   # Add symchk.exe to path.

 

# In case we are adding one more \, let's remove the extra \.

$dirForDbgTools = $dirForDbgTools.Replace("\\", "\")

 

# Windows Shell to call the console application.

$instance = new-object -comobject WScript.Shell

 

write-Host "`nExtracting manifest file from module(s)...`n" -foreground Green -background Black

 

$temp = "$dirModules\$moduleName".Replace("\\", "\")

 

# Creates directory. If it already exists it's ok.

$hideOutput = md "$outputDirName"

 

# It should be something like: symchk /om C:\SymListManifest /if c:\WINDOWS\system32\*.dll

$argument = "$dirForDbgTools /om $outputDirName$tempFile /if $temp"

 

write-Host  $argument -foreground Red -background Black

 

$output = $instance.Run($argument, 3)

 

# The Run() method from WshShell doesn't wait for the callee to finish the execution, so let's wait for 10 seconds.

# On next version let's monitor if the console window had disappeared, so we don't have to use the forced delay.

start-Sleep 10

 

write-Host "`nDone!" -foreground Green -background Black

write-Host "`nDownloading symbols to $outputDirName folder..." -foreground Green -background Black

 

$argument = "$dirForDbgTools /im $outputDirName$tempFile /s SRV*$outputDirName*http://msdl.microsoft.com/download/symbols"

write-Host  $argument -foreground Red -background Black

 

$output = $instance.Run($argument, 3)

 

write-Host "`nDone! "  -foreground Green -background Black -nonewline

write-Host $outputDirName  -foreground Red -background Black -nonewline

write-Host " has all requested PDB files.`n"  -foreground Green -background Black