这个问题已经存在了一段时间,我认为如果能让它发挥作用,我应该提供一些奖励积分。
最近在工作中,我写了一个解析器,它将以可读格式转换二进制文件。二进制文件不是具有10101010
个字符的Ascii文件。它已经以二进制编码。因此,如果我在文件上执行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
。 完成前三个步骤
一旦我的脚本将输入文本文件转换为具有十六进制值的文本文件,我会得到一个如下文件(通知我可以对其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隧道协议)消息。我想如果我对此进行逆向工程,我可以有效地创建数据生成器并创建自己的数据。
可能有复杂的工具,但我不想花太多时间学习它们。已经过了大约2个月,我已经开始研究* nix平台,只是动手了它的电源工具,如sed
和awk
。
我想要的是为实现这一目标提供一些帮助和指导。
再次感谢您的阅读!对于那些可以指导我正确方向的人来说,等待200分。 :)
以下是原始Binary File
的示例以下是允许用户输入值的Input Text File示例
以下是我的脚本在输入文本文件的所有转换完成后创建的File示例。
如何将File 3
的编码更改为File 1
?
答案 0 :(得分:14)
您可以非常简单地使用xxd与二进制文件/ hexdump进行转换。
数据到十六进制
echo Hello | xxd -p
48656c6c6f0a
十六进制到数据
echo 48656c6c6f0a | xxd -r -p
Hello
或
echo 48 65 6c 6c 6f 0a | xxd -r -p
Hello
-p
是postscript模式,允许更自由的输入
这是xxd -r -p text
的输出,其中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
答案 1 :(得分:3)
使用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
如果你想使用其他工具(想到Perl和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 :(得分:2)
要将编码从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
当然,这不是原始帖子的解决方案......解决方案将使用类似的东西来生成二进制输出。最大的问题是我们仍然不知道数据包中的字段类型。我们也不知道架构(它是bigendian,还是littleendian,是32位还是64位)。你必须给我们规范。例如,包的长度是什么类型的?我们不知道那个TXT文件!
为了帮助您做您必须做的事情,您必须找到有关这些字段大小的规范。
请注意,这是一个好的开始。例如,您需要实现便捷函数,使用十六进制值编码的字符串中的值自动填充buffer []。所以你可以做write $offset "ff c0 d3 ba be"
。
答案 3 :(得分:1)
有一个工具binmake允许以文本格式描述一些二进制数据并生成二进制文件(或输出到stdout)。它允许更改字节顺序和数字格式并接受评论。
首先获取并编译 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
答案 4 :(得分:0)
awk是这里工作的错误工具,但有一千种方法可以做到这一点。最简单的方法通常是一个小的C程序,或任何其他语言明确区分字符和一串十进制数字。
但是,要在awk中执行此操作,请使用“%c”printf格式。