LNK Parsing: You’re doing it wrong (I)

Recent developments on the malware arena (MS10-046) have raised awareness of LNK files. Due to the nature of the LNKs used by this specific malware I tried to challenge a few members of the forensic community to make them question themselves about what's publicly known of LNKs but it seems I failed miserably.

Instead, I've decided to post what I researched nearly 2 years ago. This is what I found...

An introduction no one cares about

What are LNKs really? For a long time there has been few information about them. I remember at least two papers which were quite useful back in the day, one wrote by the fellow researcher Andrés Tarascó titled Análisis de Estructuras de ficheros LNK ("LNK files Structure Analysis", it's in Spanish), the other I haven't been able to find online anymore but I'd say it was an even earlier reference on the actual format. Only recently Microsoft opened the Microsoft Shell Link Binary File Format.

Microsoft describes it as a "a data object that contains information that can be used to access another data object". What we commonly call a Shortcut. It is a very small file with an "lnk" extension.

At its core the most common type of LNK file has:

  • A Header. Which tells us what kind of information it contains, along with dates relative to the pointed file.
  • An ITEMIDLIST. Which is really an optional field, but is present on almost 99% of the LNKs.
  • A LinkInfo structure. That contains either LocalInfo, which tells us where, relative to our local system, the file can be found. Or a NetworkInfo object. Which is present when the file is to be found by using the network, as in, it's not supposed to be in our computer.

LNKs are also quite easy to spot whenever you come across one as they look like this on-disk:

Once you've looked at a few raw LNK files you will instantly recognize them on the Unallocated space

Having seen the basic layout of the most common LNKs we're ready for the next step. What we're gonna do is we'll create a sample LNK and do a fast analysis. I won't get too technical, no worries.

I recommend you follow the same steps I do so you understand what's happening under the hood in case you get lost.

Setting up the environment

We'll use Didier Stevens recently released 010 Editor LNK Template for the 010 Editor program.

  1. First we'll create 2 files on our desktop called "goforit.txt" and "hax0red.txt"
  2. We'll make it a bit more dramatic by putting a "duh" as the contents of the first file, and "PWNT!!!!!!1!!11 one one" for the second.
  3. You know what? We'll set Notepad's default font to Comic Sans 32 too.

Got it? Cool.

Files needed on your desktop

Next, we'll create a shortcut to the "goforit.txt" file via Drag with the right-mouse button > Drop > Create Shortcuts here. This will make it get named "Shortcut to goforit.txt.lnk" right? Well, you won't see the extension no matter what, but no worries.

The shortcut to goforit.txt

Then we'll open cmd.exe and create a copy of this LNK with a diferent extension so that we can view it. We'll call it "Shortcut to goforit.txt.lnl" instead.

This is one of the multiple ways of doing it. Don't forget to "cd Desktop" first!

OK, open 010 Editor and apply the LNK Template to this file. You'll see something like this (minus the fancy colors and maybe some structure name).

010 Editor with a slightly modified LNK Template

This link has a Header with a populated ITEMIDLIST, some LinkInfo which in this case points to a Local File plus some extra information we won't care about. It seems a fairly standard LNK file to me.

Now take your time to parse it with the LNK Parser of your choice. I'm gonna use EnCase's LNK parser as it's what I have available that most of you might have as well. Whatever tool you use you'll probably get the following information, if not less:

Link File: Shortcut to goforit.txt.lnk
Full Path: Case 1\Single Files\Shortcut to goforit.txt.lnk
Offset: 0
Size: 455
File Attributes: ARCHIVE
Show Window Value: SW_NORMAL_WT
Created Date: 09/08/10 22:37:28
Last Written Date: 09/08/10 22:37:43
Last Accessed Date: 09/08/10 22:37:28
Volume Label: C
Media Type: Fixed
Volume Serial: 14 2D 33 67
File Length: 3
Icon File Name:
Command Line:
Base Path: C:\Documents and Settings\nnnn\Desktop\goforit.txt
Application Path:
Working Directory: C:\Documents and Settings\nnnn\Desktop
Share Name:
Mapped Drive Letter:

Everything looks good, right? Great, this LNK is gonna be our baseline.

What no one told you

Let's focus a on the actual data contained in the LNK. In particular on data redundancy. How many times does the filename "goforit.txt" appear? A whopping 4.

  • Twice on the ITEMIDLIST. One is ASCII encoded, the other Unicode.
  • Once as the LocalBasePath of the LinkInfo structure.
  • Once as the RelativePath

These are the 4 times "goforit.txt" appears

So, do you know where does your LNK parser get the information to obtain the file path it reports? Actually, do you know where it doesn't?

The usual algorithm used to resolve the actual path given a LNK file of a post-mortem system goes like this:

  • If the LNK has a Local target, the local path is the LocalBasePath member of the LinkInfo structure.
  • If the LNK has a Network target, the network path is the NetworkSharePath + RemainingPath if present of the LinkInfo structure. (Note: "+" means to concatenate )
  • If RelativePath and WorkingDirectory are present, WorkingDirectory + RelativePath might give you the filename. (Note: I don't remember seeing this case alone in the wild, but it can happen and it DOES work. And yes, I mean ONLY having these)

This covers 2 of the 4 references we've got. What happens with the data in the ITEMIDLIST? It's skipped.

Why? Well, it seems noone cares about it. Probably because it's such an opaque data field. The official Microsoft Shell Link Binary File Format doesn't shed light on how to interpret its contents, nor does any other source of public information about the LNK file format that I know of.

Why care then? After all we're getting the right information from the other fields.

Or are we? Smile

Let's manipulate our LNK. We're gonna change the strings on the ITEMIDLIST member of the LNK file to point to "hax0red.txt" instead of "goforit.txt" and we'll run the resulting LNK.

We'll start by going into INSERT MODE on 010 Editor (press the Insert key) and modify the data. It HAS to look like this: modify the data, don't add a single byte if you don't know what you're doing.

Evil bytes }:-[

Now save it, create a copy and change the "lnl" extension to "lnk".

And run it Smile

oh noes!!!1!!1 one

Uh oh... Wait wait... This has to be wrong. Let's run it through our LNK parser again...

Link File: Copy of Shortcut to goforit.txt.lnk
Full Path: Case 1\Single Files\Copy of Shortcut to goforit.txt.lnk
Base Path: C:\Documents and Settings\nnnn\Desktop\goforit.txt

:fuuu: Let's see what EnCase gives us on the Symbolic Link column for the Entry Table.


:fuuu: Now let's check the properties of the LNK on our Live System.

How Windows interprets our LNK file

So what's going on here? Well, you just saw it: Windows gives priority to the ITEMIDLIST information when resolving LNKs, so whatever is in the ITEMIDLIST prevails for path resolution no matter what the other data fields say.

At this point you might be thinking:

But it still says "C:\Documents and Settings\nnnn\" on the File Properties and that string certainly isn't on the ITEMIDLIST so it must be getting it from the information I am already fetching with my parser!

Well spotted Mr.Eagle. But, trust me, it is NOT getting this information from the data fields on the LNK. Yeah, surprise.

This ITEMIDLIST has only 1 element and it contains no reference to the folders themselves, only the file.

Let's do one more test in case you don't believe me. Let's modify both places of the LNK where it says "nnnn" (my test user) to try to make it point to the file "hax0red.txt" from user "kkkk" instead.

DIY folder modding

Now save it and get its properties.


Wat's dis magic?

It is surprising but there's an explanation to it. And the explanation is exactly what the ITEMIDLIST is about.

The data the ITEMIDLIST contains is not defined anywhere because only whoever handles its data knows how to treat it. It is the whole point of an ITEMIDLIST, to be a neutral storage of sorts.

The main handler for LNK files is made so that it can pass the resolve-and-execute duties to other handlers in case there's the need. To be more precise, in case it's specified. This LNK we created specifies no handler and is treated as a kind of default case. And in that case the filename it refers to is relative to the Desktop of the user currently opening the LNK.

Again, if you don't believe me: copy this LNK file anywhere on the filesystem, log in as another user and click on Properties. In my case I used user "IIIIIIII" and the LNK itself was on the C root. These are my properties:


There's a lot more to the ITEMIDLIST contents which I'll try to cover in detail in one or more blog posts. Of particular interest will be how a different handler is specified and how to interpret data for each of the most common handlers.

Wrapping up

I've shown you which data is actually used by Windows for resolving LNK files. As it is data that is currently not being parsed by LNK parsing tools, you're not getting the whole picture. Used in an evil way it's a way of concealing the real target of an LNK to the eyes of the average forensic investigator. I guess you could call it an anti-forensic technique that attacks current tools.

From the half-empty-glass point of view we could put it this way:

Not only you've been looking at half the picture, you've been looking at the bad half thinking it was the good one.

And since, and I think we can all agree here, we use automatic tools to parse LNK files and never check the LNKs themselves by hand one by one we're bound to pass this up.

Now, being more realistic:

Q: What does it mean for forensic investigations? Am I getting wrong information?
A: No. The information you get is definitely there, but in my opinion you were giving it more credit than it really deserves. The information used by Windows regarding the actual target resides on the ITEMIDLIST, mostly.

Q: Is it common that users modify the LNK files this way to cover their tracks? Are there tools to automate this?
: Absolutely not from what I've seen so far. First, it requires knowing it. Second, it requires automation. I have yet to see it in a real case scenario and, as far as I know, there are no tools to automate hiding in plain sight this way.

Q: How does it change what I've been doing so far with LNK files?
A: Not much really. As the information is replicated both in the ITEMIDLIST and the LinkInfo structure, and LinkInfo is the place where you've been getting all the information, you should be safe...mostly. But it's still wrong to assume LinkInfo has the right information as far as resolving goes. What's more, not all LNK files have a LinkInfo structure at all nor they need it. That's why some LNKs, specially after Vista, seem to hold no information to the average LNK parser.

So, did you know this happened with LNKs? Do you like the trick? If you have any question make sure to drop a comment. Thanks!

Comments (7) Trackbacks (1)
  1. Hey wonderful article Smile
    Do you know any classes in Java or AS3 that can parse these files effectively?

    Cheers! Keep up the good work Smile

    • Hey Vikky! I’m glad you liked the article.

      I’m not aware of any Java or ActionScript3 class to parse them, but it shouldn’t be too hard to do one. Besides the ITEMIDLIST contents, the format is documented good enough (check the links in the article). I’d suggest you use Didier Steven’s 010 Editor template as a base if you want to create one yourself. Mostly because 010 Editor is very visual about the file format. And then you could use the directions given in this blog for parsing the contents of specific ITEMIDLIST data.

      I’m not too sure why’d you want to do it in AS3 though Smile

      Feel free to drop a comment/e-mail if you need help.

  2. Thanks a lot for this vivid explanation. I managed to create .lnk files with all the required data from the spec. Well, doesn’t work, because I omit the stupid ITEMIDLIST. The spec says, you can omit it when you (un)set the according bit in the LinkFlags. That’s exactly what I did, but while the created .lnk happily shows the comment and working dir, the target location is missing. ARRRRG! Do you have an idea if there is a way not to use the ITEMIDLIST?

    • Hi Tim!

      You should be able to omit the ITEMIDLIST by unsetting the lowest bit in the flags field of the LNK header. Then Windows will only have the LinkInfo structure to do the resolution. Are you sure your LinkInfo structure is well formatted and that you unset the right bit?

      If everything looks OK and you don’t mind sharing the LNK I can take a look at it.

      • Hi Jordi!

        Sorry I come back that late. I was kinda waiting for an email notification by your CMS. Just came back to post a follow up and I’m glad to see you answered. Sure I can share the LNK. Would you send me your email so I can mail it to you?
        Also I was trying to decipher the ITEMIDLISTSs of shortcuts I have here. They look different from your examples (http://blog.0× But first I’ll have a closer look before I burden you with those.
        If you are interested in Python I have a little project ( going on. This little library can write LNKs according to spec (without ITEMIDLISTS), but they don’t work. And yes, I’m unsetting the first lnk flag.

        Thanks a lot for your help!

        • Hi again Tim!

          No worries, I just installed the e-mail notification on comment approval plugin, so posters should receive notifications from now on. Thanks for reminding me.
          Also, last friday, I put up a small black box in the sidebar with instructions on how to contact me. I understand the LNK you have a problem with is one generated by your library, right?

          I’ll take a look at it this afternoon. And yes, I <3 python Smile

  3. Good Article! I am using linux these days and want to fetch some files from my previous windows partitions. I then sadly find that I used a lot of LNK files. In order to locate my real files, I’m searching for any utilities that can resolve full path from LNK. The following command sequence works for most scenes:
    $strings xxxx.lnk | tail -n2 | head -n1

    Here’s another reference of the format:

    I don’t know if we have other universal solutions, rather than writing our own program according to the format.

Leave a comment


Click to Insert Smiley

SmileBig SmileGrinLaughFrownBig FrownCryNeutralWinkKissRazzChicCoolAngryReally AngryConfusedQuestionThinkingPainShockYesNoLOLSillyBeautyLashesCuteShyBlushKissedIn LoveDroolGiggleSnickerHeh!SmirkWiltWeepIDKStruggleSide FrownDazedHypnotizedSweatEek!Roll EyesSarcasmDisdainSmugMoney MouthFoot in MouthShut MouthQuietShameBeat UpMeanEvil GrinGrit TeethShoutPissed OffReally PissedMad RazzDrunken RazzSickYawnSleepyDanceClapJumpHandshakeHigh FiveHug LeftHug RightKiss BlowKissingByeGo AwayCall MeOn the PhoneSecretMeetingWavingStopTime OutTalk to the HandLoserLyingDOH!Fingers CrossedWaitingSuspenseTremblePrayWorshipStarvingEatVictoryCurseAlienAngelClownCowboyCyclopsDevilDoctorFemale FighterMale FighterMohawkMusicNerdPartyPirateSkywalkerSnowmanSoldierVampireZombie KillerGhostSkeletonBunnyCatCat 2ChickChickenChicken 2CowCow 2DogDog 2DuckGoatHippoKoalaLionMonkeyMonkey 2MousePandaPigPig 2SheepSheep 2ReindeerSnailTigerTurtleBeerDrinkLiquorCoffeeCakePizzaWatermelonBowlPlateCanFemaleMaleHeartBroken HeartRoseDead RosePeaceYin YangUS FlagMoonStarSunCloudyRainThunderUmbrellaRainbowMusic NoteAirplaneCarIslandAnnouncebrbMailCellPhoneCameraFilmTVClockLampSearchCoinsComputerConsolePresentSoccerCloverPumpkinBombHammerKnifeHandcuffsPillPoopCigarette