Skip to content
Permalink
master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <unistd.h>
#include <sys/syscall.h> /* For SYS_xxx definitions */
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ptrace.h>
#include <errno.h>
#include <signal.h>
#include <sys/user.h>
#include <syscall.h>
#include <fcntl.h>
#include <stdint.h>
#include <string.h>
#include <stdarg.h>
#include <regex.h>
typedef uint64_t u64;
typedef int64_t s64;
/* from include/linux/dirent.h : */
struct linux_dirent64 {
u64 d_ino;
s64 d_off;
unsigned short d_reclen;
unsigned char d_type;
char d_name[0];
};
void die(char *fmt,...) {
va_list ap;
va_start(ap,fmt);
vfprintf(stderr,fmt,ap);
exit(1);
}
void die_regerror(int status,regex_t *re) {
char msg[80];
int s;
s=regerror(status,re,msg,sizeof(msg));
die("regex: %s\n",msg);
}
int hostnum(char *hostname) {
static regex_t *re=NULL;
int status;
regmatch_t match[2];
if (!re) {
re=malloc(sizeof(*re));
if (!re) die("");
status=regcomp(re,"^host([0-9]+)$",REG_EXTENDED);
if (status) die_regerror(status,re);
}
status=regexec(re,hostname,sizeof(match)/sizeof(*match),match,0);
if (status==0) {
char c=hostname[match[1].rm_eo];
match[1].rm_eo='\0';
int num=atoi(&hostname[match[1].rm_so]);
match[1].rm_eo=c;
return(num);
} else if (status==REG_NOMATCH) {
return(-1);
} else {
die_regerror(status,re);
}
}
struct sortentry {
struct linux_dirent64 *dirent;
int hostnum;
};
int compare_sortentry(const void *vp1,const void *vp2) {
struct sortentry *p1=(struct sortentry *)vp1;
struct sortentry *p2=(struct sortentry *)vp2;
if (p1->hostnum!=-1 && p2->hostnum!=-1) {
return p1->hostnum<p2->hostnum ? -1 : p1->hostnum>p2->hostnum ? 1 : 0;
}
return strcmp(p1->dirent->d_name,p2->dirent->d_name);
}
void fix_memory(pid_t pid,size_t count,void *dirp) {
char *memfilename;
int fd;
char *dirents_unsorted,*dirents_sorted;
struct sortentry *sort_array;
struct sortentry *sort_entry;
size_t s;
int entry_count;
int bpos;
int i;
struct linux_dirent64 *d;
if (count==0) return;
if (asprintf(&memfilename,"/proc/%d/mem",pid)==-1) die("%m\n");
fd=open(memfilename,O_RDWR);
if (fd==-1) die (memfilename);
dirents_unsorted=malloc(count);
if(!dirents_unsorted) die ("");
if (lseek(fd,(off_t)dirp,SEEK_SET)==-1) die("%s: %m\n",memfilename);
s=read(fd,dirents_unsorted,count);
if (s == -1) die("%s: %m\n",memfilename);
if (s != count) die("short reads on childs memory not implemented");
entry_count=0;
for (bpos=0;bpos<count;) {
d = (struct linux_dirent64 *) (dirents_unsorted + bpos);
entry_count++;
bpos+=d->d_reclen;
}
sort_array=malloc(entry_count*sizeof (*sort_array));
if (!sort_array) die ("");
sort_entry=sort_array;
for (bpos=0;bpos<count;) {
d = (struct linux_dirent64 *) (dirents_unsorted + bpos);
sort_entry->dirent=d;
sort_entry->hostnum=hostnum(d->d_name);
sort_entry++;
bpos+=d->d_reclen;
}
// for (i=0;i<entry_count;i++) { printf("ary[%d] : %p : %s : %d\n",i,sort_array[i].dirent,sort_array[i].dirent->d_name,sort_array[i].hostnum); }
qsort(sort_array,entry_count,sizeof(*sort_array),compare_sortentry);
// for (i=0;i<entry_count;i++) { printf("ary[%d] : %p : %s : %d\n",i,sort_array[i].dirent,sort_array[i].dirent->d_name,sort_array[i].hostnum); }
dirents_sorted=malloc(count);
if(!dirents_sorted) die ("%m\n");
bpos=0;
for (i=0;i<entry_count;i++) {
d = (struct linux_dirent64 *) (dirents_sorted + bpos);
memcpy(d,sort_array[i].dirent,sort_array[i].dirent->d_reclen);
bpos+=sort_array[i].dirent->d_reclen;
}
// for (bpos=0;bpos<count;) { d = (struct linux_dirent64 *) (dirents_sorted + bpos); printf(" --> %s\n",d->d_name); bpos+=d->d_reclen; }
if (lseek(fd,(off_t)dirp,SEEK_SET)==-1) die("%s: %m\n",memfilename);
s=write(fd,dirents_sorted,count);
if (s == -1) die(memfilename);
if (s != count) die("internal error: short write");
close(fd);
free(memfilename);
free(dirents_unsorted);
free(dirents_sorted);
free(sort_array);
}
int main(int argc, char **argv) {
pid_t pid;
int status;
int syscall_state=0;
struct user user;
static const char *TW_CLI_ORIG="/root/bin/tw_cli.exe";
pid=fork();
if (pid==0) {
if (ptrace(PTRACE_TRACEME,NULL,NULL)==-1) die("ptrace: %m\n");
execv(TW_CLI_ORIG,argv);
die("%s: %m\n",TW_CLI_ORIG);
} else if (pid==-1) {
die("fork: %m\n");
}
while(1) {
pid=wait(&status);
if (pid==-1) die("wait: %m\n");
if (WIFSIGNALED(status)) {
int signal=WTERMSIG(status);
die("child got signal %d - exiting\n",signal);
} else if (WIFSTOPPED(status)) {
int signal=WSTOPSIG(status);
if (signal==SIGTRAP) {
if(ptrace(PTRACE_SETOPTIONS,pid,NULL,PTRACE_O_TRACESYSGOOD)==-1) die("ptrace: %m\n");
if(ptrace(PTRACE_SYSCALL,pid,NULL,NULL)==-1) die ("ptrace: %m\n");
} else if (signal==SIGTRAP|0x80) {
if (syscall_state==1) {
if(ptrace(PTRACE_GETREGS,pid,NULL,&user)==-1) die("ptrace: %m\n");;
if (user.regs.orig_rax == SYS_getdents64) {
fix_memory(pid,(int)user.regs.rax,(void *)user.regs.rsi);
}
}
syscall_state=1-syscall_state;
if(ptrace(PTRACE_SYSCALL,pid,NULL,NULL)==-1) die("ptrace: %m\n");;
} else {
die("child stopped by signal %d - exiting\n",signal);
}
} else if (WIFEXITED(status)) {
if (WEXITSTATUS(status)) {
exit(1);
} else {
exit(0);
}
} else {
die("unexpected return from wait. status=%08x - exiting\n",status);
}
}
}