达美小生活

有用的内容创作

如何打开bin文件(手机解压bin文件最简单方法步骤工具)

这世界有10种人,一种人懂二进制,另一种人不懂二进制。 ——

大家好,

二进制文件是我们几乎每天都需要打交道的文件类型,但很少人知道他们的工作原理。这里所讲的二进制文件,是指一些可执行文件,包括你天天要使用的 Linux 命令,也是二进制文件的一种。

Linux 给我们提供了非常多用于二进制文件的工具,不管你在 Linux 下从事的是何种工作,知道这些工具也会让你对你的更加了解。

在本文中,将介绍几种常用的用于二进制文件的工具及命令,这些工具在大部分发行版里可以直接使用,如果不能直接用的话,可以自行安装。

file

file 命令用于文件的类型。

如果你需要二进制文件,可以首先使用 file 命令来切入。我们知道,在 Linux 下,皆文件,但并不是所有的文件都具有可执行,我们还有各种各样的文件,比如:文本文件,管道文件,链接文件,socket文件,等等。

在对一个文件进行之前,我们可以首先使用 file 命令来它们的类型。当然除此之外,我们还可以看到一些其它信息。

$ file /bin/pwd
/bin/pwd: ELF -bit L executable, x86-, version 1 (SYSV), dynamically linked (uses shared libs), for U/Linux 2.6.32, BuildID[sha1]=0d2ba2adc568f0e21cc9576df434c, stpped

ldd

ldd 命令可以用于可执行文件的依赖。

我们使用 file 命令来一个可执行文件的时候,有时候可以看到输出中有 dynamically linked 这样的字眼。这个是啥呢?

大部分程序,都会使用到第三方库,这样就可以不用重复造子,节约大量时间。简单的,我们写C程序代码的话,肯定会使用到 li 或者 gli 库。当然,除此之外,还可能使用其它的库。

那我们在什么情况下需要程序的依赖库呢?有一个场景大家肯定经历过。你去你同事那边拷备他写好的程序放到自己的环境下运行,有时候可能会跑不起来。当然跑不起来的原因可能很多,但其中一个原因可能就是缺少对应的依赖库。

这时候,ldd 就派上用场了。它可以程序需要一些什么依赖库,你只要把对应的库放在对应的位置就可以了。

$ ldd /bin/pwd
>  (0x00007ffeb73e5000)
> /lib(0x00007f908b)
/lib(0x00007f908b6ef000)

ltrace

ltrace的能是能够跟踪进程的库函数调用。

我们可以使用 ldd 命令来找到程序的依赖库,但是,一个库里少则几个,多则几千个函数,怎么知道现在程序调用的是什么函数呢?

ltrace 命令就是用来做这个事的。在下面的例子里,我们可以看到程序调用的函数,以及传递进去的参数,同时你也可以看到函数调用的输出。

$ ltrace /bin/pwd
__li_start_in(0x, 1, 0x7ffff6524cc8, 0x404a00 <unfinished >
getenv("POSIX_CORRECT")                        = nil
strrchr("/bin/pwd", '/')                         = "/pwd"
setlocale(LC_ALL, "")                            = ""
bindtextdoin("coreutils", "/usr/share/locale") = "/usr/share/locale"
textdoin("coreutils")                          = "coreutils"
__cxa_atexit(0x4022f0, 0, 0, 0x736c)   = 0
getopt_long(1, 0x7ffff6524cc8, "LP", 0x606d00, nil) = -1
getcwd(nil, 0)                                   = ""
puts("/home/alvin"/home/alvin
)                              = 12
free(0x22030)                                  = <void>
exit(0 <unfinished >
__fpending(0x7f, 0, , 0x7feb0) = 0
fileno(0x7f)                           = 1
__freading(0x7f, 0, , 0x7feb0) = 0
__freading(0x7f, 0, 2052, 0x7feb0) = 0
fflush(0x7f)                           = 0
fclose(0x7f)                           = 0
__fpending(0x7fc0, 0, 3328, 0xfbad000c)  = 0
fileno(0x7fc0)                           = 2
__freading(0x7fc0, 0, 3328, 0xfbad000c)  = 0
__freading(0x7fc0, 0, 4, 0xfbad000c)     = 0
fflush(0x7fc0)                           = 0
fclose(0x7fc0)                           = 0
+++ exited (status 0) +++

strace

strace 命令可以用于追踪程序运行过程中的调用及。

通过上面的介绍,我们知道 ltrace 命令是用来追踪函数调用的。strace 命令类似,但它追踪的是调用。何为调用?简单说就是我们可以通过调用与内核进行交互,完成我们想要的任务。

例如,如果我们想在屏幕上打印某些字符,可以使用 pntf 或 puts 函数,而这两个都是 li 的库函数,在更底层,他们都是调用 wte 这个调用。

$ strace -f /bin/pwd
execve("/bin/pwd", ["/bin/pwd"], [/* 24 vars */]) = 0
brk(NULL)                               = 0x9000
mp(NULL, 40, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f918ba
access("/etc", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc", O_RDON|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|04, st_size=, }) = 0
mp(NULL, , PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f918ba5f000
close(3)                                = 0
open("/lib", O_RDON|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\20&\2\0\0\0\0\0", 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=, }) = 0
mp(NULL, , PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f918b47b000
mptect(0x7f918b63e000, , PROT_NONE) = 0
mp(0x7f918b83e000, , PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1c3000) = 0x7f918b83e000
mp(0x7f918b, , PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f918b
close(3)
…………
+++ exited with 0 +++

hexdump

hexdump 命令用来查看二进制文件的 16 进制编码,但实际它能查看文件,而不限于二进制文件。

一个二进制文件,如果你直接使用文本编辑器打开的话,将看到一堆乱码。这时候,你就可以使用 hexdump 命令来查看它的内容了。

hexdump 的显示格式是:左边是字节序,中间是文件的 16 进制编码,如果是可打印字符的话就会显示在右边。

通过使用这个命令,我们就可以大概知道这个二进制文件里面有什么内容,后面要做什么处理就比较方便了。

$ hexdump -C /bin/pwd | head
00000000  7f 45 4c 46 02 01 01 00  00 00 00 00 00 00 00 00
00000010  02 00 3e 00 01 00 00 00  17 19 40 00 00 00 00 00  |..>@
00000020  40 00 00 00 00 00 00 00  50 7a 00 00 00 00 00 00  |@
00000030  00 00 00 00 40 00 38 00  09 00 40 00 1e 00 1d 00  @@
00000040  06 00 00 00 05 00 00 00  40 00 00 00 00 00 00 00  @
00000050  40 00 40 00 00 00 00 00  40 00 40 00 00 00 00 00  |@.@@.@
00000060  f8 01 00 00 00 00 00 00  f8 01 00 00 00 00 00 00
00000070  08 00 00 00 00 00 00 00  03 00 00 00 04 00 00 00
00000080  38 02 00 00 00 00 00 00  38 02 40 00 00 00 00 00  @
00000090  38 02 40 00 00 00 00 00  1c 00 00 00 00 00 00 00  |8.@

stngs

stngs 命令可以用来打印二进制文件中可显示的字符。

什么是可显示字符?简单说你在显示器上看到的字符都是可显示字符,比如:aA,.:。

我们知道,一个二进制文件里面的内容很多是非显示字符,所以无法直接用文本处理器打开。程序在被的时候,我们经常会加一些调试信息,比如:debug log, warn log, err log,等等。这些信息我们就可以使用 stngs 命令看得到。

$ stngs /bin/pwd | head
/lib
fflush
strcpy
__pntf_chk
readdir
setlocale
mbrtowc
strncmp
optind

readelf

readelf 一般用于查看 ELF 格式的文件信息。

ELF(Executable and Linkable Fort)即可执行连接文件格式,是一种比较复杂的文件格式,但其应用广泛。当你使用 file 命令发现某个文件是 ELF 文件时,你就可以使用 readelf 命令来读取这个文件的信息。

$ readelf -h /bin/pwd
ELF Header:
Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class:                             ELF
Data:                              2's complement, little endian
Version:                           1 (crent)
OS/A:                            UNIX -  V
A Version:                       0
Type:                              EXEC (Executable file)
Machine:                           Advanced Mic Devices X86-
Version:                           0x1
Entry point address:               0x
Start of pgram headers:           (bytes into file)
Start of section headers:           (bytes into file)
Flags:                             0x0
Size of this header:                (bytes)
Size of pgram headers:           56 (bytes)
Number of pgram headers:         9
Size of section headers:            (bytes)
Number of section headers:         30
Section header stng table index: 29

objdump

objdump是用查看目标文件或者可执行的目标文件的构成的GCC工具。

我们知道,程序在完成之后,需要经过编译,才可以生成计算机可以识别的二进制文件。我们写的代码计算机不能直接执行,需要编译成汇编程序,计算机才能依次执行。

objdump 命令可以读取可执行文件,然后将汇编指令打印出来。所以如果你想看懂 objdump 的结果,你就需要有一些汇编基才可以。

$ objdump -d /bin/pwd | head
/bin/pwd:     file fort elf-x86-
Disassembly of section .init:
0000000000 <.init>:
:       48 83 ec 08             sub    $0x8,%rsp
:       48 8b 05 6d 5c 20 00    mov    0x205c6d(%p),%rax        # 606fc8 <__ctype_b_loc@plt+0x>
b:       48 85 c0                   %rax,%rax

nm

nm命令主要是列出目标文件的符(说白了就是一些函数和全变量等)。

如果你编译出来的程序没有经过 stp ,那么 nm 命令可以挖掘出隐含在可执行文件中的重大秘密。它可以帮你列出文件中的变量及函数,这对于我们进行反向操作具有重大意义。

下面我们通过一小段简单的程序来讲解 nm 命令的用途。在编译这个程序时,我们加上了 -g 选项,这个选项可以使编译出来的文件包含更多有效信息。

$ cat
#include
int in {
pntf("Hello world!");
retn 0;
}
$
$ gcc -g
$
$ file hello
hello: ELF -bit L executable, x86-, version 1 (SYSV), dynamically linked (uses shared libs), for U/Linux 2.6.32, BuildID[sha1]=3de46c8efb98e4ad525dba3d8a5d, not stpped
$
$ ./hello
Hello world!$
$
$ nm hello | tail
0000000000600e20 d __JCR_END__
0000000000600e20 d __JCR_LIST__
00000000004005b0 T __li_u_fini
0000000000 T __li_u_init
U __li_start_in@@GLI_2.2.5
0000000000d T in
U pntf@@GLI_2.2.5
0000000000 t register_tm_clones
0000000000 T _start
0000000000 D __TMC_END__
$

gdb

gdb 就是所谓的 U debugger。

gdb 大家或多或少都有听说过。我们在使用一些 IDE 写代码的时候,可以进行打断点、步进、查看变量值等方式调试,其实这些 IDE 底层调用的也是 gdb 。

对于 gdb 的用法,可以写很多,本文就暂且不深入了。下面先演示一小段 gdb 基的能。

$ gdb -q ./hello
Reading symbols fm /home/fla
(gdb) break in
Breakpoint 1 at 0x: file , line 4.
(gdb) info break
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x0000000000 in in at
(gdb) run
Starting pgram: /home/flash/./hello
Breakpoint 1, in  at
4           pntf("Hello world!");
Missing separate debuginfos, use: debuginfo-tall
(gdb)
#0  in  at
(gdb) c
Continuing.
Hello world![Infeor 1 (pcess ) exited norlly]
(gdb) q
$

小结

如果你在 Linux 下进行程序的时候,那么你免不了跟二进制文件打交道。熟练使用以上介绍的 10 个命令,将会对你的工作产生很大的帮助。