Thursday, June 18, 2015

LoadLibraryA hook - Consecutive API functions in Shellcode

Script hooks into "LoadLibraryA" and checks if [content] of any register point to "LoadLibrayA" function. It also displays adjacent locations of the addresses pointed by the register.

For example,

call [eax] -------> eax = 0x04040404 and 04040404 if it points to address of "LoadLibraryA" our script will display data surrounding that memory location. Currently its only able to display function names for very few APIs :)

       

##
#
#Code checks for APIs in consecutive memory
#Hooks into LoadLibraryA
#
#Sample output - CVE-2015-3090 from Angler Exploit Kit
#C:\Documents and Settings\user\Desktop\SCRIPTS>LoadLib_Hook.py
#[*] LoadLibraryA hooked at: 0x7c801d77
#
#[*] LoadLibraryA in content of ESI 0x043a5c95
#0x424448b
#0x8b0c488b
#0x408b0450
#0x11048910
#0xcc0004c2
#0x7c80ac28 -----------> GetProcAddress
#0x7c801d77 -----------> LoadLibraryA
#0x7c809a81 -----------> VirtualAlloc
#0x7c809b14 -----------> VirtualFree
#0x7c81082f
#0x7c802530
#0x7c81caa2
#0x7c809b77
#0x7c82293b
#0x7c801a24
#0x7c81f8e2
#0x7c80ec1b
#0x7c910856
#0x7c959e43
#0x7c961be3
#0x7c924caa
#0x7c910a8f
##
from pydbg import *
from pydbg.defines import *

import struct
import re
import utils
import sys
import os
from ctypes import *

global is_hooked

#Stupid way to convert to hex
def hex_cnvrt(dec):
    dec = str(hex(dec))
    dec = re.sub('L', '', dec)
    return dec

def print_data(addr):
    addr -= 20          #So that we cover data in previous memory too
    addresses = []
    for x in range(0, 40):
        addr_dump = dbg.read_process_memory(addr, 4)
        addr_dump = struct.unpack("L", addr_dump)[0]
        addr += 4
        if hex_cnvrt(addr_dump) == hex_cnvrt(hook_address):
            addresses.append(hex_cnvrt(addr_dump) + ' -----------> LoadLibraryA')
        elif hex_cnvrt(addr_dump) == hex_cnvrt(get_proc_addr):
            addresses.append(hex_cnvrt(addr_dump) + ' -----------> GetProcAddress')
        elif hex_cnvrt(addr_dump) == hex_cnvrt(virtualalloc_addr):
            addresses.append(hex_cnvrt(addr_dump) + ' -----------> VirtualAlloc')
        elif hex_cnvrt(addr_dump) == hex_cnvrt(virtualallocex_addr):
            addresses.append(hex_cnvrt(addr_dump) + ' -----------> VirtualAllocEx')
        elif hex_cnvrt(addr_dump) == hex_cnvrt(writefile_addr):
            addresses.append(hex_cnvrt(addr_dump) + ' -----------> WriteFile')
        elif hex_cnvrt(addr_dump) == hex_cnvrt(virtualfree_addr):
            addresses.append(hex_cnvrt(addr_dump) + ' -----------> VirtualFree')
        elif hex_cnvrt(addr_dump) == hex_cnvrt(virtualfreeex_addr):
            addresses.append(hex_cnvrt(addr_dump) + ' -----------> VirtualFreeEx')
        elif hex_cnvrt(addr_dump) == hex_cnvrt(createremotethread_addr):
            addresses.append(hex_cnvrt(addr_dump) + ' -----------> CreateRemoteThread')
        else:
            addresses.append(hex_cnvrt(addr_dump))

    return addresses

def LoadLib(dbg, args):
    eax_content = dbg.context.Eax
    ebx_content = dbg.context.Ebx
    ecx_content = dbg.context.Ecx
    edx_content = dbg.context.Edx
    esi_content = dbg.context.Esi
    edi_content = dbg.context.Edi
    ebp_content = dbg.context.Ebp

    try:
        con_eax_content = print_data(eax_content)
        if any(hex_cnvrt(hook_address) in s for s in con_eax_content):
            print "\n[*] LoadLibraryA in content of EAX 0x%08x" % eax_content
            for addr in con_eax_content:
                print addr
    except:
        pass

    try:
        con_esi_content = print_data(esi_content)
        if any(hex_cnvrt(hook_address) in s for s in con_esi_content):
            print "\n[*] LoadLibraryA in content of ESI 0x%08x" % esi_content
            for addr in con_esi_content:
                print addr
    except:
        pass

    try:
        con_ebx_content = print_data(ebx_content)
        if any(hex_cnvrt(hook_address) in s for s in con_ebx_content):
            print "\n[*] LoadLibraryA in content of EBX 0x%08x" % ebx_content
            for addr in con_ebx_content:
                print addr
    except:
        pass

    try:
        con_ecx_content = print_data(ecx_content)
        if any(hex_cnvrt(hook_address) in s for s in con_ecx_content):
            print "\n[*] LoadLibraryA in content of ECX 0x%08x" % ecx_content
            for addr in con_ecx_content:
                print addr
    except:
        pass

    try:
        con_edx_content = print_data(edx_content)
        if any(hex_cnvrt(hook_address) in s for s in con_edx_content):
            print "\n[*] LoadLibraryA in content of EDX 0x%08x" % edx_content
            for addr in con_edx_content:
                print addr
    except:
        pass

    try:
        con_edi_content = print_data(edi_content)
        if any(hex_cnvrt(hook_address) in s for s in con_edi_content):
            print "\n[*] LoadLibraryA in content of EDI 0x%08x" % edi_content
            for addr in con_edi_content:
                print addr
    except:
        pass

    try:
        con_ebp_content = print_data(ebp_content)
        if any(hex_cnvrt(hook_address) in s for s in con_ebp_content):
            print "\n[*] LoadLibraryA in content of EBP 0x%08x" % ebp_content
            for addr in con_ebp_content:
                print addr
    except:
        pass

    return DBG_CONTINUE

def hook_Loadlib (pydbg):
    global hook_address, get_proc_addr, virtualalloc_addr, virtualallocex_addr, writefile_addr, virtualfree_addr, virtualfreeex_addr, createremotethread_addr
    is_hooked = 0
    hooks = utils.hook_container()
    hook_address = pydbg.func_resolve_debuggee("kernel32.dll", "LoadLibraryA") #API to hook
    get_proc_addr = pydbg.func_resolve_debuggee("kernel32.dll", "GetProcAddress")
    virtualalloc_addr = pydbg.func_resolve_debuggee("kernel32.dll", "VirtualAlloc")
    virtualallocex_addr = pydbg.func_resolve_debuggee("kernel32.dll", "VirtualAllocEx")
    writefile_addr = pydbg.func_resolve_debuggee("kernel32.dll", "WriteFile")
    virtualfree_addr = pydbg.func_resolve_debuggee("kernel32.dll", "VirtualFree")
    virtualfreeex_addr = pydbg.func_resolve_debuggee("kernel32.dll", "VirtualFreeEx")
    createremotethread_addr = pydbg.func_resolve_debuggee("kernel32.dll", "CreateRemoteThread")
    if (is_hooked != 1):
        if hook_address:
            res = hooks.add(pydbg, hook_address, 0, LoadLib, None)
            is_hooked = 1
            print "[*] LoadLibraryA hooked at: 0x%08x" % hook_address
        else:
            print "[*] Error: Couldn't resolve hook address."
    return DBG_CONTINUE

dbg = pydbg()
dbg.set_callback(EXCEPTION_BREAKPOINT, hook_Loadlib)
found_program = False

for (pid, name) in dbg.enumerate_processes():
 if name.lower() == "iexplore.exe":
  found_program = True
  dbg.attach(pid)

if found_program:
 dbg.run()
else:
 dbg.detach()
       

Snapshot from windbg at the same memory location.

1 comment: