Package src :: Module pyfault
[hide private]
[frames] | no frames]

Source Code for Module src.pyfault

  1  # 
  2  # PyFault 
  3  # Copyright (C) 2007 Justin Seitz <jms@bughunter.ca> 
  4  # 
  5  # 
  6  # This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public 
  7  # License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later 
  8  # version. 
  9  # 
 10  # This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied 
 11  # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 
 12  # 
 13  # You should have received a copy of the GNU General Public License along with this program; if not, write to the Free 
 14  # Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
 15  # 
 16   
 17  import pyfault_defines 
 18  import faultx 
 19  import ctypes 
 20   
 21   
 22  kernel32 = ctypes.windll.kernel32 
 23   
 24   
25 -class pyfault:
26 27 ''' 28 This class is mainly a DLL injector/ejector, but I hope to expand it to be a fault injection suite, 29 to torture software on those days the elusive 0-day doesn't come knocking. For now inject 30 away until I have time to code up some other lovin' 31 ''' 32
33 - def __init__ (self):
34 35 self.dll_path = None # Full path to DLL for injection. 36 self.pid = None # Process id for various nastiness. Mainly DLL injection.
37 38 39 ############################################################################## 40 ''' 41 This function is basically a nice wrapper around CreateToolhelp32Snapshot() to retrieve detailed 42 information on a DLL for use in ejection. 43 ''' 44 ############################################################################## 45
46 - def get_module_info(self,dll_name,pid):
47 48 # http://msdn2.microsoft.com/en-us/library/ms686849.aspx Reference to iterating a module list for a process 49 # As well its worth noting that PaiMei (http://paimei.openrce.org) by Pedram Amini 50 # has a reference to this functionality somewhat. Original credit in the PaiMei framework 51 # goes to Otto Ebeling. 52 53 # We create a snapshot of the current process, this let's us dig out all kinds of 54 # useful information, including DLL info. We are really after the reference count 55 # so that we can decrement it enough to get rid of the DLL we want unmapped 56 current_process = pyfault_defines.MODULEENTRY32() 57 h_snap = kernel32.CreateToolhelp32Snapshot(pyfault_defines.TH32CS_SNAPMODULE,pid) 58 59 # check for a failure to create a valid snapshot 60 if h_snap == pyfault_defines.INVALID_HANDLE_VALUE: 61 raise faultx("CreateToolHelp32Snapshot(TH32CS_SNAPMODULE,%d) failed." % pid) 62 63 # we have to initiliaze the size of the MODULEENTRY32 struct or this will all fail 64 current_process.dwSize = ctypes.sizeof(current_process) 65 66 # check to make sure we have a valid list 67 if not kernel32.Module32First(h_snap, ctypes.byref(current_process)): 68 raise faultx("Couldn't find a valid reference to the module %s" % dll_name) 69 70 71 # Keep looking through the loaded modules to try to find the one specified for ejection 72 while current_process.szModule.lower() != dll_name.lower(): 73 74 if not kernel32.Module32Next(h_snap, ctypes.byref(current_process)): 75 raise faultx("Couldn't find the DLL %s" % dll_name) 76 77 78 # close the handle to the snapshot 79 kernel32.CloseHandle(h_snap) 80 81 # return the MODULEENTRY32 structure of our DLL 82 return current_process
83 84 85 86 ############################################################################## 87 ''' 88 This function removes a DLL from a running process, use at your own RISK! :) 89 ''' 90 ############################################################################## 91
92 - def eject_dll(self,dll_name,pid):
93 ''' 94 Eject a loaded DLL from a running process. 95 @type dll_name: String 96 @param dll_name: The name of the DLL you wish to eject. 97 @type pid: Integer 98 @param pid: The process ID that you want to eject a DLL from. 99 100 @returns True if successful, False if not. 101 ''' 102 103 # We need to get the reference count, and the base address to pop the DLL out 104 current_process = self.get_module_info(dll_name,pid) 105 106 if current_process != False: 107 108 # Crack open the process 109 h_process = kernel32.OpenProcess(pyfault_defines.PROCESS_ALL_ACCESS, False, pid) 110 111 # Get a handle directly to kernel32.dll 112 h_kernel32 = kernel32.GetModuleHandleA("kernel32.dll") 113 114 # Get the address of FreeLibrary 115 h_freelib = kernel32.GetProcAddress(h_kernel32,"FreeLibrary") 116 117 # Now we try to create the remote thread hopefully freeing that DLL, the reason we loop is that 118 # FreeLibrary merely decrements the reference count of the DLL we are freeing. Once the ref count 119 # hits 0 it will unmap the DLL from memory 120 count = 0 121 while count <= current_process.GlblcntUsage: 122 thread_id = ctypes.c_ulong() 123 if not kernel32.CreateRemoteThread(h_process,None,0,h_freelib,current_process.hModule,0,ctypes.byref(thread_id)): 124 raise faultx("CreateRemoteThread failed, couldn't run FreeLibrary()") 125 count += 1 126 127 # Free some handles so we aren't leaking them all over the floor 128 kernel32.CloseHandle(h_process) 129 kernel32.CloseHandle(h_kernel32) 130 kernel32.CloseHandle(h_freelib) 131 132 return True 133 134 else: 135 136 return False
137 138 139 ############################################################################## 140 ''' 141 This is a simple method for injecting a DLL into a running process. 142 ''' 143 ############################################################################## 144
145 - def inject_dll(self,dll_path,pid):
146 147 ''' 148 Inject a DLL of your choice into a running process. 149 @type dll_name: String 150 @param dll_name: The path to the DLL you wish to inject. 151 @type pid: Integer 152 @param pid: The process ID that you wish to inject into. 153 154 @returns True if the DLL was injected successfully, False if it wasn't. 155 ''' 156 157 dll_len = len(dll_path) 158 159 # Get a handle to the process we are injecting into. 160 h_process = kernel32.OpenProcess(pyfault_defines.PROCESS_ALL_ACCESS, False, pid) 161 162 # Now we have to allocate enough bytes for the name and path of our DLL. 163 arg_address = kernel32.VirtualAllocEx(h_process,0,dll_len,pyfault_defines.VIRTUAL_MEM,pyfault_defines.PAGE_READWRITE) 164 165 # Write the path of the DLL into the previously allocated space. The pointer returned 166 written = ctypes.c_int(0) 167 kernel32.WriteProcessMemory(h_process, arg_address, dll_path, dll_len, ctypes.byref(written)) 168 169 # Get a handle directly to kernel32.dll 170 h_kernel32 = kernel32.GetModuleHandleA("kernel32.dll") 171 172 # Get the address of LoadLibraryA 173 h_loadlib = kernel32.GetProcAddress(h_kernel32,"LoadLibraryA") 174 175 # Now we try to create the remote thread, with the entry point of 176 thread_id = ctypes.c_ulong(0) 177 if not kernel32.CreateRemoteThread(h_process,None,0,h_loadlib,arg_address,0,ctypes.byref(thread_id)): 178 raise faultx("CreateRemoteThread failed, unable to inject the DLL.") 179 180 # Return the threadid of the newly injected DLL 181 return True
182