Malware Analysis xRatLocker Ransomware Analysis

Opcode

Level 28
Content Creator
Joined
Aug 17, 2017
Messages
1,733
#1


Introduction

This thread is to go over some results of my manual analysis for a malware sample which was shared by @Der.Reisende over on the malware hub today. The threat name is xRatLocker (Ransomware) and you can find the original thread link here: https://malwaretips.com/threads/xratlocker-ransomware.77089/

I've done a little bit of both static and dynamic analysis. The sample will be able to do more than what is covered here, I was only focusing on the essential information to share. Feel free to take a look at the sample yourself to dig deeper and reveal more about the inner workings of it.

File name: 0add56a81c194a06fce1f79102ef46b3fd130d7355d3a419feb7d7c671312347.exe (SHA-256 with *.exe extension)

MD5 hash: 5a5403fab09f64500fe01eba6c6c491b
SHA-1 hash: 87ba8ffec8fa9db809bc6336a6032f66b015390a
SHA-256 hash: 0add56a81c194a06fce1f79102ef46b3fd130d7355d3a419feb7d7c671312347


Static analysis

To start off, we will check the sample with Exeinfo PE. For those of you who are unaware, Exeinfo PE is a very useful tool which can be used to check if a known packer has been applied for the sample (or obfuscator for MSIL executables). I used to use PEiD however it is outdated now, Exeinfo PE follows the same User Interface theme and is essentially the updated copy of PEiD.





According to Exeinfo PE, the sample is not packed. We will verify this further by checking other characteristics of the PE, such as the imports - it is common for packed samples to only import a few functions such as GetProcAddress and LoadLibraryA/W. You could check the entropy calculation for the PE as another indicator on whether it is packed or not, but I do not feel this is necessary right now... The entropy is calculated based on the randomness of data within the PE; a low score represents the data is not random and therefore the PE is likely not to be packed, and a high score represents the opposite of this.

The next thing I will do is open up the sample in Interactive Disassembler (IDA). The reason I will do this is because I prefer to use IDA for viewing the Imports and Exports, and it also gives us an opportunity to check the references to various functions. Using features within IDA, we'll be able to see if the Import Address Table is faked or not and inspect various functions which call APIs of interest to us.





If we go over to the Exports tab, we'll be able to see which functions are exported by the Portable Executable. Usually you will find a main start function which could be related to the CRT (Common Run-Time) - it depends on the language used by the sample and the compiler. IDA attempts to find the entry-point via a combination of techniques, one of them being signature-based detection.





We can see from the above Exports tab that the PE exports five different functions.

Code:
ReflectiveLoader
TlsCallback_0
TlsCallback_1
TlsCallback_2
start
IDA has automatically identified that the start function is the main entry for the sample. At this point, I am not very interested in pursuing further with either of the exported functions; I know I will be doing dynamic analysis later on to identify the bare bones functioning for the sample. For this reason, I will switch over to the Imports tab - I wish to see which functions are statically imported so I can check the references to them.





We have 236 statically imported functions. Between all the statically imported functions, the following modules are used: advapi32.dll, iphlpapi.dll, kernel32.dll, mpr.dll, msvcrt.dll, netapi32.dll, shell32.dll, shlwapi.dll and wsa_32.dll.

I have gone through the list of statically linked imported functions and have made a separate list of the functions which may potentially be of interest to us.

Code:
OpenServiceW (ADVAPI32)
CreateServiceW (ADVAPI32)
StartServiceW (ADVAPI32)
ControlService (ADVAPI32)
DeleteService (ADVAPI32)

CryptAcquireContextW (ADVAPI32)
CryptCreateHash (ADVAPI32)
CryptDeriveKey (ADVAPI32)
CryptDestroyHash (ADVAPI32)
CryptDestroyKey (ADVAPI32)
CryptDuplicateKey (ADVAPI32)
CryptEncrypt (ADVAPI32)
CryptGenRandom (ADVAPI32)
CryptHashData (ADVAPI32)
CryptImportKey (ADVAPI32)
CryptReleaseContext (ADVAPI32)
CryptSetKeyParam (ADVAPI32)

RegCreateKeyExW (ADVAPI32)
RegOpenKeyExW (ADVAPI32)
RegSetValueExA (ADVAPI32)
RegSetValueExW (ADVAPI32)
RegDeleteValueW (ADVAPI32)

GetUserNameW (ADVAPI32)

GetAdaptersInfo (IPHLPAPI)

CreateProcessA (KERNEL32)

CreateFileW (KERNEL32)
ReadFile (KERNEL32)
WriteFile (KERNEL32)
DeleteFileW (KERNEL32)
GetFileSizeEx (KERNEL32)
GetFileAttributesW (KERNEL32)
MoveFileExW (KERNEL32)

GetSystemDirectoryA (KERNEL32)
GetTempFileNameW (KERNEL32)

LoadResource (KERNEL32)

GetComputerNameW (KERNEL32)

IsDebuggerPresent (KERNEL32)

ShellExecuteW (SHELL32)

NetApiBufferFree (NETAPI32)
NetShareEnum (NETAPI32)

WSAStartup (WSA_32)
closesocket (WSA_32)
connect (WSA_32)
getaddrinfo (WSA_32)
htons (WSA_32)
inet_addr (WSA_32)
socket (WSA_32)
All the functions in the above list are documented over at Microsoft Developer Network (MSDN). The functions mentioned above can be used for a wide variety of things: Windows Service operations, cryptography operations, registry operations, retrieval of data (computer name, system file path, temp path), file-system operations, resource operations, process operations (e.g. process execution was what I was focusing on), detection of a debugger being attached to the process (anti-reversing), and network operations. There are a few functions I left out of the list which are still important: FindFirstFileW, FindNextFileW and GetLogicalDriveStrings.

Since we already know that the sample is ransomware, we would naturally expect file encryption to occur at some point during execution, and a demand for ransom payment afterwards to gain useful access to the affected documents again. There are many types of ransomware, not all of them will actually encrypt documents. However, looking at the statically imported functions, you may get the idea that the sample will indeed work like most traditional ransomware and encrypt the user documents. If you had an idea that this was going to happen, you were right before you started the real analysis!

The sample statically imports the functions FindFirstFileW and FindNextFileW because they are responsible for file enumeration. The sample needs a way to enumerate through all the files on the system at the specified directory, and preferably also in sub-directories. This means the sample will have a routine responsible for the file enumeration, and it'd make perfect sense for this routine to be using both of those mentioned functions, otherwise what would the point in them being statically imported be?

There is a structure called WIN32_FIND_DATA (Win32 API) which is used when FindFirstFileW is called. The implementation works by setting the variable data within the structure pointed to the function call depending on the data for the currently enumerated file. This allows someone to gain data about the current file during the enumeration operation.

Code:
typedef struct _WIN32_FIND_DATA {
  DWORD    dwFileAttributes;
  FILETIME ftCreationTime;
  FILETIME ftLastAccessTime;
  FILETIME ftLastWriteTime;
  DWORD    nFileSizeHigh;
  DWORD    nFileSizeLow;
  DWORD    dwReserved0;
  DWORD    dwReserved1;
  TCHAR    cFileName[MAX_PATH];
  TCHAR    cAlternateFileName[14];
} WIN32_FIND_DATA, *PWIN32_FIND_DATA, *LPWIN32_FIND_DATA;
I'm going to double click on the FindFirstFileW function from the Imports tab in IDA. It should take me to another view.





I want to check for cross references to the statically imported function so I can find the routine/s responsible for file enumeration (operand reference search). The short-cut key for this is X by default.





The first one selected by default shows us that the Text value for the reference entry is call eax. The entry below this one (second reference) shows us the mov eax instruction being performed. The second reference occurs before the first one, we know this from the Address values (they both exist in the same function prologue however the second one is + 303 whereas the first one is + 308 which indicates to us that the second happens before the first).

Code:
mov eax, ds:FindFirstFileW ; the address of FindFirstFileW is being put into the EAX register
...
call eax ; FindFirstFileW is being called because code execution flow moves to the address within EAX
Based on the reference search, we know that the function is only called once within the entire program (unless a dynamic import for the function was used within another routine) in one single routine. The likelihood is that the routine it is used in is responsible for the file enumeration operation which is used to find files which need to be encrypted.

Let's go to this routine.





We can see that the function is indeed called by this routine at some point. We can also see that there are test conditions performed after the call, but still related to the call - using the data within the structure passed to the function as the second parameter. We know this from the first box we can see on the screen view at the bottom right: mov eax, ... and then the test/jz instructions being used.





The call to FindFirstFileW is performed and the results are stored to the FindFileData variable (data-type of WIN32_FIND_DATA). We can see it was declared at the start of the function.





This confirms to us that the sample will attempt to receive data about a specific file, or about all files within a given directory. If you check the documentation for FindFirstFile (A/W) you will find the following clear remark for the first parameter (v12 reference in IDA view).

The directory or path, and the file name. The file name can include wildcard characters, for example, an asterisk (*) or a question mark (?).

This parameter should not be NULL, an invalid string (for example, an empty string or a string that is missing the terminating null character), or end in a trailing backslash (\).

If the string ends with a wildcard, period (.), or directory name, the user must have access permissions to the root and all subdirectories on the path.
If we move down further on IDA, we will find a call to FindNextFileW.





This confirms to us that file enumeration will happen at some point during execution flow, since FindNextFileW is being used (as well as a loop for it).

The question we need to ask ourselves now is: what happens during enumeration? You will be able to see many different functions being called for different things, and since we are performing disassembly... It can be very time-consuming and tricky at times to go through all function calls and determine what exactly is going on.

The ransomware sample is going to need to open a handle to the target file before it can read the data from it (and write to it for replacing the data with the encrypted data). This is a clue. We need to look out for usage of CreateFile, ReadFile and WriteFile.

CreateFile - can be used to open a handle to a file which already exists or alternatively create a new file on-disk.

ReadFile - can be used to read data within a file into memory, the handle returned from CreateFile is passed in to represent that target file.

WriteFile - can be used to write data to the target file, passing in the handle to represent the target file.


We can easily find where these three functions are called using the operand reference check again, as we did to find usage of FindFirstFileW earlier on. We know that CreateFileW, ReadFile and WriteFileW is statically imported already from the start of the analysis where we checked the statically imported functions (KERNEL32 exports).

I located the routine responsible for:
1. Opening the handle to the target file (found within the enumeration -> the currently enumerated file)
2. Reading the contents of the file into memory.
3. Encrypting the data within the buffer in memory (the buffer is the location in memory where the data read from the file is placed).
4. Writing to the file using the handle previously opened to replace the data with the encrypted version.

The function was sub_434F04 and takes in seven (7) parameters. We are going to go through a bit of it briefly so we can understand what operations are performed for these tasks to be completed.







The variable v57 is assigned a value of the file name (which is the file path) of the currently found file. The variable v39 will be assigned the value of v57 and v39 is passed as the second parameter to the sub_434F04 function (which I will manually re-name to and refer to from now on as EncryptFileRoutine).





This indicates for us that the EncryptFileRoutine function will reference the second parameter (a2) for a file handle opening request (via CreateFileW). We can see from the image below that this is indeed the case.





The reason the function GetFileSizeEx (KERNEL32) is called after a conditional statement is performed to ensure the handle for the targeted file could indeed be successfully opened, is because the size of the file is necessary before memory allocation can be performed. In-case you are wondering why memory allocation has to be performed, it is because there needs to be free memory with a sufficient file size to hold the data of the file - the data within the file is read into this memory later on. The encryption targets the data in local memory, and then the file write operation uses the buffer (data from the local memory) to replace the original data within the file.





Dst is the variable which will hold the address to the local memory. We can see it being assigned a value of the return for sub_4ED770. Let's take a look at this routine.





It returns the value returned by another function, let's go to sub_4ED790.




We can see from the above image that one parameter only is passed in (named a1) and it has a data-type of size_t. The function malloc is called, passing the variable v1 as the parameter. Beforehand, v1 is assigned a value of a1, however if the value of a1 is NULL (0 - empty) then the value of v1 equals one (1).

The return for the malloc function call is returned by the function. The function malloc is from the C/C++ run-time library.

If we go back to the EncryptFileRoutine function, we'll find a call to ReadFile (KERNEL32), using the memory allocated from these functions used as the buffer to hold the data read from the file (bytes).

After the read operation has been performed, we'll find a call to the CryptEncrypt (ADVAPI32) function before the WriteFile (KERNEL32) call is made.





For the record, prior to the CryptEncrypt being used, other cryptography-related functions which also happen to be exported by ADVAPI32 will be used. The routine responsible for calling them is invoked during the file enumeration also, but prior to the EncryptFileRoutine function being invoked.










This is how the encryption for this ransomware sample works. Some ransomware samples may rely on the same method, not all of them will. Others may append to files or rely on third-party libraries (e.g. for RSA-4096 encryption) and more automation.

The last thing we will look at for static analysis is the anti-reversing technique the sample applies. The sample statically imports a function called IsDebuggerPresent (KERNEL32) as we know from earlier with the Import Address Table check.



The way the function works is if the function returns TRUE (1) then this represents that the current process is attached to a debugger, whereas if the return value is FALSE (0) then this represents the opposite. The return value is located within the EAX register.

To bypass this anti-reversing trick, you can set a break-point for IsDebuggerPresent (KERNEL32) and mov eax, 0 before returning back. All you need to do is make the value within the EAX register equal to zero (0), meaning the program will believe that FALSE was returned and be tricked into believing a debugger is not present even if there is.

All in all, the anti-reversing trick which is applied is really nothing special at all and has been known for years, years and many more years. It is so well known that I don't even understand why the author of this sample bothered to add it in... It is literally meaningless and is likely to have hardly an effect at all due to how known and simple it is.


Dynamic analysis

In this section we will go over a few things we have already gone through during the static analysis section (although in a dynamic way as opposed to static) and look at a few things we did not during static analysis. Please remember to feel free to analyse the sample yourself because this analysis is not full, I am only focusing on the bare functionality really.

This section will evolve around API Monitoring (with API Monitor), as opposed to using a debugger such as OllyDbg/WinDbg which you were likely expecting.

Before I can start the dynamic analysis and explanations, I need to cover a few things briefly so you will understand better.

Win32 API functions for process execution will always trigger two functions: NtCreateUserProcess and NtResumeThread. Both NtCreateUserProcess and NtResumeThread are exported by NTDLL, however are also undocumented. The call to NtResumeThread is performed to start the main thread of the newly starting up process. The reason a break-point/detour is set for both of these functions is so I can dynamically intercept process start-up requests (and make sure the newly starting up process is affected within the monitoring scope prior to its main thread being resumed which would result in its code starting to execute).

- malloc (MSVCRT) will result in a call to NtAllocateVirtualMemory (NTDLL).
- memcpy (MSVCRT) will result in a call to NtWriteVirtualMemory (NTDLL).
- CreateFile (KERNEL32) will end up calling NtCreateFile (NTDLL).
- GetFileSizeEx (KERNEL32) will end up calling NtQueryInformationFile (NTDLL).
- ReadFile (KERNEL32) will end up calling NtReadFile (NTDLL).
- WriteFile (KERNEL32) will end up calling NtWriteFile (NTDLL).

When the sample first starts up, one of the first things it will do is perform a cryptography operation. It will make a call to the function CryptImportKey (ADVAPI32).

The next stage is a lot of process execution, you can thank the interception on NtCreateUserProcess for these logs.
1. "cmd.exe /c wevtutil cl Application"
2. "cmd.exe /c wevtutil cl security"
3. "cmd.exe /c wevtutil cl setup"
4. "cmd.exe /c wevtutil cl system"
5. "cmd.exe /c vssadmin.exe Delete Shadows \/All \/Quiet"
6. "cmd.exe /c WMIC SERVICE WHERE 'caption LIKE '%Firebird%'' CALL STOPSERVICE"
7. "cmd.exe /c WMIC SERVICE WHERE 'caption LIKE '%MSSQL%'' CALL STOPSERVICE"
8. "cmd.exe /c WMIC SERVICE WHERE 'caption LIKE '%SQL%'' CALL STOPSERVICE"
9. "cmd.exe /c WMIC SERVICE WHERE 'caption LIKE '%Exchange%'' CALL STOPSERVICE"
10. "cmd.exe /c WMIC SERVICE WHERE 'caption LIKE '%wsbex%'' CALL STOPSERVICE"
11. "cmd.exe /c WMIC SERVICE WHERE 'caption LIKE '%postgresql%'' CALL STOPSERVICE"
12. "cmd.exe /c WMIC SERVICE WHERE 'caption LIKE '%BACKP%'' CALL STOPSERVICE"
13. "cmd.exe /c WMIC SERVICE WHERE 'caption LIKE '%tomcat%'' CALL STOPSERVICE"
14. "cmd.exe /c WMIC SERVICE WHERE 'caption LIKE '%SharePoint%'' CALL STOPSERVICE"
15. "cmd.exe /c WMIC SERVICE WHERE 'caption LIKE '%SBS%'' CALL STOPSERVICE"
16. "cmd.exe /c WMIC SERVICE WHERE 'caption LIKE '%Firebird%'' CALL ChangeStartMode 'Disabled'"
17. "cmd.exe /c WMIC SERVICE WHERE 'caption LIKE '%MSSQL%'' CALL ChangeStartMode 'Disabled'"
18. "cmd.exe /c WMIC SERVICE WHERE 'caption LIKE '%SQL%'' CALL ChangeStartMode 'Disabled'"
19. "cmd.exe /c WMIC SERVICE WHERE 'caption LIKE '%Exchange%'' CALL ChangeStartMode 'Disabled'"
20. "cmd.exe /c WMIC SERVICE WHERE 'caption LIKE '%postgresql%'' CALL ChangeStartMode 'Disabled'"
21. "cmd.exe /c WMIC SERVICE WHERE 'caption LIKE '%BACKP%'' CALL ChangeStartMode 'Disabled'"
22. "cmd.exe /c WMIC SERVICE WHERE 'caption LIKE '%tomcat%'' CALL ChangeStartMode 'Disabled'"
23. "cmd.exe /c WMIC SERVICE WHERE 'caption LIKE '%SharePoint%'CALL ChangeStartMode 'Disabled'"
24. "cmd.exe /c WMIC SERVICE WHERE 'caption LIKE '%SBS%'' CALL ChangeStartMode 'Disabled'"
25. "cmd.exe /c sc config FirebirdServerDefaultInstance start= disabled"
26. "cmd.exe /c taskkill \/IM fb_inet_server.exe \/F"
27. "cmd.exe /c net stop FirebirdServerDefaultInstance"
28. "cmd.exe /c taskkill \/IM sqlservr.exe \/F" "/c taskkill \/IM sqlservr.exe \/F"
29. "cmd.exe /c sc config MSSQLSERVER start= disabled"
30. "cmd.exe /c sc config MSSQL$SQLEXPRESS start= disabled"
31. "cmd.exe /c net stop MSSQLSERVER"
32. "cmd.exe /c net stop MSSQL$SQLEXPRESS"
33. "cmd.exe /c taskkill \/IM pg_ctl.exe \/F"
34. "cmd.exe /c sc config postgresql-9.0 start= disabled"
35. "cmd.exe /c net stop postgresql-9.0"
36. "cmd.exe /c sc config MSExchangeAB start= disabled"
37. "cmd.exe /c sc config MSExchangeAntispamUpdate start= disabled"
38. "cmd.exe /c sc config MSExchangeEdgeSync start= disabled"
39. "cmd.exe /c sc config MSExchangeFDS start= disabled"
40. "cmd.exe /c sc config MSExchangeFBA start= disabled"
41. "cmd.exe /c sc config MSExchangeImap4 start= disabled"
42. "cmd.exe /c sc config MSExchangeIS start= disabled"
43. "cmd.exe /c sc config MSExchangeMailSubmission start= disabled"
44. "cmd.exe /c sc config MSExchangeMailboxAssistants start= disabled"
45. "cmd.exe /c sc config MSExchangeMailboxReplication start= disabled"
46. "cmd.exe /c sc config MSExchangeMonitoring start= disabled"
47. "cmd.exe /c sc config MSExchangePop3 start= disabled"
48. "cmd.exe /c sc config MSExchangeProtectedServiceHost start= disabled"
49. "cmd.exe /c sc config MSExchangeRepl start= disabled"
50. "cmd.exe /c sc config MSExchangeRPC start= disabled"
51. "cmd.exe /c sc config MSExchangeSearch start= disabled"
52. "cmd.exe /c sc config wsbexchange start= disabled"
53. "cmd.exe /c sc config MSExchangeServiceHost start= disabled"
54. "cmd.exe /c sc config MSExchangeSA start= disabled"
55. "cmd.exe /c sc config MSExchangeThrottling start= disabled"
56. "cmd.exe /c sc config MSExchangeTransport start= disabled"
57. "cmd.exe /c sc config MSExchangeTransportLogSearch start= disabled"
58. "cmd.exe /c sc config MSExchangeADTopology start= disabled"
59. "cmd.exe /c net stop MSExchangeAB"
60. "cmd.exe /c net stop MSExchangeAntispamUpdate"
61. "cmd.exe /c net stop MSExchangeEdgeSync"
62. "cmd.exe /c net stop MSExchangeFDS"
63. "cmd.exe /c net stop MSExchangeFBA"
64. "cmd.exe /c net stop MSExchangeImap4"
65. "cmd.exe /c net stop MSExchangeIS"
66. "cmd.exe /c net stop MSExchangeMailSubmission"
67. "cmd.exe /c net stop MSExchangeMailboxAssistants"
68. "cmd.exe /c net stop MSExchangeMailboxReplication"
69. "cmd.exe /c net stop MSExchangeMonitoring"
70. "cmd.exe /c net stop MSExchangePop3"
72. "cmd.exe /c net stop MSExchangeProtectedServiceHost"
73. "cmd.exe /c net stop MSExchangeRepl"
74. "cmd.exe /c net stop MSExchangeRPC"
75. "cmd.exe /c net stop MSExchangeSearch"
76. "cmd.exe /c net stop wsbexchange"
77. "cmd.exe /c net stop MSExchangeServiceHost"
78. "cmd.exe /c net stop MSExchangeSA"
79. "cmd.exe /c net stop MSExchangeThrottling"
80. "cmd.exe /c net stop MSExchangeTransport"
81. "cmd.exe /c net stop MSExchangeTransportLogSearch"
82. "cmd.exe /c net stop MSExchangeADTopology""





The next operation the sample performs is related to cryptography. If you remember back to earlier before the process execution tasks related to cmd.exe, the sample made a call to a function called CryptImportKey (ADVAPI32). Now it makes a duplicate of the key via CryptDuplicateKey (ADVAPI32), using the key it received from the CryptImportKey function.



A second call to CryptDuplicateKey will be made afterwards.

The next stage is the enumeration of files on the system; it targets the system drive which is usually the C drive ("C:\\"). Therefore, a call to FindFirstFileW (KERNEL32) is made and afterwards calls to FindNextFileW (KERNEL32) will be made.



After these calls, another cryptographic function is called, known as CryptGenRandom (ADVAPI32). It is responsible for filling a buffer (area in memory) with random bytes.

The sample will attempt to scan the D drive ("D:\\") even if there is not one present, also via FindFirstFileW.



The sample will now destroy the original key with CryptDestroyKey (ADVAPI32).



A call to CryptDeriveKey (ADVAPI32) will be made. The second parameter for the function call will be CALG_AES_256 (AES-256 encryption).



CryptDuplicateKey will be called once again, then a function called CryptSetKeyParam (ADVAPI32) will be called twice, and then CryptDuplicateKey a few more times.



According to the call stack, all of these calls are coming from a function called ReflectiveLoader@4 (which we saw from the Exports check at the very start of the static analysis section).

The next stage is some networking operations.
The sample will start by calling the function htons (used for a conversion), passing the value 445 as the parameter. Afterwards, another function called inet_addr will be called, passing an IP address as the parameter ("192.168.77.1"). The last function call related to this IP address will be a call to the function socket, where the flags AF_INET_SOCK_STREAM is specified for the first parameter, and IPPROTO_IP for the second.

The same will repeat the exact same networking operations for other IP address afterwards:
- 192.168.77.2
- 192.168.77.3
- 192.168.77.4
- 192.168.77.5
- 192.168.77.6
- 192.168.77.7
- 192.168.77.8
- 192.168.77.9
- 192.168.77.10
- 192.168.77.11
- 192.168.77.12
- 192.168.77.13
- 192.168.77.14
......

It will keep attempting to connect with socket up until 192.168.77.X reaches 256 (where X = 256). If the call fails, SOCKET_ERROR is returned. If it cannot connect by the time the X value reaches 256, it will give up and get on with the encryption operations further.

The encryption routine
Once the encryption routine becomes the main focus depending on the socket connection attempts, every enumerated file in the firing line for encryption will have a handle opened to it via CreateFile (KERNEL32) (which means the NtCreateFile break-point will get hit), ReadFile (KERNEL32) will be called to read the file contents into memory (a buffer -> after memory allocation with the sufficient size), CryptEncrypt (ADVAPI32) will be called and then WriteFile (KERNEL32) will be called to replace the normal data with the encrypted version of the data.

The below images demonstrate an example of one of the NtCreateFile calls (which was a file targeted due to being found on the file enumeration) as well as showing how the sample will create a *.html file in each directory it encrypts a file within for instructions about decryption of the affected files.







Once the encryption routine was complete, I decided to take a look at the dropped html documents. This is what it will look like.








I am not a cryptography expert but I don't recall it using RSA-2048. I thought it only used AES-256 encryption during analysis...

During my first run of the sample, it dropped a script to the desktop (batch I believe) which was responsible for self-deleting the main sample when executed. I couldn't get the same to replicate this a second time, therefore sadly I cannot add this in properly.

----------------------------------------------------------

I'd like to thank @Der.Reisende for kindly sharing the sample with the community today before I end this analysis thread.

Thank you for reading,
- Opcode.
 
Last edited:

Opcode

Level 28
Content Creator
Joined
Aug 17, 2017
Messages
1,733
#2
To bypass this anti-reversing trick, you can set a break-point for IsDebuggerPresent (KERNEL32) and mov eax, 0 before returning back. All you need to do is make the value within the EAX register equal to zero (0), meaning the program will believe that FALSE was returned and be tricked into believing a debugger is not present even if there is.
For those that are interested in anti-reversing, the function IsDebuggerPresent uses the Process Environment Block.

Code:
typedef struct _PEB
{
    UCHAR InheritedAddressSpace;
    UCHAR ReadImageFileExecOptions;
    UCHAR BeingDebugged;
    UCHAR BitField;
    ULONG ImageUsesLargePages: 1;
    ULONG IsProtectedProcess: 1;
    ULONG IsLegacyProcess: 1;
    ULONG IsImageDynamicallyRelocated: 1;
    ULONG SpareBits: 4;
    PVOID Mutant;
    PVOID ImageBaseAddress;
    PPEB_LDR_DATA Ldr;
    PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
    PVOID SubSystemData;
    PVOID ProcessHeap;
    PRTL_CRITICAL_SECTION FastPebLock;
    PVOID AtlThunkSListPtr;
    PVOID IFEOKey;
    ULONG CrossProcessFlags;
    ULONG ProcessInJob: 1;
    ULONG ProcessInitializing: 1;
    ULONG ReservedBits0: 30;
    union
    {
         PVOID KernelCallbackTable;
         PVOID UserSharedInfoPtr;
    };
    ULONG SystemReserved[1];
    ULONG SpareUlong;
    PPEB_FREE_BLOCK FreeList;
    ULONG TlsExpansionCounter;
    PVOID TlsBitmap;
    ULONG TlsBitmapBits[2];
    PVOID ReadOnlySharedMemoryBase;
    PVOID HotpatchInformation;
    VOID * * ReadOnlyStaticServerData;
    PVOID AnsiCodePageData;
    PVOID OemCodePageData;
    PVOID UnicodeCaseTableData;
    ULONG NumberOfProcessors;
    ULONG NtGlobalFlag;
    LARGE_INTEGER CriticalSectionTimeout;
    ULONG HeapSegmentReserve;
    ULONG HeapSegmentCommit;
    ULONG HeapDeCommitTotalFreeThreshold;
    ULONG HeapDeCommitFreeBlockThreshold;
    ULONG NumberOfHeaps;
    ULONG MaximumNumberOfHeaps;
    VOID * * ProcessHeaps;
    PVOID GdiSharedHandleTable;
    PVOID ProcessStarterHelper;
    ULONG GdiDCAttributeList;
    PRTL_CRITICAL_SECTION LoaderLock;
    ULONG OSMajorVersion;
    ULONG OSMinorVersion;
    WORD OSBuildNumber;
    WORD OSCSDVersion;
    ULONG OSPlatformId;
    ULONG ImageSubsystem;
    ULONG ImageSubsystemMajorVersion;
    ULONG ImageSubsystemMinorVersion;
    ULONG ImageProcessAffinityMask;
    ULONG GdiHandleBuffer[34];
    PVOID PostProcessInitRoutine;
    PVOID TlsExpansionBitmap;
    ULONG TlsExpansionBitmapBits[32];
    ULONG SessionId;
    ULARGE_INTEGER AppCompatFlags;
    ULARGE_INTEGER AppCompatFlagsUser;
    PVOID pShimData;
    PVOID AppCompatInfo;
    UNICODE_STRING CSDVersion;
    _ACTIVATION_CONTEXT_DATA * ActivationContextData;
    _ASSEMBLY_STORAGE_MAP * ProcessAssemblyStorageMap;
    _ACTIVATION_CONTEXT_DATA * SystemDefaultActivationContextData;
    _ASSEMBLY_STORAGE_MAP * SystemAssemblyStorageMap;
    ULONG MinimumStackCommit;
    _FLS_CALLBACK_INFO * FlsCallback;
    LIST_ENTRY FlsListHead;
    PVOID FlsBitmap;
    ULONG FlsBitmapBits[4];
    ULONG FlsHighIndex;
    PVOID WerRegistrationData;
    PVOID WerShipAssertPtr;
} PEB, *PPEB;
Source: struct PEB

The entry in the PEB structure of interest is the third one called BeingDebugged (UCHAR - unsigned char). 0 means it is not, 1 means it is (FALSE/TRUE). The value of this variable is put into the EAX/RAX register (EAX is a 32-bit register whereas RAX is the 64-bit version of EAX).

You can retrieve the information manually via finding the Process Environment Block -> extracting the data:
1. __readfsdword() for 32-bit processes or __readgsqword() for 64-bit processes -> obtain the Thread Environment Block (TEB)
2. Obtain the Process Environment Block (PEB) from the Thread Environment Block (TEB)
3. Check the contents of third entry

A much better way for anti-debugging is via NtQueryInformationProcess using the PROCESS_INFORMATION_CLASS as 7 (ProcessDebugPort) = the memory for the ProcessInformation parameter becomes -1 if a debugger is attached to the process. Norton wrote about this technique a very long time ago: Windows Anti-Debug Reference | Symantec Connect (2007 paper)

For IsDebuggerPresent, all you must do is set a break-point on the function -> change EAX/RAX to 0 (MOV EAX, 0 or MOV RAX, 0) -> now the program is tricked. If it is implemented manually (e.g. extracting data from PEB manually) then you just break-point at those instructions -> do the same thing.
 

Opcode

Level 28
Content Creator
Joined
Aug 17, 2017
Messages
1,733
#5
5. "cmd.exe /c vssadmin.exe Delete Shadows \/All \/Quiet"
This one is for deleting shadow copies, which is very common for ransomware to do. For those of you that rely on anti-executable, set vssadmin.exe in the Vulnerable Process List (VPL). If execution is triggered and there are arguments for deleting the shadow copies ("Delete Shadows") then block the action unless you are doing something yourself to trigger this, or consent for software to perform this action.

@Der.Reisende @BoraMurdar It was a pleasure, thank you for your support! :)
 
Last edited:
Joined
Mar 13, 2017
Messages
29
OS
Windows 10
Antivirus
ESET
#9
As I saw API monitor uses kernel driver for hooking.
Why is API monitor driver mapped as DLL in Process Explorer window?


I thought that user apps was unaware of drivers, and especially not mapped to userland. I'm confused.
 

Opcode

Level 28
Content Creator
Joined
Aug 17, 2017
Messages
1,733
#10
@Zhou He The apimonitor-drv-x64.sys isn't a real driver, it is a user-mode DLL. The DLL is injected into the monitored process and will hook various APIs depending on the configuration. This is the same for both the 32-bit and 64-bit compiled ".sys" files.

I am not entirely sure why the author tried to make it appear as a kernel-mode device driver. It certainly isn't one, I don't understand what the point of that even was. Regardless, I still like the software and use it a lot when analysing malware (only down-side is I have to manually detour CreateProcessInternalW or NtTerminateProcess since it doesn't support those two functions - should I want to intercept them).
 

Opcode

Level 28
Content Creator
Joined
Aug 17, 2017
Messages
1,733
#12
@Zhou He I don't recall Nymaim ransomware making use of atom-bombing yet, the threat has been around for many years now (started in 2013 I believe).

An easy way to detect any malware is relying on Atom Bombing/Normal APC injection would be to monitor usage of NtQueueApcThread. If NtQueueApcThread is triggered, you can take a step back and check what is going on around the time of the call more closely to determine if it was atom bombing/normal APC injection.

About the specific sample you asked about, based on what I can see from the Hybrid-Analysis report, I really doubt it will deploy atom-bombing injection. I don't think there is a need for manual analysis to check on this, it is extremely unlikely. The ransomware family, Nymaim, isn't known for doing this.
 
Last edited:

Opcode

Level 28
Content Creator
Joined
Aug 17, 2017
Messages
1,733
#13
@Zhou He The JavaScript will be executed under wscript.exe (genuine Windows process) -> will lead to a PE being dropped to the Temp folder and then CreateProcessA/W will be called to spawn it (break-point for NtCreateUserProcess and you'll catch wscript.exe trying to execute it, and the call-stack will notify you that the original call which led to this break-point was due to CreateProcessA/W).

This is why most people set processes like wscript.exe, cmd.exe and others on a Vulnerable Process List (VPL) when using software such as anti-executable. Vendors like Avast should flag the behavior from wscript.exe for these types of attacks through its Behavior Shield component (thanks to @silversurfer for testing with it over on the thread where he/she posted the sample).
 

Opcode

Level 28
Content Creator
Joined
Aug 17, 2017
Messages
1,733
#15
Hi. I am new and i was wondering where can i download the sample?
I'd share the sample with you if I still had it but sadly I do not. You can download the sample using the Hybrid-Analysis report however they've recently introduced a new download system and it requires you to submit an application form for their vetting process.

You could try your luck and see if @silversurfer or @Der.Reisende still have the sample.
 
Likes: Der.Reisende

JuanMa

New Member
Joined
Jan 22, 2018
Messages
2
#16
I'd share the sample with you if I still had it but sadly I do not. You can download the sample using the Hybrid-Analysis report however they've recently introduced a new download system and it requires you to submit an application form for their vetting process.

You could try your luck and see if @silversurfer or @Der.Reisende still have the sample.
@silversurfer or @Der.Reisende

@silversurfer , @Der.Reisende Please, can you share it if still have it?. I tried using Hybrid-Analysis but i have to provide personal information.
 
Likes: Der.Reisende