Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Hooking Functions (Part 1)

DZone's Guide to

Hooking Functions (Part 1)

Function hooking is just one of the ways that a malware author can capture control of a program.

· Security Zone
Free Resource

Discover an in-depth knowledge about the different kinds of iOS hacking tools and techniques with the free iOS Hacking Guide from Security Innovation.

One of the primary goals of a malware author is to capture control of a program. I'm going through a variety of different ways we can do this, including techniques like shellcode injection, return-to-libc attacks, and return oriented programming. There are other tricks you can use too, and we'll cover one of those here.

Today, we're going to discuss function hooking.

The example I'm going to cover is more accurately referred to as function interposingon MacOS and iOS, and you can use it to intercept function calls. It uses specific commands in generated executable images (libraries specifically) and environmental settings to tell the program loader to load specific functions in the place of others. We're going to go through a simple example where we intercept calls to malloc(.) and free(.). This approach is based on Jon Levin's example in Mac OS X and iOS Internals (great book - his new book, *OS Internals Volume III, is even better). That example doesn't work anymore; however, this one does.

Function Interposing

Okay, so what is this function interposing thing? Basically, you need to do a couple of things. First, you need to compile the library such that the generated binary code has the appropriate loading commands. These commands will tell the loader to take functions defined in the library and replace other indicated functions with them. In this example, I've changed the functions themselves very little from Jon's original functions, but I've changed the way I go about interposing in that I've pulled a macro from dyld-interposing.h and I use that to instruct the compiler to generate interposing code. The specific macro is:

#define INTERPOSE(_replacement, _replacee) \
    __attribute__((used)) static struct { \
        const void* replacement; \
        const void* replacee; \
    } _interpose_##_replacee __attribute__ ((section("__DATA, __interpose"))) = { \
        (const void*) (unsigned long) &_replacement, \
        (const void*) (unsigned long) &_replacee \
    };

I know, kind of a mess, but it basically defines a structure of a specific format with attributes that create the interposing section within the generated library. After compilation, if you take a look at the generated binary, you'll see this:

$ otool -lvV libInterposeMalloc.dylib | less
...
sectname __interpose
   segname __DATA
      addr 0x0000000000001028
      size 0x0000000000000020
    offset 4136
     align 2^3 (8)
    reloff 0
    nreloc 0
      type S_REGULAR
attributes (none)
 reserved1 0
 reserved2 0
 ...

If we break out IDA, we can see this in the library as well:

__interpose:0000000000001028 __interpose     segment para public '' use64
__interpose:0000000000001028                 assume cs:__interpose
__interpose:0000000000001028                 ;org 1028h
__interpose:0000000000001028                 assume es:nothing, ss:nothing, ds:nothing, fs:nothing, gs:nothing
__interpose:0000000000001028 __interpose_free dq offset _my_free
__interpose:0000000000001030                 dq offset __imp__free
__interpose:0000000000001038 __interpose_malloc dq offset _my_malloc
__interpose:0000000000001040                 dq offset __imp__malloc
__interpose:0000000000001040 __interpose     ends

I'll spare you the disassembly of the functions we've implemented (if you're dying to know otool -p _my_malloc -tvV libInterposeMalloc.dylib, I will show you some of it). Here's the relevant library C code, which you compile with clang -dynamiclib -o libInterposeMalloc.dylib interpose_malloc.c(where interpose_malloc.c is the name of the file):

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <malloc/malloc.h>

#define INTERPOSE(_replacement, _replacee) \
    __attribute__((used)) static struct { \
        const void* replacement; \
        const void* replacee; \
    } _interpose_##_replacee __attribute__ ((section("__DATA, __interpose"))) = { \
        (const void*) (unsigned long) &_replacement, \
        (const void*) (unsigned long) &_replacee \
    };

void *my_malloc (int size)
{
    void *returned = malloc(size);
    malloc_printf("[+] %p %d\n",returned, size);
    return (returned);
}

void my_free (void *freed)
{
    malloc_printf("[-] %p\n", freed);
    free(freed);
}

INTERPOSE(my_free,free);
INTERPOSE(my_malloc,malloc);

Here, the my_malloc(.) and my_free(.) functions are Jon's original interposing functions, with some very small changes. The INTERPOSE(.) macro is copied from Apple's open-source dynamic loader code, formatted for readability. Now we can build the library and we can see the code we generate; next, we'll write a small executable and see interposing in action. We'll go over this next time.

Learn about the importance of a strong culture of cybersecurity, and examine key activities for building – or improving – that culture within your organization.

Topics:
function hooking ,security ,function interposing

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}