Come modificare i file binari con Vim?


77

C'è un modo per modificare i file binari in una sorta di modalità esadecimale?

Ad esempio se ho alcuni dati binari mostrati da xxdo in hexdump -Cquesto modo:

$ hexdump -C a.bin | head -n 5
00000000  cf fa ed fe 07 00 00 01  03 00 00 80 02 00 00 00  |................|
00000010  12 00 00 00 40 05 00 00  85 00 20 00 00 00 00 00  |....@..... .....|
00000020  19 00 00 00 48 00 00 00  5f 5f 50 41 47 45 5a 45  |....H...__PAGEZE|
00000030  52 4f 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |RO..............|
00000040  00 00 00 00 01 00 00 00  00 00 00 00 00 00 00 00  |................|

$ xxd a.bin | head -n 5
0000000: cffa edfe 0700 0001 0300 0080 0200 0000  ................
0000010: 1200 0000 4005 0000 8500 2000 0000 0000  ....@..... .....
0000020: 1900 0000 4800 0000 5f5f 5041 4745 5a45  ....H...__PAGEZE
0000030: 524f 0000 0000 0000 0000 0000 0000 0000  RO..............
0000040: 0000 0000 0100 0000 0000 0000 0000 0000  ................

Se voglio cambiare il valore in una posizione specifica, questo tipo di vista aiuterà a trovare il posto giusto, ad esempio quando la posizione da cambiare si trova vicino a una stringa nota.

Risposte:


89

Il modo più semplice è usare l' binaryopzione. Da :help binary:

This option should be set before editing a binary file.  You can also
use the -b Vim argument.  When this option is switched on a few
options will be changed (also when it already was on):
        'textwidth'  will be set to 0
        'wrapmargin' will be set to 0
        'modeline'   will be off
        'expandtab'  will be off
Also, 'fileformat' and 'fileformats' options will not be used, the
file is read and written like 'fileformat' was "unix" (a single <NL>
separates lines).
The 'fileencoding' and 'fileencodings' options will not be used, the
file is read without conversion.

[..]

When writing a file the <EOL> for the last line is only written if
there was one in the original file (normally Vim appends an <EOL> to
the last line if there is none; this would make the file longer).  See
the 'endofline' option.

Se non lo fai, e il tuo ambiente utilizza una codifica multibyte (ad esempio UTF-8, come la maggior parte delle persone usa), Vim tenta di codificare il testo in quanto tale, di solito portando alla corruzione dei file.

Puoi verificarlo aprendo un file e semplicemente usando :w. Ora è cambiato.
Se si imposta LANGe LC_ALLsu C(ASCII), Vim non converte nulla e i file rimangono gli stessi (aggiunge comunque una nuova riga) poiché Vim non dovrà eseguire alcuna codifica multibyte.

Personalmente preferisco anche disabilitare set wrap per binario, anche se altri potrebbero preferire abilitarlo . YMMV. Un'altra cosa utile da fare è :set display=uhex. Da :help 'display':

uhex            Show unprintable characters hexadecimal as <xx>
                instead of using ^C and ~C.

E come ultimo suggerimento, puoi mostrare il valore esadecimale del personaggio sotto il cursore nel righello con %B( :set rulerformat=0x%B).

Più avanzato: xxd

È possibile utilizzare lo xxd(1)strumento per convertire un file in un formato più leggibile e (questo è il bit importante), analizzare il "formato leggibile" modificato e riscriverlo come dati binari. xxdfa parte di vim, quindi se hai viminstallato dovresti avere anche xxd.

Per usarlo:

$ xxd /bin/ls | vi -

Oppure se hai già aperto il file, puoi utilizzare:

:%!xxd

Ora apporta le tue modifiche, devi farlo sul lato sinistro del display (i numeri esadecimali), le modifiche sul lato destro (rappresentazione stampabile) vengono ignorate in scrittura.

Per salvarlo, utilizzare xxd -r:

:%!xxd -r > new-ls

Questo salverà il file in new-ls.

Oppure per caricare il file binario nel buffer corrente:

:%!xxd -r

Da xxd(1):

   -r | -revert
          reverse operation: convert (or patch) hexdump into  binary.   If
          not  writing  to stdout, xxd writes into its output file without
          truncating it. Use the combination -r -p to read plain hexadeci‐
          mal dumps without line number information and without a particu‐
          lar column layout. Additional  Whitespace  and  line-breaks  are
          allowed anywhere.

E poi basta usare :wper scriverlo. ( attenzione : si desidera impostare l' binary opzione prima di scrivere sul file, per gli stessi motivi indicati sopra).

Tasti complementari per semplificare un po 'questo:

" Hex read
nmap <Leader>hr :%!xxd<CR> :set filetype=xxd<CR>

" Hex write
nmap <Leader>hw :%!xxd -r<CR> :set binary<CR> :set filetype=<CR>

Questo è disponibile anche dal menu se stai usando gVim, sotto 'Strumenti ➙ Converti in esadecimale' e 'Strumenti ➙ Converti indietro'.

Il wiki di vim tips ha una pagina con maggiori informazioni e alcuni script di supporto. Personalmente, penso che probabilmente stai meglio usando un vero editor esadecimale se stai modificando i file binari così spesso. Vim può fare un po 'il lavoro, ma ovviamente non è progettato per questo, e se mai scrivessi senza :set binaryVim potresti distruggere i tuoi file binari!


4
Bella risposta, ma probabilmente dovrebbe iniziare con "Non provarlo a casa, ragazzi!"
msw,

Cosa succede se devo rimuovere alcuni byte? ad esempio nel mezzo del binario.
Anton K,

Non so cosa stia facendo Vim, ma sta aggiungendo 95 KB di testo a un file binario da 200 KB, nonostante io non abbia cambiato nulla. Anche con :set binary noeol fenc=utf-8. In effetti, lo fa immediatamente all'apertura del file prima che lo dica [noeol] [converted]. Perché vim deve aumentare il buffer del 150%? Come posso impedirgli di corrompere file del genere?
Braden Best

L'unica cosa che funziona è :r !xxd <file>(o $ xxd <file> | vim -) leggere e :w !xxd -r > <file>scrivere, ma questo non è l'ideale.
Braden Best

Risposta eccellente. Nota che l'URL per benedire non funziona; L'ho trovato (penso) su github su github.com/bwrsandman/Bless .
Sonofagun,

19

Per visualizzare il contenuto di un file binario in una vista esadecimale, aprire il file, attivare la modalità binaria e filtrare il buffer tramite il xxdcomando:

:set binary
:%!xxd

È possibile apportare modifiche nell'area sinistra (modificare i numeri esadecimali) e, quando è pronto, filtrare xxd -re infine salvare il file:

:%!xxd -r
:w

Se il passaggio del filtro dopo l'apertura e prima della chiusura sembra noioso, e spesso lo fai con i file con .binestensione, puoi aggiungerlo al tuo vimrc per rendere automatico il processo:

" for hex editing
augroup Binary
  au!
  au BufReadPre  *.bin let &bin=1
  au BufReadPost *.bin if &bin | %!xxd
  au BufReadPost *.bin set ft=xxd | endif
  au BufWritePre *.bin if &bin | %!xxd -r
  au BufWritePre *.bin endif
  au BufWritePost *.bin if &bin | %!xxd
  au BufWritePost *.bin set nomod | endif
augroup END

Se seguo queste istruzioni (aprire file binario, :%!xxd, :%!xxd -r, :w, non ha ancora apportare alcuna modifica!), Allora il file binario scritto è non è la stessa come l'originale ... E 'questo il caso per voi (ho provato con /bin/ls). Devo usare :set binaryprima di salvare (vedi anche la mia risposta che spiega perché) ... Forse è qualcosa nel mio VIMRC? Ma a prescindere, set binary
userei

1
Puoi invece aggiungere lo augroupscript a ~/.vim/plugin/binary.vimse non vuoi ingombrare il tuo.vimrc
thom_nic il

Se sei su un'installazione straniera, tale augroup Binaryelenco si trova in :help hex-editingo :help using-xxdin qualsiasi Vim dal 5,5 (settembre 1999).
bb010g,

6

Utilizzare l'editor "bvi". http://bvi.sourceforge.net/ (è presente in ogni repository Linux.)

$ apt-cache show bvi
[snip]
Description-en: binary file editor
 The bvi is a display-oriented editor for binary files, based on the vi
 text editor. If you are familiar with vi, just start the editor and begin to
 edit! If you never heard about vi, maybe bvi is not the best choice for you.

1
Un'alternativa più avanzata è bviplus, che ha controlli vim.
Anton K,


3

TL; Risposta DR

Apri il file con Vim in modalità binaria:

vim -b <file_to_edit>

In Vim, entra in modalità di modifica esadecimale in questo modo:

:%!xxd -p

Salvare:

:%!xxd -p -r
:w

Questo convertirà il buffer dalla modalità esadecimale e quindi salverà il file come al solito.

Nota l'opzione -p. Questo evita tutta la lanugine aggiuntiva stampabile e indirizza e ti mostra solo l'esagono. Ometti -p se vuoi il contesto extra.

Fai attenzione ad aprire il file con Vim non in modalità binaria, poiché aggiungerà un carattere LF (di solito non intenzionale) alla fine del file quando lo salvi.


Questo in realtà non aggiunge nulla che non sia nelle altre risposte.
Herb Wolfe,

5
Il vero TL; DR è dentro :h using-xxded è in circolazione da allora v7.0001e probabilmente più a lungo. Questo sito sarebbe meno attivo se le persone cercassero i documenti.
Tommy A

1

Questo appare come un plugin utile po 'vim che fa il lavoro utilizzando un file temporaneo, che scrive avanti e indietro in modo automatico.

Alcuni anni fa ho trovato un plug-in simile che ho adattato e migliorato per uso personale. Ho incluso il codice pertinente per quello qui, nel caso qualcuno lo voglia. Anch'esso si basa sullo strumento xxd. Sono sicuro che la versione di GitHub che ho linkato sopra funzioni meglio, ma in realtà non l'ho usata da sola, quindi ho pensato di pubblicare anche questa che so per certo che funziona.

La fonte di questa altra versione era la vim wikia, in particolare questa pagina .

Ecco il codice:

"-------------------------------------------------------------------------------  
" Hexmode  
"-------------------------------------------------------------------------------  
" Creates an automatic hex viewing mode for vim by converting between hex dump  
" and binary formats. Makes editing binary files a breeze.  
"-------------------------------------------------------------------------------  
" Source: vim.wikia.com/wiki/Improved_Hex_editing  
" Author: Fritzophrenic, Tim Baker  
" Version: 7.1  
"-------------------------------------------------------------------------------  
" Configurable Options {{{1  
"-------------------------------------------------------------------------------  

" Automatically recognized extensions  
let s:hexmode_extensions = "*.bin,*.exe,*.hex"  

"-------------------------------------------------------------------------------
" Commands and Mappings {{{1
"-------------------------------------------------------------------------------

" ex command for toggling hex mode - define mapping if desired
command! -bar Hexmode call ToggleHex()
command! -nargs=0 Hexconfig edit $VIM\vimfiles\plugin\hexmode.vim | exe "normal 11G" | exe "normal zo"

nnoremap <C-H> :Hexmode<CR>
inoremap <C-H> <Esc>:Hexmode<CR>
vnoremap <C-H> :<C-U>Hexmode<CR>

"-------------------------------------------------------------------------------    
" Autocommands {{{1  
"-------------------------------------------------------------------------------  

if exists("loaded_hexmode")  
    finish  
endif  
let loaded_hexmode = 1  

" Automatically enter hex mode and handle file writes properly  
if has("autocmd")  
  " vim -b : edit binary using xxd-format  
  augroup Binary  
    au!  

    " set binary option for all binary files before reading them  
    exe "au! BufReadPre " . s:hexmode_extensions . " setlocal binary"

    " if on a fresh read the buffer variable is already set, it's wrong
    au BufReadPost *
          \ if exists('b:editHex') && b:editHex |
          \   let b:editHex = 0 |
          \ endif

    " convert to hex on startup for binary files automatically
    au BufReadPost *
          \ if &binary | Hexmode | endif

    " When the text is freed, the next time the buffer is made active it will
    " re-read the text and thus not match the correct mode, we will need to
    " convert it again if the buffer is again loaded.
    au BufUnload *
          \ if getbufvar(expand("<afile>"), 'editHex') == 1 |
          \   call setbufvar(expand("<afile>"), 'editHex', 0) |
          \ endif

    " before writing a file when editing in hex mode, convert back to non-hex
    au BufWritePre *
          \ if exists("b:editHex") && b:editHex && &binary |
          \  let oldro=&ro | let &ro=0 |
          \  let oldma=&ma | let &ma=1 |
          \  silent exe "%!xxd -r" |
          \  let &ma=oldma | let &ro=oldro |
          \  unlet oldma | unlet oldro |
          \ endif

    " after writing a binary file, if we're in hex mode, restore hex mode
    au BufWritePost *
          \ if exists("b:editHex") && b:editHex && &binary |
          \  let oldro=&ro | let &ro=0 |
          \  let oldma=&ma | let &ma=1 |
          \  silent exe "%!xxd" |
          \  exe "set nomod" |
          \  let &ma=oldma | let &ro=oldro |
          \  unlet oldma | unlet oldro |
          \ endif
  augroup END  
endif  

"-------------------------------------------------------------------------------
" Functions {{{1
"-------------------------------------------------------------------------------

" helper function to toggle hex mode
function! ToggleHex()
  " hex mode should be considered a read-only operation
  " save values for modified and read-only for restoration later,
  " and clear the read-only flag for now
  let l:modified=&mod
  let l:oldreadonly=&readonly
  let &readonly=0
  let l:oldmodifiable=&modifiable
  let &modifiable=1
  if !exists("b:editHex") || !b:editHex
    " save old options
    let b:oldft=&ft
    let b:oldbin=&bin
    " set new options
    setlocal binary " make sure it overrides any textwidth, etc.
    let &ft="xxd"
    " set status
    let b:editHex=1
    " switch to hex editor
    set sh=C:/cygwin/bin/bash
    %!xxd
  else
    " restore old options
    let &ft=b:oldft
    if !b:oldbin
      setlocal nobinary
    endif
    " set status
    let b:editHex=0
    " return to normal editing
    %!xxd -r
  endif
  " restore values for modified and read only state
  let &mod=l:modified
  let &readonly=l:oldreadonly
  let &modifiable=l:oldmodifiable
endfunction

" vim: ft=vim:fdc=2:fdm=marker
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.