, 2008-02-26
Old school virus methods appear to be in vogue at the moment! Hot on the heels of Trojan.Mebroot, which overwrote the MBR, we have discovered a new worm that is reviving another old school trick in order to hide itself. At first glance it appears to be a regular worm, but there is more going on here than meets the eye.
The worm in question is called W32.Joydotto and it initially appeared to be just another worm that spreads by copying itself and an autorun.inf file to all removable devices. However, upon closer examination it was seen that the worm copies itself to removable devices without using a file name for itself. By doing this the worm cannot be seen using any file-listing tools since there is no filename to find. In addition to this the worm ensures its longevity by marking part of the disk as being corrupted. In this way it will not be overwritten because that part of the disk is thought to be corrupt. In fact the only way to find the worm on the disk is to know its exact location, along with the correct decryption keys. This information is only stored in one place: a loader file that the worm uses to manifest and execute itself. This is a trick that some older dos viruses used back in their heyday, however this trick has not been popular for quite some time now.
The worm works in the following manner:
- It searches for all removable devices that contain a FAT partition.
- It then finds a random location on disk with enough space to store itself.
- It then encrypts itself using three randomly generated keys.
- It writes the encrypted data directly to the location found above (this way, no filename is needed).
- Next, it marks any clusters it used as being "corrupted/reserved".
- It then creates a small loader file, which is stored as a regular file on the disk as [drive letter]:\Recycled\L.exe.
- Finally, it creates an autorun.inf file in the root of the disk that will run the small loader file.[1]
The loader files' sole purpose is to find the encrypted worm, decrypt it, copy it to the system folder and execute it. In order to hide itself the encrypted worm is not stored as a regular file on the disk. Instead, the worm requests raw access to the disk and writes data directly to the disk, not to a file. This method of writing does not require a file name to be used, it only requires an offset on disk and the data to place at that offset. As shown below the worm is using CreateFileA but the file name used is not in the typical format. Using the filename \\?\E: opens the entire disk as if it were one file.

Writing to the disk in this way means that the encrypted worm cannot be accessed by filename because it had no filename to begin with. The only way the encrypted worm can be accessed is by knowing the exact location on the disk where it is stored and exactly how much data is stored at that location.
The loader file that will decrypt and execute the worm must contain this information in order to find the worm. Each loader file must also contain the three keys required to decrypt the worm. This information changes every time the worm is executed, so each loader file is slightly different from the last. Shown below is a comparison between two loader files created during testing. The only difference between them is the location of the worm on disk, the decryption keys used and the checksum.
The problem with this way of writing to the disk is that the OS does not know that there is data stored at that location. Therefore, the next time the OS writes to the disk it could overwrite the stored data since the OS has no knowledge of it. To prevent this from happening the worm marks each cluster that was used to store the worm with the "corrupted/reserved" flag in the File Allocation Table. Now when the OS tries to write a file to the disk, it will skip those bad clusters leaving the encrypted data intact. Shown below is the loop to modify the File Allocation Table. To set a cluster to "corrupt/reserved" the flag 0xFFF7 is used.
Although the worm is using this trick to hide itself, it still needs an autorun.inf file and a loader file in order in start automatically. This is not a sophisticated approach but it does have some advantages. One is that the loader file is very small and can be changed very easily by the worm's author if it becomes detected. Another is that if the user suspects that the loader file is malicious and submits it for analysis, the analysts will only see that it reads some data from a specific offset on disk and copies it to the system folder. The actual worm code itself would be harder for the user to extract from the disk.
The following image shows the state of the disk after the worm has infected it. The disk had been freshly formatted before infection and had no files on the disk and no corrupted sectors. After infection, as can be seen below, the disk contains three files (e:\autorun.inf and e:\Recycled\ and e:\Recycled\L.exe) which in total occupy 32,768 bytes on disk. The image also shows 481,280 bytes in bad sectors -- this is the space reserved for the encrypted worm.

Although the worm is using some advanced techniques it does have some defects in the way it works; some of the defects that may affect users are shown below. Evidence of the first defect of the worm can actually be seen in the previous image. In the previous image the size of the bad sectors is 481,280 bytes. Therefore, we expect the worm executable to be around 481,280 bytes in size as well; however, the worm executable is in fact 96,256 bytes in size.
Since the worm only marks the clusters/sectors[2] that it used to store itself as corrupt, something must be wrong; the worm should not be using 481,280 bytes to store itself. After further analysis, the reason for this discrepancy was uncovered. The author of the worm made a mistake in the code. The mistake is that the worm first tries to write itself to disk and afterwards marks the clusters as corrupted. The problem is that the worm does not check if the write was successful or not. Even if the write was unsuccessful the clusters are still marked as corrupted.
The relevant code is shown below. After the Write_Sectors_Fnc is called there is no check to ensure that the write was successful, however the function to set the clusters flags is still called no matter what the outcome was.
After this point in the code the worm tries to write the encrypted worm to disk a second time and the same mistake is made. In all, the worm continues this process five times until the device is infected correctly. This means that 5 * 96,256 bytes are actually marked as corrupted during infection. A little maths shows us that 5 * 96,256 = 481,280; the size of the bad sectors we noticed above after infection. Due to this mistake the user loses almost half a megabyte of storage space when the disk is infected even though the worm is just under 100Kb.
The second defect of the worm is that it decides whether or not it should infect a device by checking for the presence of an autorun.inf file in the root of the device. This is not the smartest choice and may lead to problems for some users in the following manner:
Let us assume that the user is infected, that the user notices an autorun.inf file on the removable device and that the user deletes this autorun.inf file. In this scenario the worm will still be running from the %system% folder.
When the worm notices that the autorun.inf file is missing, it will try to re-infect the removable device.
The problem is that the worm has no knowledge of previous infections on the removable device since it does not store the encryption keys it used for previous infections. Due to this the worm will mark new clusters as "corrupted" while leaving the old corrupted clusters still in place. This process means that the user loses more storage space on the removable device every time it is infected. The image below highlights this situation.
The image below shows the state of the disk after the second infection. To infect the disk a second time the autorun.inf file was deleted while the worm was still running. Although the size of the hidden executables remains constant, the size of the bad sectors has doubled.

Combining this defect with the previous defect means that every time the device is re-infected the user will lose an additional 481,280 bytes of storage space due to those extra bad sectors. Should a disk lose storage space (as shown above) due to an infection of W32.Joydotto, the lost storage space can be recovered by simply formatting the disk.
This worm is interesting due to the fact that it has revived an old trick that was thought to be dead and buried. Trojan.Mebroot which was discovered recently revived an old school favorite: that of overwriting the MBR. The trick this worm uses was not as popular, but it is still an effective technique for hiding files. The emergence of this worm does show that virus writers are looking to the past and are creating new worms using old and forgotten (but not quite) tricks.
Thanks to Senior Engineer Adam Blaszczyk for his help during this analysis.
[1] The file will be executed automatically only if autorun is enabled in the registry, the default value for autorun is "enabled" if you wish to disable autorun you may do so for all drives or on a drive by drive basis. There are many articles already available elsewhere that show how to do this.
[2] The File allocation table can only mark clusters as corrupt, not sectors, however the worm calculates which clusters contain its sectors, and marks those clusters as corrupted, for this reason the term cluster and sector are interchangeable in reference to being corrupted.


