First sheel implementation using GNU readline

This commit is contained in:
Yann Weber 2023-03-03 17:38:49 +01:00
commit c97d54e149
4 changed files with 109 additions and 181 deletions

View file

@ -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
View file

@ -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(&regs, sizeof(regs));
if(ptrace(PTRACE_GETREGS, cpid, NULL, &regs) < 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;
}

View file

@ -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

View file

@ -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])