import os import sys import glob import argparse import pefile def dump_directory(path): for filename in glob.glob(path+os.sep+"*.sys"): dump_file(filename) def dump_file(filename): print "Fixing up: %s"%filename try: pe = pefile.PE(filename) for section in pe.sections: print "Updating: %s PointerToRawData 0x%x to"\ " VirtualAddress: 0x%x"%(section.Name, section.VirtualAddress, section.PointerToRawData) # Update the section.PointerToRawData to be equal to # the VirtualAddress/ section.PointerToRawData = section.VirtualAddress # write the changes pe.write(filename='new_'+filename[filename.rindex(os.sep)+1:]) print "new_%s written to disk."%filename except pefile.PEFormatError, msg: print "Error %s file is not a PE file? msg: %s"%(filename, msg) def main(): parser = argparse.ArgumentParser( description='Fixes up the VirtualAddress of drivers dumped from memory.') parser.add_argument('--directory', '-d', action='store', help='Directory with *.sys driver files.') parser.add_argument('--file', '-f', action='store', help='Single file to fix up.') args = parser.parse_args() if args.directory is not None: dump_directory(args.directory) elif args.file is not None: dump_file(args.file) else: parser.print_help() if __name__ == '__main__': main()
If you are curious about the recommendations I got. @skier_t recommended his tool rreat. The tool from @iMHLv2 was a pretty interesting looking framework/toolset for memory analysis of malware called volatility. I'll definitely play around with their tools more, but for now i'mma write my own junk :>.
So besides fixing up the image once dumped, I've also been working on looking at the various functions of the driver after it's loaded. I came across two very curious blocks of code. At first, IDA didn't flag them as being functions.
|IDA listing just the code as is|
|woo, we have functions! :>|
Anyways, it appears that the above disassembly stores the IDT values in memory, does a modification (*notice the mov eax, dword_EE01033C...) then reloads the modified version back into the idt register. When doing run-time analysis I didn't see anything at that address except nulls, so i'm not really sure what the point of it is yet. Keep in mind i'm pretty new to this whole IDT business as well. I tried setting a breakpoint on the two functions which modify the IDT and I can't seem them being called at any point yet. I think I will need to do more work in this area to get a better understanding of it all.
One thing I did notice however is that I'd like an automated way of inspecting the various interrupt entries. If you love python and you use windbg, you should really take a look at pykd, it's pretty damn awesome. After a few minutes of poking through it's samples I found an old (non-working) script which read the IDT entries. I had to rewrite most of the sample script to run in the latest version, but it works now. It's pretty simple in that it just loops through the IDT entries, extracts the dispatch address, dispatch code and the symbol name and displays it. Here's the code:
from pykd import * import sys if __name__ == "__main__": if isKernelDebugging(): dprintln( "check interrupt handlers...\n" ) idtr = reg( "idtr" ) nt = loadModule( "nt" ) ErrorCount = 0 dprintln("idtr is: %08x"%idtr) for i in xrange(0, 255): idtEntry = nt.typedVar("_KIDTENTRY", idtr+i*8) if idtEntry.Selector == 8: offset = ( idtEntry.ExtendedOffset * 0x10000 ) + idtEntry.Offset InterruptHandler = offset kinterrupt = nt.typedVar("_KINTERRUPT",InterruptHandler) if InterruptHandler != 0x00: try: dprintln("IDT [%02x] InterruptHandler: 0x%08x "\ "DispatchAddress: 0x%08x "\ "KINTERRUPT.DispatchCode 0x%08x"\ " (symbol: %s)"%(i,InterruptHandler, kinterrupt.DispatchAddress, kinterrupt.DispatchCode, findSymbol(InterruptHandler))) except Exception, msg: dprintln("IDT [%02x] empty"%i) else: dprintln( "we are not debugging the kernel..." )
And here's some output from it being run from WinDBG:
|idt_dump.py pykd script, dumpin' some interrupt tables baby!|