vector-uefi/fd/tool/chipsec/helper/win/win32helper.py
#!/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 helpers
# __chipsec/helper/win/win32helper.py__ -- Management and communication with Windows kernel mode driver
# which provides access to hardware resources
# NOTE: on Windows you need to install pywin32 Python extension corresponding to your Python version:
# http://sourceforge.net/projects/pywin32/
#
#
__version__ = '1.0'
import os.path
import struct
import sys
from ctypes import *
from threading import Lock
import platform
import re
from collections import namedtuple
from chipsec.helper.oshelper import OsHelperError
import errno
import pywintypes
import win32service #win32serviceutil, win32api, win32con
import winerror
from win32file import FILE_SHARE_READ, FILE_SHARE_WRITE, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, FILE_FLAG_OVERLAPPED, INVALID_HANDLE_VALUE
import win32api, win32process, win32security, win32file
from chipsec.logger import logger, print_buffer
import chipsec.file
class PCI_BDF(Structure):
_fields_ = [("BUS", c_ushort, 16), # Bus
("DEV", c_ushort, 16), # Device
("FUNC", c_ushort, 16), # Function
("OFF", c_ushort, 16)] # Offset
kernel32 = windll.kernel32
drv_hndl_error_msg = "Cannot open chipsec driver handle. Make sure chipsec driver is installed and started if you are using option -e (see README)"
DRIVER_FILE_NAME = "chipsec_hlpr.sys"
DEVICE_FILE = "\\\\.\\chipsec_hlpr"
SERVICE_NAME = "chipsec"
DISPLAY_NAME = "CHIPSEC Service"
CHIPSEC_INSTALL_PATH = os.path.join(sys.prefix, "Lib\site-packages\chipsec")
# Defines for Win32 API Calls
GENERIC_READ = 0x80000000
GENERIC_WRITE = 0x40000000
OPEN_EXISTING = 0x3
FILE_DEVICE_UNKNOWN = 0x00000022
METHOD_BUFFERED = 0
METHOD_IN_DIRECT = 1
METHOD_OUT_DIRECT = 2
METHOD_NEITHER = 3
FILE_ANY_ACCESS = 0
FILE_SPECIAL_ACCESS = (FILE_ANY_ACCESS)
FILE_READ_ACCESS = ( 0x0001 )
FILE_WRITE_ACCESS = ( 0x0002 )
def CTL_CODE( DeviceType, Function, Method, Access ):
return ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method)
#
# chipsec driver IOCTL codes
#
CHIPSEC_CTL_ACCESS = (FILE_READ_ACCESS | FILE_WRITE_ACCESS)
CLOSE_DRIVER = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x803, METHOD_BUFFERED, CHIPSEC_CTL_ACCESS)
READ_PCI_CFG_REGISTER = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x807, METHOD_BUFFERED, CHIPSEC_CTL_ACCESS)
WRITE_PCI_CFG_REGISTER = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x808, METHOD_BUFFERED, CHIPSEC_CTL_ACCESS)
IOCTL_READ_PHYSMEM = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x809, METHOD_BUFFERED, CHIPSEC_CTL_ACCESS)
IOCTL_WRITE_PHYSMEM = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80a, METHOD_BUFFERED, CHIPSEC_CTL_ACCESS)
IOCTL_ALLOC_PHYSMEM = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x812, METHOD_BUFFERED, CHIPSEC_CTL_ACCESS)
IOCTL_LOAD_UCODE_PATCH = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80b, METHOD_BUFFERED, CHIPSEC_CTL_ACCESS)
IOCTL_WRMSR = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80c, METHOD_BUFFERED, CHIPSEC_CTL_ACCESS)
IOCTL_RDMSR = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80d, METHOD_BUFFERED, CHIPSEC_CTL_ACCESS)
IOCTL_READ_IO_PORT = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80e, METHOD_BUFFERED, CHIPSEC_CTL_ACCESS)
IOCTL_WRITE_IO_PORT = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80f, METHOD_BUFFERED, CHIPSEC_CTL_ACCESS)
IOCTL_GET_CPU_DESCRIPTOR_TABLE = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x810, METHOD_BUFFERED, CHIPSEC_CTL_ACCESS)
IOCTL_SWSMI = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x811, METHOD_BUFFERED, CHIPSEC_CTL_ACCESS)
#
# NT Errors
#
# Defined in WinDDK\7600.16385.1\inc\api\ntstatus.h
#
#
# UEFI constants
#
# Default buffer size for EFI variables
#EFI_VAR_MAX_BUFFER_SIZE = 128*1024
EFI_VAR_MAX_BUFFER_SIZE = 1024*1024
attributes = {
"EFI_VARIABLE_NON_VOLATILE" : 0x00000001,
"EFI_VARIABLE_BOOTSERVICE_ACCESS" : 0x00000002,
"EFI_VARIABLE_RUNTIME_ACCESS" : 0x00000004,
"EFI_VARIABLE_HARDWARE_ERROR_RECORD" : 0x00000008,
"EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS" : 0x00000010,
"EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS" : 0x00000020,
"EFI_VARIABLE_APPEND_WRITE" : 0x00000040
}
PyLong_AsByteArray = pythonapi._PyLong_AsByteArray
PyLong_AsByteArray.argtypes = [py_object,
c_char_p,
c_size_t,
c_int,
c_int]
def packl_ctypes( lnum, bitlength ):
length = (bitlength + 7)/8
a = create_string_buffer( length )
PyLong_AsByteArray(lnum, a, len(a), 1, 1) # 4th param is for endianness 0 - big, non 0 - little
return a.raw
#
# Windows 8 NtEnumerateSystemEnvironmentValuesEx (infcls = 2)
#
def guid_str(guid0, guid1, guid2, guid3):
return ( "%08X-%04X-%04X-%04s-%06s" % (guid0, guid1, guid2, guid3[:2].encode('hex').upper(), guid3[-6::].encode('hex').upper()) )
class EFI_HDR_WIN( namedtuple('EFI_HDR_WIN', 'Size DataOffset DataSize Attributes guid0 guid1 guid2 guid3') ):
__slots__ = ()
def __str__(self):
return """
Header (Windows)
----------------
VendorGuid= {%08X-%04X-%04X-%04s-%06s}
Size = 0x%08X
DataOffset= 0x%08X
DataSize = 0x%08X
Attributes= 0x%08X
""" % ( self.guid0, self.guid1, self.guid2, self.guid3[:2].encode('hex').upper(), self.guid3[-6::].encode('hex').upper(), self.Size, self.DataOffset, self.DataSize, self.Attributes )
def getEFIvariables_NtEnumerateSystemEnvironmentValuesEx2( nvram_buf ):
start = 0
buffer = nvram_buf
bsize = len(buffer)
header_fmt = "<IIIIIHH8s"
header_size = struct.calcsize( header_fmt )
variables = dict()
off = 0
while (off + header_size) < bsize:
efi_var_hdr = EFI_HDR_WIN( *struct.unpack_from( header_fmt, buffer[ off : off + header_size ] ) )
next_var_offset = off + efi_var_hdr.Size
efi_var_buf = buffer[ off : next_var_offset ]
efi_var_data = buffer[ off + efi_var_hdr.DataOffset : off + efi_var_hdr.DataOffset + efi_var_hdr.DataSize ]
#efi_var_name = "".join( buffer[ start + header_size : start + efi_var_hdr.DataOffset ] ).decode('utf-16-le')
str_fmt = "%ds" % (efi_var_hdr.DataOffset - header_size)
s, = struct.unpack( str_fmt, buffer[ off + header_size : off + efi_var_hdr.DataOffset ] )
efi_var_name = unicode(s, "utf-16-le", errors="replace").split(u'\u0000')[0]
if efi_var_name not in variables.keys():
variables[efi_var_name] = []
# off, buf, hdr, data, guid, attrs
variables[efi_var_name].append( (off, efi_var_buf, efi_var_hdr, efi_var_data, guid_str(efi_var_hdr.guid0, efi_var_hdr.guid1, efi_var_hdr.guid2, efi_var_hdr.guid3), efi_var_hdr.Attributes) )
if 0 == efi_var_hdr.Size: break
off = next_var_offset
return variables
# return ( start, next_var_offset, efi_var_buf, efi_var_hdr, efi_var_name, efi_var_data, guid_str(efi_var_hdr.guid0, efi_var_hdr.guid1, efi_var_hdr.guid2, efi_var_hdr.guid3), efi_var_hdr.Attributes )
class Win32Helper:
def __init__(self):
import platform
self.os_system = platform.system()
self.os_release = platform.release()
self.os_version = platform.version()
self.os_machine = platform.machine()
self.os_uname = platform.uname()
if "windows" == self.os_system.lower():
win_ver = "win7_" + self.os_machine.lower()
if ("5" == self.os_release): win_ver = "winxp"
"""
if ("8" == self.os_release.lower()):
win_ver = "win7_" + self.os_machine.lower()
#elif ("post2008server" == self.os_release.lower()):
elif ("2008server" in self.os_release.lower()):
win_ver = "win7_" + self.os_machine.lower()
elif ("7" == self.os_release.lower()):
win_ver = "win7_" + self.os_machine.lower()
else:
logger().warn( "Unknown OS release: %s %s %s" % (self.os_system, self.os_release, self.os_version) )
win_ver = "win7_" + self.os_machine.lower()
"""
logger().log( "[helper] OS: %s %s %s" % (self.os_system, self.os_release, self.os_version) )
logger().log( "[helper] Using 'helper/win/%s' path for driver" % win_ver )
self.hs = None
self.driver_path = None
self.win_ver = win_ver
self.driver_handle = None
#self.device_file = u"%s" % DEVICE_FILE
self.device_file = pywintypes.Unicode(DEVICE_FILE)
# enable required SeSystemEnvironmentPrivilege privilege
privilege = win32security.LookupPrivilegeValue( None, 'SeSystemEnvironmentPrivilege' )
token = win32security.OpenProcessToken( win32process.GetCurrentProcess(), win32security.TOKEN_READ|win32security.TOKEN_ADJUST_PRIVILEGES )
win32security.AdjustTokenPrivileges( token, False, [(privilege, win32security.SE_PRIVILEGE_ENABLED)] )
win32api.CloseHandle( token )
# import firmware variable API
try:
self.GetFirmwareEnvironmentVariable = kernel32.GetFirmwareEnvironmentVariableW
self.GetFirmwareEnvironmentVariable.restype = c_int
self.GetFirmwareEnvironmentVariable.argtypes = [c_wchar_p, c_wchar_p, c_void_p, c_int]
self.SetFirmwareEnvironmentVariable = kernel32.SetFirmwareEnvironmentVariableW
self.SetFirmwareEnvironmentVariable.restype = c_int
self.SetFirmwareEnvironmentVariable.argtypes = [c_wchar_p, c_wchar_p, c_void_p, c_int]
except AttributeError, msg:
logger().warn( "G[S]etFirmwareEnvironmentVariableW function doesn't seem to exist" )
pass
try:
self.NtEnumerateSystemEnvironmentValuesEx = windll.ntdll.NtEnumerateSystemEnvironmentValuesEx
self.NtEnumerateSystemEnvironmentValuesEx.restype = c_int
self.NtEnumerateSystemEnvironmentValuesEx.argtypes = [c_int, c_void_p, c_void_p]
except AttributeError, msg:
logger().warn( "NtEnumerateSystemEnvironmentValuesEx function doesn't seem to exist" )
pass
c_int_p = POINTER(c_int)
#self.GetFirmwareEnvironmentVariableEx = kernel32.GetFirmwareEnvironmentVariableW
#self.SetFirmwareEnvironmentVariableEx = kernel32.SetFirmwareEnvironmentVariableW
try:
self.GetFirmwareEnvironmentVariableEx = kernel32.GetFirmwareEnvironmentVariableExW
self.GetFirmwareEnvironmentVariableEx.restype = c_int
self.GetFirmwareEnvironmentVariableEx.argtypes = [c_wchar_p, c_wchar_p, c_void_p, c_int, c_int_p]
self.SetFirmwareEnvironmentVariableEx = kernel32.SetFirmwareEnvironmentVariableExW
self.SetFirmwareEnvironmentVariableEx.restype = c_int
self.SetFirmwareEnvironmentVariableEx.argtypes = [c_wchar_p, c_wchar_p, c_void_p, c_int, c_int]
except AttributeError, msg:
logger().warn( "G[S]etFirmwareEnvironmentVariableExW function doesn't seem to exist" )
pass
def __del__(self):
try:
##kernel32.CloseHandle( self.driver_handle )
#win32api.CloseHandle( self.driver_handle )
del self.driver_handle
del self.device_file
#self.delete()
except NameError:
pass
###############################################################################################
# Driver/service management functions
###############################################################################################
def start( self ):
(type, state, ca, exitcode, svc_exitcode, checkpoint, waithint) = win32service.QueryServiceStatus( self.hs )
if logger().VERBOSE: logger().log( "[helper] starting chipsec service: handle = 0x%x, type = 0x%x, state = 0x%x" % (self.hs, type, state) )
if win32service.SERVICE_RUNNING == state:
if logger().VERBOSE: logger().log( "[helper] chipsec service already running" )
else:
try:
win32service.StartService( self.hs, None );
state = win32service.QueryServiceStatus( self.hs )[1]
while win32service.SERVICE_START_PENDING == state:
time.sleep( 1 )
state = win32service.QueryServiceStatus( self.hs )[1]
if win32service.SERVICE_RUNNING == state:
if logger().VERBOSE: logger().log( "[helper] chipsec service started (SERVICE_RUNNING)" )
except win32service.error, (hr, fn, msg):
if (winerror.ERROR_ALREADY_EXISTS == hr):
if logger().VERBOSE: logger().log( "[helper] chipsec service already exists: %s (%d)" % (msg, hr) )
else:
win32service.CloseServiceHandle( self.hs )
self.hs = None
string = "StartService failed: %s (%d)" % (msg, hr)
logger().error( string )
raise OsHelperError(string,hr)
#if logger().VERBOSE:
# logger().log( "[helper] chipsec service handle = 0x%08x" % self.hs )
def create( self ):
logger().log( "" )
logger().warn( "Chipsec should only be used on test systems!" )
logger().warn( "It should not be installed/deployed on production end-user systems." )
logger().warn( "See WARNING.txt" )
logger().log( "" )
try:
hscm = win32service.OpenSCManager( None, None, win32service.SC_MANAGER_ALL_ACCESS ) # SC_MANAGER_CREATE_SERVICE
except win32service.error, (hr, fn, msg):
string = "OpenSCManager failed: %s (%d)" % (msg, hr)
logger().error( string )
raise OsHelperError(string,hr)
if logger().VERBOSE: logger().log( "[helper] SC Manager opened (handle = 0x%08x)" % hscm )
driver_path = os.path.join(chipsec.file.get_main_dir(), "chipsec" , "helper" ,"win" )
driver_path = os.path.join( driver_path, self.win_ver , DRIVER_FILE_NAME )
if os.path.exists( driver_path ) and os.path.isfile( driver_path ):
self.driver_path = driver_path
if logger().VERBOSE: logger().log( "[helper] driver path: '%s'" % os.path.abspath(self.driver_path) )
else:
logger().error( "could not locate driver file '%.256s'" % driver_path )
return False
try:
self.hs = win32service.CreateService( hscm,
SERVICE_NAME,
DISPLAY_NAME,
(win32service.SERVICE_QUERY_STATUS|win32service.SERVICE_START|win32service.SERVICE_STOP), # SERVICE_ALL_ACCESS, STANDARD_RIGHTS_REQUIRED, DELETE
win32service.SERVICE_KERNEL_DRIVER,
win32service.SERVICE_DEMAND_START,
win32service.SERVICE_ERROR_NORMAL,
os.path.abspath(driver_path),
None, 0, u"", None, None )
if not self.hs:
raise win32service.error, (0, None, "hs is None")
if logger().VERBOSE: logger().log( "[helper] service created (handle = 0x%08x)" % self.hs )
except win32service.error, (hr, fn, msg):
#if (winerror.ERROR_SERVICE_EXISTS == hr) or (winerror.ERROR_DUPLICATE_SERVICE_NAME == hr):
if (winerror.ERROR_SERVICE_EXISTS == hr):
if logger().VERBOSE: logger().log( "[helper] chipsec service already exists: %s (%d)" % (msg, hr) )
try:
self.hs = win32service.OpenService( hscm, SERVICE_NAME, (win32service.SERVICE_QUERY_STATUS|win32service.SERVICE_START|win32service.SERVICE_STOP) ) # SERVICE_ALL_ACCESS
except win32service.error, (hr, fn, msg):
self.hs = None
string = "OpenService failed: %s (%d)" % (msg, hr)
logger().error( string )
raise OsHelperError(string,hr)
else:
self.hs = None
string = "CreateService failed: %s (%d)" % (msg, hr)
logger().error( string )
raise OsHelperError(string,hr)
#(type, state, ca, exitcode, svc_exitcode, checkpoint, waithint) = win32service.QueryServiceStatus( self.hs )
#if logger().VERBOSE:
# logger().log( "[helper] chipsec service: handle = 0x%x, type = 0x%x, state = 0x%x (SERVICE_RUNNING is 0x%x)" % (self.hs, type, state, win32service.SERVICE_RUNNING) )
return True
finally:
win32service.CloseServiceHandle( hscm )
def stop( self ):
state = 0
if (self.hs is not None):
if logger().VERBOSE: logger().log( "[helper] stopping service (handle = 0x%08x).." % self.hs )
try:
state = win32service.ControlService( self.hs, win32service.SERVICE_CONTROL_STOP )
#state = win32serviceutil.StopService( name, machine )[1]
except win32service.error, (hr, fn, msg):
logger().error( "StopService failed: %s (%d)" % (msg, hr) )
state = win32service.QueryServiceStatus( self.hs )[1]
#while win32service.SERVICE_STOP_PENDING == state:
# time.sleep( 1 )
# state = win32service.QueryServiceStatus( self.hs )[1]
# Close the driver handle - should do that in __del__ rather than here
#kernel32.CloseHandle( self.driver_handle )
return state
def delete( self ):
if (self.hs is not None):
if logger().VERBOSE:
logger().log( "[helper] deleting service (handle = 0x%08x).." % self.hs )
win32service.DeleteService( self.hs )
win32service.CloseServiceHandle( self.hs )
self.hs = None
return True
def destroy( self ):
self.stop()
self.delete()
def get_driver_handle( self ):
# This is bad but DeviceIoControl fails ocasionally if new device handle is not opened every time ;(
if (self.driver_handle is not None) and (INVALID_HANDLE_VALUE != self.driver_handle):
return self.driver_handle
#self.driver_handle = win32file.CreateFile( device_file, 0, win32file.FILE_SHARE_READ, None, win32file.OPEN_EXISTING, 0, None)
#self.driver_handle = kernel32.CreateFileW( self.device_file, GENERIC_READ | GENERIC_WRITE, 0, None, OPEN_EXISTING, 0, None )
#self.driver_handle = kernel32.CreateFileW( self.device_file, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, None, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, None )
self.driver_handle = win32file.CreateFile( self.device_file, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, None, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, None )
if (self.driver_handle is None) or (INVALID_HANDLE_VALUE == self.driver_handle):
logger().error( drv_hndl_error_msg )
raise OsHelperError(drv_hndl_error_msg,errno.ENXIO)
else:
if logger().VERBOSE: logger().log( "[helper] opened device '%.64s' (handle: %08x)" % (DEVICE_FILE, self.driver_handle) )
return self.driver_handle
def check_driver_handle( self ):
if (0x6 == kernel32.GetLastError()):
#kernel32.CloseHandle( self.driver_handle )
win32api.CloseHandle( self.driver_handle )
self.driver_handle = None
self.get_driver_handle()
logger().warn( "Invalid handle (wtf?): re-opened device '%.64s' (new handle: %08x)" % (self.device_file, self.driver_handle) )
return False
return True
#
# Auxiliary functions
#
def get_threads_count ( self ):
sum = 0
proc_group_count = (kernel32.GetActiveProcessorGroupCount() & 0xFFFF)
for grp in range(proc_group_count):
procs = kernel32.GetActiveProcessorCount( grp )
sum = sum + procs
return sum
def getcwd( self ):
return ("\\\\?\\" + os.getcwd())
#
# Generic IOCTL call function
#
def _ioctl( self, ioctl_code, in_buf, out_length ):
out_buf = (c_char * out_length)()
self.get_driver_handle()
#ret = kernel32.DeviceIoControl( self.driver_handle, ioctl_code, in_buf, len(in_buf), byref(out_buf), out_length, byref(out_size), None )
if logger().VERBOSE: print_buffer( in_buf )
try:
out_buf = win32file.DeviceIoControl( self.driver_handle, ioctl_code, in_buf, out_length, None )
except pywintypes.error, msg:
logger().error( 'DeviceIoControl returned error: %s' % str(msg) )
return None
return out_buf
###############################################################################################
# Actual driver IOCTL functions to access HW resources
###############################################################################################
def read_phys_mem( self, phys_address_hi, phys_address_lo, length ):
out_length = length
out_buf = (c_char * out_length)()
out_size = c_ulong(out_length)
in_buf = struct.pack( '3I', phys_address_hi, phys_address_lo, length )
out_buf = self._ioctl( IOCTL_READ_PHYSMEM, in_buf, out_length )
del in_buf, out_length, out_size
return out_buf
def write_phys_mem( self, phys_address_hi, phys_address_lo, length, buf ):
in_length = length + 12
out_buf = (c_char * 4)()
out_size = c_ulong(4)
in_buf = struct.pack( '3I', phys_address_hi, phys_address_lo, length ) + buf
out_buf = self._ioctl( IOCTL_WRITE_PHYSMEM, in_buf, 4 )
del in_buf, in_length, out_size
return out_buf
def alloc_phys_mem( self, length, max_pa ):
(va, pa) = (0,0)
in_length = 12
out_length = 16
out_buf = (c_char * out_length)()
out_size = c_ulong(out_length)
in_buf = struct.pack( 'QI', max_pa, length )
out_buf = self._ioctl( IOCTL_ALLOC_PHYSMEM, in_buf, out_length )
try:
(va, pa) = struct.unpack( '2Q', out_buf )
except:
logger().error( 'DeviceIoControl did not return 4 DWORD values' )
del in_buf, in_length, out_length, out_size
return (va, pa)
def read_msr( self, cpu_thread_id, msr_addr ):
(eax,edx) = (0,0)
out_length = 8
out_buf = (c_char * out_length)()
out_size = c_ulong(out_length)
in_buf = struct.pack( '=BI', cpu_thread_id, msr_addr )
out_buf = self._ioctl( IOCTL_RDMSR, in_buf, out_length )
try:
(eax, edx) = struct.unpack( '2I', out_buf )
except:
logger().error( 'DeviceIoControl did not return 2 DWORD values' )
del in_buf, out_length, out_size
return (eax, edx)
def write_msr( self, cpu_thread_id, msr_addr, eax, edx ):
out_length = 0
out_buf = (c_char * out_length)()
out_size = c_ulong(out_length)
in_buf = struct.pack( '=B3I', cpu_thread_id, msr_addr, eax, edx )
out_buf = self._ioctl( IOCTL_WRMSR, in_buf, out_length )
del in_buf, out_length, out_size
return
def read_pci_reg( self, bus, device, function, address, size ):
value = 0xFFFFFFFF
bdf = PCI_BDF( bus&0xFFFF, device&0xFFFF, function&0xFFFF, address&0xFFFF )
out_length = size
out_buf = (c_char * out_length)()
out_size = c_ulong(out_length)
in_buf = struct.pack( '4HB', bdf.BUS, bdf.DEV, bdf.FUNC, bdf.OFF, size )
out_buf = self._ioctl( READ_PCI_CFG_REGISTER, in_buf, out_length )
try:
if 1 == size:
value = struct.unpack( 'B', out_buf )[0]
elif 2 == size:
value = struct.unpack( 'H', out_buf )[0]
else:
value = struct.unpack( 'I', out_buf )[0]
except:
logger().error( "DeviceIoControl did not return value of proper size %x (value = '%s')" % (size, out_buf.raw) )
del in_buf, out_length, out_size
return value
def write_pci_reg( self, bus, device, function, address, value, size ):
bdf = PCI_BDF( bus&0xFFFF, device&0xFFFF, function&0xFFFF, address&0xFFFF )
out_length = 0
out_buf = (c_char * out_length)()
out_size = c_ulong(out_length)
in_buf = struct.pack( '4HIB', bdf.BUS, bdf.DEV, bdf.FUNC, bdf.OFF, value, size )
out_buf = self._ioctl( WRITE_PCI_CFG_REGISTER, in_buf, out_length )
del in_buf, out_length, out_size
return
def load_ucode_update( self, cpu_thread_id, ucode_update_buf ):
in_length = len(ucode_update_buf) + 3
out_length = 0
out_buf = (c_char * out_length)()
out_size = c_ulong(out_length)
in_buf = struct.pack( '=BH', cpu_thread_id, len(ucode_update_buf) ) + ucode_update_buf
#print_buffer( in_buf )
out_buf = self._ioctl( IOCTL_LOAD_UCODE_PATCH, in_buf, out_length )
del in_buf, in_length, out_size
return True
def read_io_port( self, io_port, size ):
in_buf = struct.pack( '=HB', io_port, size )
out_buf = self._ioctl( IOCTL_READ_IO_PORT, in_buf, size )
try:
if 1 == size:
value = struct.unpack( 'B', out_buf )[0]
elif 2 == size:
value = struct.unpack( 'H', out_buf )[0]
else:
value = struct.unpack( 'I', out_buf )[0]
except:
logger().error( "DeviceIoControl did not return value of proper size %x (value = '%s')" % (size, out_buf) )
return value
def write_io_port( self, io_port, value, size ):
in_buf = struct.pack( '=HIB', io_port, value, size )
return self._ioctl( IOCTL_WRITE_IO_PORT, in_buf, 0 )
#
# IDTR/GDTR/LDTR
#
def get_descriptor_table( self, cpu_thread_id, desc_table_code ):
in_buf = struct.pack( 'BB', cpu_thread_id, desc_table_code )
out_buf = self._ioctl( IOCTL_GET_CPU_DESCRIPTOR_TABLE, in_buf, 18 )
(limit,base,pa) = struct.unpack( '=HQQ', out_buf )
return (limit,base,pa)
#
# EFI Variable API
#
def get_EFI_variable( self, name, guid, attrs=None ):
efi_var = create_string_buffer( EFI_VAR_MAX_BUFFER_SIZE )
if attrs is None:
if self.GetFirmwareEnvironmentVariable is not None:
if logger().VERBOSE: logger().log( "[helper] calling GetFirmwareEnvironmentVariable( name='%s', GUID='%s' ).." % (name, "{%s}" % guid) )
length = self.GetFirmwareEnvironmentVariable( name, "{%s}" % guid, efi_var, EFI_VAR_MAX_BUFFER_SIZE )
else:
if self.GetFirmwareEnvironmentVariableEx is not None:
pattrs = c_int(attrs)
if logger().VERBOSE: logger().log( "[helper] calling GetFirmwareEnvironmentVariableEx( name='%s', GUID='%s', attrs = 0x%X ).." % (name, "{%s}" % guid, attrs) )
length = self.GetFirmwareEnvironmentVariableEx( name, "{%s}" % guid, efi_var, EFI_VAR_MAX_BUFFER_SIZE, pattrs )
if (0 == length) or (efi_var is None):
if logger().VERBOSE or logger().UTIL_TRACE:
logger().error( 'GetFirmwareEnvironmentVariable[Ex] failed (GetLastError = 0x%x)' % kernel32.GetLastError() )
print WinError()
return None
#raise WinError(errno.EIO,"Unable to get EFI variable")
return efi_var[:length]
def set_EFI_variable( self, name, guid, var, attrs=None ):
var_len = 0
if var is None: var = bytes(0)
else: var_len = len(var)
if attrs is None:
if self.SetFirmwareEnvironmentVariable is not None:
if logger().VERBOSE: logger().log( "[helper] calling SetFirmwareEnvironmentVariable( name='%s', GUID='%s', length=0x%X ).." % (name, "{%s}" % guid, var_len) )
success = self.SetFirmwareEnvironmentVariable( name, "{%s}" % guid, var, var_len )
else:
if self.SetFirmwareEnvironmentVariableEx is not None:
if logger().VERBOSE: logger().log( "[helper] calling SetFirmwareEnvironmentVariableEx( name='%s', GUID='%s', length=0x%X, length=0x%X ).." % (name, "{%s}" % guid, var_len, attrs) )
success = self.SetFirmwareEnvironmentVariableEx( name, "{%s}" % guid, var, var_len, attrs )
if 0 == success:
err = kernel32.GetLastError()
if logger().VERBOSE or logger().UTIL_TRACE:
logger().error( 'SetFirmwareEnvironmentVariable failed (GetLastError = 0x%x)' % err )
print WinError()
#raise WinError(errno.EIO, "Unable to set EFI variable")
return success
def list_EFI_variables( self, infcls=2 ):
if logger().VERBOSE: logger().log( '[helper] calling NtEnumerateSystemEnvironmentValuesEx( infcls=%d )..' % infcls )
efi_vars = create_string_buffer( EFI_VAR_MAX_BUFFER_SIZE )
length = packl_ctypes( long(EFI_VAR_MAX_BUFFER_SIZE), 32 )
status = self.NtEnumerateSystemEnvironmentValuesEx( infcls, efi_vars, length )
status = ( ((1 << 32) - 1) & status)
if (0xC0000023 == status):
retlength, = struct.unpack("<I", length)
efi_vars = create_string_buffer( retlength )
status = self.NtEnumerateSystemEnvironmentValuesEx( infcls, efi_vars, length )
elif (0xC0000002 == status):
logger().warn( 'NtEnumerateSystemEnvironmentValuesEx was not found (NTSTATUS = 0xC0000002)' )
logger().log( '[*] Your Windows does not expose UEFI Runtime Variable API. It was likely installed as legacy boot. To use UEFI variable functions, chipsec needs to run in OS installed with UEFI boot (enable UEFI Boot in BIOS before installing OS)' )
return None
if 0 != status:
logger().error( 'NtEnumerateSystemEnvironmentValuesEx failed (GetLastError = 0x%x)' % kernel32.GetLastError() )
logger().error( '*** NTSTATUS: %08X' % ( ((1 << 32) - 1) & status) )
raise WinError()
# for debug purposes (in case NtEnumerateSystemEnvironmentValuesEx changes format of the output binary)
#from chipsec.file import write_file
#write_file( 'list_EFI_variables.bin', efi_vars )
if logger().VERBOSE: logger().log( '[helper] len(efi_vars) = 0x%X (should be 0x20000)' % len(efi_vars) )
return getEFIvariables_NtEnumerateSystemEnvironmentValuesEx2( efi_vars )
#
# Interrupts
#
def send_sw_smi( self, SMI_code_data, _rax, _rbx, _rcx, _rdx, _rsi, _rdi ):
out_length = 0
out_buf = (c_char * out_length)()
out_size = c_ulong(out_length)
in_buf = struct.pack( '=H6Q', SMI_code_data, _rax, _rbx, _rcx, _rdx, _rsi, _rdi )
out_buf = self._ioctl( IOCTL_SWSMI, in_buf, out_length )
del in_buf, out_length, out_size
return
#
# Get instance of this OS helper
#
def get_helper():
return Win32Helper( )