Как преобразовать двузначные текстовые данные в двоичные (битовое представление)

Большинство демонов, выполненных как корень, некоторые (из соображений безопасности, для ограничения их способности к вреду) выполненный как их собственные пользователи. Они перечислены в /etc/passwd файл. Большинство дистрибутивов ограничивает UID "пользователя системы" некоторым значением, как 500 или 1000, так, чтобы дал ключ к разгадке. Некоторые deamons имеют GECOS (пользовательское описание) записи, говоря, что "демон", у других есть странные оболочки. Но существуют также фантомные пользователи для NFS и другого использования.

4
25.06.2015, 18:57
5 ответов

Другой перл:

perl -pe 'BEGIN { binmode \*STDOUT } chomp; tr/AB/\0\1/; $_ = pack "B*", $_'

Доказательство:

$ echo ABBBAAAABBBBBABBABBBABBB | \
    perl -pe 'BEGIN { binmode \*STDOUT } chomp; tr/AB/\0\1/; $_ = pack "B*", $_' | \
    od -tx1
0000000 70 fb 77
0000003

Вышеуказанное считывается по одной строке за раз. Вам необходимо убедиться, что эти строки именно такие, какими они должны быть.

Редактирование: Обратная операция:

#!/usr/bin/env perl

binmode \*STDIN;

while ( defined ( $_ = getc ) ) {
    $_ = unpack "B*";
    tr/01/AB/;
    print;
    print "\n" if ( not ++$cnt % 3 );
}
print "\n" if ( $cnt % 3 );

Одновременно считывается байт ввода.

Редактирование 2: Проще обратная операция:

perl -pe 'BEGIN { $/ = \3; $\ = "\n"; binmode \*STDIN } $_ = unpack "B*"; tr/01/AB/'

Вышеуказанное считывание 3 байта одновременно с STDIN (но получение EOF посередине последовательности не является фатальной проблемой).

5
27.01.2020, 20:48

Перл:

my $len = 24;
my $str = "ABBBAAAABBBBBABBABBBABBB\n";
$str =~ s/\s//g;
(my $bin = $str) =~ y/AB/01/;
my $val = oct("0b".$bin);
printf "%s -> %s -> %X\n", $str, $bin, $val;

my ($filename, $fh) = ("temp.out");

# write the file
open $fh, '>', $filename;
print $fh pack("N", $val);      # this actually writes 4 bytes
close $fh;

# now read it, and convert back to a string:
open $fh, '<', $filename;
read $fh, my $data, 4;
close $fh;

my $new_val = unpack "N", $data;
my $new_bin = substr unpack("B32", $data), -$len;
(my $new_str = $new_bin) =~ y/01/AB/;

printf "%X -> %s -> %s\n", $new_val, $new_bin, $new_str;
ABBBAAAABBBBBABBABBBABBB -> 011100001111101101110111 -> 70FB77
70FB77 -> 011100001111101101110111 -> ABBBAAAABBBBBABBABBBABBB

Благодаря идеальному ответу lcd047 мой становится:

my $str = "ABBBAAAABBBBBABBABBBABBB\n";
$str =~ s/\s//g;
(my $bin = $str) =~ y/AB/01/;
printf "%s -> %s\n", $str, $bin;

my ($filename, $fh) = ("temp.out");

# write the file
open $fh, '>', $filename;
print $fh pack("B*", $bin);
close $fh;

my $size = -s $filename;
print $size, "\n";

# now read it, and convert back to a string:
open $fh, '<', $filename;
read $fh, my $data, 1024;
close $fh;

my $new_bin = unpack("B*", $data);
(my $new_str = $new_bin) =~ y/01/AB/;

printf "%s -> %s\n", $new_bin, $new_str;
ABBBAAAABBBBBABBABBBABBB -> 011100001111101101110111
3
011100001111101101110111 -> ABBBAAAABBBBBABBABBBABBB
1
27.01.2020, 20:48
{   printf '2i[q]sq[?z0=qPl?x]s?l?x'
    tr -dc AB | tr AB 01 | fold -b24
}   <infile   | dc

Делая следующее утверждение, @ lcd047 довольно хорошо решил мое предыдущее состояние замешательства:

Вы, кажется, сбиты с толку результатом od . Используйте od -tx1 для просмотра байтов. od -x читает слова, а на машинах с прямым порядком байтов меняет местами байты. Я не внимательно следил за обменом выше, но я думаю, что ваша первоначальная версия была правильной, и вам вообще не нужно связываться с порядком байтов. Просто используйте od -tx1 , а не od -x .

Теперь я чувствую себя участником лучше - прежняя потребность в dd conv = swab беспокоила меня весь день. Я не мог его закрепить, но знал, что с ним что-то не так. Очень утешает то, что я могу объяснить это своей собственной глупостью, тем более, что я кое-чему научился.

В любом случае, это удалит каждый байт, который не является [AB] , затем tr заменит их на [01] соответственно, прежде чем свернуть в результирующий поток по 24 байта в строке. dc ? читает строку за раз, проверяет, содержит ли ввод что-либо, и, если да, P записывает байтовое значение этого числа в стандартный вывод.

Из man dc :

  • P

    • Извлекает значение из вершины стека. Если это строка, она просто печатается без символа новой строки в конце. В противном случае это число, и целая часть его абсолютного значения печатается как поток байтов «base ( UCHAR_MAX + 1 .
  • i

    • Извлекает значение из вершины стека и использует его для установки входной системы счисления.

некоторая автоматизация оболочки

Вот функция оболочки, которую я написал на основе вышеизложенного, которая может работать в обоих направлениях:

ABdc()( HOME=/dev/null  A='[fc[fc]]sp[100000000o]p2o[fc]' B=2i
        case    $1      in
        (-B) {  echo "$B"; tr AB 01      | paste -dP - ~      ; }| dc;;
        (-A) {  echo "$A"; od -vAn -tu1  | paste -dlpx - ~ ~ ~; }| dc|
         dc  |  paste - - - ~            | expand -t10,20,30     |
                cut -c2-9,12-19,22-29    | tr ' 01' AAB         ;;
        (*)     set '' "$1";: ${1:?Invalid opt: "'$2'"}         ;;
        esac
)

Она преобразует материал ABABABA в байты с помощью -B , поэтому вы можете просто сделать:

ABdc -B <infile

Но он преобразует произвольный ввод в 24 ABABABA строки, закодированные бит на байт - в той же форме, что и представленная, например, в вопросе - w / -B .

seq 5 | ABdc -A | tee /dev/fd/2 | ABdc -B

AABBAAABAAAABABAAABBAABA
AAAABABAAABBAABBAAAABABA
AABBABAAAAAABABAAABBABAB
AAAABABAAAAAAAAAAAAAAAAA
1
2
3
4
5

Для вывода -A я набрал здесь cut , expand и od , которые я рассмотрю в минуту, но я также добавил еще один DC . Я отказался от строкового сценария ? read dc для другого метода, который одновременно обрабатывает массив с помощью f - это команда, которая печатает f ull dc стек команд в стандартный вывод. Конечно, поскольку dc - это приложение, ориентированное на стек последним вошел, первым вышел , это означает, что ull-стек f выходит в в обратном порядке.

Это может быть проблемой, но я все равно использую другой dc с o utput Radix, установленным на 100000000 для обработки все нулевые отступы настолько просто, насколько это возможно. И когда он считывает другой поток последний пришел, первый вышел , он применяет эту логику к нему снова и снова, и все это выходит в стирке. Два dc работают согласованно следующим образом:

{   echo '[fc[fc]]sp[100000000o]p2o[fc]'
    echo some data | 
    od -An -tu1        ###arbitrary input to unsigned decimal ints
    echo lpx           ###load macro stored in p and execute
} | tee /dev/fd/2  |   ###just using tee to show stream stages
dc| tee /dev/fd/2  |dc 

...поток на первый тройник ...

[fc[fc]]sp[100000000o]pc2o[fc]            ###dc's init cmd from 1st echo
 115 111 109 101  32 100  97 116  97  10  ###od's output
lpx                                       ###load p; execute

... на второй тройник , как записано из постоянного тока в постоянного тока ...

100000000o                             ###first set output radix
1010                                   ###bin/rev vs of od's out
1100001                                ###dc #2 reads it in, revs and pads it 
1110100                                
1100001
1100100
100000
1100101
1101101
1101111                                ###this whole process is repeated
1110011                                ###once per od output line, so
fc                                     ###each worked array is 16 bytes.

... а вывод, который записывает второй dc , будет ...

 01110011
 01101111
 01101101
 01100101
 00100000
 01100100
 01100001
 01110100
 01100001
 00001010

Отсюда функция вставить в <вкладки> ...

 01110011    01101111    01101101
 01100101    00100000    01100100
 01100001    01110100    01100001
 00001010

... развернуть в <вкладки> на пробелы с интервалом в 10 столбцов ...

 01110011  01101111  01101101
 01100101  00100000  01100100
 01100001  01110100  01100001
 00001010

... вырезать все, кроме байтов 2-9,12-19,22-29 ...

011100110110111101101101
011001010010000001100100
011000010111010001100001
00001010

... и tr заменяет <пробелы> и нули на A , а единицы на B ...

ABBBAABBABBABBBBABBABBAB
ABBAABABAABAAAAAABBAABAA
ABBAAAABABBBABAAABBAAAAB
AAAABABAAAAAAAAAAAAAAAAA

Вы можете видеть в последней строке мою главную мотивацию для включения expand - это такой легкий фильтр, который очень легко гарантирует, что каждая записанная последовательность - даже последняя - дополняется до 24 закодированных битов. Когда это происходит в обратном порядке, и строки декодируются в -B yte-value, к ним добавляются два NUL:

ABdc -B <<\IN | od -tc
ABBBAABBABBABBBBABBABBAB
ABBAABABAABAAAAAABBAABAA
ABBAAAABABBBABAAABBAAAAB
AAAABABAAAAAAAAAAAAAAAAA
IN

... как вы можете видеть ...

0000000   s   o   m   e       d   a   t   a  \n  \0  \0
0000014

данные реального мира

Я поигрался с ним и попробовал несколько простых, реалистичных потоков. Я построил этот тщательно продуманный конвейер для поэтапных отчетов ...

{                            ###dunno why, but I often use man man
    (                        ###as a test input source
        {   man man       |  ###streamed to tee
            tee /dev/fd/3 |  ###branched to stdout
            wc -c >&2        ###and to count source bytes
        }   3>&1          |  ###the branch to stdout is here
        ABdc -A           |  ###converted to ABABABA
        tee /dev/fd/3     |  ###branched again
        ABdc -B              ###converted back to bytes
        times >&2            ###the process is timed
    ) | wc -c >&2            ###ABdc -B's output is counted
} 3>&1| wc -c                ###and so is the output of ABdc -A

Однако у меня нет хорошей основы для сравнения производительности. Могу только сказать, что меня довели до этого теста, когда я был (возможно, наивно) достаточно впечатлен, чтобы сделать это ...

man man | ABdc -A | ABdc -B

... который нарисовал экран моего терминала с человеком выводит с той же заметной скоростью, что и нефильтрованная команда. Результатом теста было ...

37595                       ###source byte count
0m0.000000s 0m0.000000s     ###shell processor time nil
0m0.720000s 0m0.250000s     ###shell children's total user, system time
37596                       ###ABdc -B output byte count
313300                      ###ABdc -A output byte count

начальные тесты

Остальное - просто более простое доказательство того, что это вообще работает ...

printf %s ABBBAAAABBBBBABBABBBABBB|
tee - - - - - - - -|
tee - - - - - - - - - - - - - - - |
{   printf '2i[q]sq[?z0=qPl?x]s?l?x'
    tr -dc AB | tr AB 01 | fold -b24
} | dc        | od -tx1
0000000 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70
0000020 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb
0000040 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77
0000060 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70
0000100 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb
0000120 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77
0000140 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70
0000160 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb
0000200 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77
0000220 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70
0000240 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb
0000260 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77
0000300 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70
0000320 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb
0000340 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77
0000360 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70
0000400 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb
0000420 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77
0000440 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70
0000460 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb
0000500 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77
0000520 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70
0000540 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb
0000560 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77
0000600 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70
0000620 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb
0000640 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77
0000660

3
27.01.2020, 20:48

Следующее решение основано только на xxd (один из инструментов, упомянутых в вопросе), Bash и GNU sed.

Предполагается, что ввод состоит из полных байтов (групп из восьми букв), произвольно разделенных символами новой строки.

Подход таков:

  1. Удалите все символы новой строки.

  2. Сгруппируйте буквы в группы из четырех букв, оканчивающиеся пробелами.

  3. Отфильтруйте эти квадграфы в шестнадцатеричные цифры, не отделенные друг от друга.

  4. Сгруппируйте пары шестнадцатеричных цифр вместе, каждая пара в отдельной строке.

  5. Прочтите эти байтовые значения с помощью цикла оболочки и восстановите xxd совместимый шестнадцатеричный дамп.

  6. Перенаправить в xxd -r для преобразования дампа в шестнадцатеричные данные.

Код:

#!/bin/bash

addr=0
tr -d '\n' | \
sed -e 's/..../& /g' |
sed -e 's/AAAA /0/g' \
    -e 's/AAAB /1/g' \
    -e 's/AABA /2/g' \
    -e 's/AABB /3/g' \
    -e 's/ABAA /4/g' \
    -e 's/ABAB /5/g' \
    -e 's/ABBA /6/g' \
    -e 's/ABBB /7/g' \
    -e 's/BAAA /8/g' \
    -e 's/BAAB /9/g' \
    -e 's/BABA /A/g' \
    -e 's/BABB /B/g' \
    -e 's/BBAA /C/g' \
    -e 's/BBAB /D/g' \
    -e 's/BBBA /E/g' \
    -e 's/BBBB /F/g' |
sed -e 's/../&\n/g' |
while read hexbyte ; do
  if [ $((addr % 16)) == 0 ] ; then
     printf "%08x: " $addr
  fi
  printf "%s" $hexbyte
  if [ $((addr % 16)) == 15 ] ; then
    printf "\n"
  else
    printf " "
  fi
  : $(( addr++ ))
done |
xxd -r - -

Скромный прогон образца:

$ cat data
AAAABBB
B
ABABABAB
ABABAABBBBAABBAB

$ ./ab.sh < data > data.bin

$ xxd data.bin
0000000: 0f55 53cd                                .US.

Вот модификация кода для обработки конечной группы из семи или менее битов, путем дополнения ее нулями, чтобы получился полный байт, так что, например, файл не содержащий ничего, кроме B , отображается в байт 0x80 :

#!/bin/bash

addr=0
tr -d '\n' | \
sed -e 's/..../& /g' |
sed -e 's/AAAA /0/g' \
    -e 's/AAAB /1/g' \
    -e 's/AABA /2/g' \
    -e 's/AABB /3/g' \
    -e 's/ABAA /4/g' \
    -e 's/ABAB /5/g' \
    -e 's/ABBA /6/g' \
    -e 's/ABBB /7/g' \
    -e 's/BAAA /8/g' \
    -e 's/BAAB /9/g' \
    -e 's/BABA /A/g' \
    -e 's/BABB /B/g' \
    -e 's/BBAA /C/g' \
    -e 's/BBAB /D/g' \
    -e 's/BBBA /E/g' \
    -e 's/BBBB /F/g' \
    -e 's/AAA$/0/g' \
    -e 's/AAB$/2/g' \
    -e 's/ABA$/4/g' \
    -e 's/ABB$/6/g' \
    -e 's/BAA$/8/g' \
    -e 's/BAB$/A/g' \
    -e 's/BBA$/C/g' \
    -e 's/BBB$/E/g' \
    -e 's/AA$/0/g' \
    -e 's/AB$/4/g' \
    -e 's/BA$/8/g' \
    -e 's/BB$/C/g' \
    -e 's/A$/0/g' \
    -e 's/B$/8/g' |
sed -e 's/../&\n/g' |
sed -e 's/^.$/&0\n/' |
while read hexbyte ; do
  if [ $((addr % 16)) == 0 ] ; then
     printf "%08x: " $addr
  fi
  printf "%s" $hexbyte
  if [ $((addr % 16)) == 15 ] ; then
    printf "\n"
  else
    printf " "
  fi
  : $(( addr++ ))
done |
xxd -r - -
1
27.01.2020, 20:48

заменить символы в текстовом файле:

sed -i 's/A/0/g' file.in
sed -i 's/B/1/g' file.in

Если вы представляете символы новой строки с помощью \n, замените их символами новой строки:

sed 's/\\n/\'$'\n''/g' file.in

(ABBBAAAABBBBBABBBBBBBBBBB становится 011100001111101101110111)

Обработка строки ascii ()в файле file.in как двоичных данных для записи (как есть )в двоичный файл:

data=$(cat file.in)

# replace file
echo $(printf '%x\n' "$((2#$data))") | xxd -r -p > file.out
# or write to existing file without truncating
echo $(printf '%x\n' "$((2#$data))") | xxd -r -p - file.out

который дает следующие шестнадцатеричные коды при чтении (3 -байта )двоичного файла:

hd file.out
70fb77

Чтобы декодировать (обратное ), прочитайте двоичный файл с помощью hd или xxd, преобразуйте шестнадцатеричные коды в двоичные, затем поменяйте местами 0 и 1 для A и B.

Протестировано на Ubuntu 16.04.7

1
29.01.2021, 04:55

Теги

Похожие вопросы