將二進制文件作爲目標文件中的一個段


本文將展示,如何將一個二進制文件(如圖片、音頻等)作爲目標文件中的一個段,該技巧主要應用在一些無文件系統的平臺。


本次的實驗場景爲i386:x86-64 GNU/Linux,測試音頻爲nhxc.wav,測試程序爲bin2obj.c

查看該平臺的ELF文件相關信息

生成目標文件

$ gcc -c bin2obj.c -o bin2obj.o

查看該平臺ELF文件相關信息

$ objdump -x bin2obj.o

bin2obj.o:     file format elf64-x86-64
bin2obj.o
architecture: i386:x86-64, flags 0x00000011:
HAS_RELOC, HAS_SYMS
start address 0x0000000000000000

由上可知,文件格式爲elf64-x86-64CPU架構爲architecture

轉換

首先通過objcopy --help選項查看相關參數的意義:

$ objcopy --help
-I --input-target <bfdname>      Assume input file is in format <bfdname>
-O --output-target <bfdname>     Create an output file in format <bfdname>
-B --binary-architecture <arch>  Set output arch, when input is arch-less
......
objcopy: supported targets: elf64-x86-64 elf32-i386 elf32-iamcu elf32-x86-64 a.out-i386-linux pei-i386 pei-x86-64 elf64-l1om elf64-k1om elf64-little elf64-big elf32-little elf32-big pe-x86-64 pe-bigobj-x86-64 pe-i386 plugin srec symbolsrec verilog tekhex binary ihex

由上可知,-I選項指定輸入文件的格式,-O指定輸出文件的格式,在supported targets中選擇對應的格式;-B是指定目標文件的架構i386:x86-64,即上文objdump -x命令查詢的architecture

轉換:

$ objcopy -I binary -O elf64-x86-64 -B i386:x86-64 nhxc.wav audio.o

查看轉換後生成的目標文件:

$ objdump -x audio.o

audio.o:     file format elf64-x86-64
audio.o
architecture: i386:x86-64, flags 0x00000010:
HAS_SYMS
start address 0x0000000000000000

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .data         0000fab0  0000000000000000  0000000000000000  00000040  2**0
                  CONTENTS, ALLOC, LOAD, DATA
SYMBOL TABLE:
0000000000000000 l    d  .data	0000000000000000 .data
0000000000000000 g       .data	0000000000000000 _binary_nhxc_wav_start
000000000000fab0 g       .data	0000000000000000 _binary_nhxc_wav_end
000000000000fab0 g       *ABS*	0000000000000000 _binary_nhxc_wav_size

可以看到file formatarchitecture信息與bin2obj.o的相同,_binary_nhxc_wav_start指向音頻內容的起始地址,_binary_nhxc_wav_end指向音頻內容的結尾地址,_binary_nhxc_wav_size指向文件大小的存儲地址。

_binary_*_start/end/size*是二進制文件的文件名及後綴名。

測試

bin2obj.c

#include <stdio.h>
#include <elf.h>

extern _binary_nhxc_wav_start;
extern _binary_nhxc_wav_end;
extern _binary_nhxc_wav_size;

int main() {
	printf("binary to object:\n");
    
	printf("elf head: %ld\n", sizeof(Elf64_Ehdr));
    printf("_binary_nhxc_wav_size: %p\n_binary_nhxc_wav_end: %p\n_binary_nhxc_wav_size: %p\n", &_binary_nhxc_wav_start, &_binary_nhxc_wav_end,  &_binary_nhxc_wav_size);

    unsigned char * audio_buf = (unsigned char *)&_binary_nhxc_wav_start;
    unsigned long size = (unsigned long)&_binary_nhxc_wav_size;

	FILE *fp = fopen("./out.wav", "wb");
	if (!fp) {
		fprintf(stderr, "fopen failed!\n");
		return -1;
	}

	fwrite(audio_buf, size, 1, fp);

	fclose(fp);

	return 0;
}

通過_binary_nhxc_wav_start_binary_nhxc_wav_size兩個符號,讀取音頻文件。

編譯並運行:

$ gcc -c bin2obj.c -o bin2obj.o
$ g++ bin2obj.o audio.o -o bin2obj
$ ./bin2obj
binary to object:
elf head: 64
_binary_nhxc_wav_size: 0x601040
_binary_nhxc_wav_end: 0x610af0
_binary_nhxc_wav_size: 0xfab0

比對寫入的文件out.wav與原始文件nhxc.wav,完全一致:

155e62d81e84fa7493fefe82223bcc2a  nhxc.wav
155e62d81e84fa7493fefe82223bcc2a  out.wav

查看audio.o:

$ hexdump -C audio.o | head -n 5
00000000  7f 45 4c 46 02 01 01 00  00 00 00 00 00 00 00 00  |.ELF............|
00000010  01 00 3e 00 01 00 00 00  00 00 00 00 00 00 00 00  |..>.............|
00000020  00 00 00 00 00 00 00 00  d0 fb 00 00 00 00 00 00  |................|
00000030  00 00 00 00 40 00 00 00  00 00 40 00 05 00 02 00  |....@.....@.....|
00000040  52 49 46 46 a8 fa 00 00  57 41 56 45 66 6d 74 20  |RIFF....WAVEfmt |

如程序輸出,ELF文件頭部信息結構體爲64字節,而轉換生成的目標文件中,音頻內容始於0x40字節偏移(wav頭始於RIFF,可以參考wav文件解析),而0x40正是十進制的64

Reference

  • 《程序員的自我修養——鏈接、裝載與庫》P68

微信公衆號同步更新,微信搜索"AnSwEr不是答案"或者掃描二維碼,即可訂閱。

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章