Created
November 20, 2023 17:06
-
-
Save Dump-GUY/5e3f053a252307ba133a4e5b6cfeacb0 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
# Get IL code and pre-compiled native code disassembly of R2R Assembly methods | |
# Using AsmResolver + Iced + PowerShell | |
# More Info Here: https://docs.washi.dev/asmresolver/guides/peimage/ready-to-run.html | |
# Loading dependecies | |
[System.Reflection.Assembly]::LoadFrom([System.IO.Path]::GetFullPath(".\libs\AsmResolver\net6.0\AsmResolver.PE.dll")) | Out-Null | |
[System.Reflection.Assembly]::LoadFrom([System.IO.Path]::GetFullPath(".\libs\AsmResolver\net6.0\AsmResolver.DotNet.dll")) | Out-Null | |
[System.Reflection.Assembly]::LoadFrom([System.IO.Path]::GetFullPath(".\libs\Iced\netstandard2.1\Iced.dll")) | Out-Null | |
$filePath = [System.IO.Path]::GetFullPath(".\test_files\CompileDecoy_ReplaceReal_SC_Original.dll") # R2R Assembly Sample | |
$moduleDef = [AsmResolver.DotNet.ModuleDefinition]::FromFile($filePath) | |
$peImage = [AsmResolver.PE.PEImage]::FromFile($filePath) | |
# Check if it is a R2R Assembly | |
if ($peImage.DotNetDirectory.ManagedNativeHeader -isnot [AsmResolver.PE.DotNet.ReadyToRun.ReadyToRunDirectory]) | |
{ | |
Write-Host "Not R2R Assembly!!!" -ForegroundColor Red | |
return | |
} | |
# Getting RuntimeFunctions section - contains info about pre-compiled functions | |
$R2RDirectory = $peImage.DotNetDirectory.ManagedNativeHeader | |
$RFSection = $null | |
if (!$R2RDirectory.TryGetSection([AsmResolver.PE.DotNet.ReadyToRun.ReadyToRunSectionType]::RuntimeFunctions, [ref] $RFSection)) | |
{ | |
Write-Host "R2R Assembly does not have a RuntimeFunctions section!!!" -ForegroundColor Red | |
return | |
} | |
# Getting MethodDefEntryPoints section - to later find out what pre-compiled code corresponds to what method | |
$MEPSection = $null | |
if (!$R2RDirectory.TryGetSection([AsmResolver.PE.DotNet.ReadyToRun.ReadyToRunSectionType]::MethodDefEntryPoints, [ref] $MEPSection)) | |
{ | |
Write-Host "R2R Assembly does not have a MethodDefEntryPoints section!!!" -ForegroundColor Red | |
return | |
} | |
# Loop all EntryPoints in MethodDefEntryPoints section - in order | |
for ($i = 0; $i -lt $MEPSection.EntryPoints.Count; $i++) | |
{ | |
# Create Token that should correspond to EntryPoint function - because of ordering | |
$token = [AsmResolver.PE.DotNet.Metadata.Tables.MetadataToken]::new([AsmResolver.PE.DotNet.Metadata.Tables.TableIndex]::Method, ($i + 1)) | |
$entrypoint = $MEPSection.EntryPoints[$i] | |
if ($null -eq $entrypoint) | |
{ | |
Write-Host "Method Token:$token is not mapped to a runtime function!!!" -ForegroundColor Red | |
continue | |
} | |
# Find the method in module definition using the calculated Token | |
$method = $null | |
if (!$moduleDef.TryLookupMember($token, [ref] $method)) | |
{ | |
Write-Host "Method with Token:$token is not found in Module!!!" -ForegroundColor Red | |
continue | |
} | |
# Check if CIL Body of the method not empty | |
if ($null -eq $method.CilMethodBody) | |
{ | |
Write-Host "Method Name:'$($method.Name.ToString())' with Token:$token has no IL body!!!" -ForegroundColor Red | |
continue | |
} | |
# Print Method Name, Token, IL code - Instructions | |
Write-Host "`nMethod Name:'$($method.Name.ToString())' Token:$token" -ForegroundColor Green | |
Write-Host "IL Body:" -ForegroundColor Green | |
$formatter = [AsmResolver.PE.DotNet.Cil.CilInstructionFormatter]::new() | |
foreach ($inst in $method.CilMethodBody.Instructions) | |
{ | |
Write-Host ($formatter.FormatInstruction($inst)) -ForegroundColor Yellow | |
} | |
# Get the opcode bytes of the pre-compiled native code of the method | |
Write-Host "Native Pre-Compiled Body - Disassembly:" -ForegroundColor Green | |
$runtimeFunction = $RFSection.Functions[$entrypoint.RuntimeFunctionIndex] | |
if (!$runtimeFunction.Begin.CanRead) | |
{ | |
Write-Host "Can NOT Read Native Opcode bytes of Method Name:'$($method.Name.ToString())' with Token:$token!!!" -ForegroundColor Red | |
continue | |
} | |
$length = $runtimeFunction.End.Rva - $runtimeFunction.Begin.Rva | |
[byte[]]$buffer = [byte[]]::new($length) | |
$runtimeFunction.Begin.CreateReader().ReadBytes($buffer, 0, $length) | Out-Null | |
# Setup for the disassembler and disassembly formatter - using Iced for opcode bytes disassembling | |
if ($peImage.MachineType -eq [AsmResolver.PE.File.Headers.MachineType]::Amd64) | |
{ | |
$codeBitness = 64 | |
} | |
else {$codeBitness = 32} | |
$HEXBYTES_COLUMN_BYTE_LENGTH = 10 | |
$codeRIP = $runtimeFunction.Begin.Rva | |
$codeBytes = $buffer | |
$codeReader = [Iced.Intel.ByteArrayCodeReader]::new($codeBytes) | |
$decoder = [Iced.Intel.Decoder]::Create($codeBitness, $codeReader) | |
$decoder.IP = $codeRIP | |
$endRip = $decoder.IP + $codeBytes.Length | |
# Disassembly instructions | |
$instructions = New-Object Collections.Generic.List[Iced.Intel.Instruction] | |
while ($decoder.IP -lt $endRip) | |
{ | |
$instructions.Add($decoder.Decode()) | |
} | |
# Format and print the disassembly of the pre-compiled native code of the method | |
$formatter = [Iced.Intel.NasmFormatter]::new() | |
$formatter.Options.DigitSeparator = '`' | |
$formatter.Options.FirstOperandCharIndex = 10 | |
$output = [Iced.Intel.StringOutput]::new() | |
foreach ($instr in $instructions) | |
{ | |
$formatter.Format([ref] $instr, $output) | |
Write-Host ($instr.IP.ToString("X16")) -NoNewline -ForegroundColor Blue | |
Write-Host " " -NoNewline -ForegroundColor Blue | |
$instrLen = $instr.Length | |
$byteBaseIndex = [int]($instr.IP - $codeRIP) | |
for ($j = 0; $j -lt $instrLen; $j++) | |
{ | |
Write-Host ($codeBytes[$byteBaseIndex + $j].ToString("X2")) -NoNewline -ForegroundColor Blue | |
} | |
$missingBytes = $HEXBYTES_COLUMN_BYTE_LENGTH - $instrLen | |
for ($k = 0; $k -lt $missingBytes; $k++) | |
{ | |
Write-Host " " -NoNewline -ForegroundColor Blue | |
} | |
Write-Host " " -NoNewline -ForegroundColor Blue | |
Write-Host ($output.ToStringAndReset()) -ForegroundColor Blue | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment