Skip to content

Instantly share code, notes, and snippets.

@antonioCoco
Created May 8, 2023 02:57
Show Gist options
  • Save antonioCoco/4cc6aff7bcbed2130f6a2eb387d7fe22 to your computer and use it in GitHub Desktop.
Save antonioCoco/4cc6aff7bcbed2130f6a2eb387d7fe22 to your computer and use it in GitHub Desktop.
Invoke-CoreImpactUnpacker allows you to automatically unpack Core Impact loaders observed in the wild.
function Invoke-CoreImpactUnpacker{
<#
.SYNOPSIS
Invoke-CoreImpactUnpacker - Automatically unpack Core Impact loaders
Author: Antonio Cocomazzi @ SentinelOne
License: MIT
.DESCRIPTION
Invoke-CoreImpactUnpacker allows you to automatically unpack Core Impact loaders observed in the wild.
.PARAMETER InputPath
The path of the Core Impact loader or a directory containing Core Impact loaders
.EXAMPLE
PS>Invoke-CoreImpactUnpacker 52e261a7cab837489dfcb8cd49aaf82ee287968c.pic
Description
-----------
Unpack a PIC Core Impact loader sample
#>
Param
(
[Parameter(Position = 0, Mandatory = $True)]
[String]
$InputPath
)
# We need this helper to use the "unchecked" keyword while simulating asm operations with overflows
function ImportUnpackerCsHelper{
$source = "
using System;
public static class UnpackerCsHelper
{
public static Int64 DecryptSuppressOverflows(Int64 encryptedData, Int64 key)
{
Int64 rax_r = encryptedData; // mov rax, [rbx+0]
Int64 r10_r = (Int64)key; // mov r10, 0D88D45A187845BCAh
Int64 r12_r = (Int64)r10_r; // mov r12, r10
unchecked{
r12_r = (Int64)r12_r & (Int64)rax_r; // and r12, rax
r12_r = (Int64)r12_r + (Int64)r12_r; // add r12, r12
rax_r = (Int64)rax_r + (Int64)r10_r; // add rax, r10
rax_r = (Int64)rax_r - (Int64)r12_r; // sub rax, r12
}
return (Int64)rax_r;
}
}
";
Add-Type -TypeDefinition $source -Language CSharp;
}
# Manage both cases if InputPath is a folder or a file
$files_to_unpack = @()
if(Test-Path -Path $InputPath -PathType Container){
Get-ChildItem -Path $InputPath -File -ErrorAction SilentlyContinue | ForEach-Object { $files_to_unpack += $_.FullName}
}
else{
$files_to_unpack += (Resolve-Path $InputPath).ToString()
}
ImportUnpackerCsHelper
foreach ($file_to_unpack in $files_to_unpack){
$unpack_success = $false
$file_bytes = [System.IO.File]::ReadAllBytes($file_to_unpack)
if(-not $unpack_success){
$pic_start_offset = 0
$packer_signature_matched = $false;
# doing a binary memory search on all file content bytes based on the known packer signatures
for ($pic_start_offset = 0; $pic_start_offset -le $file_bytes.Length; $pic_start_offset++)
{
# Checking packer signature 1 { E9 [4] 5B 48 B9 [8] 49 BA [70-100] E9 05 00 00 00 E8 }
if($file_bytes[$pic_start_offset] -eq 0xE9 -and $file_bytes[$pic_start_offset+5] -eq 0x5B -and $file_bytes[$pic_start_offset+6] -eq 0x48 -and $file_bytes[$pic_start_offset+7] -eq 0xB9 -and $file_bytes[$pic_start_offset+16] -eq 0x49 -and $file_bytes[$pic_start_offset+17] -eq 0xBA){
$jmp_target = ([BitConverter]::ToInt32($file_bytes[($pic_start_offset+1)..($pic_start_offset+4)],0))
$jmp_target_offset = $pic_start_offset + $jmp_target
if($file_bytes[$jmp_target_offset] -eq 0xE9 -and $file_bytes[$jmp_target_offset+1] -eq 0x05 -and $file_bytes[$jmp_target_offset+2] -eq 0x00 -and $file_bytes[$jmp_target_offset+3] -eq 0x00 -and $file_bytes[$jmp_target_offset+4] -eq 0x00 -and $file_bytes[$jmp_target_offset+5] -eq 0xE8){
Write-Output "[+] PIC has matched known packer signature 1 { E9 [4] 5B 48 B9 [8] 49 BA [70-100] E9 05 00 00 00 E8 } at offset 0x$($pic_start_offset.ToString('X')) ! Trying to unpack it..."
$packed_data_offset = $jmp_target_offset + 5 + 5
$packed_data_size = ([BitConverter]::ToInt64($file_bytes[($pic_start_offset+8)..($pic_start_offset+15)],0))
$key = $file_bytes[($pic_start_offset+18)..($pic_start_offset+25)]
$packer_signature_matched = $true
}
}
# Checking packer signature 2 { E9 [4] 5B 53 48 BB [12] 49 BB [50-60] E9 05 00 00 00 E8}
if($file_bytes[$pic_start_offset] -eq 0xE9 -and $file_bytes[$pic_start_offset+5] -eq 0x5B -and $file_bytes[$pic_start_offset+6] -eq 0x53 -and $file_bytes[$pic_start_offset+7] -eq 0x48 -and $file_bytes[$pic_start_offset+8] -eq 0xBB -and $file_bytes[$pic_start_offset+21] -eq 0x49 -and $file_bytes[$pic_start_offset+22] -eq 0xBB){
$jmp_target = ([BitConverter]::ToInt32($file_bytes[($pic_start_offset+1)..($pic_start_offset+4)],0))
$jmp_target_offset = $pic_start_offset + $jmp_target
if($file_bytes[$jmp_target_offset] -eq 0xE9 -and $file_bytes[$jmp_target_offset+1] -eq 0x05 -and $file_bytes[$jmp_target_offset+2] -eq 0x00 -and $file_bytes[$jmp_target_offset+3] -eq 0x00 -and $file_bytes[$jmp_target_offset+4] -eq 0x00 -and $file_bytes[$jmp_target_offset+5] -eq 0xE8){
Write-Output "[+] PIC has matched known packer signature 2 { E9 [4] 5B 53 48 BB [12] 49 BB [50-60] E9 05 00 00 00 E8} at offset 0x$($pic_start_offset.ToString('X')) ! Trying to unpack it..."
$packed_data_offset = $jmp_target_offset + 5 + 5
$packed_data_size = ([BitConverter]::ToInt64($file_bytes[($pic_start_offset+9)..($pic_start_offset+16)],0))
$key = $file_bytes[($pic_start_offset+23)..($pic_start_offset+30)]
$packer_signature_matched = $true
}
}
# Checking packer signature 3 { E9 [4] 5B 48 B9 [10] 49 BC [70-100] E9 05 00 00 00 E8 }
if($file_bytes[$pic_start_offset] -eq 0xE9 -and $file_bytes[$pic_start_offset+5] -eq 0x5B -and $file_bytes[$pic_start_offset+6] -eq 0x48 -and $file_bytes[$pic_start_offset+7] -eq 0xB9 -and $file_bytes[$pic_start_offset+16] -eq 0x41 -and $file_bytes[$pic_start_offset+17] -eq 0x54 -and $file_bytes[$pic_start_offset+18] -eq 0x49 -and $file_bytes[$pic_start_offset+19] -eq 0xBC){
$jmp_target = ([BitConverter]::ToInt32($file_bytes[($pic_start_offset+1)..($pic_start_offset+4)],0))
$jmp_target_offset = $pic_start_offset + $jmp_target
if($file_bytes[$jmp_target_offset] -eq 0xE9 -and $file_bytes[$jmp_target_offset+1] -eq 0x05 -and $file_bytes[$jmp_target_offset+2] -eq 0x00 -and $file_bytes[$jmp_target_offset+3] -eq 0x00 -and $file_bytes[$jmp_target_offset+4] -eq 0x00 -and $file_bytes[$jmp_target_offset+5] -eq 0xE8){
Write-Output "[+] PIC has matched known packer signature 3 { E9 [4] 5B 48 B9 [10] 49 BC [70-100] E9 05 00 00 00 E8 } at offset 0x$($pic_start_offset.ToString('X')) ! Trying to unpack it..."
$packed_data_offset = $jmp_target_offset + 5 + 5
$packed_data_size = ([BitConverter]::ToInt64($file_bytes[($pic_start_offset+8)..($pic_start_offset+15)],0))
$key = $file_bytes[($pic_start_offset+20)..($pic_start_offset+27)]
$packer_signature_matched = $true
}
}
# Checking packer signature 4 { E9 [4] 5B ?? ?? 49 BB [14] 48 B8 [70-100] E9 05 00 00 00 E8 }
if($file_bytes[$pic_start_offset] -eq 0xE9 -and $file_bytes[$pic_start_offset+5] -eq 0x5B -and $file_bytes[$pic_start_offset+8] -eq 0x49 -and $file_bytes[$pic_start_offset+9] -eq 0xBB -and $file_bytes[$pic_start_offset+24] -eq 0x48 -and $file_bytes[$pic_start_offset+25] -eq 0xB8){
$jmp_target = ([BitConverter]::ToInt32($file_bytes[($pic_start_offset+1)..($pic_start_offset+4)],0))
$jmp_target_offset = $pic_start_offset + $jmp_target
if($file_bytes[$jmp_target_offset] -eq 0xE9 -and $file_bytes[$jmp_target_offset+1] -eq 0x05 -and $file_bytes[$jmp_target_offset+2] -eq 0x00 -and $file_bytes[$jmp_target_offset+3] -eq 0x00 -and $file_bytes[$jmp_target_offset+4] -eq 0x00 -and $file_bytes[$jmp_target_offset+5] -eq 0xE8){
Write-Output "[+] PIC has matched known packer signature 4 { E9 [4] 5B ?? ?? 49 BB 30 [13] 48 B8 [70-100] E9 05 00 00 00 E8 } at offset 0x$($pic_start_offset.ToString('X')) ! Trying to unpack it..."
$packed_data_offset = $jmp_target_offset + 5 + 5
$packed_data_size = ([BitConverter]::ToInt64($file_bytes[($pic_start_offset+10)..($pic_start_offset+17)],0))
$key = $file_bytes[($pic_start_offset+26)..($pic_start_offset+33)]
$packer_signature_matched = $true
}
}
# Checking packer signature 5 { E9 [4] 5B ?? 48 B8 [13] 48 B9 [50-60] E9 05 00 00 00 E8}
if($file_bytes[$pic_start_offset] -eq 0xE9 -and $file_bytes[$pic_start_offset+5] -eq 0x5B -and $file_bytes[$pic_start_offset+7] -eq 0x48 -and $file_bytes[$pic_start_offset+8] -eq 0xB8 -and $file_bytes[$pic_start_offset+22] -eq 0x48 -and $file_bytes[$pic_start_offset+23] -eq 0xB9){
$jmp_target = ([BitConverter]::ToInt32($file_bytes[($pic_start_offset+1)..($pic_start_offset+4)],0))
$jmp_target_offset = $pic_start_offset + $jmp_target
if($file_bytes[$jmp_target_offset] -eq 0xE9 -and $file_bytes[$jmp_target_offset+1] -eq 0x05 -and $file_bytes[$jmp_target_offset+2] -eq 0x00 -and $file_bytes[$jmp_target_offset+3] -eq 0x00 -and $file_bytes[$jmp_target_offset+4] -eq 0x00 -and $file_bytes[$jmp_target_offset+5] -eq 0xE8){
Write-Output "[+] PIC has matched known packer signature 5 { E9 [4] 5B ?? 48 B8 [13] 48 B9 [50-60] E9 05 00 00 00 E8} at offset 0x$($pic_start_offset.ToString('X')) ! Trying to unpack it..."
$packed_data_offset = $jmp_target_offset + 5 + 5
$packed_data_size = ([BitConverter]::ToInt64($file_bytes[($pic_start_offset+9)..($pic_start_offset+16)],0))
$key = $file_bytes[($pic_start_offset+24)..($pic_start_offset+31)]
$packer_signature_matched = $true
}
}
# Checking packer signature 6 { E9 [4] 5B ?? 48 B8 [12] 49 BD [70-100] E9 05 00 00 00 E8}
if($file_bytes[$pic_start_offset] -eq 0xE9 -and $file_bytes[$pic_start_offset+5] -eq 0x5B -and $file_bytes[$pic_start_offset+7] -eq 0x48 -and $file_bytes[$pic_start_offset+8] -eq 0xB8 -and $file_bytes[$pic_start_offset+21] -eq 0x49 -and $file_bytes[$pic_start_offset+22] -eq 0xBD){
$jmp_target = ([BitConverter]::ToInt32($file_bytes[($pic_start_offset+1)..($pic_start_offset+4)],0))
$jmp_target_offset = $pic_start_offset + $jmp_target
if($file_bytes[$jmp_target_offset] -eq 0xE9 -and $file_bytes[$jmp_target_offset+1] -eq 0x05 -and $file_bytes[$jmp_target_offset+2] -eq 0x00 -and $file_bytes[$jmp_target_offset+3] -eq 0x00 -and $file_bytes[$jmp_target_offset+4] -eq 0x00 -and $file_bytes[$jmp_target_offset+5] -eq 0xE8){
Write-Output "[+] PIC has matched known packer signature 6 { E9 [4] 5B ?? 48 B8 [12] 49 BD [70-100] E9 05 00 00 00 E8} at offset 0x$($pic_start_offset.ToString('X')) ! Trying to unpack it..."
$packed_data_offset = $jmp_target_offset + 5 + 5
$packed_data_size = ([BitConverter]::ToInt64($file_bytes[($pic_start_offset+9)..($pic_start_offset+16)],0))
$key = $file_bytes[($pic_start_offset+23)..($pic_start_offset+30)]
$packer_signature_matched = $true
}
}
# Checking packer signature 7 { E9 [4] 5B 48 B9 [9] 48 BA [70-100] E9 05 00 00 00 E8}
if($file_bytes[$pic_start_offset] -eq 0xE9 -and $file_bytes[$pic_start_offset+5] -eq 0x5B -and $file_bytes[$pic_start_offset+6] -eq 0x48 -and $file_bytes[$pic_start_offset+7] -eq 0xB9 -and $file_bytes[$pic_start_offset+17] -eq 0x48 -and $file_bytes[$pic_start_offset+18] -eq 0xBA){
$jmp_target = ([BitConverter]::ToInt32($file_bytes[($pic_start_offset+1)..($pic_start_offset+4)],0))
$jmp_target_offset = $pic_start_offset + $jmp_target
if($file_bytes[$jmp_target_offset] -eq 0xE9 -and $file_bytes[$jmp_target_offset+1] -eq 0x05 -and $file_bytes[$jmp_target_offset+2] -eq 0x00 -and $file_bytes[$jmp_target_offset+3] -eq 0x00 -and $file_bytes[$jmp_target_offset+4] -eq 0x00 -and $file_bytes[$jmp_target_offset+5] -eq 0xE8){
Write-Output "[+] PIC has matched known packer signature 7 { E9 [4] 5B 48 B9 [9] 48 BA [70-100] E9 05 00 00 00 E8} at offset 0x$($pic_start_offset.ToString('X')) ! Trying to unpack it..."
$packed_data_offset = $jmp_target_offset + 5 + 5
$packed_data_size = ([BitConverter]::ToInt64($file_bytes[($pic_start_offset+8)..($pic_start_offset+15)],0))
$key = $file_bytes[($pic_start_offset+19)..($pic_start_offset+26)]
$packer_signature_matched = $true
}
}
if($packer_signature_matched){
$key = ([BitConverter]::ToInt64($key, 0))
$final_unpacked_pic = New-Object Byte[]($packed_data_size)
$final_unpacked_pic_index = 0
for ($offset=$packed_data_offset; $offset -lt ($packed_data_offset+$packed_data_size); $offset=$offset+8)
{
$encrypted_data = ([BitConverter]::ToInt64($file_bytes[($offset)..($offset+7)],0))
$decrypted_bytes_int64 = [UnpackerCsHelper]::DecryptSuppressOverflows($encrypted_data, $key);
$decrypted_bytes = [BitConverter]::GetBytes($decrypted_bytes_int64)
[System.Buffer]::BlockCopy($decrypted_bytes, 0, $final_unpacked_pic, $final_unpacked_pic_index, 8)
$final_unpacked_pic_index = $final_unpacked_pic_index + 8
}
if($final_unpacked_pic_index -eq $packed_data_size){
$output_path = $file_to_unpack + '.unpacked'
Set-Content $output_path -Value $final_unpacked_pic -Encoding Byte
Write-Output "[+] PIC unpacked! Dumped to file $output_path"
$unpack_success = $true
}
break
}
}
}
if(-not $unpack_success)
{
Write-Output "[!] File '$file_to_unpack' does not match the Core Impact loader signatures."
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment