Last active
August 25, 2024 04:30
-
-
Save ThioJoe/9b0b0b193783ebf4ceaf1c6c25d18c7a to your computer and use it in GitHub Desktop.
Takes an XML file that contains windows embedded DLL string references and outputs a new version with the resolved actual string values.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Windows XML String Resolver | |
# Author: ThioJoe | |
# | |
# Purpose: This script takes an XML file that contains string references (e.g., "@shell32.dll,-1234") | |
# and resolves them to their actual string values. It's particularly useful for working with | |
# Windows resource files or any XML that uses similar string reference formats. | |
# | |
# How to Use: | |
# 1. Open PowerShell and navigate to the path containing this script using the 'cd' command. | |
# 2. Run the following command to allow running scripts for the current session: | |
# Set-ExecutionPolicy -ExecutionPolicy unrestricted -Scope Process | |
# 3. Without closing the PowerShell window, run the script by typing the name of the script file starting with .\ for example: | |
# .\Windows_XML_String_Resolver.ps1 | |
# Usage With Arguments: You can either run the script and enter the XML file path when prompted, or specify the file/path as a parameter (can be relative or absolute) | |
# Example 1: .\Windows_XML_String_Resolver.ps1 "C:\path\to\file.xml" | |
# Example 2: .\Windows_XML_String_Resolver.ps1 WhateverName.xml | |
param( | |
[string]$XmlFilePath | |
) | |
# Import necessary .NET classes | |
Add-Type @" | |
using System; | |
using System.Runtime.InteropServices; | |
using System.Text; | |
public class Windows { | |
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] | |
public static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hFile, uint dwFlags); | |
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] | |
public static extern int LoadString(IntPtr hInstance, uint uID, StringBuilder lpBuffer, int nBufferMax); | |
[DllImport("kernel32.dll", SetLastError = true)] | |
[return: MarshalAs(UnmanagedType.Bool)] | |
public static extern bool FreeLibrary(IntPtr hModule); | |
} | |
"@ | |
function Get-LocalizedString { | |
param ( [string]$StringReference ) | |
if ($StringReference -match '@(.+),-(\d+)') { | |
$dllPath = [Environment]::ExpandEnvironmentVariables($Matches[1]) | |
$resourceId = [uint32]$Matches[2] | |
$hModule = [Windows]::LoadLibraryEx($dllPath, [IntPtr]::Zero, 0x00000800) # LOAD_LIBRARY_AS_DATAFILE | |
if ($hModule -eq [IntPtr]::Zero) { | |
$errorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() | |
Write-Warning "Failed to load library: $dllPath. Error code: $errorCode" | |
return $StringReference | |
} | |
$stringBuilder = New-Object System.Text.StringBuilder 1024 | |
$result = [Windows]::LoadString($hModule, $resourceId, $stringBuilder, $stringBuilder.Capacity) | |
[void][Windows]::FreeLibrary($hModule) | |
if ($result -ne 0) { | |
return $stringBuilder.ToString() | |
} else { | |
$errorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() | |
Write-Warning "Failed to load string resource: $resourceId from $dllPath. Error code: $errorCode" | |
return $StringReference | |
} | |
} else { | |
return $StringReference | |
} | |
} | |
function Resolve-XmlStringReferences { | |
param ( | |
[string]$XmlContent | |
) | |
$resolvedXml = $XmlContent | |
$stringRefPattern = '@[^,]+,-\d+' | |
$stringMatches = [regex]::Matches($XmlContent, $stringRefPattern) | |
foreach ($match in $stringMatches) { | |
$originalString = $match.Value | |
$resolvedString = Get-LocalizedString $originalString | |
if ($resolvedString -ne $originalString) { | |
$resolvedXml = $resolvedXml.Replace($originalString, [System.Security.SecurityElement]::Escape($resolvedString)) | |
} | |
} | |
return $resolvedXml | |
} | |
# Main script logic | |
if (-not $XmlFilePath) { | |
$XmlFilePath = Read-Host "Please enter the path to the XML file" | |
} | |
# Remove quotes if present | |
$XmlFilePath = $XmlFilePath.Trim('"') | |
if (-not (Test-Path $XmlFilePath)) { | |
Write-Error "The specified file does not exist: $XmlFilePath" | |
exit 1 | |
} | |
try { | |
$xmlContent = Get-Content $XmlFilePath -Raw | |
$resolvedXml = Resolve-XmlStringReferences $xmlContent | |
$outputPath = [System.IO.Path]::Combine( | |
[System.IO.Path]::GetDirectoryName($XmlFilePath), | |
[System.IO.Path]::GetFileNameWithoutExtension($XmlFilePath) + "-resolved.xml" | |
) | |
$resolvedXml | Out-File $outputPath -Encoding UTF8 | |
Write-Host "Resolved XML saved to: $outputPath" | |
} catch { | |
Write-Error "An error occurred: $_" | |
exit 1 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment