심각하게 손상된 Sqlite 파일이 있습니다. 모든 것을 SQL 파일에 덤프하고 새 파일에 로드하는 일반적인 방법이 작동하지 않지만 16진수 편집기를 사용하면 복구해야 할 데이터가 있다는 것을 알 수 있습니다.
이런 패턴을 만났어요
vim이 ASCII 문자만 표시하고 다른 바이트를 이진 데이터로 처리할 수 있나요?
vi가 인쇄할 수 없는 문자를 16진수로 표시하도록 합니다.
굉장하네요, 알려드릴게요
14>>07>>테이스티 맥타이슨 씨[이메일 보호됨]
그런데 표시하면서 파일에 쓸 수 있는 방법이 있나요?
따라서 vi가 버퍼에 <14>라는 16진수 값으로 표시하는 것은 실제로 이를 텍스트 파일의 해당 문자로 변경합니다.
vi에서 정규식 검색 및 교체를 수행하여 이 작업을 수행할 수 있지만 인쇄할 수 없는 각 문자에 대해 한 번에 하나씩 수행해야 하며 이는 꽤 큰 파일입니다.
나중에 <14><07>을 16비트 정수로 처리할 계획이지만 먼저 이를 실제 문자로 텍스트 파일에 넣을 수 있어야 합니다.
미리 감사드립니다
답변1
xxd
함께 제공되는 내용을 보고 vim
열에 16진수 데이터와 인쇄 가능한 문자를 덤프할 수 있습니다. 16진수를 편집하는 경우 데이터를 다시 푸시하여 xxd -r
2진수로 다시 변환할 수 있습니다.
그러나 최종 목표를 살펴보면 더 강력한 것이 필요할 수 있습니다 perl
. 예를 들어 저는 이에 대한 전문가는 아니지만 다음이 유용할 수 있습니다.
#!/usr/bin/perl
# https://unix.stackexchange.com/a/452784/119298
use strict;
sub fn{
my ($ch,$ch2,$rest) = @_;
return sprintf("%5u",(ord($ch)<<8)|ord($ch2)).$rest;
}
my $data = join("",<>);
$data =~ s/(.)(.)([a-zA-Z][ -~]{10,})/fn($1,$2,$3)/ge;
print $data;
stdin의 모든 데이터를 변수로 읽은 $data
다음 s/.../.../g
임의의 2바이트와 알파벳 문자(az 및 AZ 범위), 그 뒤에 10개 이상의 인쇄 가능한 문자(물결표까지의 범위, C 언어 환경 가정)를 쌍으로 연결합니다. 이러한 부분은 ()
3개의 개별 부분으로 분할되어 캡처되고 함수 호출로 대체됩니다 fn
. e
결국 이것이 의미하는 바입니다.
이 함수는 단순히 정수로 변환되고 변경되지 않은 세 번째 인수와 연결된 2바이트 문자열 인쇄를 반환합니다.
도움을 주기 위해 원하는 작업을 수행하는 더 간단한 버전이 있습니다. 인쇄되지 않는 문자를 <..>
.
my $data = join("",<>);
$data =~ s/([^ -~\n])/sprintf("<%02x>",ord($1))/ge;
print $data;
^
여기의 패턴은 상대적으로 간단합니다. 즉, 의미가 있는 인쇄할 수 없는 문자(및 개행 문자)의 범위입니다.아니요. 간단한 sqlite 파일을 살펴보면 텍스트 데이터 바로 앞의 문자가 일반적으로 인쇄 가능한 문자라는 것을 알았습니다. 그래서 문자 시작 문자를 테스트하는 패턴을 사용했지만 더 나은 경험적 방법을 사용하는 것이 좋습니다.
답변2
다음은 0x00 - 0x20 범위의 인쇄되지 않는 문자(CR, LF, 탭 및 공백 제외)를 대체합니다. #xDD#
여기서 DD
문자의 16진수 표현은 다음과 같습니다(감사합니다)이 문제잘 정의된 범위의 경우):
sed $( (seq 0 8; seq 11 12; seq 14 31) | awk '{ printf("s/\\x%02x/#x%02x#/;", $0, $0) }' )
나는 seq
대체할 문자 범위를 생성하고 awk
패턴을 생성하는 데 사용합니다 sed
. 후자가 실제 대체를 수행합니다.
다음과 같이 테스트할 수 있습니다.
seq 0 32 | awk '{$0 =$0 sprintf("%c",$0)} 1' | sed $( (seq 0 8; seq 11 12; seq 14 31) | awk '{ printf("s/\\x%02x/#x%02x#/;", $0, $0) }' )
FWIW 검색어에서 이 내용을 찾은 사람을 위해 알파인 도커 이미지(내 손상된 파일을 처리하려는 위치)는 sed
NULL 문자를 좋아하지 않으므로 다음과 같이 수정해야 했습니다.
sed $( (seq 1 8; seq 11 12; seq 14 31) | awk '{ printf("s/\\x%02x/#x%02x#/;", $0, $0) }' ) | tr '\0' '\1' | sed 's/\x01/#x00#/'