You are currently viewing Obfuscation using Export Table

Obfuscation using Export Table

Hey Folks! Today I am going to share how you can use the export table to obfuscate Winapi calls to bypass Antivirus’s static and dynamic (upto certain extent) detection. So , let’s begin!

 

What is Export Directory

The export directory contains information about functions and symbols that other executable files or libraries can use. When a developer creates a dynamic link library (DLL) or an executable that provides functions for other programs to use, they define these functions as exports. The export directory keeps track of these exported functions, their names, and their memory addresses within the file.

Now let’s understand the structure of Export directory

Structure of export directory

The above picture will give you an overview of the structure of the export directory. Now let’s break down the structure.

  • Name: name of the dll
  • Base:  the number used to subtract from the ordinal number to get the index into the AddressOfFunctions array.
  • NumberofFunctions: Total number of functions exported by the DLL
  • NumberofNames: number of exported names, which need not be the NumberOfFunctions that presents all of the functions exported by module. Rather than that, this field presents only the number of functions exported by name. Functions can also be exported by ordinal, rather than name. If this value is 0, then all of the functions in this module are exported by ordinal and none of them is exported by name.
  • AddressOfFunctions: an RVA to the list of exported functions – it points to an array of NumberOfFunctions DWORD values. Each value is either an RVA pointing to the desired function, or in the case of forwarded functions, an RVA pointing to a forwarding string.
  • AddressOfNames: an RVA to the list of exported names – it points to an array of NumberOfNames DWORD values, each being an RVA to the exported symbol name.
  • AddressOfNameOrdinals: This field is an RVA and points to an array of WORDs. The WORDs are the export ordinals of all the exported functions in this module. However, don’t forget to add in the starting ordinal number specified in the Base field.

You have a little idea of the export directory from the above bookish definition. If you didn’t get what is happening, don’t worry soon you will get it. Just keep in mind that instead of directly calling the Windows API like VirtualAlloc(), we will use the address of these APIs, and how we will get the address by parsing the export table.

 

Working of Export Table

To get the address of an API/Function following steps needed to be done.

  1. Iterate the “AddressOfNames” array from i=0 to i=(NumberOfNames-1), comparing AddressOfNames[i] with the string name3.
  2. Once we have a match in the “i” position, the loader will refer to AddressOfNameOrdinals[i] and get the ordinal associated to this function. Let’s suppose that AddressOfNameOrdinals[i] = 4.
  3. Having the ordinal = 4, the loader will now refer to AddressOfFunctions on 4th position, that is AddressOfFunctions[4], to finally get the RVA associated to the “name3” function.

Now once you got the RVA, 80% of our work is done. We will use the concept of function pointer to see how we can leverage the RVA to get the work done.

The Code

You can refer to the whole source code of Obfuscation here.

If you observe in the main function we are first loading the user32.dll because we want to call the MessageBox() Function through export table. Once we loaded the DLL , we have to get the HAndle to the DLL, which is going to help in parsing the export table.

Once we got the handle , we will call the ParseExportTable Function which is going to give the RVA to the API. Let’s have a look at that function as well.

First we got the base address , we have type casted it as well into character pointer. Once we got the base address then we are going to use that for getting dos header -> nt header -> optional header -> data directory. After getting the pointer to data directory we can now access the export directory. (Please check this to get an idea of how we can parse the PE file)

Now we have the pointer to the export directory , we can get pointers to AddressofNames, AddressofNameOrdinals, and AddressofFunctions.

Using the above three members of export directory structure we will first try to find the index where the string got matched with our API name (“MessageBox”).

  1. Iterating the addressofNames till we got addressofNames[i] matched with “MessageBox”
  2. Once it got matched we will get its ordinal by AddressofOrdinals[i]
  3. After that we can get the RVA by AddressofFunction[AddressofOrdinals[i]]

Once we got the RVA we will add it to the base address, to get the exact address of API. We can use the function pointer to use that RVA as shown below.

 

Also, if the API is in forwarded string format like “ntdll.library_name”, then we can also have that use case covered using the strchr function in string library of C to check if there is “.” present in the forwarded string, if it is present then we can separate the API name using strchr and again  repeat the process to get the address of API, as shown below

It will look something like this on running.

 

References

PE Internals Part 1: A few words about Export Address Table (EAT) – ferreirasc – Hacking, Programming and Random stuff

Exploring the Export Table [Windows PE Internals] – DEV Community

A dive into the PE file format – Introduction – 0xRick’s Blog