|
|
# Using Api Monitor And Frida
|
|
|
API Monitor is a free software that lets you monitor and control API calls made by applications and services. Its a powerful tool for seeing how applications and services work or for tracking down problems that you have in your own applications.
|
|
|
___
|
|
|
For this example, I will be using API Monitor to figureout what data is being passed when a program launches another program, and I will be using Frida to automatically change the program that will launch.
|
|
|
###Setup
|
|
|
---
|
|
|
Api Monitor is a simple setup. Easy as download and run. [You can find the download here.](http://www.rohitab.com/downloads) I would recommend downloading the portable version as it doesn't require an install and includes the x86 and x64 programs of Api Monitor. This is useful since programs can only be monitored based on bits, so a 32 bit program can only be monitored with Api Monitor x86. API Monitor works by using monitoring Dll calls from a monitored process and showing the data caught from the call. However, API Monitor can also be used for much more too.
|
|
|
|
|
|
|
|
|
### Getting Started
|
|
|
---
|
|
|
Once installed, API monitor may seem a bit cluttered at first which it's 8 windows open, but once you start using it, it gets much easier to navigate.
|
|
|

|
|
|
|
|
|
The 8 windows shown above are API Filter, Running Processes, Monitored Processes, Summary, Parameters, Call Stack, Hex Buffer, and Output.
|
|
|
|
|
|
To set up the capturing of a packet it's as easy as selecting what API Filters you want enabled, which process or processes you want monitored, and seeing the resulting captures in summary when that call is issued. (A walk through of how to set all of this up will be shown in the process of use.)
|
|
|
|
|
|
|
|
|
### Exploitation
|
|
|
---
|
|
|
**Recon**
|
|
|
To exploit an application using API Monitor, first a target process must be decided and what call you want monitored. For this example, Im going to target Steam and change the data of the call when it launches a game. The first thing you must do is select a call you want and work down what you can exploit. Since I'm going to be changing what Steam launches when it launches a game, I'll be working the System Services, Processes and Threads, Process, since it will mostlikely be able to find useful information.
|
|
|

|
|
|
Look at that! It looks like CreateProcessW from the Kernel32.dll gives the string locations of where Steam launches the executable from. I bet we could use this. Change the API Filter to a narrowed down filter so we can get a more specific look at data calls.
|
|
|

|
|
|
Now lets look at the call we got a bit more closely.
|
|
|

|
|
|
This window, gives us parameters of the function as well as the data types, and strings attached to it. Looking as this window shows us that the variables IpApplicationName, IpCommandLine, and IpCurrentDirectory will the be strings we can alter to change what launches. Lets see if it works!
|
|
|
_ _ _
|
|
|
**Testing**
|
|
|
API Monitor has this handy thing where we can set breakpoints and interrupt the data that is being passed to the call. We can set it before, after, and during and error or exception. Lets get a Breakpoint set before the call so we can alter the data that is being passed to the function.
|
|
|

|
|
|
Now lets instigate the action that will make CreateProcessW trigger, and get the data that is passed.
|
|
|

|
|
|
We have hit the breakpoint, this will cause the application you are monitoring to freeze (sometimes it may crash), however this will allow us change the data passed to CreateProcessW. Now that we can see the breakpoint call, we can double click on the string and change it. We can change the string to anything we want, but will changing the application exe locations allow us to change where the program launches? For my testing, I wanted to see if I could change what game was currently trying to be launched, however, this could have been any other exe so it could have been a malicous exe. For all examples in this demo, Ill be testing using the game McPixel as it launched quickly and easy on its own without DRM.
|
|
|

|
|
|
I changed the strings to parameters IpApplicationName, IpCommandLine, and IpCurrentDirectory. Lets see if continuing will launch the game we want.
|
|
|

|
|
|
Look at that it launched McPixel! This means that this is the only data we need to alter to successfully launch a different executable when intercepting the call from Steam! Interestingly, changing this keeps all other information in the Steam overlay connected to Faster Than Light, so Steam did not even noticed we changed anything. Neat!
|
|
|
|
|
|
_ _ _
|
|
|
**Frida**
|
|
|
So, now we know that the function Steam uses to launch programs is CreateProcessW and its located in the Kernel32.dll, so we should be able to create a simple Frida program to auotmatically intercept and the change the launch location without any noticable slow down. To alter the data, I created a program that latches onto the Kernel32.dll and waits until Steam.exe calls the CreateProcessW function. When it does, I take the parameters and change them to run the executable I want it to. (Code seen at bottom of page)
|
|
|

|
|
|
When running Frida and launching a game on Steam, I was able to successfully reroute the launching to my program get McPixel to run without any problem!
|
|
|

|
|
|
That does not look like Faster Than Light to me! I successfullly was able to change the launch path of a executable on the fly using Frida!
|
|
|
|
|
|
### Conclusion
|
|
|
So, through this demo, you were able to see how API Monitor can be used for recon and how it can help track function down to later be exploited using Frida. API Monitor is a powerful tool and can really show how quickly a functions calls can be tracked, intercepted and exploited. API Monitor can also be used for much more than changing the launch path of a function. It can track any of the core Windows DLLs as well as using custom DLLs. So, test it out and see what data are your programs actually passing!
|
|
|
|
|
|
---
|
|
|
|
|
|
###### Frida Code Incase Anyone Was Curious
|
|
|
```
|
|
|
from __future__ import print_function
|
|
|
import frida
|
|
|
import sys
|
|
|
|
|
|
|
|
|
def on_message(message, data):
|
|
|
print("[%s] => %s" % (message, data))
|
|
|
|
|
|
|
|
|
def main(target_process):
|
|
|
session = frida.attach(target_process)
|
|
|
|
|
|
script = session.create_script("""
|
|
|
|
|
|
// Find base address of current imported steamclient.dll by main process steam.exe
|
|
|
var baseAddr = Module.findBaseAddress('steamclient.dll');
|
|
|
console.log('steamclient.dll baseAddr: ' + baseAddr);
|
|
|
|
|
|
var CreateProcessW = resolveAddress(baseAddr, '0x599e5ced'); // Here we use the function address as seen in our disassembler. Got something
|
|
|
CreateProcessW = Module.findExportByName('Kernel32.dll', 'CreateProcessW');
|
|
|
Interceptor.attach(CreateProcessW, { // Intercept calls to our CreateProcessW function
|
|
|
// When function is called, print out its parameters
|
|
|
onEnter: function (args) {
|
|
|
console.log('');
|
|
|
console.log('[+] Called CreateProcessW' + CreateProcessW);
|
|
|
console.log('[+] AppName: ' + args[0]);
|
|
|
console.log('[+] CmdLine: ' + args[1]);
|
|
|
console.log('[+] CurrentDirectory: ' + args[7]);
|
|
|
dumpAddr('Input', args[1], 147); //146
|
|
|
this.outptr = args[2]; // Store arg2 and arg3 in order to see when we leave the function
|
|
|
|
|
|
var bSlash = '\\\\';
|
|
|
console.log(bSlash);
|
|
|
|
|
|
newAppName = 'F:\\\\Applications\\\\Steam\\\\steamapps\\\\common\\\\mcpixel\\\\McLauncher.exe';
|
|
|
newCmdLine= '"F:\\\\Applications\\\\Steam\\\\steamapps\\\\common\\\\mcpixel\\\\McLauncher.exe"';
|
|
|
newDir = 'F:\\\\Applications\\\\Steam\\\\steamapps\\\\common\\\\mcpixel\\\\.\\\\ ';
|
|
|
newDir = newDir.substring(0, newDir.length - 1);
|
|
|
|
|
|
//Clear memory at arguments
|
|
|
clearMem(args[0],146);
|
|
|
clearMem(args[1],147);
|
|
|
clearMem(args[7],129);
|
|
|
|
|
|
Memory.writeUtf16String(args[0],newAppName);
|
|
|
Memory.writeUtf16String(args[1],newCmdLine);
|
|
|
Memory.writeUtf16String(args[7],newDir);
|
|
|
},
|
|
|
|
|
|
// When function is finished
|
|
|
onLeave: function (retval) {
|
|
|
dumpAddr('Output', this.outptr, this.outsize); // Print out data array, which will contain de/encrypted data as output
|
|
|
console.log('[+] Returned from CreateProcessW: ' + retval);
|
|
|
}
|
|
|
});
|
|
|
|
|
|
function clearMem(loc,size){
|
|
|
var outStr = '';
|
|
|
for(var i =0;i<size;i++){
|
|
|
outStr += ' ';
|
|
|
}
|
|
|
Memory.writeUtf16String(loc,outStr);
|
|
|
}
|
|
|
|
|
|
function dumpAddr(info, addr, size) {
|
|
|
if (addr.isNull())
|
|
|
return;
|
|
|
|
|
|
console.log('Data dump ' + info + ' :');
|
|
|
var buf = addr.readByteArray(size);
|
|
|
|
|
|
// If you want color magic, set ansi to true
|
|
|
console.log(hexdump(buf, { offset: 0, length: size, header: true, ansi: false }));
|
|
|
}
|
|
|
|
|
|
function resolveAddress(base,addr) {
|
|
|
var idaBase = ptr(base); // Enter the base address of steamclient.dll as seen in your favorite disassembler
|
|
|
var offset = ptr(addr).sub(idaBase); // Calculate offset in memory from base address in IDA database
|
|
|
var result = baseAddr.add(offset); // Add current memory base address to offset of function to monitor
|
|
|
console.log('[+] New addr=' + result); // Write location of function in memory to console
|
|
|
return result;
|
|
|
}
|
|
|
""")
|
|
|
|
|
|
script.on('message', on_message)
|
|
|
script.load()
|
|
|
print("[!] Ctrl+D on UNIX, Ctrl+Z on Windows/cmd.exe to detach from instrumented program.\n\n")
|
|
|
sys.stdin.read()
|
|
|
session.detach()
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
if len(sys.argv) != 2:
|
|
|
print("Usage: %s <process name or PID>" % __file__)
|
|
|
sys.exit(1)
|
|
|
|
|
|
try:
|
|
|
target_process = int(sys.argv[1])
|
|
|
except ValueError:
|
|
|
target_process = sys.argv[1]
|
|
|
main(target_process)
|
|
|
|
|
|
```
|
|
|
intercept.py |
|
|
\ No newline at end of file |