If you take a look at an unpacked Emotet sample, something will certainly stick out to you. The sample will have few to no imports. Yet the malware is clearly making heavy use of the Windows API to achieve its objectives. So how is it doing this? It is making use of a well-known shell coding technique to dynamically load APIs at runtime without the use of strings.
Emotet is locating the DLL name from the Process Environment Block. The malware will search for the desired module name and then locate the image base. From the image base of the located module, it is then able to walk the export table locating function pointers for its own import table. In Windows, the FS register points to the Thread Environment Block, or TEB. The offset 0x30 contains a pointer to the Process Environment Block, or PEB. From there the malware will walk the structure to _PEB_LDR_DATA which contains the head of a doubly-linked list called InMemoryOrderModuleList. This list contains the list entries containing BaseDllName and DllBase. When the entry point to the PE header is located, the PE structure is walked to find the export table. Emotet will then loop over the exported names to find the API function it is searching for.
Let’s take a look at this in action. The sample I am looking at is 0b96754a84bc2c01e4e8d64a534c03b5636fb6e958f7c381f9c27e646466cd32.
Sub_403640 starts off by grabbing a reference to the TEB and then grabbing a pointer to the PEB at offset 0x30. From there, a pointer to the _PEB_LDR_DATA structure is saved off along with the module hash that was stored in ecx prior to the function call.
The code then loops over the BaseDllNames comparing them to the module hash. If the hashed BaseDllName matches the hash that was passed in, the DllBase is moved into eax prior to returning from the function.
The next function to look at is sub_4037C0 which locates the specific API in the selected module. Two parameters are moved into registers for this function call. edx contains the hash and ecx will contain the module address that was just resolved. The beginning of the function starts by getting the offset of the PE header. Next, the RVA of the IMAGE_DIRECTORY_ENTRY_EXPORT is located. From there, the table of exported functions is located which is an RVA from the base of image. The function then begins a loop over the exported functions calculating a hash of each function name as it progresses. The function pointer is located by getting the RVA of the ordinals and then finding the specific ordinal of the function. The RVA of function pointers is then located before locating the specific RVA of the function. The RVA is converted to a virtual address before being stored.
The two function calls Sub_403640 (GetModuleAddress) and sub_4037C0 (GetAPIAddress) will be paired together throughout the code. Once Emotet has resolved the API in a given module, parameters are pushed onto the stack before the call eax.