chore: simplify project to engine docs and tests
Remove planning and acceptance scaffolding while retaining the native Vulkan mission preview, format readers, runtime algorithms, and ordinary Rust tests. Keep the book aligned with the runnable project and validate checked-in shaders without generated tool metadata.
This commit is contained in:
@@ -1,111 +0,0 @@
|
||||
[CmdletBinding()]
|
||||
param([Parameter(Mandatory = $true)][int]$ProcessId)
|
||||
|
||||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
# Read-only observer for ai.dll's `GetSuperAI` singleton array. It never sends
|
||||
# input, writes memory, suspends, injects, or calls into the original process.
|
||||
Add-Type -TypeDefinition @'
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
public static class FparkanAiInitCapture {
|
||||
public const uint TH32CS_SNAPMODULE = 0x00000008;
|
||||
public const uint TH32CS_SNAPMODULE32 = 0x00000010;
|
||||
public const uint PROCESS_QUERY_INFORMATION = 0x00000400;
|
||||
public const uint PROCESS_VM_READ = 0x00000010;
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||
public struct MODULEENTRY32 {
|
||||
public uint dwSize, th32ModuleID, th32ProcessID, GlblcntUsage, ProccntUsage;
|
||||
public IntPtr modBaseAddr;
|
||||
public uint modBaseSize;
|
||||
public IntPtr hModule;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] public string szModule;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string szExePath;
|
||||
}
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern IntPtr CreateToolhelp32Snapshot(uint flags, uint processId);
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
public static extern bool Module32First(IntPtr snapshot, ref MODULEENTRY32 entry);
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
public static extern bool Module32Next(IntPtr snapshot, ref MODULEENTRY32 entry);
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern IntPtr OpenProcess(uint access, bool inheritHandle, uint processId);
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern bool ReadProcessMemory(IntPtr process, IntPtr address,
|
||||
[Out] byte[] buffer, IntPtr size, out IntPtr bytesRead);
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern bool CloseHandle(IntPtr handle);
|
||||
}
|
||||
'@
|
||||
|
||||
function Read-Bytes([IntPtr]$Process, [Int64]$Address, [int]$Length) {
|
||||
$bytes = [byte[]]::new($Length); $read = [IntPtr]::Zero
|
||||
if (-not [FparkanAiInitCapture]::ReadProcessMemory($Process, [IntPtr]$Address,
|
||||
$bytes, [IntPtr]$Length, [ref]$read) -or $read.ToInt64() -ne $Length) {
|
||||
throw "ReadProcessMemory failed at 0x$('{0:X8}' -f $Address)"
|
||||
}
|
||||
$bytes
|
||||
}
|
||||
|
||||
$snapshot = [FparkanAiInitCapture]::CreateToolhelp32Snapshot(
|
||||
[FparkanAiInitCapture]::TH32CS_SNAPMODULE -bor [FparkanAiInitCapture]::TH32CS_SNAPMODULE32,
|
||||
[uint32]$ProcessId)
|
||||
$aiBase = $null
|
||||
$modules = @()
|
||||
try {
|
||||
$entry = [FparkanAiInitCapture+MODULEENTRY32]::new()
|
||||
$entry.dwSize = [Runtime.InteropServices.Marshal]::SizeOf([type][FparkanAiInitCapture+MODULEENTRY32])
|
||||
if ([FparkanAiInitCapture]::Module32First($snapshot, [ref]$entry)) {
|
||||
do {
|
||||
$modules += [ordered]@{
|
||||
name = $entry.szModule
|
||||
base = $entry.modBaseAddr.ToInt64()
|
||||
size = [int64]$entry.modBaseSize
|
||||
}
|
||||
if ($entry.szModule -ieq 'ai.dll') { $aiBase = $entry.modBaseAddr.ToInt64() }
|
||||
$entry = [FparkanAiInitCapture+MODULEENTRY32]::new()
|
||||
$entry.dwSize = [Runtime.InteropServices.Marshal]::SizeOf([type][FparkanAiInitCapture+MODULEENTRY32])
|
||||
} while ([FparkanAiInitCapture]::Module32Next($snapshot, [ref]$entry))
|
||||
}
|
||||
} finally { [void][FparkanAiInitCapture]::CloseHandle($snapshot) }
|
||||
if ($null -eq $aiBase) { throw "ai.dll is not loaded by process $ProcessId" }
|
||||
|
||||
$process = [FparkanAiInitCapture]::OpenProcess(
|
||||
[FparkanAiInitCapture]::PROCESS_QUERY_INFORMATION -bor [FparkanAiInitCapture]::PROCESS_VM_READ,
|
||||
$false, [uint32]$ProcessId)
|
||||
if ($process -eq [IntPtr]::Zero) { throw "OpenProcess read-only failed" }
|
||||
try {
|
||||
# CreateSuperAI stores its tenth host-callback argument at DAT_100555e4.
|
||||
$callbackBytes = Read-Bytes $process ($aiBase + 0x555e4) 4
|
||||
$callback = [BitConverter]::ToUInt32($callbackBytes, 0)
|
||||
$callbackModule = $modules | Where-Object {
|
||||
$callback -ge $_.base -and [int64]$callback -lt ($_.base + $_.size)
|
||||
} | Select-Object -First 1
|
||||
# GetSuperAI(i) returns (&DAT_10055398)[i], with ai.dll preferred base 0x10000000.
|
||||
$entries = Read-Bytes $process ($aiBase + 0x55398) (64 * 4)
|
||||
$samples = for ($index = 0; $index -lt 64; $index++) {
|
||||
$pointer = [BitConverter]::ToUInt32($entries, $index * 4)
|
||||
if ($pointer -le 0x10000) { continue }
|
||||
try {
|
||||
$fields = Read-Bytes $process ([int64]$pointer) 0x88
|
||||
[ordered]@{
|
||||
index = $index
|
||||
super_ai = ('0x{0:X8}' -f $pointer)
|
||||
word_7c = [BitConverter]::ToUInt32($fields, 0x7c)
|
||||
float_80 = [BitConverter]::ToSingle($fields, 0x80)
|
||||
float_84 = [BitConverter]::ToSingle($fields, 0x84)
|
||||
}
|
||||
} catch { }
|
||||
}
|
||||
[ordered]@{
|
||||
schema = 'fparkan-ai-init-v1'
|
||||
process_id = $ProcessId
|
||||
ai_module_base = ('0x{0:X8}' -f $aiBase)
|
||||
handler30_callback = ('0x{0:X8}' -f $callback)
|
||||
handler30_callback_module = if ($null -eq $callbackModule) { $null } else { $callbackModule.name }
|
||||
handler30_callback_rva = if ($null -eq $callbackModule) { $null } else { ('0x{0:X}' -f ([int64]$callback - $callbackModule.base)) }
|
||||
entries = @($samples)
|
||||
} |
|
||||
ConvertTo-Json -Depth 4 -Compress
|
||||
} finally { [void][FparkanAiInitCapture]::CloseHandle($process) }
|
||||
@@ -1,213 +0,0 @@
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[int]$ProcessId,
|
||||
[ValidateRange(1, 16384)]
|
||||
[int]$ViewportWidth = 1024,
|
||||
[ValidateRange(1, 16384)]
|
||||
[int]$ViewportHeight = 768,
|
||||
[ValidateRange(0.001, 1000.0)]
|
||||
[double]$NearPlane = 0.5,
|
||||
[ValidateRange(0.01, 100000.0)]
|
||||
[double]$FarPlane = 700.0,
|
||||
[ValidateRange(0.01, 3.13)]
|
||||
[double]$FieldOfViewRadians = 1.3,
|
||||
[ValidateRange(1, 600)]
|
||||
[int]$CaptureAttempts = 60,
|
||||
[ValidateRange(0, 1000000.0)]
|
||||
[double]$MinimumWorldTranslation = 100.0,
|
||||
[ValidateRange(0, 1000)]
|
||||
[int]$RetryIntervalMilliseconds = 100
|
||||
)
|
||||
|
||||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
# This observer deliberately opens only PROCESS_QUERY_INFORMATION | PROCESS_VM_READ.
|
||||
# It neither sends input nor writes, suspends, injects into, or calls the original game.
|
||||
Add-Type -TypeDefinition @'
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
public static class FparkanOriginalCamera {
|
||||
public const uint TH32CS_SNAPMODULE = 0x00000008;
|
||||
public const uint TH32CS_SNAPMODULE32 = 0x00000010;
|
||||
public const uint PROCESS_QUERY_INFORMATION = 0x00000400;
|
||||
public const uint PROCESS_VM_READ = 0x00000010;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||
public struct MODULEENTRY32 {
|
||||
public uint dwSize;
|
||||
public uint th32ModuleID;
|
||||
public uint th32ProcessID;
|
||||
public uint GlblcntUsage;
|
||||
public uint ProccntUsage;
|
||||
public IntPtr modBaseAddr;
|
||||
public uint modBaseSize;
|
||||
public IntPtr hModule;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] public string szModule;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string szExePath;
|
||||
}
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern IntPtr CreateToolhelp32Snapshot(uint flags, uint processId);
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
public static extern bool Module32First(IntPtr snapshot, ref MODULEENTRY32 entry);
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
public static extern bool Module32Next(IntPtr snapshot, ref MODULEENTRY32 entry);
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern IntPtr OpenProcess(uint access, bool inheritHandle, uint processId);
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern bool ReadProcessMemory(
|
||||
IntPtr process,
|
||||
IntPtr address,
|
||||
[Out] byte[] buffer,
|
||||
IntPtr size,
|
||||
out IntPtr bytesRead);
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern bool CloseHandle(IntPtr handle);
|
||||
}
|
||||
'@
|
||||
|
||||
function Get-LastWin32ErrorText {
|
||||
$code = [Runtime.InteropServices.Marshal]::GetLastWin32Error()
|
||||
"$code ($([ComponentModel.Win32Exception]::new($code).Message))"
|
||||
}
|
||||
|
||||
function Read-OriginalBytes {
|
||||
param(
|
||||
[IntPtr]$Process,
|
||||
[Int64]$Address,
|
||||
[int]$Length
|
||||
)
|
||||
$buffer = [byte[]]::new($Length)
|
||||
$read = [IntPtr]::Zero
|
||||
if (-not [FparkanOriginalCamera]::ReadProcessMemory(
|
||||
$Process,
|
||||
[IntPtr]$Address,
|
||||
$buffer,
|
||||
[IntPtr]$Length,
|
||||
[ref]$read)) {
|
||||
throw "ReadProcessMemory at 0x$('{0:X8}' -f $Address) failed: $(Get-LastWin32ErrorText)"
|
||||
}
|
||||
if ($read.ToInt64() -ne $Length) {
|
||||
throw "ReadProcessMemory at 0x$('{0:X8}' -f $Address) returned $($read.ToInt64()) of $Length bytes"
|
||||
}
|
||||
$buffer
|
||||
}
|
||||
|
||||
$snapshot = [FparkanOriginalCamera]::CreateToolhelp32Snapshot(
|
||||
[FparkanOriginalCamera]::TH32CS_SNAPMODULE -bor [FparkanOriginalCamera]::TH32CS_SNAPMODULE32,
|
||||
[uint32]$ProcessId
|
||||
)
|
||||
if ($snapshot -eq [IntPtr]::Zero -or $snapshot.ToInt64() -eq -1) {
|
||||
throw "CreateToolhelp32Snapshot failed: $(Get-LastWin32ErrorText)"
|
||||
}
|
||||
|
||||
$terrainBase = $null
|
||||
try {
|
||||
$module = [FparkanOriginalCamera+MODULEENTRY32]::new()
|
||||
$module.dwSize = [Runtime.InteropServices.Marshal]::SizeOf([type][FparkanOriginalCamera+MODULEENTRY32])
|
||||
if (-not [FparkanOriginalCamera]::Module32First($snapshot, [ref]$module)) {
|
||||
throw "Module32First failed: $(Get-LastWin32ErrorText)"
|
||||
}
|
||||
do {
|
||||
if ($module.szModule -ieq 'Terrain.dll') {
|
||||
$terrainBase = $module.modBaseAddr.ToInt64()
|
||||
break
|
||||
}
|
||||
$module = [FparkanOriginalCamera+MODULEENTRY32]::new()
|
||||
$module.dwSize = [Runtime.InteropServices.Marshal]::SizeOf([type][FparkanOriginalCamera+MODULEENTRY32])
|
||||
} while ([FparkanOriginalCamera]::Module32Next($snapshot, [ref]$module))
|
||||
} finally {
|
||||
[void][FparkanOriginalCamera]::CloseHandle($snapshot)
|
||||
}
|
||||
|
||||
if ($null -eq $terrainBase) {
|
||||
throw "Terrain.dll is not loaded by process $ProcessId"
|
||||
}
|
||||
|
||||
$process = [FparkanOriginalCamera]::OpenProcess(
|
||||
[FparkanOriginalCamera]::PROCESS_QUERY_INFORMATION -bor [FparkanOriginalCamera]::PROCESS_VM_READ,
|
||||
$false,
|
||||
[uint32]$ProcessId
|
||||
)
|
||||
if ($process -eq [IntPtr]::Zero) {
|
||||
throw "OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ) failed: $(Get-LastWin32ErrorText)"
|
||||
}
|
||||
|
||||
try {
|
||||
# Terrain.dll image RVA 0x7355c -> active 0x1a4-byte outer camera object.
|
||||
# Its selector-0 affine block begins at outer + 0x20. Words 3/7/11 are
|
||||
# the proven world-space translation components. AutoDemo also briefly
|
||||
# selects normalized/reflection-like camera objects; a finite matrix alone
|
||||
# is not sufficient evidence that it can project the mission world.
|
||||
$expectedOuterVtable = [uint32]($terrainBase + 0x665b4)
|
||||
$matrixBytes = $null
|
||||
$translation = $null
|
||||
$cameraOuter = $null
|
||||
$lastObservation = 'camera pointer unavailable'
|
||||
for ($attempt = 1; $attempt -le $CaptureAttempts; $attempt++) {
|
||||
$candidateOuter = [BitConverter]::ToUInt32(
|
||||
(Read-OriginalBytes $process ($terrainBase + 0x7355c) 4),
|
||||
0
|
||||
)
|
||||
if ($candidateOuter -lt 0x10000) {
|
||||
$lastObservation = "camera pointer 0x$('{0:X8}' -f $candidateOuter)"
|
||||
continue
|
||||
}
|
||||
$outerVtable = [BitConverter]::ToUInt32(
|
||||
(Read-OriginalBytes $process ([int64]$candidateOuter) 4),
|
||||
0
|
||||
)
|
||||
if ($outerVtable -ne $expectedOuterVtable) {
|
||||
$lastObservation = "outer vtable 0x$('{0:X8}' -f $outerVtable)"
|
||||
continue
|
||||
}
|
||||
$matrixBytes = Read-OriginalBytes $process ([int64]$candidateOuter + 0x20) 64
|
||||
$candidateTranslation = @(
|
||||
[BitConverter]::ToSingle($matrixBytes, 12),
|
||||
[BitConverter]::ToSingle($matrixBytes, 28),
|
||||
[BitConverter]::ToSingle($matrixBytes, 44)
|
||||
)
|
||||
$nonFinite = @($candidateTranslation | Where-Object {
|
||||
[Single]::IsNaN($_) -or [Single]::IsInfinity($_)
|
||||
})
|
||||
$length = [Math]::Sqrt(
|
||||
[double]$candidateTranslation[0] * $candidateTranslation[0] +
|
||||
[double]$candidateTranslation[1] * $candidateTranslation[1] +
|
||||
[double]$candidateTranslation[2] * $candidateTranslation[2]
|
||||
)
|
||||
if ($nonFinite.Count -eq 0 -and $length -ge $MinimumWorldTranslation) {
|
||||
$cameraOuter = $candidateOuter
|
||||
$translation = $candidateTranslation
|
||||
break
|
||||
}
|
||||
$lastObservation = "translation length $length at 0x$('{0:X8}' -f $candidateOuter)"
|
||||
if ($attempt -lt $CaptureAttempts -and $RetryIntervalMilliseconds -gt 0) {
|
||||
Start-Sleep -Milliseconds $RetryIntervalMilliseconds
|
||||
}
|
||||
}
|
||||
if ($null -eq $translation) {
|
||||
throw "No world-space selector-0 transform after $CaptureAttempts samples (minimum translation length $MinimumWorldTranslation; last observation: $lastObservation)"
|
||||
}
|
||||
$words = for ($index = 0; $index -lt 16; $index++) {
|
||||
[BitConverter]::ToUInt32($matrixBytes, $index * 4)
|
||||
}
|
||||
[ordered]@{
|
||||
schema = 'fparkan-legacy-camera-v1'
|
||||
process_id = $ProcessId
|
||||
terrain_module_base = ('0x{0:X8}' -f $terrainBase)
|
||||
terrain_camera_global_rva = '0x7355c'
|
||||
terrain_camera_outer = ('0x{0:X8}' -f $cameraOuter)
|
||||
selector0_words = @($words)
|
||||
selector0_translation = @($translation)
|
||||
# LegacyD3d7Projection carries a D3D7 RECT: left, top, right, bottom.
|
||||
viewport = @(0, 0, $ViewportWidth, $ViewportHeight)
|
||||
near_plane = $NearPlane
|
||||
far_plane = $FarPlane
|
||||
field_of_view_radians = $FieldOfViewRadians
|
||||
} | ConvertTo-Json -Depth 4 -Compress
|
||||
} finally {
|
||||
[void][FparkanOriginalCamera]::CloseHandle($process)
|
||||
}
|
||||
@@ -1,272 +0,0 @@
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[int]$ProcessId,
|
||||
[ValidateRange(1, 60)]
|
||||
[int]$CaptureAttempts = 6,
|
||||
[ValidateRange(0, 1000)]
|
||||
[int]$RetryIntervalMilliseconds = 100,
|
||||
[ValidateRange(0x00010000, 0x7fff0000)]
|
||||
[UInt32]$SearchStart = 0x01000000,
|
||||
[ValidateRange(0x00010000, 0x7fff0000)]
|
||||
[UInt32]$SearchEnd = 0x20000000
|
||||
)
|
||||
|
||||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
# This observer deliberately opens only PROCESS_QUERY_INFORMATION | PROCESS_VM_READ.
|
||||
# It neither sends input nor writes, suspends, injects into, or calls the original game.
|
||||
Add-Type -TypeDefinition @'
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
public static class FparkanTerrainShadeProbe {
|
||||
public const uint TH32CS_SNAPMODULE = 0x00000008;
|
||||
public const uint TH32CS_SNAPMODULE32 = 0x00000010;
|
||||
public const uint PROCESS_QUERY_INFORMATION = 0x00000400;
|
||||
public const uint PROCESS_VM_READ = 0x00000010;
|
||||
public const uint MEM_COMMIT = 0x1000;
|
||||
public const uint PAGE_NOACCESS = 0x01;
|
||||
public const uint PAGE_GUARD = 0x100;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||
public struct MODULEENTRY32 {
|
||||
public uint dwSize;
|
||||
public uint th32ModuleID;
|
||||
public uint th32ProcessID;
|
||||
public uint GlblcntUsage;
|
||||
public uint ProccntUsage;
|
||||
public IntPtr modBaseAddr;
|
||||
public uint modBaseSize;
|
||||
public IntPtr hModule;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] public string szModule;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string szExePath;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct MEMORY_BASIC_INFORMATION {
|
||||
public IntPtr BaseAddress;
|
||||
public IntPtr AllocationBase;
|
||||
public uint AllocationProtect;
|
||||
public IntPtr RegionSize;
|
||||
public uint State;
|
||||
public uint Protect;
|
||||
public uint Type;
|
||||
}
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern IntPtr CreateToolhelp32Snapshot(uint flags, uint processId);
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
public static extern bool Module32First(IntPtr snapshot, ref MODULEENTRY32 entry);
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
public static extern bool Module32Next(IntPtr snapshot, ref MODULEENTRY32 entry);
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern IntPtr OpenProcess(uint access, bool inheritHandle, uint processId);
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern bool ReadProcessMemory(
|
||||
IntPtr process, IntPtr address, [Out] byte[] buffer, IntPtr size, out IntPtr bytesRead);
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern IntPtr VirtualQueryEx(
|
||||
IntPtr process, IntPtr address, out MEMORY_BASIC_INFORMATION buffer, IntPtr length);
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern bool CloseHandle(IntPtr handle);
|
||||
|
||||
public static int FindU32(byte[] bytes, uint expected, int start) {
|
||||
for (int index = start; index <= bytes.Length - 4; index += 4) {
|
||||
if (BitConverter.ToUInt32(bytes, index) == expected) return index;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static ulong Fnv1a64(byte[] bytes, int offset, int length) {
|
||||
ulong hash = 14695981039346656037UL;
|
||||
unchecked {
|
||||
for (int index = offset; index < offset + length; index++) {
|
||||
hash ^= bytes[index];
|
||||
hash *= 1099511628211UL;
|
||||
}
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
'@
|
||||
|
||||
function Get-LastWin32ErrorText {
|
||||
$code = [Runtime.InteropServices.Marshal]::GetLastWin32Error()
|
||||
"$code ($([ComponentModel.Win32Exception]::new($code).Message))"
|
||||
}
|
||||
|
||||
function Get-TerrainModuleBase {
|
||||
param([int]$ProbeProcessId)
|
||||
$snapshot = [FparkanTerrainShadeProbe]::CreateToolhelp32Snapshot(
|
||||
[FparkanTerrainShadeProbe]::TH32CS_SNAPMODULE -bor [FparkanTerrainShadeProbe]::TH32CS_SNAPMODULE32,
|
||||
[uint32]$ProbeProcessId
|
||||
)
|
||||
if ($snapshot -eq [IntPtr]::Zero -or $snapshot.ToInt64() -eq -1) {
|
||||
throw "CreateToolhelp32Snapshot failed: $(Get-LastWin32ErrorText)"
|
||||
}
|
||||
try {
|
||||
$module = [FparkanTerrainShadeProbe+MODULEENTRY32]::new()
|
||||
$module.dwSize = [Runtime.InteropServices.Marshal]::SizeOf([type][FparkanTerrainShadeProbe+MODULEENTRY32])
|
||||
if (-not [FparkanTerrainShadeProbe]::Module32First($snapshot, [ref]$module)) {
|
||||
throw "Module32First failed: $(Get-LastWin32ErrorText)"
|
||||
}
|
||||
do {
|
||||
if ($module.szModule -ieq 'Terrain.dll') {
|
||||
return $module.modBaseAddr.ToInt64()
|
||||
}
|
||||
$module = [FparkanTerrainShadeProbe+MODULEENTRY32]::new()
|
||||
$module.dwSize = [Runtime.InteropServices.Marshal]::SizeOf([type][FparkanTerrainShadeProbe+MODULEENTRY32])
|
||||
} while ([FparkanTerrainShadeProbe]::Module32Next($snapshot, [ref]$module))
|
||||
} finally {
|
||||
[void][FparkanTerrainShadeProbe]::CloseHandle($snapshot)
|
||||
}
|
||||
throw "Terrain.dll is not loaded by process $ProbeProcessId"
|
||||
}
|
||||
|
||||
function Read-Bytes {
|
||||
param([IntPtr]$Process, [Int64]$Address, [int]$Length)
|
||||
$buffer = [byte[]]::new($Length)
|
||||
$read = [IntPtr]::Zero
|
||||
if (-not [FparkanTerrainShadeProbe]::ReadProcessMemory(
|
||||
$Process, [IntPtr]$Address, $buffer, [IntPtr]$Length, [ref]$read)) {
|
||||
return $null
|
||||
}
|
||||
if ($read.ToInt64() -ne $Length) {
|
||||
return $null
|
||||
}
|
||||
return $buffer
|
||||
}
|
||||
|
||||
function Find-ShadeCache {
|
||||
param(
|
||||
[IntPtr]$Process,
|
||||
[UInt32]$ExpectedVtable,
|
||||
[UInt32]$Start,
|
||||
[UInt32]$End,
|
||||
[Int64]$ExcludedImageStart,
|
||||
[Int64]$ExcludedImageEnd
|
||||
)
|
||||
$mbiSize = [Runtime.InteropServices.Marshal]::SizeOf([type][FparkanTerrainShadeProbe+MEMORY_BASIC_INFORMATION])
|
||||
[Int64]$cursor = $Start
|
||||
while ($cursor -lt $End) {
|
||||
$mbi = [FparkanTerrainShadeProbe+MEMORY_BASIC_INFORMATION]::new()
|
||||
$queried = [FparkanTerrainShadeProbe]::VirtualQueryEx(
|
||||
$Process, [IntPtr]$cursor, [ref]$mbi, [IntPtr]$mbiSize
|
||||
)
|
||||
if ($queried -eq [IntPtr]::Zero) { break }
|
||||
$base = $mbi.BaseAddress.ToInt64()
|
||||
$size = $mbi.RegionSize.ToInt64()
|
||||
if ($size -le 0) { break }
|
||||
$next = $base + $size
|
||||
if ($mbi.State -eq [FparkanTerrainShadeProbe]::MEM_COMMIT -and
|
||||
($mbi.Protect -band [FparkanTerrainShadeProbe]::PAGE_NOACCESS) -eq 0 -and
|
||||
($mbi.Protect -band [FparkanTerrainShadeProbe]::PAGE_GUARD) -eq 0) {
|
||||
$regionStart = [Math]::Max($base, [Int64]$Start)
|
||||
$regionEnd = [Math]::Min($next, [Int64]$End)
|
||||
for ([Int64]$offset = $regionStart; $offset -lt $regionEnd; $offset += 65536) {
|
||||
$length = [int][Math]::Min(65536, $regionEnd - $offset)
|
||||
$bytes = Read-Bytes $Process $offset $length
|
||||
if ($null -eq $bytes) { continue }
|
||||
$searchIndex = 0
|
||||
while ($searchIndex -le $bytes.Length - 4) {
|
||||
$index = [FparkanTerrainShadeProbe]::FindU32($bytes, $ExpectedVtable, $searchIndex)
|
||||
if ($index -lt 0) { break }
|
||||
$candidate = $offset + $index
|
||||
if ($candidate -lt $ExcludedImageStart -or $candidate -ge $ExcludedImageEnd) {
|
||||
return $candidate
|
||||
}
|
||||
$searchIndex = $index + 4
|
||||
}
|
||||
}
|
||||
}
|
||||
$cursor = [Math]::Max($next, $cursor + 4096)
|
||||
}
|
||||
return $null
|
||||
}
|
||||
|
||||
function Get-ShadeCacheSummary {
|
||||
param([IntPtr]$Process, [Int64]$Cache, [byte[]]$Header)
|
||||
$entryTable = [BitConverter]::ToUInt32($Header, 316)
|
||||
$entryCount = [BitConverter]::ToUInt32($Header, 320)
|
||||
$summary = [ordered]@{
|
||||
materialized_entries = $null
|
||||
profile_banks = @()
|
||||
}
|
||||
# The count field is runtime data. Keep a hard observer bound so a corrupt
|
||||
# or stale candidate cannot turn a passive sample into an excessive read.
|
||||
if ($entryTable -lt 0x1000 -or $entryCount -gt 100000) { return $summary }
|
||||
$entryBytes = Read-Bytes $Process $entryTable ([int]($entryCount * 8))
|
||||
if ($null -eq $entryBytes) { return $summary }
|
||||
$materialized = 0
|
||||
$banks = [System.Collections.Generic.SortedSet[int]]::new()
|
||||
for ($index = 0; $index -lt $entryCount; $index++) {
|
||||
$offset = $index * 8
|
||||
if ([BitConverter]::ToUInt32($entryBytes, $offset) -ge 0x1000) {
|
||||
$materialized++
|
||||
[void]$banks.Add([int]$entryBytes[$offset + 4])
|
||||
}
|
||||
}
|
||||
$summary.materialized_entries = $materialized
|
||||
if ($banks.Count -eq 0) { return $summary }
|
||||
$maxBank = $banks.Max
|
||||
if ($maxBank -ge 100) { return $summary }
|
||||
$bankBytes = Read-Bytes $Process ($Cache + 332) (($maxBank + 1) * 212)
|
||||
if ($null -eq $bankBytes) { return $summary }
|
||||
$profiles = [System.Collections.Generic.List[object]]::new()
|
||||
foreach ($bank in $banks) {
|
||||
$profiles.Add([ordered]@{
|
||||
bank = $bank
|
||||
fnv1a64 = [FparkanTerrainShadeProbe]::Fnv1a64($bankBytes, $bank * 212, 212).ToString()
|
||||
})
|
||||
}
|
||||
$summary.profile_banks = @($profiles)
|
||||
return $summary
|
||||
}
|
||||
|
||||
if ($SearchEnd -le $SearchStart) { throw 'SearchEnd must exceed SearchStart' }
|
||||
$terrainBase = Get-TerrainModuleBase $ProcessId
|
||||
$process = [FparkanTerrainShadeProbe]::OpenProcess(
|
||||
[FparkanTerrainShadeProbe]::PROCESS_QUERY_INFORMATION -bor [FparkanTerrainShadeProbe]::PROCESS_VM_READ,
|
||||
$false,
|
||||
[uint32]$ProcessId
|
||||
)
|
||||
if ($process -eq [IntPtr]::Zero) { throw "OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ) failed: $(Get-LastWin32ErrorText)" }
|
||||
|
||||
try {
|
||||
$expectedVtable = [uint32]($terrainBase + 0x643d0)
|
||||
$last = 'cache vtable was not present in readable scan range'
|
||||
for ($attempt = 1; $attempt -le $CaptureAttempts; $attempt++) {
|
||||
# The vtable value itself naturally appears in the Terrain image as
|
||||
# relocation data; only a heap-resident object is a cache candidate.
|
||||
$cache = Find-ShadeCache $process $expectedVtable $SearchStart $SearchEnd $terrainBase ($terrainBase + 0x100000)
|
||||
if ($null -ne $cache) {
|
||||
$header = Read-Bytes $process $cache 324
|
||||
if ($null -ne $header) {
|
||||
$summary = Get-ShadeCacheSummary $process $cache $header
|
||||
[ordered]@{
|
||||
schema = 'fparkan-terrain-shade-cache-v1'
|
||||
process_id = $ProcessId
|
||||
terrain_module_base = ('0x{0:X8}' -f $terrainBase)
|
||||
cache_vtable_rva = '0x643d0'
|
||||
cache_object = ('0x{0:X8}' -f $cache)
|
||||
result_view = ('0x{0:X8}' -f [BitConverter]::ToUInt32($header, 24))
|
||||
entry_table = ('0x{0:X8}' -f [BitConverter]::ToUInt32($header, 316))
|
||||
entry_count = [BitConverter]::ToUInt32($header, 320)
|
||||
materialized_entries = $summary.materialized_entries
|
||||
profile_banks = $summary.profile_banks
|
||||
scan_attempt = $attempt
|
||||
} | ConvertTo-Json -Compress
|
||||
exit 0
|
||||
}
|
||||
$last = "cache candidate 0x$('{0:X8}' -f $cache) became unreadable"
|
||||
}
|
||||
if ($attempt -lt $CaptureAttempts -and $RetryIntervalMilliseconds -gt 0) {
|
||||
Start-Sleep -Milliseconds $RetryIntervalMilliseconds
|
||||
}
|
||||
}
|
||||
throw "No live GetShade cache after $CaptureAttempts scans ($last)"
|
||||
} finally {
|
||||
[void][FparkanTerrainShadeProbe]::CloseHandle($process)
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
// Emits the GOG CreateSuperAI export to recover the mission-to-SuperAI
|
||||
// initialization boundary. Run headless; the original PE remains read only.
|
||||
import ghidra.app.decompiler.DecompInterface;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Function;
|
||||
|
||||
public class ExportAiCreateSuperAi extends GhidraScript {
|
||||
private static final long ADDRESS = 0x1000f710L;
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
Address address = currentProgram.getAddressFactory().getDefaultAddressSpace()
|
||||
.getAddress(ADDRESS);
|
||||
Function function = currentProgram.getFunctionManager().getFunctionAt(address);
|
||||
println("===== AI CreateSuperAI =====");
|
||||
if (function == null) { println("missing"); return; }
|
||||
DecompInterface decompiler = new DecompInterface();
|
||||
decompiler.openProgram(currentProgram);
|
||||
println(decompiler.decompileFunction(function, 120, monitor).getDecompiledFunction().getC());
|
||||
decompiler.dispose();
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
// Emits the decompiled AI expression evaluator containing the recovered
|
||||
// tag 1..5 dispatch. Run through Ghidra headless analysis only; it never
|
||||
// mutates the original PE image.
|
||||
import ghidra.app.decompiler.DecompInterface;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Function;
|
||||
|
||||
public class ExportAiExpressionDispatcher extends GhidraScript {
|
||||
private static final long ADDRESS = 0x10005180L;
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
Address address = currentProgram.getAddressFactory().getDefaultAddressSpace()
|
||||
.getAddress(ADDRESS);
|
||||
Function function = currentProgram.getFunctionManager().getFunctionContaining(address);
|
||||
println("===== AI expression dispatcher =====");
|
||||
if (function == null) { println("missing"); return; }
|
||||
println("entry=" + function.getEntryPoint());
|
||||
DecompInterface decompiler = new DecompInterface();
|
||||
decompiler.openProgram(currentProgram);
|
||||
println(decompiler.decompileFunction(function, 60, monitor).getDecompiledFunction().getC());
|
||||
decompiler.dispose();
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
// Emits the x87-to-integer helper called by Handler(19). Run headless; the
|
||||
// original PE remains read only.
|
||||
import ghidra.app.decompiler.DecompInterface;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Function;
|
||||
|
||||
public class ExportAiFtol extends GhidraScript {
|
||||
private static final long ADDRESS = 0x1001df70L;
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
Address address = currentProgram.getAddressFactory().getDefaultAddressSpace()
|
||||
.getAddress(ADDRESS);
|
||||
Function function = currentProgram.getFunctionManager().getFunctionAt(address);
|
||||
println("===== AI x87 __ftol helper =====");
|
||||
if (function == null) { println("missing"); return; }
|
||||
DecompInterface decompiler = new DecompInterface();
|
||||
decompiler.openProgram(currentProgram);
|
||||
println(decompiler.decompileFunction(function, 60, monitor).getDecompiledFunction().getC());
|
||||
decompiler.dispose();
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
// Emits the GOG ai.dll GetSuperAI export to recover the live singleton
|
||||
// boundary for read-only handler-input capture.
|
||||
import ghidra.app.decompiler.DecompInterface;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Function;
|
||||
|
||||
public class ExportAiGetSuperAi extends GhidraScript {
|
||||
private static final long ADDRESS = 0x1000f780L;
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
Address address = currentProgram.getAddressFactory().getDefaultAddressSpace()
|
||||
.getAddress(ADDRESS);
|
||||
Function function = currentProgram.getFunctionManager().getFunctionAt(address);
|
||||
println("===== AI GetSuperAI =====");
|
||||
if (function == null) { println("missing"); return; }
|
||||
DecompInterface decompiler = new DecompInterface();
|
||||
decompiler.openProgram(currentProgram);
|
||||
println(decompiler.decompileFunction(function, 60, monitor).getDecompiledFunction().getC());
|
||||
decompiler.dispose();
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
// Emits the GOG AI script-bundle loader, discovered from references to
|
||||
// "MISSIONS\\SCRIPTS\\" and ".scr". Run headless; original input stays read only.
|
||||
import ghidra.app.decompiler.DecompInterface;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Function;
|
||||
|
||||
public class ExportAiScriptLoader extends GhidraScript {
|
||||
private static final long ADDRESS = 0x10001000L;
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
Address address = currentProgram.getAddressFactory().getDefaultAddressSpace()
|
||||
.getAddress(ADDRESS);
|
||||
Function function = currentProgram.getFunctionManager().getFunctionAt(address);
|
||||
println("===== AI script loader =====");
|
||||
if (function == null) { println("missing"); return; }
|
||||
DecompInterface decompiler = new DecompInterface();
|
||||
decompiler.openProgram(currentProgram);
|
||||
println(decompiler.decompileFunction(function, 60, monitor).getDecompiledFunction().getC());
|
||||
decompiler.dispose();
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
// Emits path literals used by the GOG AI script loader at 0x10001000.
|
||||
// Run headless; the original PE remains read only.
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.program.model.address.Address;
|
||||
|
||||
public class ExportAiScriptLoaderStrings extends GhidraScript {
|
||||
private static final long[] ADDRESSES = {
|
||||
0x10038a88L, 0x10038a9cL, 0x10038aa4L, 0x10038aacL,
|
||||
0x10038ab4L, 0x10038abcL, 0x10038ad0L, 0x10038ad8L,
|
||||
0x10038ae0L
|
||||
};
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
for (long value : ADDRESSES) {
|
||||
Address address = currentProgram.getAddressFactory().getDefaultAddressSpace()
|
||||
.getAddress(value);
|
||||
byte[] bytes = new byte[256];
|
||||
int count = currentProgram.getMemory().getBytes(address, bytes);
|
||||
StringBuilder text = new StringBuilder();
|
||||
for (int index = 0; index < count && bytes[index] != 0; index++) {
|
||||
text.append((char) (bytes[index] & 0xff));
|
||||
}
|
||||
println(address + " = \"" + text + "\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
// Emits the immediate .scr package reader called by the AI script loader.
|
||||
// Run through Ghidra headless analysis; the original PE is never modified.
|
||||
import ghidra.app.decompiler.DecompInterface;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Function;
|
||||
|
||||
public class ExportAiScriptPackageReader extends GhidraScript {
|
||||
private static final long ADDRESS = 0x10011B20L;
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
Address address = currentProgram.getAddressFactory().getDefaultAddressSpace()
|
||||
.getAddress(ADDRESS);
|
||||
Function function = currentProgram.getFunctionManager().getFunctionAt(address);
|
||||
println("===== AI .scr package reader =====");
|
||||
if (function == null) { println("missing"); return; }
|
||||
DecompInterface decompiler = new DecompInterface();
|
||||
decompiler.openProgram(currentProgram);
|
||||
println(decompiler.decompileFunction(function, 60, monitor).getDecompiledFunction().getC());
|
||||
decompiler.dispose();
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
// Emits the SuperAI constructor called by CreateSuperAI. Run headless; the
|
||||
// original PE remains read only.
|
||||
import ghidra.app.decompiler.DecompInterface;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Function;
|
||||
|
||||
public class ExportAiSuperAiConstructor extends GhidraScript {
|
||||
private static final long ADDRESS = 0x10001000L;
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
Address address = currentProgram.getAddressFactory().getDefaultAddressSpace()
|
||||
.getAddress(ADDRESS);
|
||||
Function function = currentProgram.getFunctionManager().getFunctionAt(address);
|
||||
println("===== AI SuperAI constructor =====");
|
||||
if (function == null) { println("missing"); return; }
|
||||
DecompInterface decompiler = new DecompInterface();
|
||||
decompiler.openProgram(currentProgram);
|
||||
println(decompiler.decompileFunction(function, 120, monitor).getDecompiledFunction().getC());
|
||||
decompiler.dispose();
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
// Emits the text `.var` loader called after the AI script loader selects a
|
||||
// bundle-local or shared varset. Run headless; the original PE remains read only.
|
||||
import ghidra.app.decompiler.DecompInterface;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Function;
|
||||
|
||||
public class ExportAiVarSetLoader extends GhidraScript {
|
||||
private static final long ADDRESS = 0x10011ea0L;
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
Address address = currentProgram.getAddressFactory().getDefaultAddressSpace()
|
||||
.getAddress(ADDRESS);
|
||||
Function function = currentProgram.getFunctionManager().getFunctionAt(address);
|
||||
println("===== AI varset loader =====");
|
||||
if (function == null) { println("missing"); return; }
|
||||
DecompInterface decompiler = new DecompInterface();
|
||||
decompiler.openProgram(currentProgram);
|
||||
println(decompiler.decompileFunction(function, 60, monitor).getDecompiledFunction().getC());
|
||||
decompiler.dispose();
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
// Emits the actual text-to-varset parser called by the AI varset loader.
|
||||
// Run headless; the original PE remains read only.
|
||||
import ghidra.app.decompiler.DecompInterface;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Function;
|
||||
|
||||
public class ExportAiVarSetParser extends GhidraScript {
|
||||
private static final long ADDRESS = 0x100174a0L;
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
Address address = currentProgram.getAddressFactory().getDefaultAddressSpace()
|
||||
.getAddress(ADDRESS);
|
||||
Function function = currentProgram.getFunctionManager().getFunctionAt(address);
|
||||
println("===== AI varset parser =====");
|
||||
if (function == null) { println("missing"); return; }
|
||||
DecompInterface decompiler = new DecompInterface();
|
||||
decompiler.openProgram(currentProgram);
|
||||
println(decompiler.decompileFunction(function, 60, monitor).getDecompiledFunction().getC());
|
||||
decompiler.dispose();
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
// Emits the u32 resolver used by corpus-reachable Handler(30) for indexed
|
||||
// varset records. Run headless; the original PE remains read only.
|
||||
import ghidra.app.decompiler.DecompInterface;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Function;
|
||||
|
||||
public class ExportAiVarSetU32Resolver extends GhidraScript {
|
||||
private static final long ADDRESS = 0x10013570L;
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
Address address = currentProgram.getAddressFactory().getDefaultAddressSpace()
|
||||
.getAddress(ADDRESS);
|
||||
Function function = currentProgram.getFunctionManager().getFunctionAt(address);
|
||||
println("===== AI varset u32 resolver =====");
|
||||
if (function == null) { println("missing"); return; }
|
||||
DecompInterface decompiler = new DecompInterface();
|
||||
decompiler.openProgram(currentProgram);
|
||||
println(decompiler.decompileFunction(function, 60, monitor).getDecompiledFunction().getC());
|
||||
decompiler.dispose();
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
// Emits the first function in the AI DLL's verified 73-entry VM handler table.
|
||||
// Run through Ghidra headless analysis; the original PE remains read only.
|
||||
import ghidra.app.decompiler.DecompInterface;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Function;
|
||||
|
||||
public class ExportAiVmHandler0 extends GhidraScript {
|
||||
private static final long ADDRESS = 0x10008034L;
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
Address address = currentProgram.getAddressFactory().getDefaultAddressSpace()
|
||||
.getAddress(ADDRESS);
|
||||
Function function = currentProgram.getFunctionManager().getFunctionAt(address);
|
||||
println("===== AI VM handler 0 =====");
|
||||
if (function == null) { println("missing"); return; }
|
||||
DecompInterface decompiler = new DecompInterface();
|
||||
decompiler.openProgram(currentProgram);
|
||||
println(decompiler.decompileFunction(function, 60, monitor).getDecompiledFunction().getC());
|
||||
decompiler.dispose();
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
// Emits Handler(1), the second function in the AI DLL's verified 73-entry VM table.
|
||||
// Run through Ghidra headless analysis; the original PE remains read only.
|
||||
import ghidra.app.decompiler.DecompInterface;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Function;
|
||||
|
||||
public class ExportAiVmHandler1 extends GhidraScript {
|
||||
private static final long ADDRESS = 0x10007fd0L;
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
Address address = currentProgram.getAddressFactory().getDefaultAddressSpace()
|
||||
.getAddress(ADDRESS);
|
||||
Function function = currentProgram.getFunctionManager().getFunctionAt(address);
|
||||
println("===== AI VM Handler(1) =====");
|
||||
if (function == null) { println("missing"); return; }
|
||||
DecompInterface decompiler = new DecompInterface();
|
||||
decompiler.openProgram(currentProgram);
|
||||
println(decompiler.decompileFunction(function, 60, monitor).getDecompiledFunction().getC());
|
||||
decompiler.dispose();
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
// Emits Handler(15), a frequent non-sentinel selector in the GOG compiled
|
||||
// script corpus. Run headless; the original PE remains read only.
|
||||
import ghidra.app.decompiler.DecompInterface;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Function;
|
||||
|
||||
public class ExportAiVmHandler15 extends GhidraScript {
|
||||
private static final long ADDRESS = 0x10008054L;
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
Address address = currentProgram.getAddressFactory().getDefaultAddressSpace()
|
||||
.getAddress(ADDRESS);
|
||||
Function function = currentProgram.getFunctionManager().getFunctionAt(address);
|
||||
println("===== AI VM Handler(15) =====");
|
||||
if (function == null) { println("missing"); return; }
|
||||
DecompInterface decompiler = new DecompInterface();
|
||||
decompiler.openProgram(currentProgram);
|
||||
println(decompiler.decompileFunction(function, 60, monitor).getDecompiledFunction().getC());
|
||||
decompiler.dispose();
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
// Emits Handler(19), the first instruction in both AutoDemo default-script
|
||||
// Init events. Run headless; the original PE remains read only.
|
||||
import ghidra.app.decompiler.DecompInterface;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Function;
|
||||
|
||||
public class ExportAiVmHandler19 extends GhidraScript {
|
||||
private static final long ADDRESS = 0x1000aa38L;
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
Address address = currentProgram.getAddressFactory().getDefaultAddressSpace()
|
||||
.getAddress(ADDRESS);
|
||||
Function function = currentProgram.getFunctionManager().getFunctionAt(address);
|
||||
println("===== AI VM Handler(19) =====");
|
||||
if (function == null) { println("missing"); return; }
|
||||
DecompInterface decompiler = new DecompInterface();
|
||||
decompiler.openProgram(currentProgram);
|
||||
println(decompiler.decompileFunction(function, 60, monitor).getDecompiledFunction().getC());
|
||||
decompiler.dispose();
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
// Emits Handler(19)'s common x87 varset setter. Run headless; the original PE
|
||||
// remains read only.
|
||||
import ghidra.app.decompiler.DecompInterface;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Function;
|
||||
|
||||
public class ExportAiVmHandler19Setter extends GhidraScript {
|
||||
private static final long ADDRESS = 0x10013770L;
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
Address address = currentProgram.getAddressFactory().getDefaultAddressSpace()
|
||||
.getAddress(ADDRESS);
|
||||
Function function = currentProgram.getFunctionManager().getFunctionAt(address);
|
||||
println("===== AI VM Handler(19) setter =====");
|
||||
if (function == null) { println("missing"); return; }
|
||||
DecompInterface decompiler = new DecompInterface();
|
||||
decompiler.openProgram(currentProgram);
|
||||
println(decompiler.decompileFunction(function, 60, monitor).getDecompiledFunction().getC());
|
||||
decompiler.dispose();
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
// Emits the common varset storage helper reached by Handler(19)'s setter.
|
||||
// Run headless; the original PE remains read only.
|
||||
import ghidra.app.decompiler.DecompInterface;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Function;
|
||||
|
||||
public class ExportAiVmHandler19SetterCallee extends GhidraScript {
|
||||
private static final long ADDRESS = 0x10012fe0L;
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
Address address = currentProgram.getAddressFactory().getDefaultAddressSpace()
|
||||
.getAddress(ADDRESS);
|
||||
Function function = currentProgram.getFunctionManager().getFunctionAt(address);
|
||||
println("===== AI VM Handler(19) setter storage helper =====");
|
||||
if (function == null) { println("missing"); return; }
|
||||
DecompInterface decompiler = new DecompInterface();
|
||||
decompiler.openProgram(currentProgram);
|
||||
println(decompiler.decompileFunction(function, 60, monitor).getDecompiledFunction().getC());
|
||||
decompiler.dispose();
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
// Emits the two direct callees recovered from AI VM Handler(1).
|
||||
// Run through Ghidra headless analysis; the original PE remains read only.
|
||||
import ghidra.app.decompiler.DecompInterface;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Function;
|
||||
|
||||
public class ExportAiVmHandler1Callees extends GhidraScript {
|
||||
private static final long[] ADDRESSES = { 0x10002d30L, 0x10013190L };
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
DecompInterface decompiler = new DecompInterface();
|
||||
decompiler.openProgram(currentProgram);
|
||||
for (long value : ADDRESSES) {
|
||||
Address address = currentProgram.getAddressFactory().getDefaultAddressSpace()
|
||||
.getAddress(value);
|
||||
Function function = currentProgram.getFunctionManager().getFunctionAt(address);
|
||||
println("===== AI VM Handler(1) callee " + address + " =====");
|
||||
if (function == null) { println("missing"); continue; }
|
||||
println(decompiler.decompileFunction(function, 60, monitor).getDecompiledFunction().getC());
|
||||
}
|
||||
decompiler.dispose();
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
// Emits Handler(2), the third function in the AI DLL's verified 73-entry VM table.
|
||||
// Run through Ghidra headless analysis; the original PE remains read only.
|
||||
import ghidra.app.decompiler.DecompInterface;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Function;
|
||||
|
||||
public class ExportAiVmHandler2 extends GhidraScript {
|
||||
private static final long ADDRESS = 0x10009610L;
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
Address address = currentProgram.getAddressFactory().getDefaultAddressSpace()
|
||||
.getAddress(ADDRESS);
|
||||
Function function = currentProgram.getFunctionManager().getFunctionAt(address);
|
||||
println("===== AI VM Handler(2) =====");
|
||||
if (function == null) { println("missing"); return; }
|
||||
DecompInterface decompiler = new DecompInterface();
|
||||
decompiler.openProgram(currentProgram);
|
||||
println(decompiler.decompileFunction(function, 60, monitor).getDecompiledFunction().getC());
|
||||
decompiler.dispose();
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
// Emits the opaque direct callee reached by corpus-reachable AI VM Handler(2).
|
||||
// Run through Ghidra headless analysis; the original PE remains read only.
|
||||
import ghidra.app.decompiler.DecompInterface;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Function;
|
||||
|
||||
public class ExportAiVmHandler2Callee extends GhidraScript {
|
||||
private static final long ADDRESS = 0x100059f0L;
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
Address address = currentProgram.getAddressFactory().getDefaultAddressSpace()
|
||||
.getAddress(ADDRESS);
|
||||
Function function = currentProgram.getFunctionManager().getFunctionAt(address);
|
||||
println("===== AI VM Handler(2) direct callee =====");
|
||||
if (function == null) { println("missing"); return; }
|
||||
DecompInterface decompiler = new DecompInterface();
|
||||
decompiler.openProgram(currentProgram);
|
||||
println(decompiler.decompileFunction(function, 60, monitor).getDecompiledFunction().getC());
|
||||
decompiler.dispose();
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
// Emits the direct post-insertion dispatcher reached by the corpus-reachable
|
||||
// AI VM Handler(2) scheduler boundary. Run headless; the original PE is read only.
|
||||
import ghidra.app.decompiler.DecompInterface;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Function;
|
||||
|
||||
public class ExportAiVmHandler2Dispatch extends GhidraScript {
|
||||
private static final long[] ADDRESSES = {
|
||||
0x1000f920L, 0x10004be0L, 0x10004d00L, 0x10004db0L
|
||||
};
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
DecompInterface decompiler = new DecompInterface();
|
||||
decompiler.openProgram(currentProgram);
|
||||
for (long value : ADDRESSES) {
|
||||
Address address = currentProgram.getAddressFactory().getDefaultAddressSpace()
|
||||
.getAddress(value);
|
||||
Function function = currentProgram.getFunctionManager().getFunctionAt(address);
|
||||
println("===== AI Handler(2) post-insertion helper " + address + " =====");
|
||||
if (function == null) { println("missing"); continue; }
|
||||
println(decompiler.decompileFunction(function, 60, monitor).getDecompiledFunction().getC());
|
||||
}
|
||||
decompiler.dispose();
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
// Emits record construction, equality, refresh and insertion helpers called by
|
||||
// the corpus-reachable AI VM Handler(2) scheduler boundary.
|
||||
// Run through Ghidra headless analysis; the original PE remains read only.
|
||||
import ghidra.app.decompiler.DecompInterface;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Function;
|
||||
|
||||
public class ExportAiVmHandler2SchedulerHelpers extends GhidraScript {
|
||||
private static final long[] ADDRESSES = {
|
||||
0x10004e50L, 0x10004c50L, 0x10005070L, 0x100073e0L
|
||||
};
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
DecompInterface decompiler = new DecompInterface();
|
||||
decompiler.openProgram(currentProgram);
|
||||
for (long value : ADDRESSES) {
|
||||
Address address = currentProgram.getAddressFactory().getDefaultAddressSpace()
|
||||
.getAddress(value);
|
||||
Function function = currentProgram.getFunctionManager().getFunctionAt(address);
|
||||
println("===== AI Handler(2) scheduler helper " + address + " =====");
|
||||
if (function == null) { println("missing"); continue; }
|
||||
println(decompiler.decompileFunction(function, 60, monitor).getDecompiledFunction().getC());
|
||||
}
|
||||
decompiler.dispose();
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
// Emits Handler(30), the most frequent non-sentinel selector in the GOG
|
||||
// compiled-script corpus. Run headless; the original PE remains read only.
|
||||
import ghidra.app.decompiler.DecompInterface;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Function;
|
||||
|
||||
public class ExportAiVmHandler30 extends GhidraScript {
|
||||
private static final long ADDRESS = 0x1000c266L;
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
Address address = currentProgram.getAddressFactory().getDefaultAddressSpace()
|
||||
.getAddress(ADDRESS);
|
||||
Function function = currentProgram.getFunctionManager().getFunctionAt(address);
|
||||
println("===== AI VM Handler(30) =====");
|
||||
if (function == null) { println("missing"); return; }
|
||||
DecompInterface decompiler = new DecompInterface();
|
||||
decompiler.openProgram(currentProgram);
|
||||
println(decompiler.decompileFunction(function, 60, monitor).getDecompiledFunction().getC());
|
||||
decompiler.dispose();
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
// Emits Handler(8), a frequent non-sentinel selector in the GOG compiled
|
||||
// script corpus. Run headless; the original PE remains read only.
|
||||
import ghidra.app.decompiler.DecompInterface;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Function;
|
||||
|
||||
public class ExportAiVmHandler8 extends GhidraScript {
|
||||
private static final long ADDRESS = 0x10009b0dL;
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
Address address = currentProgram.getAddressFactory().getDefaultAddressSpace()
|
||||
.getAddress(ADDRESS);
|
||||
Function function = currentProgram.getFunctionManager().getFunctionAt(address);
|
||||
println("===== AI VM Handler(8) =====");
|
||||
if (function == null) { println("missing"); return; }
|
||||
DecompInterface decompiler = new DecompInterface();
|
||||
decompiler.openProgram(currentProgram);
|
||||
println(decompiler.decompileFunction(function, 60, monitor).getDecompiledFunction().getC());
|
||||
decompiler.dispose();
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
// Emits the two non-trivial local callees reached by Handler(8). Run headless;
|
||||
// the original PE remains read only.
|
||||
import ghidra.app.decompiler.DecompInterface;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Function;
|
||||
|
||||
public class ExportAiVmHandler8Callees extends GhidraScript {
|
||||
private static final long[] ADDRESSES = {0x10002e90L, 0x10005710L};
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
DecompInterface decompiler = new DecompInterface();
|
||||
decompiler.openProgram(currentProgram);
|
||||
for (long value : ADDRESSES) {
|
||||
Address address = currentProgram.getAddressFactory().getDefaultAddressSpace()
|
||||
.getAddress(value);
|
||||
Function function = currentProgram.getFunctionManager().getFunctionAt(address);
|
||||
println("===== AI Handler(8) callee " + address + " =====");
|
||||
if (function == null) { println("missing"); continue; }
|
||||
println(decompiler.decompileFunction(function, 60, monitor).getDecompiledFunction().getC());
|
||||
}
|
||||
decompiler.dispose();
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
// Emits the state-transition helpers selected by Handler(8). Run headless;
|
||||
// the original PE remains read only.
|
||||
import ghidra.app.decompiler.DecompInterface;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Function;
|
||||
|
||||
public class ExportAiVmHandler8Transitions extends GhidraScript {
|
||||
private static final long[] ADDRESSES = {0x10005010L, 0x10005040L};
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
DecompInterface decompiler = new DecompInterface();
|
||||
decompiler.openProgram(currentProgram);
|
||||
for (long value : ADDRESSES) {
|
||||
Address address = currentProgram.getAddressFactory().getDefaultAddressSpace()
|
||||
.getAddress(value);
|
||||
Function function = currentProgram.getFunctionManager().getFunctionAt(address);
|
||||
println("===== AI Handler(8) transition " + address + " =====");
|
||||
if (function == null) { println("missing"); continue; }
|
||||
println(decompiler.decompileFunction(function, 60, monitor).getDecompiledFunction().getC());
|
||||
}
|
||||
decompiler.dispose();
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
// Emits the routine that receives the AI VM's verified 73-entry handler table.
|
||||
// Run through Ghidra headless analysis; the original PE remains read only.
|
||||
import ghidra.app.decompiler.DecompInterface;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Function;
|
||||
|
||||
public class ExportAiVmTableInstall extends GhidraScript {
|
||||
private static final long ADDRESS = 0x10011E70L;
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
Address address = currentProgram.getAddressFactory().getDefaultAddressSpace()
|
||||
.getAddress(ADDRESS);
|
||||
Function function = currentProgram.getFunctionManager().getFunctionAt(address);
|
||||
println("===== AI VM handler table install =====");
|
||||
if (function == null) { println("missing"); return; }
|
||||
DecompInterface decompiler = new DecompInterface();
|
||||
decompiler.openProgram(currentProgram);
|
||||
println(decompiler.decompileFunction(function, 60, monitor).getDecompiledFunction().getC());
|
||||
decompiler.dispose();
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
// Emits the function containing the observed AniMesh Control-loader sequence.
|
||||
import ghidra.app.decompiler.DecompInterface;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Function;
|
||||
|
||||
public class ExportAniMeshControlCaller extends GhidraScript {
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
Address address = currentProgram.getAddressFactory().getDefaultAddressSpace()
|
||||
.getAddress(0x100032e7L);
|
||||
Function function = currentProgram.getFunctionManager().getFunctionContaining(address);
|
||||
println("===== AniMesh Control caller =====");
|
||||
if (function == null) { println("missing"); return; }
|
||||
println("entry=" + function.getEntryPoint());
|
||||
DecompInterface decompiler = new DecompInterface();
|
||||
decompiler.openProgram(currentProgram);
|
||||
println(decompiler.decompileFunction(function, 60, monitor).getDecompiledFunction().getC());
|
||||
decompiler.dispose();
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
// Emits decompiled C for the stable public Control.dll exports.
|
||||
// Run only through Ghidra headless analysis; it does not modify the input PE.
|
||||
import ghidra.app.decompiler.DecompInterface;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Function;
|
||||
|
||||
public class ExportControlFunctions extends GhidraScript {
|
||||
private static final String[] NAMES = {
|
||||
"InitializeSettings", "LoadControlSystem", "LoadPhysicalModel",
|
||||
"CreateCollManager", "CreateCollObject"
|
||||
};
|
||||
private static final long[] ADDRESSES = {
|
||||
0x10032260L, 0x10032280L, 0x10032580L, 0x100325d0L, 0x10032600L
|
||||
};
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
DecompInterface decompiler = new DecompInterface();
|
||||
decompiler.openProgram(currentProgram);
|
||||
for (int index = 0; index < NAMES.length; index++) {
|
||||
Address address = currentProgram.getAddressFactory()
|
||||
.getDefaultAddressSpace().getAddress(ADDRESSES[index]);
|
||||
Function function = currentProgram.getFunctionManager().getFunctionAt(address);
|
||||
println("\n===== " + NAMES[index] + " =====");
|
||||
if (function == null) {
|
||||
println("missing");
|
||||
continue;
|
||||
}
|
||||
println(decompiler.decompileFunction(function, 60, monitor)
|
||||
.getDecompiledFunction().getC());
|
||||
}
|
||||
decompiler.dispose();
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
// Emits the live CreateSuperAI host callback selected by the GOG AutoDemo.
|
||||
// Run headless; the original PE remains read only.
|
||||
import ghidra.app.decompiler.DecompInterface;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Function;
|
||||
|
||||
public class ExportIron3dAiCallback extends GhidraScript {
|
||||
private static final long ADDRESS = 0x100611d0L;
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
Address address = currentProgram.getAddressFactory().getDefaultAddressSpace()
|
||||
.getAddress(ADDRESS);
|
||||
Function function = currentProgram.getFunctionManager().getFunctionAt(address);
|
||||
println("===== Iron3D CreateSuperAI callback =====");
|
||||
if (function == null) { println("missing"); return; }
|
||||
DecompInterface decompiler = new DecompInterface();
|
||||
decompiler.openProgram(currentProgram);
|
||||
println(decompiler.decompileFunction(function, 120, monitor).getDecompiledFunction().getC());
|
||||
decompiler.dispose();
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
// Emits the command-one consumer reached from the recovered CreateSuperAI
|
||||
// host callback. Run headless; the original PE remains read only.
|
||||
import ghidra.app.decompiler.DecompInterface;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Function;
|
||||
|
||||
public class ExportIron3dAiCallbackCommand1 extends GhidraScript {
|
||||
private static final long ADDRESS = 0x10095160L;
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
Address address = currentProgram.getAddressFactory().getDefaultAddressSpace()
|
||||
.getAddress(ADDRESS);
|
||||
Function function = currentProgram.getFunctionManager().getFunctionAt(address);
|
||||
println("===== Iron3D CreateSuperAI callback command 1 =====");
|
||||
if (function == null) { println("missing"); return; }
|
||||
DecompInterface decompiler = new DecompInterface();
|
||||
decompiler.openProgram(currentProgram);
|
||||
println(decompiler.decompileFunction(function, 120, monitor).getDecompiledFunction().getC());
|
||||
decompiler.dispose();
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
// Emits command one's selected-node dispatch callee. Run headless; the
|
||||
// original PE remains read only.
|
||||
import ghidra.app.decompiler.DecompInterface;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Function;
|
||||
|
||||
public class ExportIron3dAiCallbackCommand1Dispatch extends GhidraScript {
|
||||
private static final long ADDRESS = 0x10095600L;
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
Address address = currentProgram.getAddressFactory().getDefaultAddressSpace()
|
||||
.getAddress(ADDRESS);
|
||||
Function function = currentProgram.getFunctionManager().getFunctionAt(address);
|
||||
println("===== Iron3D callback command 1 node dispatch =====");
|
||||
if (function == null) { println("missing"); return; }
|
||||
DecompInterface decompiler = new DecompInterface();
|
||||
decompiler.openProgram(currentProgram);
|
||||
println(decompiler.decompileFunction(function, 120, monitor).getDecompiledFunction().getC());
|
||||
decompiler.dispose();
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
// Locates callers that reference the stable AI script-loader literals.
|
||||
// Run through Ghidra headless analysis; the original PE is read only.
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Function;
|
||||
import ghidra.program.model.mem.Memory;
|
||||
import ghidra.program.model.symbol.Reference;
|
||||
import ghidra.program.model.symbol.ReferenceManager;
|
||||
|
||||
public class FindAiScriptLoaderReferences extends GhidraScript {
|
||||
private static final String[] NEEDLES = {".scr", "MISSIONS\\SCRIPTS\\"};
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
Memory memory = currentProgram.getMemory();
|
||||
ReferenceManager references = currentProgram.getReferenceManager();
|
||||
for (String needle : NEEDLES) {
|
||||
byte[] bytes = (needle + "\0").getBytes("US-ASCII");
|
||||
Address address = memory.findBytes(memory.getMinAddress(), memory.getMaxAddress(), bytes, null, true, monitor);
|
||||
println("===== " + needle + " =====");
|
||||
if (address == null) { println("missing"); continue; }
|
||||
println("literal=" + address);
|
||||
for (Reference reference : references.getReferencesTo(address)) {
|
||||
Function caller = currentProgram.getFunctionManager().getFunctionContaining(reference.getFromAddress());
|
||||
println("reference=" + reference.getFromAddress() + " caller=" + (caller == null ? "missing" : caller.getEntryPoint()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
// Finds writers and readers of Handler(30)'s callback pointer, then decompiles
|
||||
// their containing functions. Run headless; the original PE remains read only.
|
||||
import ghidra.app.decompiler.DecompInterface;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Function;
|
||||
import ghidra.program.model.symbol.Reference;
|
||||
|
||||
public class FindAiVmHandler30Callback extends GhidraScript {
|
||||
private static final long ADDRESS = 0x100555e4L;
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
Address address = currentProgram.getAddressFactory().getDefaultAddressSpace()
|
||||
.getAddress(ADDRESS);
|
||||
DecompInterface decompiler = new DecompInterface();
|
||||
decompiler.openProgram(currentProgram);
|
||||
for (Reference reference : currentProgram.getReferenceManager().getReferencesTo(address)) {
|
||||
Function function = currentProgram.getFunctionManager()
|
||||
.getFunctionContaining(reference.getFromAddress());
|
||||
println("===== callback reference " + reference.getFromAddress() + " =====");
|
||||
if (function == null) { println("no containing function"); continue; }
|
||||
println(decompiler.decompileFunction(function, 60, monitor).getDecompiledFunction().getC());
|
||||
}
|
||||
decompiler.dispose();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user