Pomiar entropii Claude’a E. Shannona w teorii informacji
Źródło informacji posiada entropię H, która jest miarą nieprzewidywalności, niepewności, wyboru. [1]
Poniższy wzór pozwala na obliczenie entropii H dyskretnego źródła informacji.
- H – entropia dyskretnego źródła informacji.
- K – stała dodatnia oznaczająca jednostkę miary (przeważnie równa jeden).
- n – liczba możliwych stanów. Np. liczba różnych wartości bajtów w ciągu.
- i – indeks zdarzeń. Przyjmuje wartości od jeden do n w operacji sumowania.
- pi – prawdopodobieństwo wystąpienia zdarzenia o indeksie i. Suma wszystkich prawdopodobieństw powinna wynosić jeden.
- log pi – logarytm o podstawie dwa pozwala wyrazić wynik w bitach.
Wzór matematyczny można przedstawić w postaci następującego skryptu PowerShell.
'ethical.blue' | % { $e = 0.00; $n = $_; $n[0..$n.Length] | Group-Object | % { $p = $_.Count / $n.Length; $e -= $p * [Math]::Log2($p); }; $e; }
Entropia H przykładowego ciągu znaków ethical.blue wynosi 3,25.
Nic nie stoi na przeszkodzie, aby podobnie obliczać entropię z plików. Przykładowy program zaprezentowany poniżej dość sprawnie radzi sobie z małymi i średnimi plikami. W przypadku naprawdę dużych plików należy przetwarzać je fragmentami.
┌ Entropia (C#)
└─ entropy.txt
Dziwo (ang. weird) nazwane Weird.Win64.Blau!E posiada entropię o wartości 3,15. Zgadza się to ze stanem faktycznym, ponieważ jest to mały plik (4 KB), stworzony w Asemblerze MASM x64 i zawiera zwykły kod maszynowy.
W celach eksperymentalnych utworzono plik binarny wypełniony wyłącznie bajtami o wartości 0xCC. Pomiar entropii wskazał wartość zero. Jest to dowód, że przewidywalne wartości, czyli różne wypełnienia (ang. padding) w plikach powodują obniżenie wartości entropii.
Inny przykład to tekst w języku angielskim zawarty w pliku o nazwie c3a1.text. Entropia tego pliku wynosi 4,95 bita na bajt. Nieopublikowane tutaj doświadczenia pokazały, że statystycznie dla tekstu w języku angielskim zakres entropii całego pliku przeważnie wynosi od 4,00 do 5,00 bitów na bajt.
Kod maszynowy spotykany w plikach binarnych posiada powtarzające się bajty takie jak m.in. prefiksy rozkazów czy kody operacyjne (ang. opcode). Kolejne doświadczenie to pomiar entropii pliku zawierającego kod maszynowy dla architektury x64. Uzyskany wynik to 6,43 bita na bajt. Nieopublikowane tutaj doświadczenia pokazały, że statystycznie dla kodu maszynowego (x64) zakres entropii całego pliku przeważnie wynosi od 4,80 do 6,50 bitów na bajt.
Najwyższa wartość entropii jest generowana przez mocno losowe dane, które są często wynikiem zastosowania kompresji lub szyfrowania. Plik o nazwie Aes.encrypted zawiera przykładowe dane zaszyfrowane algorytmem AES (ang. Advanced Encryption Standard). Wynik pomiaru entropii całego pliku to 7,99 bita na bajt.
Wartym uwagi jest narzędzie binwalk3, które pozwala tworzyć wykresy entropii Claude’a E. Shannona dla wskazanych danych. Wstępne zbadanie całego pliku za pomocą narzędzia ent wykazało podwyższoną wartość tego parametru. Z tego powodu kolejnym krokiem było stworzenie wykresu entropii programem binwalk3, co pozwoliło na dokładniejszą analizę struktury pliku.
Wykres sugeruje, że plik zawiera nagłówki, po których występuje kod maszynowy oraz zaszyfrowany lub skompresowany ładunek (ang. payload). Jednak jest to tylko wstępne rozeznanie, które wymaga weryfikacji przy pracy z nieznanymi danymi.
Dla przejrzystości poniższy wykres został ręcznie przerysowany i wyostrzony w programie graficznym.
Po przeprowadzeniu eksperymentów na różnych plikach można łatwo zauważyć, że wysoka entropia sugeruje zastosowanie kompresji lub szyfrowania.
W przypadku mało czytelnego wykresu możliwe, że należy podzielić badany plik na fragmenty.
Przykładowe polecenie PowerShell może być następujące.
$z = [System.IO.File]::OpenRead("sample.binary"); $z.Position = 0x400; $c = 0x20400; $n = [byte[]]::new($c); $z.Read($n, 0, $c) | Out-Null; [System.IO.File]::WriteAllBytes("part.binary", $n); $z.Close();
Natomiast pracując w systemie Kali Linux można zastosować narzędzie dd w następujący sposób.
dd if=sample.binary of=part.binary bs=1 skip=$((0x400)) count=$((0x20400))
Przykładowa wartość 0x400 oznacza pozycję początkową (ang. offset) w pliku, a druga wartość (0x20400) to liczba bajtów do wycięcia i umieszczenia w pliku wynikowym.
Wykaz literatury
[1] Claude E. Shannon, A Mathematical Theory of Communication, 1948.
[2] The MITRE Corporation, d3fend.mitre.org/dao/artifact/d3f:File, 2025.
[3] The MITRE Corporation, emb3d.mitre.org/mitigations/MID-047.html, 2026.