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.

Sprzętowy identyfikator w C#

Sprzętowy identyfikator komputera

Krótki snippet w C# dla .NET 4 (jak skorygowali mnie koledzy, zadziała także od .NET 2) pobierający sprzętowy identyfikator maszyny, wykorzystując interfejs WMI, podobne algorytmy stosowane są w aplikacjach, których klucze licencyjne przypisywane są do jednego komputera

using System.Management;
using System.Security.Cryptography;

/// 
/// pobiera sprzętowy identyfikator maszyny korzystając z interfejsu WMI
/// 
/// identyfikator sprzętowy w formie hasha SHA1
public static String hardwareId()
{
    // tymczasowy string
    String tempString = "";

    // "baza danych", z której pobieramy informacje o systemie
    String wmiScope = @"root\CIMV2";

    // tabela zapytań WMI i pobieranych elementów
    String[,] wmiQueries = new String[,]
    {
        { "SELECT ProcessorId FROM Win32_Processor", "ProcessorId" },
        { "SELECT Caption FROM Win32_Processor", "Caption" },
        { "SELECT Manufacturer FROM Win32_Processor", "Manufacturer" },
        { "SELECT Caption FROM Win32_BIOS", "Caption" }
    };

    // wywołujemy kolejne zapytania WMI
    for (int i = 0; i < wmiQueries.GetLength(0); i++)
    {
        try
        {
            // wykonaj zapytanie WMI
            ManagementObjectSearcher searcher = new ManagementObjectSearcher(wmiScope, wmiQueries[i, 0]);

            // zbuduj string z kolejnymi elementami odpowiedzi po zapytaniach WMI
            foreach (ManagementObject obj in searcher.Get())
            {
                tempString += obj[wmiQueries[i, 1]].ToString();
            }
        }
        catch (ManagementException exception)
        {
            // loguj błąd odczytu danych z WMI
        }
    }

    // generuj hash SHA1 ze wszystkich zebranych danych WMI
    SHA1 hash = SHA1CryptoServiceProvider.Create();

    // ciąg znaków zamień na tablicę bajtów
    byte[] plainTextBytes = Encoding.ASCII.GetBytes(tempString);

    // oblicz hash SHA1
    byte[] hashBytes = hash.ComputeHash(plainTextBytes);

    // konwertuj hash SHA1 na postać tekstową (i usuń zbędne znaki "-")
    tempString = BitConverter.ToString(hashBytes).Replace("-", "");

    return tempString;
}

Więcej o WMI na CodeProject:
http://www.codeproject.com/KB/system/WQLByExample.aspx

Exe protector za 50 PLN

Czasami dostaje różne propozycje współpracy czy napisania jakiegoś programu, jednak głupota niektórych ludzi jest aż zabawna (przykro to stwierdzić, ale rodacy przodują w tego typu rzeczach), niedawno otrzymałem intratną propozycję stworzenia prostego exe-protectora w assemblerze, z komentarzami etc., do pracy inżynierskiej dla jednego czuczona.

Jako, że nie chciało mu się szukać niczego w sieci, zaproponowałem mu 400 PLN, gdyż taki prosty template posiadam w swojej kolekcji, jest przetestowany, sprawny, kompatybilny i oto jak potoczyła się dalsza dyskusja:

Czuczon: Ty mi proponowałeś protektor za 400zł
Czuczon: kolega mi proponuje za 50zł

Czuczon: ile byś za to chciał? z przekazaniem praw autorskich, zebym to mogl uzyc jako pracy inżynierskiej
Ja: 400 PLN
Czuczon: przesadzasz z tą ceną
Ja: to napisz sam
Ja: to proste
Czuczon: kolega mi dał źródła protektora co szyfruje AES’em, ale to za trudne do ogarnięcia, nie rozumiem tego kodu :/
Czuczon: a wiesz może jak trzeba przerobić kod, żeby nie był plagiatem?
Ja: wiem
Ja: trzeba go solidnie pozmieniac na tak samo dzialajace instrukcje i funkcje
Czuczon: czyli np. przepisanie go na inny język programowania wystarczy?
Czuczon: mówie o C++ -> Asm
Ja: no jak ci sie uda
Czuczon: troche problem bo na klasach pisany, prawie 100% obiektowo

Dyskusja na tym się zakończyła, gdyż nie byłem w stanie zaproponować bardziej konkurencyjnej ceny do 50 PLN :). Tak szczerze mówiąc to nie wiem co tacy ludzie myślą, że takie rzeczy na drzewie rosną i że to pisze się z buta i jeszcze ma wszystko działać, a nie zdają sobie sprawy ile wiedzy w to zostało włożone, czasu na napisanie, na przetestowanie na różnych OS-ach, nawet takiego głupiego exe-protectora doh!

Jeśli mieliście podobne przypadki równie intratnych zleceń, napiszcie w komentach, pośmiejemy się razem 🙂

Nietypowy problem w drzewie genealogicznym

Wycieki pamięci, zawieszanie programu, problemy z kompatybilnością są niczym wobec prawdziwych, życiowych problemów, z którymi muszą borykać się programiści! Znalezione na StackOverflow.com:

Jestem programistą pewnego oprogramowania do tworzenia drzew genealogicznych (napisany w C++ i Qt). Nie miałem żadnych problemów, aż jeden z moich klientów wysłał na skrzynkę pocztową raport z błędem. Problem polega na tym, że ma dwoje dzieci z własną córką i nie może użyć mojego programu z powodu tego błędu.

Te błędy są wynikiem moich różnorakich założeń dotyczących funkcjonowania drzewa genealogicznego (przykładowo, po przejściu cyklu, program zakłada, że X nie może być jednocześnie ojcem i dziadkiem Y).

Jak mogą rozwiązać te problemy bez usuwania wszystkich założeń dotyczących funkcjonowania drzewa genealogicznego?

Jak wy byście rozwiązali ten problem?

Jak oddać głos w PHP

Prosty skrypt, który zrobiłem dla znajomego, pozwalający automatycznie oddać głos w ankiecie (może to nie za bardzo etyczne, ale kogo to obchodzi).

Przykładowa forma głosowania (update, dzięki Tomek) wygląda tak:



Forma zawiera 3 ukryte pola (może to być np. identyfikator głosowania) oraz button Submit, należy również zwrócić uwagę na sposób przesyłania danych, tzn. POST lub GET. Skrypt do głosowania:

 urlencode('param 1 value'),
                'param2' => urlencode('param 2 value'),
                'param3' => urlencode('param 3 value'),
                'submit' => urlencode('Submit vote')
        );

// zbuduj poprawny ciag dla cURL
foreach($fields as $key => $value)
{
        $fields_string .= $key.'='.$value.'&';
}

rtrim($fields_string, '&');

$ch = curl_init();

// adres strony
curl_setopt($ch, CURLOPT_URL, $url);

// ilosc parametrow
curl_setopt($ch, CURLOPT_POST, count($fields));

// parametry POST
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string);

// przegladarka
curl_setopt($ch, CURLOPT_USERAGENT, array_rand($agents));

// zwroc tylko wynik
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$result = curl_exec($ch);

curl_close($ch);

// wyswietl wynikowy kod html
//echo $result;

?>

Skrypt wymaga zainstalowanej biblioteki cURL.

Ile kodu napisałeś?

Jeśli jesteś ciekawy ile linijek kodu napisałeś, a ile jest w nich komentarzy, w twoim projekcie, który wydaje Ci się duży, możesz to łatwo sprawdzić i pozbyć się wszelkich złudzeń 🙂

CLOC (Count Lines of Code) to program, który dokładnie analizuje pliki źródłowe w kilkudziesięciu językach programowania, pokazująć ile tak naprawdę jest samego kodu w kodzie 😉

http://cloc.sourceforge.net