@ -15,6 +15,7 @@ import os
@@ -15,6 +15,7 @@ import os
READELF_CMD = os . getenv ( ' READELF ' , ' /usr/bin/readelf ' )
OBJDUMP_CMD = os . getenv ( ' OBJDUMP ' , ' /usr/bin/objdump ' )
NONFATAL = { ' HIGH_ENTROPY_VA ' } # checks which are non-fatal for now but only generate a warning
def check_ELF_PIE ( executable ) :
'''
@ -117,26 +118,50 @@ def check_ELF_Canary(executable):
@@ -117,26 +118,50 @@ def check_ELF_Canary(executable):
def get_PE_dll_characteristics ( executable ) :
'''
Get PE DllCharacteristics bits
Get PE DllCharacteristics bits .
Returns a tuple ( arch , bits ) where arch is ' i386:x86-64 ' or ' i386 '
and bits is the DllCharacteristics value .
'''
p = subprocess . Popen ( [ OBJDUMP_CMD , ' -x ' , executable ] , stdout = subprocess . PIPE , stderr = subprocess . PIPE , stdin = subprocess . PIPE )
( stdout , stderr ) = p . communicate ( )
if p . returncode :
raise IOError ( ' Error opening file ' )
arch = ' '
bits = 0
for line in stdout . split ( ' \n ' ) :
tokens = line . split ( )
if len ( tokens ) > = 2 and tokens [ 0 ] == ' architecture: ' :
arch = tokens [ 1 ] . rstrip ( ' , ' )
if len ( tokens ) > = 2 and tokens [ 0 ] == ' DllCharacteristics ' :
return int ( tokens [ 1 ] , 16 )
return 0
bits = int ( tokens [ 1 ] , 16 )
return ( arch , bits )
IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA = 0x0020
IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE = 0x0040
IMAGE_DLL_CHARACTERISTICS_NX_COMPAT = 0x0100
def check_PE_PIE ( executable ) :
def check_PE_DYNAMIC_BAS E ( executable ) :
''' PIE: DllCharacteristics bit 0x40 signifies dynamicbase (ASLR) '''
return bool ( get_PE_dll_characteristics ( executable ) & 0x40 )
( arch , bits ) = get_PE_dll_characteristics ( executable )
reqbits = IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE
return ( bits & reqbits ) == reqbits
# On 64 bit, must support high-entropy 64-bit address space layout randomization in addition to DYNAMIC_BASE
# to have secure ASLR.
def check_PE_HIGH_ENTROPY_VA ( executable ) :
''' PIE: DllCharacteristics bit 0x20 signifies high-entropy ASLR '''
( arch , bits ) = get_PE_dll_characteristics ( executable )
if arch == ' i386:x86-64 ' :
reqbits = IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA
else : # Unnecessary on 32-bit
assert ( arch == ' i386 ' )
reqbits = 0
return ( bits & reqbits ) == reqbits
def check_PE_NX ( executable ) :
''' NX: DllCharacteristics bit 0x100 signifies nxcompat (DEP) '''
return bool ( get_PE_dll_characteristics ( executable ) & 0x100 )
( arch , bits ) = get_PE_dll_characteristics ( executable )
return ( bits & IMAGE_DLL_CHARACTERISTICS_NX_COMPAT ) == IMAGE_DLL_CHARACTERISTICS_NX_COMPAT
CHECKS = {
' ELF ' : [
@ -146,7 +171,8 @@ CHECKS = {
@@ -146,7 +171,8 @@ CHECKS = {
( ' Canary ' , check_ELF_Canary )
] ,
' PE ' : [
( ' PIE ' , check_PE_PIE ) ,
( ' DYNAMIC_BASE ' , check_PE_DYNAMIC_BASE ) ,
( ' HIGH_ENTROPY_VA ' , check_PE_HIGH_ENTROPY_VA ) ,
( ' NX ' , check_PE_NX )
]
}
@ -171,12 +197,18 @@ if __name__ == '__main__':
@@ -171,12 +197,18 @@ if __name__ == '__main__':
continue
failed = [ ]
warning = [ ]
for ( name , func ) in CHECKS [ etype ] :
if not func ( filename ) :
failed . append ( name )
if name in NONFATAL :
warning . append ( name )
else :
failed . append ( name )
if failed :
print ( ' %s : failed %s ' % ( filename , ' ' . join ( failed ) ) )
retval = 1
if warning :
print ( ' %s : warning %s ' % ( filename , ' ' . join ( warning ) ) )
except IOError :
print ( ' %s : cannot open ' % filename )
retval = 1