Создайте двоичные файлы в UNIX - PullRequest
8 голосов
/ 11 ноября 2011

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

Что я делал…

Недавно на работе я написал парсер, который конвертировал бы двоичный файл в читаемый формат.Двоичный файл не является файлом Ascii с 10101010 символами.Он был закодирован в двоичном формате.Поэтому, если я сделаю cat для файла, я получу следующее -

[jaypal~/Temp/GTP]$ cat T20111017153052.NEW 
==?sGTP?ղ?N????W????&Xx1?T?&Xx1?;
?d@#e?
      ?0H????????|?X?@@(?ղ??VtPOC01
cceE??k@9??W傇??R?K?i2??d@#e???&Xx1&Xx??!?
blackberrynet?/??!

??!

??#ripassword??W傅?W傆??0H??
                            #R??@Vtc@@(?ղ??n?POC01

Поэтому я использовал утилиту hexdump, чтобы файл отображал следующее содержимое и перенаправлял его в файл.Теперь у меня был выходной файл, который представлял собой текстовый файл, содержащий значения Hex.

[jaypal~/Temp/GTP]$ hexdump -C T20111017153052.NEW 
00000000  3d 3d 01 f8 73 47 54 50  02 f1 d5 b2 be 4e e4 d7  |==..sGTP.....N..|
00000010  00 01 01 00 01 80 00 cc  57 e5 82 00 00 00 00 00  |........W.......|
00000020  00 00 00 00 00 00 00 00  87 d3 f5 13 00 00 00 00  |................|
00000030  00 00 00 00 00 00 00 00  00 00 00 00 00 01 00 10  |................|
00000040  01 01 0f 00 00 00 00 00  26 58 78 31 00 b3 54 c5  |........&Xx1..T.|
00000050  26 58 78 31 00 b4 3b 0a  00 00 ad 64 13 40 01 03  |&Xx1..;....d.@..|
00000060  23 16 65 f3 01 01 0b 91  30 19 48 99 f2 ff ff ff  |#.e.....0.H.....|
00000070  ff ff ff 02 00 7c 00 dc  01 58 00 a0 40 40 28 02  |.....|...X..@@(.|
00000080  f1 d5 b2 b8 ca 56 74 50  4f 43 30 31 00 00 00 00  |.....VtPOC01....|
00000090  00 04 0a 63 63 07 00 00  00 00 00 00 00 00 00 00  |...cc...........|
000000a0  00 00 00 65 45 00 00 b4  fb 6b 40 00 39 11 16 cd  |...eE....k@.9...|
000000b0  cc 57 e5 82 87 d3 f5 52  85 a1 08 4b 00 a0 69 02  |.W.....R...K..i.|
000000c0  32 10 00 90 00 00 00 00  ad 64 00 00 02 13 40 01  |2........d....@.|

После множества awk, sed и cut скрипт преобразовал шестнадцатеричные значения в читаемый текст.Для этого я использовал смещение, которое будет отмечать начальную и конечную позиции каждого преобразованного параметра.Полученный файл после всех преобразований выглядит следующим образом

[jaypal:~/Temp/GTP] cat textfile.txt 
Beginning of DB Package Identifier: ==
Total Package Length: 508
Offset to Data Record Count field: 115
Data Source: GTP
Timestamp: 2011-10-25
Matching Site Processor ID: 1
DB Package format version: 1
DB Package Resolution Type: 0
DB Package Resolution Value: 1
DB Package Resolution Cause Value: 128
Transport Protocol: 0
SGSN IP Address: 220.206.129.47
GGSN IP Address: 202.4.210.51

Почему я это сделал

Я инженер-тестировщик, и ручная проверка двоичных файлов была серьезной проблемой.Мне пришлось вручную анализировать смещения и использовать калькулятор для их преобразования и проверки на соответствие Wireshark и GUI.

Теперь часть вопроса

Я хочу сделать все наоборот.Это был мой план -

  • Иметь легко читаемый текстовый файл ввода, который будет иметь Parameters : Values.
  • Пользователь может просто поместить значения рядом с ними (например, Date будет параметром, а пользователь может указать дату, которую он хочет иметь в файле данных).
  • Сценарий вырезает всю необходимую информацию (предоставленную пользователем) из входного текстового файла и преобразует их в шестнадцатеричные значения.
  • Как только файл будет преобразован в шестнадцатеричные значения, мне бы хотелосьзакодировать его обратно в двоичный файл.

Первые три шага сделаны

Задача

Как только мой скрипт преобразует входной текстовый файл в текстовый файл с шестнадцатеричными значениями,Я получаю файл следующим образом ( обратите внимание, что я могу сделать cat для него ).

[visdba@hw-diam-test01 ParserDump]$ cat temp_file | sed 's/.\{32\}/&\n/g' | sed 's/../& /g'
3d 3d 01 fc 73 47 54 50 02 f1 d6 55 3c 9f 49 9c
00 01 01 00 01 80 00 dc ce 81 2f 00 00 00 00 00
00 00 00 00 00 00 00 00 ca 04 d2 33 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10
01 01 0f 00 00 07 04 ea 00 00 ff ff 00 00 14 b7
00 00 ff ff 00 00 83 ec 00 00 83 62 54 14 59 00
60 38 34 f5 01 01 0b 58 62 70 11 60 f6 ff ff ff
ff ff ff 02 00 7c 00 d0 01 4c 00 b0 40 40 28 02
f1 d6 55 38 cb 2b 23 50 4f 43 30 31 00 00 00 00
00 04 0a 63 63 07 00 00 00 00 00 00 00 00 00 00

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

[jaypal~/Temp/GTP]$ cat temp.file 
==?sGTP?ղ?N????W????&Xx1?T?&Xx1?;
?d@#e?
      ?0H????????|?X?@@(?ղ??VtPOC01
cceE??k@9??W傇??R?K?i2??d@#e???&Xx1&Xx??!?
blackberrynet?/??!

??!

Так вот вопрос. Как мне закодировать его в этой форме?

Почему я хочу это сделать?

У нас не так много сообщений GTP (GPRS Tunneling Protocol)производство.Я подумал, что если я перепроектирую это, я смогу эффективно создать генератор данных и создать свои собственные данные.

Подводя итоги

Там могут быть сложные инструменты, но я не хочу тратить слишком много времени на их изучение.Прошло около 2 месяцев, я начал работать на платформе * nix и просто начал изучать такие мощные инструменты, как sed и awk.

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

Еще раз спасибо за чтение!200 баллов ждут того, кто может направить меня в правильном направлении.:)

Образцы файлов

Вот пример оригинального двоичного файла

Вот пример Входной текстовый файл это позволило бы пользователю вводить значения

Вот пример File , который создает мой сценарий после завершения преобразования из входного текстового файла.

Как изменить кодировку File 3 на File 1?

Ответы [ 5 ]

14 голосов
/ 29 ноября 2011

Вы можете использовать xxd для преобразования в / из двоичных файлов / hexdumps довольно просто.

данные в шестнадцатеричные

echo  Hello | xxd -p 
48656c6c6f0a

hexк данным

echo 48656c6c6f0a | xxd -r -p
Hello

или

echo 48 65 6c 6c 6f 0a | xxd -r -p
Hello

-p - это режим постскриптума, который допускает более произвольный ввод

Это вывод из xxd -r -p text, гдетекст - это данные, которые вы передаете выше

==▒sGTP▒▒U<▒I▒▒▒΁/▒▒3▒▒▒▒▒▒▒▒▒bTY`84▒
                                     Xbp`▒▒▒▒▒▒▒|▒L▒@@(▒▒U8▒+#POC01
:▒ިv▒b▒▒▒▒TY`84Ud▒▒▒▒>▒▒▒▒▒▒▒!▒
blackberrynet▒/▒▒!
M
▒▒!
N
▒▒#Oripassword▒▒΁/▒▒΁/▒▒Xbp`▒@@(▒▒U8▒IvPOC01
:qU▒b▒▒▒▒▒▒TY`84U▒▒▒*:▒▒!
▒k▒▒▒#O Welcmme!
▒!
M
3 голосов
/ 27 ноября 2011

Используя cut и awk, вы можете сделать это довольно просто, используя функцию расширения gawk (GNU Awk), strtonum():

cut -c11-60 inputfile |
awk '{ for (i = 1; i <= NF; i++)
       {
           c = strtonum("0x" $i)
           printf("%c", c);
       }
     }' > outputfile

Или, если вы используетене-GNU версия 'new awk', тогда вы можете использовать:

cut -c11-60 inputfile |
awk '{  for (i = 1; i <= NF; i++)
        {
            s = toupper($i)
            c0 = index("0123456789ABCDEF", substr(s, 1, 1)) - 1
            c1 = index("0123456789ABCDEF", substr(s, 2, 1)) - 1
            printf("%c", c0*16 + c1);
        }
     }' > outputfile

Если вы хотите использовать другие инструменты (Pern и Python sprint на ум; Ruby будет другой возможностью), вы можетесделать это достаточно легко.

odx - это программа, аналогичная программе hexdump.Приведенный выше сценарий был изменен для чтения «hexdump.out» в качестве входного файла, и вывод передается по каналу odx вместо файла, и дает следующий вывод:

$ cat hexdump.out
00000000  3d 3d 01 fc 73 47 54 50  02 f1 d6 55 3c 9f 49 9c  |==..sGTP...U<.I.|
00000010  00 01 01 00 01 80 00 dc  ce 81 2f 00 00 00 00 00  |........../.....|
00000020  00 00 00 00 00 00 00 00  ca 04 d2 33 00 00 00 00  |...........3....|
00000030  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 10  |................|
00000040  01 01 0f 00 00 07 04 ea  00 00 ff ff 00 00 14 b7  |................|
00000050  00 00 ff ff 00 00 83 ec  00 00 83 62 54 14 59 00  |...........bT.Y.|
00000060  60 38 34 f5 01 01 0b 58  62 70 11 60 f6 ff ff ff  |`84....Xbp.`....|
00000070  ff ff ff 02 00 7c 00 d0  01 4c 00 b0 40 40 28 02  |.....|...L..@@(.|
$ sh -x revdump.sh | odx
+ cut -c11-60 hexdump.out
+ awk '{  for (i = 1; i <= NF; i++)
        {
            #c = strtonum("0x" $i)
            #printf("%c", c);
            s = toupper($i)
            c0 = index("0123456789ABCDEF", substr(s, 1, 1)) - 1
            c1 = index("0123456789ABCDEF", substr(s, 2, 1)) - 1
            printf("%c", c0*16 + c1);
        }
     }'
0x0000: 3D 3D 01 FC 73 47 54 50 02 F1 D6 55 3C 9F 49 9C   ==..sGTP...U<.I.
0x0010: 00 01 01 00 01 80 00 DC CE 81 2F 00 00 00 00 00   ........../.....
0x0020: 00 00 00 00 00 00 00 00 CA 04 D2 33 00 00 00 00   ...........3....
0x0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10   ................
0x0040: 01 01 0F 00 00 07 04 EA 00 00 FF FF 00 00 14 B7   ................
0x0050: 00 00 FF FF 00 00 83 EC 00 00 83 62 54 14 59 00   ...........bT.Y.
0x0060: 60 38 34 F5 01 01 0B 58 62 70 11 60 F6 FF FF FF   `84....Xbp.`....
0x0070: FF FF FF 02 00 7C 00 D0 01 4C 00 B0 40 40 28 02   .....|...L..@@(.
0x0080:
$ 

Или, используя hexdump -C вместо odx:

$ sh -x revdump.sh | hexdump -C
+ cut -c11-60 hexdump.out
+ awk '{  for (i = 1; i <= NF; i++)
        {
            #c = strtonum("0x" $i)
            #printf("%c", c);
            s = toupper($i)
            c0 = index("0123456789ABCDEF", substr(s, 1, 1)) - 1
            c1 = index("0123456789ABCDEF", substr(s, 2, 1)) - 1
            printf("%c", c0*16 + c1);
        }
     }'
00000000  3d 3d 01 fc 73 47 54 50  02 f1 d6 55 3c 9f 49 9c  |==..sGTP...U<.I.|
00000010  00 01 01 00 01 80 00 dc  ce 81 2f 00 00 00 00 00  |........../.....|
00000020  00 00 00 00 00 00 00 00  ca 04 d2 33 00 00 00 00  |...........3....|
00000030  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 10  |................|
00000040  01 01 0f 00 00 07 04 ea  00 00 ff ff 00 00 14 b7  |................|
00000050  00 00 ff ff 00 00 83 ec  00 00 83 62 54 14 59 00  |...........bT.Y.|
00000060  60 38 34 f5 01 01 0b 58  62 70 11 60 f6 ff ff ff  |`84....Xbp.`....|
00000070  ff ff ff 02 00 7c 00 d0  01 4c 00 b0 40 40 28 02  |.....|...L..@@(.|
00000080
$
2 голосов
/ 29 ноября 2011

Чтобы изменить кодировку с File3 на File1, вы используете скрипт, подобный следующему:

#!/bin/bash

# file name: tobin.sh

fileName="tobin.txt"   # todo: pass it as parameter
                       #       or prepare it to be used via the pipe...
while read line; do
  for hexValue in $line; do
    echo -n -e "\x$hexValue"
  done
done < $fileName

Или, если вы просто хотите передать это, и используйте, как пример xxd в этой теме:

#!/bin/bash

# file name: tobin.sh
# usage: cat file3.txt | ./tobin.sh > file1.bin

while read line; do
  for hexValue in $line; do
    echo -n -e "\x$hexValue"
  done
done

Если вы действительно хотите использовать BASH для этого, тогда я предлагаю вам начать использовать массив для хорошей сборки вашего пакета.Вот начальный код:

#!/bin/sh

# We assume the script will run on a LSB architecture.

hexDump() {
  for idx in $(seq 0 ${#buffer[@]}); do
    printf "%02X", ${buffer[$idx]}
  done
} # hexDump() function

###
# dump() dumps the current content of the buffer[] array to the STDOUT.
#
dump() {
  # or, use $ptr here...
  for idx in $(seq 0 ${#buffer[@]}); do
    printf "%c" ${buffer[$idx]}
  done
} # dump() function

# Beginning of DB Package Identifier: ==
buffer[0]=$'\x3d' # =
buffer[1]=$'\x3d' # =
size=2

# Total Package Length: 2
# We start with 2, and later on we update it once we know the exact size...
# Assuming 32bit architecture, LSB, this is how we encode number 2 (that is our current size of the packet)
buffer[2]=$'\x02'
buffer[3]=$'\x00'
buffer[4]=$'\x00'
buffer[5]=$'\x00'

# Offset to Data Record Count field: 115
# I assume this is also a 32bit field of unsigned int type
ptr=5
buffer[++ptr]=$'\x73'  # 115
buffer[++ptr]=$'\x00'
buffer[++ptr]=$'\x00'
buffer[++ptr]=$'\x00'

#hexDump
dump

Вывод:

$ ./tobin2.sh | hexdump -C
00000000  3d 3d 02 00 00 00 73 00  00 00 00                 |==....s....|
0000000b

Конечно, это не решение оригинальной публикации ... Решение будет использовать что-то подобное для генерации двоичного вывода.Самая большая проблема в том, что мы до сих пор не знаем типы полей в пакете .Мы также не знаем архитектуру (будь то бигендовская или малоизвестная, 32-битная или 64-битная).Вы должны дать нам спецификацию.Например, длина пакета какого типа?Мы не знаем, что из этого файла TXT!

Чтобы помочь вам сделать то, что вам нужно, вы должны найти нам спецификацию размеров этих полей.

Обратите внимание, что этохорошее начало, хотя.Вам необходимо реализовать вспомогательные функции, например, для автоматического заполнения буфера [] значениями из строки, закодированной шестнадцатеричными значениями.Таким образом, вы можете сделать что-то вроде write $offset "ff c0 d3 ba be".

1 голос
/ 04 января 2017

Существует инструмент binmake , позволяющий описывать в текстовом формате некоторые двоичные данные и генерировать двоичный файл (или выводить на стандартный вывод).Позволяет изменять порядковый номер и числовые форматы и принимать комментарии.

Сначала получить и скомпилировать binmake (двоичная программа будет в bin/):

$ git clone https://github.com/dadadel/binmake
$ cd binmake
$ make

Создайте свой текстовый файл file.txt:

# an exemple of file description of binary data to generate
# set endianess to big-endian
big-endian

# default number is hexadecimal
00112233

# man can explicit a number type: %b means binary number
%b0100110111100000

# change endianess to little-endian
little-endian

# if no explicit, use default
44556677

# bytes are not concerned by endianess
88 99 aa bb

# change default to decimal
decimal

# following number is now decimal
0123

# strings are delimited by " or '
"this is some raw string"

# explicit hexa number starts with %x
%xff

Создайте свой двоичный файл file.bin:

$ ./binmake file.txt file.bin
$ hexdump file.bin -C
00000000  00 11 22 33 4d e0 77 66  55 44 88 99 aa bb 7b 74  |.."3M.wfUD....{t|
00000010  68 69 73 20 69 73 20 73  6f 6d 65 20 72 61 77 20  |his is some raw |
00000020  73 74 72 69 6e 67 ff                              |string.|
00000027

Вы также можете передать его, используя stdin и stdout:

$ echo '32 decimal 32 %x61 61' | ./binmake | hexdump -C
00000000  32 20 61 3d                                       |2 a=|
00000004
0 голосов
/ 11 ноября 2011

awk - неподходящий инструмент для этой работы, но есть тысячи способов сделать это.Самым простым способом часто является небольшая программа на C или любой другой язык, который явно делает различие между символом и строкой десятичных цифр.

Однако, чтобы сделать это в awk, используйте "% c" printfформат.

...