thematrix: PE Loader and Windows API tracer

Windows API tracer

TheMatrix

This project was created to ease the malware analysis process. The goal is to create an activator binary whose purpose is to load a user-defined binary and monitor the execution by using Win32 API hooks. Relevant data is then saved to disk. The code supports both x86 and x64 binaries.

Windows API tracer

Usage

To monitor a new binary is necessary to create an activator. The activator will load and monitor a user input binary. To create an activator use the -add option. An example of usage is the following one:

c:\>TheMatrix.exe -add c:\path\to\my\binary.dll
Activator file created
c:\>regsvr32.exe TheMatrix.build.dll

This command will create a new PE file representing the activator. The activator will have the same format (DLL or EXE) of the input binary.

Once created, you can just run it in you preferred way (for DLL the suggested way is to use the rundll32.exe utility).

During the execution the data generated by the monitored functions is saved to ./Desktop/thematrix/[process ID]/ (this depends on the log_data function implemented in utility.c).

Limitation:

  • The project modifies the PEB.Ldr structure in order to allow specific APIs to work correctly (such as GetModuleHandle, …). If you run the activator on a WOW64 system (x86 binary on an x64 OS), only the x86 PEB.Ldr is modified (WOW64 processes have both x86 and x64 PEB). When the CPU changes to x64, the Windows Native APIs (ntdll.dll) will use the x64 version of PEB.Ldr. This implies that the activator might not work properly. To be sure that the x86 works, run the binary on an x86 OS.

  • The newly created file does not export all the methods and does not contain the original file resources. This will cause possible errors, for example if a DLL calls GetModuleFileName -> LoadLibrary -> FindResource. This code path will load the original TheMatrix DLL that does not contain the wanted resource.

Customization

Adding new functions to the monitor is an easy task, have a look at the hooks.c file for some examples of Kernel32.dll and bcrypt.dll hooks. To add a new hook is enough to call the function hook_add. Below an example of hook creation is shown:

LPVOID __stdcall hook_BCryptEncrypt(BCRYPT_KEY_HANDLE hKey, PUCHAR pbInput, ULONG cbInput, VOID* pPaddingInfo, PUCHAR pbIV, ULONG cbIV, PUCHAR pbOutput, ULONG cbOutput, ULONG* pcbResult, ULONG dwFlags)

{
// save plain data
if (cbInput) {
char name[MAX_PATH] = { 0 };
snprintf(name, sizeof(name), "BCryptEncrypt_%llx_%d", (uint64_t)pbInput, cbInput);
log_data(cbInput, pbInput, name);
}

LPVOID ret = call_original(
hKey,
pbInput,
cbInput,
pPaddingInfo,
pbIV,
cbIV,
pbOutput,
cbOutput,
pcbResult,
dwFlags
);
return ret;
}

hook_add("Bcrypt.dll", "BCryptEncrypt", hook_BCryptEncrypt);

 

The function must have the same signature of the hooked function. The function call_original is used to call the original function. It is enough to call this function with the original function input parameters, the framework will do all the heavy work for you in order to call the correct function 😉 The call to the call_original function must be performed in the same thread executing the hook, otherwise, the process will crash.

Download & Tutorial