Steganografia i jej analiza w Pythonie

Zgłosił się do mnie klient z projektem, którego celem było dojście do tego, czy w danym obrazku nie znajdują się ukryte informacje zakodowane poprzez steganografię.

Steganografia Kodek Online

Poniżej prezentuję skrypt w Pythonie, który wyciąga piksele w trybach horyzontalnych (czyli piksel po pikselu na wysokość obrazka) i wertykalnych z grafiki:

  • najmniej znaczące bity w składowych R
  • najmniej znaczące bity w składowych G
  • najmniej znaczące bity w składowych B
  • najmniej znaczące bity w składowych ALPHA
  • kombinowane najmniej znaczące bity w RGB
  • kombinowane najmniej znaczące bity w BGR
  • kombinowane najmniej znaczące bity w RGBA
  • kombinowane najmniej znaczące bity w ABGR

Są to najczęściej stosowane metody używane przez narzędzia do steganografii do ukrywania rozbitych danych w najmniej znaczących bitach składowych kolorów RGB.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
from PIL import Image
from bitarray import bitarray
def dump(filename, content):
f = open(filename, 'wb')
f.write(content)
f.close()
def stego(filename, filename_prefix):
im = Image.open(filename)
pixels = im.load()
width, height = im.size
#
# RED, GREEN, BLUE least significant bits
#
byte1, byte2, byte3, byte4, bits = 0, 0, 0, 0, 0
out1, out2, out3, out4 = bytearray(), bytearray(), bytearray(), bytearray()
bit1, bit2, bit3, bit4 = bitarray(), bitarray(), bitarray(), bitarray()
all1, all2, all3, all4 = bitarray(), bitarray(), bitarray(), bitarray()
rgb, rgba = bitarray(), bitarray()
xx = width
yy = height
horizontal = True
if filename_prefix == "vertical":
xx = height
yy = width
horizontal = False
for x in range(xx):
for y in range(yy):
if horizontal is True:
pixel = pixels[x, y]
else:
pixel = pixels[y, x]
# separate R G B
bit1.append(pixel[0] & 1)
bit2.append(pixel[1] & 1)
bit3.append(pixel[2] & 1)
bit4.append(pixel[3] & 1)
# combined RGB
all1.append(pixel[0] & 1)
all2.append(pixel[1] & 1)
all3.append(pixel[2] & 1)
all4.append(pixel[3] & 1)
# RGB
rgb.append(pixel[0] & 1)
rgb.append(pixel[1] & 1)
rgb.append(pixel[2] & 1)
# RGBA
rgba.append(pixel[0] & 1)
rgba.append(pixel[1] & 1)
rgba.append(pixel[2] & 1)
rgba.append(pixel[3] & 1)
# compose 8 bits
if bits < 8:
byte1 = (byte1 << 1) | (pixel[0] & 1)
byte2 = (byte2 << 1) | (pixel[1] & 1)
byte3 = (byte3 << 1) | (pixel[2] & 1)
byte4 = (byte4 << 1) | (pixel[3] & 1)
bits = bits + 1
else:
bits = 0
out1.append(byte1 & 0xFF)
out2.append(byte2 & 0xFF)
out3.append(byte3 & 0xFF)
out4.append(byte4 & 0xFF)
dump(filename_prefix + "_1_RED.bin", out1)
dump(filename_prefix + "_1_GREEN.bin", out2)
dump(filename_prefix + "_1_BLUE.bin", out3)
dump(filename_prefix + "_1_ALPHA.bin", out4)
dump(filename_prefix + "_2_RED_BITS.bin", bit1)
dump(filename_prefix + "_2_GREEN_BITS.bin", bit2)
dump(filename_prefix + "_2_BLUE_BITS.bin", bit3)
dump(filename_prefix + "_2_ALPHA_BITS.bin", bit4)
bit1.reverse()
bit2.reverse()
bit3.reverse()
bit4.reverse()
dump(filename_prefix + "_3_RED_REV_BITS.bin", bit1)
dump(filename_prefix + "_3_GREEN_REV_BITS.bin", bit2)
dump(filename_prefix + "_3_BLUE_REV_BITS.bin", bit3)
dump(filename_prefix + "_3_ALPHA_REV_BITS.bin", bit4)
dump(filename_prefix + "_4_RED_BITS_RGB.bin", all1)
dump(filename_prefix + "_4_GREEN_BITS_RGB.bin", all2)
dump(filename_prefix + "_4_BLUE_BITS_RGB.bin", all3)
dump(filename_prefix + "_4_ALPHA_BITS_RGB.bin", all4)
all1.reverse()
all2.reverse()
all3.reverse()
all4.reverse()
dump(filename_prefix + "_5_RED_BITS_BGR.bin", all1)
dump(filename_prefix + "_5_GREEN_BITS_BGR.bin", all2)
dump(filename_prefix + "_5_BLUE_BITS_BGR.bin", all3)
dump(filename_prefix + "_5_ALPHA_BITS_BGR.bin", all4)
dump(filename_prefix + "_6_RGB_ALL_BITS.bin", rgb)
dump(filename_prefix + "_6_RGBA_ALL_BITS.bin", rgba)
rgb.reverse()
rgba.reverse()
dump(filename_prefix + "_6_RGB_ALL_REV_BITS.bin", rgb)
dump(filename_prefix + "_6_RGBA_ALL_REV_BITS.bin", rgba)
if __name__ == '__main__':
stego('IMG1.PNG', 'horizontal')
stego('IMG1.PNG', 'vertical' )
from PIL import Image from bitarray import bitarray def dump(filename, content): f = open(filename, 'wb') f.write(content) f.close() def stego(filename, filename_prefix): im = Image.open(filename) pixels = im.load() width, height = im.size # # RED, GREEN, BLUE least significant bits # byte1, byte2, byte3, byte4, bits = 0, 0, 0, 0, 0 out1, out2, out3, out4 = bytearray(), bytearray(), bytearray(), bytearray() bit1, bit2, bit3, bit4 = bitarray(), bitarray(), bitarray(), bitarray() all1, all2, all3, all4 = bitarray(), bitarray(), bitarray(), bitarray() rgb, rgba = bitarray(), bitarray() xx = width yy = height horizontal = True if filename_prefix == "vertical": xx = height yy = width horizontal = False for x in range(xx): for y in range(yy): if horizontal is True: pixel = pixels[x, y] else: pixel = pixels[y, x] # separate R G B bit1.append(pixel[0] & 1) bit2.append(pixel[1] & 1) bit3.append(pixel[2] & 1) bit4.append(pixel[3] & 1) # combined RGB all1.append(pixel[0] & 1) all2.append(pixel[1] & 1) all3.append(pixel[2] & 1) all4.append(pixel[3] & 1) # RGB rgb.append(pixel[0] & 1) rgb.append(pixel[1] & 1) rgb.append(pixel[2] & 1) # RGBA rgba.append(pixel[0] & 1) rgba.append(pixel[1] & 1) rgba.append(pixel[2] & 1) rgba.append(pixel[3] & 1) # compose 8 bits if bits < 8: byte1 = (byte1 << 1) | (pixel[0] & 1) byte2 = (byte2 << 1) | (pixel[1] & 1) byte3 = (byte3 << 1) | (pixel[2] & 1) byte4 = (byte4 << 1) | (pixel[3] & 1) bits = bits + 1 else: bits = 0 out1.append(byte1 & 0xFF) out2.append(byte2 & 0xFF) out3.append(byte3 & 0xFF) out4.append(byte4 & 0xFF) dump(filename_prefix + "_1_RED.bin", out1) dump(filename_prefix + "_1_GREEN.bin", out2) dump(filename_prefix + "_1_BLUE.bin", out3) dump(filename_prefix + "_1_ALPHA.bin", out4) dump(filename_prefix + "_2_RED_BITS.bin", bit1) dump(filename_prefix + "_2_GREEN_BITS.bin", bit2) dump(filename_prefix + "_2_BLUE_BITS.bin", bit3) dump(filename_prefix + "_2_ALPHA_BITS.bin", bit4) bit1.reverse() bit2.reverse() bit3.reverse() bit4.reverse() dump(filename_prefix + "_3_RED_REV_BITS.bin", bit1) dump(filename_prefix + "_3_GREEN_REV_BITS.bin", bit2) dump(filename_prefix + "_3_BLUE_REV_BITS.bin", bit3) dump(filename_prefix + "_3_ALPHA_REV_BITS.bin", bit4) dump(filename_prefix + "_4_RED_BITS_RGB.bin", all1) dump(filename_prefix + "_4_GREEN_BITS_RGB.bin", all2) dump(filename_prefix + "_4_BLUE_BITS_RGB.bin", all3) dump(filename_prefix + "_4_ALPHA_BITS_RGB.bin", all4) all1.reverse() all2.reverse() all3.reverse() all4.reverse() dump(filename_prefix + "_5_RED_BITS_BGR.bin", all1) dump(filename_prefix + "_5_GREEN_BITS_BGR.bin", all2) dump(filename_prefix + "_5_BLUE_BITS_BGR.bin", all3) dump(filename_prefix + "_5_ALPHA_BITS_BGR.bin", all4) dump(filename_prefix + "_6_RGB_ALL_BITS.bin", rgb) dump(filename_prefix + "_6_RGBA_ALL_BITS.bin", rgba) rgb.reverse() rgba.reverse() dump(filename_prefix + "_6_RGB_ALL_REV_BITS.bin", rgb) dump(filename_prefix + "_6_RGBA_ALL_REV_BITS.bin", rgba) if __name__ == '__main__': stego('IMG1.PNG', 'horizontal') stego('IMG1.PNG', 'vertical' )
from PIL import Image
from bitarray import bitarray


def dump(filename, content):
    f = open(filename, 'wb')
    f.write(content)
    f.close()


def stego(filename, filename_prefix):
    im = Image.open(filename)
    pixels = im.load()

    width, height = im.size

    #
    # RED, GREEN, BLUE least significant bits
    #
    byte1, byte2, byte3, byte4, bits = 0, 0, 0, 0, 0
    out1, out2, out3, out4 = bytearray(), bytearray(), bytearray(), bytearray()
    bit1, bit2, bit3, bit4 = bitarray(), bitarray(), bitarray(), bitarray()
    all1, all2, all3, all4 = bitarray(), bitarray(), bitarray(), bitarray()

    rgb, rgba = bitarray(), bitarray()

    xx = width
    yy = height
    horizontal = True

    if filename_prefix == "vertical":
        xx = height
        yy = width
        horizontal = False

    for x in range(xx):
        for y in range(yy):

            if horizontal is True:
                pixel = pixels[x, y]
            else:
                pixel = pixels[y, x]

            # separate R G B
            bit1.append(pixel[0] & 1)
            bit2.append(pixel[1] & 1)
            bit3.append(pixel[2] & 1)
            bit4.append(pixel[3] & 1)

            # combined RGB
            all1.append(pixel[0] & 1)
            all2.append(pixel[1] & 1)
            all3.append(pixel[2] & 1)
            all4.append(pixel[3] & 1)

            # RGB
            rgb.append(pixel[0] & 1)
            rgb.append(pixel[1] & 1)
            rgb.append(pixel[2] & 1)

            # RGBA
            rgba.append(pixel[0] & 1)
            rgba.append(pixel[1] & 1)
            rgba.append(pixel[2] & 1)
            rgba.append(pixel[3] & 1)

            # compose 8 bits
            if bits < 8:
                byte1 = (byte1 << 1) | (pixel[0] & 1)
                byte2 = (byte2 << 1) | (pixel[1] & 1)
                byte3 = (byte3 << 1) | (pixel[2] & 1)
                byte4 = (byte4 << 1) | (pixel[3] & 1)
                bits = bits + 1
            else:
                bits = 0
                out1.append(byte1 & 0xFF)
                out2.append(byte2 & 0xFF)
                out3.append(byte3 & 0xFF)
                out4.append(byte4 & 0xFF)

    dump(filename_prefix + "_1_RED.bin", out1)
    dump(filename_prefix + "_1_GREEN.bin", out2)
    dump(filename_prefix + "_1_BLUE.bin", out3)
    dump(filename_prefix + "_1_ALPHA.bin", out4)

    dump(filename_prefix + "_2_RED_BITS.bin", bit1)
    dump(filename_prefix + "_2_GREEN_BITS.bin", bit2)
    dump(filename_prefix + "_2_BLUE_BITS.bin", bit3)
    dump(filename_prefix + "_2_ALPHA_BITS.bin", bit4)

    bit1.reverse()
    bit2.reverse()
    bit3.reverse()
    bit4.reverse()

    dump(filename_prefix + "_3_RED_REV_BITS.bin", bit1)
    dump(filename_prefix + "_3_GREEN_REV_BITS.bin", bit2)
    dump(filename_prefix + "_3_BLUE_REV_BITS.bin", bit3)
    dump(filename_prefix + "_3_ALPHA_REV_BITS.bin", bit4)

    dump(filename_prefix + "_4_RED_BITS_RGB.bin", all1)
    dump(filename_prefix + "_4_GREEN_BITS_RGB.bin", all2)
    dump(filename_prefix + "_4_BLUE_BITS_RGB.bin", all3)
    dump(filename_prefix + "_4_ALPHA_BITS_RGB.bin", all4)

    all1.reverse()
    all2.reverse()
    all3.reverse()
    all4.reverse()

    dump(filename_prefix + "_5_RED_BITS_BGR.bin", all1)
    dump(filename_prefix + "_5_GREEN_BITS_BGR.bin", all2)
    dump(filename_prefix + "_5_BLUE_BITS_BGR.bin", all3)
    dump(filename_prefix + "_5_ALPHA_BITS_BGR.bin", all4)

    dump(filename_prefix + "_6_RGB_ALL_BITS.bin", rgb)
    dump(filename_prefix + "_6_RGBA_ALL_BITS.bin", rgba)

    rgb.reverse()
    rgba.reverse()

    dump(filename_prefix + "_6_RGB_ALL_REV_BITS.bin", rgb)
    dump(filename_prefix + "_6_RGBA_ALL_REV_BITS.bin", rgba)


if __name__ == '__main__':
    stego('IMG1.PNG', 'horizontal')
    stego('IMG1.PNG', 'vertical' )

Może komuś się kiedyś przyda.

2 komentarze do “Steganografia i jej analiza w Pythonie”

Dodaj komentarz