First sheel implementation using GNU readline
This commit is contained in:
parent
101ce9fa0f
commit
c97d54e149
4 changed files with 109 additions and 181 deletions
|
|
@ -2,7 +2,7 @@ bin_PROGRAMS = asmsh child
|
|||
|
||||
libcheck_asmsh_a_SOURCES = mmap_parse.c asm_env.c compile.c logger.c
|
||||
|
||||
asmsh_SOURCES = asmsh.c $(libasmsh_a_SOURCES)
|
||||
asmsh_SOURCES = asmsh.c $(libcheck_asmsh_a_SOURCES)
|
||||
child_SOURCES = child.s
|
||||
|
||||
asmsh_LDFLAGS=-g -O2
|
||||
|
|
@ -41,7 +41,7 @@ $(LCOV_HTML): $(LCOV_INFO)
|
|||
endif
|
||||
|
||||
clean-local:
|
||||
-rm -rf $(TO_CLEAN_LOCAL)
|
||||
-rm -rf $(TO_LOCAL_CLEAN)
|
||||
|
||||
endif
|
||||
|
||||
|
|
|
|||
282
asmsh.c
282
asmsh.c
|
|
@ -1,204 +1,128 @@
|
|||
#include<fcntl.h>
|
||||
#include<stdio.h>
|
||||
#include<unistd.h>
|
||||
#include<signal.h>
|
||||
#include<stdlib.h>
|
||||
#include<string.h>
|
||||
#include<sys/ptrace.h>
|
||||
#include<sys/types.h>
|
||||
#include<sys/stat.h>
|
||||
#include<sys/user.h>
|
||||
#include<sys/wait.h>
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <readline/readline.h>
|
||||
#include <readline/history.h>
|
||||
|
||||
#define CHILD_EXEC_PATH "./child"
|
||||
|
||||
void child_process();
|
||||
#include "asm_env.h"
|
||||
#include "compile.h"
|
||||
|
||||
static void print_regs(asmsh_env_t *env)
|
||||
{
|
||||
asmsh_env_update_regs(env);
|
||||
struct user_regs_struct *r = &env->regs;
|
||||
|
||||
#define FLG(b, l) ( (r->eflags & (1<<b))?l:'-' )
|
||||
|
||||
printf("rax: %016lx rbx: %016lx rcx: %016lx rdx: %016lx\n\
|
||||
rbp: %016lx rsi: %016lx rdi: %016lx rsp: %016lx\n\
|
||||
r8: %016lx r9: %016lx r10: %016lx r11: %016lx\n\
|
||||
r12: %016lx r13: %016lx r14: %016lx r15: %016lx\n\
|
||||
rip: %016lx flg: %016lx\n\
|
||||
cs: %04x ds: %04x es: %04x fs:%04x gs: %04x ss:%04x\n\
|
||||
flags: %c%c%c%c|%c%c%c\n\
|
||||
ODSZ|APC\n\
|
||||
", r->rax, r->rbx, r->rcx, r->rdx,\
|
||||
r->rbp, r->rsi, r->rdi, r->rsp,\
|
||||
r->r8, r->r9, r->r10, r->r11,\
|
||||
r->r12, r->r13, r->r14, r->r15,\
|
||||
r->rip, r->eflags,\
|
||||
r->cs, r->ds, r->es, r->fs, r->gs, r->ss,
|
||||
FLG(11,'O'), FLG(10, 'D'), FLG(7, 'S'), FLG(6, 'Z'),
|
||||
FLG(4, 'A'), FLG(2, 'P'), FLG(0, 'C'));
|
||||
|
||||
#undef FLG
|
||||
}
|
||||
|
||||
|
||||
static char *asm_match_generator(const char *text, int state)
|
||||
{
|
||||
//dprintf(2,"2 '%s' %d\n", text, state);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static char **asmsh_completion(const char *text, int start, int end)
|
||||
{
|
||||
rl_attempted_completion_over = 1;
|
||||
//dprintf(2,"\n'%s' '%s' %d %d\n", rl_line_buffer, text, start, end);
|
||||
return rl_completion_matches(text, asm_match_generator);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[], char *envp[])
|
||||
{
|
||||
int cpid, wstatus;
|
||||
unsigned long pret;
|
||||
pid_t wpid;
|
||||
int sigpipe[2];
|
||||
char sigbuf;
|
||||
struct user_regs_struct regs;
|
||||
asmsh_asmc_ctx_t *cctx;
|
||||
asmsh_env_t *env;
|
||||
asmsh_bytecode_t bcode;
|
||||
|
||||
if(pipe(sigpipe) < 0)
|
||||
int ret, status;
|
||||
char *cmd;
|
||||
|
||||
if(!(env = asmsh_env(CHILD_EXEC_PATH)))
|
||||
{
|
||||
perror("Unable to open pipe");
|
||||
perror("Unable to init asm_env");
|
||||
return 1;
|
||||
}
|
||||
|
||||
cpid = fork();
|
||||
if(cpid < 0)
|
||||
if(!(cctx = asmsh_asmc_ctx_default()))
|
||||
{
|
||||
perror("Unable to fork :");
|
||||
return 1;
|
||||
}
|
||||
else if(cpid == 0)
|
||||
{
|
||||
child_process(argv, envp, sigpipe);
|
||||
perror("Unable to init compilation ctx");
|
||||
}
|
||||
|
||||
printf("Child started %d\n", cpid);
|
||||
rl_attempted_completion_function = asmsh_completion;
|
||||
|
||||
if(ptrace(PTRACE_ATTACH, cpid, 0, 0) == -1)
|
||||
while(1)
|
||||
{
|
||||
perror("Unable to attach to child process");
|
||||
|
||||
goto err_cleanup;
|
||||
}
|
||||
|
||||
if(waitpid(cpid, &wstatus, 0) < 0)
|
||||
{
|
||||
perror("Unable to wait for child process to stop");
|
||||
goto err_cleanup;
|
||||
}
|
||||
if(!WIFSTOPPED(wstatus))
|
||||
{
|
||||
dprintf(2, "Wstatus = %d\n", wstatus);
|
||||
goto err_cleanup;
|
||||
}
|
||||
|
||||
|
||||
//read(sigpipe[0], &sigbuf, 1); // sync message
|
||||
printf("Attached to %d\n", cpid);
|
||||
if(ptrace(PTRACE_SETOPTIONS, cpid, NULL, PTRACE_O_TRACEEXEC) < 0)
|
||||
{
|
||||
perror("Setoptions error");
|
||||
goto err_cleanup;
|
||||
}
|
||||
|
||||
if(ptrace(PTRACE_CONT, cpid, NULL, 0) < 0)
|
||||
{
|
||||
perror("CONT error");
|
||||
goto err_cleanup;
|
||||
}
|
||||
|
||||
if(waitpid(cpid, &wstatus, 0) < 0)
|
||||
{
|
||||
perror("Unable to wait for child process to stop");
|
||||
goto err_cleanup;
|
||||
}
|
||||
if(wstatus >> 8 != (SIGTRAP | (PTRACE_EVENT_EXEC<<8)))
|
||||
{
|
||||
dprintf(2, "Wstatus = %d\n", wstatus);
|
||||
goto err_cleanup;
|
||||
}
|
||||
|
||||
// first syscall is execve ret
|
||||
// then mmap in & out
|
||||
for(int i=0; i<3; i++)
|
||||
{
|
||||
if(ptrace(PTRACE_SYSCALL, cpid, NULL, 0) < 0)
|
||||
print_regs(env);
|
||||
cmd = readline("asmsh> ");
|
||||
if(!cmd)
|
||||
{
|
||||
perror("CONT error");
|
||||
goto err_cleanup;
|
||||
break;
|
||||
}
|
||||
printf("syscall sent, waiting child to stop\n");
|
||||
|
||||
if(waitpid(cpid, &wstatus, 0) < 0)
|
||||
if(strcmp(cmd, "quit") == 0)
|
||||
{
|
||||
perror("Unable to wait for child process to stop");
|
||||
goto err_cleanup;
|
||||
break;
|
||||
}
|
||||
if(wstatus != 1407)
|
||||
ret = asmsh_asmc_compile(cctx, cmd, &bcode);
|
||||
if(ret < 0)
|
||||
{
|
||||
dprintf(2, "Wstatus = %d\n", wstatus);
|
||||
goto err_cleanup;
|
||||
perror("Invalid instruction");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
printf("mmap done ?\n");
|
||||
|
||||
|
||||
bzero(®s, sizeof(regs));
|
||||
if(ptrace(PTRACE_GETREGS, cpid, NULL, ®s) < 0)
|
||||
{
|
||||
perror("GETREGS error");
|
||||
goto err_cleanup;
|
||||
if(asmsh_env_write_code(env, &bcode))
|
||||
{
|
||||
perror("Unable to write instruction");
|
||||
goto err;
|
||||
}
|
||||
ret = asmsh_env_step(env, &status);
|
||||
if(ret)
|
||||
{
|
||||
if(WIFEXITED(status))
|
||||
{
|
||||
printf("exited with status %d\n", WEXITSTATUS(status));
|
||||
}
|
||||
else if(WCOREDUMP(status))
|
||||
{
|
||||
printf("SEGFAULT");
|
||||
goto err;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Unknown status %d\n", status);
|
||||
goto err;
|
||||
}
|
||||
break;
|
||||
}
|
||||
add_history(cmd);
|
||||
}
|
||||
|
||||
printf("rax = %016llX rsp=%016llX r15=%016llX rip=%016llX\n",
|
||||
regs.rax, regs.rsp, regs.r15, regs.rip);
|
||||
|
||||
/*
|
||||
if((pret = ptrace(PTRACE_PEEKTEXT, cpid, regs.rsp, 0)) < 0)
|
||||
{
|
||||
perror("PEEKTEXT fails");
|
||||
goto err_cleanup;
|
||||
}
|
||||
|
||||
printf("mmap_addr : %08lx", pret);
|
||||
|
||||
if((pret = ptrace(PTRACE_PEEKTEXT, cpid, regs.rsp+sizeof(long), 0)) < 0)
|
||||
{
|
||||
perror("PEEKTEXT fails");
|
||||
goto err_cleanup;
|
||||
}
|
||||
printf(" %08lx\n", pret);
|
||||
*/
|
||||
char mapfile[256];
|
||||
snprintf(mapfile, 256, "/proc/%d/maps", cpid);
|
||||
int mapfd = open(mapfile, O_RDONLY);
|
||||
char buff[256];
|
||||
int read_ret;
|
||||
|
||||
do
|
||||
{
|
||||
read_ret = read(mapfd, buff, 255);
|
||||
buff[read_ret] = '\0';
|
||||
if(read_ret)
|
||||
{
|
||||
printf("%s", buff);
|
||||
}
|
||||
}while(read_ret > 0);
|
||||
|
||||
printf("Exiting...\n");
|
||||
kill(cpid, SIGKILL);
|
||||
exit(0);
|
||||
|
||||
err_cleanup:
|
||||
/*
|
||||
if(waitpid(cpid, &wstatus, 0) < 0)
|
||||
{
|
||||
perror("Unable to wait for child process to stop");
|
||||
goto err_cleanup;
|
||||
}
|
||||
if(WIFEXITED(wstatus))
|
||||
{
|
||||
dprintf(2, "child exited with status %d\n", WEXITSTATUS(wstatus));
|
||||
|
||||
} else if(WCOREDUMP(wstatus)) {
|
||||
dprintf(2, "child segfault\n");
|
||||
} else if(WIFSTOPPED(wstatus)) {
|
||||
dprintf(2, "child stopped\n");
|
||||
} else {
|
||||
dprintf(2, "Wstatus = %d\n", wstatus);
|
||||
}
|
||||
*/
|
||||
|
||||
dprintf(2, "Hardkill %d\n", cpid);
|
||||
kill(cpid, SIGKILL);
|
||||
exit(2);
|
||||
asmsh_asmc_ctx_free(cctx);
|
||||
asmsh_env_free(env);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
void child_process(char * argv[], char *envp[], int sigpipe[2])
|
||||
{
|
||||
char sigbuf = '\0';
|
||||
//char* const argv[] = {"child"};
|
||||
//char* const envp[] = {};
|
||||
/*
|
||||
if(ptrace(PTRACE_TRACEME, 0,0,0) < 0)
|
||||
{
|
||||
perror("Unable to TRACEME");
|
||||
exit(5);
|
||||
}
|
||||
printf("TRACEME %d [OK]\n", getpid());
|
||||
*/
|
||||
//write(sigpipe[1], &sigbuf, 1); // sync message
|
||||
printf("%d execve\n", getpid());
|
||||
execve(CHILD_EXEC_PATH, argv, envp);
|
||||
perror("Unable to execve");
|
||||
exit(5);
|
||||
err:
|
||||
asmsh_asmc_ctx_free(cctx);
|
||||
asmsh_env_free(env);
|
||||
return 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@
|
|||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
/* Define to 1 if you have the `readline' library (-lreadline). */
|
||||
#undef HAVE_LIBREADLINE
|
||||
|
||||
/* Define to 1 if you have the <limits.h> header file. */
|
||||
#undef HAVE_LIMITS_H
|
||||
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ AM_CONDITIONAL([HAVE_GCOV], [test -n "$GCOV"])
|
|||
AM_CONDITIONAL([HAVE_LCOV], [test -n "$LCOV"])
|
||||
|
||||
# Checks for libraries.
|
||||
AC_CHECK_LIB(readline, readline)
|
||||
|
||||
# Checks for header files.
|
||||
AC_CHECK_HEADERS([fcntl.h limits.h stdlib.h string.h unistd.h])
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue