Red Team Notes logo Red Team Notes

An antivirus (AV) checks which DLLs or functions our binary is calling. These calls can serve as indicators to determine whether our binary is malicious or not.

Function call obfuscation is a technique used to conceal the DLLs or external functions that will be called during runtime. This can be achieved using standard Windows API functions.

handle = GetModuleHandle("library.dll");
GetProcAddress(handle, "MyFunction");

The following is an example of a program with the VirtualAlloc function:

#include <windows.h>
#include <stdio.h>

int main() {
   
    void * valloc;
    valloc = VirtualAlloc(0, 1000, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    printf("valloc -> 0x%p", valloc);
    return 0;
}

If we check the imports we can see that VirtualAlloc is on the Import Address Table (IAT).

c:\Tools\DropIsec\test>dumpbin /imports test.exe
Microsoft (R) COFF/PE Dumper Version 9.00.30729.01
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file test.exe

File Type: EXECUTABLE IMAGE

  Section contains the following imports:

    KERNEL32.dll
             14000A000 Import Address Table
             14000BCD8 Import Name Table
                     0 time date stamp
                     0 Index of first forwarder reference

                         4F8 VirtualAlloc
                         18C GetCommandLineA
...
                          88 CreateFileA

  Summary

        4000 .data
        1000 .pdata
        3000 .rdata
        9000 .text

The idea of Function Call Obfuscation is to call the function without being on the IAT.

We can search the function pointer with GetModuleHandle and GetProcAddress.

Find the decorator

First we need to find the sintax of the WinAPI on microsoft documentation.

Note: Search for <winapi> msdns.

LPVOID VirtualAlloc(
  [in, optional] LPVOID lpAddress,
  [in]           SIZE_T dwSize,
  [in]           DWORD  flAllocationType,
  [in]           DWORD  flProtect
);

And check in requirements section in which dll is implemented, in that case in kernell.dll.

Obfuscate

Create a pointer global variable which will store the address of the WINAPI and avoid using the literal string of the WINAPI (encrypt or obfuscate it).

typedef LPVOID (WINAPI * t_VirtualAlloc)(
    LPVOID lpAddress,
    SIZE_T dwSize,
    DWORD  flAllocationType,
    DWORD  flProtect
);

We need to find the address and use the new pointer.

t_VirtualAlloc pVirtualAlloc;
pVirtualAlloc = (t_VirtualAlloc)GetProcAddress(GetModuleHandle("kernel32.dll"), "VirtualAlloc");
valloc = pVirtualAlloc(0, 1000, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);

Now VirtualAlloc is not present in the IAT but yes as a hardcoded string.

c:\Tools\DropIsec\test>c:\Tools\Sysinternals\strings.exe -n 8 test.exe | findstr /i "virtual"
VirtualAlloc
pVirtualAlloc -> 0x%p
- pure virtual function call
RtlVirtualUnwind

We can encrypt or obfuscate it:

char sVirtualAlloc[] = {'V','i','r','t','u','a','l','A','l','l','o','c', 0x0};
pVirtualAlloc = (t_VirtualAlloc)GetProcAddress(GetModuleHandle("kernel32.dll"), sVirtualAlloc);

Final code:

#include <windows.h>
#include <stdio.h>

typedef LPVOID (WINAPI * t_VirtualAlloc)(
    LPVOID lpAddress,
    SIZE_T dwSize,
    DWORD  flAllocationType,
    DWORD  flProtect
);


int main() {
   
    void * valloc;
    t_VirtualAlloc pVirtualAlloc;
    char sVirtualAlloc[] = {'V','i','r','t','u','a','l','A','l','l','o','c'};
    pVirtualAlloc = (t_VirtualAlloc)GetProcAddress(GetModuleHandle("kernel32.dll"), sVirtualAlloc);
    valloc = pVirtualAlloc(0, 1000, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    printf("valloc -> 0x%p\n", valloc);
    printf("pVirtualAlloc -> 0x%p\n", pVirtualAlloc); 
    return 0;
}

Clean results:

c:\Tools\test>dumpbin /imports test.exe | findstr /i "virtual"
     426 RtlVirtualUnwind
c:\Tools\test>strings.exe -n 8 test.exe | findstr /i "virtual"
pVirtualAlloc -> 0x%p
- pure virtual function call
RtlVirtualUnwind