reverse-skills-max: initial public release (restored, redacted, hardened)

This commit is contained in:
baradok609hecl1pq6qi
2026-10-20 02:17:15 +03:00
commit da24c2bd20
2227 changed files with 443931 additions and 0 deletions

View 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
}
}

View File

@@ -0,0 +1,171 @@
<#
.SYNOPSIS
Start IDA Pro MCP HTTP server (background, non-blocking)
.DESCRIPTION
1. Kill old process
2. Start idalib-mcp HTTP server in hidden window mode
3. Wait for service ready (max 15 seconds)
4. Output result
Usage: run without parameters
#>
param(
[string]$IdaDir,
[int]$Port = 13337,
[string]$ServerPath
)
function Get-InstalledIdaDir {
$registryPaths = @(
'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*',
'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*',
'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*'
)
$fromRegistry = $registryPaths |
ForEach-Object {
Get-ItemProperty $_ -ErrorAction SilentlyContinue
} |
Where-Object {
($_.DisplayName -match 'IDA|Hex-Rays') -and
-not [string]::IsNullOrWhiteSpace($_.InstallLocation) -and
(Test-Path -LiteralPath $_.InstallLocation)
} |
Select-Object -ExpandProperty InstallLocation -First 1
if ($fromRegistry) {
return $fromRegistry
}
$idaCandidates = @(
'C:\Program Files\IDA Pro',
'C:\Program Files\IDA',
'C:\IDA Pro',
'C:\IDA',
'D:\IDA',
'E:\Program Files\IDA',
(Join-Path $env:USERPROFILE 'Tools\IDA')
) | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }
return $idaCandidates | Where-Object { Test-Path -LiteralPath $_ } | Select-Object -First 1
}
if ([string]::IsNullOrWhiteSpace($IdaDir)) {
if (-not [string]::IsNullOrWhiteSpace($env:IDADIR)) {
$IdaDir = $env:IDADIR
} else {
$persistedIdaDir = [Environment]::GetEnvironmentVariable('IDADIR', 'User')
if ([string]::IsNullOrWhiteSpace($persistedIdaDir)) {
$persistedIdaDir = [Environment]::GetEnvironmentVariable('IDADIR', 'Machine')
}
if (-not [string]::IsNullOrWhiteSpace($persistedIdaDir) -and (Test-Path -LiteralPath $persistedIdaDir)) {
$IdaDir = $persistedIdaDir
} else {
# Search registry install records and common fallback paths
$foundIda = Get-InstalledIdaDir
if ($foundIda) {
$IdaDir = $foundIda
} else {
Write-Output "ERR:IDADIR not set and IDA Pro not found. Set IDADIR environment variable."
exit 1
}
}
}
}
$env:IDADIR = $IdaDir
if ([string]::IsNullOrWhiteSpace($ServerPath)) {
# Try both possible executable names (idalib-mcp is the HTTP server, ida-pro-mcp is the installer CLI)
$resolved = Get-Command idalib-mcp -ErrorAction SilentlyContinue
if (-not $resolved) {
$resolved = Get-Command ida-pro-mcp -ErrorAction SilentlyContinue
}
if ($resolved) {
$ServerPath = $resolved.Source
}
else {
$roamingPython = Join-Path $env:APPDATA 'Python'
if (Test-Path -LiteralPath $roamingPython) {
$candidate = Get-ChildItem -LiteralPath $roamingPython -Directory -ErrorAction SilentlyContinue |
ForEach-Object {
$scripts = Join-Path $_.FullName 'Scripts'
@('idalib-mcp.exe', 'ida-pro-mcp.exe') | ForEach-Object { Join-Path $scripts $_ }
} |
Where-Object { Test-Path -LiteralPath $_ } |
Select-Object -First 1
if ($candidate) {
$ServerPath = $candidate
}
}
}
}
# Auto-bootstrap if still not found
if ([string]::IsNullOrWhiteSpace($ServerPath)) {
$bootstrapScript = Join-Path $PSScriptRoot '..\..\scripts\bootstrap-reverse.ps1'
if (Test-Path -LiteralPath $bootstrapScript) {
Write-Output "INFO: ida-pro-mcp not found, attempting auto-bootstrap (installing mrexodia/ida-pro-mcp)..."
& powershell.exe -NoProfile -ExecutionPolicy Bypass -File $bootstrapScript -Capability @('idalib-mcp') -SkipRefresh
$resolved = Get-Command ida-pro-mcp -ErrorAction SilentlyContinue
if (-not $resolved) {
$resolved = Get-Command idalib-mcp -ErrorAction SilentlyContinue
}
if ($resolved) {
$ServerPath = $resolved.Source
}
else {
$roamingPython = Join-Path $env:APPDATA 'Python'
if (Test-Path -LiteralPath $roamingPython) {
$candidate = Get-ChildItem -LiteralPath $roamingPython -Directory -ErrorAction SilentlyContinue |
ForEach-Object {
$scripts = Join-Path $_.FullName 'Scripts'
@('ida-pro-mcp.exe', 'idalib-mcp.exe') | ForEach-Object { Join-Path $scripts $_ }
} |
Where-Object { Test-Path -LiteralPath $_ } |
Select-Object -First 1
if ($candidate) {
$ServerPath = $candidate
}
}
}
}
}
if ([string]::IsNullOrWhiteSpace($ServerPath)) {
throw 'Missing required CLI tool: ida-pro-mcp — auto-bootstrap failed. Install manually: pip install git+https://github.com/mrexodia/ida-pro-mcp.git && ida-pro-mcp --install'
}
# 清理旧进程(杀进程树,包括 worker 子进程)
$old = Get-Process -Name "ida-pro-mcp" -ErrorAction SilentlyContinue
if (-not $old) { $old = Get-Process -Name "idalib-mcp" -ErrorAction SilentlyContinue }
if ($old) {
foreach ($process in @($old)) {
& taskkill.exe /F /T /PID $process.Id 2>$null | Out-Null
}
Start-Sleep 2
}
# 后台启动
Start-Process -WindowStyle Hidden -FilePath $ServerPath -ArgumentList "--host 127.0.0.1 --port $Port"
# 等待就绪
$ready = $false
for ($i = 0; $i -lt 15; $i++) {
Start-Sleep -Seconds 1
try {
$r = Invoke-RestMethod "http://127.0.0.1:$Port/mcp" -Method Post `
-Body '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' `
-ContentType "application/json" -ErrorAction Stop
if ($r.result.tools.Count -gt 0) {
Write-Output "OK:$($r.result.tools.Count)"
$ready = $true
break
}
} catch {}
}
if (-not $ready) {
Write-Output "ERR:timeout"
}