EXE Packer dla .NET

.netshrink v2.3

.netshrink to kompresor (tzw. exe-packer) aplikacji .NET-owych, wykorzystujący kompresję LZMA

.netshrink v2.3

.netshrink to także DLL binder pozwalający scalić aplikację oraz jej dodatkowe moduły DLL do jednego pliku EXE:

.netshrink DLL binder

Ostatnie zmiany:

v2.3

  • dodana obsługa plików projektów
  • dodana lista lokalnie zapisanych haseł
  • usunięto błędy obsługi 64 bitowych aplikacji

v2.2

  • zachowywanie oryginalnej architektury CPU w skompresowanych plikach
  • poprawione uruchamianie assemblies ze ścieżek UNC (udziały sieciowe)

Strona domowa:
https://www.pelock.com/products/netshrink

Wersje demonstracyjną można ściągnąć z:

Setup:
https://www.pelock.com/download/netshrink.exe (713 kB)

Archiwum zip:
https://www.pelock.com/download/netshrink.zip (427 kB)

Kompresja aplikacji .NET

.netshrink v2.2

.netshrink to kompresor (tzw. exe-packer) aplikacji .NET-owych, wykorzystujący kompresję LZMA, DLL binder pozwalający scalić aplikację oraz jej dodatkowe moduły DLL do jednego pliku EXE, .netshrink pozwala także na ochronę aplikacji na hasło przed uruchomieniem.

W zaktualizowanej wersji poprawione zostało uruchamianie skompresowanych aplikacji ze ścieżek UNC (zasoby sieciowe) z linii komend i zachowywanie oryginalnej architektury CPU dla skompresowanych plików.

Strona domowa:
https://www.pelock.com/products/netshrink

Wersje demonstracyjną można ściągnąć z:

Setup:
https://www.pelock.com/download/netshrink.exe (701 kB)

Archiwum zip:
https://www.pelock.com/download/netshrink.exe (415 kB)

.netshrink v2.1 – kompresor i DLL binder dla aplikacji .NET

.netshrink v2.1

Właśnie ukazała się nowa wersja mojego małego narzędzia do kompresji aplikacji .NET.

.netshrink to kompresor (tzw. exe-packer)  aplikacji .NET-owych, wykorzystujący kompresję LZMA.

DLL Binder

W nowej wersji została dodana opcja dołączania bibliotek dynamicznych DLL do aplikacji, dzięki czemu można swoją aplikację i jej pomocnicze biblioteki skompresować do pojedynczego pliku wykonywalnego.

Wykrywanie narzędzi do łamania aplikacji

Zaktualizowana wersja pozwala również skompresowanym aplikacjom na wykrywanie popularnych narzędzi do łamania i rozpakowywania oprogramowania poprzez stałe monitorowanie systemu na ich obecność, w razie ich wykrycia, skompresowana aplikacja zostanie zamknięta.

Ochrona na hasło

.netshrink pozwala także na zaszyfrowanie aplikacji hasłem, bez poprawnego hasła nie można uruchomić skompresowanej aplikacji. Zabezpieczenie na hasło wykorzystuje weryfikację bazującą na funkcji skrótu SHA256 i szyfrowanie danych algorytmem AES / Rijndael z kluczem 256 bitowym bazującym na wartości hash z hasła.

.netshrink kompresor i DLL binder dla aplikacji .NET

Nowości obejmują także:

  • tworzenie kopii zapasowej kompresowanych aplikacji
  • tworzenie skryptu wsadowego .BAT pozwalającego na szybkie przywrócenie oryginalnego pliku z kopii zapasowej
  • zachowywanie oryginalnych atrybutów kompresowanego assembly (nazwa aplikacji, dane firmy etc.)

Strona domowa:
https://www.pelock.com/products/netshrink

Wersje demonstracyjną można ściągnąć z:

Setup:
https://www.pelock.com/download/netshrink.exe (692 kB)

Archiwum zip:
https://www.pelock.com/download/netshrink.exe (405 kB)

Patcher dla C#

Czekałem na koniec świata, ale jakoś go nie było, tymczasem mała klasa w C# do patchowania plików z paroma przydatnymi opcjami jak np. patchowanie stringow Delphi.

using System;
////////////////////////////////////////////////////////////////////////////////
//
// Simple C# Patcher Class for Windows (Complex)
//
// You can patch:
//
// - byte arrays
// - single bytes
// - integers
// - strings
// - delphi strings
//
// Language : C#
// Author   : Bartosz Wójcik
// Website  : https://www.pelock.com
//
////////////////////////////////////////////////////////////////////////////////

using System;
using System.IO;
using System.Collections.Generic;
using System.Text;

namespace NetPatcher
{
    class Patcher
    {
        public FileStream inputFile;

        public Patcher()
        {
        }

        ~Patcher()
        {
            CloseFile();
        }

        public bool OpenFile(string filePath)
        {
            try
            {
                inputFile = new FileStream(filePath, FileMode.Open, FileAccess.ReadWrite);

                return inputFile == null ? false : true;
            }
            catch (Exception e)
            {
                return false;
            }

            return false;
        }

        public void CloseFile()
        {
            if (inputFile != null)
            {
                inputFile.Close();
            }

            inputFile = null;
        }

        public long PatchArray(long fileOffset, byte[] patchBytes)
        {
            inputFile.Seek(fileOffset, SeekOrigin.Begin);
            inputFile.Write(patchBytes, 0, patchBytes.Length);

            return inputFile.Position;
        }

        public long PatchByte(long fileOffset, byte patchByte)
        {
            inputFile.Seek(fileOffset, SeekOrigin.Begin);
            inputFile.WriteByte(patchByte);

            return inputFile.Position;
        }

        public long PatchString(long fileOffset, string patchString)
        {
            System.Text.Encoding asciiEncoding = System.Text.Encoding.ASCII;
            byte[] encodedPatchString = asciiEncoding.GetBytes(patchString);

            return PatchArray(fileOffset, encodedPatchString);
        }

        public long PatchDelphiString(long fileOffset, string patchString)
        {
            System.Text.Encoding asciiEncoding = System.Text.Encoding.GetEncoding(1250);
            
            byte[] encodedPatchString = asciiEncoding.GetBytes(patchString);

            PatchByte(fileOffset, (byte)encodedPatchString.Length);
            PatchArray(fileOffset + 1, encodedPatchString);

            return inputFile.Position;
        }

        public long PatchInt32(long fileOffset, Int32 patchInt32)
        {
            byte[] encodedInt32 = BitConverter.GetBytes(patchInt32);
            PatchArray(fileOffset, encodedInt32);

            return inputFile.Position;
        }

        public long PatchFill(long fileOffset, long Length, byte patchByteFill)
        {
            while (Length-- != 0)
            {
                PatchByte(fileOffset++, patchByteFill);
            }

            return inputFile.Position;
        }

    }
}

Źródła dostępne także na https://github.com/PELock/Simple-DotNet-Patcher-Class

Wykrywanie VMware w C#

Jak wykryć VMware

VMware jest często wykorzystywane w celu uruchamiania złamanego oprogramowania lub aby ominąć zabezpieczenia autora oprogramowania.

Często to wygląda tak, że kupujący po zakupie oprogramowania otrzymuje licencję zablokowaną na sprzętowy identyfikator jednego komputera, który okazuje się być obrazem VMware i tak później oprogramowanie jest dystrybuowane (czytaj sprzedawane) dalej.

Wersji natywnych, wykorzystujących systemowe różnice w działaniu na wykrywanie VMware są dziesiątki, chciałem przedstawić krótki snippet w C# do wykrywania może nie samego VMware, ale narzędzi VMware Tools, które instaluje się na wirtualnej maszynie, aby zapewnić komfortową pracę między wirtualną maszyną, a maszyną użytkownika (np. zapewnić funkcje drag&drop plików etc.), jest to zwykle jedna z pierwszych czynności jakie robi się po zainstalowaniu systemu na wirtualnej maszynie.

using System;
using System.Runtime.InteropServices;

// potrzebne importy
[DllImport("KERNEL32.dll", SetLastError=true)]
static extern IntPtr OpenEvent(uint dwDesiredAccess, bool bInheritHandle, string lpName);

[DllImport("KERNEL32.dll", SetLastError=true)]
static extern IntPtr CreateMutex(IntPtr lpMutexAttributes, bool bInitialOwner, string lpName);

[DllImport("KERNEL32.dll")]
private extern static Boolean CloseHandle(IntPtr handle);

public const int ERROR_ALREADY_EXISTS = 183;

/// 
/// wykrywanie obecności VMWare po zainstalowanych narzędziach VMWare Tools
/// na wirtualnej maszynie
/// 
/// true jeśli wykryto zainstalowane narzędzia VMWare Tools
public static bool IsVMWare()
{
    // otwórz obiekt "VMwareDnDManagerEvent"
    IntPtr eventHandle = OpenEvent(0x001F0003, false, "VMwareDnDManagerEvent");

    // jeśli udało się otworzyć event, to znaczy, że obecne są narzędzia VMWare Tools
    if (eventHandle != IntPtr.Zero)
    {
        CloseHandle(eventHandle);
        return true;
    }

    // utwórz mutex o nazwie wykorzystywanej przez VMWare Tools
    IntPtr mutexHandle = CreateMutex(IntPtr.Zero, false, "VMwareGuestDnDDataMutex");

    // zamknij uchwyt mutexa
    if (mutexHandle != IntPtr.Zero)
    {
        CloseHandle(mutexHandle);
    }

    // jeśli mutex o tej nazwie istnieje, to znaczy, że są obecne narzędzia VMware Tools
    if (Marshal.GetLastWin32Error() == ERROR_ALREADY_EXISTS)
    {
        return true;
    }

    return false;
}

Wykrywanie dotyczy VMware w wersji 7, w wersji 8 należy już zastosować inne nazwy obiektów ze względu na zaktualizowane VMware Tools, jeśli ktoś jest zainteresowany wykrywaniem VMware w najnowszych wersjach (i nie tylko tego środowiska, np. VirtualBox etc.), proszę o kontakt.