WEBVTT

00:00:01.140 --> 00:00:04.260
Let's now discuss API monitoring in more detail.

00:00:04.840 --> 00:00:08.390
API monitoring usually consists of injecting a monitoring

00:00:08.390 --> 00:00:11.460
DLL inside newly created processes.

00:00:12.640 --> 00:00:16.800
The injection is usually performed by Kernel‑mode driver, as explained

00:00:16.800 --> 00:00:22.950
previously. The DLL will leverage an API hooking library, such as Microsoft

00:00:22.950 --> 00:00:29.220
Detours, to hook frequently abused APIs. By hooking an API, the antivirus can

00:00:29.220 --> 00:00:32.110
ensure that if the monitored API is called,

00:00:32.280 --> 00:00:36.400
the call will be proxied by the monitoring DLL, which gives the

00:00:36.400 --> 00:00:40.080
antivirus an opportunity to log the parameters which were passed to

00:00:40.080 --> 00:00:45.550
the API. Antivirus and EDR solutions will usually monitor APIs which

00:00:45.550 --> 00:00:48.340
are regularly used by evasive malware.

00:00:48.440 --> 00:00:52.510
We saw previously that the reflective DLL injection library used by

00:00:52.510 --> 00:00:58.340
Meterpreter makes use of the GetProcAddress, VirtualAlloc, and LoadLibraryA

00:00:58.350 --> 00:01:02.300
APIs, so one could expect those APIs to be monitored.

00:01:02.440 --> 00:01:05.770
Other APIs which can be used to inject malicious code into other

00:01:05.770 --> 00:01:10.670
processes, such as WriteProcessMemory and CreateRemoteThread, are also

00:01:10.670 --> 00:01:14.260
interesting targets for antivirus and EDR solutions.

00:01:14.740 --> 00:01:18.060
Here is an example of what API monitoring looks like.

00:01:18.640 --> 00:01:21.420
On the left‑hand side we have a process which is

00:01:21.420 --> 00:01:23.460
being monitored by an antivirus.

00:01:24.340 --> 00:01:29.200
The antivirus driver has loaded and launched its API monitoring DLL inside the

00:01:29.200 --> 00:01:34.060
process, which in turn has hooked all functions which it needs to monitor.

00:01:35.540 --> 00:01:40.050
When an API call is performed by the process, all the parameters are passed to

00:01:40.050 --> 00:01:44.690
the API monitoring DLL, which can send them to the antivirus so that it can

00:01:44.690 --> 00:01:46.450
perform heuristic analysis.

00:01:47.040 --> 00:01:51.350
The API monitoring DLL will then call the original API on behalf

00:01:51.350 --> 00:01:53.780
of the caller and return the result to him,

00:01:54.030 --> 00:01:56.980
which once again gives the antivirus an opportunity to

00:01:56.980 --> 00:01:59.760
analyze the values returned by the API call.

00:01:59.790 --> 00:02:03.200
On the right‑hand side, you can see what this process looks like

00:02:03.210 --> 00:02:05.960
when no API monitoring is being performed.

00:02:06.240 --> 00:02:10.970
As you can see, when the calls are made, the antivirus has no visibility inside

00:02:10.970 --> 00:02:14.660
the process and therefore cannot perform heuristic analysis.

00:02:15.040 --> 00:02:17.910
You may at this point be wondering why this monitoring cannot

00:02:17.910 --> 00:02:20.850
be performed inside the kernel, this would avoid having to

00:02:20.850 --> 00:02:25.110
inject a monitoring DLL into every user mode process running on

00:02:25.110 --> 00:02:28.810
the system. Unfortunately, or fortunately,

00:02:28.820 --> 00:02:30.370
depending on the way you look at it,

00:02:30.700 --> 00:02:34.980
Microsoft enforces a technology called Kernel Patch Protection,

00:02:34.990 --> 00:02:36.510
also known as Patch Guard,

00:02:36.580 --> 00:02:40.380
which prevents antivirus companies from performing this kind of monitoring

00:02:40.380 --> 00:02:44.930
from inside the Kernel. This technology was originally meant to protect

00:02:44.930 --> 00:02:48.980
systems from rootkits, but has the unfortunate side effect of forcing

00:02:48.980 --> 00:02:51.430
antivirus monitoring inside user mode,

00:02:51.440 --> 00:02:54.200
which as we will discover in later modules, makes this

00:02:54.200 --> 00:02:56.460
approach somewhat flawed by design.

00:02:58.040 --> 00:03:01.400
Let's take a closer look at API monitoring in practice.

00:03:01.840 --> 00:03:05.080
I have placed the shellcode runner, which we wrote during the

00:03:05.090 --> 00:03:07.810
Meterpreter deep dive module, on the desktop.

00:03:07.850 --> 00:03:13.360
I have also placed a folder on the desktop called EDR, which contains two

00:03:13.360 --> 00:03:18.190
monitoring DLLs, as well as the driver which will register the callback

00:03:18.190 --> 00:03:22.950
routines and trigger the DLL injections when new processes are started on the

00:03:22.950 --> 00:03:28.310
machine. I have configured the monitoring DLLs to hook the VirtualAlloc and

00:03:28.310 --> 00:03:34.230
LoadLibraryA APIs, which if you recall, were used in our shellcode runner, as

00:03:34.230 --> 00:03:35.680
well as the stager itself.

00:03:35.690 --> 00:03:38.060
When calls are made to these two functions,

00:03:38.140 --> 00:03:41.970
the monitoring DLLs will print the recorded activity to a

00:03:41.970 --> 00:03:47.170
debugger. Real antivirus or EDR would of course send this data to

00:03:47.170 --> 00:03:50.150
its engine to perform analysis on the data.

00:03:50.210 --> 00:03:55.650
To start the driver, I ran the sc start command from an elevated command prompt.

00:03:56.080 --> 00:03:57.300
Once started,

00:03:57.310 --> 00:04:01.170
I opened Debug view to capture the debug messages which

00:04:01.170 --> 00:04:02.930
are recorded by the monitoring DLLs.

00:04:03.360 --> 00:04:08.160
I then launched the stager shellcode runner, which is located on the desktop.

00:04:08.640 --> 00:04:13.340
If we take a look at the running processes and search for our shellcode runner,

00:04:13.420 --> 00:04:17.570
you will notice it has the process idea of 936. Since this

00:04:17.570 --> 00:04:19.670
was compiled as a console application,

00:04:19.680 --> 00:04:24.970
you will also find a child process which was spawned, called conhost.exe,

00:04:25.170 --> 00:04:30.430
which has a process ID of 8968. If we observe the

00:04:30.430 --> 00:04:32.770
loaded modules in Process Explorer,

00:04:33.020 --> 00:04:37.270
we can also see that our monitoring DLL has indeed been injected.

00:04:37.360 --> 00:04:39.760
If we now move over to Debug view,

00:04:39.840 --> 00:04:43.520
we can see that the driver's callback routine was notified by the

00:04:43.520 --> 00:04:47.990
kernel that these two processes were being spawned and was able to log

00:04:47.990 --> 00:04:52.480
the command line used to start them. Next, we can see that the DLL was

00:04:52.480 --> 00:04:56.540
successfully injected into both the conhost and shellcode runner

00:04:56.540 --> 00:04:58.260
processes by the driver.

00:04:59.240 --> 00:05:03.290
We can also see that the hooking library which the DLLs are using was able to

00:05:03.290 --> 00:05:07.710
hook the LoadLibraryA and VirtualAlloc APIs successfully.

00:05:07.770 --> 00:05:11.050
We can then see that a call to VirtualAlloc was made

00:05:11.060 --> 00:05:12.950
by the shellcode runner's process.

00:05:13.340 --> 00:05:17.900
You may recall that our shellcode runner does indeed allocate memory using

00:05:17.900 --> 00:05:21.560
this API in order to place the stager's shellcode into it.

00:05:22.240 --> 00:05:27.040
In this case, I chose to log the start address of the memory to be allocated,

00:05:27.040 --> 00:05:31.600
which in our case is null. If we take a look at the prototype on MSDN for

00:05:31.600 --> 00:05:35.760
VirtualAlloc, we can see that this is normal and this means that the system

00:05:35.760 --> 00:05:38.230
will choose where the memory is allocated.

00:05:38.370 --> 00:05:42.940
I also logged the memory protection value which was passed to the API.

00:05:43.440 --> 00:05:46.560
In our case, we can see that the value was hex 40.

00:05:47.140 --> 00:05:51.250
If we look this up on MSDN once again, we can see that this

00:05:51.250 --> 00:05:54.900
corresponds to readwrite execute memory permissions.

00:05:55.640 --> 00:05:59.120
We can then see that a call to LoadLibrary was performed

00:05:59.120 --> 00:06:01.250
by the shellcode runner's process.

00:06:02.540 --> 00:06:07.280
You may recall that the reverse HTTP Meterpreter stager's shellcode makes

00:06:07.280 --> 00:06:11.970
use of this API to load the WinINet library in order to leverage some of

00:06:11.970 --> 00:06:16.740
its exported functions to communicate over HTTP. We can then see a few

00:06:16.740 --> 00:06:20.500
more calls to VirtualAlloc. These were probably performed by the

00:06:20.500 --> 00:06:24.820
reflective DLL injection library when execution was transferred to the

00:06:24.820 --> 00:06:28.500
payload by the stager. We can then see that several calls were made to

00:06:28.500 --> 00:06:29.450
LoadLibrary.

00:06:29.900 --> 00:06:32.760
This is also due to the reflective loader, which went ahead

00:06:32.760 --> 00:06:35.120
and loaded the payload's dependencies.

00:06:35.230 --> 00:06:36.290
As you can imagine,

00:06:36.360 --> 00:06:40.490
the monitoring DLLs could also have logged the return parameters

00:06:40.500 --> 00:06:43.060
of the various API calls which were performed.

00:06:44.340 --> 00:06:47.760
A good example would be the calls to VirtualAlloc, which return

00:06:47.760 --> 00:06:50.250
a pointer to the allocated memory buffer.

00:06:50.840 --> 00:06:54.280
An antivirus could trigger a scan of that memory after it

00:06:54.280 --> 00:06:57.760
has been allocated to check if it contains specific byte

00:06:57.760 --> 00:07:00.050
sequences at various offsets.

00:07:00.840 --> 00:07:04.330
A good example of a static byte sequence are the Rot13

00:07:04.330 --> 00:07:06.390
hashes we talked about previously,

00:07:06.540 --> 00:07:09.230
which are commonly used by antivirus solutions.

00:07:09.370 --> 00:07:13.290
Another big giveaway is the fact that the calls to VirtualAlloc all

00:07:13.290 --> 00:07:16.560
requested readwrite and execute memory pages,

00:07:17.040 --> 00:07:20.300
which is a good sign that code might be obfuscated and will

00:07:20.300 --> 00:07:22.980
be deobfuscated in memory at runtime.
