Ke ʻimi nei iā LD_PRELOAD

Ua kākau ʻia kēia memo ma 2014, akā ua hoʻopaʻa ʻia au ma Habré a ʻaʻole ia i ʻike i ka mālamalama o ka lā. I ka wā o ka pāpā ua poina wau iā ia, akā i kēia manawa ua loaʻa iaʻu i loko o nā kikoʻī. Noʻonoʻo wau e hoʻopau iā ia, akā pono paha ia i kekahi.

Ke ʻimi nei iā LD_PRELOAD

Ma keʻano laulā, heluhelu ʻia kahi luna o ka Pōʻalima ma ke kumuhana o ka ʻimi ʻana no "included" LD_PRELOAD.

1. ʻO kahi digression pōkole no ka poʻe ʻike ʻole i ka hoʻololi hana

Hiki i ke koena ke hele pololei i p.2.

E hoʻomaka kākou me kahi laʻana maʻamau:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main()
{
  srand (time(NULL));
  for(int i=0; i<5; i++){
    printf ("%dn", rand()%100);
  }
}

Hoʻopili mākou me ka ʻole o nā hae:

$ gcc ./ld_rand.c -o ld_rand

A, e like me ka mea i manaʻo ʻia, loaʻa iā mākou nā helu 5 ma lalo o 100:

$ ./ld_rand
53
93
48
57
20

Akā, e noʻonoʻo kākou ʻaʻole i loaʻa iā mākou ke kumu kumu o ka papahana, akā pono mākou e hoʻololi i ke ʻano.

E hana mākou i kā mākou waihona ponoʻī me kā mākou prototype hana ponoʻī, no ka laʻana:

int rand(){
  return 42;
}

$ gcc -shared -fPIC ./o_rand.c -o ld_rand.so

A i kēia manawa ua ʻike maopopo ʻia kā mākou koho koho:

# LD_PRELOAD=$PWD/ld_rand.so ./ld_rand
42
42
42
42
42

ʻOi aku ka maikaʻi o kēia hoʻopunipuni inā mākou e lawe mua i kā mākou waihona ma o

$ export LD_PRELOAD=$PWD/ld_rand.so

a i ʻole e hana mua mākou

# echo "$PWD/ld_rand.so" > /etc/ld.so.preload

a laila holo i ka papahana e like me ka maʻamau. ʻAʻole mākou i hoʻololi i hoʻokahi laina o ke code i loko o ka papahana ponoʻī, akā aia kāna hana i kēia manawa i kahi hana liʻiliʻi i kā mākou waihona. Eia kekahi, i ka manawa kākau i ka papahana, ka palaoa ʻaʻole i loaʻa.

He aha ka mea i hoʻohana ai kā mākou polokalamu i kahi hoʻopunipuni palaoa? E lawe kāua i kēlā me kēia pae.
Ke hoʻomaka kahi noi, hoʻouka ʻia kekahi mau hale waihona puke i loaʻa nā hana e pono ai ka papahana. Hiki iā mākou ke nānā iā lākou me ka hoʻohana ldd:

# ldd ./ld_rand
        linux-vdso.so.1 (0x00007ffc8b1f3000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fe3da8af000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fe3daa7e000)

Hiki ke ʻokoʻa kēia papa inoa ma muli o ka mana OS, akā pono e loaʻa kahi faila ma laila libc.so. ʻO ia ka waihona e hāʻawi i nā kelepona ʻōnaehana a me nā hana maʻamau e like me hamama, malloc, paʻi etc. Ko makou palaoa aia no hoi iwaena o lakou. E hōʻoia i kēia:

# nm -D /lib/x86_64-linux-gnu/libc.so.6 | grep " rand$"
000000000003aef0 T rand

E ʻike inā hoʻololi ka pūʻulu waihona i ka wā i hoʻohana ʻia LD_PRELOAD

# LD_PRELOAD=$PWD/ld_rand.so ldd ./ld_rand
        linux-vdso.so.1 (0x00007ffea52ae000)
        /scripts/c/ldpreload/ld_rand.so (0x00007f690d3f9000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f690d230000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f690d405000)

Ua hoʻonohonoho ʻia ka loli LD_PRELOAD hoʻoikaika i kā mākou e hoʻouka ld_rand.so ʻoiai ʻoiai ʻaʻole pono ka papahana ponoʻī iā ia. A mai kā mākou hana "rand" nā ukana ma mua o palaoa от libc.so, a laila hoʻomalu ʻo ia i ka moa.

ʻAe, hiki iā mākou ke hoʻololi i ka hana maoli, akā pehea e hiki ai iā mākou ke hōʻoia e mālama ʻia kāna hana a hoʻohui ʻia kekahi mau hana. E hoʻololi i kā mākou random:

#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
 
typedef int (*orig_rand_f_type)(void);
 
int rand()
{
  /* Выполняем некий код */
  printf("Evil injected coden");
  
  orig_rand_f_type orig_rand;
  orig_rand = (orig_rand_f_type)dlsym(RTLD_NEXT,"rand");
  return orig_rand();
}

Maʻaneʻi, e like me kā mākou "hoʻohui", paʻi wale mākou i hoʻokahi laina o ka kikokikona, a laila hana mākou i kahi kuhikuhi i ka hana kumu palaoa. No ka loaʻa ʻana o ka helu wahi o kēia hana pono mākou dlsym he hana mai ka waihona libdlka mea e loaa i ko kakou palaoa i loko o kahi pūʻulu o nā hale waihona puke. A laila e kapa mākou i kēia hana a hoʻihoʻi i kona waiwai. No laila, pono mākou e hoʻohui "-ldl" i ka wā e hui ai:

$ gcc -ldl -shared -fPIC ./o_rand_evil.c -o ld_rand_evil.so

$ LD_PRELOAD=$PWD/ld_rand_evil.so ./ld_rand
Evil injected code
66
Evil injected code
28
Evil injected code
93
Evil injected code
93
Evil injected code
95

A ke hoʻohana nei kā mākou papahana i ka "maoli" palaoa, ua hana mua i kekahi mau hana haumia.

2. Ka eha o ka huli

Ke ʻike nei e pili ana i kahi hoʻoweliweli, makemake mākou e ʻike i kēlā preload Ua hana ʻia. ʻIke ʻia ʻo ke ala maikaʻi loa e ʻike ai ʻo ia ka hoʻokomo ʻana i loko o ka kernel, akā makemake wau i nā koho ʻike i ka userspace.

A laila, e hele pū mai nā ʻoluʻolu no ka ʻike ʻana a me kā lākou hōʻole ʻana.

2.1. E hoʻomaka maʻalahi

E like me ka mea i ʻōlelo ʻia ma mua, hiki iā ʻoe ke kuhikuhi i ka waihona e hoʻouka me ka hoʻohana ʻana i ka loli LD_PRELOAD a i ʻole ma ke kākau ʻana ma kahi faila /etc/ld.so.preload. E hana kākou i ʻelua mea ʻike maʻalahi.

ʻO ka mea mua e nānā i ka hoʻololi kaiapuni i hoʻonohonoho ʻia:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>

int main()
{
  char*  pGetenv = getenv("LD_PRELOAD");
  pGetenv != NULL ?
    printf("LD_PRELOAD (getenv) [+]n"):
    printf("LD_PRELOAD (getenv) [-]n");
}

ʻO ka lua e nānā inā wehe ʻia ka faila:

#include <stdio.h>
#include <fcntl.h>

int main()
{
  open("/etc/ld.so.preload", O_RDONLY) != -1 ?
    printf("LD_PRELOAD (open) [+]n"):
    printf("LD_PRELOAD (open) [-]n");
}

E hoʻouka kākou i nā hale waihona puke:

$ export LD_PRELOAD=$PWD/ld_rand.so
$ echo "$PWD/ld_rand.so" > /etc/ld.so.preload

$ ./detect_base_getenv
LD_PRELOAD (getenv) [+]
$ ./detect_base_open
LD_PRELOAD (open) [+]

Ma ʻaneʻi a ma lalo, [+] hōʻike i ka ʻike kūleʻa.
No laila, [-] ʻo ia hoʻi ke kaʻe ʻana i ka ʻike.

Pehea ka maikaʻi o ia mea ʻike? E nānā mua kākou i ka hoʻololi kaiapuni:

#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <dlfcn.h>

char* (*orig_getenv)(const char *) = NULL;
char* getenv(const char *name)
{
    if(!orig_getenv) orig_getenv = dlsym(RTLD_NEXT, "getenv");
    if(strcmp(name, "LD_PRELOAD") == 0) return NULL;
    return orig_getenv(name);
}

$ gcc -shared -fpic -ldl ./ld_undetect_getenv.c -o ./ld_undetect_getenv.so
$ LD_PRELOAD=./ld_undetect_getenv.so ./detect_base_getenv
LD_PRELOAD (getenv) [-]

Pēlā nō, hoʻopau mākou i ka leka hamama:

#define _GNU_SOURCE
#include <string.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <errno.h>

int (*orig_open)(const char*, int oflag) = NULL;

int open(const char *path, int oflag, ...)
{
    char real_path[256];
    if(!orig_open) orig_open = dlsym(RTLD_NEXT, "open");
    realpath(path, real_path);
    if(strcmp(real_path, "/etc/ld.so.preload") == 0){
        errno = ENOENT;
        return -1;
    }
    return orig_open(path, oflag);
}

$ gcc -shared -fpic -ldl ./ld_undetect_open.c -o ./ld_undetect_open.so
$ LD_PRELOAD=./ld_undetect_open.so ./detect_base_open
LD_PRELOAD (open) [-]

ʻAe, hiki ke hoʻohana ʻia nā ala ʻē aʻe e komo ai i ka faila ma ʻaneʻi, e like me, wehe64, moku'āina etc., akā, ʻoiaʻiʻo, pono nā laina like 5-10 o ke code e hoʻopunipuni iā ​​​​lākou.

2.2. E neʻe kāua

Ma luna aʻe mākou i hoʻohana ai getenv() e loaa ka waiwai LD_PRELOAD, akā aia kekahi ala "haʻahaʻa" e hiki ai ʻO ENV-nā hoʻololi. ʻAʻole mākou e hoʻohana i nā hana waena, akā e kuhikuhi i ka array ** puni, e mālama ana i kope o ke kaiapuni:

#include <stdio.h>
#include <string.h>

extern char **environ;
int main(int argc, char **argv) {
  int i;
  char env[] = "LD_PRELOAD";
  if (environ != NULL)
    for (i = 0; environ[i] != NULL; i++)
    {
      char * pch;
      pch = strstr(environ[i],env);
      if(pch != NULL)
      {
        printf("LD_PRELOAD (**environ) [+]n");
        return 0;
      }
    }
  printf("LD_PRELOAD (**environ) [-]n");
  return 0;
}

No ka mea, ke heluhelu pololei nei mākou i ka ʻikepili mai ka hoʻomanaʻo ʻana, ʻaʻole hiki ke kāpae ʻia kēlā kelepona, a ʻo kā mākou undetect_getenv ʻaʻole ia e hoʻopilikia hou i ka ʻike ʻana i ke komo ʻana.

$ LD_PRELOAD=./ld_undetect_getenv.so ./detect_environ
LD_PRELOAD (**environ) [+]

Me he mea lā ua hoʻoholo ʻia kēia pilikia? Ke hoʻomaka nei nō.

Ma hope o ka hoʻomaka ʻana o ka papahana, ka waiwai o ka mea hoʻololi LD_PRELOAD ʻAʻole pono nā mea hackers i ka hoʻomanaʻo, ʻo ia hoʻi, hiki iā lākou ke heluhelu a holoi iā ia ma mua o ka hoʻokō ʻana i nā ʻōlelo aʻoaʻo. ʻO kaʻoiaʻiʻo, ʻo ka hoʻoponopono ʻana i kahi ʻano hoʻomanaʻo, ma ka liʻiliʻi, he ʻano papahana maikaʻi ʻole, akā hiki anei i kēia ke hoʻōki i ka mea makemake ʻole iā mākou?

No ka hana ʻana i kēia, pono mākou e hana i kā mākou hana hoʻopunipuni init(), kahi i hoʻopaʻa ʻia ai mākou LD_PRELOAD a hāʻawi i kā mākou loulou:

#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <dlfcn.h>
#include <stdlib.h>

extern char **environ;
char *evil_env;
int (*orig_execve)(const char *path, char *const argv[], char *const envp[]) = NULL;


// Создаём фейковую версию init
// которая будет вызвана при загрузке программы
// до выполнения каких-либо инструкций

void evil_init()
{
  // Сначала сохраним текущее значение LD_PRELOAD
  static const char *ldpreload = "LD_PRELOAD";
  int len = strlen(getenv(ldpreload));
  evil_env = (char*) malloc(len+1);
  strcpy(evil_env, getenv(ldpreload));

  int i;
  char env[] = "LD_PRELOAD";
  if (environ != NULL)
    for (i = 0; environ[i] != NULL; i++) {
      char * pch;
      pch = strstr(environ[i],env);
      if(pch != NULL) {
        // Избавляемся от текущего LD_PRELOAD
        unsetenv(env);
        break;
      }
    }
}

int execve(const char *path, char *const argv[], char *const envp[])
{
  int i = 0, j = 0, k = -1, ret = 0;
  char** new_env;
  if(!orig_execve) orig_execve = dlsym(RTLD_NEXT,"execve");

  // Проверям не существует ли других установленных LD_PRELOAD
  for(i = 0; envp[i]; i++){
    if(strstr(envp[i], "LD_PRELOAD")) k = i;
  }
  // Если LD_PRELOAD не было установлено до нас, то добавим его
  if(k == -1){
    k = i;
    i++;
  }
  // Создаём новое окружение
  new_env = (char**) malloc((i+1)*sizeof(char*));

  // Копируем старое окружение, за исключением LD_PRELOAD
  for(j = 0; j < i; j++) {
    // перезаписываем или создаём LD_PRELOAD
    if(j == k) {
      new_env[j] = (char*) malloc(256);
      strcpy(new_env[j], "LD_PRELOAD=");
      strcat(new_env[j], evil_env);
    }
    else new_env[j] = (char*) envp[j];
  }
  new_env[i] = NULL;
  ret = orig_execve(path, argv, new_env);
  free(new_env[k]);
  free(new_env);
  return ret;
}

Hana mākou a nānā:

$ gcc -shared -fpic -ldl -Wl,-init,evil_init  ./ld_undetect_environ.c -o ./ld_undetect_environ.so
$ LD_PRELOAD=./ld_undetect_environ.so ./detect_environ
LD_PRELOAD (**environ) [-]

2.3. /proc/self/

Eia naʻe, ʻaʻole ka hoʻomanaʻo ka wahi hope loa e loaʻa ai kahi pani LD_PRELOAD, aia kekahi /proc/. E hoʻomaka kākou me ka maopopo /proc/{PID}/ka puni.

ʻOiaʻiʻo, aia kahi hoʻonā āpau no ʻike ʻole ** puni и /proc/self/ka puni. ʻO ka pilikia ka hana "hewa". unsetenv(env).

koho pololei

void evil_init()
{
  // Сначала сохраним текущее значение LD_PRELOAD
  static const char *ldpreload = "LD_PRELOAD";
  int len = strlen(getenv(ldpreload));
  evil_env = (char*) malloc(len+1);
  strcpy(evil_env, getenv(ldpreload));
 
  int i;
  char env[] = "LD_PRELOAD";
  if (environ != NULL)
    for (i = 0; environ[i] != NULL; i++) {
      char * pch;
      pch = strstr(environ[i],env);
      if(pch != NULL) {
        // Избавляемся от текущего LD_PRELOAD 
        //unsetenv(env);
        // Вместо unset просто обнулим нашу переменную
        for(int j = 0; environ[i][j] != ' '; j++) environ[i][j] = ' ';
        break;
      }
    }
}
$ gcc -shared -fpic -ldl -Wl,-init,evil_init  ./ld_undetect_environ_2.c -o ./ld_undetect_environ_2.so
$ (LD_PRELOAD=./ld_undetect_environ_2.so cat /proc/self/environ; echo) | tr " 00" "n" | grep -F LD_PRELOAD
$

Akā, e noʻonoʻo kākou ʻaʻole i loaʻa iā mākou a /proc/self/ka puni loaʻa nā ʻikepili "pilikia".

E ho'āʻo mua me kā mākou "hoʻopunipuni" mua:

$ (LD_PRELOAD=./ld_undetect_environ.so cat /proc/self/environ; echo) | tr " 00" "n" | grep -F LD_PRELOAD
LD_PRELOAD=./ld_undetect_environ.so

popoki hoʻohana like e wehe i ka faila wehe (), no laila ua like ka hopena me ka mea i hana ʻia ma ka pauku 2.1, akā i kēia manawa ke hana nei mākou i kahi faila pōkole kahi e kope ai mākou i nā waiwai o ka hoʻomanaʻo maoli me ka ʻole o nā laina i loaʻa. LD_PRELOAD.

#define _GNU_SOURCE
#include <dlfcn.h>

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <limits.h>
#include <errno.h>

#define BUFFER_SIZE 256

int (*orig_open)(const char*, int oflag) = NULL;
char *soname = "fakememory_preload.so";

char *sstrstr(char *str, const char *sub)
{
  int i, found;
  char *ptr;
  found = 0;
  for(ptr = str; *ptr != ' '; ptr++) {
    found = 1;
    for(i = 0; found == 1 && sub[i] != ' '; i++){
      if(sub[i] != ptr[i]) found = 0;
    }
    if(found == 1)
      break;
  }
  if(found == 0)
    return NULL;
  return ptr + i;
}

void fakeMaps(char *original_path, char *fake_path, char *pattern)
{
  int fd;
  char buffer[BUFFER_SIZE];
  int bytes = -1;
  int wbytes = -1;
  int k = 0;

  pid_t pid = getpid();

  int fh;
  if ((fh=orig_open(fake_path,O_CREAT|O_WRONLY))==-1) {
    printf("LD: Cannot open write-file [%s] (%d) (%s)n", fake_path, errno, strerror(errno));
    exit (42);
  }
  if((fd=orig_open(original_path, O_RDONLY))==-1) {
    printf("LD: Cannot open read-file.n");
    exit(42);
  }
  do
  {
    char t = 0;
    bytes = read(fd, &t, 1);
    buffer[k++] = t;
    //printf("%c", t);
    if(t == ' ') {
      //printf("n");
  
      if(!sstrstr(buffer, "LD_PRELOAD")) {
        if((wbytes = write(fh,buffer,k))==-1) {
          //printf("write errorn");
        }
        else {
          //printf("writed %dn", wbytes);
        }
      }
      k = 0;
    }
  }
  while(bytes != 0);
    
  close(fd);
  close(fh);
}

int open(const char *path, int oflag, ...)
{
  char real_path[PATH_MAX], proc_path[PATH_MAX], proc_path_0[PATH_MAX];
  pid_t pid = getpid();
  if(!orig_open)
  orig_open = dlsym(RTLD_NEXT, "open");
  realpath(path, real_path);
  snprintf(proc_path, PATH_MAX, "/proc/%d/environ", pid);
  
  if(strcmp(real_path, proc_path) == 0) {
    snprintf(proc_path, PATH_MAX, "/tmp/%d.fakemaps", pid);
    realpath(proc_path_0, proc_path);
    
    fakeMaps(real_path, proc_path, soname);
    return orig_open(proc_path, oflag);
  }
  return orig_open(path, oflag);
}

A ua hala kēia pae:

$ (LD_PRELOAD=./ld_undetect_proc_environ.so cat /proc/self/environ; echo) | tr " 00" "n" | grep -F LD_PRELOAD
$

ʻO ka wahi maopopo aʻe /proc/self/maps. ʻAʻohe kumu o ka noho ʻana ma luna. Ua like loa ka hopena me ka mea ma mua: e kope i ka ʻikepili mai ka faila e hoʻemi i nā laina ma waena libc.so и ld.so.

2.4. Koho mai Chokepoint

Ua makemake nui au i kēia hoʻonā no kona maʻalahi. Hoʻohālikelike mākou i nā helu o nā hana i hoʻouka pololei ʻia mai libc, a me "NEXT".

#define _GNU_SOURCE

#include <stdio.h>
#include <dlfcn.h>

#define LIBC "/lib/x86_64-linux-gnu/libc.so.6"

int main(int argc, char *argv[]) {
  void *libc = dlopen(LIBC, RTLD_LAZY); // Open up libc directly
  char *syscall_open = "open";
  int i;
  void *(*libc_func)();
  void *(*next_func)();
  
  libc_func = dlsym(libc, syscall_open);
  next_func = dlsym(RTLD_NEXT, syscall_open);
  if (libc_func != next_func) {
    printf("LD_PRELOAD (syscall - %s) [+]n", syscall_open);
    printf("Libc address: %pn", libc_func);
    printf("Next address: %pn", next_func);
  }
  else {
    printf("LD_PRELOAD (syscall - %s) [-]n", syscall_open);
  }
  return 0;
}

Ke hoʻouka nei i ka waihona me ka interception "wehe()" a nānā:

$ export LD_PRELOAD=$PWD/ld_undetect_open.so
$ ./detect_chokepoint
LD_PRELOAD (syscall - open) [+]
Libc address: 0x7fa86893b160
Next address: 0x7fa868a26135

Ua ʻoi aku ka maʻalahi o ka hōʻole ʻana:

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>

extern void * _dl_sym (void *, const char *, void *);
void * dlsym (void * handle, const char * symbol)
{
  return _dl_sym (handle, symbol, dlsym);
}

# LD_PRELOAD=./ld_undetect_chokepoint.so ./detect_chokepoint
LD_PRELOAD (syscall - open) [-]

2.5. Syscalls

Me he mea lā ʻo ia wale nō, akā, e hoʻolele mau ana mākou. Inā kuhikuhi pololei mākou i ke kelepona ʻōnaehana i ka kernel, e kāpae kēia i ke kaʻina hana interception holoʻokoʻa. ʻO ka hoʻonā ma lalo nei, ʻoiaʻiʻo, pili i ka hoʻolālā (x86_64). E ho'āʻo kākou e hoʻokō ia mea e ʻike i kahi puka ld.so.preload.

#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>

#define BUFFER_SIZE 256

int syscall_open(char *path, long oflag)
{
    int fd = -1;
    __asm__ (
             "mov $2, %%rax;" // Open syscall number
             "mov %1, %%rdi;" // Address of our string
             "mov %2, %%rsi;" // Open mode
             "mov $0, %%rdx;" // No create mode
             "syscall;"       // Straight to ring0
             "mov %%eax, %0;" // Returned file descriptor
             :"=r" (fd)
             :"m" (path), "m" (oflag)
             :"rax", "rdi", "rsi", "rdx"
             );
    return fd;
 }
int main()
{
    syscall_open("/etc/ld.so.preload", O_RDONLY) > 0 ?
      printf("LD_PRELOAD (open syscall) [+]n"):
      printf("LD_PRELOAD (open syscall) [-]n");
        
}

$ ./detect_syscall
LD_PRELOAD (open syscall) [+]

A he hopena ko kēia pilikia. Wehe mai kanaka'A:

ʻO ka ptrace kahi mea hana e hiki ai i kahi kaʻina hana makua ke nānā a mālama i ka holomua o kahi kaʻina hana ʻē aʻe, nānā a hoʻololi i kāna ʻikepili a me nā papa inoa. Hoʻohana maʻamau kēia hana no ka hana ʻana i nā breakpoints i kahi papahana debugging a nānā i nā kelepona ʻōnaehana.

Hiki ke hoʻomaka ke kaʻina hana makua ma ke kāhea mua ʻana i ka fork(2), a laila hiki i ke kaʻina hana keiki ke hoʻokō i ka PTRACE_TRACEME, a ukali ʻia (maʻamau) me ka hoʻokō exec(3). Ma ka ʻaoʻao ʻē aʻe, hiki i ke kaʻina hana makua ke hoʻomaka e hoʻopau i kahi kaʻina hana e kū nei me ka hoʻohana ʻana iā PTRACE_ATTACH.

I ka huli ʻana, pau ke kaʻina hana o ke keiki i kēlā me kēia manawa e loaʻa iā ia kahi hōʻailona, ​​ʻoiai inā ʻaʻole mālama ʻia ka hōʻailona. (ʻO ka ʻokoʻa ʻo SIGKILL, e hana maʻamau.) E hoʻolaha ʻia ke kaʻina hana makua ma ke kāhea ʻana i ke kali (2), a laila hiki iā ia ke nānā a hoʻololi i nā mea o ke kaʻina hana keiki ma mua o ka hoʻomaka ʻana. A laila hiki i ka hana makua ke hoʻomau i ka holo ʻana, i kekahi mau manawa me ka nānā ʻole i ka hōʻailona i hoʻouna ʻia iā ia a i ʻole ka hoʻouna ʻana i kahi hōʻailona ʻē aʻe).

No laila, ʻo ka hoʻonā ka nānā ʻana i ke kaʻina hana, hoʻōki iā ia ma mua o kēlā me kēia kelepona ʻōnaehana a, inā pono, e hoʻohuli hou i ke kaula i kahi hana hook.

#define _GNU_SOURCE
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <limits.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <sys/reg.h>
#include <sys/user.h>
#include <asm/unistd.h>


#if defined(__x86_64__)
#define REG_SYSCALL ORIG_RAX
#define REG_SP rsp
#define REG_IP rip 
#endif

long NOHOOK = 0;

long evil_open(const char *path, long oflag, long cflag) 
{
    char real_path[PATH_MAX], maps_path[PATH_MAX];
    long ret;
    pid_t pid;
    pid = getpid();
    realpath(path, real_path);
    if(strcmp(real_path, "/etc/ld.so.preload") == 0)
    {
        errno = ENOENT;
        ret = -1;
    }
    else
    {
        NOHOOK = 1; // Entering NOHOOK section
        ret = open(path, oflag, cflag);
    }
    // Exiting NOHOOK section
    NOHOOK = 0;
    return ret;
}

void init()
{
    pid_t program;
    // Форкаем дочерний процесс
    program = fork();
    if(program != 0) {
        int status;
        long syscall_nr;
        struct user_regs_struct regs;
        // Подключаемся к дочернему процессу
        if(ptrace(PTRACE_ATTACH, program) != 0) {
            printf("Failed to attach to the program.n");
            exit(1);
        }
        waitpid(program, &status, 0);
        // Отслеживаем только SYSCALLs
        ptrace(PTRACE_SETOPTIONS, program, 0, PTRACE_O_TRACESYSGOOD);
        while(1) {
            ptrace(PTRACE_SYSCALL, program, 0, 0);
            waitpid(program, &status, 0);
            if(WIFEXITED(status) || WIFSIGNALED(status)) break;
            else if(WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP|0x80) {
                // Получаем номер системного вызова
                syscall_nr = ptrace(PTRACE_PEEKUSER, program, sizeof(long)*REG_SYSCALL);
                if(syscall_nr == __NR_open) {
                    // Читаем слово из памяти дочернего процесса
                    NOHOOK = ptrace(PTRACE_PEEKDATA, program, (void*)&NOHOOK);
                    // Перехватываем вызов
                    if(!NOHOOK) {
                        
                        // Копируем регистры дочернего процесса
                        // в переменную regs родительского
                        ptrace(PTRACE_GETREGS, program, 0, &regs);
                        // Push return address on the stack
                        regs.REG_SP -= sizeof(long);
                        // Копируем слово в память дочернего процесса
                        ptrace(PTRACE_POKEDATA, program, (void*)regs.REG_SP, regs.REG_IP);
                        // Устанавливаем RIP по адресу evil_open
                        regs.REG_IP = (unsigned long) evil_open;
                        // Записываем состояние регистров процесса
                        ptrace(PTRACE_SETREGS, program, 0, &regs);
                    }
                }
                ptrace(PTRACE_SYSCALL, program, 0, 0);
                waitpid(program, &status, 0);
            }
        }
        exit(0);
    }
    else {
        sleep(0);
    }
}

E nānā mākou:

$ ./detect_syscall
LD_PRELOAD (open syscall) [+]
$ LD_PRELOAD=./ld_undetect_syscall.so ./detect_syscall
LD_PRELOAD (open syscall) [-]

+0-0=5

Mahalo nui loa

Charles Hubain
Chokepoint
ValdikSS
Philippe Teuwen
derhass

, nona nā ʻatikala, nā kumu a me nā manaʻo i ʻoi aku ka nui ma mua o kaʻu i hana ai e hōʻike i kēia memo ma aneʻi.

Source: www.habr.com

Pākuʻi i ka manaʻo hoʻopuka