7

Based on this IE zero day, I'm interested in listing all DLLs in our systems that have been compiled to not work with ASLR.

Ideally, I'd like to analyze a static file and not load it into memory to detect if it's compiled without ASLR protections.

Lastly, once I have a list of files that are incompatible with ASLR, what can I do to prevent or control them from loading short of uninstalling it?

makerofthings7
  • 50,090
  • 54
  • 250
  • 536

3 Answers3

6

If you just want to know if one DLL supports ASLR, then load it into CFF Explorer, go to the Optional Header section, then click on the DllCharacteristics row. If "DLL can move" is checked, then it's ASLR-enabled, otherwise it's not.

If you want to do a lot of them, I would write a Python script that enumerates all DLLs in a target directory, then checks them using the pefile module. This gives you access to all sorts of information, including the DllCharacteristics field of the PE header, which you can check to see if IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE is set. That'll tell you whether it's ASLR-enabled or not.

In terms of preventing them from loading, there's not much you can do. However, you can use EMET to set Mandatory ASLR on a process to enforce that every DLL loaded gets ASLR enabled, regardless of whether it's set in the PE file or not.

Polynomial
  • 132,208
  • 43
  • 298
  • 379
5

Thanks to @Polynomial for that excellent pefile module suggestion. I threw together a quick python script to do this. There is probably room for improvements but it seems to work decently enough.

import argparse
import os
import pefile


class DllCharacteristics():
    def __init__(self):
        self.IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE = False
        self.IMAGE_DLLCHARACTERISTICS_WDM_DRIVER = False
        self.IMAGE_DLLCHARACTERISTICS_NO_BIND = False
        self.IMAGE_DLLCHARACTERISTICS_NO_SEH = False
        self.IMAGE_DLLCHARACTERISTICS_NO_ISOLATION = False
        self.IMAGE_DLLCHARACTERISTICS_NX_COMPAT = False
        self.IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY = False
        self.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE = False


def get_dll_characteristics(path):
    foo = DllCharacteristics()

    pe = pefile.PE(path, fast_load=True)
    dll_characteristics = pe.OPTIONAL_HEADER.DllCharacteristics

    if dll_characteristics > 0:
        if dll_characteristics >= 32768:
            foo.IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE = True
            dll_characteristics -= 32768

        if dll_characteristics >= 8192:
            foo.IMAGE_DLLCHARACTERISTICS_WDM_DRIVER = True
            dll_characteristics -= 8192

        if dll_characteristics == 2048 or dll_characteristics > 2080:
            foo.IMAGE_DLLCHARACTERISTICS_NO_BIND = True
            dll_characteristics -= 2048

        if dll_characteristics == 1024 or dll_characteristics > 1056:
            foo.IMAGE_DLLCHARACTERISTICS_NO_SEH = True
            dll_characteristics -= 1024

        if dll_characteristics == 512 or dll_characteristics > 544:
            foo.IMAGE_DLLCHARACTERISTICS_NO_ISOLATION = True
            dll_characteristics -= 512

        if dll_characteristics == 256 or dll_characteristics > 288:
            foo.IMAGE_DLLCHARACTERISTICS_NX_COMPAT = True
            dll_characteristics -= 256

        if dll_characteristics >= 128:
            foo.IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY = True
            dll_characteristics -= 128

        if dll_characteristics == 64:
            foo.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE = True
            dll_characteristics -= 64

    return foo


if __name__ == '__main__':

    parser = argparse.ArgumentParser()
    parser.add_argument('dir', help='Directory to scan')
    args = parser.parse_args()

    dep_enabled = []
    dep_disabled = []

    aslr_enabled = []
    aslr_disabled = []

    for root, dirs, files in os.walk(args.dir):
        for f in files:
            bar = get_dll_characteristics(os.path.join(root, f))

            if bar.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE:
                aslr_enabled.append(f)
            else:
                aslr_disabled.append(f)

            if bar.IMAGE_DLLCHARACTERISTICS_NX_COMPAT:
                dep_enabled.append(f)
            else:
                dep_disabled.append(f)

    print "ASLR Enabled: "
    print "=============="
    for i in aslr_enabled:
        print i
    print ""

    print "ASLR Disabled: "
    print "==============="
    for i in aslr_disabled:
        print i
    print ""

    print "DEP Enabled: "
    print "============="
    for i in dep_enabled:
        print i
    print ""

    print "DEP Disabled: "
    print "=============="
    for i in dep_disabled:
        print i
    print ""
  • Thanks for the code. Note that you can use the `&` operator to test for flags. I'm also unclear as to what `dll_characteristics > 2080` et al. are supposed to do. Could you elaborate? – avakar Nov 10 '14 at 19:08
0

5 years later, I've modified the code provided by @Ayrx using & operator to test for flags as @avakar suggested. Now it works properly:

import argparse
import os
import pefile

class DllCharacteristics():
    def __init__(self):
        self.IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE = False
        self.IMAGE_DLLCHARACTERISTICS_GUARD_CF = False
        self.IMAGE_DLLCHARACTERISTICS_WDM_DRIVER = False
        self.IMAGE_DLLCHARACTERISTICS_APPCONTAINER = False
        self.IMAGE_DLLCHARACTERISTICS_NO_BIND = False
        self.IMAGE_DLLCHARACTERISTICS_NO_SEH = False
        self.IMAGE_DLLCHARACTERISTICS_NO_ISOLATION = False
        self.IMAGE_DLLCHARACTERISTICS_NX_COMPAT = False
        self.IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY = False
        self.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE = False
        self.IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA = False

def has_flag(value, flag):
    return value & flag == flag

def get_dll_characteristics(path):
    dc = DllCharacteristics()

    pe = pefile.PE(path, fast_load=True)
    dll_characteristics = pe.OPTIONAL_HEADER.DllCharacteristics

    if dll_characteristics > 0:
        dc.IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE = has_flag(dll_characteristics, 0x8000)
        dc.IMAGE_DLLCHARACTERISTICS_GUARD_CF = has_flag(dll_characteristics, 0x4000)
        dc.IMAGE_DLLCHARACTERISTICS_WDM_DRIVER = has_flag(dll_characteristics, 0x2000)
        dc.IMAGE_DLLCHARACTERISTICS_APPCONTAINER = has_flag(dll_characteristics, 0x1000)
        dc.IMAGE_DLLCHARACTERISTICS_NO_BIND = has_flag(dll_characteristics, 0x0800)
        dc.IMAGE_DLLCHARACTERISTICS_NO_SEH = has_flag(dll_characteristics, 0x0400)
        dc.IMAGE_DLLCHARACTERISTICS_NO_ISOLATION = has_flag(dll_characteristics, 0x0200)
        dc.IMAGE_DLLCHARACTERISTICS_NX_COMPAT = has_flag(dll_characteristics, 0x0100)
        dc.IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY = has_flag(dll_characteristics, 0x0080)
        dc.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE = has_flag(dll_characteristics, 0x0040)
        dc.IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA = has_flag(dll_characteristics, 0x0020)

    return dc


if __name__ == '__main__':

    parser = argparse.ArgumentParser()
    parser.add_argument('dir', help='Directory to scan')
    args = parser.parse_args()

    dep_enabled = []
    dep_disabled = []

    aslr_enabled = []
    aslr_disabled = []

    for root, dirs, files in os.walk(args.dir):
        for f in files:
            flags = get_dll_characteristics(os.path.join(root, f))

            if flags.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE:
                aslr_enabled.append(f)
            else:
                aslr_disabled.append(f)

            if flags.IMAGE_DLLCHARACTERISTICS_NX_COMPAT:
                dep_enabled.append(f)
            else:
                dep_disabled.append(f)

    print "ASLR Enabled: "
    print "=============="
    for i in aslr_enabled:
        print i
    print ""

    print "ASLR Disabled: "
    print "==============="
    for i in aslr_disabled:
        print i
    print ""

    print "DEP Enabled: "
    print "============="
    for i in dep_enabled:
        print i
    print ""

    print "DEP Disabled: "
    print "=============="
    for i in dep_disabled:
        print i
    print ""
intrueder
  • 101