Použití takzvaného hex-editoru přichází na scénu zpravidla v případě potřeby úpravy binárních dat, případně k formátovanému náhledu na daná data. Popřípadě, pokud chceme rychle přes ssh upravit pár znaků v souboru, s ne příliš rozšířeným kódováním, kde například běžná konverze (pomocí iconv) znakové sady není možná, nebo otestovat svůj program či skript na konkrétních vstupních datech ze souboru.
O co jde?
Samotná zkratka 'hex' vychází z označení šestnáctkové neboli hexadecimální soustavy. Pro stručnost a jednoduchost zápisu bývá právě tato soustava vybrána jako výchozí pro editaci či k náhledu na binární data. Nicméně řada hex-editorů pro zobrazení dat nabízí i možnost použití soustav o jiném než šestnáctkovém základě (např. dvojkovém či osmičkovém). V takovém případě můžeme primární funkci editoru spojit i s převodem mezi těmito soustavami.
Vnitřní reprezentace a kódování souborů
Veškeré soubory a data jsou vnitřně v počítači reprezentovány za pomocí bajtů (nejmenší adresovatelná jednotka zápisu a čtení neboli jeden znak) jako binární. Bajt je zpravidla definován pomocí podmnožiny 8 bitů, jedním z 256 různých znaků či dvěma znaky (a na toto se zejména zaměříme při hex-editaci) z podmnožin 0..9; A..F v takzvané šestnáctkové soustavě.
Základní převod bajtů do šestnáctkové soustavy můžeme dohledat například za pomoci ASCII tabulky nebo už často přímo v prostředí samotného hex-editoru, který kromě pohledu zjednodušujících soustav pro editaci nabízí – pro lepší orientaci – i zjednodušenou prezentaci ve formě ASCII znaků.
Pro případ potřeby (například u neinteraktivního editoru / konvertoru) poslouží ASCII tabulka, která obsahuje základní popis a převod znaků. Případně můžeme využít také manuálovou stránku (příkaz man ascii
, pro jednotlivá rozšíření man iso_8859-1, iso_8859-2...
).
Neopomeňme ale, že uložená data mohou být dále „zaobalena“ pomocí dalšího kódování (UTF-16...), v takovém případě doporučuji si například na Internetu či v manuálu dohledat i odpovídající tabulku vnitřního kódování samotného souboru. K identifikaci konkrétního kódování nám může posloužit například příkaz file
soubor.
Než se ale pustíme do binární editace, doporučuji si veškerá vstupní data zazálohovat. A teď už k samotné editaci.
Hex-editace v prostředí editoru Vim, za pomocí rozšíření xxd
Vim
neboli vylepšená verze editoru Vi
nabízí jako součást balíku vim-common
(popř. vim-base
) rozšiřující přídavek xxd
. Nejedná se o plnohodnotný hex-editor, ale pouze o transformaci (včetně té zpětné) či filtr. S využitím nástrojů pro editaci takto převedených souborů ovšem zůstává veškerá funkcionalita jednoduchého hex-editoru zachována. Toto rozšíření můžeme aktivovat již v samotném editoru Vim
příkazem:
:%!xxd
Defaultní pohled v módu editace xxd
(zadáno bez parametrů) se zleva doprava skládá ze sedmiciferné hexadecimální adresy neboli ofsetu, která udává aktuální pozici v souboru, oddělené dvojtečkou. Dále je zde osm datových sloupců v hexadecimální podobě po dvou bajtech (oktetech), určených k zobrazení binárních dat a k jejich editaci. Úplně napravo se nachází šestnáct znaků ve formě ASCII ke zjednodušenému náhledu. Pro další formy zobrazení doporučuji nahlédnout do manuálu příkazu xxd
.
0000000: 5465 7374 2066 696c 652c 2056 696d 2078 Test file, Vim x 0000010: 7864 2064 6566 6175 6c74 2076 6965 772e xd default view. 0000020: 0a .
Po editaci a před uložením převedeme soubor zpátky do jeho původní formy, pomocí (A teď pozor, ať si nepřepíšeme originální soubor s jeho hexadecimální podobou. V takovém případě můžeme vše ale ještě napravit za pomoci terminálového příkazu) xxd -r hexaedited-file > originalform-file
):
:%!xxd -r
Nutno dodat, že manuální přepínání hexadecimálního módu není zrovna intuitivní. Pomoci si můžeme ale menšími úpravami či makry.
Pro editaci menších souborů může být tato metoda plně dostačující. V případě větších souborů může celková konverze do hexadecimální podoby trvat opravdu hodně dlouho, zatímco program neposkytuje žádné průběžné informace o již konvertovaných datech.
Můžeme si trochu pomoci oddělením částí souboru, které nás nejvíce zajímají a následným zpětným spojením (příkazy head, tail, split, dd
a cat
), případně přímo v rozšíření xxd
využitím přepínačů -p
(zjednodušený hexadecimální výstup bez ofsetů a ASCII znaků), -seek
(přeskočí zadaný počet bajtů) a -len
(vypíše pouze zadaný počet znaků). Nicméně druhý způsob vyžaduje čekání, než editor Vim
načte a zobrazí celý původní soubor, což může opět u velkých souborů trvat poměrně dlouho.
Pozor: Při ukládání v módu -seek a -len se ale uloží pouze aktuální výsek z původně načtených dat.
Příklad: :%!xxd -seek 8 -l 16
(přeskočí prvních 8 bajtů, oktetů a vypíše následujících 16)
0000008: 652c 2056 696d 2078 7864 2064 6566 6175 e, Vim xxd defau
Pokud chceme editaci dále urychlit, nabízí se možnost použití příkazu xxd
přímo v terminálu.
Hex-editace v terminálu
V případě, že si chceme práci urychlit nebo třeba naskriptovat, můžeme k binární úpravě použít příkaz xxd
přímo v terminálu. Syntaxe zůstává stejná (xxd
pro hexadecimální pohled, xxd -r
pro zpětnou konverzi). Pro úpravy doporučuji však použít zjednodušený hexadecimální mód xxd -p
a xxd -r -p
pro návrat, který je díky absenci ofsetů a ASCII znakové reprezentace poměrně vhodný pro provádění globálních úprav (vyhledávání v souboru a přepisování).
Příklad: Zkopírujeme prvních 25 bajtů ze souboru file
do file.1
. Zbývající bajty (8) téhož souboru převedeme do hexadecimální podoby a uložíme do souboru file.0x
. Následně po úpravě (pomocí příkazu sed
) obě části souboru zase spojíme.
head -c 25 file > file.1 && tail -c 8 file | xxd -p > file.0x
Úpravu hexadecimální prezentace v souboru file.0x
nyní můžeme provést v libovolném textovém editoru. Například opět v editoru Vim
, nebo terminálovým příkazem sed
, awk
atd.
V našem případě nahradíme všechny řetězce 'view' za řetězce 'mode' pomocí příkazu sed
.
echo -n mode | xxd -p
Vypíše hexadecimální podobu slova mode
, v tomto případě 6d6f6465
. Stejně postupujeme u slova view
.
Nyní můžeme, například pomocí příkazu sed
, nahradit všechny výskyty slova view
za slovo mode
.
sed -i 's/76696577/6d6f6465/g' file.0x
Následně pomocí xxd provedeme zpětnou konverzi z hex. formy do původní podoby souboru.
xxd -r -p file.0x > file.2
Nakonec spojíme všechny části, vzniklé rozdělením původního souboru, do souboru file.new
.
cat file.1 file.2 > file.new
K samotnému převodu do hexadecimální podoby můžeme použít namísto xxd
také příkazy hexdump, hd
(to stejné jako hexdump -C
), popřípadě od
, které jsou součástí většiny linuxových distribucí a poskytují rozšířené možnosti formátování a náhledu.
Ke zpětné konverzi je ale potřeba opět použít xxd -r
, protože zpětnou konverzi tyto příkazy neovládají. Je proto potřeba výsledný formát dat ještě před navrácením do původní podoby sjednotit s formátem, který xxd
zná. Těmito příkazy si tedy práci s editací binárních dat neusnadníme. Můžeme si ovšem rozšířit možnosti náhledu na binární data.
hexdump -ve '1/1 "%.2x"' file > file.0x
Opět v libovolném editoru upravíme hexadecimální prezentaci v souboru file.0x
.
xxd -r -p file.0x > file.new
Escape sekvence
Na závěr této kapitoly bych rád zmínil možnost hex-editace bez použití xxd, pomocí escape sekvencí shellu.
Možnost zadání ASCII hodnoty je zabudována již v samotném Bourne shellu (sh) a pozdějších implementacích, například pomocí escape sekvence \nnn, jenž se skládá z 1-3 cifer v osmičkové soustavě. K převodu do osmičkové soustavy můžeme použít příkaz printf %o \'znak
.
Od Bourne-again shellu a z něj odvozených implementací (bash, zsh) můžeme použít escape sekvence již v hexadecimální podobě. Hex-editaci lze provádět například příkazy echo
, sed
a dd
. Součástí escape sekvencí (v podobě jednoho ASCII znaku) je v tomto případě zadávání v osmičkové, šestnáctkové (\xHH), ale také formou unicode.
Pro více informací doporučuji nahlédnout na man bash /QUOTING
. Podobné escape sekvence můžeme použít například i v editoru Vim, bez xxd, pro přímou náhradu binárních řetězců: :%s/\%x76\%x69\%x65\%x77/mode/g
.
Příklad náhrady všech řetězců 'mode' za řetězce 'view':
sed -i 's/\x76\x69\x65\x77/\x6d\x6f\x64\x65/g' file
K hexadecimálnímu převodu můžeme použít ASCII tabulku, xxd -p, anebo převod provést po jednotlivých písmenech příkazem shellu: printf %x \'znak
.
Metoda echo a dd je použitelná i na mobilních zařízeních s OS Android, přes Android Debug Bridge (ADB) anebo terminálovou emulaci, popř. i u jiných unixových operačních systémů.
Příklad pro Android: Na pozici 5 v souboru file zapiš řetězec 'view':
./adb shell echo "\x76\x69\x65\x77" | dd conv=notrunc bs=1 seek=$((0x5)) of=file
Poznámka: Přepínač bs
(block size) příkazu dd
udává, po jakých blocích v bajtech budeme číst. Seek
přeskočí zadaný počet bloků a conv
je na Androidu standardně vypnutý. Bez conv=notrunc
příkaz odsekne veškerá data za modifikovanou pozicí! Je možné toto omezení obejít použitím např. dd od BusyBoxu.
Hex-editace pomocí editoru Bvi, Bview, bmore
Editor Bview
není standardní součástí linuxových distribucí a je třeba ho doinstalovat (pomocí apt-get install bvi
, yum install bvi
, popř. stáhnout – má pouze několik KB – či zkompilovat z oficiálních stránek). Bview
vychází z editoru Vim
, nicméně díky „kešování“ dat je práce v něm neporovnatelně rychlejší. Po spuštění ihned zobrazí hexadecimální podobu daného souboru.
Podobně jako xxd je schopen načtení pouze určitého úseku dat (není třeba načítat celý soubor), například pomocí přepínačů -s size
, -b begin
a -e end
:
bvi -s 4 read
Toto zobrazí pouze první 4 znaky:
bvi -b 1 -e 10 read
Zobrazí 10 znaků od začátku, počínaje druhým.
Při uložení se však neuloží pouze zobrazený úsek souboru, jako tomu bylo v případě transformace xxd
, ale ostatní data zůstanou zachována.
K editaci doporučuji použít přepisovací mód, buď jednoznakový r
, nebo plnohodnotný R
. Popřípadě mód připisování A
. Vkládací mód i, I
je defaultně vypnut. Vyhledávání oproti editoru Vim
doznalo několik změn, namísto práce s odstavci či řádky nyní pracujeme především s daty převedenými do hexadecimální podoby. Přepínání mezi hexadecimálním a ASCII pohledem je možno provádět pomocí klávesy TAB. Aktuální adresa (ofset) je vypsána vpravo dole. Napravo od ofsetu pak můžeme vidět prezentace znaku, na kterém se momentálně nachází kurzor, v nejrůznějších soustavách.
Jelikož jde o editor interaktivní, po provedení změny ihned v pravém sloupci vidíme, o jaký změněný ASCII znak se jedná. Oproti Vim
s přídavným filtrem xxd
zde ukládání nabízí jednu poměrně příjemnou změnu. Soubor již není třeba zpětně konvertovat z hexadecimální podoby do původní. Veškeré provedené změny se zapíší v původní podobě.
Příklad vyhledávání a náhrady řetězce xxd za řetězec bvi:
#787864 /xxd :%s/xxd/bvi/g :%s\78 78 64\62 76 69\g
Je možné jednotlivé hexadecimální dvojznaky oddělovat mezerou. První příkaz hledá hexadecimální podobu řetězce 'xxd'. (K dalšímu výskytu se přesuneme např. pomocí klávesy n
.)
Druhý hledá řetězec 'xxd' v pohledu pro ASCII prezentaci. Třetí podle stejného pohledu či klíče provede substituci všech řetězců 'xxd' za 'bvi'. Poslední příkaz dělá totéž, co ten předchozí (což není pravidlem), ale v hexadecimální podobě.
U automatické substituce je třeba dát si pozor, aby náhradní řetězec nebyl delší, než ten nahrazovaný. Jinak si totiž přepíšeme i část okolních dat. V případě, že je náhradní řetězec kratší, nahrazovaný řetězec zůstane nezkrácen. Příkaz undo u
si zase pamatuje pouze poslední změnu, ta však může být i klidně globální.
Pro případné další příklady použití doporučuji se podívat na oficiální stránky, sekce tutoriálů.
Součástí instalačního balíku je rovněž příkaz bmore
, poskytující podobný výstup jako xxd -g 1 | more
(v módu bmore -w 16
), pouze s trochu rozdílnou ofsetovou částí.
Hex-editace v prostředí editoru GNU Emacs
Zřejmě není třeba příliš dlouze představovat tento GNU GPLv2 editor, který, společně s editory vycházejícími z editoru Vi, patří mezi nejrozšířenější textové editory příkazové řádky, a to nejen na Linuxu. Přestože není standardní součástí všech linuxových distribucí, nalezneme jej ve většině oficiálních repozitářů (lze nainstalovat například pomocí příkazu sudo apt-get install emacs; yum install emacs
atd.), popřípadě lze stáhnout na stránkách gnu.org.
K dispozici máme buď GTK+ grafickou verzi editoru (obvykle název balíku emacs, bez přípony), popřípadě XEmacs (pro X-Windows). Čistě pro příkazovou řádku je určena verze emacs-nox, které se budeme následně věnovat.
Podobně jako editor Vim, nabízí také Emacs možnost hex-editace v prostředí samotného editoru; nikoli však už jako přídavný filtr. Hex-editor je zde zabudován jako nástroj editoru. Do módu hex-editace se můžeme přepnout vzájemným stiskem kláves M (neboli META klávesa, -zpravidla ALT) a x, následně zadáním příkazu hex-mode
, popř. hexl-mode
.
Nicméně tento způsob vyžaduje nejprve zobrazení souboru a následnou změnu módu. Rychlejší může být načtení souboru přímo v hexadecimálním módu, pomocí M-x
a příkazu hexl-find-file
. Na první pohled se prostředí editoru příliš neliší například od Bvi. Připomíná také interaktivní verzi editoru Vim s xxd, s tím rozdílem, že aktuální ukazatel v souboru je viditelně barevně označen a první řádek zobrazuje pozici kurzoru v samotném řádku.
Do nabídky menu se dostaneme pomocí klávesy F10, nebo dvojstiskem M-`
(kde leží klávesa tilda), či opět M-x
a příkazem menu-bar-open
. Následně si vybereme z klávesových zkratek v nabídce menu (například f
pro souborové menu), anebo šipkou na klávesnici a enterem. Mezi základní příkazy patří vyhledávání C-s
a náhrada řetězců M-%
(u automatické náhrady pozor, provedená změna se ihned nepromítne do pravého sloupce s ASCII zobrazením. Proto doporučuji provádět jednoznakové změny ručně, pomocí speciálních příkazů hexl módu (C-x, C-o,
...) viz informaci na stránce o editaci binárních souborů (zde je potom vše už v pořádku).
Na rozdíl od editoru Vim soubor již není třeba před uložením převádět do binární podoby. Asi největším omezením je však maximální velikost editovaného souboru, která díky vnitřnímu bufferování dat činí necelých 128 MB u 32bitové verze editoru. Toto omezení lze částečně obejít načtením pouze určité části původního souboru (viz příklad níže), nicméně následně je potřeba všechny části zase pospojovat, třeba pomocí příkazu cat. U 64bitové verze je tento limit už ale značně navýšen (259-1 bajtů).
Příklad načtení části souboru do aktuálního bufferu:
C-x b file-part C-u M-! tail -c 25 file C-x hexl-mode
V tomto případě si nejprve vytvoříme nový buffer pod jménem file-part a přepneme se do něj. Následně do aktuálního bufferu pomocí příkazu C-u
, příkazem M-!
načteme výsledek příkazu shellu: tail -c 25 file
, tedy posledních 25 bajtů ze souboru file. A nakonec se přepneme do hexadecimálního režimu.
Mimo tato omezení však působí prostředí samotného editoru poměrně příjemně, stabilně a přehledně. Práce v něm je poměrně rychlá.
Zhodnocení
Závěrem bych chtěl připomenout, že většina linuxových distribucí nabízí již standardně poměrně účinné nástroje k editaci binárních souborů v příkazové řádce. Uživatel si podle potřeby a osobních preferencí (je dobré vzhledem k velikosti souborů brát ohledy také na časové – v případě transformace xxd – a paměťové – Emacs – nároky editace) může vybrat mezi escape sekvencemi samotného shellu (či příkazem xxd
) a svým preferovaným textovým editorem z dvojice Vim nebo Emacs. A nakonec je zde také možnost doinstalovat i nějaký další ze svobodných hex-editorů, v této kategorii se zase nabízí poměrně rychlý a nenáročný editor Bview.
Tématem následujícího článku tohoto dvoudílného miniseriálu budou hex-editory s grafickým uživatelským rozhraním (pro KDE, GTK...).