SkillAgentSearch skills...

Ressy

Resource editor for PE files

Install / Use

/learn @Tyrrrz/Ressy

README

Ressy

Status Made in Ukraine Build Coverage Version Downloads Discord Fuck Russia

<table> <tr> <td width="99999" align="center">Development of this project is entirely funded by the community. <b><a href="https://tyrrrz.me/donate">Consider donating to support!</a></b></td> </tr> </table> <p align="center"> <img src="favicon.png" alt="Icon" /> </p>

Ressy is a library for managing native resources stored in portable executable images (i.e. EXE and DLL files). It works on Windows, Linux, and macOS by parsing PE files directly, without relying on the Windows API.

Terms of use<sup>[?]</sup>

By using this project or its source code, for any purpose and in any shape or form, you grant your implicit agreement to all the following statements:

  • You condemn Russia and its military aggression against Ukraine
  • You recognize that Russia is an occupant that unlawfully invaded a sovereign state
  • You support Ukraine's territorial integrity, including its claims over temporarily occupied territories of Crimea and Donbas
  • You reject false narratives perpetuated by Russian state propaganda

To learn more about the war and how you can help, click here. Glory to Ukraine! 🇺🇦

Install

  • 📦 NuGet: dotnet add package Ressy

Usage

Ressy's functionality is provided entirely through the PortableExecutable class. You can create an instance of this class by calling PortableExecutable.OpenWrite(...) or PortableExecutable.OpenRead(...) with the path to a PE file.

using Ressy;

using var portableExecutable = PortableExecutable.OpenWrite("some_app.exe");
// -or-
// using var portableExecutable = PortableExecutable.OpenRead("some_app.exe");

// ...

Alternatively, you can also initialize a PortableExecutable from a Stream, which is useful when you need to work on PE files that are not stored on disk:

using Ressy;

using var stream = File.OpenRead("some_app.exe");
using var portableExecutable = new PortableExecutable(stream);

// ...

[!IMPORTANT] When initializing a PortableExecutable from a stream, make sure that the stream supports seeking.

Reading resources

Enumerate resource identifiers

To get the list of resources in a PE file, use the GetResourceIdentifiers() method:

using Ressy;

using var portableExecutable = PortableExecutable.OpenWrite("some_app.exe");
var identifiers = portableExecutable.GetResourceIdentifiers();

Returned list should contain something similiar to this:

- Type: 16 (RT_VERSION), Name: 1, Language: 1033
- Type: 24 (RT_MANIFEST), Name: 1, Language: 1033
- Type: 3 (RT_ICON), Name: 1, Language: 1033
- Type: 3 (RT_ICON), Name: 2, Language: 1033
- Type: 3 (RT_ICON), Name: 3, Language: 1033
- Type: 14 (RT_GROUP_ICON), Name: 2, Language: 1033
- Type: 4 (RT_MENU), Name: 1, Language: 1033
- Type: 5 (RT_DIALOG), Name: 1, Language: 1033
- Type: 5 (RT_DIALOG), Name: 2, Language: 1033
- Type: 5 (RT_DIALOG), Name: 3, Language: 1033
- Type: "MUI", Name: 1, Language: 1033
- ...

Retrieve all resources

To retrieve all resources at once (including their binary data), call the GetResources() method:

using Ressy;

using var portableExecutable = PortableExecutable.OpenWrite("some_app.exe");
var resources = portableExecutable.GetResources();

foreach (var resource in resources)
{
    var identifier = resource.Identifier; // { Type, Name, Language }
    var data = resource.Data; // byte[]
}

Retrieve resource data

To resolve a specific resource, call the GetResource(...) method. This returns an instance of the Resource class that contains the resource data:

using Ressy;

using var portableExecutable = PortableExecutable.OpenWrite("some_app.exe");

var resource = portableExecutable.GetResource(new ResourceIdentifier(
    ResourceType.Manifest,
    ResourceName.FromCode(1),
    new Language(1033)
));

var resourceData = resource.Data; // byte[]
var resourceString = resource.ReadAsString(Encoding.UTF8); // string

If you aren't sure that the requested resource actually exists in the PE file, you can use the TryGetResource(...) method instead. It returns null in case the resource is missing:

using Ressy;

using var portableExecutable = PortableExecutable.OpenWrite("some_app.exe");

var resource = portableExecutable.TryGetResource(new ResourceIdentifier(
    ResourceType.Manifest,
    ResourceName.FromCode(100),
    new Language(1033)
)); // resource is null

Modifying resources

Set resource data

To add or overwrite a resource, call the SetResource(...) method:

using Ressy;

using var portableExecutable = PortableExecutable.OpenWrite("some_app.exe");

portableExecutable.SetResource(new Resource(
    new ResourceIdentifier(
        ResourceType.Manifest,
        ResourceName.FromCode(1),
        new Language(1033)
    ),
    [0x01, 0x02, 0x03]
));

To add or overwrite multiple resources at once, use SetResources(...). When removeOthers is true, all existing resources not in the list are deleted first:

using Ressy;

using var portableExecutable = PortableExecutable.OpenWrite("some_app.exe");

portableExecutable.SetResources(
    [
        new Resource(
            new ResourceIdentifier(ResourceType.Manifest, ResourceName.FromCode(1), new Language(1033)),
            [0x01, 0x02, 0x03]
        ),
        new Resource(
            new ResourceIdentifier(ResourceType.Version, ResourceName.FromCode(1), new Language(1033)),
            [0x04, 0x05, 0x06]
        )
    ],
    removeOthers: true
);

Remove resources

To remove a resource, call the RemoveResource(...) method:

using Ressy;

using var portableExecutable = PortableExecutable.OpenWrite("some_app.exe");

portableExecutable.RemoveResource(
    new ResourceIdentifier(
        ResourceType.Manifest,
        ResourceName.FromCode(1),
        new Language(1033)
    )
);

To remove all resources in a PE file, call the RemoveResources() method:

using Ressy;

using var portableExecutable = PortableExecutable.OpenWrite("some_app.exe");

portableExecutable.RemoveResources();

You can also remove a specific set of resources, or those matching a predicate:

using Ressy;

using var portableExecutable = PortableExecutable.OpenWrite("some_app.exe");

// Remove a specific list of resources
portableExecutable.RemoveResources(
    [
        new ResourceIdentifier(ResourceType.Manifest, ResourceName.FromCode(1), new Language(1033))
    ]
);

// Remove all resources of a specific type
portableExecutable.RemoveResources(id => id.Type == ResourceType.Manifest);

High-level operations

Ressy provides extensions for PortableExecutable that enable you to directly read and manipulate known resource types, such as icons, manifests, versions, etc.

Manifest resources

A manifest resource (type 24) contains XML data that identifies and describes native assemblies that the application should bind to at run time. It may also contain other information, such as application settings, requested execution level, and more.

[!NOTE] To learn more about application manifests, see this article.

Retrieve the manifest

To read the manifest resource as an XML text string, call the GetManifest() extension method:

using Ressy;
using Ressy.Manifests;

using var portableExecutable = PortableExecutable.OpenWrite("some_app.exe");

var manifest = portableExecutable.GetManifest();
// -or-
// var manifest = portableExecutable.TryGetManifest();

[!NOTE] If there are multiple manifest resources, this method retrieves the first one it finds, giving preference to resources with lower ordinal name (ID) and in the neutral language.

Set the manifest

To add or overwrite a manifest resource, call the SetManifest(...) extension method:

using Ressy;
using Ressy.Manifests;

using var portableExecutable = PortableExecutable.OpenWrite("some_app.exe");

portableExecutable.SetManifest("<assembly>...</assembly>");
Remove the manifest

To remove all manifest resources, call the RemoveManifest() extension method:

using Ressy;
using Ressy.Manifests;

using var portableExecutable = PortableExecutable.OpenWrite("some_app.exe");

portableExecutable.RemoveManifest();

Icon resources

Icon resources (type 3) and icon group resources (type 14) are used to visually identify an application within the operating system. Each portable executable file may contain multiple icon resources (usually in different sizes or color configurations), which are grouped together by the corresponding icon group resource.

Set the icon

To add or overwrite icon resources based on an ICO file, call the SetIcon(...) extension method:

using Ressy;
using Ressy.Icons;

using var port
View on GitHub
GitHub Stars69
CategoryDevelopment
Updated5h ago
Forks8

Languages

C#

Security Score

100/100

Audited on Apr 1, 2026

No findings