mirror of
https://github.com/chipsec/chipsec
synced 2026-06-08 13:31:00 +00:00
ac2ca7264f
UEFI shell. 2. Decompression of images in SPI flash parsing is only supported in Windows. 3. UEFI - Support for IA32 and i586 (Quark) 4. Added capability to use modules from an arbitrary path with the -I / --import command line option 5. Module functionality encapsulated in class inheriting BaseModule 6. Fixed loading platform specific configuration 7. Fixed issue with modules which run on multiple logical CPUs hanging on Bay Trail (Windows/Linux). The issue still exist when running from UEFI shell 8. Added template for a module - module_template.py 9. Added options to flush log files 10. Added ability to define custom platforms Driver changes: 1. Windows - Added IOCTL_ALLOC_PHYSMEM to allocate physical memory buffer 2. Linux - Fix wrpci defect
443 lines
14 KiB
Python
443 lines
14 KiB
Python
#!/usr/local/bin/python
|
|
#CHIPSEC: Platform Security Assessment Framework
|
|
#Copyright (c) 2010-2014, Intel Corporation
|
|
#
|
|
#This program is free software; you can redistribute it and/or
|
|
#modify it under the terms of the GNU General Public License
|
|
#as published by the Free Software Foundation; Version 2.
|
|
#
|
|
#This program is distributed in the hope that it will be useful,
|
|
#but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
#GNU General Public License for more details.
|
|
#
|
|
#You should have received a copy of the GNU General Public License
|
|
#along with this program; if not, write to the Free Software
|
|
#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
#
|
|
#Contact information:
|
|
#chipsec@intel.com
|
|
#
|
|
|
|
|
|
|
|
# -------------------------------------------------------------------------------
|
|
#
|
|
# CHIPSEC: Platform Hardware Security Assessment Framework
|
|
# (c) 2010-2012 Intel Corporation
|
|
#
|
|
# -------------------------------------------------------------------------------
|
|
## \addtogroup core
|
|
# __chipsec/logger.py__ - logging functions
|
|
#
|
|
#
|
|
|
|
import platform
|
|
import string
|
|
import sys
|
|
import os
|
|
from time import localtime, strftime
|
|
|
|
from chipsec.xmlout import xmlAux
|
|
import traceback
|
|
|
|
|
|
RESET =0
|
|
BRIGHT =1
|
|
DIM =2
|
|
UNDERLINE =3
|
|
BLINK =4
|
|
REVERSE =7
|
|
HIDDEN =8
|
|
|
|
BLACK =0
|
|
RED =1
|
|
GREEN =2
|
|
YELLOW =3
|
|
BLUE =4
|
|
MAGENTA =5
|
|
CYAN =6
|
|
WHITE =7
|
|
|
|
LOG_PATH = os.path.join( os.getcwd(), "logs" )
|
|
#LOG_STATUS_FILE_NAME = ""
|
|
#LOG_COMPLETED_FILE_NAME = ""
|
|
|
|
#
|
|
# Colored output
|
|
#
|
|
if "windows" == platform.system().lower():
|
|
|
|
try:
|
|
import WConio
|
|
|
|
COLOR_ID = {
|
|
BLACK : WConio.BLACK,
|
|
RED : WConio.LIGHTRED,
|
|
GREEN : WConio.LIGHTGREEN,
|
|
YELLOW : WConio.YELLOW,
|
|
BLUE : WConio.LIGHTBLUE,
|
|
MAGENTA: WConio.MAGENTA,
|
|
CYAN : WConio.CYAN,
|
|
WHITE : WConio.WHITE
|
|
}
|
|
|
|
def log_color( fg_color, text ):
|
|
# Store current attribute settings
|
|
old_setting = WConio.gettextinfo()[4] & 0x00FF
|
|
WConio.textattr( COLOR_ID[ fg_color ] )
|
|
print text
|
|
WConio.textattr( old_setting )
|
|
|
|
except ImportError, e:
|
|
#print "WConio package is not installed. No colored output"
|
|
def log_color( fg_color, text ):
|
|
print text
|
|
|
|
elif "linux" == platform.system().lower():
|
|
def log_color( fg_color, text ):
|
|
#_text = "\033[%dm" + text + "\033[0m" % (fg_color + 30) #FIXME: _text = "\033[%dm" + text + "\033[0m" % (fg_color + 30) \n TypeError: not all arguments converted during string formatting
|
|
|
|
print text #_text
|
|
|
|
else:
|
|
def log_color( fg_color, text ):
|
|
print text
|
|
|
|
|
|
|
|
|
|
class LoggerError (RuntimeWarning):
|
|
pass
|
|
|
|
class Logger:
|
|
"""Class for logging to console, text file or XML."""
|
|
|
|
def __init__( self ):
|
|
"""The Constructor."""
|
|
pass
|
|
self.mytime = localtime()
|
|
self.logfile = None
|
|
self.ALWAYS_FLUSH = False
|
|
#Used for interaction with XML output classes.
|
|
self.xmlAux = xmlAux()
|
|
#self._set_log_files()
|
|
|
|
def set_xml_file(self, name=None):
|
|
self.xmlAux.set_xml_file(name)
|
|
|
|
def saveXML(self):
|
|
self.xmlAux.saveXML()
|
|
|
|
def set_log_file( self, name=None ):
|
|
"""Sets the log file for the output."""
|
|
# Close current log file if it's opened
|
|
self.disable()
|
|
self.LOG_FILE_NAME = name
|
|
# specifying name=None effectively disables logging to file
|
|
if self.LOG_FILE_NAME:
|
|
# Open new log file and keep it opened
|
|
try:
|
|
self.logfile = open( self.LOG_FILE_NAME, 'a+' )
|
|
self.LOG_TO_FILE = True
|
|
except None:
|
|
print ("WARNING: Could not open log file '%s'" % name)
|
|
|
|
def set_default_log_file( self ):
|
|
"""Sets the default log file for the output."""
|
|
# Close current log file if it's opened
|
|
self.disable()
|
|
if not os.path.exists( LOG_PATH ): os.makedirs( LOG_PATH )
|
|
self.LOG_FILE_NAME = os.path.join( LOG_PATH, strftime( '%Y_%m_%d__%H%M%S', self.mytime ) + '.log')
|
|
# Open new log file and keep it opened
|
|
try:
|
|
self.logfile = open( self.LOG_FILE_NAME, 'a+' )
|
|
self.LOG_TO_FILE = True
|
|
except None:
|
|
print ("WARNING: Could not open log file '%s'" % self.LOG_FILE_NAME)
|
|
|
|
def set_status_log_file( self ):
|
|
"""Sets the status log file for the output."""
|
|
if not os.path.exists(LOG_PATH):
|
|
os.makedirs(LOG_PATH)
|
|
self.LOG_STATUS_FILE_NAME = os.path.join( LOG_PATH, strftime('%Y_%m_%d__%H%M%S', self.mytime ) + '_results.log')
|
|
self.LOG_TO_STATUS_FILE = True
|
|
|
|
def close( self ):
|
|
"""Closes the log file."""
|
|
if self.logfile:
|
|
try:
|
|
self.logfile.close()
|
|
except None:
|
|
print 'WARNING: Could not close log file'
|
|
finally:
|
|
self.logfile = None
|
|
|
|
def disable( self ):
|
|
"""Disables the logging to file and closes the file if any."""
|
|
self.LOG_TO_FILE = False
|
|
self.LOG_FILE_NAME = None
|
|
self.close()
|
|
#self.LOG_TO_STATUS_FILE = False
|
|
#self.LOG_STATUS_FILE_NAME = None
|
|
|
|
def __del__(self):
|
|
"""Disables the logger."""
|
|
self.disable()
|
|
|
|
######################################################################
|
|
# Logging functions
|
|
######################################################################
|
|
|
|
def flush(self):
|
|
sys.stdout.flush()
|
|
if self.LOG_TO_FILE and self.logfile is not None:
|
|
# not sure why flush doesn't work as excpected
|
|
# self.logfile.flush()
|
|
# close and re-open log file
|
|
try:
|
|
self.logfile.close()
|
|
self.logfile = open( self.LOG_FILE_NAME, 'a+' )
|
|
except None:
|
|
self.disable()
|
|
|
|
|
|
def set_always_flush( self, val ):
|
|
self.ALWAYS_FLUSH = val
|
|
|
|
def log( self, text):
|
|
"""Sends plain text to logging."""
|
|
self._log(text, None, None)
|
|
|
|
|
|
def _log(self, text, color, isStatus):
|
|
"""Internal method for logging"""
|
|
if self.LOG_TO_FILE: self._save_to_log_file( text )
|
|
else:
|
|
if color: log_color( color, text )
|
|
else:
|
|
print text
|
|
if self.ALWAYS_FLUSH: sys.stdout.flush()
|
|
if self.xmlAux.useXML: self.xmlAux.append_stdout(text)
|
|
if isStatus: self._save_to_status_log_file( text )
|
|
|
|
def error( self, text ):
|
|
"""Logs an Error message"""
|
|
text = "ERROR: " + text
|
|
self._log(text, RED, None)
|
|
|
|
def warn( self, text ):
|
|
"""Logs an Warning message"""
|
|
text = "WARNING: " + text
|
|
self._log(text, YELLOW, None)
|
|
|
|
def log_passed_check( self, text ):
|
|
"""Logs a Test as PASSED, this is used for XML output.
|
|
If XML file was not specified, then it will just print a PASSED test message.
|
|
"""
|
|
self.log_passed(text)
|
|
self.xmlAux.passed_check()
|
|
|
|
def log_failed_check( self, text ):
|
|
"""Logs a Test as FAILED, this is used for XML output.
|
|
If XML file was not specified, then it will just print a FAILED test message.
|
|
"""
|
|
self.log_failed(text)
|
|
self.xmlAux.failed_check( text )
|
|
|
|
def log_error_check( self, text ):
|
|
"""Logs a Test as ERROR, this is used for XML output.
|
|
If XML file was not specified, then it will just print a ERROR test message.
|
|
"""
|
|
self.error(text)
|
|
self.xmlAux.error_check( text )
|
|
|
|
def log_skipped_check( self, text ):
|
|
"""Logs a Test as SKIPPED, this is used for XML output.
|
|
If XML file was not specified, then it will just print a SKIPPED test message.
|
|
"""
|
|
self.log_skipped(text)
|
|
self.xmlAux.skipped_check( text )
|
|
|
|
def log_warn_check( self, text ):
|
|
"""Logs a Warning test, a warning test is considered equal to a PASSED test.
|
|
Logs a Test as PASSED, this is used for XML output."""
|
|
self.log_warning(text)
|
|
self.xmlAux.passed_check()
|
|
|
|
|
|
def log_passed( self, text ):
|
|
"""Logs a passed message."""
|
|
text = "[+] PASSED: " + text
|
|
self._log(text, GREEN, True)
|
|
|
|
def log_failed( self, text ):
|
|
"""Logs a failed message."""
|
|
text = "[-] FAILED: " + text
|
|
self._log(text, RED, True)
|
|
|
|
def log_warning( self, text ):
|
|
"""Logs a Warning message"""
|
|
text = "[!] WARNING: " + text
|
|
self._log(text, YELLOW, None)
|
|
#self.xmlAux.passed_check()
|
|
|
|
def log_skipped( self, text ):
|
|
"""Logs a skipped message."""
|
|
text = "[*] SKIPPED: " + text
|
|
self._log(text, YELLOW, True)
|
|
|
|
def log_heading( self, text ):
|
|
"""Logs a heading message."""
|
|
self._log(text, BLUE, None)
|
|
|
|
def log_important( self, text ):
|
|
"""Logs a important message."""
|
|
text = "[!] " + text
|
|
self._log(text, RED, None)
|
|
|
|
def log_result( self, text ):
|
|
"""Logs a result message."""
|
|
text = "[+] " + text
|
|
self._log(text, GREEN, None)
|
|
|
|
def log_bad( self, text ):
|
|
"""Logs a bad message, so it calls attention in the information displayed."""
|
|
text = "[-] " + text
|
|
self._log(text, RED, None)
|
|
|
|
def log_good( self, text ):
|
|
"""Logs a message, if colors available, displays in green."""
|
|
text = "[+] " + text
|
|
self._log(text, GREEN, None)
|
|
|
|
def log_unknown( self, text ):
|
|
"""Logs a message with a question mark."""
|
|
text = "[?] " + text
|
|
self._log(text, None, None)
|
|
|
|
def start_test( self, test_name ):
|
|
"""Logs the start point of a Test, this is used for XML output.
|
|
If XML file was not specified, it will just display a banner for the test name.
|
|
"""
|
|
text = "[x][ =======================================================================\n"
|
|
text = text + "[x][ Test: " + test_name + "\n"
|
|
text = text + "[x][ ======================================================================="
|
|
self._log(text, BLUE, True)
|
|
self.xmlAux.start_test( test_name )
|
|
|
|
|
|
def start_module( self, module_name ):
|
|
"""Displays a banner for the module name provided."""
|
|
text = "\n[+] imported %s" % module_name
|
|
self._log(text, WHITE, None)
|
|
self.xmlAux.start_module( module_name )
|
|
|
|
def end_module( self, module_name ):
|
|
#text = "\n[-] *** Done *** %s" % module_name
|
|
#self._log(text, None, None)
|
|
self.xmlAux.end_module( module_name )
|
|
|
|
def _write_log( self, text, filename ):
|
|
"""
|
|
#with open( filename, 'a+' ) as f:
|
|
# print >> f, text
|
|
f = open( filename, 'a+' )
|
|
try:
|
|
print >> f, text
|
|
finally:
|
|
f.close()
|
|
"""
|
|
print >> self.logfile, text
|
|
if self.ALWAYS_FLUSH:
|
|
# not sure why flush doesn't work as excpected
|
|
# self.logfile.flush()
|
|
# close and re-open log file
|
|
try:
|
|
self.logfile.close()
|
|
self.logfile = open( self.LOG_FILE_NAME, 'a+' )
|
|
except None:
|
|
self.disable()
|
|
|
|
def _save_to_status_log_file(self, text):
|
|
if(self.LOG_TO_STATUS_FILE):
|
|
self._write_log(text, self.LOG_STATUS_FILE_NAME)
|
|
|
|
def _save_to_log_file(self, text):
|
|
if(self.LOG_TO_FILE):
|
|
self._write_log(text, self.LOG_FILE_NAME)
|
|
|
|
VERBOSE = False
|
|
UTIL_TRACE = False
|
|
LOG_TO_STATUS_FILE = False
|
|
LOG_TO_FILE = False
|
|
LOG_STATUS_FILE_NAME = ""
|
|
LOG_FILE_NAME = ""
|
|
DEBUG = False
|
|
|
|
_logger = Logger()
|
|
def logger():
|
|
"""Returns a Logger instance."""
|
|
return _logger
|
|
|
|
|
|
##################################################################################
|
|
# Hex dump functions
|
|
##################################################################################
|
|
|
|
def dump_buffer( arr, length = 8 ):
|
|
"""Dumps the buffer."""
|
|
tmp=[]
|
|
tmp_str=[]
|
|
i=1
|
|
for c in arr:
|
|
tmp+=["%2.2x "%ord(c)]
|
|
#if 0xD == ord(c) or 0xA == ord(c):
|
|
if c in string.whitespace:
|
|
ch = " "
|
|
else:
|
|
ch = ord(c)
|
|
tmp_str+=["%c"%ch]
|
|
if i%length==0:
|
|
tmp+=["| "]
|
|
tmp+=tmp_str
|
|
tmp+=["\n"]
|
|
tmp_str=[]
|
|
#print tmp
|
|
#print "\n"
|
|
i+=1
|
|
if 0 != len(arr)%length:
|
|
tmp+=[ (length - len(arr)%length) * 3*" " ]
|
|
tmp+=["| "]
|
|
tmp+=tmp_str
|
|
tmp+=["\n"]
|
|
return "".join(tmp)
|
|
|
|
def print_buffer( arr, length = 16 ):
|
|
"""Prints the buffer."""
|
|
tmp=[]
|
|
tmp_str=[]
|
|
i=1
|
|
for c in arr:
|
|
tmp+=["%2.2x "%ord(c)]
|
|
if (not c in string.printable) or (c in string.whitespace):
|
|
ch = " "
|
|
else:
|
|
ch = ord(c)
|
|
tmp_str+=["%c"%ch]
|
|
if i%length==0:
|
|
tmp+=["| "]
|
|
tmp+=tmp_str
|
|
tmp_s = "".join(tmp)
|
|
logger().log( tmp_s )
|
|
tmp_str=[]
|
|
tmp=[]
|
|
i+=1
|
|
|
|
if 0 != len(arr)%length:
|
|
tmp+=[ (length - len(arr)%length) * 3*" " ]
|
|
tmp+=["| "]
|
|
tmp+=tmp_str
|
|
tmp_s = "".join(tmp)
|
|
logger().log( tmp_s )
|