标题: objcopy hacking
创建: 2019-01-25 14:59 链接: https://scz.617.cn/unix/201901251459.txt
本文简单介绍objcopy的一些奇技淫巧,用不用得上看个人造化。
假设arm_thumb_switch是一个ELF,源自arm_thumb_switch.s,可以用objcopy直接析 取字节流:
$ objcopy -O binary arm_thumb_switch arm_thumb_switch.raw
现在arm_thumb_switch.raw中是一段裸格式的机器码:
$ xxd -g 1 arm_thumb_switch.raw 00000000: 0e 20 a0 e3 5c 10 9f e5 01 00 a0 e3 04 70 a0 e3 . ..........p.. 00000010: 00 00 00 ef 01 c0 8f e2 1c ff 2f e1 4f f0 0c 02 ........../.O... 00000020: 0b a1 4f f0 01 00 4f f0 04 07 2e df fc 46 60 47 ..O...O......F`G 00000030: 0a 20 a0 e3 20 10 8f e2 01 00 a0 e3 04 70 a0 e3 . .. ........p.. 00000040: 2e 00 00 ef 00 00 20 e0 01 70 a0 e3 01 00 00 ef ...... ..p...... 00000050: 74 68 75 6d 62 20 6d 6f 64 65 2e 0a 61 72 6d 20 thumb mode..arm 00000060: 6d 6f 64 65 2e 0a 00 00 c0 00 01 00 48 65 6c 6c mode........Hell 00000070: 6f 2c 20 77 6f 72 6c 64 2e 0a o, world..
$ xxd -i arm_thumb_switch.raw unsigned char arm_thumb_switch_raw[] = { 0x0e, 0x20, 0xa0, 0xe3, 0x5c, 0x10, 0x9f, 0xe5, 0x01, 0x00, 0xa0, 0xe3, 0x04, 0x70, 0xa0, 0xe3, 0x00, 0x00, 0x00, 0xef, 0x01, 0xc0, 0x8f, 0xe2, 0x1c, 0xff, 0x2f, 0xe1, 0x4f, 0xf0, 0x0c, 0x02, 0x0b, 0xa1, 0x4f, 0xf0, 0x01, 0x00, 0x4f, 0xf0, 0x04, 0x07, 0x2e, 0xdf, 0xfc, 0x46, 0x60, 0x47, 0x0a, 0x20, 0xa0, 0xe3, 0x20, 0x10, 0x8f, 0xe2, 0x01, 0x00, 0xa0, 0xe3, 0x04, 0x70, 0xa0, 0xe3, 0x2e, 0x00, 0x00, 0xef, 0x00, 0x00, 0x20, 0xe0, 0x01, 0x70, 0xa0, 0xe3, 0x01, 0x00, 0x00, 0xef, 0x74, 0x68, 0x75, 0x6d, 0x62, 0x20, 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0a, 0x61, 0x72, 0x6d, 0x20, 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0a, 0x00, 0x00, 0xc0, 0x00, 0x01, 0x00, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2e, 0x0a }; unsigned int arm_thumb_switch_raw_len = 122;
"xxd -i"较少用到,以C格式转储字节流。
换个思路,假设arm_thumb_switch.raw是从非Linux的IoT设备提取得到的固件片段, 是裸代码。
从arm_thumb_switch.raw生成arm_thumb_switch.scz:
$ objcopy -I binary -O elf32-littlearm -B arm --set-section-flags .data=code,alloc --rename-section .data=.text arm_thumb_switch.raw arm_thumb_switch.scz
"-B arm"告诉objcopy,arm_thumb_switch.scz将在arm上运行,将来ld需要知道这种 信息以便链接arm相关的其他.o。有人可能认为"-O elf32-littlearm"已经暗含了 "-B arm",事实并非如此。
缺省情况下arm_thumb_switch.raw将被放到arm_thumb_switch.scz的.data,用 "--rename-section .data=.text"将之放到.text中。
"--set-section-flags .data=code,alloc"不能直接用.text,这个逻辑顺序是先设 置section的标志,再重命名section。指定code是为了方便"objdump -d"。 "objdump -d"只找有X标志的section,"objdump -D"会找所有section。
为了知道"objcopy -O"都能指定哪些值,有两种办法:
$ objcopy --info
Display a list showing all architectures and object formats available.
$ ar tv ... ar: supported targets: elf32-littlearm elf32-littlearm-fdpic elf32-bigarm elf32-bigarm-fdpic elf32-little elf32-big plugin srec symbolsrec verilog tekhex binary ihex
$ file -b arm_thumb_switch.scz ELF 32-bit LSB relocatable, ARM, version 1 (ARM), not stripped
$ readelf -Wa arm_thumb_switch.scz ELF Header: Magic: 7f 45 4c 46 01 01 01 61 00 00 00 00 00 00 00 00 Class: ELF32 Data: 2's complement, little endian Version: 1 (current) OS/ABI: ARM ABI Version: 0 Type: REL (Relocatable file) Machine: ARM Version: 0x1 Entry point address: 0x0 Start of program headers: 0 (bytes into file) Start of section headers: 392 (bytes into file) Flags: 0x0 Size of this header: 52 (bytes) Size of program headers: 0 (bytes) Number of program headers: 0 Size of section headers: 40 (bytes) Number of section headers: 5 Section header string table index: 4
Section Headers: [Nr] Name Type Addr Off Size ES Flg Lk Inf Al [ 0] NULL 00000000 000000 000000 00 0 0 0 [ 1] .text PROGBITS 00000000 000034 00007a 00 WAX 0 0 1 [ 2] .symtab SYMTAB 00000000 0000b0 000050 10 3 2 4 [ 3] .strtab STRTAB 00000000 000100 000067 00 0 0 1 [ 4] .shstrtab STRTAB 00000000 000167 000021 00 0 0 1 Key to Flags: W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), C (compressed), x (unknown), o (OS specific), E (exclude), y (purecode), p (processor specific)
There are no section groups in this file.
There are no program headers in this file.
There is no dynamic section in this file.
There are no relocations in this file.
There are no unwind sections in this file.
Symbol table '.symtab' contains 5 entries: Num: Value Size Type Bind Vis Ndx Name 0: 00000000 0 NOTYPE LOCAL DEFAULT UND 1: 00000000 0 SECTION LOCAL DEFAULT 1 2: 00000000 0 NOTYPE GLOBAL DEFAULT 1 _binary_arm_thumb_switch_raw_start 3: 0000007a 0 NOTYPE GLOBAL DEFAULT 1 _binary_arm_thumb_switch_raw_end 4: 0000007a 0 NOTYPE GLOBAL DEFAULT ABS _binary_arm_thumb_switch_raw_size
No version information found in this file.
objcopy会给arm_thumb_switch.scz增加三个符号:
_binary_arm_thumb_switch_raw_start _binary_arm_thumb_switch_raw_end _binary_arm_thumb_switch_raw_size
显然这个模式是:
binary<...>start _binary<...>end _binary<...>_size
$ objcopy -I binary -O elf32-littlearm -B arm --rename-section .data=.text,alloc,load,readonly,code,contents --redefine-sym _binary_arm_thumb_switch_raw_start=_start arm_thumb_switch.raw arm_thumb_switch.scz
"--redefine-sym _binary_arm_thumb_switch_raw_start=_start"会改符号名。新命 令没用"--set-section-flags .data=code,alloc",而是直接 "--rename-section .data=.text,alloc,load,readonly,code,contents",后者更简 捷。
$ readelf -WS arm_thumb_switch.scz There are 5 section headers, starting at offset 0x16c:
Section Headers: [Nr] Name Type Addr Off Size ES Flg Lk Inf Al [ 0] NULL 00000000 000000 000000 00 0 0 0 [ 1] .text PROGBITS 00000000 000034 00007a 00 AX 0 0 1 [ 2] .symtab SYMTAB 00000000 0000b0 000050 10 3 2 4 [ 3] .strtab STRTAB 00000000 000100 00004b 00 0 0 1 [ 4] .shstrtab STRTAB 00000000 00014b 000021 00 0 0 1 Key to Flags: W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), C (compressed), x (unknown), o (OS specific), E (exclude), y (purecode), p (processor specific)
$ objdump -x arm_thumb_switch.scz
arm_thumb_switch.scz: file format elf32-littlearm arm_thumb_switch.scz architecture: arm, flags 0x00000010: HAS_SYMS start address 0x00000000 private flags = 0: [APCS-32] [FPA float format]
Sections: Idx Name Size VMA LMA File off Algn 0 .text 0000007a 00000000 00000000 00000034 20 CONTENTS, ALLOC, LOAD, READONLY, CODE SYMBOL TABLE: 00000000 l d .text 00000000 .text 00000000 g .text 00000000 _start 0000007a g .text 00000000 _binary_arm_thumb_switch_raw_end 0000007a g ABS 00000000 _binary_arm_thumb_switch_raw_size
$ objdump -d arm_thumb_switch.scz
arm_thumb_switch.scz: file format elf32-littlearm
Disassembly of section .text:
00000000 <_start>:
0: e3a0200e mov r2, #14
4: e59f105c ldr r1, [pc, #92] ; 68 <_start+0x68>
8: e3a00001 mov r0, #1
c: e3a07004 mov r7, #4
10: ef000000 svc 0x00000000
14: e28fc001 add ip, pc, #1
18: e12fff1c bx ip
1c: 020cf04f andeq pc, ip, #79 ; 0x4f
20: f04fa10b ;
由于arm_thumb_switch.scz中没有$a、$t,"objdump -d"无法识别出中部的THUMB模 式代码。假设知道范围,可以强制objdump按THUMB模式反汇编:
$ objdump -d -M force-thumb --start-address=0x1c --stop-address=0x30 arm_thumb_switch.scz
arm_thumb_switch.scz: file format elf32-littlearm
Disassembly of section .text:
0000001c <_start+0x1c>: 1c: f04f 020c mov.w r2, #12 20: a10b add r1, pc, #44 ; (adr r1, 50 <_start+0x50>) 22: f04f 0001 mov.w r0, #1 26: f04f 0704 mov.w r7, #4 2a: df2e svc 46 ; 0x2e 2c: 46fc mov ip, pc 2e: 4760 bx ip
这篇可能看得有点不明不白,不知要点何在。确实,就是随意展示一下objcopy的某 些用法而已。