标题: 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 2**0 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 ; instruction: 0xf04fa10b 24: f04f0001 ; instruction: 0xf04f0001 28: df2e0704 svcle 0x002e0704 2c: 476046fc ; instruction: 0x476046fc 30: e3a0200a mov r2, #10 34: e28f1020 add r1, pc, #32 38: e3a00001 mov r0, #1 3c: e3a07004 mov r7, #4 40: ef00002e svc 0x0000002e 44: e0200000 eor r0, r0, r0 48: e3a07001 mov r7, #1 4c: ef000001 svc 0x00000001 50: 6d756874 ldclvs 8, cr6, [r5, #-464]! ; 0xfffffe30 54: 6f6d2062 svcvs 0x006d2062 58: 0a2e6564 beq b995f0 <_binary_arm_thumb_switch_raw_end+0xb99576> 5c: 206d7261 rsbcs r7, sp, r1, ror #4 60: 65646f6d strbvs r6, [r4, #-3949]! ; 0xfffff093 64: 00000a2e andeq r0, r0, lr, lsr #20 68: 000100c0 andeq r0, r1, r0, asr #1 6c: 6c6c6548 cfstr64vs mvdx6, [ip], #-288 ; 0xfffffee0 70: 77202c6f strvc r2, [r0, -pc, ror #24]! 74: 646c726f strbtvs r7, [ip], #-623 ; 0xfffffd91 78: Address 0x00000078 is out of bounds. 由于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的某 些用法而已。