Home > Mobile >  Intel Pin: malloc and free calls do not return immediately (Windows)
Intel Pin: malloc and free calls do not return immediately (Windows)

Time:01-05

I wrote a pintool for Intel Pin (3.25) that traces malloc and free calls before and after they are executed. Here is my code:

#include "pin.H"
#include <iostream>

VOID before_malloc(char* img_name, int size)
{
    printf("--> malloc(%d) (%s)\n", size, img_name);
}

VOID after_malloc(char* img_name, ADDRINT ret)
{
    printf("--> malloc returned %lx (%s)\n", ret, img_name);
}

VOID before_free(char* img_name, ADDRINT addr)
{ 
    printf("--> free(%lx) (%s)\n", addr, img_name);
}

VOID after_free(char* img_name, int ret)
{
    printf("--> free returned %d (%s)\n", ret, img_name);
}

VOID Image(IMG img, VOID* v)
{
    RTN rtn;

    const char* img_name = IMG_Name(img).c_str();

    // malloc
    rtn = RTN_FindByName(img, "malloc");
    if (RTN_Valid(rtn))
    {
        RTN_Open(rtn);

        RTN_InsertCall(rtn, IPOINT_BEFORE, (AFUNPTR)before_malloc,
            IARG_PTR, img_name,
            IARG_FUNCARG_ENTRYPOINT_VALUE, 0,
            IARG_END);

        RTN_InsertCall(rtn, IPOINT_AFTER, (AFUNPTR)after_malloc,
            IARG_PTR, img_name,
            IARG_FUNCRET_EXITPOINT_VALUE,
            IARG_END);

        RTN_Close(rtn);
    }

    // free
    rtn = RTN_FindByName(img, "free");
    if (RTN_Valid(rtn))
    {
        RTN_Open(rtn);

        RTN_InsertCall(rtn, IPOINT_BEFORE, (AFUNPTR)before_free,
            IARG_PTR, img_name,
            IARG_FUNCARG_ENTRYPOINT_VALUE, 0,
            IARG_END);

        RTN_InsertCall(rtn, IPOINT_AFTER, (AFUNPTR)after_free,
            IARG_PTR, img_name,
            IARG_FUNCRET_EXITPOINT_VALUE,
            IARG_END);

        RTN_Close(rtn);
    }
}

int main(int argc, char* argv[])
{
    if (PIN_Init(argc, argv))
    {
        printf("PIN_Init failed\n");
        return -1;
    }

    PIN_InitSymbols();

    IMG_AddInstrumentFunction(Image, 0);

    PIN_StartProgram();

    return 0;
}

To test this, I wrote a simple function that allocates some memory, copies a string to that memory, prints the string, and finally frees the memory.

int main()
{
    char* string = (char*)malloc(32 * sizeof(char));
    strcpy(string, "Lughnatic");
    printf("Your name is: %s\n", string);
    free(string);
    return 0;
}

Here is the output when I run the pintool:

--> malloc(32) (C:\path\to\heap_demo.exe)
Your name is: Lughnatic
--> free(a3e7f630) (C:\path\to\heap_demo.exe)
--> malloc(9327) (C:\WINDOWS\System32\msvcrt.dll)
--> malloc returned b8781260 (C:\WINDOWS\System32\msvcrt.dll)
--> malloc(544) (C:\WINDOWS\System32\msvcrt.dll)
--> malloc returned b8785ba0 (C:\WINDOWS\System32\msvcrt.dll)
--> free(b8781260) (C:\WINDOWS\System32\msvcrt.dll)
--> free returned 1 (C:\WINDOWS\System32\msvcrt.dll)
--> malloc(160) (C:\WINDOWS\System32\msvcrt.dll)
--> malloc returned b87894b0 (C:\WINDOWS\System32\msvcrt.dll)
--> malloc(24) (C:\WINDOWS\System32\msvcrt.dll)
--> malloc returned b8789560 (C:\WINDOWS\System32\msvcrt.dll)
--> malloc(40) (C:\WINDOWS\System32\msvcrt.dll)
--> malloc returned b8789580 (C:\WINDOWS\System32\msvcrt.dll)
--> free(b8780860) (C:\WINDOWS\System32\msvcrt.dll)
--> free returned 1 (C:\WINDOWS\System32\msvcrt.dll)
--> free(b8789560) (C:\WINDOWS\System32\msvcrt.dll)
--> free returned 1 (C:\WINDOWS\System32\msvcrt.dll)
--> free(b87894b0) (C:\WINDOWS\System32\msvcrt.dll)
--> free returned 1 (C:\WINDOWS\System32\msvcrt.dll)
--> free(b8789580) (C:\WINDOWS\System32\msvcrt.dll)
--> free returned 1 (C:\WINDOWS\System32\msvcrt.dll)
--> free(b87884a0) (C:\WINDOWS\System32\msvcrt.dll)
--> free returned 1 (C:\WINDOWS\System32\msvcrt.dll)

It can be seen that the calls to malloc and free by the application do not trigger the calls to after_malloc() and after_free(), which should execute when those functions return. According to the docs regarding IPOINT_AFTER, Pin will instrument all return paths. Does this mean Windows application calls to malloc and free do not return in the traditional sense? Can anyone explain what's happening here?

FYI, I am testing Windows 11 and Pin 3.25. The pintool was compiled using Microsoft's C/C Optimizing Compiler Version 19.34.31933 for x64 (cl.exe). I have already tested this on Linux and it works as expected.

CodePudding user response:

I disassembled malloc and free using Ghidra. malloc is a single jmp instruction to _malloc_base. free consists of 2 mov instructions followed by a jmp to _free_base. So my guess is that Pin does not recognize jmp instructions as a return path. I solved the issue by changing the pintool to instrument _malloc_base and _free_base.

  • Related