update to ida 7.6, add builds
This commit is contained in:
162
idasdk76/ldr/script_ldrs/archldr_tar.py
Normal file
162
idasdk76/ldr/script_ldrs/archldr_tar.py
Normal file
@@ -0,0 +1,162 @@
|
||||
# Sample archive loader: TAR file format
|
||||
# Feel free to improve it, this is just a sample
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import tarfile
|
||||
import shutil
|
||||
import tempfile
|
||||
import idaapi
|
||||
from ida_kernwin import Choose
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
def accept_file(li, filename):
|
||||
"""
|
||||
Check input file format.
|
||||
This function will be called one or more times depending on the result value.
|
||||
|
||||
@param li: a file-like object which can be used to access the input data
|
||||
@param filename: name of the file, if it is an archive member name then the actual file doesn't exist
|
||||
@return: 0 - no more supported formats
|
||||
string "name" - format name to display in the chooser dialog
|
||||
dictionary {
|
||||
'format': "name",
|
||||
'options': integer,
|
||||
'flags': integer
|
||||
}
|
||||
options: should be 1,
|
||||
if ORed with ACCEPT_ARCHIVE then it is an archive loader
|
||||
if ORed with ACCEPT_CONTINUE then this function will be called another time
|
||||
if ORed with ACCEPT_FIRST then indicates preferred format
|
||||
loader_flags: see GENFLG_
|
||||
"""
|
||||
li.seek(0)
|
||||
try:
|
||||
t = tarfile.open(fileobj=li, mode='r|*')
|
||||
t.close()
|
||||
(_, ext) = os.path.splitext(filename)
|
||||
if ext not in (".tar", ".tgz", "tar.gz"):
|
||||
return 0
|
||||
return {'format': "TAR archive",
|
||||
'options': 1 | idaapi.ACCEPT_ARCHIVE}
|
||||
except Exception:
|
||||
pass
|
||||
return 0
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
def _read_whole_file(li):
|
||||
li.seek(0)
|
||||
return li.read(li.size())
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
def _tmpnam():
|
||||
(h, n) = tempfile.mkstemp()
|
||||
os.close(h)
|
||||
return n
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
class TarMemberChoose(Choose):
|
||||
"""
|
||||
TAR archive members selection chooser
|
||||
"""
|
||||
|
||||
def __init__(self, archive, items):
|
||||
title = "Archive: " + archive
|
||||
Choose.__init__(
|
||||
self,
|
||||
title,
|
||||
[["File name", Choose.CHCOL_PATH | 60],
|
||||
["Size", Choose.CHCOL_DEC | 10]],
|
||||
icon=-1, y1=-2,
|
||||
flags = Choose.CH_MODAL | Choose.CH_NOIDB)
|
||||
self.items = items
|
||||
|
||||
def OnGetLine(self, n):
|
||||
return [self.items[n].name, str(self.items[n].size)]
|
||||
|
||||
def OnGetSize(self):
|
||||
return len(self.items)
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
def process_archive(li, archive, defmember, neflags, formatname):
|
||||
"""
|
||||
Display list of archive members and let the user select one.
|
||||
Extract the selected archive member into a temporary file.
|
||||
|
||||
@param li: a file-like object which can be used to access the input data
|
||||
@param archive: name of archive
|
||||
@param defmember: extract the specified member
|
||||
@param neflags: options selected by the user, see loader.hpp
|
||||
@param formatname: name of type of the file
|
||||
|
||||
@return: '' cancelled by the user
|
||||
string error message
|
||||
dictionary {
|
||||
'temp_file': string,
|
||||
'module_name': string,
|
||||
'neflags': integer
|
||||
}
|
||||
temp_file: name of the file with the extracted archive member
|
||||
module_name: name of the extracted archive member
|
||||
neflags: options selected by the user, see loader.hpp
|
||||
"""
|
||||
li.seek(0)
|
||||
try:
|
||||
t = tarfile.open(fileobj=li, mode='r|*')
|
||||
except tarfile.TarError as e:
|
||||
return str(e)
|
||||
|
||||
# list of archive members,
|
||||
members = t.getmembers()
|
||||
t.close()
|
||||
|
||||
# we are interested in regular files only
|
||||
items = [members[i] for i in range(0, len(members))]
|
||||
|
||||
# if default archive member is specified
|
||||
if defmember:
|
||||
for m in items:
|
||||
if os.path.basename(m.name) == defmember:
|
||||
selected_item = m
|
||||
break
|
||||
else:
|
||||
return "Unknown TAR archive default member: %s" % defmember
|
||||
else:
|
||||
chooser = TarMemberChoose(archive, items)
|
||||
code = chooser.Show(True)
|
||||
if code == Choose.NO_SELECTION:
|
||||
return "" # user canceled
|
||||
selected_item = items[code]
|
||||
|
||||
# construct archive member name
|
||||
member_name = os.path.basename(selected_item.name)
|
||||
module_name = os.path.join(os.path.dirname(archive), member_name)
|
||||
|
||||
# file for archive member
|
||||
workfile = _tmpnam()
|
||||
|
||||
# extract member
|
||||
# there is a bug reported in 2010 year but not fixed yet:
|
||||
# http://bugs.python.org/issue10436
|
||||
li.seek(0)
|
||||
buf = _read_whole_file(li)
|
||||
(h, workfile_tar) = tempfile.mkstemp()
|
||||
os.write(h, buf)
|
||||
os.close(h)
|
||||
|
||||
t = tarfile.open(name=workfile_tar, mode='r:*')
|
||||
tarinfo = t.getmember(selected_item.name)
|
||||
f_in = t.extractfile(tarinfo)
|
||||
f_out = open(workfile, 'wb')
|
||||
shutil.copyfileobj(f_in, f_out)
|
||||
f_out.close()
|
||||
f_in.close()
|
||||
t.close()
|
||||
os.unlink(workfile_tar)
|
||||
|
||||
return {'temp_file': workfile, 'module_name': module_name}
|
||||
Reference in New Issue
Block a user