Package Libs :: Module libhook
[hide private]
[frames] | no frames]

Source Code for Module Libs.libhook

  1  #!/usr/bin/env python 
  2   
  3  """ 
  4  (c) Immunity, Inc. 2004-2007 
  5   
  6   
  7  U{Immunity Inc.<http://www.immunityinc.com>} 
  8   
  9   
 10  """ 
 11   
 12  __VERSION__ = '1.1' 
 13   
 14  import struct 
 15  import debugger  
 16  import pickle 
 17   
 18  FS_UNHOOK  = 0   
 19  FS_HOOK    = 1 # hooked and running 
 20  FS_PAUSE   = 2 
 21   
 22  HookTypes  = {"ORDINARY_BP_HOOK" : 3900, "LOG_BP_HOOK" : 3909,\ 
 23                "EVERY_EXCEPTION_HOOK" : 3901,\ 
 24                "POST_ANALYSIS_HOOK" : 3902, "ACCESS_VIOLATION_HOOK": 3910,\ 
 25                "LOAD_DLL_HOOK" : 3903, "UNLOAD_DLL_HOOK" : 3904,\ 
 26                "CREATE_THREAD_HOOK" : 3905, "EXIT_THREAD_HOOK" : 3906,\ 
 27                "CREATE_PROCESS_HOOK" : 3907, "EXIT_PROCESS_HOOK" : 3908,\ 
 28                "PRE_BP_HOOK" : 3911} 
 29   
 30  HOOK_REG = {'ESI': '[ESP+4   ]',  'EDI': '[ESP]',\ 
 31              'EBX': '[ESP+0x10]',  'EAX': '[ESP+0x1C]',\ 
 32              'ECX': '[ESP+0x18]',  'EDX': '[ESP+0x14]',\ 
 33              'EBP': '[ESP+0x8 ]',  'ESP': '[ESP+0xC ]'} 
 34   
 35   
36 -class FastLogHook:
37 - def __init__(self, imm):
38 self.address = None 39 self.tbl = [] 40 self.list = [] 41 self.entry = [] 42 self.hooked = False 43 self.mem = None 44 self.imm = imm 45 self.restore = [] 46 self.status = FS_UNHOOK 47 self.AllocSize = 0 48 self.memAddress = 0
49
50 - def isHooked(self):
51 return self.status == FS_HOOK
52
53 - def isPause(self):
54 return self.status == FS_PAUSE
55
56 - def Pause(self):
57 if not self.isHooked(): 58 return False 59 60 # Removing Hook on every function 61 for ndx in range(0, len(self.tbl) ): 62 self.imm.writeMemory( self.tbl[ndx][0], self.restore[ndx][0] ) 63 64 self.status = FS_PAUSE 65 return True
66
67 - def Continue(self):
68 if not self.isPause(): 69 return False 70 71 for ndx in range(0, len(self.tbl) ): 72 self.imm.writeMemory( self.tbl[ndx][0], self.restore[ndx][1] ) 73 self.status = FS_HOOK 74 return True
75
76 - def unHook(self):
77 if not self.isHooked(): 78 return False 79 80 # Removing Hook on every function 81 for ndx in range(0, len(self.tbl) ): 82 self.imm.writeMemory( self.tbl[ndx][0], self.restore[ndx][0] ) # Cleaning up Hook Memory 83 self.imm.rVirtualFree( self.mem ) 84 self.status = FS_UNHOOK 85 return True
86
87 - def setRestore(self, restore):
88 self.restore = restore
89
90 - def Hook(self):
91 self.addFastLogHook() 92 self.status = FS_HOOK 93 return True
94
95 - def setMem(self, mem):
96 self.mem = mem
97
98 - def logFunction(self, address):
99 if self.address: 100 self.tbl.append( (self.address, self.entry) ) 101 self.entry = [] 102 self.address = address
103
104 - def logRegister(self, REG):
105 self.entry.append( (REG,) )
106
107 - def logDirectMemory(self, address):
108 self.entry.append( (address,) )
109
110 - def logBaseDisplacement(self, REG, offset = 0 ):
111 self.entry.append( ( REG, offset) )
112
113 - def getAllUniqueFunctions(self):
114 ndx = 0 115 addr = self.mem 116 self._fn = {} 117 self.ret = [] 118 119 while ndx != -1 : 120 mem = self.imm.readMemory( addr, 0x1000) 121 ndx = self._parseUniqueFn( mem ) 122 addr += ndx 123 124 return self._fn
125
126 - def getAllLog(self):
127 mem = "" 128 self.ret = [] 129 flag = False 130 addr = self.mem 131 end = self.imm.readLong(self.memAddress) 132 133 mem = self.imm.readMemory( addr, end-addr) 134 self._parseMem( mem ) 135 136 return self.ret
137
138 - def _parseUniqueFn(self, mem):
139 mem_size = len(mem) 140 ndx = 0 141 while ndx < len(mem): 142 index = struct.unpack("L", mem[ ndx : ndx+4 ] )[0] 143 if index == 0: 144 return -1 # Finished correctly 145 if index > (len(self.tbl) + 1) : 146 return -1 147 148 entry = self.tbl[ index -1 ][1] 149 ndx += 4 150 size_e = len(entry) 151 if (size_e*4 + ndx) > ( mem_size): 152 return ndx - 4 # REQUEST MORE MEM 153 ndx += size_e * 4 154 155 addr = self.tbl[ index -1 ][0] 156 if self._fn.has_key( addr ): 157 self._fn[ addr ] += 1 158 else: 159 self._fn[ addr ] = 1 160 return ndx
161 162
163 - def Clear(self):
164 #self.imm.writeLong( self.mem, 0x0 ) 165 self.imm.writeLong( self.memAddress, self.mem )
166 167
168 - def _parseMem(self, mem):
169 mem_size = len(mem) 170 ndx = 0 171 #self.imm.log("table: %d" % len(self.tbl) ) 172 while ndx < len(mem) : 173 index = struct.unpack("L", mem[ ndx : ndx+4 ] )[0] 174 #self.imm.log("Index: %d" % index) 175 if index == 0: 176 return -1 # Finished correctly 177 if index > (len(self.tbl) + 1) : 178 return -1 179 180 entry = self.tbl[ index -1 ][1] 181 ndx += 4 182 size_e = len(entry) 183 if (size_e*4 + ndx) > ( mem_size): 184 return ndx - 4 # REQUEST MORE MEM 185 ret = struct.unpack( "L" * size_e, mem[ ndx : ndx + size_e *4 ] ) 186 ndx += size_e * 4 187 self.ret.append( ( self.tbl[ index - 1 ][0], ret) ) 188 return ndx
189
190 - def get(self):
191 self.logFunction(None) 192 return self.tbl
193
194 - def setTable(self, tbl):
195 self.tbl = tbl
196
197 - def addFastLogHook(self, alloc_size = 0x100000, memAddress = 0x0):
198 CODE_HOOK_START = 8 199 #flh = hook 200 # Get the table of functions from the hook 201 self.AllocSize = alloc_size 202 203 table = self.get() 204 self.imm.log("TABLE SIZE: %d" % len(table) ) 205 # Allocate memory for the hook and the log 206 if not memAddress: 207 memAddress = self.imm.remoteVirtualAlloc( alloc_size ) 208 209 self.memAddress = memAddress 210 211 self.imm.log( "Logging at 0x%08x" % memAddress ) 212 213 # MEMORY LOOKS LIKE: 214 # mem [ ptr to data ] 215 # mem + 4 [ deadlock ] 216 # mem + 8 [ start of hook code ] 217 # mem + n [ ... ] 218 # mem + n [ start of data ] 219 220 ptr = memAddress + CODE_HOOK_START 221 222 fn_restore = [] 223 224 # for fn_ndx in range( 0, len(table) ): 225 fn_ndx = 0 226 while fn_ndx < len(table) : 227 hookAddress = table[ fn_ndx ][0] 228 entry = table[ fn_ndx ][1] 229 230 idx = 0 231 #patch_code = self.imm.assemble( "PUSH 0x%08x\nRET" % ptr ) 232 patch_code = self.imm.assemble( "JMP 0x%08x" % ptr, address = hookAddress ) 233 234 while idx < len(patch_code): 235 op = self.imm.disasm( hookAddress + idx ) 236 idx += op.getOpSize() 237 if op.isCall() or op.isJmp(): 238 op = None 239 break 240 241 # Removing the BP from the table 242 if not op: 243 self.imm.log("deleting: %d" % fn_ndx) 244 del table[ fn_ndx ] 245 continue 246 247 ex_prelude = self.imm.readMemory( hookAddress, idx ) 248 249 code = self.imm._createCodeforHook( memAddress, hookAddress + idx,\ 250 fn_ndx + 1, entry, ex_prelude, alloc_size) 251 252 self.imm.writeMemory( ptr , code ) 253 ptr += len(code) 254 self.imm.writeMemory( hookAddress, patch_code ) 255 256 fn_restore.append( (ex_prelude, patch_code ) ) # Correspond in index with function address 257 fn_ndx += 1 258 259 self.setTable( table ) 260 if ptr % 4: 261 ptr = 4 + ptr & ~(4-1) 262 self.setMem( ptr ) 263 self.imm.writeLong( memAddress, ptr ) 264 self.setRestore( fn_restore ) 265 266 267
268 -class STDCALLFastLogHook(FastLogHook):
269 - def __init__(self, imm):
270 FastLogHook.__init__(self, imm)
271 - def logFunction(self, address, args = 0 ):
272 if self.address: 273 self.tbl.append( (self.address, self.entry) ) 274 self.entry = [] 275 276 self.address = address 277 for ndx in range(0, args): 278 self.logBaseDisplacement( "ESP", ndx*4 + 4 )
279 280 #HOOK class
281 -class Hook:
282 - def __init__(self):
283 self.type=0 284 self.msg="" 285 self.string="" 286 self.address=0 287 self.enabled=True # by default hook is enabled
288
289 - def enable(self):
290 """Enable hook execution""" 291 self.enabled=True
292
293 - def disable(self):
294 """Disable hook execution""" 295 self.enabled=False
296
297 - def UnHook(self):
298 """Remove the hook""" 299 debugger.remove_hook(self.desc)
300
301 - def add(self,description,address=0,force=0,timeout=0,mode=0):
302 """Add hook to Immunity Debugger hook database 303 @param type: Type of hook 304 @param desc: Descriptive string 305 @param force: Force hook adding 306 @param timeout: time to live in memory 307 @param mode: thread mode of ttl execution 308 """ 309 310 self.desc = description 311 self.address = address 312 self.force=force 313 self.timeout=timeout 314 # mode = 1 then, execute ttl hook in the same thread enviroment as the python command/script 315 # mode = 0 use your own thread enviroment to place and execute the ttl hook 316 # you'll be using mode = 0 at least you really know what you are doing. 317 318 self.mode=mode 319 if self.type == HookTypes["ORDINARY_BP_HOOK"]: 320 debugger.set_breakpoint(self.address,0x200L,"") 321 elif self.type == HookTypes["LOG_BP_HOOK"]: 322 debugger.set_logging_breakpoint(self.address) 323 pickled_object = pickle.dumps(self) 324 return debugger.add_hook( pickled_object , self.desc , self.type, self.address,self.force,self.timeout,self.mode)
325
326 - def _run(self,regs):
327 """regs is the actual cpu context, be sure of using this values 328 and not the ones from imm.getRegs() at hook time""" 329 self.regs=regs 330 self.run(regs)
331
332 - def _runTimeout(self,regs):
333 """regs is the actual cpu context, be sure of using this values 334 and not the ones from imm.getRegs() at hook time""" 335 self.regs=regs 336 self.runTimeout(regs)
337 338 # function that will be runned once the hook is triggered
339 - def run(self,regs):
340 debugger.Error("Your hook doesnt seem to have run() defined") 341 return
342
343 - def runTimeout(self,regs):
344 debugger.Error("Your hook doesnt seem to have runTimeout() defined") 345 return
346
347 -class BpHook(Hook):
348 - def __init__(self):
349 Hook.__init__(self) 350 self.type = HookTypes["ORDINARY_BP_HOOK"] 351 self.desc = "BreakpointHook"
352
353 -class LogBpHook(Hook):
354 - def __init__(self):
355 Hook.__init__(self) 356 self.type = HookTypes["LOG_BP_HOOK"] 357 self.desc = "LoggingPointHook"
358
359 -class PreBpHook(Hook):
360 - def __init__(self):
361 Hook.__init__(self) 362 self.type = HookTypes["PRE_BP_HOOK"] 363 self.desc = "PreBreakpointHook"
364
365 -class AllExceptHook(Hook):
366 - def __init__(self):
367 Hook.__init__(self) 368 self.type = HookTypes["EVERY_EXCEPTION_HOOK"] 369 self.desc = "EveryExceptionHook"
370
371 -class PostAnalysisHook(Hook):
372 - def __init__(self):
373 Hook.__init__(self) 374 self.type = HookTypes["POST_ANALYSIS_HOOK"] 375 self.desc = "PostAnalysisHook"
376
377 -class AccessViolationHook(Hook):
378 - def __init__(self):
379 Hook.__init__(self) 380 self.type = HookTypes["ACCESS_VIOLATION_HOOK"] 381 self.desc = "AcessViolationHook"
382
383 -class RunUntilAV(Hook):
384 - def __init__(self,imm):
385 Hook.__init__(self) 386 self.type = HookTypes["ACCESS_VIOLATION_HOOK"] 387 self.desc = "AcessViolationHook" 388 imm.run()
389
390 -class LoadDLLHook(Hook):
391 - def __init__(self):
392 Hook.__init__(self) 393 self.type = HookTypes["LOAD_DLL_HOOK"] 394 self.desc = "LoadDLLHook"
395
396 -class UnloadDLLHook(Hook):
397 - def __init__(self):
398 Hook.__init__(self) 399 self.type = HookTypes["UNLOAD_DLL_HOOK"] 400 self.desc = "UnloadDLLHook"
401
402 -class CreateThreadHook(Hook):
403 - def __init__(self):
404 Hook.__init__(self) 405 self.type = HookTypes["CREATE_THREAD_HOOK"] 406 self.desc = "CreateThreadHook"
407
408 -class ExitThreadHook(Hook):
409 - def __init__(self):
410 Hook.__init__(self) 411 self.type = HookTypes["EXIT_THREAD_HOOK"] 412 self.desc = "ExitThreadHook"
413
414 -class CreateProcessHook(Hook):
415 - def __init__(self):
416 Hook.__init__(self) 417 self.type = HookTypes["CREATE_PROCESS_HOOK"] 418 self.desc = "CreateProcessHook"
419
420 -class ExitProcessHook(Hook):
421 - def __init__(self):
422 Hook.__init__(self) 423 self.type = HookTypes["EXIT_PROCESS_HOOK"] 424 self.desc = "ExitProcessHook"
425