Análise Forense, Criptografia, Programação

Esteganografia por LSB

Tempo de leitura: 6 minutos

Esteganografia, segundo Bruce Schneier, consiste em “esconder mensagens secretas em outras mensagens. (…) Truques historicamente incluem tintas invisíveis, pequenos furinhos em caracteres selecionados, pequenas diferenças em caracteres escritos a mão, marcas de caneta em caracteres datilografados, grades que cobrem a maior parte da mensagem menos algumas letras específicas, e por aí vai”¹.

“Mais recentemente, indivíduos tem escondido mensagens secretas em imagens. Substituindo o bit menos significante de cada byte da imagem com bits da mensagem. A imagem não sofre uma mudança visível – a maioria dos padrões gráficos tem mais gradações de cores que o olho humano consegue perceber” ².

O que Bruce Schneier descreve é uma técnica que se tornou um clássico na esteganografia: esconder mensagem no LSB (Least Significant Bit – Bit menos significativo). Para entender essa técnica, vamos analisar primeiro como uma cor é composta na computação.

Padrão RGB

RGB significa são as iniciais de vermelho (Red), verde (Green) e azul (Blue). Baseada na teoria dos físicos Young e Helmholtz, quando estas três cores são combinadas, é possível gerar um grande espectro de cores. Por isso este padrão é usado para reproduzir cores em monitores, televisões, scanners, projetores, etc.

Na computação, se usa um valor entre 0 (inclusive) e 255 (inclusive), para dizer quanto de cada uma das três cores está presente para formar uma outra cor.

Por exemplo: O vermelho puro tem a seguinte numeração RGB: 255, 0, 0, ou seja, tem o máximo de vermelho, nada de verde e nada de azul).

O branco tem a numeração RGB: 255, 255, 255, ou seja, máximo de vermelho, verde e azul.

A numeração de 0 a 255 é muito conveniente porque cada número do padrão cabe em 8 bits (255 = 1111 1111). Porém isso dá um número absurdo de tonalidades possíveis: mais de 16 milhões de cores! Uma mudança no bit menos significativo é completamente invisível ao olho humano. Veja por exemplo a cor abaixo:

Cor RGB 170,50,100

Esta cor tem 170 de vermelho, 50 de verde e 100 de azul, isto é, rgb(170, 50, 100). Estes números em binário respectivamente são: 1010 1010, 0011 0010 e 0110 0100. Se eu alterar o último bit do azul, tornando aquele zero em um, será uma cor totalmente diferente, mas invisível ao olho humano. Veja abaixo:

Cor RGB 170,50,101

Eu poderia até mesmo trocar o bit menos significativo das três cores e ainda assim não seria perceptível. Veja:

Cor RGB 171,51,101

Agora vou além. Colocarei uma cor do lado da outra com uma barra preta para marcar onde uma termina e a outra começa. Veja:

Três cores com códigos diferentes imperceptíveis ao olho humano

Ainda assim não é possível ver nenhuma diferença entre as três cores. Agora precisamos entender sobre caracteres e a tabela ASCII

Caracteres e Tabela ASCII

Caracteres não passam de números! Quando um servidor de e-mail envia uma mensagem para um navegador, tudo que é enviado são bits que cabem dois valores: 0 ou 1. O navegador não recebe letras ou palavras, recebe números. Portanto deve existir algum código para “transformar” letras em números… Assim como o código Braille que “transforma” letras em uma forma tátil de relevo… Existe! Se chama Tabela ASCII. Com essa tabela é possível “transformar” uma letra em número. Uma mensagem como:

Tabela ASCII eh bem legal

Se torna nestes números em decimal:

84 97 98 101 108 97 32 65 83 67 73 73 32 101 104 32 98 101 109 32 108 101 103 97 108

Todos esses números estão em base 10. Mas podem ser passados para qualquer outra base. Para a esteganografia LSB, será fundamental passar os números para binário

Escondendo mensagens em imagens

Para esconder a mensagem usando LSB, pegaremos o código de cada letra, converteremos para base binária, e o último bit de cada cor, substituiremos por cada bit da letra um a um. Deixe me exemplificar para ficar ainda mais claro:

A letra “R” equivale ao numero 82 em decimal. 82 em decimal equivale a “0101 0010” em binário. Portanto precisaremos de 8 bytes de cor para esconder essa letra R. Um pixel é formado pela junção de 3 bytes: RGB. Então três pixels de vermelho terão os seguintes bytes:

11111111 – 00000000 – 00000000 - 11111111 – 00000000 – 00000000 - 11111111 – 00000000 – 00000000

Isso porque, como vimos, o vermelho, no padrão RGB é 255, 0, 0.

Agora vamos colocar os 8 bits das letras “R” em cada byte dos três pixels. Então ficará assim:

11111110 – 00000001 – 00000000 – 11111111 – 00000000 – 00000000 – 11111111 – 00000000 – 00000000

Assim a mensagem fica escondida substituindo o “bit menos significativo” da imagem.

Exemplo real

Para uma demonstração real, provavelmente o formato mais fácil para usar neste exemplo é o BMP porque é um formato bastante simples e fácil de ler. Usarei também um código do GitHub para a demonstração. O código está em https://github.com/omriher/LSB_Steganography.git

Este código do GitHub é extremamente simples (era exatamente o que eu queria). Ele apenas lê a imagem “cat.bmp”, lê o cabeçalho do formato BMP, procura o endereço offset onde começa os bytes que, juntos, formam cada pixel de cor e começa a substituir cada bit menos significativo pelos bits que compõe a imagem que está na variável “TextToHide” do código.

Então eu criei um bmp qualquer de 24 bits e salvei como “cat.bmp”. A imagem é essa:

Essa é a imagem original

Substitui o conteúdo da variável “TextToHide” para aparecer: Escondido!

Rodei esse código com python2 e gerou uma imagem intitulada “hidden_cat.bmp”. A imagem é esta a seguir:

Imagem com mensagem codificada

Visivelmente não há diferença alguma entre elas. Porém vamos comparar as duas imagens de um editor hexadecimal para ver as diferenças a nível de bit. Mas antes precisamos converter a mensagem “Escondido!” para decimal temos 69 115 99 111 110 100 105 100 111 33. Lembre-se disso!

Analisando o código, vemos que ele coloca, antes da mensagem, o tamanho dela e um delimitador. Isso é uma informação que será usada quando for “retirar” a mensagem de uma imagem qualquer.

Então a mensagem a ser escondida era: 10$Escondido!

Analisando as duas imagens com o VBinDiff, vejo que as mudanças entre as duas imagens são as seguintes:

Visualizando as duas imagens em um editor hexadecimal

Lendo a especificação do formato BMP, vemos que no endereço offset “0x0A” diz o endereço onde começam os bytes de cor da imagem. Esta informação ocupa 4 bytes. Analisando o endereço offset 0x0A até 0x0D tem: “36 00 00 00”. Esta informação está em “Little Endian”, por isso deve ser lida “00 00 00 36”.

No endereço offset 0x36 começam os bytes de cor. Vamos separar por grupos de 8 para formar byte por byte. Como cada bit final que é alterado, pegarei os 40 primeiros bytes da sequência de cores:

24 1C ED 25 1C EC 24 1D -> “Letra” 1
EC 24 1D ED 24 1C EC 24 -> “Letra” 2
1C EC 25 1C EC 25 1C EC -> “Letra” 3
24 1D EC 24 1C ED 24 1D -> “Letra” 4
EC 25 1D ED 24 1C ED 25 -> “Letra” 5

Convertendo a primeira linha para binário, temos:

24 = 0010 0100‬
1C = 0001 1100‬
ED = 1110 1101‬
25 = 0010 0101‬
1C = 0001 1100‬
EC = 1110 1100
24 = 1110 1100‬
1D = 0001 1101

Pegando apenas os bits finais de cada byte fica: 00110001. Isso em decimal é 49. Olhando na tabela ASCII vemos que 49 vale “1” em texto.

Fazendo este mesmo processo na linha 2 temos:

EC = 1110 1100
24 = 1110 1100‬
1D = 0001 1101
ED = 1110 1101‬
24 = 0010 0100‬
1C = 0001 1100‬
EC = 1110 1100
24 = 1110 1100‬

Pegando apenas os bits finais de cada byte fica: 00110000. Isso em decimal é 48. Olhando na tabela ASCII vemos que 48 vale “0” em texto.

Fazendo este mesmo processo nos próximos grupos de 8 bytes conseguimos extrair a mensagem da imagem: 10$Escondido!

Assim funciona a esteganografia por LSB.

Abraços e até a próxima.

  1. Applied cryptography – protocols, algorithms, and source code in C
  2. Ibid

2 Comments

Leave a Comment

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *