Skip to content

tinyBigGAMES/MemoryDLL

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

22 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

MemoryDLL
Chat on Discord Follow on Bluesky

In-Memory Win64 DLL Loading & Execution for Pascal πŸ’»πŸ”„

Overview πŸ“

The MemoryDLL unit provides advanced functionality for loading dynamic-link libraries (DLLs) directly from memory in Win64 environments. Unlike traditional methods that involve loading DLLs from the file system, MemoryDLL allows you to load DLLs from byte arrays πŸ“‚ or memory streams πŸ’Ύ, retrieve function addresses, and unload themβ€”all in-memory. This library is ideal for Delphi/FreePascal developers who need to manage DLLs without relying on the filesystem, enhancing both performance ⚑ and security πŸ”’.

Features ✨

  • MemoryLoadLibrary: Loads a DLL from a memory buffer without writing to the disk πŸ’½.
  • FreeLibrary: Unloads the DLL from memory, ensuring all associated resources are properly released πŸ”„.
  • GetProcAddress: Retrieves the address of an exported function within the loaded DLL, enabling direct function calls πŸ“ž.
  • Comprehensive Error Handling: Manages issues such as invalid DLL data 🚫, memory allocation failures 🚨, and function resolution issues πŸ”§.

Key Benefits 🌟

  • Increased Security πŸ”’: By eliminating the need to store DLLs on disk, MemoryDLL reduces the risk of DLL hijacking and unauthorized access.
  • Performance Improvement ⚑: Since DLLs are handled in-memory, the overhead of disk I/O operations is avoided, resulting in faster execution πŸš€.
  • Flexibility 🀹: Suitable for embedding DLLs in the main executable, loading encrypted πŸ” or obfuscated DLLs, and supporting dynamic plugin systems where plugins are provided as in-memory modules.

Implementation Details πŸ”

MemoryDLL enables in-memory DLL loading and redirection by using placeholder DLLs and hook-based loading to bypass traditional file-based DLL loading:

  1. Hook-Based Loading πŸš€: Redirects calls to load a specific DLL by monitoring attempts to load a placeholder DLL (e.g., advapi32res.dll). This DLL acts as a trigger for the hook to intercept and handle redirection to an in-memory DLL.
  2. Placeholder DLL πŸ“‚: The placeholder DLL, which can be any specified DLL file, is not embedded within the application. It is only used to initiate the hook process, allowing seamless redirection to the in-memory DLL.
  3. In-Memory Execution βš™οΈ: The redirected DLL operates fully in memory, making all its functions accessible as if loaded conventionally. This approach avoids dependence on the filesystem, enhancing both performance and security.

Compatibility 🀝: The MemoryDLL unit is compatible with standard DLL interfaces, allowing for easy integration with existing applications. The in-memory redirection method also reduces security risks, such as code injection πŸ’‰, offering a secure alternative for DLL management.

Usage Scenarios 🎯

Embedding DLLs πŸ“¦

  • Embed DLLs directly within your executable. MemoryDLL allows you to store DLLs as resources or encrypted data and load them into memory at runtime, removing the need to distribute them as separate files.

Encrypted DLL Loading πŸ”

  • Enhance application security by storing DLLs in an encrypted form, which can then be decrypted into memory before loading with MemoryDLL. This reduces the risk of reverse engineering.

Dynamic Plugin Systems πŸ”Œ

  • Load plugins dynamically as in-memory DLLs. This approach provides a clean and secure method of extending application functionality without relying on the filesystem.

Public Functions πŸ“–

MemoryLoadLibrary πŸ“œ

Loads a module from a memory image, mimicking the behavior of the Windows API LoadLibrary function. It parses the PE format, performs necessary relocations, resolves imports, and initializes the module.

  • Parameters: Data: Pointer – A pointer to the memory image conforming to the PE format.
  • Returns: THandle representing the loaded module or 0 on failure.

Installation πŸ› οΈ

To successfully integrate MemoryDLL into your project, please follow these steps:

  1. Download the Latest Version πŸ“₯

    • Visit the official MemoryDLL repository and download the latest release.
  2. Unzip the Package πŸ“‚

    • Once the download is complete, extract the contents of the zip file to a convenient location on your device's filesystem. The extracted folder should contain the MemoryDLL source code, documentation, and any necessary dependencies.
  3. Add MemoryDLL to Your Project βž•

    • Add MemoryDLL to your project's uses section. This inclusion will make the MemoryDLL unit available for use in your application. Ensure that the path to the MemoryDLL source file is correctly configured in your project settings to avoid compilation errors.
  4. Seamless Integration with Windows API Compatibility πŸ”„

    • The MemoryDLL unit allows for easy integration by providing MemoryLoadLibrary to load DLLs directly from memory. Once loaded, standard Windows API calls such as FreeLibrary and GetProcAddress can be used to manage the in-memory DLL as if it were loaded from the filesystem. This design ensures minimal changes to existing code, maintaining compatibility with Windows API conventions while enabling efficient in-memory DLL handling.
  5. Test the Integration βœ…

    • It is recommended to thoroughly test your project after integrating MemoryDLL to ensure that all DLLs are being correctly loaded, utilized, and unloaded from memory. Given the in-memory nature of this library, testing will help identify any potential issues related to memory management or function resolution.
    • Created/tested with Delphi 12.2, on Windows 11, 64-bit (version 23H2)

πŸ“– Example Usage

To instantiate MemoryDLL, include the following code at the end of the unit’s implementation section. This code attempts to load the DLL as an embedded resource:

uses
  Windows,
  MemoryDLL;  
  
...

implementation

{
  This code is an example of using MemoryDLL to load an embedded a DLL directly
  from an embedded resource in memory, ensuring that no filesystem access is
  required. It includes methods for loading, initializing, and unloading the
  DLL. The DLL is loaded from a resource with a GUID name, providing a measure
  of security by obfuscating the resource’s identity.

  Variables:
    - DLLHandle: THandle
        - A handle to the loaded DLL. Initialized to 0, indicating the DLL has
          not been loaded. It is updated with the handle returned from
          LoadLibrary when the DLL is successfullyloaded from memory.

  Functions:
    - LoadDLL: Boolean
        - Loads the DLL from an embedded resource and initializes it by
          retrieving necessary exported functions. Returns True if the DLL is
          loaded successfully, otherwise False.

    - b6eb28fd6ebe48359ef93aef774b78d1: string
        - A GUID-named helper function that returns the resource name for the DLL.
          This GUID-like name helps avoid easy detection of the resource.

    - UnloadDLL: procedure
        - Unloads the DLL by freeing the library associated with DLLHandle. Resets
          DLLHandle to 0 to indicate the DLL is unloaded.

  Initialization:
    - The LoadDLL function is called during initialization, and the program will
      terminate with code 1 if the DLL fails to load.

  Finalization:
    - The UnloadDLL procedure is called upon finalization, ensuring the DLL is
      unloaded before program termination.

}

var
  DLLHandle: THandle = 0; // Global handle to the loaded DLL, 0 when not loaded.

{
  LoadDLL
  --------
  Attempts to load a DLL directly from a resource embedded within the executable
  file. This DLL is expected to be stored as an RCDATA resource under a specific
  GUID-like name.

  Returns:
    Boolean - True if the DLL is successfully loaded, False otherwise.
}
function LoadDLL(): Boolean;
var
  LResStream: TResourceStream; // Stream to access the DLL data stored in the
  resource.

  {
    b6eb28fd6ebe48359ef93aef774b78d1
    ---------------------------------
    Returns the name of the embedded DLL resource. Uses a GUID-like name for
    obfuscation.

    Returns:
      string - The name of the resource containing the DLL data.
  }
  function b6eb28fd6ebe48359ef93aef774b78d1(): string;
  const
    // GUID-like resource name for the embedded DLL.
    CValue = 'b87deef5bbfd43c3a07379e26f4dec9b'; 
  begin
    Result := CValue;
  end;

begin
  Result := False;

  // Check if the DLL is already loaded.
  if DLLHandle <> 0 then Exit;

  // Ensure the DLL resource exists.
  if not Boolean((FindResource(HInstance,
    PChar(b6eb28fd6ebe48359ef93aef774b78d1()), RT_RCDATA) <> 0)) then Exit;

  // Create a stream for the DLL resource data.
  LResStream := TResourceStream.Create(HInstance,
    b6eb28fd6ebe48359ef93aef774b78d1(), RT_RCDATA);

  try
    // Attempt to load the DLL from the resource stream.
    DLLHandle := MemoryLoadLibrary(LResStream.Memory);
    if DLLHandle = 0 then Exit; // Loading failed.

    // Retrieve and initialize any necessary function exports from the DLL.
    GetExports(DLLHandle);

    Result := True; // Successful load and initialization.
  finally
    LResStream.Free(); // Release the resource stream.
  end;
end;

{
  UnloadDLL
  ---------
  Frees the loaded DLL, releasing any resources associated with DLLHandle,
  and resets DLLHandle to 0.
}
procedure UnloadDLL();
begin
  if DLLHandle <> 0 then
  begin
    FreeLibrary(DLLHandle); // Unload the DLL.
    DLLHandle := 0; // Reset DLLHandle to indicate the DLL is no longer loaded.
  end;
end;

initialization
  // Attempt to load the DLL upon program startup. Halt execution with error
  // code 1 if it fails.
  if not LoadDLL() then
  begin
    Halt(1);
  end;

finalization
  // Ensure the DLL is unloaded upon program termination.
  UnloadDLL();

Acknowledgments πŸ™

This unit is based on the original MemoryDll-DllRedirect project by A-Normal-User. We gratefully acknowledge the foundational work that this unit builds upon.

License πŸ“œ

This project is licensed under the BSD-3-Clause License πŸ“ƒ, which allows for redistribution and use in source and binary forms, with or without modification, provided that certain conditions are met. It strikes a balance between permissiveness and protecting the rights of contributors.

How to Contribute 🀝

Contributions to MemoryDLL are highly encouraged. Please feel free to submit issues, suggest new features, or create pull requests to expand its capabilities and robustness.

Support πŸ“§

Delphi

Made with ❀️ in Delphi