One method that I use to conceal behavior is to embed the shared library in the main executable. It is perfectly hackable but it is simple and removes the plausible deniability protection from the user in case they try to hack.
The simplest form is like this:
// hacklib.cpp - the library
// This is the function we want to conceal
#include <cstdio>
extern "C" {
void doit() {
printf("Hello World!!!\n");
}
}
Then you compile it and export it as a C code array with xxd
$ g++ -shared -O2 hacklib.cpp -o hacklib.so
$ xxd -i -c 12 hacklib.so > hacklib_so.h
It will look like this:
unsigned char hacklib_so[] = {
0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x3e, 0x00, 0x01, 0x00, 0x00, 0x00,
...
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
unsigned int hacklib_so_len = 16200;
Then you include it in your main as a C-array. At runtime you open a file in shared memory, dump the contents and load the shared library with dlopen.
At this point, once the library is already open, it is okay to remove the file on the disk as the file will continue to exist in memory as an inode. This way the file only appears for a split second in the filesystem.
With the shared library handle, you search for the entry level symbol you want, usually a factory of sorts.
//
// This is your main application
//
#include "hacklib_so.h"
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <dlfcn.h>
#include <assert.h>
typedef void doitfn();
const char* filename = "/dev/shm/s0m3g4rbl3dm3ss.txt";
int main() {
int fd = open(filename, O_RDWR | O_CREAT, S_IRWXU);
size_t nb = write(fd, hacklib_so, hacklib_so_len);
assert(nb == hacklib_so_len);
close(fd);
void* shlib = dlopen(filename, RTLD_NOW);
unlink(filename); // It is okay to remove it here
doitfn* doit = (doitfn*)dlsym(shlib, "doit");
doit();
dlclose(shlib);
}
Afterwards you close the library and remove the file.
$ g++ -O2 hackmain.cpp -o hackmain -l dl
$ ./hackmain
Hello World!!!