FridaTrace++ – quick & dirty API monitor

In my two previous posts I described:

I’ve been experimenting with improving Frida Trace tool to enrich its output. Since the tool allows for rapid prototyping I decided to incorproate that SDK into it. After few weeks of endless coding that took barely 2-3h I came up with a first version of auto-generated handlers.

How does it work?

  • Install Python 3.7
  • Install Frida
  • Run automation (perl script) and build handlers for 16K APIs automagically
  • Place them in c:\python\__handlers__\
  • Run frida-tools

This is how it looks in practice:

  • c:\python\Scripts\frida-trace.exe c:\windows\notepad.exe -i *CreateFile*

You will notice that:

  • Instead of just an API name, we can now see a DLL name, actual API name, and all the arguments and their names as per SDK, and their values as well:
    • KernelBase.dll!CreateFileW (lpFileName=”C:\Windows\Fonts\staticcache.dat” (0x6483f8b310), dwDesiredAccess=GENERIC_READ (0x80000000), dwShareMode=0x5, lpSecurityAttributes=0x0, dwCreationDisposition=0xb6f000000003, dwFlagsAndAttributes=0x6400000000, hTemplateFile=0x0)
  • Return values are shown
    • RET = 0x<hex> /Kernel32.dll!CreateFileW/
  • For some arguments I added additional data enrichment
    • Extraction of file names passed to CreateFile* functions (also see below comment on all generic string arguments)
    • dwDesiredAccess is converted to a more readable flag dwDesiredAccess=GENERIC_READ (0x80000000) – this was a test of an idea, and it seem to work so can probably pretty quickly expand other attributes as well

If you look at the prototype files you will notice that they include a snapshot of SDK information which can help to manually develop code of a given API further:

The flag expansion idea I mention above can be best explained using the actual code – we build an array of masks, and walk through all of them, adding relevant strings as we walk through it (this code is not finished; and for some cases it will be just a direct comparison, not bit testing):

onEnter: function (log, args, state) {
GENERIC_READ      = 0x80000000
GENERIC_WRITE     = 0x40000000
GENERIC_EXECUTE   = 0x20000000
GENERIC_ALL       = 0x10000000

FILE_SHARE_READ   = 0x000000001
FILE_SHARE_WRITE  = 0x000000002
FILE_SHARE_DELETE = 0x000000004

masks =
[
  GENERIC_READ      , 'GENERIC_READ ',
  GENERIC_WRITE     , 'GENERIC_WRITE ',
  GENERIC_EXECUTE   , 'GENERIC_EXECUTE ',
  GENERIC_ALL       , 'GENERIC_ALL ',

  FILE_SHARE_READ   , 'FILE_SHARE_READ ',
  FILE_SHARE_WRITE  , 'FILE_SHARE_WRITE ',
  FILE_SHARE_DELETE , 'FILE_SHARE_DELETE '
]
dwDesiredAccess = ''

for (i = 0; i < masks.length/2; i++)
  {
    res = args[1] & masks[i*2]
    if ((res == masks[i*2]) || (res==-masks[i*2]))
     {
       if (dwDesiredAccess != '') { dwDesiredAccess = dwDesiredAccess + ' | ' }
       dwDesiredAccess = dwDesiredAccess + masks[i*2+1]
     }
  }
    log('Kernel32.dll!CreateFileW ('+
  'lpFileName='+'"' + args[0].readUtf16String() + '" (' + args[0] + ')'+', '+
  'dwDesiredAccess='+'' + dwDesiredAccess + '(' + args[1] + ')'+', '+
  'dwShareMode='+args[2]+', '+
  'lpSecurityAttributes='+args[3]+', '+
  'dwCreationDisposition='+args[4]+', '+
  'dwFlagsAndAttributes='+args[5]+', '+
  'hTemplateFile='+args[6]+')');
}

Quick and dirty stats on argument names across the whole SDK gave me this nice list:

  • dwFlags 1053
  • hdc 566
  • Flags 422
  • hWnd 352
  • hProcess 331
  • pszPath 227
  • hwnd 217
  • hKey 202
  • lpBuffer 201
  • error 187
  • lParam 175
  • engineHandle 174
  • riid 162
  • lpName 161
  • hFile 158
  • ServerIpAddress 157
  • lpFileName 156
  • Buffer 152

With that list I was able to identify a couple of arguments that are obvious strings – as a result I added argument expansion for them as well. We can see this in action here:

c:\python\Scripts\frida-trace.exe c:\windows\notepad.exe -i *strcmp*

When I ran the above command the first time I noticed that my handlers were missing msvcrt.dll prototypes for strcmp & _strcmpi so I added them manually copypasta-ing the prototypes for lstrcmp. This is obviously something that needs work as this particular library (and its versions) are very popular. Then we can think of VB programs, etc. – this just needs more time.

And speaking of time… time for a little bonus.

If you run this:

  • c:\python\Scripts\frida-trace.exe c:\windows\system32\cmd.exe -i *CreateFile* -i FindFirstFile*

you will run cmd.exe in a window of your current Frida Trace session.

So, as you type commands you can literally inspect which API calls are made to deliver given functionality. On the attached screen you can see how FindFirstFileExW API is executed to find files as per the wildcard ‘foo*’. After creating a file ‘foobar’, we can see how it is being accessed by CreateFileW.

This is literally the fastest API monitoring ever. I will be spending more time improving the handlers & when I am happy with the outcome I will post my automation script here.

My first encounter with Frida

My first real job was a web programmer. Yes, I know. I have no idea either.

This is how I learned HTML, CSS, JavaScript, perl, and php. Today all of it is obsolete, but still brings me a lot of fruits, because at least I am able to compare how many things have changed… well… since back then. Yup, this is what old people do – the fruits are totally rotten.

Today’s JavaScript is not what it used to be, and it’s funny that it became ‘the’ language of the future unlike Java. Speaking of the latter, the Java situation is so dire that it bleeds my heart to describe an observation that I made recently. Once upon a time the wet dream of futurologists is now so obscene and obsolete that infosec found a hipster-driven pleasure in taking it over as a de facto lingua franca of their beloved software creation. There are two separate phrases of French origin in my previous sentence – I encourage you to re-visit it and take pleasure in re-reading them without understanding. Back to Java. One can’t be a red teamer if one doesn’t use at least one Java-based product e.g. Burp. So is the blue teamer that is now using Ghidra – NSA had to be super pissed of with Ilfak’s pricing model to get us here … But I digress.

Seeing JavaScript penetrating every single corner of the virtual world, starting with good ol’ web 1.0, going via JQuery, node.js, React, and tones of other libraries, and then empowering the bloatware emperor aka Elektron applications, anyone who loves machine code, purity of Windows API, direct access to registers, memory, and fundamentally loves full control over the box… shivers when they hear of JavaScript.

These long paragraphs above serve as a personal journey through a catharsis process that this post is about.

I spent many months writing my assembly-based sandbox (the adventure I described in my sandboxing series), so I couldn’t bear the idea that I would be using JavaScript to do API monitoring. This was not the first time – Pedram Amini’s PaiMei python-based framework was and still is a brilliant insult to the purity of raw assembly-based API monitoring. Took me long time to get used to it, I hated it, no… I loathed it… but used it, eventually… and now, in a hindsight I see how revolutionary concept it really was. Because JavaScript-based API monitoring frameworks borrow a lot from that concept… they use python.

Okay, but what am I actually talking about?

I recently posted about limitations of API Monitoring on Windows 10. Around 20,000 people came back to me after that post – many of whom turned out to be just a bunch of infosec Kardashians looking for a virtual selfie with me – and only a few individuals less annoying than me provided actual suggestion. One of them was Frida. I put it on my todo list.

My first time with Frida was… picturesque.

I am not kidding you. I went to the site, ran ‘pip’ to install the thing as they said…:

… and this darn thing installed w/o any issue. w…t… h… I am so used to whine about open source projects requiring a lot of troubleshooting that I am still looking for my jaws somewhere in my basement.

That was just the beginning.

I tried some sample code I bookmarked earlier and hell.. it worked the very first time (only change I had to do was a mod to the address of the function that sample code was hooking, which was different due to ASLR).

I then tried frida-trace:

c:\python\Scripts\frida-trace.exe c:\windows\notepad.exe -i *CreateFile*

Are you kidding me?

Out of the box this thing builds a repo of prototypes for all API functions that it hooked:

All you have to do is .. mod it to your needs:

Seriously… After 20 years I am finally sold on JavaScript…