在linux中,二进制文件即指文件,由文件在外部设备的存放形式为二进制而得名。二进制文件编码是变长的,灵活利用率要高,而译码要难一些,不同的二进制文件译码方式是不同的。Linux中的可执行文件(脚本,文本方式的批处理文件不算)就是二进制格式的。
本教程操作环境:linux7.3系统、DellG3电脑。
二进制文件是什么
普通文件(regularfile):就是一般存取的文件,由ls-al显示出来的属性中,第一个属性为[-],例如[-rwxrwxrwx]。依照文件的内容,又大致可以分为:
1、纯文本文件(ASCII):这是Unix系统中最多的一种文件类型,之所以称为纯文本文件,是因为内容可以直接读到的数据,例如数字、字母等等。设置文件几乎都属于这种文件类型。举例来说,使用命令“cat~/.bashrc”就可以看到该文件的内容(cat是将文件内容读出来)。
2、二进制文件(binary):系统其实仅认识且可以执行二进制文件(binaryfile)。Linux中的可执行文件(脚本,文本方式的批处理文件不算)就是这种格式的。举例来说,命令cat就是一个二进制文件。
广义的二进制文件即指文件,由文件在外部设备的存放形式为二进制而得名。狭义的二进制文件即除文本文件以外的文件。文本文件是一种由很多行字符构成的计算机文件。文本文件存在于计算机系统中,通常在文本文件最后一行放置文件结束标志。文本文件的编码基于字符定长,译码相对要容易一些;二进制文件编码是变长的,灵活利用率要高,而译码要难一些,不同的二进制文件译码方式是不同的。
3、数据格式的文件(data):有些程序在运行过程中,会读取某些特定格式的文件,那些特定格式的文件可以称为数据文件(datafile)。举例来说,Linux在用户登入时,都会将登录数据记录在/var/log/wtmp文件内,该文件是一个数据文件,它能通过last命令读出来。但使用cat时,会读出linux系统乱码。因为它是属于一种特殊格式的文件。
Linux上分析二进制文件的10种方法
“这个世界上有10种人:懂二进制的人和不懂二进制的人。”
我们每天都在与二进制文件打交道,但我们对二进制文件却知之甚少。我所说的二进制,是指你每天运行的可执行文件,从命令行工具到成熟的应用程序都是。
Linux提供了一套丰富的工具,让分析二进制文件变得轻而易举。无论你的工作角色是什么,如果你在Linux上工作,了解这些工具的基本知识将帮助你更好地理解你的系统。
在这篇文章中,我们将介绍其中一些最流行的Linux工具和命令,其中大部分都是Linux发行版的一部分。如果没有找到,你可以随时使用你的软件包管理器来安装和探索它们。请记住:学习在正确的场合使用正确的工具需要大量的耐心和练习。
它的作用:帮助确定文件类型。
这将是你进行二进制分析的起点。我们每天都在与文件打交道,并非所有的文件都是可执行类型,除此之外还有各种各样的文件类型。在你开始之前,你需要了解要分析的文件类型。是二进制文件、库文件、ASCII文本文件、视频文件、图片文件、PDF、数据文件等文件吗?
命令将帮助你确定你所处理的文件类型。
/bin/ls:ELF64-bitLSBexecutable,x86-64,version1(SYSV),dynamicallylinked(usessharedlibs),forGNU/Linux2.6.32,BuildID[sha1]=94943a89d17e9d373b2794dcb1f7e38c95b66c86,stripped
$
ldd
它的作用:打印共享对象依赖关系。
如果你已经在一个可执行的二进制文件上使用了上面的命令,你肯定会看到输出中的“动态链接(dynamicallylinked)”信息。它是什么意思呢?
在开发软件的时候,我们尽量不要重造轮子。有一组常见的任务是大多数软件程序需要的,比如打印输出或从标准输入/打开的文件中读取等。所有这些常见的任务都被抽象成一组通用的函数,然后每个人都可以使用,而不是写出自己的变体。这些常用的函数被放在一个叫或的库中。
如何找到可执行程序所依赖的库?这就是命令的作用了。对动态链接的二进制文件运行该命令会显示出所有依赖库和它们的路径。
linux-vdso.so.1=>(0x00007ffef5ba1000)
libselinux.so.1=>/lib64/libselinux.so.1(0x00007fea9f854000)
libcap.so.2=>/lib64/libcap.so.2(0x00007fea9f64f000)
libacl.so.1=>/lib64/libacl.so.1(0x00007fea9f446000)
libc.so.6=>/lib64/libc.so.6(0x00007fea9f079000)
libpcre.so.1=>/lib64/libpcre.so.1(0x00007fea9ee17000)
libdl.so.2=>/lib64/libdl.so.2(0x00007fea9ec13000)
/lib64/ld-linux-x86-64.so.2(0x00007fea9fa7b000)
libattr.so.1=>/lib64/libattr.so.1(0x00007fea9ea0e000)
libpthread.so.0=>/lib64/libpthread.so.0(0x00007fea9e7f2000)
$
ltrace
我们现在知道如何使用命令找到一个可执行程序所依赖的库。一个库可以包含数百个函数。在这几百个函数中,哪些是我们的二进制程序正在使用的实际函数?
命令可以显示运行时从库中调用的所有函数。在下面的例子中,你可以看到被调用的函数名称,以及传递给该函数的参数。你也可以在输出的最右边看到这些函数返回的内容。
__libc_start_main(0x4028c0,1,0x7ffd94023b88,0x412950<unfinished...>
setlocale(LC_ALL,"")="en_US.UTF-8"
bindtextdomain("coreutils","/usr/share/locale")="/usr/share/locale"
textdomain("coreutils")="coreutils"
__cxa_atexit(0x40a930,0,0,0x736c6974756572)=0
getenv("QUOTING_STYLE")=nil
ioctl(1,21523,0x7ffd94023a50)=0
$
hexdump
它的作用:以ASCII、十进制、十六进制或八进制显示文件内容。
通常情况下,当你用一个应用程序打开一个文件,而它不知道如何处理该文件时,就会出现这种情况。尝试用打开一个可执行文件或视频文件,你屏幕上会看到的只是抛出的乱码。
在中打开未知文件,可以帮助你看到文件的具体内容。你也可以选择使用一些命令行选项来查看用ASCII表示的文件数据。这可能会帮助你了解到它是什么类型的文件。
000000007f454c46020101000000000000000000|.ELF............|
0000001002003e0001000000d442400000000000|..>......B@.....|
000000204000000000000000f0c3010000000000|@...............|
000000300000000040003800090040001f001e00|....@.8...@.....|
0000004006000000050000004000000000000000|........@.......|
0000005040004000000000004000400000000000|@.@.....@.@.....|
00000060f801000000000000f801000000000000|................|
0000007008000000000000000300000004000000|................|
0000008038020000000000003802400000000000|8.......8.@.....|
0000009038024000000000001c00000000000000|8.@.............|
$
strings
它的作用:打印文件中的可打印字符的字符串。
如果你只是在二进制中寻找可打印的字符,那么对于你的使用场景来说似乎有点矫枉过正,你可以使用命令。
在开发软件的时候,各种文本/ASCII信息会被添加到其中,比如打印信息、调试信息、帮助信息、错误等。只要这些信息都存在于二进制文件中,就可以用命令将其转储到屏幕上。
$strings/bin/ls
readelf
它的作用:显示有关ELF文件的信息。
ELF(可执行和可链接文件格式(ExecutableandLinkableFileFormat))是可执行文件或二进制文件的主流格式,不仅是Linux系统,也是各种UNIX系统的主流文件格式。如果你已经使用了像命令这样的工具,它告诉你文件是ELF格式,那么下一步就是使用命令和它的各种选项来进一步分析文件。

Magic:7f454c46020101000000000000000000
Data:2'scomplement,littleendian
Type:EXEC(Executablefile)
Machine:AdvancedMicroDevicesX86-64
Entrypointaddress:0x4042d4
Startofprogramheaders:64(bytesintofile)
Startofsectionheaders:115696(bytesintofile)
Sizeofthisheader:64(bytes)
Sizeofprogramheaders:56(bytes)
Sizeofsectionheaders:64(bytes)
Numberofsectionheaders:31
Sectionheaderstringtableindex:30
$
objdump
它的作用:从对象文件中显示信息。
二进制文件是通过你编写的源码创建的,这些源码会通过一个叫做编译器的工具进行编译。这个编译器会生成相对于源代码的机器语言指令,然后由CPU执行特定的任务。这些机器语言代码可以通过被称为汇编语言的助记词来解读。汇编语言是一组指令,它可以帮助你理解由程序所进行并最终在CPU上执行的操作。
实用程序读取二进制或可执行文件,并将汇编语言指令转储到屏幕上。汇编语言知识对于理解命令的输出至关重要。
请记住:汇编语言是特定于体系结构的。
/bin/ls:fileformatelf64-x86-64
Disassemblyofsection.init:
0000000000402150<_init@@Base>:
402150:4883ec08sub$0x8,%rsp
402154:488b056d8e2100mov0x218e6d(%rip),%rax#61afc8<__gmon_start__>
40215b:4885c0test%rax,%rax
$
strace
它的作用:跟踪系统调用和信号。
如果你用过前面提到的,那就把想成是类似的。唯一的区别是,工具不是追踪调用的库,而是追踪系统调用。系统调用是你与内核对接来完成工作的。
举个例子,如果你想把一些东西打印到屏幕上,你会使用标准库中的或函数;在底层,最终会有一个名为的系统调用来实际把东西打印到屏幕上。
execve("/bin/ls",["/bin/ls"],[])=0
mmap(NULL,4096,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0)=0x7f967956a000
access("/etc/ld.so.preload",R_OK)=-1ENOENT(Nosuchfileordirectory)
open("/etc/ld.so.cache",O_RDONLY|O_CLOEXEC)=3
fstat(3,{st_mode=S_IFREG|0644,st_size=40661,...})=0
mmap(NULL,40661,PROT_READ,MAP_PRIVATE,3,0)=0x7f9679560000
fstat(1,{st_mode=S_IFCHR|0620,st_rdev=makedev(136,1),...})=0
mmap(NULL,4096,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0)=0x7f9679569000
munmap(0x7f9679569000,4096)=0
$
nm
它的作用:列出对象文件中的符号。
如果你所使用的二进制文件没有被剥离,命令将为你提供在编译过程中嵌入到二进制文件中的有价值的信息。可以帮助你从二进制文件中识别变量和函数。你可以想象一下,如果你无法访问二进制文件的源代码时,这将是多么有用。
为了展示,我们快速编写了一个小程序,用选项编译,我们会看到这个二进制文件没有被剥离。
hello:ELF64-bitLSBexecutable,x86-64,version1(SYSV),dynamicallylinked(usessharedlibs),forGNU/Linux2.6.32,BuildID[sha1]=3de46c8efb98bce4ad525d3328121568ba3d8a5d,notstripped
$https://www.fruan.com/post/hello
0000000000600e20d__JCR_END__
0000000000600e20d__JCR_LIST__
00000000004005b0T__libc_csu_fini
0000000000400540T__libc_csu_init
U__libc_start_main@@GLIBC_2.2.5
0000000000400490tregister_tm_clones
0000000000601030D__TMC_END__
$
gdb
好吧,不是所有的二进制文件中的东西都可以进行静态分析。我们确实执行了一些运行二进制文件(进行分析)的命令,比如和;软件由各种条件组成,这些条件可能会导致执行不同的替代路径。
分析这些路径的唯一方法是在运行时环境,在任何给定的位置停止或暂停程序,并能够分析信息,然后再往下执行。
这就是调试器的作用,在Linux上,就是调试器的事实标准。它可以帮助你加载程序,在特定的地方设置断点,分析内存和CPU的寄存器,以及更多的功能。它是对上面提到的其他工具的补充,可以让你做更多的运行时分析。
有一点需要注意的是,一旦你使用加载一个程序,你会看到它自己的提示符。所有进一步的命令都将在这个命令提示符中运行,直到你退出。
我们将使用我们之前编译的程序,使用来看看它的工作原理。
$gdb-qhttps://www.fruan.com/post/hello
Readingsymbolsfrom/home/flash/hello...done.
Breakpoint1at0x400521:filehello.c,line4.
NumTypeDispEnbAddressWhat
1breakpointkeepy0x0000000000400521inmainathello.c:4
Startingprogram:/home/flash/https://www.fruan.com/post/hello
Breakpoint1,main()athello.c:4
Missingseparatedebuginfos,use:debuginfo-installglibc-2.17-260.el7_6.6.x86_64
Helloworld![Inferior1(process29620)exitednormally]
$
相关推荐:《Linux视频教程》
以上就是什么是linux二进制文件的详细内容,更多请关注主机测评网其它相关文章!
本文来源:国外服务器--什么是linux二进制文件(linux二进制文件和文本文件)
本文地址:https://www.idcbaba.com/guowai/5967.html
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 1919100645@qq.com 举报,一经查实,本站将立刻删除。




