reverse-skills-max: initial public release (restored, redacted, hardened)
This commit is contained in:
235
reverse-skill-repo/skills/ida-reverse/scripts/open.ps1
Normal file
235
reverse-skill-repo/skills/ida-reverse/scripts/open.ps1
Normal file
@@ -0,0 +1,235 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Open binary file via IDA HTTP API (bypass MCP schema issue)
|
||||
.PARAMETER Path
|
||||
Binary file path (required)
|
||||
.PARAMETER SessionId
|
||||
Session ID (optional, auto-generated)
|
||||
.PARAMETER NoAutoAnalysis
|
||||
Skip automatic analysis (faster open for large files)
|
||||
.PARAMETER TimeoutSeconds
|
||||
Open timeout in seconds, returns timeout instead of blocking forever
|
||||
#>
|
||||
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$Path,
|
||||
[string]$SessionId = "",
|
||||
[switch]$NoAutoAnalysis = $false,
|
||||
[int]$TimeoutSeconds = 120
|
||||
)
|
||||
|
||||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
if (-not [string]::IsNullOrWhiteSpace($env:IDADIR)) {
|
||||
$env:IDADIR = $env:IDADIR
|
||||
}
|
||||
else {
|
||||
# Fallback: check common IDA installation paths
|
||||
$idaCandidates = @(
|
||||
'C:\Program Files\IDA Pro',
|
||||
'C:\IDA Pro',
|
||||
'D:\IDA',
|
||||
(Join-Path $env:USERPROFILE 'Tools\IDA')
|
||||
)
|
||||
$foundIda = $idaCandidates | Where-Object { Test-Path -LiteralPath $_ } | Select-Object -First 1
|
||||
if ($foundIda) {
|
||||
$env:IDADIR = $foundIda
|
||||
} else {
|
||||
Write-Error "ERR:IDADIR not set and IDA Pro not found at common paths. Set IDADIR environment variable to your IDA installation directory."
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
$Port = 13337
|
||||
$TempDir = Join-Path $env:TEMP 'reverse-skill'
|
||||
if (-not (Test-Path -LiteralPath $TempDir)) {
|
||||
New-Item -ItemType Directory -Path $TempDir -Force | Out-Null
|
||||
}
|
||||
$PollIntervalMs = 2000
|
||||
$ProgressIntervalSeconds = 10
|
||||
|
||||
function Get-OpenReadySession {
|
||||
param(
|
||||
[string]$ExpectedSessionId,
|
||||
[string]$ExpectedPath,
|
||||
[int]$RequestPort
|
||||
)
|
||||
|
||||
$listBody = '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"idalib_list","arguments":{}}}'
|
||||
$listResult = Invoke-RestMethod "http://127.0.0.1:$RequestPort/mcp" -Method Post -Body $listBody `
|
||||
-ContentType "application/json" -TimeoutSec 10 -ErrorAction Stop
|
||||
|
||||
$sessions = @($listResult.result.structuredContent.sessions)
|
||||
foreach ($candidate in $sessions) {
|
||||
if (-not $candidate) {
|
||||
continue
|
||||
}
|
||||
|
||||
$sameSession = $candidate.session_id -eq $ExpectedSessionId
|
||||
$samePath = $candidate.input_path -eq $ExpectedPath
|
||||
$sameFile = [System.IO.Path]::GetFileName($candidate.input_path) -eq [System.IO.Path]::GetFileName($ExpectedPath)
|
||||
if (($sameSession -or $samePath -or $sameFile) -and $candidate.is_analyzing -eq $false) {
|
||||
return $candidate
|
||||
}
|
||||
}
|
||||
|
||||
return $null
|
||||
}
|
||||
|
||||
if (-not (Test-Path $Path)) {
|
||||
Write-Output "ERR:file_not_found"
|
||||
exit 1
|
||||
}
|
||||
|
||||
if ($TimeoutSeconds -le 0) {
|
||||
Write-Output "ERR:invalid_timeout"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 判断是否用了临时副本(避免递归复制)
|
||||
$isTempCopy = $Path.StartsWith($TempDir, [StringComparison]::OrdinalIgnoreCase)
|
||||
|
||||
# System32 文件自动复制到 Temp
|
||||
if (-not $isTempCopy -and $Path -match "C:\\Windows\\System32") {
|
||||
$Filename = [System.IO.Path]::GetFileName($Path)
|
||||
$TempPath = "$TempDir\$Filename"
|
||||
Copy-Item $Path $TempPath -Force -ErrorAction SilentlyContinue
|
||||
if ($?) {
|
||||
$Path = $TempPath
|
||||
$isTempCopy = $true
|
||||
}
|
||||
}
|
||||
|
||||
# 清理同名旧数据库文件(只在非 Temp 副本时尝试)
|
||||
if (-not $isTempCopy) {
|
||||
$dir = [System.IO.Path]::GetDirectoryName($Path)
|
||||
$base = [System.IO.Path]::GetFileNameWithoutExtension($Path)
|
||||
$oldExts = @(".id0", ".id1", ".id2", ".nam", ".til", ".i64")
|
||||
$hasLocked = $false
|
||||
foreach ($ext in $oldExts) {
|
||||
$f = Join-Path $dir "$base$ext"
|
||||
if (Test-Path $f) {
|
||||
Remove-Item $f -Force -ErrorAction SilentlyContinue
|
||||
if (Test-Path $f) { $hasLocked = $true }
|
||||
}
|
||||
}
|
||||
# 旧数据库文件被锁,自动用 Temp 副本
|
||||
if ($hasLocked) {
|
||||
$guid = [System.Guid]::NewGuid().ToString("N").Substring(0, 8)
|
||||
$newName = "$guid-$([System.IO.Path]::GetFileName($Path))"
|
||||
$TempPath = "$TempDir\$newName"
|
||||
Copy-Item $Path $TempPath -Force
|
||||
$Path = $TempPath
|
||||
$isTempCopy = $true
|
||||
}
|
||||
}
|
||||
|
||||
$autoAnalysis = if ($NoAutoAnalysis) { "false" } else { "true" }
|
||||
$escapedPath = $Path -replace '\\', '\\'
|
||||
|
||||
# 始终使用明确的会话 ID,便于超时时轮询会话状态判断是否已成功打开
|
||||
if (-not $SessionId) {
|
||||
$SessionId = [System.Guid]::NewGuid().ToString("N").Substring(0, 8)
|
||||
}
|
||||
|
||||
$body = @"
|
||||
{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"idalib_open","arguments":{"input_path":"$escapedPath","run_auto_analysis":$autoAnalysis,"session_id":null}}}
|
||||
"@
|
||||
if ($SessionId) {
|
||||
$body = @"
|
||||
{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"idalib_open","arguments":{"input_path":"$escapedPath","run_auto_analysis":$autoAnalysis,"session_id":"$SessionId"}}}
|
||||
"@
|
||||
}
|
||||
|
||||
# 将打开请求放到后台,避免 HTTP 长时间不回包时阻塞整个脚本
|
||||
$openJob = Start-Job -ScriptBlock {
|
||||
param($RequestBody, $RequestPort)
|
||||
try {
|
||||
Invoke-RestMethod "http://127.0.0.1:$RequestPort/mcp" -Method Post -Body $RequestBody `
|
||||
-ContentType "application/json" -ErrorAction Stop
|
||||
} catch {
|
||||
$_.Exception.Message
|
||||
}
|
||||
} -ArgumentList $body, $Port
|
||||
|
||||
$deadline = (Get-Date).AddSeconds($TimeoutSeconds)
|
||||
$openCompleted = $false
|
||||
$startTime = Get-Date
|
||||
$lastProgressAt = $startTime.AddSeconds(-$ProgressIntervalSeconds)
|
||||
|
||||
try {
|
||||
while ((Get-Date) -lt $deadline) {
|
||||
if (Wait-Job -Job $openJob -Timeout 1) {
|
||||
$openCompleted = $true
|
||||
break
|
||||
}
|
||||
|
||||
try {
|
||||
$session = Get-OpenReadySession -ExpectedSessionId $SessionId -ExpectedPath $Path -RequestPort $Port
|
||||
if ($session) {
|
||||
$tag = if ($isTempCopy) { " (temp copy)" } else { "" }
|
||||
Stop-Job -Job $openJob -ErrorAction SilentlyContinue
|
||||
Remove-Job -Job $openJob -Force -ErrorAction SilentlyContinue
|
||||
Write-Output "OK:$($session.filename):$($session.session_id)$tag"
|
||||
exit 0
|
||||
}
|
||||
} catch {}
|
||||
|
||||
$now = Get-Date
|
||||
if (($now - $lastProgressAt).TotalSeconds -ge $ProgressIntervalSeconds) {
|
||||
$elapsed = [math]::Floor(($now - $startTime).TotalSeconds)
|
||||
Write-Output "INFO:opening:$elapsed/${TimeoutSeconds}s"
|
||||
$lastProgressAt = $now
|
||||
}
|
||||
|
||||
Start-Sleep -Milliseconds $PollIntervalMs
|
||||
}
|
||||
|
||||
if (-not $openCompleted) {
|
||||
Stop-Job -Job $openJob -ErrorAction SilentlyContinue
|
||||
Remove-Job -Job $openJob -Force -ErrorAction SilentlyContinue
|
||||
|
||||
try {
|
||||
$session = Get-OpenReadySession -ExpectedSessionId $SessionId -ExpectedPath $Path -RequestPort $Port
|
||||
if ($session) {
|
||||
$tag = if ($isTempCopy) { " (temp copy)" } else { "" }
|
||||
Write-Output "OK:$($session.filename):$($session.session_id)$tag"
|
||||
exit 0
|
||||
}
|
||||
} catch {}
|
||||
|
||||
Write-Output "ERR:open_timeout_${TimeoutSeconds}s"
|
||||
exit 1
|
||||
}
|
||||
|
||||
$jobResult = Receive-Job -Job $openJob
|
||||
Remove-Job -Job $openJob -Force -ErrorAction SilentlyContinue
|
||||
|
||||
if ($jobResult -is [string]) {
|
||||
Write-Output "ERR:$jobResult"
|
||||
exit 1
|
||||
}
|
||||
|
||||
if ($jobResult.result.structuredContent.success -eq $true) {
|
||||
$session = $jobResult.result.structuredContent.session
|
||||
$tag = if ($isTempCopy) { " (temp copy)" } else { "" }
|
||||
Write-Output "OK:$($session.filename):$($session.session_id)$tag"
|
||||
} else {
|
||||
# 自动降级:非 Temp 副本失败时,复制到 Temp 重试
|
||||
if (-not $isTempCopy) {
|
||||
$guid = [System.Guid]::NewGuid().ToString("N").Substring(0, 8)
|
||||
$newName = "$guid-$([System.IO.Path]::GetFileName($Path))"
|
||||
$TempPath = "$TempDir\$newName"
|
||||
Copy-Item $Path $TempPath -Force
|
||||
& $PSCommandPath -Path $TempPath -SessionId $SessionId -NoAutoAnalysis:$NoAutoAnalysis -TimeoutSeconds $TimeoutSeconds
|
||||
} else {
|
||||
Write-Output "ERR:$($jobResult.result.structuredContent.error)"
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if ($openJob) {
|
||||
Stop-Job -Job $openJob -ErrorAction SilentlyContinue
|
||||
Remove-Job -Job $openJob -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user