Skip to content

Instantly share code, notes, and snippets.

@MarkBaggett
Last active July 4, 2019 19:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MarkBaggett/1a168c026746a627e6abae2141052742 to your computer and use it in GitHub Desktop.
Save MarkBaggett/1a168c026746a627e6abae2141052742 to your computer and use it in GitHub Desktop.
Python Windows DLLs finding and calling
import pefile
import sys
import ctypes
import glob
import argparse
import itertools
def search_tables(thefile, pename, search = []):
if hasattr(thefile, "DIRECTORY_ENTRY_IMPORT"):
if args.verbose or args.dump:
print("Processing Import Table...")
for dllimport in thefile.DIRECTORY_ENTRY_IMPORT:
fname = dllimport.dll.decode()
for eachfunc in dllimport.imports:
if args.dump:
name = eachfunc.name if eachfunc.name else b"BLANK"
print("{0: >} in {1} at offset 0x{2:0>16X}".format(name.decode(),fname,eachfunc.address ))
continue
for eachterm in search:
if args.inexact:
if eachfunc.name and (eachterm in eachfunc.name.decode().lower()) or not search:
print("{} uses {} in dll {}".format(pename, eachfunc.name, fname))
else:
if eachfunc.name and eachterm == eachfunc.name.decode():
print("{} uses {} in dll {}".format(pename, eachfunc.name, fname))
#else:
# print("{} not in {}".format(eachterm, eachfunc.name)
if hasattr(thefile, "DIRECTORY_ENTRY_EXPORT"):
if args.verbose or args.dump:
print("Processing the Export Table...")
for symbol in thefile.DIRECTORY_ENTRY_EXPORT.symbols:
fname = thefile.DIRECTORY_ENTRY_EXPORT.name.decode()
if args.dump:
name = symbol.name if symbol.name else b"BLANK"
print("{0} in {1} at offset 0x{2:0>16X} in {}".format(name.decode(), fname, symbol.address_offset))
continue
for eachterm in search:
if symbol.name:
if args.inexact:
if symbol.name and (eachterm in symbol.name.decode().lower()) or not search:
print("{0} exports {1} at 0x{2:0>16X} ".format(pename, symbol.name, symbol.address_offset))
else:
if symbol.name and eachterm == symbol.name.decode():
print("{0} exports {1} at 0x{2:0>16X}".format(pename, symbol.name, symbol.address_offset))
def bits2flag(flags,byte_value):
bits_array = map(int, format(byte_value,"016b"))
return "|".join(itertools.compress(flags[::-1],bits_array))
search = ["printf", "gets", "lstrcpyW"]
dll_characteristics = ['reserved0', 'reserved1', 'reserved2', 'reserved3', 'undefined1', 'High_Entropy_VA', 'Dynamic_Base', 'Force_Integrity', 'NX_Compat', 'No_isolation', 'No_SEH', 'No_bind', 'App_Container', 'WDM_Driver', 'Guard_CF', 'Terminal_Server_Aware']
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("-d", "--dump", action= "store_true", help = "Dump all information about the pe. No filters or search applied.")
parser.add_argument("-a","--add", nargs='*', help = "In addition to defaults also search for these functions being used by the exectuables. The function names are separated by spaces and terminated with two dashes. Example: -a modulea moduleb --")
parser.add_argument("-o","--only", nargs='*', help = "Only search for these functions being used by the executables. The function names are separated by spaces and terminated with two dashes. Example: -e modulea moduleb --")
parser.add_argument("-i","--inexact", action="store_true", help = "Ignore case sensitive and allow substring match of function names rather than exact names.")
parser.add_argument("-f","--flags", action="store_true", help = "Display the DLL Characteristic flags.")
parser.add_argument("-v","--verbose", action="store_true", help = "MAKE SOME NOISE UP IN HERE!!!")
parser.add_argument("-t", "--toggle", nargs="*", choices = dll_characteristics, help = "A list of Header Characteristics bit to toggle. Flags are spece separated and end with two dashes. Example --toggle NO_SEH Guard_CF --")
parser.add_argument("pefiles", help= "The name of an EXE or DLL is a required argument. Wildcards are supported.")
args = parser.parse_args()
pefiles = glob.glob(args.pefiles)
if len(pefiles)==0:
print("No files found.")
sys.exit(1)
if args.add:
search.extend(args.add)
if args.only:
search = args.only
for pe in pefiles:
try:
thefile = pefile.PE(pe)
except Exception as e:
print("Unable to open file {}".format(str(e)))
continue
if args.dump or args.flags:
file_options = thefile.OPTIONAL_HEADER.DllCharacteristics
print("{} flags : {}".format(pe, bits2flag(dll_characteristics, file_options)))
if args.toggle:
current_flags = thefile.OPTIONAL_HEADER.DllCharacteristics
bitsmask = 0
for eachflag in args.toggle:
bitsmask = bitsmask ^ (2**dll_characteristics.index(eachflag))
thefile.OPTIONAL_HEADER.DllCharacteristics = current_flags ^ bitsmask
thefile.write(filename = "{}.new".format(pe))
print("Flags Changes written to {}.new".format(pe))
if args.verbose:
print("Searching EXE {} for vulnerable functions {}".format(pe, str(search)))
search_tables(thefile,pe, search)
import pefile
import sys
import ctypes
import glob
import argparse
import itertools
def search_tables(thefile, pename, search = []):
if hasattr(thefile, "DIRECTORY_ENTRY_IMPORT"):
if args.verbose or args.dump:
print("Processing Import Table...")
for dllimport in thefile.DIRECTORY_ENTRY_IMPORT:
fname = dllimport.dll.decode()
for eachfunc in dllimport.imports:
if args.dump:
name = eachfunc.name if eachfunc.name else b"BLANK"
print("{0: >} in {1} at offset 0x{2:0>16X}".format(name.decode(),fname,eachfunc.address ))
continue
for eachterm in search:
if args.inexact:
if eachfunc.name and (eachterm in eachfunc.name.decode().lower()) or not search:
print("{} uses {} in dll {}".format(pename, eachfunc.name, fname))
else:
if eachfunc.name and eachterm == eachfunc.name.decode():
print("{} uses {} in dll {}".format(pename, eachfunc.name, fname))
#else:
# print("{} not in {}".format(eachterm, eachfunc.name)
if hasattr(thefile, "DIRECTORY_ENTRY_EXPORT"):
if args.verbose or args.dump:
print("Processing the Export Table...")
for symbol in thefile.DIRECTORY_ENTRY_EXPORT.symbols:
fname = thefile.DIRECTORY_ENTRY_EXPORT.name.decode()
if args.dump:
name = symbol.name if symbol.name else b"BLANK"
print("{0} in {1} at offset 0x{2:0>16X} in {}".format(name.decode(), fname, symbol.address_offset))
continue
for eachterm in search:
if symbol.name:
if args.inexact:
if symbol.name and (eachterm in symbol.name.decode().lower()) or not search:
print("{0} exports {1} at 0x{2:0>16X} ".format(pename, symbol.name, symbol.address_offset))
else:
if symbol.name and eachterm == symbol.name.decode():
print("{0} exports {1} at 0x{2:0>16X}".format(pename, symbol.name, symbol.address_offset))
def bits2flag(flags,byte_value):
bits_array = map(int, format(byte_value,"016b"))
return "|".join(itertools.compress(flags[::-1],bits_array))
search = ["printf", "gets", "lstrcpyW"]
dll_characteristics = ['reserved0', 'reserved1', 'reserved2', 'reserved3', 'undefined1', 'High_Entropy_VA', 'Dynamic_Base', 'Force_Integrity', 'NX_Compat', 'No_isolation', 'No_SEH', 'No_bind', 'App_Container', 'WDM_Driver', 'Guard_CF', 'Terminal_Server_Aware']
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("-d", "--dump", action= "store_true", help = "Dump all information about the pe. No filters or search applied.")
parser.add_argument("-a","--add", nargs='*', help = "In addition to defaults also search for these functions being used by the exectuables. The function names are separated by spaces and terminated with two dashes. Example: -a modulea moduleb --")
parser.add_argument("-o","--only", nargs='*', help = "Only search for these functions being used by the executables. The function names are separated by spaces and terminated with two dashes. Example: -e modulea moduleb --")
parser.add_argument("-i","--inexact", action="store_true", help = "Ignore case sensitive and allow substring match of function names rather than exact names.")
parser.add_argument("-f","--flags", action="store_true", help = "Display the DLL Characteristic flags.")
parser.add_argument("-v","--verbose", action="store_true", help = "MAKE SOME NOISE UP IN HERE!!!")
parser.add_argument("-t", "--toggle", choices = dll_characteristics, help = "The name of a single PE DLL Characteristics bit to toggle.")
parser.add_argument("pefiles", help= "The name of an EXE or DLL is a required argument. Wildcards are supported.")
args = parser.parse_args()
pefiles = glob.glob(args.pefiles)
if len(pefiles)==0:
print("No files found.")
sys.exit(1)
if args.add:
search.extend(args.add)
if args.only:
search = args.only
for pe in pefiles:
try:
thefile = pefile.PE(pe)
except Exception as e:
print("Unable to open file {}".format(str(e)))
continue
if args.dump or args.flags:
file_options = thefile.OPTIONAL_HEADER.DllCharacteristics
print("{} flags : {}".format(pe, bits2flag(dll_characteristics, file_options)))
if args.toggle:
current_flags = thefile.OPTIONAL_HEADER.DllCharacteristics
bitsmask = 2**dll_characteristics.index(args.toggle)
thefile.OPTIONAL_HEADER.DllCharacteristics = current_flags ^ bitsmask
thefile.write(filename = "{}.new".format(pe))
print("Flags Changes written to {}.new".format(pe))
if args.verbose:
print("Searching EXE {} for vulnerable functions {}".format(pe, str(search)))
search_tables(thefile,pe, search)
import pefile
import sys
import ctypes
import glob
import argparse
import itertools
def search_tables(thefile, pename, search = []):
if hasattr(thefile, "DIRECTORY_ENTRY_IMPORT"):
if args.verbose or args.dump:
print("Processing Import Table...")
for dllimport in thefile.DIRECTORY_ENTRY_IMPORT:
fname = dllimport.dll.decode()
for eachfunc in dllimport.imports:
if args.dump:
name = eachfunc.name if eachfunc.name else b"BLANK"
print("{0: >} in {1} at offset 0x{2:0>16X}".format(name.decode(),fname,eachfunc.address ))
continue
for eachterm in search:
if args.inexact:
if eachfunc.name and (eachterm in eachfunc.name.decode().lower()) or not search:
print("{} uses {} in dll {}".format(pename, eachfunc.name, fname))
else:
if eachfunc.name and eachterm == eachfunc.name.decode():
print("{} uses {} in dll {}".format(pename, eachfunc.name, fname))
#else:
# print("{} not in {}".format(eachterm, eachfunc.name)
if hasattr(thefile, "DIRECTORY_ENTRY_EXPORT"):
if args.verbose or args.dump:
print("Processing the Export Table...")
for symbol in thefile.DIRECTORY_ENTRY_EXPORT.symbols:
fname = thefile.DIRECTORY_ENTRY_EXPORT.name.decode()
if args.dump:
name = symbol.name if symbol.name else b"BLANK"
print("{0} in {1} at offset 0x{2:0>16X} in {}".format(name.decode(), fname, symbol.address_offset))
continue
for eachterm in search:
if symbol.name:
if args.inexact:
if symbol.name and (eachterm in symbol.name.decode().lower()) or not search:
print("{0} exports {1} at 0x{2:0>16X} ".format(pename, symbol.name, symbol.address_offset))
else:
if symbol.name and eachterm == symbol.name.decode():
print("{0} exports {1} at 0x{2:0>16X}".format(pename, symbol.name, symbol.address_offset))
def bits2flag(flags,byte_value):
bits_array = map(int, format(byte_value,"016b"))
return "|".join(itertools.compress(flags[::-1],bits_array))
def togglebit(flags, toggle_flag, byte_value):
bits_mask = 2**flags.index(toggle_flag)
return byte_value ^ bits_mask
search = ["printf", "gets", "lstrcpyW"]
dll_characteristics = ['reserved0', 'reserved1', 'reserved2', 'reserved3', 'undefined1', 'High_Entropy_VA', 'Dynamic_Base', 'Force_Integrity', 'NX_Compat', 'No_isolation', 'No_SEH', 'No_bind', 'App_Container', 'WDM_Driver', 'Guard_CF', 'Terminal_Server_Aware']
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("-d", "--dump", action= "store_true", help = "Dump all information about the pe. No filters or search applied.")
parser.add_argument("-a","--add", nargs='*', help = "In addition to defaults also search for these functions being used by the exectuables. The function names are separated by spaces and terminated with two dashes. Example: -a modulea moduleb --")
parser.add_argument("-o","--only", nargs='*', help = "Only search for these functions being used by the executables. The function names are separated by spaces and terminated with two dashes. Example: -e modulea moduleb --")
parser.add_argument("-i","--inexact", action="store_true", help = "Ignore case sensitive and allow substring match of function names rather than exact names.")
parser.add_argument("-f","--flags", action="store_true", help = "Display the DLL Characteristic flags.")
parser.add_argument("-v","--verbose", action="store_true", help = "MAKE SOME NOISE UP IN HERE!!!")
parser.add_argument("-t", "--toggle", choices = dll_characteristics, help = "The name of a single Header Characteristics bit to toggle.")
parser.add_argument("pefiles", help= "The name of an EXE or DLL is a required argument. Wildcards are supported.")
args = parser.parse_args()
pefiles = glob.glob(args.pefiles)
if len(pefiles)==0:
print("No files found.")
sys.exit(1)
if args.add:
search.extend(args.add)
if args.only:
search = args.only
for pe in pefiles:
try:
thefile = pefile.PE(pe)
except Exception as e:
print("Unable to open file {}".format(str(e)))
continue
if args.dump or args.flags:
file_options = thefile.OPTIONAL_HEADER.DllCharacteristics
print("{} flags : {}".format(pe, bits2flag(dll_characteristics, file_options)))
if args.toggle:
#LAB: Put your code here to toggle the PE flags here
#variable pe contains a string that is the file name you are processing
#variable thefile contains the pefile.PE data structure you need
#variable args.toggle contains what is passed after the -t or --toggle argument on the command line
print("Toggle is not currently supported.")
if args.verbose:
print("Searching EXE {} for vulnerable functions {}".format(pe, str(search)))
search_tables(thefile,pe, search)
import ctypes
x = ctypes.cdll.LoadLibrary(r'c:\windows\system32\crtdll.dll')
#
#Interestingly this will crash this program....
#C:\Users\mark\Desktop>python -c "print('A'*15685)"| python gets.py
#Type something for me!b'AAAAAAAAAAAAAAAAAAAA'
#But this will not
#C:\Users\mark\Desktop>python -c "print('A'*15684)"| python gets.py
#gets returns a pointer to value in memory and updates the buffer mystr
x.printf(b'Type something for me!')
mystr = ctypes.create_string_buffer(20)
respaddr = x.gets(mystr)
print(mystr.value)
#turn response address into a string
actualmem = ctypes.cast(respaddr, ctypes.c_char_p)
print(actualmem.value)
import pefile
import sys
import ctypes
import glob
import argparse
def dllinfo(dllpath, search=b""):
try:
thedll = pefile.PE(dllpath)
except Exception as e:
print("{} {}".format(dllpath,str(e)))
return
if hasattr(thedll, "DIRECTORY_ENTRY_EXPORT"):
for symbol in thedll.DIRECTORY_ENTRY_EXPORT.symbols:
if symbol.name:
if not search or (search.decode().lower() in symbol.name.decode().lower()):
print("Name {} is at offset {} in {}".format(symbol.name, symbol.address_offset,dllpath))
else:
print("{} has no exports.".format(dllpath))
def search_imports(infile, search = []):
try:
thefile = pefile.PE(infile)
except Exception as e:
print("Unable to open file {}",format(str(e)))
if hasattr(thefile, "DIRECTORY_ENTRY_IMPORT"):
for dllimport in thefile.DIRECTORY_ENTRY_IMPORT:
for eachfunc in dllimport.imports:
for eachterm in search:
if not args.exact:
if eachfunc.name and (eachterm in eachfunc.name.decode().lower()) or not search:
print("*"*100)
print("Name {} is using function {}".format(infile, eachfunc.name))
print("*"*100)
else:
if eachfunc.name and eachterm == eachfunc.name.decode():
print("*"*100)
print("Name {} is using function {}".format(infile, eachfunc.name))
print("*"*100)
#else:
# print("{} not in {}".format(eachterm, eachfunc.name)
search = ["printf", "gets", "lstrcpyw"]
parser = argparse.ArgumentParser()
parser.add_argument("-a","--add", nargs='*', help = "In addition to defaults also search for these functions being used by the exectuables.")
parser.add_argument("-o","--only", nargs='*', help = "Only search for these functions being used by the executables.")
parser.add_argument("-e","--exact", action="store_true", help = "Search for exact match of function names rather than as substrings.")
parser.add_argument("-v","--verbose", action="store_true", help = "MAKE SOME NOISE UP IN HERE!!!")
parser.add_argument("executable", help= "The name of an executable is a required argument.")
args = parser.parse_args()
exes = glob.glob(args.executable)
if len(exes)==0:
print("No Executables found.")
sys.exit(1)
if args.add:
search.extend(args.add)
if args.only:
search = args.only
for exe in exes:
if args.verbose:
print("Searching EXE {} for vulnerable functions {}".format(exe, str(search)))
search_imports(exe, search)
#x = ctypes.cdll.LoadLibrary(r'c:\windows\system32\crtdll.dll')
#x.printf("WHATS UP GOOD OLD PRINTF VULNERABILTIY!!! %x %x %x")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment