Python hooks in Windows processes with pe-hedera

Binary instrumentation is one of my favorite approaches when reverse engineering complex software, especially malware. The first step I took in this direction was APIhookLib, a static library written in C that allows setting hooks before and after the execution of functions. The main problem with it was that every time I needed to modify a hook routine I would have to recompile it and retransfer the binary in the lab environment. Wouldn’t it be nice to use an interpreted language like Python to quickly modify the hooks? Meet pe-hedera.

Feature overview

pe-hedera maintains all the functionalities of APIhooklib. It is possible to hook a target function and trigger routines before and after its execution. Target functions can be identified either by name (DLL and symbol) or by address. Several forms of manipulation are available: modify the input parameters or the return value, completely prevent its execution. Read and write the target process memory, as well as switch the hooks to any new process it may spawn. There is also an alternative to custom hook handlers called interactive handler, which is similar to a simplified version of a command-line debugger.

For all the details refer to the README in the Github repo.

VM directory

Some use cases

As my field of application is malware analysis, that is where my examples come from, but I am sure this library can be useful in many other cases.

Avoid simple anti-analysis checks

Often malware performs some recon on the system they land on before going on with their malicious actions. For example, they may not want to execute inside a virtual machine, or in the presence of a specific software like Sysmon or Wireshark. A common implementation puts all these checks inside a single function which returns 1 if the environment is “clean”. Let’s say the static analysis of the (imaginary) sample shows that this function is located at an offset of 0x1200 from the image base. We can use pe-hedera to block the execution of the function and force a return value of 1.

def force_true(hook, args):
    return 1

session = HederaSession(["malware.exe"])
session.initialize()
hook = HederaHook(session,
                  address=session.image_base + 0x1200,
                  after_hook=force_true,
                  do_call=False,
                  override_ret=True)
hook.set()
session.start()

Retrieve Emotet CC server list

The plague of Emotet seems to have finally disappeared after the global takedown operation of February 2021. Still, it makes an excellent case of study for malware analysis. To connect to its CCs, Emotet uses the library function InternetConnectW. Hooking this API allows us to inspect its parameters and retrieve the IP addresses and the ports that the malware tries to contact. An additional aspect of Emotet is that it copies itself in the local appdata folder and launches the copy in a new process, which performs the actual malicious operations.

#sample https://app.any.run/tasks/11ae7dcd-0f53-4d9e-979f-277b3b33773e/

def get_dest_from_InternetConnectW(hook, args):
    # second param = pointer to IP string
    # third param  = port
    data = hook.session.read_mem(args[1], 0x40)
    # extact the wchar string
    tmp = data.split(b"\x00\x00\x00")[0] + b"\x00"
    ip = tmp.decode("utf-16le")
    print("{}:{:d}".format(ip, args[2]))
    # override the first param with NULL
    # to make InternetConnectW fail instantly
    args[0] = 0

session = HederaSession(["emotet.exe"])
session.initialize()
hook = HederaHook(session,
                  dll_name="wininet.dll",
                  function="InternetConnectW",
                  param_num=8,
                  before_hook=get_dest_from_InternetConnectW,
                  override_params=True)
hook.set()
session.start()

VM directory

Limitations and future developments

Together with its features, pe-hedera inherits the limitations of APIhooklib. At the moment it only supports 32-bit executables and it can only handle STDCALL and CDECL calling conventions. These are two aspects I want to improve. Any feedback is more than welcome.

Written on April 5, 2021