get the function offset and jump to the function at runtime dynamically

Indeed, getting the function offset dynamically during runtime would require you to parse the symbol table of the binary. This is a complex task that would usually be done using a library like libelf or libbfd.

However, if you want a simpler solution that uses command-line tools, you can use nm or readelf to create a text file with the function offsets, and then read that file at runtime. Here’s how you might do it:

  1. Compile your program with debug symbols and without ASLR:

    1
    gcc -g -fno-pie -no-pie myprogram.c -o myprogram
  2. Create a text file with the function offsets:

    1
    nm myprogram | grep ' T ' > offsets.txt

    This command will create a text file called offsets.txt that contains the offsets of all the functions in myprogram. The ‘T’ indicates that we are interested in the text (code) section of the binary.

  3. Read the offsets file at runtime and create function pointers:

    Here’s an example in C that reads the offsets file and creates a function pointer for my_function:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

void my_function() {
printf("Hello, world!\n");
}

int main() {
FILE *file = fopen("offsets.txt", "r");
if (file == NULL) {
printf("Cannot open offsets file!\n");
return 1;
}

uintptr_t offset = 0;
char name[256];

while (fscanf(file, "%lx %*s %255s", &offset, name) == 2) {
if (strcmp(name, "my_function") == 0) {
break;
}
}

fclose(file);

if (strcmp(name, "my_function") != 0) {
printf("Did not find my_function!\n");
return 1;
}

// Cast the offset to a function pointer
void (*func_ptr)() = (void (*)())offset;

// Call the function through the pointer
func_ptr();

return 0;
}

This program reads the offsets file, line by line, until it finds my_function. It then creates a function pointer using the offset and calls the function.

Note that this only works if your program is compiled without ASLR (hence the -no-pie flag to gcc). If ASLR is enabled, the offsets will be different every time the program is run. Also note that this example only works for function with no parameters, if your function has parameters, you need to adjust the function pointer type accordingly.

Please be aware that parsing the symbol table and manually creating function pointers like this is risky and not generally recommended. It can easily lead to crashes, undefined behavior, or security vulnerabilities if not done properly. Use it carefully and only if you understand exactly what you are doing.

dlsym

It’s indeed unusual and more complex to dynamically determine the offset and execute a function at runtime. For this, you would need to parse the binary’s symbol table at runtime. Here’s a rough idea of how you might do it using the dlfcn library’s dlsym function, which can find a function’s address in a dynamically linked executable at runtime:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <stdio.h>
#include <dlfcn.h>

void my_function() {
printf("Hello, world!\n");
}

int main() {
void* handle = dlopen(NULL, RTLD_LAZY); // Open the current executable
if (!handle) {
fprintf(stderr, "%s\n", dlerror());
return 1;
}

dlerror(); // Clear any existing error

// Find the function in the executable's symbol table
void (*func_ptr)() = dlsym(handle, "my_function");

char* error = dlerror();
if (error) {
fprintf(stderr, "%s\n", error);
return 1;
}

// Call the function through the pointer
func_ptr();

dlclose(handle); // Close the executable

return 0;
}

This example uses the dlopen function to open the current executable (the NULL argument means to open the current process’s symbol table), the dlsym function to find the function in the symbol table, and a function pointer to call the function.

This approach requires that your executable is dynamically linked and the function is exposed in the symbol table, i.e., it’s not declared as static and not stripped out by the linker or strip tool. You may need to pass the -rdynamic option to the linker (usually via -Wl,-export-dynamic gcc option) to ensure that the symbol is included in the dynamic symbol table.

Again, manipulating function pointers like this can be dangerous and is generally not recommended unless you know what you are doing. The best way to call a function at runtime is typically to use a function pointer that is set at compile time.

get the function offset and jump to the function at runtime dynamically

https://www.yunwei37.com/2023/06/09/symbol/

Author

yunwei37

Posted on

2023-06-09

Updated on

2024-10-12

Licensed under

Comments