1

I have an executable in which I embed a binary file resource using the objcopy method

objcopy --input binary --output elf32-i386 --binary-architecture i386 data.txt data.o

link to data.o and use

extern char _binary_data_txt_start
extern char _binary_data_txt_end

Is it possible now to update this data inside the executable? The updated data can have the same exact size, I just need to change some of the bits.

In windows PE files this is very simple to do using UpdateResource()

shoosh
  • 76,898
  • 55
  • 205
  • 325
  • 1
    Thank you, anonymous down voter who did not leave a comment. – shoosh Oct 30 '14 at 16:07
  • Do you want the updated data to be persistent or do you only want to use it as a run-time stash? I guess the former for now. The commands and names above seem to follow the example in [this LJ article](http://www.linuxjournal.com/content/embedding-file-executable-aka-hello-world-version-5967) – Paul Nov 02 '14 at 08:20
  • I see _massive_ security problems with that. SELinux will most likely be a problem, and HIDS like tripwire will hit the ceiling. Can you elaborate the use case a bit so that we can find a solution which fits your needs without alarming the digital equivalent of the friendly guys with less friendly shotguns? – Markus W Mahlberg Nov 02 '14 at 08:33
  • Not on runtime! I want it to be persistent in the executable I'm creating. The use case is a simple self-extractor installer which I want to update without recompiling. – shoosh Nov 02 '14 at 09:47
  • @shoosh: You sure you don't rather want to dig into [shar](http://linux.die.net/man/1/shar)? – Markus W Mahlberg Nov 05 '14 at 13:02

3 Answers3

4

Nothing special and nothing hard at all. I'll give you correct sequence below, but first let me to correct slightly your embedding method. Lets not use objcopy explicitly, lets use GNU LD instead to got correct entry inside ELF file.

Lets begin. This is test-emb.c file:

#include <stdio.h>

extern unsigned char data[] asm("_binary_data_txt_start");

int
main (void)
{
  fprintf(stderr, "%u, %u, %u\n", data[0] - '0', data[1] - '0', data[2] - '0');
  return 0;
}

This is resource called data.txt

12345678

This is another resource called newdata.txt

98765432

Now compile and link:

$ gcc test-emb.c -c -m32
$ gcc -o test-emb test-emb.o -Wl,--format=binary -Wl,data.txt -Wl,--format=default -m32

Try:

$ ./test-emb 
1, 2, 3

Now start dancing. Step one: determine logical and physical address of data section:

$ readelf -S test-emb | grep "\.data" | awk '{print $4}'
080496b8

$ readelf -S test-emb | grep "\.data" | awk '{print $5}'
0006b8

Step two: start and size fo binary data:

$ readelf -s test-emb | grep _binary_data_txt_start | awk '{print $2}'
080496c0

$readelf -s test-emb | grep _binary_data_txt_size | awk '{print $2}'
00000009

Step three: doing math. We do need: find offset of binary data in data, and convert it to physical starting point:

$ echo $((0x080496c0 - 0x080496b8))
8
echo $((0x0006b8 + 8))
1728

Step four: actual replacement (count value is binary data size, taht is 9):

cat newdata.txt | dd of=test-emb bs=1 seek=1728 count=9 conv=notrunc

Now check again:

$ ./test-emb 
9, 8, 7

Everything works. You may easily fold this method into script, not harder in use, that UpdateResource under Windows, but I want to give you understanding of how things are going on.

Konstantin Vladimirov
  • 6,791
  • 1
  • 27
  • 36
  • If the file size of the newdata.txt is greater than the size of the data.txt, how to UpdateResource? Can I just copy the data into the found position? Should I handle the relocation maunally? – alpha Mar 15 '16 at 03:16
  • Yes, in this case you are in trouble. Even in the case of success, you might have problems with code itself (say it wants exact resource size) and not only relocations, but even assembler code hacking might be required. I would avoid such changes if possible. – Konstantin Vladimirov Mar 15 '16 at 10:18
  • Great answer for updating fixed-size data, while still being able to do a full relink if the size changes. To speed up the dd command, you can remove the bs=1 and put oflag=seek_bytes,count_bytes. You may need to add the --wide option to readelf if you have long symbols. Another way to find the .data (or .rodata?) section is to first find the symbol entry to read the 7th column (the last one before the symbol): this is the section number. Yet another way is objdump --wide --section=.data --section=.rodata --section-headers --syms --demangle And nm won't show the addresses of the section. – Johan Boulé Dec 10 '20 at 23:58
  • Erratum to my previous comment, for dd it's iflag=count_bytes oflag=seek_bytes – Johan Boulé Dec 11 '20 at 00:31
2

When you want to update the date in the binary you will just open the file with a mean you prefer like fopen iostream or what ever.

You can also modify the data when you executable is running. Tho modify the resource in process memory you must be sure that it is in a writable section. Verify this in your MAP file.

You can control the section with --rename-section argument of the objcopy command:

objcopy -I binary -O elf32-i386 --rename-section .rodata=.data data.txt data.o

When you really want to change the content of your elf-file before it is loaded as process than you will have to read the elf header to locate the resource data. It's easier to find the data.txt when you place it in section with a name of its own using --rename-section.

Edit:

The elf file format is too complex to decribe it in just an Stackoverflow answer. You find the basic description and links to the necessary specification here at the Wiki page.

But the easiest way to modify the linker output file is to generate a new version of data.txt and run the linker.

harper
  • 13,345
  • 8
  • 56
  • 105
  • I'm not interested in runtime, just to change the executable file on disk. can objcopy tell me exactly the offset and size of the data inside the elf file? – shoosh Nov 02 '14 at 09:49
  • `objectcopy` handles the .o file. Everything it could tell you won't be relevant after linking. – harper Nov 02 '14 at 12:02
  • then how is this an answer to my question which was clearly about editing linked executables? – shoosh Nov 02 '14 at 15:38
2

Is it possible now to update this data inside the executable? The updated data can have the same exact size, I just need to change some of the bits.

Sure: just do it:

int main()
{
    unsigned char *cp = (unsigned char*) _binary_data_txt_start
    cp[0] = 'a';    // change first byte to 0x41
    cp[42] += 3;    // increment 43rd byte by 3
}

Note: if your _binary_data_txt_start ended up in .rodata, you may have to mprotect the pages on which it resides with PROT_READ|PROT_WRITE first.

Note: if you want the updated data to persist for the next execution of the binary, then harper's answer is correct: just use fopen, seek to correct place in the file, and write the data there.

That leaves the final question: how to find the correct place. If that is your question, see libelf documentation.

Employed Russian
  • 199,314
  • 34
  • 295
  • 362