Bagaimana cara mengedit file biner dengan Vim?


77

Apakah ada cara untuk mengedit file biner dalam semacam mode heksadesimal?

Sebagai contoh jika saya memiliki beberapa data biner yang ditunjukkan oleh xxdatau hexdump -Cseperti ini:

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

Jika saya ingin mengubah nilai pada posisi tertentu, pandangan semacam ini akan membantu menemukan tempat yang tepat, misalnya ketika posisi untuk berubah dekat dengan beberapa string yang dikenal.

Jawaban:


89

Cara paling sederhana adalah dengan menggunakan binaryopsi. Dari :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.

Jika Anda tidak melakukan ini, dan lingkungan Anda menggunakan pengkodean multibyte (misalnya UTF-8, seperti yang digunakan kebanyakan orang), Vim mencoba menyandikan teks seperti itu, biasanya mengarah ke file korupsi.

Anda dapat memverifikasi ini dengan membuka file, dan hanya menggunakan :w. Sekarang sudah berubah.
Jika Anda mengatur LANGdan LC_ALLke C(ASCII), Vim tidak mengonversi apa pun dan file tetap sama (tetap menambahkan baris baru) karena Vim tidak perlu melakukan pengkodean multibyte apa pun.

Saya pribadi juga lebih memilih untuk menonaktifkan set wrap biner, meskipun orang lain mungkin lebih suka mengaktifkannya . YMMV. Hal lain yang bermanfaat untuk dilakukan adalah :set display=uhex. Dari :help 'display':

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

Dan sebagai tip terakhir, Anda dapat menunjukkan nilai hex karakter di bawah kursor dalam penggaris dengan %B( :set rulerformat=0x%B).

Lebih maju: xxd

Anda dapat menggunakan xxd(1)alat ini untuk mengonversi file ke format yang lebih mudah dibaca, dan (ini adalah bagian penting), parsing "format yang dapat dibaca" yang diedit dan tulis kembali sebagai data biner. xxdadalah bagian dari vim, jadi jika Anda telah vimmenginstal Anda juga harus memiliki xxd.

Untuk menggunakannya:

$ xxd /bin/ls | vi -

Atau jika Anda sudah membuka file, Anda dapat menggunakan:

:%!xxd

Sekarang buat perubahan Anda, Anda perlu melakukan itu di sisi kiri layar (angka hex), perubahan ke sisi kanan (representasi yang dapat dicetak) diabaikan saat menulis.

Untuk menyimpannya, gunakan xxd -r:

:%!xxd -r > new-ls

Ini akan menyimpan file new-ls.

Atau untuk memuat biner di buffer saat ini:

:%!xxd -r

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

Dan kemudian gunakan :wuntuk menulisnya. ( hati-hati : Anda ingin mengatur binary opsi sebelum menulis ke file, untuk alasan yang sama menguraikan di atas).

Ikatan pelengkap untuk membuatnya lebih mudah:

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

Ini juga tersedia dari menu jika Anda menggunakan gVim, di bawah 'Alat ➙ Konversi ke HEX' dan 'Alat ➙ Konversi kembali'.

The kiat vim wiki memiliki halaman dengan informasi lebih lanjut dan beberapa skrip pembantu. Secara pribadi, saya pikir Anda mungkin lebih baik menggunakan hex editor nyata jika Anda sering mengedit file biner. Vim dapat melakukan pekerjaan itu, tetapi jelas tidak dirancang untuk itu, dan jika Anda pernah menulis tanpa :set binaryVim dapat merusak file biner Anda!


4
Jawaban yang bagus, tetapi mungkin harus dimulai dengan "Jangan coba ini di rumah, anak-anak!"
msw

Bagaimana jika saya perlu menghapus beberapa byte? misal di tengah-tengah biner.
Anton K

Saya tidak tahu apa yang dilakukan Vim, tetapi menambahkan 95KB teks ke file biner 200KB meskipun saya tidak mengubah apa pun. Bahkan dengan :set binary noeol fenc=utf-8. Bahkan, ia melakukannya segera setelah membuka file sebelum dikatakan [noeol] [converted]. Mengapa vim perlu membuat buffer 150% lebih besar? Bagaimana saya mencegahnya merusak file seperti itu?
Braden Best

Satu-satunya hal yang berhasil adalah :r !xxd <file>(atau $ xxd <file> | vim -) membaca, dan :w !xxd -r > <file>menulis, tetapi ini tidak ideal.
Braden Best

Jawaban yang sangat bagus. Perhatikan bahwa url untuk memberkati tidak berfungsi; Saya menemukannya (saya pikir) di github di github.com/bwrsandman/Bless .
sonofagun

19

Untuk melihat konten file biner dalam tampilan hex, buka file, aktifkan mode biner, dan filter buffer melalui xxdperintah:

:set binary
:%!xxd

Anda dapat membuat perubahan di area kiri (mengedit nomor hex), dan ketika siap, filter melalui xxd -r, dan akhirnya simpan file:

:%!xxd -r
:w

Jika langkah penyaringan setelah membuka dan sebelum menutup terdengar membosankan, dan Anda sering melakukan ini dengan file dengan .binekstensi, Anda dapat menambahkan ini ke vimrc Anda untuk membuat proses otomatis:

" 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

Jika saya ikuti petunjuk ini (membuka file biner, :%!xxd, :%!xxd -r, :w, didnt membuat perubahan!) Maka file biner tertulis tidak sama dengan aslinya ... Ini adalah kasus untuk Anda (saya diuji dengan /bin/ls). Saya perlu menggunakan :set binarysebelum menyimpan (juga lihat jawaban saya yang menjelaskan mengapa) ... Mungkin ada sesuatu di vimrc saya? Tapi bagaimanapun, saya akan selalu menggunakan set binaryuntuk keselamatan ...
Martin Tournoij

1
Sebagai gantinya, Anda dapat menambahkan augroupskrip ~/.vim/plugin/binary.vimjika Anda tidak ingin mengacaukan.vimrc
thom_nic

Jika Anda menggunakan pemasangan asing, augroup Binarycantuman itu berlokasi di :help hex-editingatau :help using-xxddi Vim mana pun sejak 5,5 (Sep 1999).
bb010g

6

Gunakan editor "bvi". http://bvi.sourceforge.net/ (Ada di setiap repositori 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
Alternatif yang lebih maju adalah bviplus, yang memiliki kontrol vim.
Anton K


3

TL; DR Jawab

Buka file dengan Vim dalam mode biner:

vim -b <file_to_edit>

Di Vim, masuk ke mode edit hex seperti:

:%!xxd -p

Untuk menyimpan:

:%!xxd -p -r
:w

Ini akan mengubah buffer kembali dari mode hex dan kemudian menyimpan file seperti biasa.

Perhatikan opsi -p. Ini menghindari semua bulu cetak dan alamat tambahan dan hanya menampilkan hex. Abaikan saja -p jika Anda menginginkan konteks tambahan.

Hati-hati membuka file dengan Vim tidak dalam mode biner, karena akan menambahkan karakter LF (biasanya tidak disengaja) ke akhir file ketika Anda menyimpannya.


Ini tidak benar-benar menambahkan apa pun yang tidak ada di jawaban lain.
Herb Wolfe

5
TL; DR sebenarnya ada :h using-xxddan sudah ada sejak v7.0001dan mungkin lebih lama. Situs ini akan menjadi kurang aktif jika orang mencari dokumen.
Tommy A

1

Ini terlihat seperti plugin vim kecil yang berguna yang melakukan pekerjaan menggunakan file sementara yang ditulisnya bolak-balik untuk Anda secara otomatis.

Beberapa tahun yang lalu saya menemukan plugin serupa yang saya adaptasi dan tingkatkan untuk saya gunakan sendiri. Saya telah memasukkan kode yang relevan untuk itu di sini, kalau-kalau ada yang menginginkannya. Itu juga didasarkan pada alat xxd. Saya yakin versi GitHub yang saya tautkan di atas berfungsi lebih baik, tetapi saya belum benar-benar menggunakannya sendiri, jadi saya pikir saya juga akan memposting yang ini yang saya tahu pasti berfungsi.

Sumber untuk versi lain ini adalah wiki vim, khususnya halaman ini .

Ini kodenya:

"-------------------------------------------------------------------------------  
" 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
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.