Browse Source

Initial commit

Yann Weber 2 years ago
commit
6dfc10797f
7 changed files with 572 additions and 0 deletions
  1. 40
    0
      Makefile
  2. 7
    0
      README
  3. 204
    0
      asmsh.c
  4. 60
    0
      asmsh.s
  5. 37
    0
      child.s
  6. 175
    0
      mmap_parse.c
  7. 49
    0
      mmap_parse.h

+ 40
- 0
Makefile View File

@@ -0,0 +1,40 @@
1
+GCC=gcc
2
+AS=as
3
+LD=ld
4
+ASFLAGS=--64
5
+LDFLAGS=-s -melf_x86_64
6
+
7
+CFLAGS=-Wall
8
+CLDFLAGS=-s
9
+
10
+# To build with debugging symbols
11
+ifeq ($(DEBUG), 1)
12
+	ASFLAGS += -DDEBUG=1 --gdwarf-5 -g
13
+	LDFLAGS = -g -melf_x86_64
14
+	LIB_FILE = src/lib$(LIBNAME)_dbg.a
15
+	CFLAGS += -g
16
+	CLDFLAGS = -g
17
+endif
18
+
19
+C_SRCS=$(wildcard *.c)
20
+C_OBJ=$(C_SRCS:.c=.o)
21
+
22
+
23
+all: child asmsh
24
+
25
+asmsh: $(C_OBJ)
26
+	$(GCC) $(CLDFLAGS) -o $@ $<
27
+
28
+$(C_OBJ): %.o: %.c Makefile
29
+	$(GCC) $(CFLAGS) -o $@ -c $<
30
+
31
+child: child.o
32
+	$(LD) $(LDFLAGS) -o $@ $<
33
+
34
+child.o: child.s Makefile
35
+	$(AS) $(ASFLAGS) -o $@ $<
36
+
37
+.PHONY: clean
38
+
39
+clean:
40
+	-rm -f $(C_OBJ) child.o

+ 7
- 0
README View File

@@ -0,0 +1,7 @@
1
+asmsh
2
+
3
+An assembly shell.
4
+
5
+Interactively run assembly into a terminal emulator.
6
+
7
+Uses ptrace syscall to achieve this.

+ 204
- 0
asmsh.c View File

@@ -0,0 +1,204 @@
1
+#include<fcntl.h>
2
+#include<stdio.h>
3
+#include<unistd.h>
4
+#include<signal.h>
5
+#include<stdlib.h>
6
+#include<string.h>
7
+#include<sys/ptrace.h>
8
+#include<sys/types.h>
9
+#include<sys/stat.h>
10
+#include<sys/user.h>
11
+#include<sys/wait.h>
12
+
13
+#define CHILD_EXEC_PATH "./child"
14
+
15
+void child_process();
16
+
17
+int main(int argc, char *argv[], char *envp[])
18
+{
19
+	int cpid, wstatus;
20
+	unsigned long pret;
21
+	pid_t wpid;
22
+	int sigpipe[2];
23
+	char sigbuf;
24
+	struct user_regs_struct regs;
25
+
26
+	if(pipe(sigpipe) < 0)
27
+	{
28
+		perror("Unable to open pipe");
29
+		return 1;
30
+	}
31
+
32
+	cpid = fork();
33
+	if(cpid < 0)
34
+	{
35
+		perror("Unable to fork :");
36
+		return 1;
37
+	}
38
+	else if(cpid == 0)
39
+	{
40
+		child_process(argv, envp, sigpipe);
41
+	}
42
+
43
+	printf("Child started %d\n", cpid);
44
+
45
+	if(ptrace(PTRACE_ATTACH, cpid, 0, 0) == -1)
46
+	{
47
+		perror("Unable to attach to child process");
48
+		
49
+		goto err_cleanup;
50
+	}
51
+
52
+	if(waitpid(cpid, &wstatus, 0) < 0)
53
+	{
54
+		perror("Unable to wait for child process to stop");
55
+		goto err_cleanup;
56
+	}
57
+	if(!WIFSTOPPED(wstatus))
58
+	{
59
+		dprintf(2, "Wstatus = %d\n", wstatus);
60
+		goto err_cleanup;
61
+	}
62
+
63
+
64
+	//read(sigpipe[0], &sigbuf, 1); // sync message
65
+	printf("Attached to %d\n", cpid);
66
+	if(ptrace(PTRACE_SETOPTIONS, cpid, NULL, PTRACE_O_TRACEEXEC) < 0)
67
+	{
68
+		perror("Setoptions error");
69
+		goto err_cleanup;
70
+	}
71
+
72
+	if(ptrace(PTRACE_CONT, cpid, NULL, 0) < 0)
73
+	{
74
+		perror("CONT error");
75
+		goto err_cleanup;
76
+	}
77
+
78
+	if(waitpid(cpid, &wstatus, 0) < 0)
79
+	{
80
+		perror("Unable to wait for child process to stop");
81
+		goto err_cleanup;
82
+	}
83
+	if(wstatus >> 8 != (SIGTRAP | (PTRACE_EVENT_EXEC<<8)))
84
+	{
85
+		dprintf(2, "Wstatus = %d\n", wstatus);
86
+		goto err_cleanup;
87
+	}
88
+
89
+	// first syscall is execve ret
90
+	// then mmap in & out
91
+	for(int i=0; i<3; i++)
92
+	{
93
+		if(ptrace(PTRACE_SYSCALL, cpid, NULL, 0) < 0)
94
+		{
95
+			perror("CONT error");
96
+			goto err_cleanup;
97
+		}
98
+		printf("syscall sent, waiting child to stop\n");
99
+
100
+		if(waitpid(cpid, &wstatus, 0) < 0)
101
+		{
102
+			perror("Unable to wait for child process to stop");
103
+			goto err_cleanup;
104
+		}
105
+		if(wstatus != 1407)
106
+		{
107
+			dprintf(2, "Wstatus = %d\n", wstatus);
108
+			goto err_cleanup;
109
+		}
110
+	}
111
+	printf("mmap done ?\n");
112
+
113
+
114
+	bzero(&regs, sizeof(regs));
115
+	if(ptrace(PTRACE_GETREGS, cpid, NULL, &regs) < 0)
116
+	{
117
+		perror("GETREGS error");
118
+		goto err_cleanup;
119
+	}
120
+
121
+	printf("rax = %016llX rsp=%016llX r15=%016llX rip=%016llX\n",
122
+			regs.rax, regs.rsp, regs.r15, regs.rip);
123
+
124
+	/*
125
+	if((pret = ptrace(PTRACE_PEEKTEXT, cpid, regs.rsp, 0)) < 0)
126
+	{
127
+		perror("PEEKTEXT fails");
128
+		goto err_cleanup;
129
+	}
130
+
131
+	printf("mmap_addr : %08lx", pret);
132
+
133
+	if((pret = ptrace(PTRACE_PEEKTEXT, cpid, regs.rsp+sizeof(long), 0)) < 0)
134
+	{
135
+		perror("PEEKTEXT fails");
136
+		goto err_cleanup;
137
+	}
138
+	printf(" %08lx\n", pret);
139
+	*/
140
+	char mapfile[256];
141
+	snprintf(mapfile, 256, "/proc/%d/maps", cpid);
142
+	int mapfd = open(mapfile, O_RDONLY);
143
+	char buff[256];
144
+	int read_ret;
145
+
146
+	do
147
+	{
148
+		read_ret = read(mapfd, buff, 255);
149
+		buff[read_ret] = '\0';
150
+		if(read_ret)
151
+		{
152
+			printf("%s", buff);
153
+		}
154
+	}while(read_ret > 0);
155
+
156
+	printf("Exiting...\n");
157
+	kill(cpid, SIGKILL);
158
+	exit(0);
159
+
160
+err_cleanup:
161
+	/*
162
+		if(waitpid(cpid, &wstatus, 0) < 0)
163
+		{
164
+			perror("Unable to wait for child process to stop");
165
+			goto err_cleanup;
166
+		}
167
+		if(WIFEXITED(wstatus))
168
+		{
169
+			dprintf(2, "child exited with status %d\n", WEXITSTATUS(wstatus));
170
+
171
+		} else if(WCOREDUMP(wstatus)) {
172
+			dprintf(2, "child segfault\n");
173
+		} else if(WIFSTOPPED(wstatus)) {
174
+			dprintf(2, "child stopped\n");
175
+		} else {
176
+			dprintf(2, "Wstatus = %d\n", wstatus);
177
+		}
178
+	*/
179
+
180
+	dprintf(2, "Hardkill %d\n", cpid);
181
+	kill(cpid, SIGKILL);
182
+	exit(2);
183
+
184
+}
185
+
186
+void child_process(char * argv[], char *envp[], int sigpipe[2])
187
+{
188
+	char sigbuf = '\0';
189
+	//char* const argv[] = {"child"};
190
+	//char* const envp[] = {};
191
+	/*
192
+	if(ptrace(PTRACE_TRACEME, 0,0,0) < 0)
193
+	{
194
+		perror("Unable to TRACEME");
195
+		exit(5);
196
+	}
197
+	printf("TRACEME %d [OK]\n", getpid());
198
+	*/
199
+	//write(sigpipe[1], &sigbuf, 1); // sync message
200
+	printf("%d execve\n", getpid());
201
+	execve(CHILD_EXEC_PATH, argv, envp);
202
+	perror("Unable to execve");
203
+	exit(5);
204
+}

+ 60
- 0
asmsh.s View File

@@ -0,0 +1,60 @@
1
+	.file	"asmsh.c"
2
+	.text
3
+	.section	.rodata
4
+.LC0:
5
+	.string	"Unable to fork :"
6
+	.text
7
+	.globl	main
8
+	.type	main, @function
9
+main:
10
+.LFB6:
11
+	.cfi_startproc
12
+	pushq	%rbp
13
+	.cfi_def_cfa_offset 16
14
+	.cfi_offset 6, -16
15
+	movq	%rsp, %rbp
16
+	.cfi_def_cfa_register 6
17
+	subq	$32, %rsp
18
+	movl	%edi, -20(%rbp)
19
+	movq	%rsi, -32(%rbp)
20
+	call	fork@PLT
21
+	movl	%eax, -4(%rbp)
22
+	cmpl	$0, -4(%rbp)
23
+	jns	.L2
24
+	leaq	.LC0(%rip), %rdi
25
+	call	perror@PLT
26
+	movl	$1, %eax
27
+	jmp	.L3
28
+.L2:
29
+	cmpl	$0, -4(%rbp)
30
+	jne	.L4
31
+	movl	$0, %eax
32
+	call	child_process
33
+.L4:
34
+	movl	$0, %eax
35
+.L3:
36
+	leave
37
+	.cfi_def_cfa 7, 8
38
+	ret
39
+	.cfi_endproc
40
+.LFE6:
41
+	.size	main, .-main
42
+	.globl	child_process
43
+	.type	child_process, @function
44
+child_process:
45
+.LFB7:
46
+	.cfi_startproc
47
+	pushq	%rbp
48
+	.cfi_def_cfa_offset 16
49
+	.cfi_offset 6, -16
50
+	movq	%rsp, %rbp
51
+	.cfi_def_cfa_register 6
52
+	nop
53
+	popq	%rbp
54
+	.cfi_def_cfa 7, 8
55
+	ret
56
+	.cfi_endproc
57
+.LFE7:
58
+	.size	child_process, .-child_process
59
+	.ident	"GCC: (Debian 10.2.1-6) 10.2.1 20210110"
60
+	.section	.note.GNU-stack,"",@progbits

+ 37
- 0
child.s View File

@@ -0,0 +1,37 @@
1
+.file "child64.s"
2
+
3
+.section .text
4
+.global _start
5
+
6
+_start:
7
+	mov $0x9, %rax # MMAP
8
+	xor %rdi, %rdi
9
+	mov $0x1000, %rsi # 1 page map
10
+	mov $(0x1|0x2), %rdx # PROT_READ | PROT_WRITE
11
+	mov $(0x20 | 0x1), %r10 # MAP_ANONYMOUS | MAP_SHARED
12
+	mov $-1, %r8 # fd
13
+	xor %r9, %r9
14
+	syscall
15
+
16
+	cmp $0, %rax
17
+	jle .errmap
18
+
19
+	push %rax
20
+	xor %rax, %rax
21
+	push %rax
22
+
23
+
24
+	mov $-1, %r15
25
+	mov $34, %rax # sys_pause
26
+	syscall
27
+
28
+	jmp *(%rsp)
29
+
30
+	mov $60, %rax
31
+	xor %rdi, %rdi
32
+	syscall
33
+
34
+	.errmap:
35
+		mov $60, %rax # sys_exit
36
+		mov $1, %rdi
37
+		syscall

+ 175
- 0
mmap_parse.c View File

@@ -0,0 +1,175 @@
1
+#include "mmap_parse.h"
2
+
3
+int child_mmap_get(pid_t child_pid, child_mmap_l *maps)
4
+{
5
+	const int RDBUF_SZ = 4095;
6
+	char procfs_path[PATH_MAX+1];
7
+	char rdbuf[RDBUF_SZ+1];
8
+	char *line, *endline;
9
+	int ret, maps_fd;
10
+	size_t curmap;
11
+	void *tmp;
12
+	
13
+	if(child_pid == -1)
14
+	{
15
+		errno = EINVAL;
16
+		return -1;
17
+	}
18
+
19
+	ret = snprintf(procfs_path, PATH_MAX, "/proc/%d/maps", child_pid);
20
+	if(ret < 0) { return -1; }
21
+	procfs_path[ret] = '\0';
22
+
23
+	if((maps_fd = open(procfs_path, O_RDONLY)) < 0)
24
+	{
25
+		return -1;
26
+	}
27
+
28
+	curmap = 0;
29
+
30
+	do
31
+	{
32
+		ret = read(maps_fd, rdbuf, RDBUF_SZ);
33
+		if(ret < 0) { goto err; }
34
+		rdbuf[ret] = '\0';
35
+		line = endline = rdbuf;
36
+		while(*endline)
37
+		{
38
+			if(*endline == '\n')
39
+			{
40
+				if(maps->size <= curmap)
41
+				{
42
+					if(_child_mmap_alloc(curmap, maps) < 0)
43
+					{
44
+						goto err;
45
+					}
46
+				}
47
+
48
+				*endline = '\0';
49
+				ret = child_mmap_parseline(line, &maps->maps[curmap]);
50
+				if(ret < 0) { goto err; }
51
+				line = endline + 1;
52
+			}
53
+			endline++;
54
+		}
55
+	}while(1);
56
+
57
+	close(maps_fd);
58
+
59
+	if(curmap < maps->size)
60
+	{
61
+		tmp = realloc(maps->maps, sizeof(child_mmap_t) * curmap);
62
+		if(!tmp)
63
+		{
64
+			goto err;
65
+		}
66
+		maps->maps = tmp;
67
+		maps->size = curmap;
68
+	}
69
+
70
+
71
+	return 0;
72
+
73
+err:
74
+	ret = errno;
75
+	close(maps_fd);
76
+	errno = ret;
77
+	return -1;
78
+}
79
+
80
+int child_mmap_parseline(char *line, child_mmap_t *maps)
81
+{
82
+	char *ptr, *orig, *endptr;
83
+	unsigned long long parsed;
84
+	int errno_bck, cperm;
85
+	size_t i;
86
+
87
+	void **addr_ptr[2] = {&maps->start, &maps->stop};
88
+	const char addr_sep[2] = "- ";
89
+	const char perms[3] = "rwx";
90
+	const int perms_val[3] = {PROT_READ, PROT_WRITE, PROT_EXEC};
91
+
92
+#define parsefield(line, sep, base, mapfield) {\
93
+unsigned long long p; char *endptr;\
94
+errno = 0;\
95
+p = strtoull(line, &endptr, base);\
96
+if(errno || *endptr != sep) { goto err_inval; }\
97
+*mapfield=p;
98
+
99
+
100
+	ptr = orig = line;
101
+
102
+	for(i=0; i<2; i++)
103
+	{
104
+		errno = 0;
105
+		parsed = strtoull(line, &endptr, 16);
106
+		if(errno || *endptr != addr_sep[i])
107
+		{
108
+			goto err_inval;
109
+		}
110
+
111
+		*addr_ptr[i] = (void*)parsed;
112
+
113
+		line = endptr+1;
114
+	}
115
+	
116
+	cperm = 1;
117
+	maps->perm = 0;
118
+	for(i=0; i<3; i++)
119
+	{
120
+		if(*line == perms[i])
121
+		{
122
+			maps->perm |= perms_val[i];
123
+		}
124
+		else if (*line != '-')
125
+		{
126
+			goto err_inval;
127
+		}
128
+		line++;
129
+		cperm <<= 1;
130
+	}
131
+	switch(*line)
132
+	{
133
+		case 'p':
134
+			maps->perm |= MAP_PRIVATE;
135
+			break;
136
+		case 's':
137
+			maps->perm |= MAP_SHARED;
138
+			break;
139
+		default:
140
+			goto err_inval;
141
+	}
142
+
143
+	line++;
144
+
145
+
146
+	return 0;
147
+
148
+	err_inval:
149
+		errno_bck = errno;
150
+		dprintf(2, "Invalid procfs/[pid]/maps content '%s'", orig);
151
+	err:
152
+		return -1;
153
+}
154
+
155
+int _child_mmap_alloc(size_t curmap, child_mmap_l *maps)
156
+{
157
+	void *tmp;
158
+	maps->size++;
159
+	if(curmap == 0)
160
+	{
161
+		tmp = malloc(sizeof(child_mmap_t));
162
+	}
163
+	else
164
+	{
165
+		tmp = realloc(maps->maps,
166
+			sizeof(child_mmap_t) * maps->size);
167
+	}
168
+	if(!tmp)
169
+	{
170
+		perror("Unable to allocate maps description");
171
+		return -1;
172
+	}
173
+	maps->maps = tmp;
174
+	return 0;
175
+}

+ 49
- 0
mmap_parse.h View File

@@ -0,0 +1,49 @@
1
+#ifndef ASMSH_MMAP_PARSE_H
2
+#define ASMSH_MMAP_PARSE_H
3
+
4
+#include <sys/mman.h>
5
+#include <sys/types.h>
6
+#include <sys/stat.h>
7
+#include <errno.h>
8
+#include <fcntl.h>
9
+#include <limits.h>
10
+#include <stdlib.h>
11
+#include <stdio.h>
12
+#include <unistd.h>
13
+
14
+extern int errno;
15
+
16
+typedef struct child_mmap_s child_mmap_t;
17
+typedef struct child_mmap_list child_mmap_l;
18
+
19
+struct child_mmap_s
20
+{
21
+	void *start;
22
+	void *stop;
23
+	int perm;
24
+	size_t offset;
25
+	dev_t device;
26
+	ino_t inode;
27
+	char *pathname;
28
+};
29
+
30
+struct child_mmap_list
31
+{
32
+	child_mmap_t *maps;
33
+	size_t size;
34
+};
35
+
36
+/** Parse /proc/[pid]/map file
37
+ *
38
+ * @param pid_t The pid of the child process we ptrace attached
39
+ * @param child_mmap_l A child map that will be filled with child's mmaps
40
+ * @return 0 if no error else -1
41
+ */
42
+int child_mmap_get(pid_t child_pid, child_mmap_l *maps);
43
+
44
+
45
+int child_mmap_parseline(char *line, child_mmap_t *map);
46
+
47
+int _child_mmap_alloc(size_t curmap, child_mmap_l *maps);
48
+
49
+#endif

Loading…
Cancel
Save