Corrigindo um binário com dd

32

Eu li esta citação (abaixo) várias vezes, mais recentemente aqui , e estou continuamente perplexo com a forma como dd pode ser usado para corrigir qualquer coisa e muito menos um compilador:

The Unix system I used at school, 30 years ago, was very limited in RAM and Disk space. Especially, the /usr/tmp file system was very small, which led to problems when someone tried to compile a large program. Of course, students weren't supposed to write "large programs" anyway; large programs were typically source codes copied from "somewhere". Many of us copied /usr/bin/cc to /home/<myname>/cc, and used dd to patch the binary to use /tmp instead of /usr/tmp, which was bigger. Of course, this just made the problem worse - the disk space occupied by these copies did matter those days, and now /tmp filled up regularly, preventing other users from even editing their files. After they found out what happened, the sysadmins did a chmod go-r /bin/* /usr/bin/* which "fixed" the problem, and deleted all our copies of the C compiler.

(ênfase minha)

O dd man-page não diz nada sobre patch e não acha que poderia ser re-proposto para fazer isso de qualquer maneira.

Os binários podem realmente ser corrigidos com dd ? Existe algum significado histórico para isso?

    
por Amziraro 09.07.2015 / 11:26

2 respostas

71

Vamos tentar. Aqui está um programa C trivial:

#include <stdio.h>
int main(int argc, char **argv) {
    puts("/usr/tmp");
}

Vamos construir isso em test :

$ cc -o test test.c

Se o executarmos, será impresso "/ usr / tmp".

Vamos descobrir onde " /usr/tmp " está no binário:

$ strings -t d test | grep /usr/tmp
1460 /usr/tmp

-t d imprime o deslocamento em decimal no arquivo de cada string que encontrar.

Agora vamos criar um arquivo temporário com apenas " /tmpdd ":

$ printf "/tmp\x00" > tmp

Então agora temos o binário, sabemos onde a string que queremos mudar é, e temos um arquivo com a string de substituição nela.

Agora podemos usar tmp :

$ dd if=tmp of=test obs=1 seek=1460 conv=notrunc

Isto lê dados de /tmp/tmpddtmp%code% (nosso arquivo " %code% "), escrevendo em nosso binário, usando um tamanho de bloco de saída de 1 byte, pulando para o offset que encontramos anteriormente antes de escrever qualquer coisa, e explicitamente não truncando o arquivo quando terminar.

Podemos executar o executável corrigido:

$ ./test
/tmp

A string literal que o programa imprime foi alterada, então agora contém " %code% ", mas as funções de string param assim que vêem o primeiro byte nulo. Esse patch só permite tornar a string mais curta ou com o mesmo tamanho, e não mais, mas é adequada para essas finalidades.

Portanto, não só podemos corrigir as coisas usando %code% , como acabamos de fazer.

    
por 09.07.2015 / 11:47
9

Depende do que você entende por "corrigir o binário".

Altero os binários usando dd às vezes. É claro que não existe tal recurso em dd , mas ele pode abrir arquivos, ler e escrever coisas em compensações específicas, então se você sabe o que escrever, voila tem o seu patch.

Por exemplo, eu tive este binário que continha alguns dados PNG. Use binwalk para encontrar o deslocamento, dd para extraí-lo (geralmente a binwalk também extrai coisas, mas minha cópia foi buggy), edite com gimp , verifique se o arquivo editado é do mesmo tamanho ou menor que o original alterar as compensações não é algo que você possa fazer facilmente) e, em seguida, use dd para colocar a imagem alterada de volta no lugar.

$ binwalk thebinary
[…]
4194643    0x400153     PNG image, 800 x 160, 8-bit/color RGB, non-interlaced
[…]
$ dd if=nickel bs=1 skip=4194641 count=2 conv=swab | od -i
21869 # file size in this case - depends on the binary format
$ dd if=thebinary bs=1 skip=4194643 count=21869 of=theimage.png
$ gimp theimage.png
$ pngcrush myimage.png myimage.crush.png
# make sure myimage.crush.png is smaller than the original
$ dd if=myimage.crush.png of=thebinary bs=1 seek=4194643 conv=notrunc

Às vezes, também desejo substituir strings em binários (como nomes de caminho ou variáveis). Embora isso também possa ser feito usando dd , é mais simples usar sed . Você só precisa garantir que a string substituída tenha o mesmo tamanho da string original, para que você não acabe mudando os deslocamentos.

sed -e s@/the/old/save/path@/the/new/save/path@ -i thebinary

ou para pegar o exemplo de @ MichaelHomer com um byte de 0 em:

sed -e 's@/usr/tmp@/tmp\x00tmp@' -i test

É claro que você precisa verificar se realmente funciona depois.

    
por 09.07.2015 / 11:48