Code Monkey home page Code Monkey logo

shelk's Introduction

Shelk

Build CI

Shelk is a .NET cross-platform library for parsing Microsoft's Shell Link(.LNK) binary file.

Shell Link Format

Structure Description
SHELL_LINK_HEADER "A ShellLinkHeader structure (section 2.1), which contains identification information, timestamps, and flags that specify the presence of optional structures."
LINK_TARGET_IDLIST "An optional LinkTargetIDList structure (section 2.2), which specifies the target of the link. The presence of this structure is specified by the HasLinkTargetIDList bit (LinkFlags section 2.1.1) in the ShellLinkHeader."
LINKINFO "An optional LinkInfo structure (section 2.3), which specifies information necessary to resolve the link target. The presence of this structure is specified by the HasLinkInfo bit (LinkFlags section 2.1.1) in the ShellLinkHeader."
STRING_DATA "Zero or more optional StringData structures (section 2.4), which are used to convey user interface and path identification information. The presence of these structures is specified by bits (LinkFlags section 2.1.1) in the ShellLinkHeader."
EXTRA_DATA "Zero or more ExtraData structures (section 2.5)."

Design

All non-primitive types should inherit from IShellLinkObject, so that we may retrieve the size in bytes of the object for buffering scenarios.

Example #1

// In this scenario we are serializing 'shellLinkObject' into a file named 'MyShortcut.lnk'.
int size = shellLinkObject.GetSize();
byte[] buffer = ArrayPool<byte>.Shared.Rent(size); // Rent a buffer from the shared buffer pool that can hold at least this many bytes.
if (shellLinkObject.TryFormat(buffer, out int bytesWritten))
{
    using (var fs = new FileStream("MyShortcut.lnk", FileMode.Create))
    {
        fs.Write(buffer, 0, size);
    }
}
// Return the shared buffer back to the pool.
ArrayPool<byte>.Shared.Return(buffer);

Example #2 (TODO: TryFormat not yet implemented)

Socket client = new();
int size = shellLinkObject.GetSize();
using (IMemoryOwner<byte> bufferOwner = MemoryPool<byte>.Shared.Rent(size))
if (shellLinkObject.TryFormat(bufferOwner.Memory.Span, out int bytesWritten))
{
    int bytesSent = await client.SendAsync(bufferOwner.Memory.Slice(0, bytesWritten));
}

Parsing

All the parsing logic is located in the constructor of the type being parsed, but perhaps it may be preferable to move this logic into a static Parse interface method for each type that implements the IShellLinkObject interface. Aside from ShellLink, all other types that inherit from IShellLinkObject have a constructor with this signature:

public _(ref ReadOnlySpan<byte> source)

Using this method we're able to advance the stream by doing something like:

source = source.Slice(4);

It allows us to read primitive values from structure to structure without having to allocate a smaller buffer to pass to another structure for parsing. With the help of the internal static class Primitives, we're able to read a value from the buffer, and advance it at the same time, like so:

  Size = Primitives.Read<uint>(ref source);
  HeaderSize = Primitives.Read<uint>(ref source);
  Flags = Primitives.Read<LinkInfoFlags>(ref source);
  VolumeIDOffset = Primitives.Read<uint>(ref source);
  LocalBasePathOffset = Primitives.Read<uint>(ref source);
  CommonNetworkRelativeLinkOffset = Primitives.Read<uint>(ref source);
  CommonPathSuffixOffset = Primitives.Read<uint>(ref source);

Usage

To parse a Shell Link file we can either pass a byte array, or a path to the file:

var shellLink = new ShellLink("MyShortcut.lnk");
byte[] shellLinkBytes = File.ReadAllBytes("MyShortcut.lnk");
var shellLink = new ShellLink(shellLinkBytes);

Once initialized we can access the properties contained within the file like so:

Console.WriteLine("Attributes: " + shellLink.Header.FileAttributes);
Console.WriteLine("Creation Time: " + shellLink.Header.CreationTime);
Console.WriteLine("Write Time: " + shellLink.Header.WriteTime);
Console.WriteLine("Access Time: " + shellLink.Header.AccessTime);

Console.WriteLine("Name: " + shellLink.Strings.Name);
Console.WriteLine("Relative Path: " + shellLink.Strings.RelativePath);
Console.WriteLine("WorkingDirectory: " + shellLink.Strings.WorkingDirectory);
Console.WriteLine("Command Line Arguments: " + shellLink.Strings.CommandLineArguments);
Console.WriteLine("IconLocation: " + shellLink.Strings.IconLocation);

Will produce something similar to:

Attributes: None
Creation Time: 1/1/1601 12:00:00 AM
Write Time: 1/1/1601 12:00:00 AM
Access Time: 1/1/1601 12:00:00 AM
Name: @%ProgramFiles%\Hyper-V\SnapInAbout.dll,-132
Relative Path:
WorkingDirectory: %ProgramFiles%\Hyper-V\
Command Line Arguments: "%windir%\System32\virtmgmt.msc"
IconLocation: %ProgramFiles%\Hyper-V\SnapInAbout.dll

Demo

This project also contains a command line interface that allows you to pass a file path of a *.lnk file, or a directory containing multiple of them.

Shelk.CLI.exe "C:\MyShortcut.lnk"

At the end of execution it will have generated a dump file in the same folder the application was ran from within a folder called Shell Link Dumps.

Building & Running

To build the project open the command line in the location of the solution(Shelk.sln).

dotnet build Shelk.sln

To run the demo application:

dotnet run --project Shelk.CLI

To run all unit tests:

dotnet test

shelk's People

Contributors

arachish avatar

Stargazers

 avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.