ืžื—ืคืฉ ืืช LD_PRELOAD

ื”ืคืชืง ื”ื–ื” ื ื›ืชื‘ ื‘-2014, ืื‘ืœ ื‘ื“ื™ื•ืง ืขื‘ืจืชื™ ื“ื™ื›ื•ื™ ืขืœ ื”ืื‘ืจื” ื•ื”ื•ื ืœื ืจืื” ืื•ืจ. ื‘ื–ืžืŸ ื”ืื™ืกื•ืจ ืฉื›ื—ืชื™ ืžื–ื”, ืื‘ืœ ืขื›ืฉื™ื• ืžืฆืืชื™ ืืช ื–ื” ื‘ื˜ื™ื•ื˜ื•ืช. ื—ืฉื‘ืชื™ ืœืžื—ื•ืง ืื•ืชื•, ืื‘ืœ ืื•ืœื™ ื–ื” ื™ื•ืขื™ืœ ืœืžื™ืฉื”ื•.

ืžื—ืคืฉ ืืช LD_PRELOAD

ื‘ืื•ืคืŸ ื›ืœืœื™, ืงืจื™ืื” ืงื˜ื ื” ืฉืœ ืžื ื”ืœ ื™ื•ื ืฉื™ืฉื™ ื‘ื ื•ืฉื ื—ื™ืคื•ืฉ "ื›ืœื•ืœ" LD_PRELOAD.

1. ืกื˜ื™ื™ื” ืงืฆืจื” ืœืžื™ ืฉืื™ื ื• ื‘ืงื™ื ื‘ื”ื—ืœืคืช ืคื•ื ืงืฆื™ื•ืช

ื”ืฉืืจ ื™ื›ื•ืœื™ื ืœืœื›ืช ื™ืฉืจ p.2.

ื ืชื—ื™ืœ ืขื ื“ื•ื’ืžื” ืงืœืืกื™ืช:

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

ืื ื• ืžื”ื“ืจื™ื ืœืœื ื“ื’ืœื™ื:

$ gcc ./ld_rand.c -o ld_rand

ื•ื›ืฆืคื•ื™, ื ืงื‘ืœ 5 ืžืกืคืจื™ื ืืงืจืื™ื™ื ืคื—ื•ืช ืž-100:

$ ./ld_rand
53
93
48
57
20

ืื‘ืœ ื‘ื•ืื• ื ื“ืžื™ื™ืŸ ืฉืื™ืŸ ืœื ื• ืืช ืงื•ื“ ื”ืžืงื•ืจ ืฉืœ ื”ืชื•ื›ื ื™ืช, ืื‘ืœ ืื ื—ื ื• ืฆืจื™ื›ื™ื ืœืฉื ื•ืช ืืช ื”ื”ืชื ื”ื’ื•ืช.

ื‘ื•ืื• ื ื™ืฆื•ืจ ืกืคืจื™ื™ื” ืžืฉืœื ื• ืขื ืื‘ ื˜ื™ืคื•ืก ืคื•ื ืงืฆื™ื” ืžืฉืœื ื•, ืœืžืฉืœ:

int rand(){
  return 42;
}

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

ื•ืขื›ืฉื™ื• ื”ื‘ื—ื™ืจื” ื”ืืงืจืื™ืช ืฉืœื ื• ื“ื™ ืฆืคื•ื™ื”:

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

ื”ื˜ืจื™ืง ื”ื–ื” ื ืจืื” ืืคื™ืœื• ื™ื•ืชืจ ืžืจืฉื™ื ืื ืื ื• ืžื™ื™ืฆืื™ื ืœืจืืฉื•ื ื” ืืช ื”ืกืคืจื™ื™ื” ืฉืœื ื• ื‘ืืžืฆืขื•ืช

$ export LD_PRELOAD=$PWD/ld_rand.so

ืื• ืฉื ืขืฉื” ืืช ื–ื” ืงื•ื“ื

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

ื•ืœืื—ืจ ืžื›ืŸ ื”ืคืขืœ ืืช ื”ืชื•ื›ื ื™ืช ื›ืจื’ื™ืœ. ืœื ืฉื™ื ื™ื ื• ืฉื•ืจืช ืงื•ื“ ืื—ืช ื‘ืชื•ื›ื ื” ืขืฆืžื”, ืื‘ืœ ื”ื”ืชื ื”ื’ื•ืช ืฉืœื” ืชืœื•ื™ื” ื›ืขืช ื‘ืคื•ื ืงืฆื™ื” ื–ืขื™ืจื” ื‘ืกืคืจื™ื™ื” ืฉืœื ื•. ื™ืชืจื” ืžื›ืš, ื‘ื–ืžืŸ ื›ืชื™ื‘ืช ื”ืชื•ื›ื ื™ืช, ื” ืฉื•ืจื” ืืคื™ืœื• ืœื ื”ื™ื” ืงื™ื™ื.

ืžื” ื’ืจื ืœืชื•ื›ื ื™ืช ืฉืœื ื• ืœื”ืฉืชืžืฉ ื‘ื–ื™ื•ืฃ ืฉื•ืจื”? ื‘ื•ืื• ื ื™ืงื— ืืช ื–ื” ืฆืขื“ ืื—ืจ ืฆืขื“.
ื›ืืฉืจ ื™ื™ืฉื•ื ืžื•ืคืขืœ, ื ื˜ืขื ื•ืช ืกืคืจื™ื•ืช ืžืกื•ื™ืžื•ืช ื”ืžื›ื™ืœื•ืช ืืช ื”ืคื•ื ืงืฆื™ื•ืช ื”ื“ืจื•ืฉื•ืช ืœืชื•ื›ื ื™ืช. ืื ื—ื ื• ื™ื›ื•ืœื™ื ืœืจืื•ืช ืื•ืชื ื‘ืืžืฆืขื•ืช 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)

ืจืฉื™ืžื” ื–ื• ืขืฉื•ื™ื” ืœื”ืฉืชื ื•ืช ื‘ื”ืชืื ืœื’ืจืกืช ืžืขืจื›ืช ื”ื”ืคืขืœื”, ืืš ื—ื™ื™ื‘ ืœื”ื™ื•ืช ืฉื ืงื•ื‘ืฅ libc.so. ืกืคืจื™ื” ื–ื• ื”ื™ื ืฉืžืกืคืงืช ืงืจื™ืื•ืช ืžืขืจื›ืช ื•ืคื•ื ืงืฆื™ื•ืช ื‘ืกื™ืกื™ื•ืช ื›ื’ื•ืŸ ืœืคืชื•ื—, malloc, ื”ื“ืคืก ื•ื›ื•' ืฉืœื ื• ืฉื•ืจื” ื’ื ื‘ื™ื ื™ื”ื. ื‘ื•ืื• ื ื•ื•ื“ื ืืช ื–ื”:

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

ื‘ื•ืื• ื ืจืื” ืื โ€‹โ€‹ืกื˜ ื”ืกืคืจื™ื•ืช ืžืฉืชื ื” ื‘ืขืช ื”ืฉื™ืžื•ืฉ 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)

ืžืกืชื‘ืจ ืฉื”ืžืฉืชื ื” ืžื•ื’ื“ืจ LD_PRELOAD ืžืืœืฅ ืื•ืชื ื• ืœื˜ืขื•ืŸ ld_rand.so ื’ื ืœืžืจื•ืช ื”ืขื•ื‘ื“ื” ืฉื”ืชื•ื›ื ื™ืช ืขืฆืžื” ืื™ื ื” ื“ื•ืจืฉืช ื–ืืช. ื•ืžืื– ื”ืชืคืงื™ื“ ืฉืœื ื• "ืจืื ื“" ืขื•ืžืก ืžื•ืงื“ื ื™ื•ืชืจ ืž ืฉื•ืจื” ืž libc.so, ื•ืื– ื”ื™ื ืฉื•ืœื˜ืช ื‘ืžืงื•ื.

ืื•ืงื™ื™, ื”ืฆืœื—ื ื• ืœื”ื—ืœื™ืฃ ืืช ื”ืคื•ื ืงืฆื™ื” ื”ืžืงื•ืจื™ืช, ืื‘ืœ ืื™ืš ื ื•ื›ืœ ืœื•ื•ื“ื ืฉื”ืคื•ื ืงืฆื™ื•ื ืœื™ื•ืช ืฉืœื” ื ืฉืžืจืช ื•ืžืกืคืจ ืคืขื•ืœื•ืช ื™ืชื•ื•ืกืคื•. ื‘ื•ืื• ื ืฉื ื” ืืช ื”ืืงืจืื™ ืฉืœื ื•:

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

ื›ืืŸ, ื›"ืชื•ืกืคืช" ืฉืœื ื•, ืื ื• ืžื“ืคื™ืกื™ื ืจืง ืฉื•ืจืช ื˜ืงืกื˜ ืื—ืช, ื•ืœืื—ืจื™ื” ืื ื• ื™ื•ืฆืจื™ื ืžืฆื‘ื™ืข ืœืคื•ื ืงืฆื™ื” ื”ืžืงื•ืจื™ืช ืฉื•ืจื”. ื›ื“ื™ ืœืงื‘ืœ ืืช ื”ื›ืชื•ื‘ืช ืฉืœ ื”ืคื•ื ืงืฆื™ื” ื”ื–ื• ืื ื—ื ื• ืฆืจื™ื›ื™ื dlsym ื”ื•ื ืคื•ื ืงืฆื™ื” ืžื”ืกืคืจื™ื™ื” libdlืืฉืจ ื™ืžืฆื ืฉืœื ื• ืฉื•ืจื” ื‘ืขืจื™ืžื” ืฉืœ ืกืคืจื™ื•ืช ื“ื™ื ืžื™ื•ืช. ืœืื—ืจ ืžื›ืŸ ื ืงืจื ืœืคื•ื ืงืฆื™ื” ื”ื–ื• ื•ื ื—ื–ื™ืจ ืืช ืขืจื›ื”. ื‘ื”ืชืื, ื ืฆื˜ืจืš ืœื”ื•ืกื™ืฃ "-ldl" ื‘ืžื”ืœืš ื”ื”ืจื›ื‘ื”:

$ 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

ื•ื”ืชื•ื›ื ื™ืช ืฉืœื ื• ืžืฉืชืžืฉืช ื‘"ืžืงื•ืจื™" ืฉื•ืจื”, ืœืื—ืจ ืฉื‘ื™ืฆืข ื‘ืขื‘ืจ ื›ืžื” ืคืขื•ืœื•ืช ืžื’ื•ื ื•ืช.

2. ื›ืื‘ ื”ื—ื™ืคื•ืฉ

ื‘ื™ื“ื™ืขื” ืขืœ ืื™ื•ื ืคื•ื˜ื ืฆื™ืืœื™, ืื ื—ื ื• ืจื•ืฆื™ื ืœื–ื”ื•ืช ืืช ื–ื” preload ื–ื” ื‘ื•ืฆืข. ื‘ืจื•ืจ ืฉื”ื“ืจืš ื”ื›ื™ ื˜ื•ื‘ื” ืœื–ื”ื•ืช ื”ื™ื ืœื“ื—ื•ืฃ ืื•ืชื• ืœืงืจื ืœ, ืื‘ืœ ื”ืชืขื ื™ื™ื ืชื™ ื‘ืืคืฉืจื•ื™ื•ืช ื”ื–ื™ื”ื•ื™ ื‘ืžืจื—ื‘ ื”ืžืฉืชืžืฉ.

ืœืื—ืจ ืžื›ืŸ, ืคืชืจื•ื ื•ืช ื–ื™ื”ื•ื™ ื•ื”ืคืจื›ืชื ื™ื’ื™ืขื• ื‘ื–ื•ื’ื•ืช.

2.1. ื‘ื•ืื• ื ืชื—ื™ืœ ืคืฉื•ื˜

ื›ืคื™ ืฉื”ื•ื–ื›ืจ ืงื•ื“ื ืœื›ืŸ, ืืชื” ื™ื›ื•ืœ ืœืฆื™ื™ืŸ ืืช ื”ืกืคืจื™ื™ื” ืœื˜ืขื™ื ื” ื‘ืืžืฆืขื•ืช ื”ืžืฉืชื ื” LD_PRELOAD ืื• ืขืœ ื™ื“ื™ ื›ืชื™ื‘ืชื• ื‘ืงื•ื‘ืฅ /etc/ld.so.preload. ื‘ื•ืื• ื ื™ืฆื•ืจ ืฉื ื™ ื’ืœืื™ื ืคืฉื•ื˜ื™ื.

ื”ืจืืฉื•ืŸ ื”ื•ื ืœื‘ื“ื•ืง ืืช ืžืฉืชื ื” ื”ืกื‘ื™ื‘ื” ื”ืžื•ื’ื“ืจ:

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

ื”ืฉื ื™ ื”ื•ื ืœื‘ื“ื•ืง ืื ื”ืงื•ื‘ืฅ ื ืคืชื—:

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

ื‘ื•ืื• ื ื˜ืขืŸ ืืช ื”ืกืคืจื™ื•ืช:

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

ื›ืืŸ ื•ืžื˜ื”, [+] ืžืฆื™ื™ืŸ ื–ื™ื”ื•ื™ ืžื•ืฆืœื—.
ื‘ื”ืชืื, [-] ืคื™ืจื•ืฉื• ืขืงื™ืคืช ื–ื™ื”ื•ื™.

ื›ืžื” ื™ืขื™ืœ ื’ืœืื™ ื›ื–ื”? ื‘ื•ืื• ื ืกืชื›ืœ ืชื—ื™ืœื” ืขืœ ืžืฉืชื ื” ื”ืกื‘ื™ื‘ื”:

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

ื‘ืื•ืคืŸ ื“ื•ืžื”, ืื ื• ื ืคื˜ืจื™ื ืžื”ืฆ'ืง ืœืคืชื•ื—:

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

ื›ืŸ, ื ื™ืชืŸ ืœื”ืฉืชืžืฉ ื›ืืŸ ื‘ื“ืจื›ื™ื ืื—ืจื•ืช ืœื’ืฉืช ืœืงื•ื‘ืฅ, ื›ื’ื•ืŸ, 64, stat ื•ื›ื•', ืื‘ืœ, ืœืžืขืฉื”, ื™ืฉ ืฆื•ืจืš ื‘ืื•ืชืŸ 5-10 ืฉื•ืจื•ืช ืงื•ื“ ื›ื“ื™ ืœื”ื•ื ื•ืช ืื•ืชืŸ.

2.2. ื‘ื•ื ื ืžืฉื™ืš ื”ืœืื”

ืœืžืขืœื” ื”ืฉืชืžืฉื ื• getenv() ื›ื“ื™ ืœืงื‘ืœ ืืช ื”ืขืจืš LD_PRELOAD, ืื‘ืœ ื™ืฉ ื’ื ื“ืจืš ื™ื•ืชืจ "ื‘ืจืžื” ื ืžื•ื›ื”" ืœื”ื’ื™ืข ืืœื™ื” ENV-ืžืฉืชื ื™ื. ืœื ื ืฉืชืžืฉ ื‘ืคื•ื ืงืฆื™ื•ืช ื‘ื™ื ื™ื™ื, ืืœื ื ืชื™ื™ื—ืก ืœืžืขืจืš **ืกื‘ื™ื‘ื”, ื”ืžืื—ืกืŸ ืขื•ืชืง ืฉืœ ื”ืกื‘ื™ื‘ื”:

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

ืžื›ื™ื•ื•ืŸ ืฉื›ืืŸ ืื ื• ืงื•ืจืื™ื ื ืชื•ื ื™ื ื™ืฉื™ืจื•ืช ืžื”ื–ื™ื›ืจื•ืŸ, ืœื ื ื™ืชืŸ ืœื™ื™ืจื˜ ืฉื™ื—ื” ื›ื–ื•, ื•ืื ื—ื ื• undetect_getenv ื–ื” ื›ื‘ืจ ืœื ืžืคืจื™ืข ืœื–ื”ื•ืช ืืช ื”ื—ื“ื™ืจื”.

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

ื ืจืื” ืฉื”ื‘ืขื™ื” ื”ื–ื• ื ืคืชืจื”? ื–ื” ืขื“ื™ื™ืŸ ืจืง ืžืชื—ื™ืœ.

ืœืื—ืจ ื”ืคืขืœืช ื”ืชื•ื›ื ื™ืช, ื”ืขืจืš ืฉืœ ื”ืžืฉืชื ื” LD_PRELOAD ื”ืืงืจื™ื ื›ื‘ืจ ืœื ืฆืจื™ื›ื™ื ืื•ืชื• ื‘ื–ื™ื›ืจื•ืŸ, ื›ืœื•ืžืจ, ื”ื ื™ื›ื•ืœื™ื ืœืงืจื•ื ืื•ืชื• ื•ืœืžื—ื•ืง ืื•ืชื• ืœืคื ื™ ื‘ื™ืฆื•ืข ื”ื•ืจืื•ืช ื›ืœืฉื”ืŸ. ื›ืžื•ื‘ืŸ, ืขืจื™ื›ืช ืžืขืจืš ื‘ื–ื™ื›ืจื•ืŸ ื”ื™ื, ืœื›ืœ ื”ืคื—ื•ืช, ืกื’ื ื•ืŸ ืชื›ื ื•ืช ื’ืจื•ืข, ืื‘ืœ ื”ืื ื–ื” ื™ื›ื•ืœ ืœืขืฆื•ืจ ืžื™ืฉื”ื• ืฉืœื ื‘ืืžืช ืžืื—ืœ ืœื ื• ื˜ื•ื‘ ื‘ื›ืœ ืžืงืจื”?

ืœืฉื ื›ืš ืขืœื™ื ื• ืœื™ืฆื•ืจ ืคื•ื ืงืฆื™ื” ืžื–ื•ื™ืคืช ืžืฉืœื ื• init (), ืฉื‘ื• ืื ื• ืžื™ื™ืจื˜ื™ื ืืช ื”ืžื•ืชืงืŸ LD_PRELOAD ื•ืžืขื‘ื™ืจื™ื ืื•ืชื• ืœืžืงืฉืจ ืฉืœื ื•:

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

ืื ื• ืžื‘ืฆืขื™ื ื•ื‘ื•ื“ืงื™ื:

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

ืขื ื–ืืช, ื”ื–ื™ื›ืจื•ืŸ ื”ื•ื ืœื ื”ืžืงื•ื ื”ืื—ืจื•ืŸ ืฉื‘ื• ืืชื” ื™ื›ื•ืœ ืœืžืฆื•ื ืชื—ืœื™ืฃ LD_PRELOAD, ื™ืฉ ื’ื /proc/. ื ืชื—ื™ืœ ืขื ื”ืžื•ื‘ืŸ ืžืืœื™ื• /proc/{PID}/environ.

ืœืžืขืฉื”, ื™ืฉ ืคืชืจื•ืŸ ืื•ื ื™ื‘ืจืกืœื™ ืขื‘ื•ืจ ืœื ืœื–ื”ื•ืช **ืกื‘ื™ื‘ื” ะธ /proc/self/environ. ื”ื‘ืขื™ื” ื”ื™ื ื”ืชื ื”ื’ื•ืช "ืฉื’ื•ื™ื”". unsetenv(env).

ืืคืฉืจื•ืช ื ื›ื•ื ื”

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
$

ืื‘ืœ ื‘ื•ืื• ื ื“ืžื™ื™ืŸ ืฉืœื ืžืฆืื ื• ืืช ื–ื” ื• /proc/self/environ ืžื›ื™ืœ ื ืชื•ื ื™ื "ื‘ืขื™ื™ืชื™ื™ื".

ืจืืฉื™ืช ื‘ื•ืื• ื ื ืกื” ืขื ื”"ืชื—ืคื•ืฉืช" ื”ืงื•ื“ืžืช ืฉืœื ื•:

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

ื—ืชื•ืœ ืžืฉืชืžืฉ ื‘ืื•ืชื• ื›ื“ื™ ืœืคืชื•ื— ืืช ื”ืงื•ื‘ืฅ ืœึดืคึฐืชื•ึนื—ึท(), ืื– ื”ืคืชืจื•ืŸ ื“ื•ืžื” ืœืžื” ืฉื›ื‘ืจ ื ืขืฉื” ื‘ืกืขื™ืฃ 2.1, ืื‘ืœ ื›ืขืช ืื ื• ื™ื•ืฆืจื™ื ืงื•ื‘ืฅ ื–ืžื ื™ ืฉื‘ื• ืื ื• ืžืขืชื™ืงื™ื ืืช ืขืจื›ื™ ื”ื–ื™ื›ืจื•ืŸ ื”ืืžื™ืชื™ ืœืœื ืฉื•ืจื•ืช ื”ืžื›ื™ืœื•ืช 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);
}

ื•ื”ืฉืœื‘ ื”ื–ื” ืขื‘ืจ:

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

ื”ืžืงื•ื ื”ื‘ืจื•ืจ ื”ื‘ื ื”ื•ื /proc/self/maps. ืื™ืŸ ื˜ืขื ืœื”ืชืขื›ื‘ ืขืœ ื–ื”. ื”ืคืชืจื•ืŸ ื–ื”ื” ืœื—ืœื•ื˜ื™ืŸ ืœืงื•ื“ื: ื”ืขืชืง ืืช ื”ื ืชื•ื ื™ื ืžื”ืงื•ื‘ืฅ ืžื™ื ื•ืก ื”ืฉื•ืจื•ืช ื‘ื™ื ื™ื”ื libc.so ะธ ld.so.

2.4. ืืคืฉืจื•ืช ืž- Chokepoint

ืื”ื‘ืชื™ ื‘ืžื™ื•ื—ื“ ืืช ื”ืคืชืจื•ืŸ ื”ื–ื” ื‘ื’ืœืœ ื”ืคืฉื˜ื•ืช ืฉืœื•. ืื ื• ืžืฉื•ื•ื™ื ืืช ื”ื›ืชื•ื‘ื•ืช ืฉืœ ืคื•ื ืงืฆื™ื•ืช ืฉื ื˜ืขื ื• ื™ืฉื™ืจื•ืช ืž libc, ื•ื›ืชื•ื‘ื•ืช "ื”ื‘ื".

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

ื˜ื•ืขืŸ ืืช ื”ืกืคืจื™ื™ื” ืขื ื™ื™ืจื•ื˜ "ืœึดืคึฐืชื•ึนื—ึท()" ื•ืœื‘ื“ื•ืง:

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

ื”ื”ืคืจื›ื” ื”ืชื‘ืจืจื” ื›ืคืฉื•ื˜ื” ืขื•ื“ ื™ื•ืชืจ:

#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

ื ืจืื” ืฉื–ื” ื”ื›ืœ, ืื‘ืœ ืื ื—ื ื• ืขื“ื™ื™ืŸ ื ืกื—ื˜. ืื ื ื ืชื‘ ืืช ืงืจื™ืืช ื”ืžืขืจื›ืช ื™ืฉื™ืจื•ืช ืœืงืจื ืœ, ื–ื” ื™ืขืงื•ืฃ ืืช ื›ืœ ืชื”ืœื™ืš ื”ื™ื™ืจื•ื˜. ื”ืคืชืจื•ืŸ ืฉืœื”ืœืŸ ื”ื•ื, ื›ืžื•ื‘ืŸ, ืชืœื•ื™ ืื“ืจื™ื›ืœื•ืช (x86_64). ื‘ื•ืื• ื ื ืกื” ืœื™ื™ืฉื ืืช ื–ื” ื›ื“ื™ ืœื–ื”ื•ืช ืคืชื— ld.so.load ืžืจืืฉ.

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

ื•ืœื‘ืขื™ื” ื”ื–ื• ื™ืฉ ืคืชืจื•ืŸ. ืงื˜ืข ืžืชื•ืš ืื™ืฉ'ื:

ptrace ื”ื•ื ื›ืœื™ ื”ืžืืคืฉืจ ืœืชื”ืœื™ืš ืื‘ ืœืฆืคื•ืช ื•ืœืฉืœื•ื˜ ื‘ื”ืชืงื“ืžื•ืช ืฉืœ ืชื”ืœื™ืš ืื—ืจ, ืœื”ืฆื™ื’ ื•ืœืฉื ื•ืช ืืช ื”ื ืชื•ื ื™ื ื•ื”ืจื™ืฉื•ืžื™ื ืฉืœื•. ื‘ื“ืจืš ื›ืœืœ ืคื•ื ืงืฆื™ื” ื–ื• ืžืฉืžืฉืช ืœื™ืฆื™ืจืช ื ืงื•ื“ื•ืช ืฉื‘ื™ืจื” ื‘ืชื•ื›ื ื™ืช ืื™ืชื•ืจ ื‘ืื’ื™ื ื•ืœื ื™ื˜ื•ืจ ืงืจื™ืื•ืช ืžืขืจื›ืช.

ืชื”ืœื™ืš ื”ืื‘ ื™ื›ื•ืœ ืœื”ืชื—ื™ืœ ื‘ืžืขืงื‘ ืขืœ ื™ื“ื™ ืงืจื™ืื” ืชื—ื™ืœื” fork(2), ื•ืœืื—ืจ ืžื›ืŸ ืชื”ืœื™ืš ื”ื™ืœื“ ืฉื ื•ืฆืจ ื™ื›ื•ืœ ืœื‘ืฆืข PTRACE_TRACEME, ื•ืื—ืจื™ื• (ื‘ื“ืจืš ื›ืœืœ) ื‘ื™ืฆื•ืข exec(3). ืžืฆื“ ืฉื ื™, ืชื”ืœื™ืš ืื‘ ื™ื›ื•ืœ ืœื”ืชื—ื™ืœ ื‘ืื’ื™ื ื‘ืชื”ืœื™ืš ืงื™ื™ื ื‘ืืžืฆืขื•ืช PTRACE_ATTACH.

ื”ืžืขืงื‘ ืขื•ืฆืจ ืืช ืชื”ืœื™ืš ื”ื™ืœื“ ื‘ื›ืœ ืคืขื ืฉื”ื•ื ืžืงื‘ืœ ืื•ืช, ื’ื ืื ืžืชืขืœืžื™ื ืžื”ืื•ืช. (ื”ื™ื•ืฆื ืžืŸ ื”ื›ืœืœ ื”ื•ื SIGKILL, ืฉืคื•ืขืœ ื›ืจื’ื™ืœ.) ืชื”ืœื™ืš ื”ืื‘ ื™ืงื‘ืœ ื”ื•ื“ืขื” ืขืœ ื›ืš ืขืœ ื™ื“ื™ ืงืจื™ืืช wait(2), ื•ืœืื—ืจ ืžื›ืŸ ื”ื•ื ื™ื•ื›ืœ ืœื”ืฆื™ื’ ื•ืœืฉื ื•ืช ืืช ื”ืชื•ื›ืŸ ืฉืœ ืชื”ืœื™ืš ื”ื™ืœื“ ืœืคื ื™ ืฉื”ื•ื ืžืชื—ื™ืœ. ืชื”ืœื™ืš ื”ื”ื•ืจื” ืžืืคืฉืจ ืœื™ืœื“ ืœื”ืžืฉื™ืš ืœืจื•ืฅ, ื‘ืžืงืจื™ื ืžืกื•ื™ืžื™ื ืœื”ืชืขืœื ืžื”ืื•ืช ืฉื ืฉืœื— ืืœื™ื• ืื• ืœืฉืœื•ื— ืื•ืช ืื—ืจ ื‘ืžืงื•ื ื–ืืช).

ืœืคื™ื›ืš, ื”ืคืชืจื•ืŸ ื”ื•ื ืœืคืงื— ืขืœ ื”ืชื”ืœื™ืš, ืœืขืฆื•ืจ ืื•ืชื• ืœืคื ื™ ื›ืœ ืงืจื™ืืช ืžืขืจื›ืช ื•ื‘ืžื™ื“ืช ื”ืฆื•ืจืš ืœื”ืคื ื•ืช ืืช ื”ื—ื•ื˜ ืœืคื•ื ืงืฆื™ื™ืช 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);
    }
}

ืื ื• ื‘ื•ื“ืงื™ื:

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

+0-0=5

ืชื•ื“ื” ืจื‘ื” ืœืš

ืฆ'ืืจืœืก ื”ื•ื‘ื™ื™ืŸ
ื ืงื•ื“ืช ื—ื ืง
ValdikSS
ืคื™ืœื™ืค ื˜ื•ื•ืŸ
ื“ืจื”ืืก

, ืฉื”ืžืืžืจื™ื, ื”ืžืงื•ืจื•ืช ื•ื”ื”ืขืจื•ืช ืฉืœื• ืขืฉื• ื”ืจื‘ื” ื™ื•ืชืจ ืžืžื ื™ ื›ื“ื™ ืฉื”ืขืจื” ื–ื• ืชื•ืคื™ืข ื›ืืŸ.

ืžืงื•ืจ: www.habr.com

ื”ื•ืกืคืช ืชื’ื•ื‘ื”