-
-
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.
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
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