Comment éditer des fichiers binaires avec Vim?

77

Existe-t-il un moyen de modifier des fichiers binaires en mode hexadécimal?

Par exemple, si j'ai des données binaires montrées par xxdou hexdump -Ccomme ceci:

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

Si je souhaite modifier la valeur à une position spécifique, ce type de vue vous aidera à trouver le bon emplacement, par exemple lorsque la position à modifier est proche d'une chaîne connue.

janos
la source

Réponses:

89

Le moyen le plus simple consiste à utiliser l' binaryoption. De :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.

Si vous ne le faites pas et que votre environnement utilise un codage multi-octets (par exemple, UTF-8, comme le font la plupart des utilisateurs), Vim tente de coder le texte en tant que tel, ce qui entraîne généralement une corruption du fichier.

Vous pouvez le vérifier en ouvrant un fichier et en utilisant simplement :w. C'est maintenant changé.
Si vous définissez LANGet LC_ALLsur C(ASCII), Vim ne convertit rien et les fichiers restent identiques (il ajoute néanmoins une nouvelle ligne), car Vim n'aura pas besoin de codage multi-octets.

Personnellement, je préfère aussi désactiver set wrap pour le binaire, bien que d’autres préfèrent l’ activer . YMMV. Une autre chose utile à faire est :set display=uhex. De :help 'display':

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

Et comme dernier conseil, vous pouvez afficher la valeur hexadécimale du caractère situé sous le curseur dans la règle avec %B( :set rulerformat=0x%B).

Plus avancé: xxd

Vous pouvez utiliser l' xxd(1)outil pour convertir un fichier dans un format plus lisible, et (c'est le bit important), analyser le "format lisible" édité et le réécrire sous forme de données binaires. xxdfait partie de vim, donc si vous avez viminstallé, vous devriez également avoir xxd.

Pour l'utiliser:

$ xxd /bin/ls | vi -

Ou si vous avez déjà ouvert le fichier, vous pouvez utiliser:

:%!xxd

Maintenant, apportez vos modifications. Vous devez le faire dans la partie gauche de l’affichage (les nombres hexadécimaux). Les modifications dans la partie droite (représentation imprimable) sont ignorées lors de l’écriture.

Pour le sauvegarder, utilisez xxd -r:

:%!xxd -r > new-ls

Cela enregistrera le fichier dans new-ls.

Ou pour charger le binaire dans le tampon courant:

:%!xxd -r

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

Et puis juste utiliser :wpour l'écrire. ( attention : vous souhaitez définir l' binary option avant d'écrire dans le fichier, pour les mêmes raisons que celles décrites ci-dessus).

Des clés complémentaires pour rendre cela un peu plus facile:

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

Ceci est également disponible dans le menu si vous utilisez gVim, sous «Outils Convertir en HEX» et «Outils Convertir en arrière».

Le wiki vim tips a une page avec plus d’informations et des scripts d’aide. Personnellement, je pense que vous feriez probablement mieux d'utiliser un véritable éditeur hexadécimal si vous modifiez souvent des fichiers binaires. Vim peut en quelque sorte faire le travail, mais ce n’est évidemment pas conçu pour cela, et si jamais vous écrivez sans :set binaryVim, vos fichiers binaires seront détruits!

Martin Tournoij
la source
4
Belle réponse, mais devrait probablement commencer par "N'essayez pas cela à la maison, les enfants!"
msw
Que faire si j'ai besoin de supprimer des octets? par exemple au milieu du binaire.
Anton K
Je ne sais pas ce que fait Vim, mais cela ajoute 95 Ko de texte à un fichier binaire de 200 Ko alors que je n'ai rien changé. Même avec :set binary noeol fenc=utf-8. En fait, il le fait immédiatement après l'ouverture du fichier avant que cela ne soit indiqué [noeol] [converted]. Pourquoi vim doit-il agrandir le tampon de 150%? Comment puis-je l'empêcher de corrompre des fichiers comme ça?
Braden Best
La seule chose qui fonctionne est :r !xxd <file>(ou $ xxd <file> | vim -) lire et :w !xxd -r > <file>écrire, mais ce n’est pas idéal.
Braden Best
Excellente réponse. Notez que l'URL pour bénir ne fonctionne pas; Je l'ai trouvé (je pense) sur github à github.com/bwrsandman/Bless .
Sonofagun
19

Pour afficher le contenu d'un fichier binaire dans une vue hexadécimale, ouvrez-le, activez le mode binaire et filtrez le tampon à l'aide de la xxdcommande:

:set binary
:%!xxd

Vous pouvez apporter des modifications dans la zone de gauche (éditer les nombres hexadécimaux) et, une fois prêt, filtrer xxd -ret enfin enregistrer le fichier:

:%!xxd -r
:w

Si l'étape de filtrage après l'ouverture et avant la fermeture vous semble fastidieuse, et que vous le faites souvent avec des fichiers avec une .binextension, vous pouvez l'ajouter à votre vimrc pour automatiser le processus:

" 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
la source
Si je suivre les instructions suivantes (ouvrir un fichier binaire, :%!xxd, :%!xxd -r, :w, na pas apporter des modifications!) Le fichier binaire écrit est pas le même que l'original ... Est - ce le cas pour vous (je l' ai testé avec /bin/ls). J'ai besoin d'utiliser :set binaryavant de sauvegarder (voir aussi ma réponse qui explique pourquoi) ... Peut-être que c'est quelque chose dans mon vimrc? Mais peu importe, j'utiliserais toujours set binarypour la sécurité ...
Martin Tournoij
1
Vous pouvez plutôt ajouter le augroupscript à ~/.vim/plugin/binary.vimsi vous ne souhaitez pas encombrer votre.vimrc
thom_nic
Si vous êtes sur une installation étrangère, cette augroup Binaryliste est située dans :help hex-editingou :help using-xxddans n’importe quel Vim depuis la version 5.5 (septembre 1999).
bb010g
6

Utilisez l'éditeur "bvi". http://bvi.sourceforge.net/ (il se trouve dans tous les référentiels 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.
RonJohn
la source
1
Une alternative plus avancée est bviplus, qui a des contrôles vim.
Anton K
Page d' accueil Bviplus et captures d'écran .
Iulian Onofrei
3

Réponse de TL; DR

Ouvrez le fichier avec Vim en mode binaire:

vim -b <file_to_edit>

Dans Vim, passez en mode d'édition hexadécimale comme ceci:

:%!xxd -p

Sauver:

:%!xxd -p -r
:w

Cela reconvertira le tampon du mode hexadécimal, puis sauvegardera le fichier normalement.

Notez l'option -p. Cela évite tous les bourrages d'adresse et d'adresses imprimables et vous montre juste l'hex. Oubliez simplement -p si vous voulez le contexte supplémentaire.

Soyez prudent lorsque vous ouvrez le fichier avec Vim non en mode binaire, car cela ajoutera un caractère LF (généralement non souhaité) à la fin du fichier lorsque vous l'enregistrez.

Hintron
la source
Cela n'ajoute vraiment rien qui ne soit dans les autres réponses.
Herb Wolfe
5
Le vrai TL; DR est dedans :h using-xxdet a été autour depuis v7.0001et probablement plus longtemps. Ce site serait moins actif si les gens cherchaient dans la documentation.
Tommy Un
1

Cela ressemble à un petit plugin vim très pratique qui fait le travail en utilisant un fichier temporaire qu’il écrit automatiquement pour vous.

Il y a quelques années, j'ai trouvé un plugin similaire que j'ai adapté et amélioré pour mon propre usage. J'ai inclus le code correspondant à cela ici, au cas où quelqu'un le voudrait. Il est également basé sur l'outil xxd. Je suis sûr que la version de GitHub que j'ai liée ci-dessus fonctionne mieux, mais je ne l'ai pas utilisée moi-même. Je me suis donc dit que je publierais aussi celle-ci qui, je le sais, fonctionne.

La source de cette autre version était vim wikia, plus précisément cette page .

Voici le 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
la source