mirror of
https://github.com/idapython/src
synced 2026-06-08 14:47:00 +00:00
139 lines
4.5 KiB
Python
Executable File
139 lines
4.5 KiB
Python
Executable File
"""
|
|
summary: Add missing inodes in dirtree structure in "/lost+found" directory
|
|
|
|
description:
|
|
How to collects inodes for various dirtrees ('Local Types', 'Names',
|
|
'Functions', 'Imports', 'Address bookmark' and 'Breakpoints') in both
|
|
the dirtree structure and the database.
|
|
Create a directory an links inodes to them in the dirtree structure
|
|
You cannot add all inodes to the "/lost+found" directory because inodes
|
|
can be at various places in a dirtree structure.
|
|
The early dirtree implementations were not perfect and may have missed to
|
|
add some inodes in the tree structure, this script corrects this issue.
|
|
|
|
keywords: dirtree, recovery
|
|
"""
|
|
|
|
import ida_dirtree
|
|
from ida_dirtree import dirtree_t
|
|
import ida_typeinf
|
|
import ida_funcs
|
|
import ida_name
|
|
import ida_dbg
|
|
import ida_nalt
|
|
import ida_kernwin
|
|
import ida_moves
|
|
|
|
|
|
def get_ltypes_inode(n):
|
|
inode = n + 1
|
|
name = ida_typeinf.get_numbered_type_name(None, inode)
|
|
if name is None:
|
|
# if the name is None, we have a #deleted type,
|
|
# present in flat mode but not in fulltree mode
|
|
return True, None
|
|
else:
|
|
return False, inode
|
|
|
|
|
|
def get_func_inode(n):
|
|
inode = ida_funcs.getn_func(n).start_ea
|
|
return False, inode
|
|
|
|
|
|
def get_name_inode(n):
|
|
inode = ida_name.get_nlist_ea(n)
|
|
if inode is None:
|
|
print(hex(inode))
|
|
return False, inode
|
|
|
|
|
|
list_inodes_in_idb = []
|
|
def get_import_list():
|
|
def imp_cb(ea, name, ordinal):
|
|
list_inodes_in_idb.append(ea)
|
|
return True
|
|
nimps = ida_nalt.get_import_module_qty()
|
|
for i in range(nimps):
|
|
ida_nalt.enum_import_names(i, imp_cb)
|
|
list_inodes_in_idb.sort()
|
|
return len(list_inodes_in_idb)
|
|
|
|
|
|
def get_nth_inode_in_idb(n):
|
|
return False, list_inodes_in_idb[n]
|
|
|
|
|
|
def get_idaplace_list_inodes_in_idb():
|
|
id = ida_kernwin.get_place_class_id("idaplace_t")
|
|
p = ida_kernwin.get_place_class_template(id)
|
|
r = ida_moves.renderer_info_t()
|
|
l = ida_moves.lochist_entry_t(p, r)
|
|
for idx in range(ida_moves.bookmarks_t.size(l, None)):
|
|
ida_moves.bookmarks_t.get(l, idx, None)
|
|
idaloc = ida_kernwin.place_t.as_idaplace_t(l.place())
|
|
list_inodes_in_idb.append(idaloc.ea)
|
|
list_inodes_in_idb.sort()
|
|
return len(list_inodes_in_idb)
|
|
|
|
|
|
def get_bpt_inode(n):
|
|
bpt = ida_dbg.bpt_t()
|
|
if not ida_dbg.getn_bpt(n, bpt):
|
|
return True, None
|
|
return False, bpt.bptid
|
|
|
|
|
|
class dt_collect_inode_t(ida_dirtree.dirtree_visitor_t):
|
|
def __init__(self):
|
|
ida_dirtree.dirtree_visitor_t.__init__(self)
|
|
self.list_inodes_in_dirtree = []
|
|
def visit(self, c, de):
|
|
if dirtree_t.isfile(de):
|
|
self.list_inodes_in_dirtree.append(de.idx)
|
|
return 0
|
|
|
|
|
|
std_recovery_data = [
|
|
( ida_dirtree.DIRTREE_LOCAL_TYPES, ida_typeinf.get_ordinal_count, get_ltypes_inode, "Local Types" ),
|
|
( ida_dirtree.DIRTREE_FUNCS, ida_funcs.get_func_qty, get_func_inode, "Local Types" ),
|
|
( ida_dirtree.DIRTREE_NAMES, ida_name.get_nlist_size, get_name_inode, "Names" ),
|
|
( ida_dirtree.DIRTREE_IMPORTS, get_import_list, get_nth_inode_in_idb, "Imports" ),
|
|
( ida_dirtree.DIRTREE_IDAPLACE_BOOKMARKS, get_idaplace_list_inodes_in_idb, get_nth_inode_in_idb, "Address bookmarks" ),
|
|
( ida_dirtree.DIRTREE_BPTS, ida_dbg.get_bpt_qty, get_bpt_inode, "Breakpoints" ),
|
|
]
|
|
|
|
|
|
for dt_id, get_count_and_maybe_list_inodes_in_idb, get_inode, title in std_recovery_data:
|
|
dt = ida_dirtree.get_std_dirtree(dt_id)
|
|
print("### Dirtree ", title)
|
|
list_inodes_in_idb = []
|
|
collector = dt_collect_inode_t()
|
|
dt.traverse(collector)
|
|
set_inodes_in_dirtree = set(collector.list_inodes_in_dirtree)
|
|
nb_inodes = get_count_and_maybe_list_inodes_in_idb()
|
|
nb_not_list = 0
|
|
nb_list = len(set_inodes_in_dirtree)
|
|
print("Number of unique inodes in the idb: %d\nNumber of unique inodes in fulltree mode: %d"%(nb_inodes, nb_list))
|
|
|
|
if nb_list < nb_inodes:
|
|
err = dt.mkdir("/lost+found")
|
|
if err != ida_dirtree.DTE_OK:
|
|
print(dt.errstr(err))
|
|
err = dt.chdir("/lost+found")
|
|
if err != ida_dirtree.DTE_OK:
|
|
print(dt.errstr(err))
|
|
for n in range(nb_inodes):
|
|
inc, inode = get_inode(n)
|
|
if inode is not None:
|
|
if inode not in set_inodes_in_dirtree:
|
|
err = dt.link(inode)
|
|
if err != ida_dirtree.DTE_OK:
|
|
print("Failed to link inode ", hex(inode), " ", dt.errstr(err) )
|
|
inc = True
|
|
if inc:
|
|
nb_not_list += 1
|
|
if nb_inodes == nb_list + nb_not_list:
|
|
break
|
|
|