Skip to content

Commit

Permalink
Running all the way through, again.
Browse files Browse the repository at this point in the history
  • Loading branch information
svidovich committed Mar 9, 2020
1 parent 948bc67 commit 610df95
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 76 deletions.
80 changes: 45 additions & 35 deletions firmware_tools/ghidra/vxhunter_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ def __init__(self, firmware, vx_version=5, big_endian=False, logger=None):
if logger is None:
self.logger = logging.getLogger(__name__)
# FIXME: Log level
self.logger.setLevel(logging.DEBUG)
self.logger.setLevel(logging.INFO)
consolehandler = logging.StreamHandler()
console_format = logging.Formatter('[%(levelname)-8s][%(module)s.%(funcName)s] %(message)s')
consolehandler.setFormatter(console_format)
Expand All @@ -111,7 +111,7 @@ def prepare(self):
self.find_symbol_table()
if self._has_symbol is False:
return None
self.logger.debug("has_symbol: %s" % self._has_symbol)
self.logger.debug("has_symbol: {}".format(self._has_symbol))
self.get_symbol_table()

def _check_vxworks_endian(self):
Expand Down Expand Up @@ -255,8 +255,7 @@ def find_symbol_table(self):

if self._check_symbol_format_simple(check_data):
self.symbol_table_end = i + self._symbol_interval
# FIXME: Uncomment eventually
# self.logger.debug("self.symbol_table_end: {:010x}".format(self.symbol_table_end))
self.logger.debug("self.symbol_table_end: {:010x}".format(self.symbol_table_end))

else:
self.logger.info("Symbol table end offset: {}".format(hex(self.symbol_table_end)))
Expand Down Expand Up @@ -507,41 +506,45 @@ def _check_fix(self, func_index, str_index):
:param str_index:
:return:
"""
fault_count = 0
try:
fault_count = 0
self.logger.debug("Symbol table's first element: {}".format(self._symbol_table[0]))
if len(self._symbol_table) <= default_check_count:
count = len(self._symbol_table)
self.logger.debug("Length of symbol table, {}, is less than default. Setting iteration count to actual length of table, {}.".format(len(self._symbol_table), count))
else:
count = default_check_count
self.logger.debug("Length of symbol table, {}, is greater than default. Setting iteration count to default, {}.".format(len(self._symbol_table), count))
for i in range(count):

if len(self._symbol_table) < default_check_count:
count = len(self._symbol_table)
else:
count = default_check_count
for i in range(count):
self.logger.debug("str_index: {}".format(str_index))
self.logger.debug("self._string_table[str_index]: {}".format(self._string_table[str_index]))
self.logger.debug("func_index: {}".format(func_index))
self.logger.debug("self._symbol_table[func_index]: {}".format(self._symbol_table[func_index]))
if (func_index >= len(self._symbol_table)) or (str_index >= len(self._string_table)):
self.logger.debug("_check_fix False: func_index greater than length of _symbol_table, or str_index greater than length of _string_table.")
return False
self.logger.debug("str_index: {}; _string_table[str_index]: {}".format(str_index, self._string_table[str_index]))
self.logger.debug("func_index: {}; _symbol_table[func_index]: {}".format(func_index, self._symbol_table[func_index]))
if i == count - 1:
if fault_count < 10:
self.logger.debug("_check_fix True")
return True
else:
self.logger.debug("_check_fix False: Too many faults.")
return False

if (func_index >= len(self._symbol_table)) or (str_index >= len(self._string_table)):
self.logger.debug("_check_fix False: func_index greater than length of _symbol_table, or str_index greater than length of _string_table.")
return False
if i == count - 1:
if fault_count < 10:
self.logger.debug("_check_fix True")
return True
if self._string_table[str_index]['length'] == self._symbol_table[func_index]['symbol_name_length']:
func_index += 1
str_index += 1
self.logger.debug("_check_fix continue")

elif self._symbol_table[func_index]['symbol_name_length'] < self._string_table[str_index]['length']:
# Sometime Symbol name might point to mid of string.
fault_count += 1
func_index += 1
else:
self.logger.debug("_check_fix False: Too many faults.")
self.logger.debug("_check_fix False: symbol_name_length from func_index larger than length from str_index.")
return False

if self._string_table[str_index]['length'] == self._symbol_table[func_index]['symbol_name_length']:
func_index += 1
str_index += 1
self.logger.debug("_check_fix continue")

elif self._symbol_table[func_index]['symbol_name_length'] < self._string_table[str_index]['length']:
# Sometime Symbol name might point to mid of string.
fault_count += 1
func_index += 1
else:
self.logger.debug("_check_fix False: symbol_name_length from func_index larger than length from str_index.")
return False
except Exception as e:
self.logger.exception(e)
raise

def find_loading_address(self):
""" Find VxWorks image load address by automatic analysis.
Expand All @@ -568,6 +571,12 @@ def find_loading_address(self):

str_start_address, str_end_address = self.find_string_table_by_key_function_index(key_function_index)
self.get_string_table(str_start_address, str_end_address)
import json
with open('/Users/mydriasis/Desktop/symbol_table.log', 'w') as file_handle:
file_handle.write(json.dumps(self._symbol_table))
with open('/Users/mydriasis/Desktop/string_table.log', 'w') as file_handle:
file_handle.write(json.dumps(self._string_table))

# TODO: Need improve performance
self.logger.info("Starting loading address analysis")
for str_index in range(len(self._string_table)):
Expand Down Expand Up @@ -595,6 +604,7 @@ def _check_load_address(self, address):
if not self._has_symbol:
return False
if len(self._symbol_table) > default_check_count:
self.logger.debug("Length of symbol table greater than default. Setting iteration count to default of {}.".format(default_check_count))
count = default_check_count
else:
count = len(self._symbol_table)
Expand Down
16 changes: 7 additions & 9 deletions firmware_tools/ghidra/vxhunter_firmware_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@

# Logger setup
logger = logging.getLogger(__name__)
# FIXME: Log level
logger.setLevel(logging.DEBUG)
logger.setLevel(logging.INFO)
consolehandler = logging.StreamHandler()
console_format = logging.Formatter('[%(levelname)-8s][%(module)s] %(message)s')
consolehandler.setFormatter(console_format)
Expand All @@ -24,15 +23,13 @@
pass

try:
# vx_version = askChoice("Choice", "Please choose VxWorks main Version ", ["5.x", "6.x"], "5.x")
# if vx_version == u"5.x":
# vx_version = 5
vx_version = askChoice("Choice", "Please choose VxWorks main Version ", ["5.x", "6.x"], "5.x")
if vx_version == u"5.x":
vx_version = 5

# elif vx_version == u"6.x":
# vx_version = 6
elif vx_version == u"6.x":
vx_version = 6

# FIXME: Reimplement choice. Set to 6 for debugging purposes.
vx_version = 6
if vx_version:
firmware_path = currentProgram.domainFile.getMetadata()['Executable Location']
firmware = open(firmware_path, 'rb').read()
Expand Down Expand Up @@ -69,6 +66,7 @@
add_symbol(symbol_name, symbol_name_addr, symbol_dest_addr, symbol_flag)

except Exception as err:
logger.error("add_symbol failed: {}".format(err))
continue

else:
Expand Down
4 changes: 0 additions & 4 deletions firmware_tools/ghidra/vxhunter_utility/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,10 @@
import logging
import time


# The Python module that Ghidra directly launches is always called __main__. If we import
# everything from that module, this module will behave as if Ghidra directly launched it.
from __main__ import *


debug = False
process_is_64bit = False

Expand All @@ -33,12 +31,10 @@
else:
is_big_endian = False


process_type = currentProgram.domainFile.getMetadata()[u'Processor']
if process_type.endswith(u'64'):
process_is_64bit = True


demangler = GnuDemangler()
listing = currentProgram.getListing()
can_demangle = demangler.canDemangle(currentProgram)
Expand Down
70 changes: 42 additions & 28 deletions firmware_tools/ghidra/vxhunter_utility/symbol.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,25 @@

import logging
import string
import struct
import sys

# Constants from common
from common import can_demangle
# Objects from common
from common import demangler
# Functions from common
from common import is_address_in_current_program

from ghidra.program.model.util import CodeUnitInsertionException
from ghidra.program.model.data import (CharDataType, UnsignedIntegerDataType, IntegerDataType, UnsignedLongDataType, ShortDataType, PointerDataType, VoidDataType, ByteDataType, ArrayDataType, StructureDataType, EnumDataType)
from ghidra.program.model.symbol import RefType, SourceType
from common import *

# The Python module that Ghidra directly launches is always called __main__. If we import
# everything from that module, this module will behave as if Ghidra directly launched it.
from __main__ import *

logging.basicConfig(level=logging.DEBUG)
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

function_name_key_words = ['bzero', 'usrInit', 'bfill']
Expand Down Expand Up @@ -344,21 +352,25 @@ def demangled_symbol(symbol_string):
sym_demangled = demangler.demangle(symbol_string, False)

except DemangledException as err:
logger.debug("DemangledException: symbol_string: {}, reason:{}".format(symbol_string, err))
logger.debug("First pass demangling failed: symbol_string: {}, reason: {}".format(symbol_string, err))
pass

try:
if not sym_demangled:
if not sym_demangled:
try:
# Temp fix to handle _ prefix function name by remove _ prefix before demangle
sym_demangled = demangler.demangle(symbol_string[1:], False)

except DemangledException as err:
logger.debug("DemangledException: symbol_string: {}, reason:{}".format(symbol_string, err))
except DemangledException as err:
logger.debug("Second pass demangling failed: symbol_string: {}, reason:{}".format(symbol_string, err))
pass

if sym_demangled:
sym_demangled_name = sym_demangled.getSignature(False)

if sym_demangled_name:
logger.debug("sym_demangled_name: {}".format(sym_demangled_name))
if sym_demangled_name:
logger.debug("sym_demangled_name: {}".format(sym_demangled_name))
else:
logger.debug("Demangled symbol name for string {} is None.".format(symbol_string))

return sym_demangled_name

Expand All @@ -372,28 +384,26 @@ def add_symbol(symbol_name, symbol_name_address, symbol_address, symbol_type):
logger.debug("Have symbol name {} at address {}.".format(symbol_name_string, symbol_name_address))
# There might be a problem here. It seems like we're getting exceptions because bogus data exists at locations that
# never gets removed because this code doesn't run...
if getDataAt(symbol_name_address):
logger.debug("Data detected at {}; removing to make room for symbol {}".format(symbol_name_address, symbol_name))
removeDataAt(symbol_name_address)
else:
logger.debug("No data detected at {}. Trying to remove data to make room for symbol {} anyway.".format(symbol_address, symbol_name))
removeDataAt(symbol_name_address)

try:
symbol_name_string = createAsciiString(symbol_name_address).getValue()
logger.debug("symbol_name_string: {}".format(symbol_name_string))

logger.debug("Created ascii string {} at {}.".format(symbol_name_string, symbol_name_address))
except CodeUnitInsertionException as err:
logger.error(err)

except:
logger.error("Failed to create ascii string for symbol named {} at {}: {}".format(symbol_name, symbol_name_address, err))
except Exception as err:
logger.error("Failed to create ascii string for symbol named {} at {}: {}; returning.".format(symbol_name, symbol_name_address, err))
return

if getDataAt(symbol_name_address):
logger.debug("Data detected at {}; removing to make room for symbol {}".format(symbol_name_address, symbol_name))
removeDataAt(symbol_name_address)
else:
logger.debug("No data detected at {}. Moving on...".format(symbol_address))

if getInstructionAt(symbol_address):
logger.debug("removeInstructionAt: {}".format(symbol_address))
logger.debug("Instruction detected at {}; removing to make room for symbol {}".format(symbol_address, symbol_name))
removeInstructionAt(symbol_address)
else:
logger.debug("No instruction found at {}.".format(symbol_address))
logger.debug("No instruction detected at {}. Moving on...".format(symbol_address))

# Demangle symName
try:
Expand All @@ -411,21 +421,28 @@ def add_symbol(symbol_name, symbol_name_address, symbol_address, symbol_type):
# Add original symbol name
createLabel(symbol_address, symbol_name_string, True)

logger.debug("function: {}; sym_demangled_name: {}".format(function, sym_demangled_name))

if function and sym_demangled_name:
# Add demangled string to comment
codeUnit = listing.getCodeUnitAt(symbol_address)
codeUnit.setComment(codeUnit.PLATE_COMMENT, sym_demangled_name)
# Rename function
# TODO: demangle_function can probably be replaced. Function objects in the Ghidra API have each
# of .getName(), .getParameters, and .getReturn.
function_return, function_name, function_parameters = demangle_function(sym_demangled_name)

logger.debug("Demangled function name is: {}".format(function_name))
logger.debug("Demangled function return is: {}".format(function_return))
logger.debug("Demangled function parameters is: {}".format(function_parameters))

if function_name:
function.setName(function_name, SourceType.USER_DEFINED)
# Todo: Add parameters later
# TODO: Add parameters later
# Add original symbol name
createLabel(symbol_address, symbol_name_string, True)
if function is None and sym_demangled_name is not None:
logger.debug('Function for symbol {} was None. In createFunction, one or more functions overlapped the specified address set.'.format(sym_demangled_name))

else:
createLabel(symbol_address, symbol_name_string, True)
Expand All @@ -436,9 +453,6 @@ def add_symbol(symbol_name, symbol_name_address, symbol_address, symbol_type):
except Exception as err:
logger.error("Create symbol failed: symbol_name: {}, symbol_name_address: {}, symbol_address: {}, symbol_type: {} reason: {}".format(symbol_name_string, symbol_name_address, symbol_address, symbol_type, err))

except:
logger.debug("Create symbol failed: symbol_name: {}, symbol_name_address: {}, symbol_address: {}, symbol_type: {} with Unknown error".format(symbol_name_string, symbol_name_address, symbol_address, symbol_type))


def fix_symbol_table_structs(symbol_table_start, symbol_table_end, vx_version):
symbol_interval = 16
Expand All @@ -451,8 +465,8 @@ def fix_symbol_table_structs(symbol_table_start, symbol_table_end, vx_version):
symbol_table_start_addr = toAddr(symbol_table_start)
symbol_table_end_addr = toAddr(symbol_table_end)

ea = symbol_table_start_addr
sym_length = (symbol_table_end - symbol_table_start) // symbol_interval
logger.debug("Fixing symbol table with start at {} and end at {} with length {}.".format(symbol_table_start_addr, symbol_table_end_addr, sym_length))
createLabel(symbol_table_start_addr, "vxSymTbl", True)
clearListing(symbol_table_start_addr, symbol_table_end_addr)
vx_symbol_array_data_type = ArrayDataType(dt, sym_length, dt.getLength())
Expand Down

0 comments on commit 610df95

Please sign in to comment.