Hallo liebe AutoIt-Community!
Wie die Überschrift schon verrät, bin ich dabei, ein Steganografie-Script nach diesem Vorbild zu schreiben. Mit AutoIt allein hat das ganze für mich auch kein Problem dargestellt. Nun wollte ich jedoch den Hauptteil, nämlich das Verstecken in der Bilddatei, mit Assembler (mit AssembleIt) umsetzen.
Darin bin ich jedoch noch nicht gerade so erfahren wie in AutoIt, weshalb ich jetzt auch auf einige Problemchen stoße...
Zu meinem Skript:
- Es wird per GDIPlus eine Bitmap-Datei geladen und der Pointer auf die Pixeldaten an den ASM-Code übergeben.
- Der Geheimtext wird in eine DLL-Struct gepackt (ich hoffe, da mache ich soweit alles richtig - ganz sicher bin ich mir nicht...) und der Pointer dazu auch übergeben.
- Der ASM-Code liest nun für jedes Pixel die ursprüngliche Pixelfarbe aus sowie ein Byte des Geheimtextes.
- Die Pixelfarbe wird in (A)RGB getrennt und die untersten Bits der Farben durch Bits des Geheimtextes ersetzt (bei Rot und Grün 3 Bit, bei Blau 2 Bit -> insgesamt 8 Bit (1 Byte) pro Pixel).
- Der neue Farbwert wird zusammengesetzt und am Ende in einer neuen Bitmap-Datei gespeichert.
#include <assembleit.au3>
#include <GDIPlus.au3>
; Variablen
Local $Locked, $Scan0, $hImage
Local $iWidth, $iHeight
; GDIPlus lädt das Bild
_GDIPlus_Startup()
$hImage = _GDIPlus_BitmapCreateFromFile(@ScriptDir & "\test.bmp")
$iWidth = _GDIPlus_ImageGetWidth($hImage)
$iHeight = _GDIPlus_ImageGetHeight($hImage)
; An die Pixeldaten gelangen
$Locked = _GDIPlus_BitmapLockBits($hImage, 0, 0, $iWidth, $iHeight, $GDIP_ILMWRITE, $GDIP_PXF32ARGB)
$Scan0 = DllStructGetData($Locked, "Scan0")
$sString = "aaaa" ; String, der versteckt werden soll
$String = DllStructCreate ("byte[" & ($iWidth * $iHeight) & "]") ; DLL-Struct für den String erstellen (für jeden Pixel ein Byte)
$bBinary = StringToBinary ($sString) ; String in binär umwandeln
DllStructSetData ($String, 1, $bBinary) ; DLL-Struct füllen
; ASM-Code auführen
$_ASSEMBLEIT_FLAG = 1
$return = _assembleit("int", "Steganografie", "ptr", $Scan0, "int", $iWidth, "int", $iHeight, "ptr", DllStructGetPtr ($String))
MsgBox (0, "", "Fertig. Übersprungene Pixel: " & $return)
; Neues Bild speichern
_GDIPlus_BitmapUnlockBits($hImage, $Locked)
_GDIPlus_ImageSaveToFile ($hImage, @ScriptDir & "\output.bmp")
_GDIPlus_BitmapDispose($hImage)
_GDIPlus_Shutdown()
Func Steganografie ()
#cs
Kommentar zur Funktionsweise:
- es werden die letzten drei Bits vom Rot- und Grün-Wert eines jeden Pixels, sowie zwei Bit vom Blau-Wert durch
insgesamt 8 Bit (ein Byte) des Geheimtextes ersetzt (bei Blau nur 2 Bit, damit man auf 1 Byte kommt)
#ce
_("use32")
_("mov edi, [esp+4]") ; Pointer-Position für die Pixeldaten in edi speichern
_("mov eax, [esp+8]") ; Breite der Bitmap in eax
_("mul dword [esp+12]") ; eax *= $Height -> eax = $Width * $Height (Pixelanzahl)
_("mov ecx, eax") ; eax (Anzahl der Pixel) als Counter nach ecx
_("mov esi, [esp+16]") ; Pointer-Position auf den zu versteckenden Binärstring
_("Pixel:") ; Beginn der Schleife für jeden Pixel
; ################################################## Steganografie:
;
_("mov edx, [esi]") ; edx sind die nächsten 4 Byte (32 Bit) des Binärstrings (aber nur das erste wird verwendet)
_("cmp edx, 0") ; edx ist manchmal 0 und das Programm stürzt dann ab (Wieso?)
_("je Ende") ; -> in diesem Fall gleich beenden (und übersprungene Pixel ausgeben)
_("mov eax, [edi]") ; Farbe des Pixels (= Wert an edi-Position) in eax Form: #AARRGGBB
;
; Rot-Wert-Berechnung:
;
_("shl eax, 8") ; eax mit 2^8 = 256 multiplizieren
; -> der 32bit-Farbcode #AARRGGBB wird zu #RRGGBB00
_("shr eax, 27") ; eax um 6 Hex-Stellen (24bit) + 3bit nach rechts shiften (die drei Bit werden durch drei Bits vom Geheimtext ersetzt)
_("shl eax, 3") ; und die 3bit wieder zurückshiften (sind jetzt dadurch alle null)
; -> eax ist nur noch #RR und die letzten drei Bit sind 0
_("shr edx, 29") ; von edx werden nur die ersten 3 Bit verwendet (für den Rot-Wert)
_("add eax, edx") ; eax (Farbwert Rot) und edx (3 bit String) verknüpfen
_("push eax") ; neuen Rot-Wert auf den Stack pushen
_("mov edx, [esi]") ; edx sind noch einmal die 4 Byte (32 Bit) des Binärstrings wie bei Rot (aber nur das erste wird verwendet)
_("mov eax, dword [edi]"); Farbe des Pixels (= Wert an edi-Position) in eax Form: #AARRGGBB
;
; Grün-Wert-Berechnung:
;
_("shl eax, 16") ; eax mit 2^16 = 256^2 multiplizieren
; -> der 32bit-Farbcode #AARRGGBB wird zu #GGBB0000
_("shr eax, 27") ; eax um 6 Hex-Stellen (24bit) + 3bit nach rechts shiften (die drei Bit werden durch drei Bits vom Geheimtext ersetzt)
_("shl eax, 3") ; und die 3bit wieder zurückshiften (sind jetzt null)
; -> eax ist nur noch #GG und die letzten drei Bit sind 0
_("shl edx, 3") ; von edx werden nur die Bits 4 - 6 verwendet (für den Grün-Wert)
_("shr edx, 29") ; -> erst die ersten 3 Bit eliminieren und dann zurückshiften (->7-32 weg)
_("add eax, edx") ; eax (Farbwert Grün) und edx (3 bit String) verknüpfen
_("push eax") ; Grün-Wert auf den Stack pushen
_("mov edx, [esi]") ; edx sind noch einmal die 4 Byte (32 Bit) des Binärstrings wie bei Rot und Grün (aber nur das erste wird verwendet)
_("mov eax, dword [edi]"); Farbe des Pixels (= Wert an edi-Position) in eax Form: #AARRGGBB
;
; Blau-Wert-Berechnung:
;
_("shl eax, 24") ; eax mit 2^24 = 256^3 multiplizieren
; -> der 32bit-Farbcode #AARRGGBB wird zu #BB000000
_("shr eax, 26") ; eax um 6 Hex-Stellen (24bit) + 2bit nach rechts shiften (die zwei Bit werden durch drei Bits vom Geheimtext ersetzt)
_("shl eax, 2") ; und die 2bit wieder zurückshiften
; -> eax ist nur noch #BB und die letzten zwei Bit sind 0
_("shl edx, 6") ; von edx werden nur die Bits 7 - 8 verwendet (für den Blau-Wert)
_("shr edx, 30") ; -> erst die ersten 6 Bit eliminieren und dann zurückshiften (->9-32 weg)
_("add eax, edx") ; eax (Farbwert Blau) und edx (2 bit String) verknüpfen
; ############## Farben zusammensetzen
_("mov edx, 0xFF000000"); edx auf RGB Farbwert 0 setzen, Alphawert auf FF (standard)
_("add edx, eax") ; eax enthält noch den Blau-Wert -> dazu addieren
_("pop eax") ; eax enthält nun den Grün-Wert
_("shl eax, 8") ; eax um zwei Hex-Stellen nach links shiften -> #GG00 (Grün-Wert an richtige Stelle)
_("add edx, eax") ; und Grün-Wert zu edx addieren
_("pop eax") ; eax enthält den Rot-Wert
_("shl eax, 16") ; eax um 4 Hex-Stellen nach links shiften -> #RR0000 (Rot-Wert an richtige Stelle)
_("add edx, eax") ; und zu edx addieren
_("mov [edi], edx") ; Farbwert in der Bitmap speichern
; ##################### Ende der Steganografie
_("add esi, 1") ; ebx um 1 Byte erhöhen (es wird pro Pixel 1 Byte Text versteckt)
_("add edi, 4") ; edi um 4 Bytes (1 Pixel) erhöhen
_("dec ecx") ; ecx -= 1 -> Schleifendurchläufe rückwärts zählen
_("cmp ecx, 0") ; Sind alle Pixel durchlaufen?
_("jne Pixel") ; wenn nicht, dann Schleife wiederholen
_("Ende:")
_("mov eax, ecx")
_("ret")
EndFunc
Was nicht so funktioniert:
- Ich habe als Bitmap eine 2x2 Pixel reinweiße Bitmap genommen (Farbe: #FFFFFF; Datei siehe Anhang) und als Geheimtext "aaaa". Da in jedem Pixel genau ein Buchstabe versteckt wird, sollten alle Pixel am Ende wieder gleich sein (4 mal ein weißer Pixel mit "a" drin). Dies ist aber nicht der Fall, das erste Pixel ist andersfarbig.
- Wenn die Länge des Geheimtextes kleiner ist als die Pixelanzahl, stürzt das Programm ab. Ich frage mich, wieso das Programm nicht richtig weiter macht, wenn es als Byte des Geheimtextes 0 ausliest. Denn das ist ja schließlich auch nur eine Zahl, oder nicht?
Ich bedanke mich schonmal sehr für eure Hilfe, ich habe nun schon viele Stunden an diesem Skript verbracht und komme der Lösung leider nicht näher...
LG Xenon
PS: Ich habe es mal in diesem Forum gepostet, weil es hauptsächlich um ASM und weniger um AutoIt geht. Ich hoffe das ist okay so, ansonsten bitte verschieben.