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
.