Link an ELF binary with a c program - c

Given only access to a standalone ELF program I want to be able to call a function within the program from my own program.
Let's say the below code is main.c
#include <stdio.h>
extern int mystery(int a,int b);
int main() {
int a = 0;
int b = 1;
printf("mystery(a,b) = %d\n",mystery(a,b));
return 0;
}
The function mystery exists in some elf file not_my_program.
What I'm trying to do is something along the lines of
gcc main.c not_my_program
However this gives me an undefined reference error to mystery . I've looked for methods
on forums and found that converting this elf file into a shared object file is not possible. I've also looked into compiling main.c into a relocatable object file with
gcc -c main.c
and then using ld to link the elf with main.o but I could not figure out how to do it. The elf is 32 bit but I've omitted the -m32 flag. If the flag is different for ld please let me know. Any help would be very much appreciated.
edit:
output of readelf -h not_my_program
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: DYN (Shared object file)
Machine: Intel 80386
Version: 0x1
Entry point address: 0x10e0
Start of program headers: 52 (bytes into file)
Start of section headers: 15116 (bytes into file)
Flags: 0x0
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 11
Size of section headers: 40 (bytes)
Number of section headers: 30
Section header string table index: 29

This hacky way worked with a very simple case.
[ aquila ~ ] $ cat 1.c
int func (int a) { return a * (a-1) ; }
int main(int argc) { return func (argc) ; }
[ aquila ~ ] $ cc 1.c
[ aquila ~ ] $ ./a.out ; echo $?
0
[ aquila ~ ] $ readelf -s a.out | grep func
43: 0000000000400487 19 FUNC GLOBAL DEFAULT 11 func
[ aquila ~ ] $ cat 2.c
#include <stdlib.h>
static __attribute__((constructor)) void main() {
int (*func)() = (int (*)())0x0000000000400487;
exit(func(3));
}
[ aquila ~ ] $ cc -fPIC -shared 2.c -o a.so
[ aquila ~ ] $ LD_PRELOAD=./a.so ./a.out ; echo $?
6
The caller in 2.c is made into a constructor with an exit so that the main program's main() is not called, in an attempt to limit the execution of the code other than the caller and func() itself. The return value being 6 instead of 0 shows both that the call worked and that the main program's main() did not get called.

Given only access to a standalone ELF program I want to be able to call a function within the program from my own program
It sounds like you have an XY problem.
While what you desire is technically possible, the difficulty of doing this is approximately 1000x of what you have tried so far. If you are not prepared to spend a month or two getting this working, you should look for other solutions.
Effectively you would have to write a custom ELF loader to load not_my_program into memory and initialize it, but then call mystery instead of main in it.
Note also that mystery may depend on global data, and that data may be initialized in main, so there is no guarantee that mystery will work at all when called before main.
P.S. Would it be sufficient to call mystery from a debugger? That can be achieved in under 30 seconds.

Related

Why has the .bss segment not increased when variables are added?

Recently,I learned that the .bss segment store uninitialized data. However, when I try a small program as below and use size(1) command in terminal, the .bss segment didn't change, even if I add some global variables. Do I misunderstand something?
jameschu#aspire-e5-573g:~$ cat test.c
#include <stdio.h>
int main(void)
{
printf("hello world\n");
return 0;
}
jameschu#aspire-e5-573g:~$ gcc -c test.c
jameschu#aspire-e5-573g:~$ size test.o
text data bss dec hex filename
89 0 0 89 59 test.o
jameschu#aspire-e5-573g:~$ cat test.c
#include <stdio.h>
int a1;
int a2;
int a3;
int main(void)
{
printf("hello world\n");
return 0;
}
jameschu#aspire-e5-573g:~$ gcc -c test.c
jameschu#aspire-e5-573g:~$ size test.o
text data bss dec hex filename
89 0 0 89 59 test.o
This is because the way global variables work.
The problem that is being solved is that it is possible to declare a global variable, without initializing it, in several .c files and not getting a duplicate symbol error. That is, every global uninitialized declaration works like a weak declaration, that can be considered external if no other declaration contains an initialization.
How it this implemented by the compiler? Easy:
when compiling, instead of adding that variable in the bss segment it will be added to the COMMON segment.
when linking, however, it will merge all the COMMON variables with the same name and discard anyone that is already in other section. The remaining ones will be moved to the bss of the executable.
And that is why you don't see your variables in the bss of the object file, but you do in the executable file.
You can check the contents of the object sections using a more modern alternative to size, such as objdump -x. And note how the variables are placed in *COM*.
It is worth noting that if you declare your global variable as static you are saying that the variable belongs to that compilation unit, so the COMMON is not used and you get the behavior you expect:
int a;
int b;
static int c;
$ size test.o
text data bss dec hex filename
91 0 4 95 5f test.o
Initializing to 0 will get a similar result.
int a;
int b;
int c = 0;
$ size test.o
text data bss dec hex filename
91 0 4 95 5f test.o
However initializing to anything other than 0 will move that variable to data:
int a;
int b = 1;
int c = 0;
$ size test.o
text data bss dec hex filename
91 4 4 99 5f test.o

How to load library defined symbols to a specified location?

The test is on Ubuntu 12.04, 32-bit, with gcc 4.6.3.
Basically I am doing some binary manipulation work on ELF binaries, and what I have to do now is to assemble a assembly program and guarantee the libc symbols are loaded to a predefined address by me.
Let me elaborate it in an simple example.
Suppose in the original code, libc symbols stdout#GLIBC_2.0 is used.
#include <stdio.h>
int main() {
FILE* fout = stdout;
fprintf( fout, "hello\n" );
}
When I compile it and check the symbol address using these commands:
gcc main.c
readelf -s a.out | grep stdout
I got this:
0804a020 4 OBJECT GLOBAL DEFAULT 25 stdout#GLIBC_2.0 (2)
0804a020 4 OBJECT GLOBAL DEFAULT 25 stdout##GLIBC_2.0
and the .bss section is like this:
readelf -S a.out | grep bss
[25] .bss NOBITS 0804a020 001014 00000c 00 WA 0 0 32
Now what I am trying to do is to load the stdout symbol in a predefined address, so I did this:
echo "stdout = 0x804a024;" > symbolfile
gcc -Wl,--just-symbols=symbolfile main.c
Then when I check the .bss section and symbol stdout, I got this:
[25] .bss NOBITS 0804a014 001014 000008 00 WA 0 0 4
4: 0804a024 0 NOTYPE GLOBAL DEFAULT ABS stdout
49: 0804a024 0 NOTYPE GLOBAL DEFAULT ABS stdout
It seems that I didn't successfully load the symbol stdout##GLIBC_2.0, but just a wired stdout. (I tried to write stdout##GLIBC_2.0 in symbolfile, but it can't compile... )
It seems that as I didn't make it, the beginning address of .bss section has also changed, which makes the address of stdout symbol in a non-section area. During runtime, it throws a segmentation fault when loading from 0x804a024.
Could anyone help me on how to successfully load the library symbol at a predefined address? Thanks!

What is the easiest way to find the sizeof a type without compiling and executing code?

I wrote a bash script to determine the size of gcc's datatypes (e.g. ./sizeof int double outputs the respective sizes of int and double) by wrapping each of its arguments in the following P() macro and then compiling and running the code.
#define P(x) printf("sizeof(" #x ") = %u\n", (unsigned int)sizeof(x))
The problem is that this is relative slow (it takes a whole second!), especially the linking step (since compiling with -c or -S takes virtually no time, and so does running the outputted binary). One second is not really that slow by itself, but if I were to use this script in other scripts, it would add up.
Is there a faster, less roundabout way to find out what sizes gcc uses for datatypes?
You can achieve the functionality for standard types using the GCC's preprocessor only. For standard types there are predefined macros:
__SIZEOF_INT__
__SIZEOF_LONG__
__SIZEOF_LONG_LONG__
__SIZEOF_SHORT__
__SIZEOF_POINTER__
__SIZEOF_FLOAT__
__SIZEOF_DOUBLE__
__SIZEOF_LONG_DOUBLE__
__SIZEOF_SIZE_T__
__SIZEOF_WCHAR_T__
__SIZEOF_WINT_T__
__SIZEOF_PTRDIFF_T__
So, by using code like the following:
#define TYPE_TO_CHECK __SIZEOF_INT__
#define VAL_TO_STRING(x) #x
#define V_TO_S(x) VAL_TO_STRING(x)
#pragma message V_TO_S(TYPE_TO_CHECK)
#error "terminate"
you will be able to get the value of __SIZEOF_INT__ from the preprocessor itself without even starting the compilation. In your script you can define the TYPE_TO_CHECK (with -D) to whatever you need and pass it to gcc. Of course you will get some junk output, but I believe you can deal with that.
You can use the 'negative array size' trick that autoconf (see: AC_COMPUTE_INT) uses. That way, you don't need to link or execute code. Therefore, it also works when cross compiling. e.g.,
int n[1 - 2 * !(sizeof(double) == 8)];
fails to compile if: sizeof(double) != 8
The downside is, you might have to pass -DCHECK_SIZE=8 or something similar in the command line, since it might take more than one pass to detect an unusual value. So, I'm not sure if this will be any faster in general - but you might be able to take advantage of it.
Edit: If you are using gcc exclusively, I think #wintermute's comment is probably the best solution.
Here are three possible solutions.
The first one will work with any type whose size is less than 256. On my system, it takes about 0.04s (since it doesn't need headers or libraries other than the basic runtime). One downside is that it will only do one at a time, because of the small size of the output channel. Another problem is that it doesn't compensate for slow linking on some systems (notably MinGW):
howbig() {
gcc -x c - <<<'int main() { return sizeof ('$*'); }' && ./a.out
echo $?
}
$ time howbig "struct { char c; union { double d; int i[3];};}"
24
real 0m0.041s
user 0m0.031s
sys 0m0.014s
$ time howbig unsigned long long
8
real 0m0.044s
user 0m0.035s
sys 0m0.009s
If you wanted to be able to do larger types, you could get the size one byte at a time, at the cost of a couple more centiseconds:
howbig2 ()
{
gcc -x c - <<< 'int main(int c,char**v) {
return sizeof ('$*')>>(8*(**++v&3)); }' &&
echo $((0x$(printf %02x $(./a.out 3;echo $?) $(./a.out 2;echo $?) \
$(./a.out 1;echo $?) $(./a.out 0;echo $?)) ))
}
$ time howbig2 struct '{double d; long long u[12];}([973])'
101192
real 0m0.054s
user 0m0.036s
sys 0m0.019s
If you are compiling for x86, the following will probably work, although I'm not in a position to test it thoroughly on a wide variety of architectures and platforms. It avoids the link step (notoriously slow on MinGW, for example), by analyzing the compiled assembly output. (It would probably be slightly more robust to analyze the compiled object binary, but I fear that binutils on MinGW are also slow.) Even on Ubuntu, it is significantly faster:
howbig3 () {
gcc -S -o - -x c - <<< 'int hb(void) { return sizeof ('$*'); }' |
awk '$1~/movl/&&$3=="%eax"{print substr($2,2,length($2)-2)}'
}
$ time howbig3 struct '{double d; long long u[12];}([973])'
101192
real 0m0.020s
user 0m0.017s
sys 0m0.004s
Using nm with no code
Just make your thing a global variable. nm can report its size.
// getsize.c
struct foo {
char str[3];
short s; // expect padding galore...
int i;
} my_struct;
Compile but don't link, then use nm:
$ gcc -c getsize.c
$ nm getsize.o --format=posix
my_struct C 000000000000000c 000000000000000c
Note that the last column is the size (in hex), here is how we can get it:
$ nm test.o -P | cut -d ' ' -f 4
000000000000000c
# or in decimal
$ printf %d 0x`nm test.o -P | cut -d ' ' -f 4`
12
 
Using objdump with no code
If nm doesn't work for some reason, you can store the size itself in a global variable.
Start with this C file:
// getsize.c
struct foo { char str[3]; short s; int i; };
unsigned long my_sizeof = sizeof(struct foo);
Now we have to find the value of this variable from the object file.
$ gcc -c sizeof.c
$ objdump -Sj .data sizeof.o
test.o: file format elf64-x86-64
Disassembly of section .data:
0000000000000000 <my_sizeof>:
0: 0c 00 00 00 00 00 00 00 ........
Darn, little endian! You could write a script to parse this, but the following solution (assuming GCC extensions) will force it to always be big endian:
// getsize.c
struct foo { char str[3]; short s; int i; };
struct __attribute__ ((scalar_storage_order("big-endian"))) {
unsigned long v;
} my_sizeof = { sizeof(struct foo) };
This yields:
0000000000000000 <my_sizeof>:
0: 00 00 00 00 00 00 00 0c ........
Watch out! You can't just strip out all non-hex characters because sometimes the "...." stuff on the right will be valid ASCII. But the first one should always be a .. The following command keeps things between the : and the first ..
$ gcc -c sizeof.c
$ objdump -Sj .data sizeof.o |
sed '$!d # keep last line only
s/\s//g # remove tabs and spaces
s/.*:\([^.]*\)\..*/\1/' # only keep between : and .'
000000000000000c
If you happen to be in an IDE like VS2019, you can just type char foo[sizeof(MyType)] anywhere in the code, hover over foo and get the answer :)

How can the exit status of a process depend on whether it's statically built?

A modern system:
% pacman -Q glibc gcc
glibc 2.16.0-4
gcc 4.7.1-6
% uname -sr
Linux 3.5.4-1-ARCH
A trivial program:
% < wtf.c
void main(){}
Let's do static and dynamic builds:
% gcc -o wtfs wtf.c -static
% gcc -o wtfd wtf.c
Everything looks fine:
% file wtf?
wtfd: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=0x4b421af13d6b3ccb6213b8580e4a7b072b6c7c3e, not stripped
wtfs: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=0x1f2a9beebc0025026b89a06525eec5623315c267, not stripped
Could anybody explain this to me?
% for n in $(seq 1 10); do ./wtfd; echo $?; done | xargs
0 0 0 0 0 0 0 0 0 0
% for n in $(seq 1 10); do ./wtfs; echo $?; done | xargs
128 240 48 128 128 32 64 224 160 48
Sure, one can use int main(). And -Wmain will issue a warning (return type of ‘main’ is not ‘int’).
I'd just like to understand what is going on there.
That's EXACTLY the point.
There is no "void main()". There is ALWAYS a result value, and if you don't return one and don't do anything in your program, the return value is what happens to be in the appropiate register at program start (or specifically, whatever happens to be there when main is called from the startup code). Which can certainly depend on what the program is doing before main, such as dealing with shared libs.
EDIT: to get an idea how this can happen, try this:
int foo(void)
{
return 55;
}
void main(void)
{
foo();
}
There is no guarantee, of course, but there's a good chance that this program will have an exit code of 55, simply because that's the last value returned by some function. Just imagine that call happened before main.
To further illustrate what Christian is saying. Even though you declared void main() your process will return whatever value was previous in eax (since you are on linux x86 arch).
void main() {
asm("movl $55, %eax");
}
So now it always returns 55 b/c the above code explicitly initializes eax.
$ cc rval.c
$ ./a.out
$ echo $?
55
Again this example will only work on the current major OSs since I am assuming the calling convention. There is no reason an OS could not have a different calling convention and the return value could be somewhere else (RAM, register, whatever).

How to convert from binary to relocatable object file and back?

I wish to inject an object file into an existing binary. The method I am attempting is:
Convert a compiled binary into a relocatable object file.
Use gcc/ld to link the relocatable object file with the object file to be embedded.
Given the source:
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
puts("main");
return EXIT_SUCCESS;
}
I compile this to host with the following:
gcc -Wall host.c -o host
I do the conversion to relocatable object file with:
objcopy -B i386 -I binary -O elf64-x86-64 host host.o
I then attempt a link with:
gcc host.o -o host
Ideally, this would relink the relocatable object file back to a binary. This would also give a chance to link in any extra object files. Unfortunately the command gives the following error:
/usr/lib/gcc/x86_64-linux-gnu/4.6.1/../../../x86_64-linux-gnu/crt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
collect2: ld returned 1 exit status
My question is why is this error appearing and how would I go about properly relinking?
Something I tried was to link in another object file at this point which contained a dummy main (because I figured I could manually patch up the entry point later anyway), but what happened was that the new binary seemed to relocate the old code in a weird way with the symbol table completely messed up.
Extra Information
readelf on the binary yields the following:
mike#mike-ubuntu:~/Desktop/inject-obj$ readelf -h host
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x400410
Start of program headers: 64 (bytes into file)
Start of section headers: 4424 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 9
Size of section headers: 64 (bytes)
Number of section headers: 30
Section header string table index: 27
And on the relocatable object file:
mike#mike-ubuntu:~/Desktop/inject-obj$ readelf -h host.o
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: REL (Relocatable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x0
Start of program headers: 0 (bytes into file)
Start of section headers: 8480 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 0 (bytes)
Number of program headers: 0
Size of section headers: 64 (bytes)
Number of section headers: 5
Section header string table index: 2
Rationale
For those interested, the rationale can be found here.
An executable file that is not PIE is impossible to make relocatable. Relocations have already been performed and the record of those relocations was thrown away. That is, relocating it would require finding all addresses of objects or functions inside the code and data of the binary, but it's impossible to determine whether a sequence of bytes is an address or some other sort of data or code.
There should be a way to do what you originally wanted to do (adding in new code), but the approach you're taking is doomed to failure.

Resources