Linux: update embedded resource from executable - linux

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()

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.

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.

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.

Related

Can "tee" command in linux print both the input and the output of a C program?

I have a simple C program where the it will ask to take an integer from the user, and then it will print that integer.
#include <stdio.h>
int main() {
int number;
printf("Enter an integer: ");
scanf("%d", &number);
printf("You entered: %d", number);
return 0;}
When I use this command:
gcc program.c -o test
./test | tee text.txt
The program running on terminal does not print the enter integer line but instead, waits for an input and when I provide that input, it prints it and also into the text.txt folder. I want to run the program as it is and store everything running on terminal into the text.txt folder including both the input and the output. Any possible way to do that?
The tee command works with one input, but you want to capture two. With some care, you could use two separate tee commands two copy both the input and the output to the same file, but you would be better off with a utility designed for your purpose, such as script.
For Debian based Linuxes, run apt install devscripts, and then try the annotate-output util. For example, run cat using a process substitution and a file that's not there at all:
annotate-output cat <(echo hello) /bin/nosuchfile
...which shows what otherwise would be input, output, and standard error output, all sent to standard output which could then be piped to a file:
13:01:03 I: Started cat /dev/fd/63 /bin/nosuchfile
13:01:03 O: hello
13:01:03 E: cat: /bin/nosuchfile: No such file or directory
13:01:03 I: Finished with exitcode 1

How to determine the configuration of gcc from a bash script?

I have a bash script that compiles a program as well on older versions of Ubuntu (14.04.x and 16.04.x) than on the last one (18.04.x) and on other distributions (Arch, CentOS, Debian, Fedora, etc.) and therefore... with different gcc settings.
Then, to obtain an executable that can be launched (among other ways) by a double click, I must compile this program without the "-no-pie" option with older versions of gcc setting (Ubuntu 14.04.x and 16.04.x) when I have to use this option "=no-pie" for the new version of the gcc 7.3 setting (on Ubuntu 18.04.x).
The problem is that on the last Ubuntu release (18.04.x) and its derivatives (Kubuntu, Xbuntu, etc. and maybe with other distributions) with the new configuration of gcc (7.3) having the option "--enable-default-pie", if I compile my program without the option "-no-pie", the result is that the file created is an executable which is of the "shared library" type which can not be launched by a double click.
My question is either:
a) Is there a command that allows me to determine from a bash script if gcc is configured with the "--enable-default-pie" setting?
b) if not, is there a command that allows me to determine from a bash script if the compiled file is of the "shared library" or "executable" type?
For this second option, a solution could be how to save the response of "gcc -v" in a .txt file and check if there is the "--enable-default-pie" string but I've absolutely no clue how to do it.
If I there is not an answer to my first option, the second option (it is true less elegant but just as effective) would allow me to compile my program first without the "-no-pie" option, then check the status of such a created executable and if the result is a "shared library", of restart this compilation this time using the option "-no-pie" for, in one case as in the other, get an executable that can be launched by a double click whatever the setting of gcc may be.
Thank you in advance for your time, ideas and suggestions.
Best regards.
The recommend way to check for PIE support is to compile C code like this
#if defined __PIC__ || defined __pic__ || defined PIC || defined pic
# error PIC is default.
#endif
with the requested compiler flags and check whether there is an error. If you need special treatment for PIE, this will recognize PIE if it has been specified through the CC or CFLAGS variables, even if is not immediately apparent there. For example, for technical reasons, Fedora hides the PIE flags behind a -specs argument.
Yes, you can check GCC build options with gcc -v or gcc -###
In order to have pretty print you can use:
gcc -### -E 2>&1 | grep "Configured with" | sed 's/--/\n--/g'
So bash oneliner to say you have pie or not may be:
if [[ -n "`gcc -v -E 2>&1 | grep 'Configured with' | sed 's/--/\n--/g' | grep enable-default-spie`" ]]; then echo "PIE DEFAULT"; else echo "PIE NOT DEFAULT"; fi
To check file type just use file command, eg.:
file /usr/bin/x86_64-linux-gnu-gcc-7
/usr/bin/x86_64-linux-gnu-gcc-7: ELF 64-bit LSB executable,
x86-64, version 1 (SYSV), dynamically linked, interpreter
/lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0,
BuildID[sha1]=02ac46ba938c15f55f6fab165133e0f527bc2197, stripped
file /usr/lib/libchm.so.1.0.0
/usr/lib/libchm.so.1.0.0: ELF 64-bit LSB shared object, x86-64,
version 1 (SYSV), dynamically linked,
BuildID[sha1]=7c603d9a0771b5bfd5b869b4446e2f78ef13802a, stripped
File type function
function whatfile { file $1 -i | grep application | sed 's/^.*application\/x-//g;s/,.*$//g'; }
Example output:
aaa#xxx:~ $ whatfile /boot/grub/grub.conf
aaa#xxx:~ $ whatfile /usr/lib/libnss3.so
sharedlib
aaa#xxx:~ $ whatfile /bin/zcat
executable
Unfortunately, comments don't allow CR+LF (to show pre-formatted text).
Below is my formatted translation of your gcc setting command:
check_gcc_setting()
{
if [ -n "`gcc -v -E 2>&1 | grep 'Configured with' | sed 's/--/\n--/g' | grep enable-default-pie`" ]
then
GCC_SETTING="1"
else
GCC_SETTING="0"
fi
read -p "The gcc setting is $GCC_SETTING " GCCRESULT
}
Below is the result:
whatfile { file $1 -i | grep application | sed 's/^.*application\/x-//g;s/,.*$//g'; }
-bash: syntax error near unexpected token `}'

How to get source file name from its executable via plan9port db(1) unility?

Moving to plan9port utilites I can't get used of src utility for executables (for scripts it works fine). It refers to db(1) to get a source file-name from executable in the following way:
% echo 'main?z' | db $1 | <some staff>
where $1 is an executable program name and main?z a special instruction to db(1) debugger to print the file-name with function main.
But in my version of linux (Ubuntu) it doesn't works. db(1) do not produce a file-name, - it just prints the name of procedure: main() and no sources info.
I've tried to compile with 9c -n (I think -n prevents compiler from stripping the code) with no luck.
DWARF-2 is the key:
$ 9c -gdwarf-2 wc.c -o wc.o
$ 9l wc.o -o wc
$ echo 'p9main?z' | db wc
wc: linux 386 executable
no dt_debug section
p9main? p9main() /home/egor/plan9port/src/cmd/wc.c:21

"grep" offset of ascii string from binary file

I'm generating binary data files that are simply a series of records concatenated together. Each record consists of a (binary) header followed by binary data. Within the binary header is an ascii string 80 characters long. Somewhere along the way, my process of writing the files got a little messed up and I'm trying to debug this problem by inspecting how long each record actually is.
This seems extremely related, but I don't understand perl, so I haven't been able to get the accepted answer there to work. The other answer points to bgrep which I've compiled, but it wants me to feed it a hex string and I'd rather just have a tool where I can give it the ascii string and it will find it in the binary data, print the string and the byte offset where it was found.
In other words, I'm looking for some tool which acts like this:
tool foobar filename
or
tool foobar < filename
and its output is something like this:
foobar:10
foobar:410
foobar:810
foobar:1210
...
e.g. the string which matched and a byte offset in the file where the match started. In this example case, I can infer that each record is 400 bytes long.
Other constraints:
ability to search by regex is cool, but I don't need it for this problem
My binary files are big (3.5Gb), so I'd like to avoid reading the whole file into memory if possible.
grep --byte-offset --only-matching --text foobar filename
The --byte-offset option prints the offset of each matching line.
The --only-matching option makes it print offset for each matching instance instead of each matching line.
The --text option makes grep treat the binary file as a text file.
You can shorten it to:
grep -oba foobar filename
It works in the GNU version of grep, which comes with linux by default. It won't work in BSD grep (which comes with Mac by default).
You could use strings for this:
strings -a -t x filename | grep foobar
Tested with GNU binutils.
For example, where in /bin/ls does --help occur:
strings -a -t x /bin/ls | grep -- --help
Output:
14938 Try `%s --help' for more information.
162f0 --help display this help and exit
I wanted to do the same task. Though strings | grep worked, I found gsar was the very tool I needed.
http://tjaberg.com/
The output looks like:
>gsar.exe -bic -sfoobar filename.bin
filename.bin: 0x34b5: AAA foobar BBB
filename.bin: 0x56a0: foobar DDD
filename.bin: 2 matches found

What is a reliable way to determine which shared library will be loaded across linux platforms?

I need to find out which library will be loaded given in the information returned from /sbin/ldconfig. I came up with the following:
#!/bin/bash
echo $(dirname $(/sbin/ldconfig -p | awk "/$1/ {print \$4}" | head -n 1))
Running this results with:
$ whichlib libGL.so
/usr/X11R6/lib
This a two part question:
Will this produce a reliable result across platform?
Is there a slicker way to parse the output of ldconfig?
Thanks,
Paul
There're several ways the library is loaded by executeable:
1.
Using $LD_LIBRARY_PATH
Using ld cache
Libary with full path compiled into binary (-rpath gcc flag)
You're using option 2, while option 1 and 3 are not considered.
Depending on what exactly you're doing you may want to run ldd directly on the executable you're planning to run rather than the general case ldconfig.
Since you asked, you could write your script like this:
dirname "$(/sbin/ldconfig -p | awk "\$1 == "$1" {print \$4; exit}")"
It's a little more precise and has one less pipe. Also echo $(cmd) is redundant; you can just write cmd.

Resources