Raadinta LD_PRELOAD

Qoraalkan waxaa la qoray 2014, laakiin hadda uun baan la kulmay cadaadis Habré mana arkin iftiinka maalinta. Muddadii xayiraadda waan ilaaway, laakiin hadda waxaan ka dhex helay qabyo. Waxaan ku fikiray inaan tirtiro, laakiin waxaa laga yaabaa inay waxtar u leedahay qof.

Raadinta LD_PRELOAD

Guud ahaan, maamulaha wax yar oo jimce ah oo akhrinaya mawduuca raadinta "ku daray" LD_PRELOAD.

1. Digression gaaban oo loogu talagalay kuwa aan aqoon u lahayn beddelka shaqada

Inta soo hartay waxay toos u aadi kartaa ..2.

Aan ku bilowno tusaale caadi ah:

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

Waxaan uruurineynaa iyada oo aan lahayn wax calan ah:

$ gcc ./ld_rand.c -o ld_rand

Iyo, sida la filayo, waxaan helnaa 5 lambar oo random in ka yar 100:

$ ./ld_rand
53
93
48
57
20

Laakin aan qiyaasno in aanan haysanin koodka isha ee barnaamijka, laakiin waxaan u baahanahay inaan bedelno habdhaqanka.

Aan abuurno maktabad noo gaar ah oo leh nooca shaqadeena, tusaale ahaan:

int rand(){
  return 42;
}

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

Haddana doorashadayada random-ka waa wax la saadaalin karo:

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

Khiyaamadani waxay u muuqataa mid aad u cajiib badan haddii aan marka hore dhoofinno maktabadda

$ export LD_PRELOAD=$PWD/ld_rand.so

ama waanu samayn doonaa marka hore

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

ka dibna u socodsii barnaamijka sida caadiga ah. Ma aanan bedelin hal sadar oo kood ah barnaamijka laftiisa, laakiin dhaqankiisu hadda wuxuu ku xiran yahay shaqada yar ee maktabadeena. Intaa waxaa dheer, waqtiga qorista barnaamijka, the rand xitaa ma jirin.

Maxaa ka dhigay barnaamijkeena inuu isticmaalo been abuur rand? Aan talaabo talaabo u qaadno.
Marka codsigu bilaabo, maktabado gaar ah ayaa la raray kuwaas oo ka kooban hawlaha uu u baahan yahay barnaamijku. Waxaan ku arki karnaa iyaga oo isticmaalaya 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)

Liiskani wuu kala duwanaan karaa iyadoo ku xidhan nooca OS, laakiin waa inuu jiro fayl halkaas yaal libc.so. Waa maktabadda tan bixisa wicitaannada nidaamka iyo hawlaha aasaasiga ah sida furan, malloc, printf iwm. Our rand ayaa sidoo kale ka mid ah. Aan hubino tan:

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

Aynu eegno haddii qaybta maktabadaha ay isbeddelaan marka la isticmaalo 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)

Soo baxday doorsoomayaasha waa la dejiyay LD_PRELOAD nagu qasbaya in aan rarno ld_rand.so xitaa inkastoo xaqiiqda ah in barnaamijka laftiisa uusan u baahnayn. Iyo tan iyo shaqadayada "Rand" rarka ka hor rand ka libc.so, dabadeed iyadaa xukunta roogga.

Hagaag, waxaan ku guuleysanay inaan bedelno shaqada asalka ah, laakiin sidee ayaan u hubin karnaa in shaqeynteeda la ilaaliyo oo falalka qaar lagu daro. Aan wax ka beddelno si aan toos ahayn:

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

Halkan, sida "ku dar", waxaan daabacnaa hal xariiq oo qoraal ah, ka dib markaa waxaan abuurnaa tilmaame shaqada asalka ah rand. Si aan u helno ciwaanka shaqadan waxaan u baahanahay dlsym waa shaqo ka socota maktabadda libdlkaas oo naga heli doona rand oo ku jira maktabado firfircoon oo badan. Taas ka dib waxaan wici doonaa shaqadan oo aan soo celin doonaa qiimaheeda. Sidaas awgeed, waxaan u baahan doonaa inaan ku darno "-ldl" inta lagu jiro kulanka:

$ 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

Barnaamijkeenana waxa uu isticmaalaa "dhalad" rand, isagoo hore u sameeyay falal foolxun.

2. Xanuunka raadinta

Annaga oo og khatarta iman karta, waxaan rabnaa inaan ogaanno taas soo rar Waa la fuliyay. Way caddahay in habka ugu wanaagsan ee lagu ogaan karo ay tahay in lagu riixo kernel-ka, laakiin waxaan xiisaynayay fursadaha ogaanshaha ee goobta adeegsadaha.

Marka xigta, xalalka ogaanshaha iyo diidmadoodu waxay u iman doonaan labo-labo.

2.1. Aan ku bilowno fudud

Sidii hore loo sheegay, waxaad cayimi kartaa maktabadda inaad ku shubto doorsoomaha LD_PRELOAD ama adigoo ku qoraya fayl /etc/ld.so.preload. Aynu abuurno laba qalab oo fudud.

Midda kowaad waa in la hubiyo doorsoomayaasha deegaanka ee go'an:

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

Midda labaad waa in la hubiyo in faylka la furay iyo in kale:

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

Aan raro maktabadaha:

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

Halkan iyo hoosta, [+] waxay muujinaysaa ogaanshaha guusha leh.
Sidaas awgeed, [-] waxay ka dhigan tahay ogaanshaha la dhaafo.

Intee in le'eg ayuu wax-ku-sheegaha noocaas ahi waxtar u leeyahay? Aynu marka hore eegno doorsoomaha deegaanka:

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

Sidoo kale, waxaan ka takhalusnaa jeegga furan:

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

Haa, siyaabo kale oo lagu galo faylka ayaa loo isticmaali karaa halkan, sida, open64, stat iwm, laakiin, dhab ahaantii, isla 5-10 khadadka code ayaa loo baahan yahay si loo khiyaaneeyo.

2.2. Aan hore u socono

Xagga sare ayaan isticmaalnay getenv() si loo helo qiimaha LD_PRELOAD, laakiin waxa kale oo jira hab ka badan oo "heer hoose" oo lagu tago ENV-kala duwanaansho. Ma isticmaali doono hawlo dhexdhexaad ah, laakiin waxaan tixraaci doonaa soo diyaarinta ** deegaanka, kaas oo kaydiya koobiga deegaanka:

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

Maadaama halkan aan si toos ah xogta uga akhrineyno xusuusta, wicitaanka noocan oo kale ah lama joojin karo, iyo annaga aan la ogaan_getenv mar dambe ma faragelinayso aqoonsiga faragelinta.

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

Waxay u egtahay in dhibaatadan la xaliyay? Wali waa bilow

Ka dib marka barnaamijka la bilaabo, qiimaha doorsoomayaasha LD_PRELOAD Hackers hadda uma baahna xusuusta, taas oo ah, way akhrin karaan oo way tirtiri karaan ka hor intaanay fulin wax tilmaamo ah. Dabcan, tafatirka shaxanka xusuusta waa, ugu yaraan, qaab barnaamijeed xun, laakiin sidee tani u joojin kartaa qof aan runtii wanaag noo rajeynayn?

Si tan loo sameeyo waxaan u baahanahay inaan abuurno shaqadeena been abuurka ah init(), kaas oo aanu dhex galno ku rakiban LD_PRELOAD una gudbi xiriiriyahayaga:

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

Waanu fulinaa oo hubinaa:

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

Si kastaba ha ahaatee, xusuustu maaha meesha ugu dambeysa ee aad ka heli karto beddelaad LD_PRELOAD, waxaa kaloo jira /proc/. Aan ku bilowno wax muuqda /proc/{PID}/deegaan.

Dhab ahaantii, waxaa jira xal caalami ah oo loogu talagalay aan la ogaan ** deegaanka и /proc/self/environ. Dhibaatadu waa habdhaqanka "qaldan". unsetenv(env).

doorasho sax ah

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
$

Laakiin aan qiyaasno in aynaan helin iyo /proc/self/environ ka kooban yahay xogta "dhibaato leh".

Marka hore aan isku dayno "is-qarin" hore:

$ (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 wuxuu isticmaalaa isku mid si uu u furo faylka furan(), markaa xalku wuxuu la mid yahay wixii hore loo sameeyay ee qaybta 2.1, laakiin hadda waxaan abuurnaa fayl ku meel gaar ah halkaas oo aan ku koobeyno qiimaha xusuusta dhabta ah iyada oo aan lahayn khadadka 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);
}

Marxaladaanna waa laga soo gudbay:

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

Meesha cad ee xigta waa /proc/self/maps. Faa'iido ma leh in lagu dul noolaado. Xalku gabi ahaanba wuxuu la mid yahay kii hore: koobi xogta faylka laga jaray xariiqyada u dhexeeya libc.so и ld.so.

2.4. Ikhtiyaarka Chokepoint

Waxaan si gaar ah u jeclaa xalkan fududaantiisa. Waxaan is barbar dhigeynaa cinwaanada shaqooyinka si toos ah looga soo raray libc, iyo ciwaanada "XIGA"

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

Ku rarida maktabadda dhexda "furan()" oo hubi:

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

Beeninta ayaa noqotay mid ka sii fudud:

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

Waxay u ekaan kartaa in tani dhammaanteed tahay, laakiin weli waynu qulquli doonnaa. Haddii aan toos u toosino wacitaanka nidaamka kernel-ka, tani waxay dhaafi doontaa dhammaan habka is-dhexgalka. Xalka hoose waa, dabcan, qaab-dhismeedku-ku-tiirsanaan (x86_64). Aan isku dayno inaan hirgelinno si aan u ogaano meel furan 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) [+]

Dhibaatadani waxay leedahay xal. Xigasho labA:

ptrace waa qalab u oggolaanaya habsocodka waalidku inuu ilaaliyo oo uu xakameeyo horumarka hab-socod kale, eego oo beddelo xogtiisa iyo diiwaangelintiisa. Caadi ahaan shaqadan waxaa loo isticmaalaa in lagu abuuro dhibco jabsan barnaamijka qaladka iyo la socoshada wicitaanada nidaamka.

Habka waalidku wuxuu ku bilaabi karaa baafinta isagoo marka hore waca fargeeto(2), ka bacdina nidaamka ilmahu wuxuu fulin karaa PTRACE_TRACEME, oo ay ku xigto (badanaa) adoo fulinaya fulinta (3). Dhanka kale, nidaamka waalidku waxa uu bilaabi karaa ciribtirka habka jira isagoo isticmaalaya PTRACE_ATTACH.

Marka la baafinayo, habka cunuggu wuu joogsadaa mar kasta oo ay helaan calaamad, xitaa haddii ishalallada la iska indhatiro. (Ka reebban waa SIGKILL, oo ​​si caadi ah u shaqeysa.) Habka waalidka waxaa lagu wargelin doonaa tan iyadoo la wacayo sugitaanka(2), ka dib waxay arki kartaa oo wax ka beddeli kartaa waxa ku jira habka cunugga ka hor inta uusan bilaaban. Nidaamka waalidku wuxuu markaa u ogolaanayaa ilmaha inuu sii wado orodka, xaaladaha qaarkood isagoo iska indhatiray calaamada loo soo diray ama u diri karo calaamad kale).

Sidaa darteed, xalku waa in la kormeero habka, la joojiyo ka hor inta aan la wacin nidaam kasta iyo, haddii loo baahdo, dib u habeynta dunta si ay u shaqeyso jillaab.

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

Hubinta:

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

+0-0=5

Aad baad u mahadsantahay

Charles Hubain
dhibic ceejis
ValdikSS
Philippe Teuwen
derhass

, kuwaas oo maqaalladooda, ilaha iyo faallooyinka ay sameeyeen wax ka badan intii aan sameeyay in qoraalkani halkan ka muuqdo.

Source: www.habr.com

Add a comment