PowerShell Script To Remove Office Macro Protection

In some cases in my app compat battles I’ve had to debug macros developed by those who have long since disappeared from a company. However the source is inaccessible due to Macro protection. While commercial 3rd party tools to remove such passwords have existed for a long time, I have had a habit of doing so via a Hex Editor. Apparently not everyone is in love with hex editors so here is a *rough* scripted version. Note: It is possible to completely remove the password programmatically, but it is a lot more complex. One day if I had the time to waste I might do so…until then here is the quick & dirty method. This uses a simple method that has been popular for a long time which is to replace the DPB= value in the office file with DPx=

Note: This method only removes passwords on Macros, not other types of office document passwords and does not work on .Docx/.Xlsx formats

We are also utilizing pointers in our PowerShell code. Can BASH do that? Smile

First thing is this rough PowerShell script which is utilized in the following way:

Unlock-OfficeDocumentMacro -InputFile “c:\Support\Locked.xls” “c:\Support\Unlocked.xls”

Function to unlock office 2000-2003 document by @chentiangemalc

# Function to unlock office 2000-2003 document by @chentiangemalc
# Proof-of-Concept Code lacking performance optimization & error handling
# This should not be considered example of how to write PowerShell code.

# Binary "IndexOf"
# too lazy (or busy…) to write this code in PowerShell, couldn’t find any good PowerShell example
# And this is fast. From http://stackoverflow.com/users/649008/foubar
# at http://stackoverflow.com/questions/283456/byte-array-pattern-search
$compilerParameters = New-Object System.CodeDom.Compiler.CompilerParameters
$compilerParameters.CompilerOptions="/unsafe"

Add-Type -PassThru -CompilerParameters $compilerParameters -TypeDefinition @"
using System;
using System.Collections.Generic;

public static class FastByte
{

public static unsafe long IndexOf(byte[] Haystack, byte[] Needle)
{
fixed (byte* H = Haystack) fixed (byte* N = Needle)
{
long i = 0;
for (byte* hNext = H, hEnd = H + Haystack.LongLength; hNext < hEnd; i++, hNext++)
{
bool Found = true;
for (byte* hInc = hNext, nInc = N, nEnd = N + Needle.LongLength; Found && nInc < nEnd; Found = *nInc == *hInc, nInc++, hInc++);
if (Found) return i;
}
return -1;
}
}
}
"@

Function Unlock-OfficeDocumentMacro
{
# To-do -
# * Check for valid office file formats. Currently works for Word/Acess/Excel 2000-2003 format
Param
(
[ValidateScript({Test-Path $_ -PathType Leaf})]
[String]
$InputFile
,
[String]
$OutputFile
)
Process
{
# We’ll work on the copy—just in case we mess up the original
Copy-Item $InputFile $OutputFile

# Load our target file all at once
# Not scalable … &c but works to test the concept
Write-Host "Loading $OutputFile"
$data=Get-Content -Encoding Byte $OutputFile

Write-Host "Searching file contents"
# The searchString is hex equivelant for string DPB=
[Byte[]] $searchBytes = 0×44,0×50,0×42,0x3D,0×22
[Byte[]] $replaceBytes = 0×44,0×50,0×78,0x3D,0×22

$index=[FastByte]::IndexOf($data,$searchBytes)

Write-Host "Found at $index"

# update file
# so many chances for failures here…add error checking!
[System.IO.Stream]$stream = [System.IO.File]::Open($OutputFile,[System.IO.FileMode]::Open)
$stream.Position=$index
$stream.Write($replaceBytes,0,$replaceBytes.Length)
$stream.Dispose()

Write-Host "Update Complete! Output file: $OutputFile"

}
}

Unlock-OfficeDocumentMacro -InputFile "c:\Support\Locked.xls" "c:\Support\Unlocked.xls"

Once the unlocked file has been output there remains some manual steps.

1. On launching unprotected file office will throw warning. Just click Yes

image

2. Then open Visual Basic Editor. You will probably see another error like below:

image

3. Right click the VBAProject and select VBAPRoject Properties

image

4. On the Protection tab set your own password and click OK

image

5. Once this is done you can go back into properties and remove Lock project for viewing

About chentiangemalc

specializes in end-user computing technologies. disclaimer 1) use at your own risk. test any solution in your environment. if you do not understand the impact/consequences of what you're doing please stop, and ask advice from somebody who does. 2) views are my own at the time of posting and do not necessarily represent my current view or the view of my employer and family members/relatives. 3) over the years Microsoft/Citrix/VMWare have given me a few free shirts, pens, paper notebooks/etc. despite these gifts i will try to remain unbiased.
This entry was posted in Office, PowerShell and tagged . Bookmark the permalink.

One Response to PowerShell Script To Remove Office Macro Protection

  1. Karpu says:

    code giving an error at
    [Byte[]] $searchBytes = 0×44,0×50,0×42,0x3D,0×22
    [Byte[]] $replaceBytes = 0×44,0×50,0×78,0x3D,0×22
    Missing argument in perameter list.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s