Android下使用GDB调试无符号ELF文件

本文介绍如何使用gdb工具在Android设备上调试/system/bin/ping应用。通过实例展示如何设置断点、查看汇编指令及跟踪main函数等调试技巧。

以下以adb shell下通过gdb工具调试/system/bin/ping举例:

# /data/local/tmp/gdb --args /system/bin/ping
GNU gdb (GDB) 7.3.1-gg2
...
(gdb) info target
Symbols from "/system/bin/ping".
Local exec file:
        `/system/bin/ping', file type elf32-littlearm.
        Entry point: 0x1078
        0x00000134 - 0x00000147 is .interp
        0x00000148 - 0x00000598 is .dynsym
        0x00000598 - 0x0000081e is .dynstr
        0x00000820 - 0x00000a48 is .hash
        0x00000a48 - 0x00000bf0 is .rel.dyn
        0x00000bf0 - 0x00000db8 is .rel.plt
        0x00000db8 - 0x00001078 is .plt
        0x00001078 - 0x0000436c is .text
        0x0000436c - 0x00004384 is .note.android.ident
        0x00004384 - 0x00004454 is .ARM.exidx
        0x00004454 - 0x0000446c is .ARM.extab
        0x0000446c - 0x00005466 is .rodata
        0x00006d40 - 0x00006d48 is .preinit_array
        0x00006d48 - 0x00006d50 is .init_array
        0x00006d50 - 0x00006d58 is .fini_array
        0x00006d58 - 0x00006e50 is .dynamic
        0x00006e50 - 0x00007000 is .got
        0x00007000 - 0x000070c0 is .data
        0x000070c0 - 0x0001a1ee is .bss
(gdb) b *0x1078    // 设置断点到text段首地址
Breakpoint 1 at 0x1078
(gdb) r
Starting program: /system/bin/ping
warning: Breakpoint address adjusted from 0x40003ca5 to 0x40003ca4.
Warning:
Cannot insert breakpoint 1.
Error accessing memory address 0x1078: Input/output error.


(gdb) d 1   // 在开启了内存布局随机化的kernel中,必然出现上述异常,无视,直接删掉断点1
(gdb) info target
Symbols from "/system/bin/ping".
Unix child process:
        Using the running image of child process 9782.
        While running this, GDB does not access memory from...
Local exec file:
        `/system/bin/ping', file type elf32-littlearm.
        Entry point: 0x2a001078
        0x2a000134 - 0x2a000147 is .interp
        0x2a000148 - 0x2a000598 is .dynsym
        0x2a000598 - 0x2a00081e is .dynstr
        0x2a000820 - 0x2a000a48 is .hash
        0x2a000a48 - 0x2a000bf0 is .rel.dyn
        0x2a000bf0 - 0x2a000db8 is .rel.plt
        0x2a000db8 - 0x2a001078 is .plt
        0x2a001078 - 0x2a00436c is .text
        0x2a00436c - 0x2a004384 is .note.android.ident
        0x2a004384 - 0x2a004454 is .ARM.exidx
        0x2a004454 - 0x2a00446c is .ARM.extab
        0x2a00446c - 0x2a005466 is .rodata
        0x2a006d40 - 0x2a006d48 is .preinit_array
        0x2a006d48 - 0x2a006d50 is .init_array
        0x2a006d50 - 0x2a006d58 is .fini_array
        0x2a006d58 - 0x2a006e50 is .dynamic
        0x2a006e50 - 0x2a007000 is .got
        0x2a007000 - 0x2a0070c0 is .data
        0x2a0070c0 - 0x2a01a1ee is .bss
........

(gdb) x/32i 0x2a001078   // 查看新text段汇编指令,寻找libc_init调用
   0x2a001078:  push    {r11, lr}
   0x2a00107c:  add     r11, sp, #4
   0x2a001080:  sub     sp, sp, #16
   0x2a001084:  ldr     r3, [pc, #80]   ; 0x2a0010dc
   0x2a001088:  add     r3, pc, r3
   0x2a00108c:  ldr     r2, [pc, #76]   ; 0x2a0010e0
   0x2a001090:  ldr     r2, [r3, r2]
   0x2a001094:  str     r2, [r11, #-20]
   0x2a001098:  ldr     r2, [pc, #68]   ; 0x2a0010e4
   0x2a00109c:  ldr     r2, [r3, r2]
   0x2a0010a0:  str     r2, [r11, #-16]
   0x2a0010a4:  ldr     r2, [pc, #60]   ; 0x2a0010e8
   0x2a0010a8:  ldr     r2, [r3, r2]
   0x2a0010ac:  str     r2, [r11, #-12]
   0x2a0010b0:  mov     r2, r11
   0x2a0010b4:  add     r2, r2, #4
   0x2a0010b8:  str     r2, [r11, #-8]
   0x2a0010bc:  sub     r12, r11, #20
   0x2a0010c0:  ldr     r0, [r11, #-8]
   0x2a0010c4:  mov     r1, #0
   0x2a0010c8:  ldr     r2, [pc, #28]   ; 0x2a0010ec
   0x2a0010cc:  ldr     r3, [r3, r2]
   0x2a0010d0:  mov     r2, r3
   0x2a0010d4:  mov     r3, r12
   0x2a0010d8:  bl      0x2a000dcc   (参见附注,r2即为main函数)
   0x2a0010dc:  andeq   r5, r0, r0, lsl #29
   0x2a0010e0:                  ; <UNDEFINED> instruction: 0xffffff40
   0x2a0010e4:                  ; <UNDEFINED> instruction: 0xffffff44
   0x2a0010e8:                  ; <UNDEFINED> instruction: 0xffffff48
   0x2a0010ec:                  ; <UNDEFINED> instruction: 0xffffff4c
   0x2a0010f0:  push    {r11, lr}
   0x2a0010f4:  add     r11, sp, #4
(gdb) b *0x2a0010d8
Breakpoint 2 at 0x2a0010d8
(gdb) c
Continuing.


Breakpoint 2, 0x2a0010d8 in ?? ()
(gdb) p/x $r2     // 查看main函数地址
$1 = 0x2a0017c9
(gdb) b *0x2a0017c9  // main函数上下断点,此时libc.so已加载,还可以b open/fputs/exit ...
warning: Breakpoint address adjusted from 0x2a0017c9 to 0x2a0017c8.
Breakpoint 3 at 0x2a0017c8
(gdb) c
Continuing.
warning: Breakpoint 3 address previously adjusted from 0x2a0017c9 to 0x2a0017c8.


Breakpoint 3, 0x2a0017c8 in ?? ()
(gdb) display /4i $pc
1: x/4i $pc
=> 0x2a0017c8:  stmdb   sp!, {r4, r5, r6, r7, r8, r9, r10, r11, lr}
   0x2a0017cc:  ldr.w   r4, [pc, #2600] ; 0x2a0021f8
   0x2a0017d0:  ldr.w   r3, [pc, #2600] ; 0x2a0021fc
   0x2a0017d4:  add     r4, pc
(gdb) ni
0x2a0017cc in ?? ()
1: x/4i $pc
=> 0x2a0017cc:  ldr.w   r4, [pc, #2600] ; 0x2a0021f8
   0x2a0017d0:  ldr.w   r3, [pc, #2600] ; 0x2a0021fc
   0x2a0017d4:  add     r4, pc
   0x2a0017d6:  mov     r6, r0
(gdb)
0x2a0017d0 in ?? ()
1: x/4i $pc
=> 0x2a0017d0:  ldr.w   r3, [pc, #2600] ; 0x2a0021fc
   0x2a0017d4:  add     r4, pc
   0x2a0017d6:  mov     r6, r0
   0x2a0017d8:  ldr     r0, [r4, r3]
(gdb)

....


附注:

ELF可执行文件入口,__libc_init第3个参数即为main:

bionic\libc\arch-arm\bionic\crtbegin.c

__LIBC_HIDDEN__ void _start() {
......
  void* raw_args = (void*) ((uintptr_t) __builtin_frame_address(0) + sizeof(void*));
  __libc_init(raw_args, NULL, &main, &array);
}

gdb采用的是Android toolchain中的gdb7.3.1-gg2源码编译生成,编译工具使用codesourcery的arm-none-linux-gnueabi。


<think>好的,我现在需要回答用户关于BIN文件ELF文件区别、转换及应用场景的问题。首先,我得回忆一下这两种文件的基本概念。ELF文件是可执行与可链接格式,常见于Unix-like系统,而BIN文件是纯二进制文件,通常用于嵌入式系统或固件烧录。 接下来,用户可能想知道它们的结构差异。ELF包含更多的元数据,比如段头表、符号表等,而BIN文件是直接的二进制数据,没有这些结构。需要解释这些结构对开发的影响,比如调试信息在ELF中但不在BIN中。 然后用途方面,ELF主要用于程序开发阶段,支持动态链接和调试,而BIN文件用于实际部署,尤其是在资源受限的环境。应用场景的例子需要具体,比如嵌入式系统用BIN,Linux应用程序用ELF。 转换部分,用户可能想知道如何将ELF转成BIN,这里需要提到工具如objcopy,以及可能的脚本,比如用户提供的引用中提到的工具。同时,转换时的注意事项,比如内存布局处理,引用中的相关信息需要整合进来。 还要注意用户提供的引用,比如引用[1]提到ELF转BIN的脚本工具,引用[3]和[4]提到转换方法和工具链的使用。需要确保在回答中正确引用这些内容,说明转换工具和步骤。 最后,生成相关问题,可能需要包括性能优化、工具使用、应用场景比较等。要确保问题相关且有深度,帮助用户进一步探索。 检查是否遵循了系统级指令,比如行内数学公式用$...$,独立公式用$$...$$,但当前问题可能不需要公式。中文回答,结构清晰,分点说明。确保引用标记正确,比如转换工具部分引用[1]和[4]。 现在整理思路,分结构回答:区别、用途、转换方法、应用场景,最后相关问题。确保每个部分简明,引用正确,并覆盖用户需求。</think>### BIN文件ELF文件的区别、转换及应用场景 #### 一、核心区别 1. **文件结构** - **ELF文件**(Executable and Linkable Format) 是包含元数据的结构化二进制文件,包含以下部分: - 文件头(标识架构、入口地址等) - 程序头表(描述段加载到内存的方式) - 节头表(代码、数据、符号表、调试信息等) 示例:`$$ \text{ELF} = \{\text{Header}, \text{Program Headers}, \text{Section Headers}, \text{Sections}\} $$` - **BIN文件** 是纯二进制镜像文件,仅包含可直接写入存储介质的原始数据,无组织结构或元数据[^3]。 2. **用途差异** - **ELF**:用于程序开发阶段,支持动态链接、调试(如GDB)和符号分析。 - **BIN**:用于固件烧录或嵌入式系统部署,直接映射到内存地址执行[^3][^4]。 --- #### 二、转换方法与工具 1. **ELF转BIN** - **工具**:使用GNU工具链的`objcopy`命令: ```bash arm-none-eabi-objcopy -O binary input.elf output.bin ``` 该命令提取ELF中的`.text`(代码)、`.data`(初始化数据)等段,生成连续二进制数据[^4]。 - **脚本工具**:用户可通过自动化脚本(如Python或Windows批处理)批量处理,参考开源工具[^1]。 2. **注意事项** - **内存布局**:需确保链接脚本(`.ld`文件)正确配置,避免地址间隙导致BIN文件数据不连续[^4]。 - **调试信息剔除**:转换时可通过`--strip-all`移除ELF中的调试段以减小体积。 --- #### 三、典型应用场景 | 文件类型 | 场景 | 示例 | |---------|------|------| | **ELF** | - 开发调试<br>- 动态链接库(.so/.dll)<br>- 带符号表的崩溃分析 | Linux可执行程序、Android应用 | | **BIN** | - 微控制器固件烧录(如STM32)<br>- Bootloader镜像<br>- 无文件系统的裸机环境 | 路由器固件、智能硬件升级包[^2][^3] | --- #### 四、选择依据 - **是否需要调试**:ELF保留符号和行号信息,适合开发阶段;BIN仅保留运行所需最小数据。 - **目标平台限制**:部分嵌入式设备仅支持BIN格式直接执行。 - **文件体积**:BIN文件通常比ELF更小,适合存储空间受限的场景。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值