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.