mirror of
https://github.com/jtang613/IDAssist
synced 2026-08-09 12:43:55 +00:00
Updates.
This commit is contained in:
+1
-1
@@ -3,7 +3,7 @@
|
||||
"plugin": {
|
||||
"name": "IDAssist",
|
||||
"entryPoint": "idassist_plugin.py",
|
||||
"version": "1.2.0",
|
||||
"version": "1.3.0",
|
||||
"description": "AI-powered reverse engineering plugin with LLM analysis, semantic knowledge graphs, RAG search, and SymGraph collaboration",
|
||||
"license": "MIT",
|
||||
"urls": {
|
||||
|
||||
@@ -590,6 +590,21 @@ class SymGraphController(QObject):
|
||||
else:
|
||||
self.view.set_binary_info("<no binary loaded>", None)
|
||||
|
||||
def _get_symbol_provenance(self, is_auto: bool, address: int, symbol_type: str) -> str:
|
||||
"""Determine symbol provenance: decompiler, llm, or user."""
|
||||
if is_auto:
|
||||
return 'decompiler'
|
||||
try:
|
||||
from src.services.analysis_db_service import AnalysisDBService
|
||||
binary_hash = self._get_sha256()
|
||||
if binary_hash:
|
||||
db = AnalysisDBService()
|
||||
if db.is_llm_renamed(binary_hash, address, symbol_type):
|
||||
return 'llm'
|
||||
except Exception:
|
||||
pass
|
||||
return 'user'
|
||||
|
||||
def _get_sha256(self) -> Optional[str]:
|
||||
"""Get SHA256 hash of the original binary."""
|
||||
return get_binary_hash() or None
|
||||
@@ -1006,7 +1021,7 @@ class SymGraphController(QObject):
|
||||
'name': func_name,
|
||||
'data_type': data_type,
|
||||
'confidence': 0.5 if is_auto else 0.9,
|
||||
'provenance': 'decompiler' if is_auto else 'user'
|
||||
'provenance': self._get_symbol_provenance(is_auto, func.start_ea, 'function')
|
||||
}
|
||||
|
||||
def _is_auto_generated_name(self, name: str) -> bool:
|
||||
@@ -1221,7 +1236,7 @@ class SymGraphController(QObject):
|
||||
'raw_content': node.raw_code,
|
||||
'llm_summary': node.llm_summary,
|
||||
'confidence': confidence,
|
||||
'provenance': 'user' if node.user_edited else 'decompiler',
|
||||
'provenance': 'user' if node.user_edited else ('llm' if node.llm_summary else 'decompiler'),
|
||||
}
|
||||
|
||||
if node.security_flags:
|
||||
|
||||
@@ -189,7 +189,7 @@ class ActionsService:
|
||||
execute_on_main_thread(_do_rename)
|
||||
|
||||
if result_holder[0]:
|
||||
# Sync rename to knowledge graph (best-effort)
|
||||
# Sync rename to knowledge graph and record LLM provenance (best-effort)
|
||||
try:
|
||||
from .analysis_db_service import AnalysisDBService
|
||||
from .graphrag.graph_store import GraphStore
|
||||
@@ -199,10 +199,12 @@ class ActionsService:
|
||||
bh_holder[0] = get_binary_hash()
|
||||
execute_on_main_thread(_get_hash)
|
||||
if bh_holder[0]:
|
||||
gs = GraphStore(AnalysisDBService())
|
||||
db = AnalysisDBService()
|
||||
gs = GraphStore(db)
|
||||
gs.update_node_name(bh_holder[0], function_address, new_name)
|
||||
db.record_llm_rename(bh_holder[0], function_address, 'function', new_name)
|
||||
except Exception as e:
|
||||
log.log_warn(f"Graph name sync failed (non-fatal): {e}")
|
||||
log.log_warn(f"Graph/provenance sync failed (non-fatal): {e}")
|
||||
|
||||
return ActionResult(
|
||||
success=True,
|
||||
@@ -262,6 +264,19 @@ class ActionsService:
|
||||
execute_on_main_thread(_do_rename)
|
||||
|
||||
if result_holder[0]:
|
||||
# Record LLM rename for provenance tracking (best-effort)
|
||||
try:
|
||||
from .analysis_db_service import AnalysisDBService
|
||||
from src.ida_compat import get_binary_hash
|
||||
bh_holder = [None]
|
||||
def _get_hash():
|
||||
bh_holder[0] = get_binary_hash()
|
||||
execute_on_main_thread(_get_hash)
|
||||
if bh_holder[0]:
|
||||
AnalysisDBService().record_llm_rename(bh_holder[0], function_address, 'variable', new_name)
|
||||
except Exception as e:
|
||||
log.log_warn(f"Provenance record failed (non-fatal): {e}")
|
||||
|
||||
return ActionResult(
|
||||
success=True,
|
||||
message=f"Renamed variable from '{var_name}' to '{new_name}'",
|
||||
@@ -320,6 +335,19 @@ class ActionsService:
|
||||
execute_on_main_thread(_do_rename)
|
||||
|
||||
if result_holder[0]:
|
||||
# Record LLM rename for provenance tracking (best-effort)
|
||||
try:
|
||||
from .analysis_db_service import AnalysisDBService
|
||||
from src.ida_compat import get_binary_hash
|
||||
bh_holder = [None]
|
||||
def _get_hash():
|
||||
bh_holder[0] = get_binary_hash()
|
||||
execute_on_main_thread(_get_hash)
|
||||
if bh_holder[0]:
|
||||
AnalysisDBService().record_llm_rename(bh_holder[0], function_address, 'variable', new_name)
|
||||
except Exception as e:
|
||||
log.log_warn(f"Provenance record failed (non-fatal): {e}")
|
||||
|
||||
return ActionResult(
|
||||
success=True,
|
||||
message=f"Renamed stack variable '{var_name}' to '{new_name}'",
|
||||
|
||||
@@ -1826,6 +1826,37 @@ class AnalysisDBService:
|
||||
log.log_error(f"Database cleanup failed: {e}")
|
||||
return {"expired_contexts": 0, "old_chat_messages": 0}
|
||||
|
||||
def record_llm_rename(self, binary_id: str, address: int, symbol_type: str, new_name: str):
|
||||
"""Record that a symbol was renamed by an LLM suggestion."""
|
||||
try:
|
||||
conn = self._get_connection()
|
||||
cursor = conn.cursor()
|
||||
cursor.execute(
|
||||
"INSERT OR REPLACE INTO llm_renames (binary_id, address, symbol_type, new_name, created_at) "
|
||||
"VALUES (?, ?, ?, ?, ?)",
|
||||
(binary_id, address, symbol_type, new_name, int(__import__('time').time()))
|
||||
)
|
||||
conn.commit()
|
||||
conn.close()
|
||||
except Exception as e:
|
||||
log.log_error(f"Failed to record LLM rename: {e}")
|
||||
|
||||
def is_llm_renamed(self, binary_id: str, address: int, symbol_type: str) -> bool:
|
||||
"""Check if a symbol at the given address was renamed by an LLM."""
|
||||
try:
|
||||
conn = self._get_connection()
|
||||
cursor = conn.cursor()
|
||||
cursor.execute(
|
||||
"SELECT COUNT(*) FROM llm_renames WHERE binary_id = ? AND address = ? AND symbol_type = ?",
|
||||
(binary_id, address, symbol_type)
|
||||
)
|
||||
result = cursor.fetchone()[0] > 0
|
||||
conn.close()
|
||||
return result
|
||||
except Exception as e:
|
||||
log.log_error(f"Failed to check LLM rename: {e}")
|
||||
return False
|
||||
|
||||
def vacuum_database(self) -> bool:
|
||||
"""Optimize database by running VACUUM"""
|
||||
try:
|
||||
|
||||
@@ -80,6 +80,7 @@ class DatabaseMigrations:
|
||||
(4, DatabaseMigrations._migration_004_graphrag_tables),
|
||||
(5, DatabaseMigrations._migration_005_graphrag_communities),
|
||||
(6, DatabaseMigrations._migration_006_graphrag_fts),
|
||||
(7, DatabaseMigrations._migration_007_llm_renames),
|
||||
]
|
||||
|
||||
for version, migration_func in migrations:
|
||||
@@ -494,6 +495,33 @@ class DatabaseMigrations:
|
||||
log.log_warn(f"Migration 006 issue: {e}. FTS5 may be unavailable.")
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def _migration_007_llm_renames(db_path: str) -> bool:
|
||||
"""Migration 007: LLM renames tracking table"""
|
||||
try:
|
||||
conn = sqlite3.connect(db_path)
|
||||
cursor = conn.cursor()
|
||||
|
||||
cursor.execute('''
|
||||
CREATE TABLE IF NOT EXISTS llm_renames (
|
||||
binary_id TEXT NOT NULL,
|
||||
address INTEGER NOT NULL,
|
||||
symbol_type TEXT NOT NULL DEFAULT 'function',
|
||||
new_name TEXT NOT NULL,
|
||||
created_at INTEGER NOT NULL,
|
||||
PRIMARY KEY (binary_id, address, symbol_type)
|
||||
)
|
||||
''')
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
log.log_info("Migration 007: llm_renames table created successfully")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
log.log_error(f"Migration 007 failed: {e}")
|
||||
return False
|
||||
|
||||
|
||||
class DatabaseCleanup:
|
||||
"""Database cleanup utilities"""
|
||||
|
||||
@@ -351,6 +351,18 @@ def _rename_function(args: Dict) -> List['TextContent']:
|
||||
if result_holder[2]:
|
||||
return [TextContent(type="text", text=f"Error: {result_holder[2]}")]
|
||||
if result_holder[0]:
|
||||
# Record LLM rename for provenance tracking (best-effort)
|
||||
try:
|
||||
from .analysis_db_service import AnalysisDBService
|
||||
from src.ida_compat import get_binary_hash
|
||||
bh_holder = [None]
|
||||
def _get_hash():
|
||||
bh_holder[0] = get_binary_hash()
|
||||
execute_on_main_thread(_get_hash)
|
||||
if bh_holder[0]:
|
||||
AnalysisDBService().record_llm_rename(bh_holder[0], ea, 'function', new_name)
|
||||
except Exception:
|
||||
pass
|
||||
return [TextContent(type="text", text=f"Renamed '{result_holder[1]}' to '{new_name}'")]
|
||||
else:
|
||||
return [TextContent(type="text", text=f"Failed to rename function to '{new_name}'")]
|
||||
|
||||
Reference in New Issue
Block a user