2006年12月15日星期五

injectso finder v0.0.1- 共享库注射探测工具

injectso finder 是一个针对于使用共享库注射技术的后门的探测工具,现在的版本是0.0.1,也就说是它还很简陋。
目前这个版本的思路就是将指定进程使用的共享库和其对应的二进制文件中指明需要的共享库都打印出来,供使用者比对。一般来讲,二进制文件共享库列 表中出现的库在进程中没有出现应该不算异常,但是如果进程中出现的库在二进制文件共享库列表中不存在,就需要注意了,那很可能就是一个injectso加 载的共享库。

/*
* injectso-finder v0.0.1 (2004/12/21)
* written by grip2
*/
#include
#include
#define _GNU_SOURCE
#include
#include
#include
#include
#include
#include

#include "gelf.h"
#include "gptrace.h"

extern void *memmem(const void *haystack, size_t haystacklen,
const void *needle, size_t needlelen);
static void usage(void);
static char *get_file_by_pid(pid_t pid);

int main(int argc, char *argv[])
{
pid_t pid;
char *pchar;
char *filename;

printf("injectso finder v0.0.1 written by grip2 \n");

if (argc != 2)
usage();

pid = strtol(argv[1], &pchar, 10);
if (*pchar != '\0')
usage();

/* Runtime process */
ptrace_attach(pid);
print_sharelib_runtime(pid);
ptrace_detach(pid);

/* Binary file */
if ((filename = get_file_by_pid(pid)) != NULL) {
print_sharelib(filename);
}
else {
fprintf(stderr, "[** ALERT] Can't locate binary file\n");
}
free(filename);

return 0;
}

void usage(void)
{
fprintf(stderr, "Usage: ./injectso-finder pid\n");
exit(1);
}

char *get_file_by_pid(pid_t pid)
{
int fd = -1;
char file[256];
char *path;
char environ[32], cmdline[32];
char buff[4096];
char *filename;
int ret;

snprintf(environ, sizeof(environ), "/proc/%d/environ", pid);
snprintf(cmdline, sizeof(cmdline), "/proc/%d/cmdline", pid);

/* Get file */
fd = open(cmdline, O_RDONLY);
if (fd == -1) {
perror(cmdline);
goto err;
}

ret = read(fd, file, sizeof(file) - 1);
if (ret == -1) {
perror(cmdline);
goto err;
}
file[ret] = '\0';
close(fd);

/* Get path */
fd = open(environ, O_RDONLY);
if (fd == -1) {
perror(environ);
goto err;
}

ret = read(fd, buff, sizeof(buff) - 1);
if (ret == -1) {
perror(environ);
goto err;
}
buff[ret] = '\0';
close(fd);

path = (char *) memmem(buff, ret, "PWD=", 4);
if (path == NULL) {
goto err;
}
path += 4;

filename = (char *) malloc(strlen(path)+strlen(file)+2);
if (!filename)
goto err;

sprintf(filename, "%s/%s", path, file);
return filename;
err:
if (fd != -1) close(fd);
return NULL;
}

------------------------------------------------------------------------------------------------------

gelf.h

#ifndef _G2_ELF_API_
#define _G2_ELF_API_

int print_sharelib_runtime(pid_t pid);
int print_sharelib(char *filename);

#endif

------------------------------------------------------------------------------------------------------

/*
* gelf.c (2004)
* written by grip2
*/

#include
#include
#include
#include
#include
#include

#include "gelf.h"
#include "gptrace.h"

#define IMAGE_ADDR 0x08048000

static struct link_map * get_linkmap(pid_t pid)
{
Elf32_Ehdr *ehdr = (Elf32_Ehdr *) malloc(sizeof(Elf32_Ehdr));
Elf32_Phdr *phdr = (Elf32_Phdr *) malloc(sizeof(Elf32_Phdr));
Elf32_Dyn *dyn = (Elf32_Dyn *) malloc(sizeof(Elf32_Dyn));
Elf32_Word got;
unsigned long phdr_addr,dyn_addr,map_addr;
struct link_map *map = (struct link_map *) malloc(sizeof(struct link_map));
int i = 0;

ptrace_read(pid, IMAGE_ADDR, ehdr, sizeof(Elf32_Ehdr));
phdr_addr = IMAGE_ADDR + ehdr->e_phoff;

ptrace_read(pid, phdr_addr, phdr, sizeof(Elf32_Phdr));
while(phdr->p_type != PT_DYNAMIC)
ptrace_read(pid, phdr_addr += sizeof(Elf32_Phdr), phdr, sizeof(Elf32_Phdr));
dyn_addr = phdr->p_vaddr;

ptrace_read(pid, dyn_addr, dyn, sizeof(Elf32_Dyn));
while(dyn->d_tag != DT_PLTGOT) {
ptrace_read(pid, dyn_addr + i * sizeof(Elf32_Dyn), dyn, sizeof(Elf32_Dyn));
i++;
}

got = (Elf32_Word) dyn->d_un.d_ptr;
got += 4;

ptrace_read(pid, got, &map_addr, 4);
ptrace_read(pid, map_addr, map, sizeof(struct link_map));

free(ehdr);
free(phdr);
free(dyn);
return map;
}

int print_sharelib_runtime(pid_t pid)
{
struct link_map *lm = (struct link_map *) malloc(sizeof(struct link_map));
char *str;

printf("-------- runtime process --------\n");
printf("PROCESS ID: [%d]\n", pid);

lm = get_linkmap(pid);
if (!lm) return -1;

#if 0
str = ptrace_readstr(pid, (unsigned long) lm->l_name);
printf("[%s]\n", str);
free(str);
#endif

if (!lm->l_next) return -1;

ptrace_read(pid, (unsigned long) lm->l_next, lm, sizeof(struct link_map));
while(lm->l_next) {
ptrace_read(pid, (unsigned long) lm->l_next, lm, sizeof(struct link_map));

str = ptrace_readstr(pid, (unsigned long) lm->l_name);
printf("[%s]\n", str);
free(str);
}

printf("------------ end ------------\n");
return 0;
}

int print_sharelib(char *filename)
{
Elf32_Ehdr *ehdr = (Elf32_Ehdr *) malloc(sizeof(Elf32_Ehdr));
Elf32_Phdr *phdr = (Elf32_Phdr *) malloc(sizeof(Elf32_Phdr));
Elf32_Dyn *dyn = (Elf32_Dyn *) malloc(sizeof(Elf32_Dyn));
Elf32_Addr strtab = 0;
unsigned int needed[64];
int needed_count = 0;
char str[1024];
int fd = -1;
int i, res;
unsigned long dyn_segment_offset = 0;
unsigned long interp_segment_offset = 0;

printf("---------- binary file ----------\n");
printf("BINARY FILE: [%s]\n", filename);

fd = open(filename, O_RDONLY);
if (fd == -1) {
perror(filename);
goto err;
}

read(fd, ehdr, sizeof(Elf32_Ehdr));

lseek(fd, ehdr->e_phoff, SEEK_SET);
for (i = 0; i <>e_phnum; i++) {
read(fd, phdr, sizeof(Elf32_Phdr));
if (phdr->p_type == PT_INTERP) {
interp_segment_offset = phdr->p_offset;
}
else if (phdr->p_type == PT_DYNAMIC) {
dyn_segment_offset = phdr->p_offset;
}
}

/* dynamic segment */
lseek(fd, dyn_segment_offset, SEEK_SET);
res = read(fd, dyn, sizeof(Elf32_Dyn));
while(res == sizeof(Elf32_Dyn) && dyn->d_tag) {
switch (dyn->d_tag) {
case DT_NEEDED:
if (needed_count < sizeof(needed)/sizeof(needed[0]))
needed[needed_count++] = dyn->d_un.d_val;
else
fprintf(stderr, "[** ALERT] Too many sharelib!\n");
break;
case DT_STRTAB:
strtab = dyn->d_un.d_ptr;
break;
default:
break;
}

res = read(fd, dyn, sizeof(Elf32_Dyn));
}

for (i = 0; i < needed_count; i++) {
lseek(fd, strtab-IMAGE_ADDR+needed[i], SEEK_SET);
res = read(fd, str, sizeof(str)-1);
if (res > 0) {
str[res] ='\0';
printf("[%s]\n", str);
}
}

/* interpreter segment */
lseek(fd, interp_segment_offset, SEEK_SET);
res = read(fd, str, sizeof(str)-1);
if (res > 0) {
str[res] ='\0';
printf("[%s]\n", str);
}

free(ehdr);
free(phdr);
free(dyn);
close(fd);
printf("------------ end ------------\n");
return 0;
err:
if (fd != -1)
close(fd);
printf("------------ end ------------\n");
return -1;
}

-----------------------------------------------------------------------------------------------

gptrace.h

#ifndef _G2_PTRACE_API_
#define _G2_PTRACE_API_

#include
#include
#include
#include
#include
#include
#include

extern void ptrace_attach(int pid);
extern void ptrace_cont(int pid);
extern void ptrace_detach(int pid);
extern void ptrace_write(int pid, unsigned long addr, void *vptr, int len);
extern void ptrace_read(int pid, unsigned long addr, void *vptr, int len);
extern char * ptrace_readstr(int pid, unsigned long addr);
extern void ptrace_readreg(int pid, struct user_regs_struct *regs);
extern void ptrace_writereg(int pid, struct user_regs_struct *regs);
extern void * ptrace_push(int pid, void *paddr, int size);
extern void ptrace_call(int pid, unsigned long addr);
extern void restart_syscall(void);

#endif

-----------------------------------------------------------------------------------------------

/*
* gptrace.c (2002)
* written by grip2
*/

#include "gptrace.h"

struct user_regs_struct oldregs;

void ptrace_attach(pid_t pid)
{
if(ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) {
perror("ptrace_attach");
exit(-1);
}

waitpid(pid, NULL, WUNTRACED);

ptrace_readreg(pid, &oldregs);
#if 0
restart_syscall();
#endif
}

void ptrace_cont(pid_t pid)
{
int stat;

if(ptrace(PTRACE_CONT, pid, NULL, NULL) < 0) {
perror("ptrace_cont");
exit(-1);
}

while(!WIFSTOPPED(stat))
waitpid(pid, &stat, WNOHANG);
}

void ptrace_detach(pid_t pid)
{
ptrace_writereg(pid, &oldregs);

if(ptrace(PTRACE_DETACH, pid, NULL, NULL) < 0) {
perror("ptrace_detach");
exit(-1);
}
}

void ptrace_write(pid_t pid, unsigned long addr, void *vptr, int len)
{
int count;
long word;

count = 0;

while(count < len) {
memcpy(&word, vptr + count, sizeof(word));
word = ptrace(PTRACE_POKETEXT, pid, addr + count, word);
count += 4;

if(errno != 0)
printf("ptrace_write failed\t %ld\n", addr + count);
}
}

void ptrace_read(pid_t pid, unsigned long addr, void *vptr, int len)
{
int i,count;
long word;
unsigned long *ptr = (unsigned long *)vptr;

i = count = 0;

while (count < len) {
word = ptrace(PTRACE_PEEKTEXT, pid, addr + count, NULL);
count += 4;
ptr[i++] = word;
}
}

char * ptrace_readstr(pid_t pid, unsigned long addr)
{
char *str = (char *) malloc(64);
int i,count;
long word;
char *pa;

i = count = 0;
pa = (char *)&word;

while(i <= 60) {
word = ptrace(PTRACE_PEEKTEXT, pid, addr + count, NULL);
count += 4;

if (pa[0] == '\0') {
str[i] = '\0';
break;
}
else
str[i++] = pa[0];

if (pa[1] == '\0') {
str[i] = '\0';
break;
}
else
str[i++] = pa[1];

if (pa[2] == '\0') {
str[i] = '\0';
break;
}
else
str[i++] = pa[2];

if (pa[3] == '\0') {
str[i] = '\0';
break;
}
else
str[i++] = pa[3];
}

return str;
}


void ptrace_readreg(pid_t pid, struct user_regs_struct *regs)
{
if(ptrace(PTRACE_GETREGS, pid, NULL, regs))
printf("*** ptrace_readreg error ***\n");

}


void ptrace_writereg(pid_t pid, struct user_regs_struct *regs)
{
if(ptrace(PTRACE_SETREGS, pid, NULL, regs))
printf("*** ptrace_writereg error ***\n");
}


void * ptrace_push(pid_t pid, void *paddr, int size)
{
unsigned long esp;
struct user_regs_struct regs;

ptrace_readreg(pid, ®s);
esp = regs.esp;
esp -= size;
esp = esp - esp % 4;
regs.esp = esp;

ptrace_writereg(pid, ®s);

ptrace_write(pid, esp, paddr, size);

return (void *)esp;
}


void ptrace_call(pid_t pid, unsigned long addr)
{
void *pc;
struct user_regs_struct regs;
int stat;
void *pra;

pc = (void *) 0x41414140;
pra = ptrace_push(pid, &pc, sizeof(pc));

ptrace_readreg(pid, ®s);
regs.eip = addr;
ptrace_writereg(pid, ®s);

ptrace_cont(pid);

while(!WIFSIGNALED(stat))
waitpid(pid, &stat, WNOHANG);
}


void restart_syscall(void)
{
if (oldregs.eax != oldregs.orig_eax && oldregs.orig_eax != 0xffffff00)
{
oldregs.eip -= 2;
oldregs.eax = oldregs.orig_eax;
}
}


void ptrace_call_special(pid_t pid, unsigned long addr)
{
void *pc;
struct user_regs_struct regs;
int stat;
void *pra;

pc = (void *) 0x41414140;
pra = ptrace_push(pid, &pc, sizeof(pc));

ptrace_readreg(pid, ®s);
regs.eip = addr;
ptrace_writereg(pid, ®s);

ptrace_cont(pid);
ptrace_detach(pid);
stat = 0;
while(!WIFSIGNALED(stat))
waitpid(pid, &stat, WNOHANG);
}


void ptrace_attach_special(pid_t pid)
{
void *pc;
void *pra;

if(ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) {
perror("ptrace_attach");
exit(-1);
}

waitpid(pid, NULL, WUNTRACED);
pc = (void *) 0x41414140;
pra = ptrace_push(pid, &pc, sizeof(pc));
}



-----------------------------------------------------------------------------------------------

OBJ=gptrace.o gelf.o

all: injectso-finder
injectso-finder: injectso-finder.c $(OBJ)
gcc -O2 $< -o $@ -Wall $(OBJ)
gptrace.o: gptrace.c
gcc -O2 $< -c -o $@ -Wall
gelf.o: gelf.c
gcc -O2 $< -c -o $@ -Wall
clean:
rm *.o -rf
rm injectso-finder -rf

没有评论: