gpt4 book ai didi

linux - 在大型二进制文件中查找数据并带上下文输出

转载 作者:太空宇宙 更新时间:2023-11-04 03:36:14 24 4
gpt4 key购买 nike

序言/背景

上周我的根文件系统被只读重新挂载了几次,我通过 ddrescue 拍摄了完整的快照。遗憾的是文件系统已经损坏并且一些文件丢失。目前,我尝试找到我的 ejabberd 用户数据库,它应该位于图像中的某个位置。 Testdisk 找到所需的文件(标记为已删除),但无法恢复它。由于该文件非常小,而且我有一个月前的备份,因此我考虑对整个图像进行二进制搜索。

现在我有一个文件系统损坏的 64GB 文件,并且想要提取一些包含特定模式的 4kb block 。

问题

如何在 64GB 大文件中找到数据并通过一些上下文 (4kb) 提取结果?

由于文件系统镜像驻留在我的服务器上,我更喜欢 Linux cli 工具。

最佳答案

工具

由于找不到符合我要求的工具,所以我自己用golang编写了它。我称之为bima(二进制匹配)。它并不漂亮,但它完成了任务:

package main

import (
"bytes"
"encoding/hex"
"fmt"
"gopkg.in/alecthomas/kingpin.v1"
"io"
"log"
"math"
"os"
)

var (
debug = kingpin.Flag("debug", "Enable debug mode.").Short('d').Bool()
bsize = kingpin.Flag("blocksize", "Blocksize").Short('b').Default("126976").Int()
debugDetail = kingpin.Flag("debugdetail", "Debug Detail").Short('v').Default("10").Int()

matchCommand = kingpin.Command("match", "Match a value")
matchCommandValue = matchCommand.Arg("value", "The value (Hex Encoded e.g.: 616263 == abc)").Required().String()
matchCommandFile = matchCommand.Arg("file", "The file").Required().String()
)

func main() {
kingpin.Version("0.1")
mode := kingpin.Parse()

if *bsize <= 0 {
log.Fatal("The blocksize has to be larger than 0")
}

if *debugDetail <= 0 {
log.Fatal("The Debug Detail has to be larger than 0")
}

if mode == "match" {
searchBytes, err := hex.DecodeString(*matchCommandValue)
if err != nil {
log.Fatal(err)
}

scanFile(searchBytes, *matchCommandFile)
}
}

func scanFile(search []byte, path string) {
searchLength := len(search)
blocksize := *bsize

f, err := os.Open(path)
if err != nil {
log.Fatal(err)
}
defer f.Close()

fi, err := f.Stat()
if err != nil {
log.Fatal(err)
}
filesize := fi.Size()
expectedRounds := int(math.Ceil(float64(filesize-int64(searchLength))/float64(blocksize)) + 1)
if expectedRounds <= 0 {
expectedRounds = 1
}

data := make([]byte, 0, blocksize+searchLength-1)
data2 := make([]byte, 0, blocksize+searchLength-1)
offset := make([]byte, searchLength-1)
//reading the len of the slice or less (but not the cap)
readCount, err := f.Read(offset)
if err == io.EOF {
fmt.Println("The files seems to be empty")
return
} else if err != nil {
log.Fatal(err)
}

data = append(data, offset...)

buffer := make([]byte, blocksize)
var blockpos int
var idx int
blockpos = 0

lastLevel := -1
roundLevel := 0
idxOffset := 0
for round := 0; ; round++ {
if *debug {
roundLevel = ((round * 100) / expectedRounds)
if (roundLevel%*debugDetail == 0) && (roundLevel > lastLevel) {
lastLevel = roundLevel
fmt.Fprintln(os.Stderr, "Starting round", round+1, "of", expectedRounds, "--", ((round * 100) / expectedRounds))
}
}

//At EOF, the count will be zero and err will be io.EOF
readCount, err = f.Read(buffer)
if err != nil {
if err == io.EOF {
if *debug {
fmt.Fprintln(os.Stderr, "Done - Found EOF")
}
break
}
fmt.Println(err)
return
}

data = append(data, buffer[:readCount]...)
data2 = data
idxOffset = 0
for {
idx = bytes.Index(data2, search)
if idx >= 0 {
fmt.Println(blockpos + idxOffset + idx)
if idx+searchLength < len(data2) {
data2 = data2[idx+searchLength:]
idxOffset += idx
} else {
break
}
} else {
break
}
}
data = data[readCount:]
blockpos += readCount
}
}

故事

为了完整起见,以下是我为解决问题所做的事情:

起初我使用 hexedit 发现所有数据库文件都有相同的 header 。以十六进制编码,如下所示:0102030463584d0b0000004b62574c41

所以我使用我的工具来查找 sda.image 文件中的所有出现情况:

./bima match 0102030463584d0b0000004b62574c41 ./sda.image >DBfiles.txt

对于 64GB,这大约需要 8 分钟,我认为 HDD 是限制因素。

我用 dd 从图像中提取了大约 1200 个出现的结果。由于我不知道文件的确切大小,我只是提取了 20.000 字节的 block :

for f in $(cat DBfiles.txt); do
dd if=sda.image of=$f.dunno bs=1 ibs=1 skip=$f count=20000
done

现在我有大约 1200 个文件,必须找到正确的文件。第一步,我搜索 passwd 文件(passwd.DCD 和 passwd.DCL)。后来我对名册文件做了同样的事情。由于文件头包含名称,我只是简单地查找 passwd:

for f in *.dunno; do
if [ "$(cat $f | head -c 200 | grep "passwd" | wc -l)" == "1" ]; then
echo "$f" | sed 's/\.$//g' >> passwd_files.list
fi
done

因为 block 比文件大,所以我必须手动找到每个文件的结尾。我用 Curses Hexedit 进行了更正.

在此过程中,我可以看到每个文件的头部包含 dcl_logkdcd_logk。这样我就知道哪些文件是DCL文件,哪些是DCD文件。

最后,每个文件我都看了十次,并且必须决定要使用哪个版本。一般来说,我选择了最大的文件。将文件放入新的ejabberd服务器的DB目录中并重新启动后,所有帐户又恢复了。 :-)

关于linux - 在大型二进制文件中查找数据并带上下文输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31489475/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com