• Stars
    star
    113
  • Rank 310,115 (Top 7 %)
  • Language
    C++
  • License
    MIT License
  • Created over 4 years ago
  • Updated over 4 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

API monitoring via return-hijacking thunks; works without information about target function prototypes.

Prototypeless Hooks

https://travis-ci.org/vovkos/protolesshooks.svg?branch=master https://ci.appveyor.com/api/projects/status/enh19e87fmxhqurc?svg=true

Abstract

The protolesshooks library provides a hooking engine that works without information on target functions prototypes.

This code is intended for use in the upcoming API Spy plugin for IO Ninja; API Spy is going to be an advanced cross-platform alternative for ltrace.

Overview

The idea of API hooking is to intercept calls to system or 3rd-party libraries and redirect those through your spy functions, also known as hooks. Hooking is often required in reverse-engineering and many other non-trivial debugging scenarios. Depending on the chosen hooking method, with hooks you can:

  1. Display API function names called by the process;
  2. Measure the time of each call;
  3. Build a call-graph;
  4. Inspect/modify function call arguments;
  5. Inspect/modify return values;
  6. Block the target function completely.

Most hooking-related libraries, frameworks, and articles focus on injection techniques, i.e., the details of making your hook getting called every time before the original function. Once this task is accomplished, the problem is deemed to be solved -- your hook can now proxy-call the original function, pass its return value back to the caller, and perform logging/argument/retval modification as necessary.

The problem here, however, is that you can't proxy-call without target function prototypes! Yes, it's easy to jump directly to the original function (thus getting the capability (1) of the list above). But for (2), (3), and (5) your hook needs to regain control after return from the target function -- which is trivial with the knowledge of target function prototypes, and quite challenging without.

Not to state the obvious, but to encode prototypes for all the library calls in a process is nearly impossible -- there could be hundreds of different API calls, and many of those may be undocumented.

The protolesshooks library provides return-hijacking thunks that work without the knowledge of target functions prototypes. This makes it possible, for example, to enumerate and intercept all shared libraries in a process, gain a birds-eye overview of the API call-graph, then gradually add prototype information for parameter/retval decoding as necessary.

The prototype information can be incomplete. For instance, we may have some clues about the first two parameters of a particular function, but no idea about the rest. With the traditional hooking (when your hook is inserted into the call chain), it's just not going to work -- you need exact information about the expected stack frame! With protolesshooks it's absolutely fine.

Features

  • Works without information about target function prototypes;
  • Function entry hooks;
  • Function exit hooks;
  • SEH-exception hooks (Windows x64 only);
  • Arguments can be modified before jumping to the target function;
  • Retvals can be modified before returning to the caller;
  • The target function can be blocked if necessary;
  • Thunks can be used with trampoline-based hooking engines, too.

Supported calling conventions:

  • Microsoft x64 (MSC);
  • SystemV AMD64 (GCC/Clang);
  • x86 cdecl (MSC, GCC/Clang);
  • x86 stdcall (MSC, GCC/Clang);
  • x86 __thiscall (MSC);
  • x86 __fastcall (MSC);
  • x86 __attribute__((regparm(n)) (GCC/Clang).

Built-in enumerators for import tables:

  • PE (Windows)
  • ELF (Linux)
  • Mach-O (macOS)

SEH x64 Note

On Windows x64, thunks properly dispatch exceptions to lower SEH handlers without losing the hook after the first exception. This is important because multiple exceptions can occur without unwinding (if one of the SEH filters returns EXCEPTION_CONTINUE_EXECUTION), for example:

void foo()
{
        // recoverable exception happens here...
        ...
        // now unrecoverable exception happens here...
}

int barFilter(EXCEPTION_POINTERS* exception)
{
        if (/* can recover? */)
        {
                // recover, e.g. commit/protect the faulting page
                return EXCEPTION_CONTINUE_EXECUTION;
        }
        return EXCEPTION_EXECUTE_HANDLER;
}

void bar()
{
        __try
        {
                foo();
        }
        __except (barFilter(GetExceptionInformation()))
        {
                // unrecoverable exception is caught here
        }
}

Samples

  • sample_00_trivial

    The hello-world sample. Allocates a basic enter/leave hook for a void function with no arguments; then calls it directly.

  • sample_01_params

    Demonstrates how to decode register/stack arguments and return values.

  • sample_02_enum

    Demonstrates how to enumerate all loaded modules and imports for each module.

  • sample_03_global

    The global interception of all imports in all loaded modules.

  • sample_04_modify

    Demonstrates how to modify register/stack arguments and return values.

  • sample_05_block

    Demonstrates how to pass-through, proxy-call, or completely block the target function.

More Repositories

1

doxyrest

A compiler from Doxygen XML to reStructuredText -- hence, the name. It parses XML databases generated by Doxygen and produces reStructuredText for the Python documentation generator Sphinx.
C++
306
star
2

llvm-package-windows

Provides LLVM binary packages for an (almost) complete Windows build matrix. Built and packaged on GitHub Actions.
Batchfile
114
star
3

jancy

The first and only scripting language with safe pointer arithmetics, high level of ABI and source compatibility with C, spreadsheet-like reactive programming, built-in lexer generator, and more.
C++
61
star
4

ioninja-scripts

Official plugins for IO Ninja
21
star
5

graco

A EBNF-based generator of table-driven top-down parsers of LL(k) grammars featuring predictable & configurable conflict resolution mechanism, ANYTOKEN support, retargetable back-end, etc.
C++
7
star
6

install-inf

A simple Perl script to force-install LibUSB-compatible driver (e.g. winusb.sys) on Windows. Can be used as a lighweight replacement for Zadig.
Perl
6
star
7

ecckey

ECCKey is a command line utility for generating ECC-based product keys. You can use ECCKey as a ready-to-use generator of product keys for shareware products of all kinds.
C++
5
star
8

axl

AXL is a lightweight C++ library featuring Java naming convention, non-zero-terminated UTF-8 string slices as the default string-passing model, Lua-based string template engine, incremental regular expression engine, wrappers for many popular libraries, etc.
C++
4
star
9

doxyrest_b

This is a repository bundle (Doxyrest + AXL). With this bundle you can conveniently build Doxyrest and all the libraries it depends on -- in correct order and from the single source tree.
CMake
4
star
10

llvm-package-travis

Provides LLVM binary packages for a complete build matrix on Travis CI to help you avoid building LLVM and wasting those precious 50 minutes per job.
Shell
4
star
11

rpi-gpio-test

Raspberry Pi kernel GPIO benchmarking test
C
3
star
12

cmakedoxyxml

C++
1
star
13

jancy_b

This is a repository bundle (Jancy + Graco + AXL). With this bundle you can conveniently build Jancy and all the libraries and tools it depends on -- in correct order and from the single source tree.
CMake
1
star