W
Wave
Thread author
Previous thread: https://malwaretips.com/threads/malware-analysis-1-introduction.61972/
Hello and welcome to my thread on Malware Analysis.
[DISCLAIMER]
I have intentionally set the font size to 3 because this thread is very long and with the normal font size it may actually be even more of a pain to go through... I highly recommend you zoom in once in your browser, and it will appear much nicer to read the text (as opposed to reading it without zooming in once or as it is by default).
If you find any false information/mistakes in this thread then please let me know so I can fix them.
[/DISCLAIMER]
In this tutorial we will be performing static analysis: checking the dynamically linked imports of a PE (Portable Executable). For this tutorial I will be using IDA (from Hex Rays) however since not everyone may want to jump into using IDA due to its complexity to start off, I will also be making an additional part to this tutorial which will demonstrate how to check the imports using different tools. This tutorial will have four parts – the first part will be theory based, the second part will be about explaining how we actually check for the imported functions (whilst using a clean test sample) whereas the third part will be doing it again but with a malicious sample. The fourth (additional) part will be explaining how to use other tools to check for the imports for future reference, should anyone run into trouble with using other tools for it.
All images will be placed within a SPOILER (spoiler tags).
Below the information regarding the requirements to carry out this tutorial you will find a part under the title “Theory”.
What you will need to follow this tutorial (prerequisites):
- An environment for performing malware analysis (a secure, working and set-up Virtual Machine will do just fine).
- IDA (for the Part 2 & 3 of this tutorial - the free version should be fine if you do not have the pro version).
- FileAlyzer/PE Explorer (for the Part 4 of this tutorial).
- Samples to practise on (check below for the download links).
You can download the clean test sample which I made myself for the purpose of this tutorial from the following link: Private file (remember that this is a clean test sample although running it is really pointless - it's all setup to have some imported functions for the main tutorial part - there is no password to the archive since it is 100% clean).
You can download the malicious sample we will be using for the second part of the tutorial from the following link: hxxp://www78.zippyshare.com/v/dBUabsTF/file.html/ (the sample is not packed) (warning: this download is malicious and you should only download it from within your secure analysis environment – replaced http with hxxp for security purposes & the archive password is infected).
The link in the custom fields for this thread will lead to the malicious sample (and the VT analysis will be for the malicious sample of course).
Theory
PE stands for Portable Executable and you can identify a Portable Executable based on the first few bytes in the binary (and through checking for information regarding DOS in the bytes of the binary). As well as this, you can identify a PE based on its extension (*.exe), however even if the extension is not for a PE this does not mean it is not really a PE. For example, you can have the extension of a Portable Executable different to that of *.exe, even though you won’t be able to open it up normally (but if it is really a PE you can find out through the bytes in the binary – first bytes should be “MZ” and following all this near the top should be information about DOS). If the extension is not *.exe but the binary is indeed a real PE file, it can actually be loaded and executed (regardless of the extension change – but not done through clicking the file to open it for example).
The hexadecimal representation for the start of the PE format (“MZ”) would be 4D 5A. Underneath this should be bytes for things relating to DOS (e.g. “This program cannot be run in DOS mode” which in hex would be 54 68 69 73 20 70 72 6F 67 72 61 6D 20 63 61 6E 6E 6F 74 20 62 65 20 72 75 6E 20 69 6E 20 44 4F 53 20 6D 6F 64 65). There is also the PE File Signature which is explained further down.
Every Portable Executable has parts/sections and there are many of these with different purposes.
The first parts to a PE is the MZ Header (as discussed above) and a stub for MS-DOS (which is 38 bytes in size). You may be asking yourself why there is a stub with a size of 38 bytes for MS-DOS and the reason behind this is because there needs to be some sort of backwards compatibility so if someone attempts to run a program on MS-DOS it will let them know that it is not supported (which is why there is the error message text “This program cannot be run in DOS mode” found – this is from the MS-DOS stub and the MZ header is also for MS-DOS).
The next part to a PE file is the PE File Header which is very important. The PE File Header contains information such as the PE File Signature (which is for the Windows Loader – the signature is PE00 (50 45 00 00)), information regarding machines the Portable Executable can be run on (e.g. Intel processors), information regarding the size of the sections table, information regarding the size of the optional header, a flag for characteristic information and then the optional header (includes information like the PEP (Program Entry Point) and OS version along with some other information).
In the PE File Header there is a Virtual Address (VA for short) and a Relative Virtual Address (RVA for short). The RVA is an address of an item after it has been loaded into memory however for it to be the RVA you must subtract the base address of the image file from it. Whereas the VA is an address of an item after it has been loaded into memory without subtracting the base address. Each process will have its own VA.
Within the Portable Executable there will be many sections however we will only talk about a few of them for now: .text, .bss, .rdata, .data and the .idata section. I may make an entire reference thread which will have much more detail regarding the Portable Executable format (the internals of it) however for now this is not necessary.
The purpose of the .text section is to hold the actual instructions for the executable. In other words, it is the code (heart) of the program.
The purpose of the .bss section is to hold static/dynamic variables (which are uninitialized). If you are not aware of what an uninitialized variable actually is, it is essentially a variable which has been declared in the code but was not given a definite value before it was used.
The purpose of the .data section is to hold data which was defined within the compiled code (in the program). For example, if you created a variable and set its value as you created it, then this is defining data and it would be stored within this section.
The purpose of the .rdata section is to hold read-only data which was defined within the compiled code (in the program). An example of this would be a constant variable which should not have its value changed (therefore since it is read-only it is placed in this section). Basically it is the .data section but read-only.
The purpose of the .idata section is for containment of information regarding the imports for the program. This is also where the IAT (Import Address Table) resides (which I explain below since I feel it deserves its own paragraph explanation due to it being very important and being a key part to this tutorial).
An imported function is where a program makes use of a function which is from another DLL. In Windows there are many import libraries which Microsoft provides and there are many functions within these available libraries which are officially documented (at MSDN for example). It is important that functions from libraries provided by Microsoft are documented because if you are performing analysis and find that a function from a Windows library is being used you need to understand what it does to a reasonable extent to understand what the malware is actually doing. However, not all functions within these libraries are documented for specific reasons of their own (which I will explain a bit about below) and in fact, not all libraries are documented for the purpose of Microsoft not wanting them being used at all.
When you run a Portable Executable, the Windows Loader will make sure that the correct DLLs (Dynamic Link Libraries) are imported if a function from them are being used. If a program makes use of a function from a Windows Library then the DLL which holds this function being called will be imported into the address space of the process (when you run a Portable Executable, the Windows Loader will have this PE loaded into memory and therefore it receives its own process which is built up of “threads”).
The Import Address Table (IAT) is key to this thread and very important in Portable Executables. The purpose of the IAT is to hold addresses (pointer addresses) which will reside to the function imported (located within the imported library) in the PE. It is a table which holds functions in a list and each entry to the table has its own pointer address which can be accessed (e.g. via a JMP instruction). When a function is imported the Windows Loader will make sure that the function has a place in the IAT and corresponds to a pointer address which will trail to the function within the imported library (DLL). When this imported function is called it is looked up in the IAT and then it performs an instruction to go to that address for the function call (e.g. CALL/JMP instruction). The IAT was made to prevent having to statically link all the functions (adding the function code within the PE itself) but instead it is dynamically-linked since the PE will import the required modules containing the functions and then work with a function pointer to call/jmp (jump) to the called function.
Part 2
For this second part of the thread we will actually start the tutorial for checking the imports of a sample. However, we will be using a test sample for this part of the tutorial. This means that there will be no malicious usage of functions within the sample, all the executing code will be clean. Although this is a static analysis tutorial therefore there is no need to actually run the sample. You can find the download to the test sample at the beginning of the thread. You will also require IDA (the free version should be fine) for this part of the tutorial.
To get started you will need to open up IDA (I will be using the Pro version). You need to open up the correct version (there is a version for x86 binaries and another for x64 – both sample downloads will be for x86 for people who only have the Free version since the Free version doesn’t support x64 binaries).
Once you open up IDA you will be presented with the Quick Start dialog (depending on the configuration settings). This dialog will have some options for you to get started with working in IDA: ‘New’, ‘Go’ and ‘Previous’. The first option is ‘New’ which will take you into the IDA environment and then present you with an open file dialog (to select the file you will be working with). The second option which is ‘Go’ will take you to the work space environment for IDA but will not give you an open file dialog (you will have to manually open the file into the environment). The third option which is ‘Previous’ will open the most recently open file (with any saved data if any from your recent work on it with IDA). At the bottom after the options there will be a list of previously opened files and double clicking on this will open them up in IDA again.
Since we will be working with the clean test sample for this part of the tutorial we will be using the ‘New’ option. Select this option and when prompted use the dialog to open the clean test sample.
After opening the test file (Portable Executable) you should have another dialog show up. By default, it should have the first option selected as “Portable Executable for… (PE) […]” and all the other settings should be left the same. If you want to make sure that the settings on the dialog are the same as mine, you can check the below screenshot of the dialog within the spoiler (excluding settings for things which require an additional dialog since as long as you leave those settings un-touched you won’t need to compare at all for whatever reason). Just hit OK.
After sending confirmation that you are happy with the settings by hitting OK you will be presented with some more dialog's which hopefully should speed through and auto-close. Eventually you will get a dialog which requires user-interaction which will be about a *.pdb file. This file is actually used for things relating to debugging however just ignore this and choose No. You can even tick the box to not show it again (as it won’t be required for now at least). You’ll get a bunch more dialog's after this which should speed through, the last one will be user-interaction based but all you’ll have to do is click OK.
Now you should be presented with the main work space of IDA with the Portable Executable successfully loaded. Everything might look quite complex at first glance but after you learn to use the environment then it won’t be as bad as it looks, trust me!
By default, IDA will attempt to locate the start function of the program (most likely by signature detection) and leave it there at the ‘IDA View-A’ tab (you may have already noticed that there are main tabs for the work space next to the functions window which is placed next to it on the left by default). The functions window aside to the main tabs is very important however that is for another tutorial – for now just ignore all the windows and tabs there, except the tab with the title ‘Imports’ (check the screenshot in the below screenshot if you are not sure of where it is located).
If you haven’t caught on yet, we are interested in this tab for this tutorial and this part of the tutorial will strictly evolve around it. We do not require to use the other tabs for things such as checking the exports, looking at the actual instructions at certain functions within the program and converting this to a more appropriate and readable code (since reading ASM may not always be convenient depending on the circumstances), and so on. Simply navigate to this Imports tab and then follow on!
Once you have selected the tab it should look something like this (if you have the same test sample loaded, otherwise the Imports will be different):
Once you are viewing this tab you should see 4 columns (Address, Ordinal, Name and Library).
The value in the address is the location in memory as to where the function was defined since we reference it within the program (if you double click the item it will take you to that address – feel free to do so and don’t be shy, just go back to the Imports tab after and you’re back to where you started… Or press Esc and it’ll take you back to where you started on the IDA View-A tab before it moved to the address from the Imports tab).
The value in the Name column (string) will be the function name which is from the library. As an example, if the program uses a function called “GiveWaveOneMillionPounds” from a library called “Wave32.dll” then the Name column will have an entry with the value “GiveWaveOneMillionPounds” and the Library column will have the value (string also) of “Wave32.dll” corresponding to that entry in the list.
My test sample was created with a Win32 template (Console Application) with Visual Studio, which is making use of functions from a library called MSVCP140 therefore we can ignore this for now (and the VCRUNTIME140/api-ms-win-crt-runtime-l1-1-0 library). However, we should take interest in the imports from KERNEL32.DLL and USER32.DLL.
Straight off the bat from the top of the list entries we can see some imported functions from KERNEL32: CreateFileW, SetUnhandledExceptionFilter, GetCurrentProcess, TerminateProcess, IsProcessorFeaturePresent, QueryPerformanceCounter, GetCurrentProcessId, GetCurrentThreadId, GetSystemTimeAsFileTime, InitializeSListHead, IsDebuggerPresent, GetModuleHandleW and UnhandledExceptionFilter.
Firstly, not all these functions were imported by me. Some of these functions were imported automatically for functions which are generated for functions like the ExitProcess function (which makes use of functions like TerminateProcess to end the process) which are called when you exit the program.
Secondly, without further analysis we cannot pick out functions like TerminateProcess and say that it will attempt to terminate an external process (since this function is being used by default for the actual program to terminate itself when the program is closed). The same goes for the function IsDebuggerPresent – we cannot just assume that the sample is checking if it is being debugged or not to avoid the correct instruction execution/to close if it detects a debugger because this had nothing to do with my code but it was relating to the auto-generated code which was built with the compiler for the pre-after code execution of my own code. Therefore, should you encounter these functions in future analysis, you can perform other static analysis techniques (and dynamic analysis) to further investigate the purpose being the import of these functions to make sure you don’t accidentally jump to conclusions with false facts.
The functions we need to be looking at is kernel32.dll!CreateFileW, User32!MessageBoxA and User32!MessageBoxW. These functions won’t be added in automatically by the compiler therefore it must have been added by the programmer (in the case of this clean test sample… Me (Wave))!
I suspect that you won’t know (unless you have a programming background with the Win32 API) about what these functions I pin-pointed out are/do.
The first one, CreateFileW, is a Win32 API function (as we know – we also know it is from kernel32 library) which has the ability to create files given the correct information. This tells us that the program will create a file at some point during execution flow.
The second and third one are actually more-or-less the same. MessageBoxA and MessageBoxW are the same however one is for Ascii (the one with the ‘A’ at the end) and the other is for Unicode. I won’t go into my own zone talking about the differences between Ascii and Unicode in this thread as it’s not really necessary however it is relating to data types for the passed in information to the function parameters. In fact, it is quite often to find a Win32 API with a version for both the Ascii and Unicode version. Since there are both functions imported, this tells us that at some point during program execution flow, it will call both of them (maybe not one after the other, we would need to perform further analysis to discover when the calls are made, etc).
If you are not familiar with the Win32 API but would like to know how a function from the Win32 API works which is used within a sample you are checking the imports on, you can try looking up the function at MSDN (Microsoft Developer Network).
https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx
https://msdn.microsoft.com/en-us/library/windows/desktop/ms645505(v=vs.85).aspx
I should note that there are many libraries within the Win32 API; not just KERNEL32.DLL and USER32.DLL.
Hopefully you as a reader are still with me and have understood so far… If you are just spectating to learn, I highly recommend trying this out yourself. If you try to follow this tutorial practically then you may catch a much better understanding. I believe this is the end of Part 2, therefore feel free to move onto Part 3 if you are still interested and I haven’t scared you off!
Part 3
Since Part 2 was the actual tutorial of checking the imports of a PE we will not be going over everything again. You can scroll up to read above information from the main tutorial in Part 2 to help you with this part if you get stuck.
All I will be doing in this part is talking about some of the imported functions within the malicious sample. Of course you can do further analysis to practise your analysis skills (if you have previous experience) then feel free to do so. Just make sure you are in your secure analysis environment.
The malicious sample we will be using for the purpose of this Part 3 is typically being detected as “spyware” (Zeus Bot) by most (if not all) vendors which detect the sample according to some online scan results. You can view the VirusTotal report at the following link: https://virustotal.com/en/file/05af...817fa3914838059008b6b095cb0e632b9c4/analysis/
MD5 hash of the sample: b38cddd0fa7713d0033f5db5186a9d98
SHA256 hash of the sample: 05afbcd2f3801ac0b4954ad9b38e0817fa3914838059008b6b095cb0e632b9c4
NOTE: I have not done any further analysis other than what is taught in this tutorial. I have done this so my knowledge on the sample is more-or-less the same as the readers (through checking imports and based on the detections from existing vendors). For all we know, the detections from the vendors are maybe incorrect (and then a bunch of vendors may have copied the incorrect detection name), but I will assume that the existing detections are indeed correct for now and base my opinions around the existing evidence which other analysts have already found.
I still start by opening up the malicious sample in IDA (with the default settings) and navigate to the Imports tab. You can see a screenshot of my Imports tab below:
Straight off the bat you can see that there are many imports within this malicious sample and therefore they do not all fit inside of one screenshot. I have used the Copy All (Ctrl + Shift + Ins) to copy all of the information in the Imports tab have posted it below for you.
I will not be going through every single individual import since this would take much more time than what is necessary however what I will be doing is picking out some of the imported functions from the list which are more interesting and have more relevance to malware/the detections from AV vendors.
The first entry of the imports table is Advapi.dll!InitiateSystemShutdownExW (W = Unicode). This function will allow the sample to shut down the system. For more information: InitiateSystemShutdownEx function (Windows)
We can see that there are many registry functions imported: RegCreateKeyExW, RegCloseKey, RegEnumValueW, RegDeleteValueW, RegQueryInfoKeyW, RegCreateKeyW, RegSetValueExW and others. This tells us that the sample most likely interacts with the registry for whatever purpose at some point during execution flow.
The functions RegCreateKeyExW/RegCreateKeyW (from Advapi32.dll library) will allow the sample to create a new key in the registry. Based on first view I would suspect that the sample would be using this to allow itself to auto-start at boot, although without further analysis I can only assume. Based on some of the functions I listed above with relevance to registry operations, we know that the sample is capable of: deleting registry keys, querying info from registry keys, modifying the value of existing registry keys, and closing the handle to a registry key it had opened. You can find more information about Windows API registry functions at the following page: Registry Functions (Windows)
The function GetWindowsDirectoryW (from Kernel32.dll) will return the path of the Windows folder. For more information check the following page: GetWindowsDirectory function (Windows)
The functions Process32FirstW and CreateToolhelp32Snapshot (both present in Kernel32.dll) which caught my eye whilst looking at the imported functions tells me that the malicious sample will most likely enumerate through all the processes to find a specific process (preferably passing a process name (string) and then receiving the PID if a process with that name was found). I actually assume this due to experience of using these functions and using them for a function which will do exactly this, although I can still be wrong. This is just an assumption based on the imports.
I think that it is worth mentioning that the sample has the ability to inject into external processes should it have a need too for whatever purpose. It can accomplish through using the common DLL injection method by using the CreateRemoteThread function it imports (which will force the target process to call LoadLibraryA/LoadLibraryW on the target DLL to be injected, thus it becomes loaded in the address space of the target process and therefore the malicious code within the DLL becomes executed from within that targeted process). The usage to do this also evolves around using functions such as WriteProcessMemory to modify the memory of an external process prior to calling the CreateRemoteThread function to set things up, therefore for me this is enough evidence that the sample will attempt to inject into an external process at some point during execution flow. Maybe my opinion on this is a bit far-fetched, though.
Interestingly, the sample actually imports functions from the CryptoAPI (Crypt32.dll). Another thing I found interesting about the sample is how it imported ntdll!NtQueryKey (ntdll.dll will be covered in a theory thread therefore be sure to watch out for when that thread arrives sometime in distant future).
Pointing out different functions imported by the sample and giving a very brief explanation of what the function is for/what the sample may be doing with it can go on forever with the amount of imports this sample has, however to put it short, the sample has the ability to do many things such as (but not limited to): shutting down the local system (or systems on a network); modifying the security descriptor (DACL) – this can actually be done to protect a process from termination against non-admin processes; registry modification, file modification, modifying process tokens, modifying the priority of threads within a process, performing injection attacks into external processes, enumerating through running processes/threads, duplicate handles, process creation/termination, perform network activity (e.g. send/open HTTP requests – network activity could be used to send the required info about the user/system back to the attacker and receive back instructions to be performed. However, network activity could also be used maliciously to perform network attacks to targeted services such as DDoS attacks), obtain net user information, obtain clipboard data, work with the CryptoAPI, call NTAPI functions (instead of just using the Windows API equivalent and having it point to that direction anyway), and more.
I believe that sufficient information was presented in this part 3 therefore we shall move onto part 4 (for anyone who needs it). The purpose of this part 3 was not to be another tutorial embedded into this tutorial, but to do a quick analysis of a malicious sample based on the import checking we did in the main part of this thread (part 1).
Part 4
The purpose of this part 4 is to quickly overview checking the imports of a Portable Executable via two other pieces of software (which can be freely obtained – or at least there is a free version which will be good enough).
FileAlyzer:
Before we can get started you will need to have downloaded and installed FileAlyzer. You can download FileAlyzer from the official website here.
After you have downloaded and installed FileAlyzer you need to open it up (you do not need to necessarily run it with admin rights, it can run with standard rights right now).
When you open it up at first, you should be granted with an open file dialog. You can actually exit this dialog and it won’t close the program – you’ll be taken to the normal overview work space area however if you haven’t opened anything to analyse then it will all be empty.
Open up the Portable Executable you wish to analyse. For the purpose of this section (part 4) I will be using the malicious sample we used in part 3. After opening it up, the work space should change to something like this:
In my opinion it looks very simple to read. The General tab will provide you details on the path of the sample, the file size, version (if available), hash checksums (CRC-32, MD5, SHA1), file attribute information (e.g. Read only, Hidden, System file, etc), and creation/access/write information. For now, you can ignore all of this and all of the tabs except the “PE Imports” tab. Simply navigate to this tab.
Once you have navigated to the PE Imports tab it should look something like this:
FileAlyzer will actually group each import to the library it’s from. As an example, all Advapi32.dll imports were grouped into their own section, whereas the imports from Kernel32.dll were placed within their own group. The + and – symbols with the green/red boxes are for if the imported function is available on a specific OS (I believe). If you right click you can search for more information for a specific function – this will search for information on the function using your default web browser on Google but filter for MSDN results only.
NOTE: The PE Imports tab may be very “laggy” for you. It normally is for me at least whilst dealing with a PE containing many imports.
Now you’re done! That is all you have to do to view the imports of a PE with FileAlyzer.
PE Explorer:
Before we can get started you will need to have downloaded and installed PE Explorer (free edition will be just fine). You can download PE Explorer from the official website here.
After you have downloaded and installed PE Explorer you need to open it up (you do not need to necessarily run it with admin rights, it can run with standard rights right now).
When you first open it up you should be presented with a quick splash screen however this will close and load the main GUI speedily. You should see something like below:
It looks quite simple, right? The next thing you’ll need to do is actually open up the target file (I will be using the malicious sample from earlier – you can drag it onto the GUI or use the quick-open toolbar icon… Or go to File > Open File (Ctrl + O)).
After opening up the PE it should take you to the “Headers info” tab by default. All you need to do is click the “Import” tab button on the toolbar to be taken to the Imports tab. Check the screenshots in the below spoiler:
Now the useful feature of the Imports tab with this software which I like is that it allows you to go through the different libraries which functions are imported from and then it displays the functions from that library which were imported in a separate list as opposed to mixing it all up, and it does this quite quickly. Nor do I experience any sort of “lag” whilst navigating the Imports tab GUI, unlike with other software.
Another good feature is that it provides a feature known as “Syntax Details” with a box containing text elements which gives some information on the function (e.g. parameters).
NOTE: The free version is actually a 30-day evaluation of the paid version. Although there is nothing wrong with experimenting with it for analysis of malware during this evaluation!
Now you’re done! That is all you have to do to view the imports of a PE with PE Explorer.
---------------
Part four was just a bonus addition to not only improve the quality of this thread but to potentially help anyone who does actually find themselves stuck attempting to check the imports with another tool – when you are starting out it can be very easy to become confused and stuck and this can be very stressful. Therefore, even though it should be fairly obvious on using another tool for checking the imports (to some people), it may not be as simple for others and this was the reason I added in part four.
IDA is a very sophisticated piece of software for reverse engineering and has a very large feature set. Due to this, I intentionally did not cover a lot of things and strictly tried to stay on topic and base it down to what was needed to be mentioned. Other things will be covered with IDA in future tutorials (both static and dynamic tutorials).
---------------
Thank you for reading and hopefully this tutorial helped you.
Wave.
Hello and welcome to my thread on Malware Analysis.
[DISCLAIMER]
I have intentionally set the font size to 3 because this thread is very long and with the normal font size it may actually be even more of a pain to go through... I highly recommend you zoom in once in your browser, and it will appear much nicer to read the text (as opposed to reading it without zooming in once or as it is by default).
If you find any false information/mistakes in this thread then please let me know so I can fix them.
[/DISCLAIMER]
In this tutorial we will be performing static analysis: checking the dynamically linked imports of a PE (Portable Executable). For this tutorial I will be using IDA (from Hex Rays) however since not everyone may want to jump into using IDA due to its complexity to start off, I will also be making an additional part to this tutorial which will demonstrate how to check the imports using different tools. This tutorial will have four parts – the first part will be theory based, the second part will be about explaining how we actually check for the imported functions (whilst using a clean test sample) whereas the third part will be doing it again but with a malicious sample. The fourth (additional) part will be explaining how to use other tools to check for the imports for future reference, should anyone run into trouble with using other tools for it.
All images will be placed within a SPOILER (spoiler tags).
Below the information regarding the requirements to carry out this tutorial you will find a part under the title “Theory”.
What you will need to follow this tutorial (prerequisites):
- An environment for performing malware analysis (a secure, working and set-up Virtual Machine will do just fine).
- IDA (for the Part 2 & 3 of this tutorial - the free version should be fine if you do not have the pro version).
- FileAlyzer/PE Explorer (for the Part 4 of this tutorial).
- Samples to practise on (check below for the download links).
You can download the clean test sample which I made myself for the purpose of this tutorial from the following link: Private file (remember that this is a clean test sample although running it is really pointless - it's all setup to have some imported functions for the main tutorial part - there is no password to the archive since it is 100% clean).
You can download the malicious sample we will be using for the second part of the tutorial from the following link: hxxp://www78.zippyshare.com/v/dBUabsTF/file.html/ (the sample is not packed) (warning: this download is malicious and you should only download it from within your secure analysis environment – replaced http with hxxp for security purposes & the archive password is infected).
The link in the custom fields for this thread will lead to the malicious sample (and the VT analysis will be for the malicious sample of course).
Theory
PE stands for Portable Executable and you can identify a Portable Executable based on the first few bytes in the binary (and through checking for information regarding DOS in the bytes of the binary). As well as this, you can identify a PE based on its extension (*.exe), however even if the extension is not for a PE this does not mean it is not really a PE. For example, you can have the extension of a Portable Executable different to that of *.exe, even though you won’t be able to open it up normally (but if it is really a PE you can find out through the bytes in the binary – first bytes should be “MZ” and following all this near the top should be information about DOS). If the extension is not *.exe but the binary is indeed a real PE file, it can actually be loaded and executed (regardless of the extension change – but not done through clicking the file to open it for example).
The hexadecimal representation for the start of the PE format (“MZ”) would be 4D 5A. Underneath this should be bytes for things relating to DOS (e.g. “This program cannot be run in DOS mode” which in hex would be 54 68 69 73 20 70 72 6F 67 72 61 6D 20 63 61 6E 6E 6F 74 20 62 65 20 72 75 6E 20 69 6E 20 44 4F 53 20 6D 6F 64 65). There is also the PE File Signature which is explained further down.
Every Portable Executable has parts/sections and there are many of these with different purposes.
The first parts to a PE is the MZ Header (as discussed above) and a stub for MS-DOS (which is 38 bytes in size). You may be asking yourself why there is a stub with a size of 38 bytes for MS-DOS and the reason behind this is because there needs to be some sort of backwards compatibility so if someone attempts to run a program on MS-DOS it will let them know that it is not supported (which is why there is the error message text “This program cannot be run in DOS mode” found – this is from the MS-DOS stub and the MZ header is also for MS-DOS).
The next part to a PE file is the PE File Header which is very important. The PE File Header contains information such as the PE File Signature (which is for the Windows Loader – the signature is PE00 (50 45 00 00)), information regarding machines the Portable Executable can be run on (e.g. Intel processors), information regarding the size of the sections table, information regarding the size of the optional header, a flag for characteristic information and then the optional header (includes information like the PEP (Program Entry Point) and OS version along with some other information).
In the PE File Header there is a Virtual Address (VA for short) and a Relative Virtual Address (RVA for short). The RVA is an address of an item after it has been loaded into memory however for it to be the RVA you must subtract the base address of the image file from it. Whereas the VA is an address of an item after it has been loaded into memory without subtracting the base address. Each process will have its own VA.
Within the Portable Executable there will be many sections however we will only talk about a few of them for now: .text, .bss, .rdata, .data and the .idata section. I may make an entire reference thread which will have much more detail regarding the Portable Executable format (the internals of it) however for now this is not necessary.
The purpose of the .text section is to hold the actual instructions for the executable. In other words, it is the code (heart) of the program.
The purpose of the .bss section is to hold static/dynamic variables (which are uninitialized). If you are not aware of what an uninitialized variable actually is, it is essentially a variable which has been declared in the code but was not given a definite value before it was used.
The purpose of the .data section is to hold data which was defined within the compiled code (in the program). For example, if you created a variable and set its value as you created it, then this is defining data and it would be stored within this section.
The purpose of the .rdata section is to hold read-only data which was defined within the compiled code (in the program). An example of this would be a constant variable which should not have its value changed (therefore since it is read-only it is placed in this section). Basically it is the .data section but read-only.
The purpose of the .idata section is for containment of information regarding the imports for the program. This is also where the IAT (Import Address Table) resides (which I explain below since I feel it deserves its own paragraph explanation due to it being very important and being a key part to this tutorial).
An imported function is where a program makes use of a function which is from another DLL. In Windows there are many import libraries which Microsoft provides and there are many functions within these available libraries which are officially documented (at MSDN for example). It is important that functions from libraries provided by Microsoft are documented because if you are performing analysis and find that a function from a Windows library is being used you need to understand what it does to a reasonable extent to understand what the malware is actually doing. However, not all functions within these libraries are documented for specific reasons of their own (which I will explain a bit about below) and in fact, not all libraries are documented for the purpose of Microsoft not wanting them being used at all.
When you run a Portable Executable, the Windows Loader will make sure that the correct DLLs (Dynamic Link Libraries) are imported if a function from them are being used. If a program makes use of a function from a Windows Library then the DLL which holds this function being called will be imported into the address space of the process (when you run a Portable Executable, the Windows Loader will have this PE loaded into memory and therefore it receives its own process which is built up of “threads”).
The Import Address Table (IAT) is key to this thread and very important in Portable Executables. The purpose of the IAT is to hold addresses (pointer addresses) which will reside to the function imported (located within the imported library) in the PE. It is a table which holds functions in a list and each entry to the table has its own pointer address which can be accessed (e.g. via a JMP instruction). When a function is imported the Windows Loader will make sure that the function has a place in the IAT and corresponds to a pointer address which will trail to the function within the imported library (DLL). When this imported function is called it is looked up in the IAT and then it performs an instruction to go to that address for the function call (e.g. CALL/JMP instruction). The IAT was made to prevent having to statically link all the functions (adding the function code within the PE itself) but instead it is dynamically-linked since the PE will import the required modules containing the functions and then work with a function pointer to call/jmp (jump) to the called function.
Part 2
For this second part of the thread we will actually start the tutorial for checking the imports of a sample. However, we will be using a test sample for this part of the tutorial. This means that there will be no malicious usage of functions within the sample, all the executing code will be clean. Although this is a static analysis tutorial therefore there is no need to actually run the sample. You can find the download to the test sample at the beginning of the thread. You will also require IDA (the free version should be fine) for this part of the tutorial.
To get started you will need to open up IDA (I will be using the Pro version). You need to open up the correct version (there is a version for x86 binaries and another for x64 – both sample downloads will be for x86 for people who only have the Free version since the Free version doesn’t support x64 binaries).
Once you open up IDA you will be presented with the Quick Start dialog (depending on the configuration settings). This dialog will have some options for you to get started with working in IDA: ‘New’, ‘Go’ and ‘Previous’. The first option is ‘New’ which will take you into the IDA environment and then present you with an open file dialog (to select the file you will be working with). The second option which is ‘Go’ will take you to the work space environment for IDA but will not give you an open file dialog (you will have to manually open the file into the environment). The third option which is ‘Previous’ will open the most recently open file (with any saved data if any from your recent work on it with IDA). At the bottom after the options there will be a list of previously opened files and double clicking on this will open them up in IDA again.
Since we will be working with the clean test sample for this part of the tutorial we will be using the ‘New’ option. Select this option and when prompted use the dialog to open the clean test sample.
After opening the test file (Portable Executable) you should have another dialog show up. By default, it should have the first option selected as “Portable Executable for… (PE) […]” and all the other settings should be left the same. If you want to make sure that the settings on the dialog are the same as mine, you can check the below screenshot of the dialog within the spoiler (excluding settings for things which require an additional dialog since as long as you leave those settings un-touched you won’t need to compare at all for whatever reason). Just hit OK.
After sending confirmation that you are happy with the settings by hitting OK you will be presented with some more dialog's which hopefully should speed through and auto-close. Eventually you will get a dialog which requires user-interaction which will be about a *.pdb file. This file is actually used for things relating to debugging however just ignore this and choose No. You can even tick the box to not show it again (as it won’t be required for now at least). You’ll get a bunch more dialog's after this which should speed through, the last one will be user-interaction based but all you’ll have to do is click OK.
Now you should be presented with the main work space of IDA with the Portable Executable successfully loaded. Everything might look quite complex at first glance but after you learn to use the environment then it won’t be as bad as it looks, trust me!
By default, IDA will attempt to locate the start function of the program (most likely by signature detection) and leave it there at the ‘IDA View-A’ tab (you may have already noticed that there are main tabs for the work space next to the functions window which is placed next to it on the left by default). The functions window aside to the main tabs is very important however that is for another tutorial – for now just ignore all the windows and tabs there, except the tab with the title ‘Imports’ (check the screenshot in the below screenshot if you are not sure of where it is located).
If you haven’t caught on yet, we are interested in this tab for this tutorial and this part of the tutorial will strictly evolve around it. We do not require to use the other tabs for things such as checking the exports, looking at the actual instructions at certain functions within the program and converting this to a more appropriate and readable code (since reading ASM may not always be convenient depending on the circumstances), and so on. Simply navigate to this Imports tab and then follow on!
Once you have selected the tab it should look something like this (if you have the same test sample loaded, otherwise the Imports will be different):
Once you are viewing this tab you should see 4 columns (Address, Ordinal, Name and Library).
The value in the address is the location in memory as to where the function was defined since we reference it within the program (if you double click the item it will take you to that address – feel free to do so and don’t be shy, just go back to the Imports tab after and you’re back to where you started… Or press Esc and it’ll take you back to where you started on the IDA View-A tab before it moved to the address from the Imports tab).
The value in the Name column (string) will be the function name which is from the library. As an example, if the program uses a function called “GiveWaveOneMillionPounds” from a library called “Wave32.dll” then the Name column will have an entry with the value “GiveWaveOneMillionPounds” and the Library column will have the value (string also) of “Wave32.dll” corresponding to that entry in the list.
My test sample was created with a Win32 template (Console Application) with Visual Studio, which is making use of functions from a library called MSVCP140 therefore we can ignore this for now (and the VCRUNTIME140/api-ms-win-crt-runtime-l1-1-0 library). However, we should take interest in the imports from KERNEL32.DLL and USER32.DLL.
Straight off the bat from the top of the list entries we can see some imported functions from KERNEL32: CreateFileW, SetUnhandledExceptionFilter, GetCurrentProcess, TerminateProcess, IsProcessorFeaturePresent, QueryPerformanceCounter, GetCurrentProcessId, GetCurrentThreadId, GetSystemTimeAsFileTime, InitializeSListHead, IsDebuggerPresent, GetModuleHandleW and UnhandledExceptionFilter.
Firstly, not all these functions were imported by me. Some of these functions were imported automatically for functions which are generated for functions like the ExitProcess function (which makes use of functions like TerminateProcess to end the process) which are called when you exit the program.
Secondly, without further analysis we cannot pick out functions like TerminateProcess and say that it will attempt to terminate an external process (since this function is being used by default for the actual program to terminate itself when the program is closed). The same goes for the function IsDebuggerPresent – we cannot just assume that the sample is checking if it is being debugged or not to avoid the correct instruction execution/to close if it detects a debugger because this had nothing to do with my code but it was relating to the auto-generated code which was built with the compiler for the pre-after code execution of my own code. Therefore, should you encounter these functions in future analysis, you can perform other static analysis techniques (and dynamic analysis) to further investigate the purpose being the import of these functions to make sure you don’t accidentally jump to conclusions with false facts.
The functions we need to be looking at is kernel32.dll!CreateFileW, User32!MessageBoxA and User32!MessageBoxW. These functions won’t be added in automatically by the compiler therefore it must have been added by the programmer (in the case of this clean test sample… Me (Wave))!
The reason I wrote “kernel32.dll!CreateFileW” instead of “CreateFileW from kernel32.dll” is because they both mean the same things and it is much shorter to use the first format which I used. It is also more commonly used by programmers.
I suspect that you won’t know (unless you have a programming background with the Win32 API) about what these functions I pin-pointed out are/do.
The first one, CreateFileW, is a Win32 API function (as we know – we also know it is from kernel32 library) which has the ability to create files given the correct information. This tells us that the program will create a file at some point during execution flow.
The second and third one are actually more-or-less the same. MessageBoxA and MessageBoxW are the same however one is for Ascii (the one with the ‘A’ at the end) and the other is for Unicode. I won’t go into my own zone talking about the differences between Ascii and Unicode in this thread as it’s not really necessary however it is relating to data types for the passed in information to the function parameters. In fact, it is quite often to find a Win32 API with a version for both the Ascii and Unicode version. Since there are both functions imported, this tells us that at some point during program execution flow, it will call both of them (maybe not one after the other, we would need to perform further analysis to discover when the calls are made, etc).
If you are not familiar with the Win32 API but would like to know how a function from the Win32 API works which is used within a sample you are checking the imports on, you can try looking up the function at MSDN (Microsoft Developer Network).
https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx
https://msdn.microsoft.com/en-us/library/windows/desktop/ms645505(v=vs.85).aspx
I should note that there are many libraries within the Win32 API; not just KERNEL32.DLL and USER32.DLL.
Hopefully you as a reader are still with me and have understood so far… If you are just spectating to learn, I highly recommend trying this out yourself. If you try to follow this tutorial practically then you may catch a much better understanding. I believe this is the end of Part 2, therefore feel free to move onto Part 3 if you are still interested and I haven’t scared you off!
Part 3
Since Part 2 was the actual tutorial of checking the imports of a PE we will not be going over everything again. You can scroll up to read above information from the main tutorial in Part 2 to help you with this part if you get stuck.
All I will be doing in this part is talking about some of the imported functions within the malicious sample. Of course you can do further analysis to practise your analysis skills (if you have previous experience) then feel free to do so. Just make sure you are in your secure analysis environment.
The malicious sample we will be using for the purpose of this Part 3 is typically being detected as “spyware” (Zeus Bot) by most (if not all) vendors which detect the sample according to some online scan results. You can view the VirusTotal report at the following link: https://virustotal.com/en/file/05af...817fa3914838059008b6b095cb0e632b9c4/analysis/
MD5 hash of the sample: b38cddd0fa7713d0033f5db5186a9d98
SHA256 hash of the sample: 05afbcd2f3801ac0b4954ad9b38e0817fa3914838059008b6b095cb0e632b9c4
NOTE: I have not done any further analysis other than what is taught in this tutorial. I have done this so my knowledge on the sample is more-or-less the same as the readers (through checking imports and based on the detections from existing vendors). For all we know, the detections from the vendors are maybe incorrect (and then a bunch of vendors may have copied the incorrect detection name), but I will assume that the existing detections are indeed correct for now and base my opinions around the existing evidence which other analysts have already found.
I still start by opening up the malicious sample in IDA (with the default settings) and navigate to the Imports tab. You can see a screenshot of my Imports tab below:
Straight off the bat you can see that there are many imports within this malicious sample and therefore they do not all fit inside of one screenshot. I have used the Copy All (Ctrl + Shift + Ins) to copy all of the information in the Imports tab have posted it below for you.
Code:
Address Ordinal Name Library
------- ------- ---- -------
00401000 InitiateSystemShutdownExW ADVAPI32
00401004 CryptCreateHash ADVAPI32
00401008 AllocateAndInitializeSid ADVAPI32
0040100C LookupPrivilegeValueW ADVAPI32
00401010 SetNamedSecurityInfoW ADVAPI32
00401014 SetSecurityDescriptorDacl ADVAPI32
00401018 InitializeSecurityDescriptor ADVAPI32
0040101C CryptReleaseContext ADVAPI32
00401020 RegCreateKeyExW ADVAPI32
00401024 GetTokenInformation ADVAPI32
00401028 GetSidSubAuthorityCount ADVAPI32
0040102C OpenThreadToken ADVAPI32
00401030 CryptAcquireContextW ADVAPI32
00401034 GetSidSubAuthority ADVAPI32
00401038 OpenProcessToken ADVAPI32
0040103C CryptGetHashParam ADVAPI32
00401040 IsWellKnownSid ADVAPI32
00401044 RegCloseKey ADVAPI32
00401048 RegEnumValueW ADVAPI32
0040104C RegDeleteValueW ADVAPI32
00401050 RegQueryInfoKeyW ADVAPI32
00401054 RegCreateKeyW ADVAPI32
00401058 EqualSid ADVAPI32
0040105C RegQueryValueExW ADVAPI32
00401060 RegQueryValueExA ADVAPI32
00401064 ConvertSidToStringSidW ADVAPI32
00401068 GetLengthSid ADVAPI32
0040106C CreateProcessAsUserW ADVAPI32
00401070 CreateProcessAsUserA ADVAPI32
00401074 SetSecurityInfo ADVAPI32
00401078 FreeSid ADVAPI32
0040107C RegOpenKeyExW ADVAPI32
00401080 GetSecurityDescriptorSacl ADVAPI32
00401084 CheckTokenMembership ADVAPI32
00401088 SetSecurityDescriptorSacl ADVAPI32
0040108C CryptDestroyHash ADVAPI32
00401090 AdjustTokenPrivileges ADVAPI32
00401094 RegSetValueExW ADVAPI32
00401098 GetSecurityDescriptorDacl ADVAPI32
0040109C CryptHashData ADVAPI32
004010A0 RegEnumKeyExW ADVAPI32
004010A4 RegEnumKeyW ADVAPI32
004010A8 ConvertStringSecurityDescriptorToSecurityDescriptorW ADVAPI32
004010B0 PFXImportCertStore CRYPT32
004010B4 CertDeleteCertificateFromStore CRYPT32
004010B8 CryptUnprotectData CRYPT32
004010BC CertCloseStore CRYPT32
004010C0 CertEnumCertificatesInStore CRYPT32
004010C4 CertDuplicateCertificateContext CRYPT32
004010C8 PFXExportCertStoreEx CRYPT32
004010CC CertOpenSystemStoreW CRYPT32
004010D4 GetDeviceCaps GDI32
004010DC GetModuleHandleA KERNEL32
004010E0 FindFirstFileW KERNEL32
004010E4 GetCurrentThread KERNEL32
004010E8 FileTimeToSystemTime KERNEL32
004010EC SetThreadPriority KERNEL32
004010F0 FindClose KERNEL32
004010F4 FindNextFileW KERNEL32
004010F8 GetWindowsDirectoryW KERNEL32
004010FC GetCommandLineW KERNEL32
00401100 CreateDirectoryW KERNEL32
00401104 LoadLibraryW KERNEL32
00401108 lstrcmpiA KERNEL32
0040110C WTSGetActiveConsoleSessionId KERNEL32
00401110 MoveFileExW KERNEL32
00401114 SetFilePointer KERNEL32
00401118 SetEndOfFile KERNEL32
0040111C WriteFile KERNEL32
00401120 ExpandEnvironmentStringsW KERNEL32
00401124 GetPrivateProfileStringW KERNEL32
00401128 FlushFileBuffers KERNEL32
0040112C GetPrivateProfileIntW KERNEL32
00401130 GetUserDefaultUILanguage KERNEL32
00401134 CreateMutexW KERNEL32
00401138 SetErrorMode KERNEL32
0040113C GetComputerNameW KERNEL32
00401140 TerminateThread KERNEL32
00401144 WriteProcessMemory KERNEL32
00401148 CreateThread KERNEL32
0040114C SetHandleInformation KERNEL32
00401150 GetExitCodeProcess KERNEL32
00401154 ReadFile KERNEL32
00401158 GetExitCodeThread KERNEL32
0040115C CreatePipe KERNEL32
00401160 GetEnvironmentVariableW KERNEL32
00401164 FileTimeToDosDateTime KERNEL32
00401168 GetTempFileNameW KERNEL32
0040116C VirtualFree KERNEL32
00401170 GetTickCount KERNEL32
00401174 SystemTimeToFileTime KERNEL32
00401178 SetFilePointerEx KERNEL32
0040117C GetLogicalDriveStringsW KERNEL32
00401180 HeapFree KERNEL32
00401184 GetProcessHeap KERNEL32
00401188 SetFileTime KERNEL32
0040118C VirtualQueryEx KERNEL32
00401190 Thread32First KERNEL32
00401194 WideCharToMultiByte KERNEL32
00401198 ReadProcessMemory KERNEL32
0040119C HeapDestroy KERNEL32
004011A0 HeapCreate KERNEL32
004011A4 lstrcpynW KERNEL32
004011A8 Thread32Next KERNEL32
004011AC GetTimeZoneInformation KERNEL32
004011B0 MultiByteToWideChar KERNEL32
004011B4 lstrlenW KERNEL32
004011B8 GetTempPathW KERNEL32
004011BC GetFileSizeEx KERNEL32
004011C0 OpenMutexW KERNEL32
004011C4 VirtualProtectEx KERNEL32
004011C8 VirtualAllocEx KERNEL32
004011CC RemoveDirectoryW KERNEL32
004011D0 QueryDosDeviceW KERNEL32
004011D4 GetFileTime KERNEL32
004011D8 ReleaseMutex KERNEL32
004011DC FileTimeToLocalFileTime KERNEL32
004011E0 GetVolumeNameForVolumeMountPointW KERNEL32
004011E4 GetFileInformationByHandle KERNEL32
004011E8 GetSystemTime KERNEL32
004011EC InterlockedExchange KERNEL32
004011F0 GetLocalTime KERNEL32
004011F4 ResetEvent KERNEL32
004011F8 SetLastError KERNEL32
004011FC GetLastError KERNEL32
00401200 CreateEventA KERNEL32
00401204 SetFileAttributesW KERNEL32
00401208 GetLogicalDrives KERNEL32
0040120C GetDriveTypeW KERNEL32
00401210 lstrcmpiW KERNEL32
00401214 LoadLibraryA KERNEL32
00401218 FreeLibrary KERNEL32
0040121C GetFileAttributesW KERNEL32
00401220 GlobalUnlock KERNEL32
00401224 GlobalLock KERNEL32
00401228 GetCurrentProcessId KERNEL32
0040122C HeapReAlloc KERNEL32
00401230 OpenEventW KERNEL32
00401234 SetEvent KERNEL32
00401238 LocalFree KERNEL32
0040123C GetVersionExW KERNEL32
00401240 GetNativeSystemInfo KERNEL32
00401244 WaitForMultipleObjects KERNEL32
00401248 CreateEventW KERNEL32
0040124C Sleep KERNEL32
00401250 ResumeThread KERNEL32
00401254 DeleteFileW KERNEL32
00401258 DuplicateHandle KERNEL32
0040125C CreateToolhelp32Snapshot KERNEL32
00401260 VirtualProtect KERNEL32
00401264 Process32NextW KERNEL32
00401268 CreateFileMappingA KERNEL32
0040126C Process32FirstW KERNEL32
00401270 GetProcAddress KERNEL32
00401274 CreateFileW KERNEL32
00401278 TerminateProcess KERNEL32
0040127C CopyFileW KERNEL32
00401280 OpenProcess KERNEL32
00401284 CreateRemoteThread KERNEL32
00401288 IsBadReadPtr KERNEL32
0040128C GetModuleHandleW KERNEL32
00401290 GetCurrentProcess KERNEL32
00401294 CreateProcessW KERNEL32
00401298 WaitForSingleObject KERNEL32
0040129C UnmapViewOfFile KERNEL32
004012A0 MapViewOfFile KERNEL32
004012A4 GetFileSize KERNEL32
004012A8 CloseHandle KERNEL32
004012AC GetFileAttributesExW KERNEL32
004012B0 GetProcessId KERNEL32
004012B4 EnterCriticalSection KERNEL32
004012B8 VirtualAlloc KERNEL32
004012BC LeaveCriticalSection KERNEL32
004012C0 VirtualFreeEx KERNEL32
004012C4 InitializeCriticalSection KERNEL32
004012C8 SetThreadContext KERNEL32
004012CC GetThreadContext KERNEL32
004012D0 ExitProcess KERNEL32
004012D4 ExitThread KERNEL32
004012D8 GetModuleFileNameW KERNEL32
004012DC HeapAlloc KERNEL32
004012E4 NetApiBufferFree NETAPI32
004012E8 NetUserEnum NETAPI32
004012EC NetUserGetInfo NETAPI32
004012F4 2 SysAllocString OLEAUT32
004012F8 9 VariantClear OLEAUT32
004012FC 8 VariantInit OLEAUT32
00401300 6 SysFreeString OLEAUT32
00401308 CommandLineToArgvW SHELL32
0040130C ShellExecuteW SHELL32
00401310 SHGetFolderPathW SHELL32
00401314 ShellExecuteExW SHELL32
0040131C PathUnquoteSpacesW SHLWAPI
00401320 PathRemoveBackslashW SHLWAPI
00401324 PathQuoteSpacesW SHLWAPI
00401328 PathRenameExtensionW SHLWAPI
0040132C StrCmpNIA SHLWAPI
00401330 UrlUnescapeA SHLWAPI
00401334 wvnsprintfW SHLWAPI
00401338 PathIsDirectoryW SHLWAPI
0040133C PathAddBackslashW SHLWAPI
00401340 SHDeleteValueW SHLWAPI
00401344 PathSkipRootW SHLWAPI
00401348 SHDeleteKeyW SHLWAPI
0040134C PathCombineW SHLWAPI
00401350 PathAddExtensionW SHLWAPI
00401354 PathMatchSpecW SHLWAPI
00401358 wvnsprintfA SHLWAPI
0040135C StrStrIA SHLWAPI
00401360 StrStrIW SHLWAPI
00401364 StrCmpNIW SHLWAPI
00401368 PathRemoveFileSpecW SHLWAPI
0040136C PathFindFileNameW SHLWAPI
00401370 PathIsURLW SHLWAPI
00401378 GetUserNameExW Secur32
00401380 CharUpperW USER32
00401384 CharLowerA USER32
00401388 GetDC USER32
0040138C CharLowerW USER32
00401390 MsgWaitForMultipleObjects USER32
00401394 LoadImageW USER32
00401398 ToUnicode USER32
0040139C PeekMessageW USER32
004013A0 DispatchMessageW USER32
004013A4 GetForegroundWindow USER32
004013A8 CharLowerBuffA USER32
004013AC GetKeyboardState USER32
004013B0 TranslateMessage USER32
004013B4 GetMessageW USER32
004013B8 GetCursorPos USER32
004013BC GetIconInfo USER32
004013C0 DrawIcon USER32
004013C4 MessageBoxA USER32
004013C8 CharToOemW USER32
004013CC ExitWindowsEx USER32
004013D0 GetClipboardData USER32
004013D8 GetFileVersionInfoSizeW VERSION
004013DC VerQueryValueW VERSION
004013E0 GetFileVersionInfoW VERSION
004013E8 HttpQueryInfoA WININET
004013EC InternetSetStatusCallbackA WININET
004013F0 InternetOpenA WININET
004013F4 InternetSetOptionA WININET
004013F8 InternetCrackUrlW WININET
004013FC InternetCrackUrlA WININET
00401400 InternetQueryOptionW WININET
00401404 InternetConnectA WININET
00401408 InternetQueryOptionA WININET
0040140C InternetCloseHandle WININET
00401410 HttpEndRequestW WININET
00401414 HttpSendRequestA WININET
00401418 HttpAddRequestHeadersA WININET
0040141C HttpEndRequestA WININET
00401420 InternetSetFilePointer WININET
00401424 InternetGetCookieA WININET
00401428 HttpOpenRequestW WININET
0040142C HttpOpenRequestA WININET
00401430 HttpAddRequestHeadersW WININET
00401434 InternetSetStatusCallbackW WININET
00401438 GetUrlCacheEntryInfoW WININET
0040143C HttpSendRequestW WININET
00401440 InternetReadFile WININET
00401444 InternetReadFileExA WININET
00401448 InternetQueryDataAvailable WININET
0040144C HttpSendRequestExW WININET
00401450 HttpSendRequestExA WININET
00401458 WSAGetOverlappedResult WS2_32
0040145C WSARecv WS2_32
00401460 WSAEventSelect WS2_32
00401464 WSAEnumNetworkEvents WS2_32
00401468 WSAConnect WS2_32
0040146C 111 WSAGetLastError WS2_32
00401470 11 inet_addr WS2_32
00401474 52 gethostbyname WS2_32
00401478 5 getpeername WS2_32
0040147C 17 recvfrom WS2_32
00401480 WSAIoctl WS2_32
00401484 4 connect WS2_32
00401488 WSAAddressToStringW WS2_32
0040148C 115 WSAStartup WS2_32
00401490 getaddrinfo WS2_32
00401494 WSASocketA WS2_32
00401498 22 shutdown WS2_32
0040149C 21 setsockopt WS2_32
004014A0 20 sendto WS2_32
004014A4 16 recv WS2_32
004014A8 2 bind WS2_32
004014AC 23 socket WS2_32
004014B0 freeaddrinfo WS2_32
004014B4 112 WSASetLastError WS2_32
004014B8 19 send WS2_32
004014BC 13 listen WS2_32
004014C0 WSAWaitForMultipleEvents WS2_32
004014C4 6 getsockname WS2_32
004014C8 1 accept WS2_32
004014CC WSACloseEvent WS2_32
004014D0 WSAResetEvent WS2_32
004014D4 3 closesocket WS2_32
004014D8 18 select WS2_32
004014DC WSACreateEvent WS2_32
004014E0 WSASend WS2_32
004014E8 NtQueryKey ntdll
004014F0 StringFromGUID2 ole32
004014F4 CoInitializeEx ole32
004014F8 CoInitialize ole32
004014FC CoGetObject ole32
00401500 CLSIDFromString ole32
00401504 CoUninitialize ole32
00401508 CoSetProxyBlanket ole32
0040150C CoCreateInstance ole32
00401510 CoInitializeSecurity ole32
I will not be going through every single individual import since this would take much more time than what is necessary however what I will be doing is picking out some of the imported functions from the list which are more interesting and have more relevance to malware/the detections from AV vendors.
The first entry of the imports table is Advapi.dll!InitiateSystemShutdownExW (W = Unicode). This function will allow the sample to shut down the system. For more information: InitiateSystemShutdownEx function (Windows)
We can see that there are many registry functions imported: RegCreateKeyExW, RegCloseKey, RegEnumValueW, RegDeleteValueW, RegQueryInfoKeyW, RegCreateKeyW, RegSetValueExW and others. This tells us that the sample most likely interacts with the registry for whatever purpose at some point during execution flow.
The functions RegCreateKeyExW/RegCreateKeyW (from Advapi32.dll library) will allow the sample to create a new key in the registry. Based on first view I would suspect that the sample would be using this to allow itself to auto-start at boot, although without further analysis I can only assume. Based on some of the functions I listed above with relevance to registry operations, we know that the sample is capable of: deleting registry keys, querying info from registry keys, modifying the value of existing registry keys, and closing the handle to a registry key it had opened. You can find more information about Windows API registry functions at the following page: Registry Functions (Windows)
The function GetWindowsDirectoryW (from Kernel32.dll) will return the path of the Windows folder. For more information check the following page: GetWindowsDirectory function (Windows)
The functions Process32FirstW and CreateToolhelp32Snapshot (both present in Kernel32.dll) which caught my eye whilst looking at the imported functions tells me that the malicious sample will most likely enumerate through all the processes to find a specific process (preferably passing a process name (string) and then receiving the PID if a process with that name was found). I actually assume this due to experience of using these functions and using them for a function which will do exactly this, although I can still be wrong. This is just an assumption based on the imports.
I think that it is worth mentioning that the sample has the ability to inject into external processes should it have a need too for whatever purpose. It can accomplish through using the common DLL injection method by using the CreateRemoteThread function it imports (which will force the target process to call LoadLibraryA/LoadLibraryW on the target DLL to be injected, thus it becomes loaded in the address space of the target process and therefore the malicious code within the DLL becomes executed from within that targeted process). The usage to do this also evolves around using functions such as WriteProcessMemory to modify the memory of an external process prior to calling the CreateRemoteThread function to set things up, therefore for me this is enough evidence that the sample will attempt to inject into an external process at some point during execution flow. Maybe my opinion on this is a bit far-fetched, though.
Interestingly, the sample actually imports functions from the CryptoAPI (Crypt32.dll). Another thing I found interesting about the sample is how it imported ntdll!NtQueryKey (ntdll.dll will be covered in a theory thread therefore be sure to watch out for when that thread arrives sometime in distant future).
Pointing out different functions imported by the sample and giving a very brief explanation of what the function is for/what the sample may be doing with it can go on forever with the amount of imports this sample has, however to put it short, the sample has the ability to do many things such as (but not limited to): shutting down the local system (or systems on a network); modifying the security descriptor (DACL) – this can actually be done to protect a process from termination against non-admin processes; registry modification, file modification, modifying process tokens, modifying the priority of threads within a process, performing injection attacks into external processes, enumerating through running processes/threads, duplicate handles, process creation/termination, perform network activity (e.g. send/open HTTP requests – network activity could be used to send the required info about the user/system back to the attacker and receive back instructions to be performed. However, network activity could also be used maliciously to perform network attacks to targeted services such as DDoS attacks), obtain net user information, obtain clipboard data, work with the CryptoAPI, call NTAPI functions (instead of just using the Windows API equivalent and having it point to that direction anyway), and more.
I believe that sufficient information was presented in this part 3 therefore we shall move onto part 4 (for anyone who needs it). The purpose of this part 3 was not to be another tutorial embedded into this tutorial, but to do a quick analysis of a malicious sample based on the import checking we did in the main part of this thread (part 1).
Part 4
The purpose of this part 4 is to quickly overview checking the imports of a Portable Executable via two other pieces of software (which can be freely obtained – or at least there is a free version which will be good enough).
FileAlyzer:
Before we can get started you will need to have downloaded and installed FileAlyzer. You can download FileAlyzer from the official website here.
After you have downloaded and installed FileAlyzer you need to open it up (you do not need to necessarily run it with admin rights, it can run with standard rights right now).
When you open it up at first, you should be granted with an open file dialog. You can actually exit this dialog and it won’t close the program – you’ll be taken to the normal overview work space area however if you haven’t opened anything to analyse then it will all be empty.
Open up the Portable Executable you wish to analyse. For the purpose of this section (part 4) I will be using the malicious sample we used in part 3. After opening it up, the work space should change to something like this:
In my opinion it looks very simple to read. The General tab will provide you details on the path of the sample, the file size, version (if available), hash checksums (CRC-32, MD5, SHA1), file attribute information (e.g. Read only, Hidden, System file, etc), and creation/access/write information. For now, you can ignore all of this and all of the tabs except the “PE Imports” tab. Simply navigate to this tab.
Once you have navigated to the PE Imports tab it should look something like this:
FileAlyzer will actually group each import to the library it’s from. As an example, all Advapi32.dll imports were grouped into their own section, whereas the imports from Kernel32.dll were placed within their own group. The + and – symbols with the green/red boxes are for if the imported function is available on a specific OS (I believe). If you right click you can search for more information for a specific function – this will search for information on the function using your default web browser on Google but filter for MSDN results only.
NOTE: The PE Imports tab may be very “laggy” for you. It normally is for me at least whilst dealing with a PE containing many imports.
Now you’re done! That is all you have to do to view the imports of a PE with FileAlyzer.
PE Explorer:
Before we can get started you will need to have downloaded and installed PE Explorer (free edition will be just fine). You can download PE Explorer from the official website here.
After you have downloaded and installed PE Explorer you need to open it up (you do not need to necessarily run it with admin rights, it can run with standard rights right now).
When you first open it up you should be presented with a quick splash screen however this will close and load the main GUI speedily. You should see something like below:
It looks quite simple, right? The next thing you’ll need to do is actually open up the target file (I will be using the malicious sample from earlier – you can drag it onto the GUI or use the quick-open toolbar icon… Or go to File > Open File (Ctrl + O)).
After opening up the PE it should take you to the “Headers info” tab by default. All you need to do is click the “Import” tab button on the toolbar to be taken to the Imports tab. Check the screenshots in the below spoiler:
Now the useful feature of the Imports tab with this software which I like is that it allows you to go through the different libraries which functions are imported from and then it displays the functions from that library which were imported in a separate list as opposed to mixing it all up, and it does this quite quickly. Nor do I experience any sort of “lag” whilst navigating the Imports tab GUI, unlike with other software.
Another good feature is that it provides a feature known as “Syntax Details” with a box containing text elements which gives some information on the function (e.g. parameters).
NOTE: The free version is actually a 30-day evaluation of the paid version. Although there is nothing wrong with experimenting with it for analysis of malware during this evaluation!
Now you’re done! That is all you have to do to view the imports of a PE with PE Explorer.
---------------
Part four was just a bonus addition to not only improve the quality of this thread but to potentially help anyone who does actually find themselves stuck attempting to check the imports with another tool – when you are starting out it can be very easy to become confused and stuck and this can be very stressful. Therefore, even though it should be fairly obvious on using another tool for checking the imports (to some people), it may not be as simple for others and this was the reason I added in part four.
IDA is a very sophisticated piece of software for reverse engineering and has a very large feature set. Due to this, I intentionally did not cover a lot of things and strictly tried to stay on topic and base it down to what was needed to be mentioned. Other things will be covered with IDA in future tutorials (both static and dynamic tutorials).
---------------
Thank you for reading and hopefully this tutorial helped you.
Wave.