Wie bearbeite ich Binärdateien mit Vim?

77

Gibt es eine Möglichkeit, Binärdateien im Hexadezimalmodus zu bearbeiten?

Zum Beispiel , wenn ich einige binäre Daten durch gezeigt xxdoder hexdump -Cwie folgt aus :

$ 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  ................

Wenn ich den Wert an einer bestimmten Position ändern möchte, hilft diese Art der Ansicht dabei, die richtige Stelle zu finden, z. B. wenn sich die zu ändernde Position in der Nähe einer bekannten Zeichenfolge befindet.

janos
quelle

Antworten:

89

Am einfachsten ist es, die binaryOption zu verwenden. Von :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.

Wenn Sie dies nicht tun und Ihre Umgebung eine Multibyte-Codierung verwendet (z. B. UTF-8, wie es die meisten Leute verwenden), versucht Vim, den Text als solchen zu codieren, was normalerweise zu Dateibeschädigungen führt.

Sie können dies überprüfen, indem Sie eine Datei öffnen und einfach verwenden :w. Es ist jetzt geändert.
Wenn Sie LANGund LC_ALLauf C(ASCII) setzen, konvertiert Vim nichts und die Dateien bleiben gleich (es wird jedoch immer noch ein Zeilenumbruch eingefügt), da Vim keine Multibyte-Codierung durchführen muss.

Ich persönlich bevorzuge auch die Deaktivierung set wrap für Binärdateien, obwohl andere es vielleicht vorziehen, sie zu aktivieren . YMMV. Eine weitere nützliche Sache ist :set display=uhex. Von :help 'display':

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

Und als letzten Tipp können Sie den Hex-Wert des Zeichens unter dem Cursor im Lineal mit %B( :set rulerformat=0x%B) anzeigen .

Fortgeschrittener: xxd

Mit dem xxd(1)Tool können Sie eine Datei in ein besser lesbares Format konvertieren und (dies ist das wichtige Bit) das bearbeitete "lesbare Format" analysieren und als Binärdaten zurückschreiben. xxdist ein Teil von vim, also wenn Sie viminstalliert haben, sollten Sie auch haben xxd.

Um es zu benutzen:

$ xxd /bin/ls | vi -

Wenn Sie die Datei bereits geöffnet haben, können Sie Folgendes verwenden:

:%!xxd

Nehmen Sie nun Ihre Änderungen vor, Sie müssen dies auf der linken Seite des Displays tun (die Hex-Zahlen), Änderungen auf der rechten Seite (druckbare Darstellung) werden beim Schreiben ignoriert.

Verwenden Sie zum Speichern Folgendes xxd -r:

:%!xxd -r > new-ls

Dadurch wird die Datei in gespeichert new-ls.

Oder um die Binärdatei in den aktuellen Puffer zu laden:

:%!xxd -r

Von 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.

Und dann benutze :wes einfach , um es zu schreiben. ( Achtung : Sie möchten die binary Option vor dem Schreiben in die Datei aus denselben Gründen wie oben festlegen ).

Komplementäre Tastenkombinationen, um dies ein bisschen einfacher zu machen:

" 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>

Dies ist auch über das Menü verfügbar, wenn Sie gVim verwenden, und zwar unter "Extras"> "In HEX konvertieren" und "Extras"> "Zurück konvertieren".

Das Vim Tips Wiki hat eine Seite mit mehr Informationen und einigen Hilfsskripten. Persönlich denke ich, dass Sie mit einem echten Hex-Editor wahrscheinlich besser dran sind, wenn Sie so oft Binärdateien bearbeiten. Vim kann die Arbeit erledigen, aber es ist offensichtlich nicht dafür ausgelegt, und wenn Sie jemals ohne :set binaryVim schreiben , können Ihre Binärdateien zerstört werden!

Martin Tournoij
quelle
4
Schöne Antwort, sollte aber wahrscheinlich mit "Versuchen Sie das nicht zu Hause, Kinder!" Beginnen.
msw
Was ist, wenn ich einige Bytes entfernen muss? zB in der Mitte der Binärdatei.
Anton K
Ich weiß nicht, was Vim tut, aber es fügt einer 200-KB-Binärdatei 95 KB Text hinzu, obwohl ich nichts geändert habe. Auch mit :set binary noeol fenc=utf-8. Tatsächlich wird dies sofort beim Öffnen der Datei ausgeführt, bevor die Meldung erscheint [noeol] [converted]. Warum muss vim den Puffer 150% größer machen? Wie verhindere ich, dass solche Dateien beschädigt werden?
Braden Best
Das einzige, was funktioniert, ist :r !xxd <file>(oder $ xxd <file> | vim -) zu lesen und :w !xxd -r > <file>zu schreiben, aber das ist nicht ideal.
Braden Best
Hervorragende Antwort. Beachten Sie, dass die URL für den Segen nicht funktioniert. Ich habe es (glaube ich) auf github unter github.com/bwrsandman/Bless gefunden .
sonofagun
19

Um den Inhalt einer Binärdatei in einer Hex-Ansicht anzuzeigen, öffnen Sie die Datei, aktivieren Sie den Binärmodus und filtern Sie den Puffer mithilfe des xxdBefehls:

:set binary
:%!xxd

Sie können Änderungen im linken Bereich vornehmen (die Hex-Zahlen bearbeiten) und, wenn Sie fertig sind, xxd -rdie Datei filtern und schließlich speichern:

:%!xxd -r
:w

Wenn der Filterschritt nach dem Öffnen und vor dem Schließen mühsam klingt und Sie dies häufig mit Dateien mit der .binErweiterung tun , können Sie dies zu Ihrem vimrc hinzufügen, um den Prozess automatisch zu machen:

" 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
janos
quelle
Wenn ich diesen Anweisungen (öffnen Binärdatei, folgen :%!xxd, :%!xxd -r, :w, nur knapp sein Ziel Änderungen vornehmen!) , Dann die Binärdatei geschrieben ist nicht das gleiche wie das Original ... Ist dies der Fall für Sie (ich getestet /bin/ls). Ich muss :set binaryvor dem Speichern verwenden (siehe auch meine Antwort, die erklärt, warum) ... Vielleicht ist es etwas in meinem vimrc? Aber egal, ich würde immer set binaryfür die Sicherheit verwenden ...
Martin Tournoij
1
Sie können stattdessen das augroupSkript hinzufügen , ~/.vim/plugin/binary.vimwenn Sie nicht möchten, dass Ihre.vimrc
thom_nic
Wenn Sie auf einem fremden sind installieren, dass augroup Binarysich die Auflistung am befindet :help hex-editingoder :help using-xxdin einem der Vim seit 5.5 (September 1999).
bb010g
6

Verwenden Sie den "bvi" -Editor. http://bvi.sourceforge.net/ (Es ist in jedem Linux-Repository.)

$ 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.
RonJohn
quelle
1
Weiterentwickelte Alternative ist bviplus, das über vim-Steuerelemente verfügt.
Anton K
Bviplus Homepage und Screenshots .
Iulian Onofrei
3

TL; DR Antwort

Öffnen Sie die Datei mit Vim im Binärmodus:

vim -b <file_to_edit>

Gehen Sie in Vim wie folgt in den Hex-Bearbeitungsmodus:

:%!xxd -p

Speichern:

:%!xxd -p -r
:w

Dadurch wird der Puffer wieder aus dem Hex-Modus konvertiert und die Datei wie gewohnt gespeichert.

Beachten Sie die Option -p. Dies vermeidet alle zusätzlichen Druck- und Adressflusen und zeigt Ihnen nur das Hex. Lassen Sie -p einfach weg, wenn Sie den zusätzlichen Kontext wünschen.

Öffnen Sie die Datei mit Vim nicht im Binärmodus, da beim Speichern ein (normalerweise nicht beabsichtigtes) LF-Zeichen an das Ende der Datei angehängt wird.

Hintron
quelle
Dies fügt nichts hinzu, was nicht in den anderen Antworten enthalten ist.
Herb Wolfe
5
Der echte TL; DR ist :h using-xxdund ist seit v7.0001und wahrscheinlich länger da. Diese Seite wäre weniger aktiv, wenn Leute die Dokumente durchsuchen würden.
Tommy A
1

Dies sieht aus wie ein handliches kleines VIM-Plugin, das die Arbeit mit einer temporären Datei erledigt, die es automatisch für Sie hin und her schreibt.

Vor einigen Jahren habe ich ein ähnliches Plugin gefunden, das ich für meinen eigenen Gebrauch angepasst und verbessert habe. Ich habe hier den entsprechenden Code eingefügt, falls jemand dies wünscht. Es basiert ebenfalls auf dem Tool xxd. Ich bin mir sicher, dass die GitHub-Version, die ich oben verlinkt habe, besser funktioniert, aber ich habe sie selbst nicht verwendet. Ich dachte, ich würde auch diese veröffentlichen, von der ich sicher weiß, dass sie funktioniert.

Die Quelle für diese andere Version war das Vim-Wiki, speziell diese Seite .

Hier ist der Code:

"-------------------------------------------------------------------------------  
" 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
Tim
quelle