Nahradenie hex stringu

Nahradenie hex stringu
« kdy: 08. 03. 2019, 17:49:31 »
Chcel by som poprosit o radu. Hladam nejaky linuxovy prikaz/program, ktorym sa da zautomatizovat (pouzit v scripte) nahradenie urciteho hex retazcu inym retazcom. Teda programu dam povodny retazec, novy retazec, nazov suboru a program urobi tuto zmenu priamo v subore, bez vytvarania noveho/upraveneho suboru. Povodny aj novy hex string ma rovnaku velkost, takze velkost suboru sa nezmeni a malo by to byt okamzite. Takisto by sa hodilo, aby program po prvom vyskyte/nahradeni uz nepokracoval zbytocne dalej v hladani stringu v celom subore (kedze subory su velke).

Viem, ze hex stringy sa daju nahradit napr. cez sed:
Kód: [Vybrat]
sed 's/\x0A\x0B/\x0C\x0D/g'Avsak sed aj pri pouziti moznosti in-place (-i) vytvara novy subor, co zbytocne predlzuje cas. Tiez je tu ten problem, ze ak hexstring obsahuje newline character (0x0A), tak sed s tym ma problem a nic nenahradi. Da sa toto nejak vyriesit?

Dakujem za tipy.


Re:Nahradenie hex stringu
« Odpověď #1 kdy: 08. 03. 2019, 19:32:27 »
Pokud jste už zkoušel takový program hledat a nic jste nenašel, asi takový program k nalezení nebude. Je to dost netypická úloha, takže pokud to někdo potřeboval, nejspíš si na to napsal nějaký jednorázový nástroj a nezveřejnil ho.

Ale asi by to šlo poskládat – pro přepis té části soubory by asi šlo použít dd, a pak už jde jen o to najít, kde ten řetězec v souboru začíná.

Jinak požadavek na to, aby to bylo okamžitě, obecně není splnitelný – na CoW souborovém systému se příslušný blok stejně bude muset zapsat na nové místo.
« Poslední změna: 08. 03. 2019, 19:38:14 od Filip Jirsák »

Re:Nahradenie hex stringu
« Odpověď #2 kdy: 09. 03. 2019, 01:53:08 »
No predpokladal som, ze nahradenie hex stringu v subore je vcelku trivialna a nie vynimocna zalezitost, takze ma celkom prekvapuje, ze na to nie je dostatok utilit...

Co sa tyka toho okamziteho zapisu, na Windows som pouzival HxD hexeditor, kde sa dal upravit priamo subor, tak som cakal, ze nieco podobne bude aj pre linux a v terminali...

Ink

  • *****
  • 654
    • Zobrazit profil
    • E-mail
Re:Nahradenie hex stringu
« Odpověď #3 kdy: 09. 03. 2019, 08:45:25 »
Bez zaruky a bez krasy:

#!/usr/bin/env python3

import sys

def findIndex(f, sa):
    ri = 0
    ra = []
    sl = len(sa)
    while True:
        try:
            b = f.read(1)
            if (len(b) == 0):
                raise EOFError()
            ra.append(b[0])
        except EOFError:
            return -1
        ri += 1
        if (len(ra) > len(sa)):
            ra.pop(0)
        if (ra == sa):
            return ri - sl


def write(f, index, s):
    f.seek(index)
    f.write(s)


def replace(fn, ih, oh):
    f = open(fn, "rb+")
    index = findIndex(f, list(bytes.fromhex(ih)))
    if (index == -1):
        print("Not found")
    else:
        write(f, index, bytes.fromhex(oh))
    f.close()


if __name__ == '__main__':
    if (len(sys.argv) != 4):
        print("Usage: %s filename inhex outhex", sys.argv[0])
    else:
        replace(sys.argv[1], sys.argv[2], sys.argv[3])

Re:Nahradenie hex stringu
« Odpověď #4 kdy: 09. 03. 2019, 10:27:10 »
No predpokladal som, ze nahradenie hex stringu v subore je vcelku trivialna a nie vynimocna zalezitost, takze ma celkom prekvapuje, ze na to nie je dostatok utilit...
Za triviální a nikoli výjimečnou záležitost je v unixu považováno dokonce nahrazení textu v proudu bajtů, přičemž proud bajtů je obecnější věc, než jen soubor. Takže utilit na to existuje spousta. Vy ale na tu náhradu máte speciální předpoklady a speciální požadavky, ty obecné nástroje tedy nechcete použít.

Co sa tyka toho okamziteho zapisu, na Windows som pouzival HxD hexeditor, kde sa dal upravit priamo subor, tak som cakal, ze nieco podobne bude aj pre linux a v terminali...
A ten HxD jste mohl použít dávkově? Unix je založený na tom, že má spoustu jednoduchých nástrojů, které můžete kombinovat. Takže to, co chcete udělat, samozřejmě je možné, akorát si musíte pospojovat použití vhodných nástrojů. Díky tomu pak ty nástroje můžete snadno používat dávkově.


gill

  • ****
  • 270
    • Zobrazit profil
    • E-mail
Re:Nahradenie hex stringu
« Odpověď #5 kdy: 10. 03. 2019, 09:34:23 »
Bez zaruky a bez krasy:

#!/usr/bin/env python3

import sys

def findIndex(f, sa):
    ri = 0
    ra = []
    sl = len(sa)
    while True:
        try:
            b = f.read(1)
            if (len(b) == 0):
                raise EOFError()
            ra.append(b[0])
        except EOFError:
            return -1
        ri += 1
        if (len(ra) > len(sa)):
            ra.pop(0)
        if (ra == sa):
            return ri - sl


def write(f, index, s):
    f.seek(index)
    f.write(s)


def replace(fn, ih, oh):
    f = open(fn, "rb+")
    index = findIndex(f, list(bytes.fromhex(ih)))
    if (index == -1):
        print("Not found")
    else:
        write(f, index, bytes.fromhex(oh))
    f.close()


if __name__ == '__main__':
    if (len(sys.argv) != 4):
        print("Usage: %s filename inhex outhex", sys.argv[0])
    else:
        replace(sys.argv[1], sys.argv[2], sys.argv[3])


to je hodne neefektivni. Pouzijte radeji mmap.

Ink

  • *****
  • 654
    • Zobrazit profil
    • E-mail
Re:Nahradenie hex stringu
« Odpověď #6 kdy: 10. 03. 2019, 10:18:19 »
to je hodne neefektivni. Pouzijte radeji mmap.

Tohle mě zajímá. Soubor se čte sekvenčně, pravděpodobně s bufferováním. Zapisuje se stejně dlouhý řetězec, tudíž se v souboru nic neposouvá. Co na tom vylepší mmap?

Ink

  • *****
  • 654
    • Zobrazit profil
    • E-mail
Re:Nahradenie hex stringu
« Odpověď #7 kdy: 10. 03. 2019, 10:29:16 »
to je hodne neefektivni. Pouzijte radeji mmap.

Tohle mě zajímá. Soubor se čte sekvenčně, pravděpodobně s bufferováním. Zapisuje se stejně dlouhý řetězec, tudíž se v souboru nic neposouvá. Co na tom vylepší mmap?

Asi bude rychlejší použít find(), o tom žádná. Ale pak člověk musí řešit přesahy apod. Já jsem napsal rychlořešení za dvě minuty, ani jsem netvrdil, že to je dokonalé řešení.

Ink

  • *****
  • 654
    • Zobrazit profil
    • E-mail
Re:Nahradenie hex stringu
« Odpověď #8 kdy: 10. 03. 2019, 10:59:53 »
Tohle je výrazně optimálnější, i bez mmap()...

#!/usr/bin/env python3

import sys


def regions(f):
    chunkLength = 50000000
    offset = 0
    c1 = f.read(chunkLength)
    while (len(c1) == chunkLength):
        c2 = f.read(chunkLength)
        yield offset, c1 + c2
        c1 = c2
        offset += chunkLength
    yield offset, c1


def findIndex(f, s):
    for offset, chunk in regions(f):
        index = chunk.find(s)
        if (index >= 0):
            return offset + index

    return -1


def write(f, index, s):
    f.seek(index)
    f.write(s)


def replace(fn, ih, oh):
    f = open(fn, "rb+")
    index = findIndex(f, bytes.fromhex(ih))
    if (index == -1):
        print("Not found")
    else:
        write(f, index, bytes.fromhex(oh))
    f.close()


if __name__ == '__main__':
    if (len(sys.argv) != 4):
        print("Usage: %s filename inhex outhex", sys.argv[0])
    else:
        replace(sys.argv[1], sys.argv[2], sys.argv[3])

Re:Nahradenie hex stringu
« Odpověď #9 kdy: 10. 03. 2019, 12:10:35 »
Tu mas Go verziu(2mb), ale moc som to netestoval takze za nic nerucim.

Kód: [Vybrat]
package main

import (
"flag"
"golang.org/x/exp/mmap"
"log"
"os"
"time"
)

var (
what, with, where string
)

func main() {
flag.StringVar(&what, "replace", "", "String to be replaced.")
flag.StringVar(&with, "with", "", "String to act as replacement.")
flag.StringVar(&where, "in", "", "Path to file.")
flag.Parse()

reader, err := mmap.Open(where)
if err != nil {
log.Fatal(err)
}
defer reader.Close()

file, err := os.OpenFile(where, os.O_WRONLY, 0666)
if err != nil {
log.Fatal(err)
}
defer file.Close()

start := time.Now()
defer func() {
log.Println("Elapsed time:", time.Now().Sub(start).String())
}()

var pos int
whatLen := len(what)
cpr := make([]byte, whatLen, whatLen)
first := what[0]
max := reader.Len()

for {
if pos >= max {
log.Println("no match found")
return
}

if reader.At(pos) == first {
if _, err := reader.ReadAt(cpr, int64(pos)); err != nil {
log.Fatal(err)
}
if string(cpr) == what {
if _, err := file.WriteAt([]byte(with), int64(pos)); err != nil {
log.Fatal(err)
} else {
log.Println("Success")
}
return
} else {
pos += whatLen
continue
}
}

pos++
}
}

« Poslední změna: 10. 03. 2019, 12:12:30 od klobások »

Re:Nahradenie hex stringu
« Odpověď #10 kdy: 10. 03. 2019, 12:11:16 »
mmap verze, python 3

Kód: [Vybrat]
#!/usr/bin/env python3
# vim:ts=4 sw=4:

import sys
import os
import mmap

if len(sys.argv) < 4:
    print("Usage: "+sys.argv[0]+" file searchHex replaceHex")
    sys.exit(-1)

(repl_from, repl_to) = [bytearray.fromhex(h) for h in sys.argv[2:4]]
repl_len = len(repl_from)
if repl_len != len(repl_to):
    print("Error: search and replacement strings have different lengths")
    sys.exit(-2)
filename=sys.argv[1]

with open(filename, "r+b") as f:
    map = mmap.mmap(f.fileno(), 0)
    idx = 0
    while True:
        idx=map.find(repl_from, idx)
        if idx<0:
            break;
        map.seek(idx)
        map.write(repl_to)
        idx += repl_len
    map.close()

Re:Nahradenie hex stringu
« Odpověď #11 kdy: 10. 03. 2019, 12:17:01 »
Tu mas Go verziu(2mb), ale moc som to netestoval takze za nic nerucim.
Při zběžném pohledu se mi zdá, že to bude fungovat korektně jen pokud je v hledaném řetězci každý byte unikátní.

Ink

  • *****
  • 654
    • Zobrazit profil
    • E-mail
Re:Nahradenie hex stringu
« Odpověď #12 kdy: 10. 03. 2019, 13:32:53 »
Hm, nevadí vám, že se soubor při takto jednoduchém použití mmap musí celý vejít do RAM? Nebo mi něco uniká?

Re:Nahradenie hex stringu
« Odpověď #13 kdy: 10. 03. 2019, 13:51:47 »
https://en.wikipedia.org/wiki/Demand_paging

Cele nacitanie suboru vznika len v pripade ak robis "read all" operacie. Cize bezne sa subory prechadzaju riadok za riadkom, pripadne v blokoch, len malokedy sa nacitaju cele do pamete. Je jedno o aky jazyk ide.

Ink

  • *****
  • 654
    • Zobrazit profil
    • E-mail
Re:Nahradenie hex stringu
« Odpověď #14 kdy: 10. 03. 2019, 14:11:15 »
https://en.wikipedia.org/wiki/Demand_paging

Cele nacitanie suboru vznika len v pripade ak robis "read all" operacie. Cize bezne sa subory prechadzaju riadok za riadkom, pripadne v blokoch, len malokedy sa nacitaju cele do pamete. Je jedno o aky jazyk ide.

To mi nedává moc smysl:

1. Jestli si načtu do paměti obsah celého souboru najednou, nebo po kouskách, do toho mmapu nic není. To je věc aplikace.

2. Hledání podřetězce v souboru přece je v nejhorším případě opravdu "read all".

3. Dovedu si samozřejmě představit, že je OS "chytrý" a dokáže podle potřeby uvolňovat kusy paměti, ale přijde mi to celé proti filosofii a smyslu toho mechanismu. Jednak on nemůže vědět, kam si budu chtít sáhnout hned v další operaci (tudíž se to celé může dost prodražit) a vůbec asi pro rychlou práci nechci takto nedeterministické chování systému.