├── .gitignore ├── README.md └── main.c /.gitignore: -------------------------------------------------------------------------------- 1 | trace_write 2 | trace_read 3 | trace_execve 4 | tw 5 | te 6 | *.zip 7 | *.tar.gz -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Trace SYScall 3 | 4 | Trace SYScall to reach the expected requirements. 5 | 6 | It is only supported for Linux. 7 | 8 | > It uses **PTRACE_GET_SYSCALL_INFO** (since Linux 5.3) to retrieve information about the system call that caused the stop. 9 | 10 | ## Compile 11 | 12 | ```shell 13 | gcc -g -D TRACE_WRITE main.c -o trace_write 14 | gcc -g -D TRACE_READ main.c -o trace_read 15 | gcc -g -D TRACE_EXECVE main.c -o trace_execve 16 | ``` 17 | 18 | ## Trace Write 19 | 20 | Trace `SYS_write` and `SYS_wirtev` to show the files that are being written by the specified application. 21 | 22 | ```shell 23 | $ gcc -g -D TRACE_WRITE main.c -o trace_write 24 | $ ./trace_write 25 | Usage: ./trace_write command 26 | $ ./trace_write pip install requests 27 | [TRACE INFO]: pipe:[508966] 28 | [TRACE INFO]: pipe:[503529] 29 | [TRACE INFO]: /dev/null 30 | [TRACE INFO]: pipe:[503526] 31 | [TRACE INFO]: pipe:[508968] 32 | [TRACE INFO]: /tmp/4vw85v75 33 | [TRACE INFO]: socket:[508975] 34 | [TRACE INFO]: /root/.cache/pip/http/e/a/c/6/1/eac61126daf80149d2a016f12a54eab5e3b5c1dbc77410ff1a97edc4okrq1ute.tmp 35 | [TRACE INFO]: /dev/pts/2 36 | Collecting requests 37 | [TRACE INFO]: socket:[508977] 38 | Downloading requests-2.27.1-py2.py3-none-any.whl (63 kB) 39 | [TRACE INFO]: /tmp/pip-unpack-8qb0r_s9/requests-2.27.1-py2.py3-none-any.whl 40 | |███████████████████████████████▏| 61 kB 182 kB/s eta 0:00:01[TRACE INFO]: /root/.cache/pip/http/7/4/4/4/0/7444028c92844801309674fa32b7e7e4cedf52a841b159c3a0c5c614872p4s2f.tmp 41 | |████████████████████████████████| 63 kB 175 kB/s 42 | [TRACE INFO]: /tmp/pip-req-tracker-tda92i_f/7444028c92844801309674fa32b7e7e4cedf52a841b159c3a0c5c614 43 | Requirement already satisfied: certifi>=2017.4.17 in /usr/lib/python3/dist-packages (from requests) (2019.11.28) 44 | Requirement already satisfied: urllib3<1.27,>=1.21.1 in /usr/lib/python3/dist-packages (from requests) (1.25.8) 45 | [TRACE INFO]: /root/.cache/pip/http/5/b/d/8/9/5bd894eeb3dfe1c8aaee1daecdfb74bbb314293813a730238621f077_rveqaj7.tmp 46 | Collecting charset-normalizer~=2.0.0 47 | Downloading charset_normalizer-2.0.12-py3-none-any.whl (39 kB) 48 | [TRACE INFO]: /tmp/pip-unpack-u64f27m4/charset_normalizer-2.0.12-py3-none-any.whl 49 | [TRACE INFO]: /root/.cache/pip/http/7/b/e/7/0/7be70c2367d09448b3057000aeeba81fbe2b757c84f8f2d4d928f49cfpq9hpl7.tmp 50 | [TRACE INFO]: /tmp/pip-req-tracker-tda92i_f/7be70c2367d09448b3057000aeeba81fbe2b757c84f8f2d4d928f49c 51 | Requirement already satisfied: idna<4,>=2.5 in /usr/lib/python3/dist-packages (from requests) (2.8) 52 | Installing collected packages: charset-normalizer, requests 53 | [TRACE INFO]: /usr/local/lib/python3.8/dist-packages/charset_normalizer/__init__.py 54 | [TRACE INFO]: /usr/local/lib/python3.8/dist-packages/charset_normalizer/api.py 55 | [TRACE INFO]: /usr/local/lib/python3.8/dist-packages/charset_normalizer/cd.py 56 | [TRACE INFO]: /usr/local/lib/python3.8/dist-packages/charset_normalizer/constant.py 57 | ... 58 | [TRACE INFO]: /usr/local/lib/python3.8/dist-packages/requests/__pycache__/structures.cpython-38.pyc.139768695870208 59 | [TRACE INFO]: /usr/local/lib/python3.8/dist-packages/requests/__pycache__/utils.cpython-38.pyc.139768697467360 60 | [TRACE INFO]: /usr/local/lib/python3.8/dist-packages/requests-2.27.1.dist-info/INSTALLER1ao0qzaa.tmp 61 | [TRACE INFO]: /usr/local/lib/python3.8/dist-packages/requests-2.27.1.dist-info/RECORDe5jz3x93.tmp 62 | Successfully installed charset-normalizer-2.0.12 requests-2.27.1 63 | ``` 64 | 65 | ## Trace Read 66 | 67 | Trace `SYS_read` and `SYS_readv` to show the files that are being read by the specified application. 68 | 69 | ```shell 70 | $ gcc -g -D TRACE_READ main.c -o trace_read 71 | $ ./trace_read 72 | Usage: ./trace_read command 73 | $ ./trace_read useradd trace 74 | [TRACE INFO]: /usr/lib/libaudit.so.1.0.0 75 | [TRACE INFO]: /usr/lib/libacl.so.1.1.2301 76 | [TRACE INFO]: /usr/lib/libattr.so.1.1.2501 77 | [TRACE INFO]: /usr/lib/libdl-2.33.so 78 | [TRACE INFO]: /usr/lib/libc-2.33.so 79 | [TRACE INFO]: /usr/lib/libcap-ng.so.0.0.0 80 | [TRACE INFO]: /proc/sys/kernel/cap_last_cap 81 | [TRACE INFO]: /proc/sys/kernel/ngroups_max 82 | [TRACE INFO]: /etc/login.defs 83 | [TRACE INFO]: /etc/default/useradd 84 | [TRACE INFO]: /etc/nsswitch.conf 85 | [TRACE INFO]: /usr/lib/libnss_files-2.33.so 86 | [TRACE INFO]: /etc/group 87 | [TRACE INFO]: /usr/lib/libnss_systemd.so.2 88 | [TRACE INFO]: /usr/lib/librt-2.33.so 89 | [TRACE INFO]: /usr/lib/libm-2.33.so 90 | [TRACE INFO]: /usr/lib/libcrypt.so.2.0.0 91 | [TRACE INFO]: /usr/lib/libcrypto.so.1.1 92 | [TRACE INFO]: /usr/lib/libp11-kit.so.0.3.0 93 | [TRACE INFO]: /usr/lib/libgcc_s.so.1 94 | [TRACE INFO]: /usr/lib/libpthread-2.33.so 95 | [TRACE INFO]: /usr/lib/libffi.so.8.1.0 96 | [TRACE INFO]: /proc/sys/kernel/random/boot_id 97 | [TRACE INFO]: /etc/passwd 98 | [TRACE INFO]: /etc/gshadow 99 | [TRACE INFO]: /etc/shadow 100 | [TRACE INFO]: /usr/share/zoneinfo/Asia/Shanghai 101 | ``` 102 | 103 | ## Trace Execve 104 | 105 | Trace `SYS_execve` to show the command that are being executed by the specified application. 106 | 107 | ```shell 108 | $ gcc -g -D TRACE_EXECVE main.c -o trace_execve 109 | $ ./trace_execve 110 | Usage: ./trace_execve command 111 | $ ./trace_execve gcc -g -D TRACE_EXECVE main.c -o trace_execve2 112 | [TRACE INFO]: /usr/bin/gcc -g -D TRACE_EXECVE main.c -o trace_execve2 113 | [TRACE INFO]: /usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/cc1 -quiet -D TRACE_EXECVE main.c -quiet -dumpdir trace_execve2- -dumpbase main.c -dumpbase-ext .c -mtune=generic -march=x86-64 -g -o /tmp/cchVCsia.s 114 | [TRACE INFO]: /usr/local/bin/as --gdwarf-5 --64 -o /tmp/cc1c9jzt.o /tmp/cchVCsia.s 115 | [TRACE INFO]: /usr/bin/as --gdwarf-5 --64 -o /tmp/cc1c9jzt.o /tmp/cchVCsia.s 116 | [TRACE INFO]: /usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/collect2 -plugin /usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/lto-wrapper -plugin-opt=-fresolution=/tmp/ccZGZTqG.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s --build-id --eh-frame-hdr --hash-style=gnu -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -o trace_execve2 /usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/../../../../lib/Scrt1.o /usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/../../../../lib/crti.o /usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/crtbeginS.o -L/usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0 -L/usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/../../../../lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/../../.. /tmp/cc1c9jzt.o -lgcc --push-state --as-needed -lgcc_s --pop-state -lc -lgcc --push-state --as-needed -lgcc_s --pop-state /usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/crtendS.o /usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/../../../../lib/crtn.o 117 | [TRACE INFO]: /usr/bin/ld -plugin /usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/lto-wrapper -plugin-opt=-fresolution=/tmp/ccZGZTqG.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s --build-id --eh-frame-hdr --hash-style=gnu -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -o trace_execve2 /usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/../../../../lib/Scrt1.o /usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/../../../../lib/crti.o /usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/crtbeginS.o -L/usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0 -L/usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/../../../../lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/../../.. /tmp/cc1c9jzt.o -lgcc --push-state --as-needed -lgcc_s --pop-state -lc -lgcc --push-state --as-needed -lgcc_s --pop-state /usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/crtendS.o /usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/../../../../lib/crtn.o 118 | ``` 119 | 120 | 121 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | // Show more information 22 | #ifdef DEBUG 23 | #define DPRINTF printf 24 | #else 25 | #define DPRINTF(...) 26 | #endif 27 | 28 | /** 29 | * The value must be TRUE, or the program will break down. 30 | * e.g., the value is thing what the program need to do. 31 | **/ 32 | #define CHECK(value) \ 33 | { \ 34 | if ((value) == 0) \ 35 | { \ 36 | fprintf(stderr, "%s:%d: %m\n", __FILE__, __LINE__); \ 37 | abort(); \ 38 | } \ 39 | } 40 | 41 | #define TTY_WORKED 1 42 | #define TTY_NONE 2 43 | #define TTY_ERROR 3 44 | int tty_status = 0; 45 | 46 | int check_tty() 47 | { 48 | int result; 49 | int session_id; 50 | 51 | result = ioctl(STDOUT_FILENO, TIOCGSID, &session_id); 52 | if(result != -1) 53 | { 54 | DPRINTF("[TRACE DEBUG]: TTY terminal\n"); 55 | tty_status = TTY_WORKED; 56 | result = 0; 57 | } 58 | else 59 | { 60 | if(errno == ENOTTY) 61 | { 62 | DPRINTF("[TRACE DEBUG]: ENOTTY\n"); 63 | tty_status = TTY_NONE; 64 | result = 0; 65 | } 66 | else 67 | { 68 | DPRINTF("[TRACE DEBUG]: Error\n"); 69 | fprintf(stderr, "[TRACE ERROR]: ioctl %m %s:%d\n", __FILE__, __LINE__); 70 | tty_status = TTY_ERROR; 71 | result = -1; 72 | } 73 | } 74 | 75 | return result; 76 | } 77 | 78 | #if (defined(TRACE_WRITE) || defined(TRACE_READ)) 79 | int handle_file_IO(int pid, struct ptrace_syscall_info *info) 80 | { 81 | char path_buf[0x1000], path[0x1000], *result; 82 | int existed, i; 83 | static char **path_lists = NULL; 84 | static size_t node_max = 0x400, node_count = 0; 85 | 86 | // Initial 87 | if (path_lists == NULL) 88 | { 89 | path_lists = (char **)malloc(sizeof(char *) * node_max); 90 | CHECK(path_lists != NULL); 91 | } 92 | 93 | memset(path_buf, 0, sizeof(path_buf)); 94 | snprintf(path_buf, sizeof(path_buf) - 1, "/proc/%d/fd/%lld", pid, info->entry.args[0]); 95 | memset(path, 0, sizeof(path)); 96 | if (readlink(path_buf, path, sizeof(path) - 1) != -1) 97 | { 98 | existed = 0; 99 | for (i = 0; existed == 0 && i < node_count; i++) 100 | { 101 | if (strcmp(path, path_lists[i]) == 0) 102 | { 103 | existed = 1; 104 | } 105 | } 106 | if (existed == 0) 107 | { 108 | // Extend 109 | if (node_count + 1 > node_max) 110 | { 111 | result = realloc(path_lists, sizeof(char *) * node_max * 2); 112 | CHECK(result != NULL); 113 | node_max = node_max * 2; 114 | path_lists = (char **)result; 115 | } 116 | result = strdup(path); 117 | CHECK(result != NULL); 118 | path_lists[node_count] = result; 119 | node_count++; 120 | if(tty_status == TTY_WORKED) 121 | { 122 | printf("[TRACE INFO]: \033[1;32m%s\033[0m\n", path); 123 | } 124 | else 125 | { 126 | printf("[TRACE INFO]: %s\n", path); 127 | } 128 | } 129 | } 130 | else 131 | { 132 | fprintf(stderr, "[TRACE ERROR]: pid %5d : readlink(%s) error : %m\n", pid, path_buf); 133 | } 134 | 135 | return 0; 136 | } 137 | #endif 138 | 139 | #ifdef TRACE_EXECVE 140 | int handle_double_quotation(char *out, char *in, int size) 141 | { 142 | int i = 0, j = 0; 143 | 144 | out[i++] = '"'; 145 | for(j = 0; in[j] && j < size && i < size ; j++) 146 | { 147 | switch (in[j]) 148 | { 149 | case '"': 150 | if(i < size) out[i++] = '\\'; 151 | if(i < size) out[i++] = in[j]; 152 | break; 153 | 154 | default: 155 | if(i < size) out[i++] = in[j]; 156 | break; 157 | } 158 | } 159 | 160 | if(i < size) 161 | { 162 | out[i++] = '"'; 163 | } 164 | else 165 | { 166 | return -1; 167 | } 168 | 169 | return 0; 170 | } 171 | int handle_execve(int pid, struct ptrace_syscall_info *info) 172 | { 173 | char buf[0x1000]; 174 | int fd, i, j; 175 | char *mem_addr, *result, chr; 176 | char **args_lists = NULL; 177 | size_t node_max = 0x400, node_count = 0; 178 | 179 | memset(buf, 0, sizeof(buf)); 180 | snprintf(buf, sizeof(buf) - 1, "/proc/%d/mem", pid); 181 | fd = open(buf, O_RDONLY); 182 | CHECK(fd != -1); 183 | 184 | // Initial 185 | args_lists = (char **)malloc(sizeof(char *) * node_max); 186 | CHECK(args_lists != NULL); 187 | 188 | for (i = 1, mem_addr = (char *)info->entry.args[0]; mem_addr; i++) 189 | { 190 | 191 | if (mem_addr) 192 | { 193 | memset(buf, 0, sizeof(buf)); 194 | for (j = 0, chr = -1; chr && j < sizeof(buf) - 1; j++) 195 | { 196 | CHECK(pread(fd, &chr, sizeof(chr), (size_t)mem_addr + j * sizeof(chr)) != -1); 197 | buf[j] = chr; 198 | } 199 | 200 | if (node_count + 1 > node_max) 201 | { 202 | result = realloc(args_lists, sizeof(char *) * node_max * 2); 203 | CHECK(result != NULL); 204 | node_max = node_max * 2; 205 | args_lists = (char **)result; 206 | } 207 | 208 | if(strchr(buf, ' ') == NULL) 209 | { 210 | result = strdup(buf); 211 | CHECK(result != NULL); 212 | } 213 | else 214 | { 215 | result = malloc(sizeof(buf)); 216 | CHECK(result != NULL); 217 | memset(result, 0, sizeof(buf)); 218 | handle_double_quotation(result, buf, sizeof(buf)); 219 | } 220 | 221 | args_lists[node_count] = result; 222 | node_count++; 223 | } 224 | 225 | // Next 226 | if (info->entry.args[1]) 227 | { 228 | CHECK(pread(fd, &mem_addr, sizeof(char *), info->entry.args[1] + i * sizeof(char *)) != -1); 229 | } 230 | else 231 | { 232 | mem_addr = NULL; 233 | } 234 | } 235 | 236 | // Output command 237 | for (i = 0; i < node_count; i++) 238 | { 239 | if (node_count == 1 && i == 0) // Only one 240 | { 241 | if(tty_status == TTY_WORKED) 242 | { 243 | printf("[TRACE INFO]: \033[1;32m%s\033[0m\n", args_lists[i]); 244 | } 245 | else 246 | { 247 | printf("[TRACE INFO]: %s\n", args_lists[i]); 248 | } 249 | } 250 | else if (i == 0) // The head node 251 | { 252 | if(tty_status == TTY_WORKED) 253 | { 254 | printf("[TRACE INFO]: \033[1;32m%s ", args_lists[i]); 255 | } 256 | else 257 | { 258 | printf("[TRACE INFO]: %s ", args_lists[i]); 259 | } 260 | } 261 | else if (i + 1 == node_count) // The final node 262 | { 263 | if(tty_status == TTY_WORKED) 264 | { 265 | printf("%s\033[0m\n", args_lists[i]); 266 | } 267 | else 268 | { 269 | printf("%s\n", args_lists[i]); 270 | } 271 | } 272 | else // Middle nodes 273 | { 274 | printf("%s ", args_lists[i]); 275 | } 276 | 277 | free(args_lists[i]); 278 | args_lists[i] = NULL; 279 | } 280 | 281 | free(args_lists); 282 | close(fd); 283 | 284 | return 0; 285 | } 286 | #endif 287 | 288 | int syscall_monitor(int pid, struct ptrace_syscall_info *info) 289 | { 290 | 291 | switch (info->entry.nr) 292 | { 293 | #ifdef TRACE_WRITE 294 | case SYS_write: 295 | case SYS_writev: 296 | handle_file_IO(pid, info); 297 | break; 298 | #endif 299 | 300 | #ifdef TRACE_READ 301 | case SYS_read: 302 | case SYS_readv: 303 | handle_file_IO(pid, info); 304 | #endif 305 | 306 | #ifdef TRACE_EXECVE 307 | case SYS_execve: 308 | handle_execve(pid, info); 309 | #endif 310 | 311 | default: 312 | break; 313 | } 314 | return 0; 315 | } 316 | 317 | int execve_with_args(char **argv) 318 | { 319 | char *env, *item; 320 | char buf[0x800], path[0x800]; 321 | 322 | if (access(argv[0], X_OK) == 0) 323 | { 324 | execv(argv[0], argv); 325 | } 326 | 327 | env = getenv("PATH"); 328 | if (env) 329 | { 330 | memset(buf, 0, sizeof(buf)); 331 | strncpy(buf, env, sizeof(buf) - 1); 332 | 333 | for (item = strtok(buf, ":"); item; item = strtok(NULL, ":")) 334 | { 335 | memset(path, 0, sizeof(path)); 336 | strncpy(path, item, sizeof(path) - 1); 337 | if (path[strlen(path) - 1] != '/') 338 | { 339 | strncat(path, "/", sizeof(path) - 1); 340 | } 341 | strncat(path, argv[0], sizeof(path) - 1); 342 | if (access(path, X_OK) == 0) 343 | { 344 | execv(path, argv); 345 | } 346 | } 347 | } 348 | 349 | fprintf(stderr, "%s:%d:%s: %m\n", __FILE__, __LINE__, "execv"); 350 | exit(EXIT_FAILURE); 351 | 352 | return -1; 353 | } 354 | 355 | int handle_trapped_event(int pid, int wstatus) 356 | { 357 | int event = wstatus >> 16; 358 | switch (event) 359 | { 360 | case 0: 361 | break; 362 | case PTRACE_EVENT_FORK: 363 | DPRINTF("[TRACE DEBUG]: pid %5d : trapped by event PTRACE_EVENT_FORK\n", pid); 364 | break; 365 | case PTRACE_EVENT_VFORK: 366 | DPRINTF("[TRACE DEBUG]: pid %5d : trapped by event PTRACE_EVENT_VFORK\n", pid); 367 | break; 368 | case PTRACE_EVENT_CLONE: 369 | DPRINTF("[TRACE DEBUG]: pid %5d : trapped by event PTRACE_EVENT_CLONE\n", pid); 370 | break; 371 | case PTRACE_EVENT_EXEC: 372 | DPRINTF("[TRACE DEBUG]: pid %5d : trapped by event PTRACE_EVENT_EXEC\n", pid); 373 | break; 374 | case PTRACE_EVENT_VFORK_DONE: 375 | DPRINTF("[TRACE DEBUG]: pid %5d : trapped by event PTRACE_EVENT_VFORK_DONE\n", pid); 376 | break; 377 | case PTRACE_EVENT_EXIT: 378 | DPRINTF("[TRACE DEBUG]: pid %5d : trapped by event PTRACE_EVENT_EXIT\n", pid); 379 | break; 380 | case PTRACE_EVENT_SECCOMP: 381 | DPRINTF("[TRACE DEBUG]: pid %5d : trapped by event PTRACE_EVENT_SECCOMP\n", pid); 382 | break; 383 | case PTRACE_EVENT_STOP: 384 | DPRINTF("[TRACE DEBUG]: pid %5d : trapped by event PTRACE_EVENT_STOP\n", pid); 385 | break; 386 | default: 387 | fprintf(stderr, "[TRACE ERROR]: pid %5d : trapped by unknown event %d (%#x)\n", pid, event, event); 388 | break; 389 | } 390 | return 0; 391 | } 392 | 393 | int handle_syscall_info(int pid, int wstatus) 394 | { 395 | struct ptrace_syscall_info info; 396 | 397 | for(errno = 0; ptrace(PTRACE_GET_SYSCALL_INFO, pid, sizeof(info), &info) == -1 && errno == ESRCH;) 398 | ; 399 | if(errno != 0 && errno != ESRCH) 400 | { 401 | fprintf(stderr, "[TRACE ERROR]: pid %5d : ptrace(PTRACE_GET_SYSCALL_INFO) error: %m\n", pid); 402 | return -1; 403 | } 404 | 405 | switch (info.op) 406 | { 407 | case PTRACE_SYSCALL_INFO_NONE: 408 | DPRINTF("[TRACE DEBUG]: pid %5d : got info PTRACE_SYSCALL_INFO_NONE\n", pid); 409 | break; 410 | case PTRACE_SYSCALL_INFO_ENTRY: 411 | DPRINTF("[TRACE DEBUG]: pid %5d : got info PTRACE_SYSCALL_INFO_ENTRY(%lld)\n", pid, info.entry.nr); 412 | syscall_monitor(pid, &info); 413 | break; 414 | case PTRACE_SYSCALL_INFO_EXIT: 415 | DPRINTF("[TRACE DEBUG]: pid %5d : got info PTRACE_SYSCALL_INFO_EXIT(%lld)\n", pid, info.exit.rval); 416 | break; 417 | case PTRACE_SYSCALL_INFO_SECCOMP: 418 | DPRINTF("[TRACE DEBUG]: pid %5d : got info PTRACE_SYSCALL_INFO_SECCOMP\n", pid); 419 | break; 420 | default: 421 | fprintf(stderr, "[TRACE ERROR]: pid %5d : got unknown info %d (%#x)\n", pid, info.op, info.op); 422 | break; 423 | } 424 | return 0; 425 | } 426 | 427 | int handle_stopped_signal(int pid, int wstatus) 428 | { 429 | switch (WSTOPSIG(wstatus)) 430 | { 431 | case SIGINT: 432 | printf("[TRACE INFO]: pid %5d : stopped by signal SIGINT\n", pid); 433 | ptrace(PTRACE_KILL, pid); 434 | break; 435 | case SIGILL: 436 | printf("[TRACE INFO]: pid %5d : stopped by signal SIGILL\n", pid); 437 | ptrace(PTRACE_KILL, pid); 438 | break; 439 | case SIGABRT: 440 | printf("[TRACE INFO]: pid %5d : stopped by signal SIGABRT\n", pid); 441 | ptrace(PTRACE_KILL, pid); 442 | break; 443 | case SIGFPE: 444 | printf("[TRACE INFO]: pid %5d : stopped by signal SIGFPE\n", pid); 445 | break; 446 | case SIGSEGV: 447 | printf("[TRACE INFO]: pid %5d : stopped by signal SIGSEGV\n", pid); 448 | ptrace(PTRACE_KILL, pid); 449 | break; 450 | case SIGTERM: 451 | printf("[TRACE INFO]: pid %5d : stopped by signal SIGTERM\n", pid); 452 | ptrace(PTRACE_KILL, pid); 453 | break; 454 | case SIGHUP: 455 | printf("[TRACE INFO]: pid %5d : stopped by signal SIGHUP\n", pid); 456 | break; 457 | case SIGQUIT: 458 | printf("[TRACE INFO]: pid %5d : stopped by signal SIGQUIT\n", pid); 459 | break; 460 | case SIGTRAP: 461 | DPRINTF("[TRACE DEBUG]: pid %5d : stopped by signal SIGTRAP\n", pid); 462 | handle_trapped_event(pid, wstatus); 463 | handle_syscall_info(pid, wstatus); 464 | break; 465 | case SIGKILL: 466 | printf("[TRACE INFO]: pid %5d : stopped by signal SIGKILL\n", pid); 467 | break; 468 | case SIGPIPE: 469 | printf("[TRACE INFO]: pid %5d : stopped by signal SIGPIPE\n", pid); 470 | break; 471 | case SIGALRM: 472 | printf("[TRACE INFO]: pid %5d : stopped by signal SIGALRM\n", pid); 473 | break; 474 | case SIGPOLL: 475 | printf("[TRACE INFO]: pid %5d : stopped by signal SIGPOLL\n", pid); 476 | break; 477 | case SIGCHLD: 478 | DPRINTF("[TRACE DEBUG]: pid %5d : stopped by signal SIGCHLD\n", pid); 479 | break; 480 | case SIGSTKFLT: 481 | printf("[TRACE INFO]: pid %5d : stopped by signal SIGSTKFLT\n", pid); 482 | break; 483 | case SIGPWR: 484 | printf("[TRACE INFO]: pid %5d : stopped by signal SIGPWR\n", pid); 485 | break; 486 | case SIGBUS: 487 | printf("[TRACE INFO]: pid %5d : stopped by signal SIGBUS\n", pid); 488 | break; 489 | case SIGSYS: 490 | printf("[TRACE INFO]: pid %5d : stopped by signal SIGSYS\n", pid); 491 | break; 492 | case SIGURG: 493 | printf("[TRACE INFO]: pid %5d : stopped by signal SIGURG\n", pid); 494 | break; 495 | case SIGSTOP: 496 | DPRINTF("[TRACE DEBUG]: pid %5d : stopped by signal SIGSTOP\n", pid); 497 | break; 498 | case SIGTSTP: 499 | printf("[TRACE INFO]: pid %5d : stopped by signal SIGTSTP\n", pid); 500 | break; 501 | case SIGCONT: 502 | printf("[TRACE INFO]: pid %5d : stopped by signal SIGCONT\n", pid); 503 | break; 504 | case SIGTTIN: 505 | printf("[TRACE INFO]: pid %5d : stopped by signal SIGTTIN\n", pid); 506 | break; 507 | case SIGTTOU: 508 | printf("[TRACE INFO]: pid %5d : stopped by signal SIGTTOU\n", pid); 509 | break; 510 | case SIGXFSZ: 511 | printf("[TRACE INFO]: pid %5d : stopped by signal SIGXFSZ\n", pid); 512 | break; 513 | case SIGXCPU: 514 | printf("[TRACE INFO]: pid %5d : stopped by signal SIGXCPU\n", pid); 515 | break; 516 | case SIGVTALRM: 517 | printf("[TRACE INFO]: pid %5d : stopped by signal SIGVTALRM\n", pid); 518 | break; 519 | case SIGPROF: 520 | printf("[TRACE INFO]: pid %5d : stopped by signal SIGPROF\n", pid); 521 | break; 522 | case SIGUSR1: 523 | printf("[TRACE INFO]: pid %5d : stopped by signal SIGUSR1\n", pid); 524 | break; 525 | case SIGUSR2: 526 | printf("[TRACE INFO]: pid %5d : stopped by signal SIGUSR2\n", pid); 527 | break; 528 | case SIGWINCH: 529 | printf("[TRACE INFO]: pid %5d : stopped by signal SIGWINCH\n", pid); 530 | break; 531 | case SIGTRAP | 0x80: 532 | /** 533 | * From ptrace(2), setting PTRACE_O_TRACESYSGOOD has the effect 534 | * of delivering SIGTRAP | 0x80 as the signal number for syscall 535 | * stops. This allows easily distinguishing syscall stops from 536 | * genuine SIGTRAP signals. 537 | **/ 538 | DPRINTF("[TRACE DEBUG]: pid %5d : stopped by signal SIGTRAP|0x80\n", pid); 539 | handle_trapped_event(pid, wstatus); 540 | handle_syscall_info(pid, wstatus); 541 | break; 542 | default: 543 | fprintf(stderr, "[TRACE ERROR]: pid %5d : stopped by unknown signal %d (%#x)\n", pid, 544 | WSTOPSIG(wstatus), WSTOPSIG(wstatus)); 545 | break; 546 | } 547 | 548 | return 0; 549 | } 550 | 551 | int handle_killed_signal(int pid, int wstatus) 552 | { 553 | switch (WTERMSIG(wstatus)) 554 | { 555 | case SIGINT: 556 | fprintf(stderr, "[TRACE ERROR]: pid %5d : killed by signal SIGINT\n", pid); 557 | break; 558 | case SIGILL: 559 | fprintf(stderr, "[TRACE ERROR]: pid %5d : killed by signal SIGILL\n", pid); 560 | break; 561 | case SIGABRT: 562 | fprintf(stderr, "[TRACE ERROR]: pid %5d : killed by signal SIGABRT\n", pid); 563 | break; 564 | case SIGFPE: 565 | fprintf(stderr, "[TRACE ERROR]: pid %5d : killed by signal SIGFPE\n", pid); 566 | break; 567 | case SIGSEGV: 568 | fprintf(stderr, "[TRACE ERROR]: pid %5d : killed by signal SIGSEGV\n", pid); 569 | break; 570 | case SIGTERM: 571 | fprintf(stderr, "[TRACE ERROR]: pid %5d : killed by signal SIGTERM\n", pid); 572 | break; 573 | case SIGHUP: 574 | fprintf(stderr, "[TRACE ERROR]: pid %5d : killed by signal SIGHUP\n", pid); 575 | break; 576 | case SIGQUIT: 577 | fprintf(stderr, "[TRACE ERROR]: pid %5d : killed by signal SIGQUIT\n", pid); 578 | break; 579 | case SIGTRAP: 580 | fprintf(stderr, "[TRACE ERROR]: pid %5d : killed by signal SIGTRAP\n", pid); 581 | break; 582 | case SIGKILL: 583 | fprintf(stderr, "[TRACE ERROR]: pid %5d : killed by signal SIGKILL\n", pid); 584 | break; 585 | case SIGPIPE: 586 | fprintf(stderr, "[TRACE ERROR]: pid %5d : killed by signal SIGPIPE\n", pid); 587 | break; 588 | case SIGALRM: 589 | fprintf(stderr, "[TRACE ERROR]: pid %5d : killed by signal SIGALRM\n", pid); 590 | break; 591 | case SIGPOLL: 592 | fprintf(stderr, "[TRACE ERROR]: pid %5d : killed by signal SIGPOLL\n", pid); 593 | break; 594 | case SIGCHLD: 595 | fprintf(stderr, "[TRACE ERROR]: pid %5d : killed by signal SIGCHLD\n", pid); 596 | break; 597 | case SIGSTKFLT: 598 | fprintf(stderr, "[TRACE ERROR]: pid %5d : killed by signal SIGSTKFLT\n", pid); 599 | break; 600 | case SIGPWR: 601 | fprintf(stderr, "[TRACE ERROR]: pid %5d : killed by signal SIGPWR\n", pid); 602 | break; 603 | case SIGBUS: 604 | fprintf(stderr, "[TRACE ERROR]: pid %5d : killed by signal SIGBUS\n", pid); 605 | break; 606 | case SIGSYS: 607 | fprintf(stderr, "[TRACE ERROR]: pid %5d : killed by signal SIGSYS\n", pid); 608 | break; 609 | case SIGURG: 610 | fprintf(stderr, "[TRACE ERROR]: pid %5d : killed by signal SIGURG\n", pid); 611 | break; 612 | case SIGSTOP: 613 | fprintf(stderr, "[TRACE ERROR]: pid %5d : killed by signal SIGSTOP\n", pid); 614 | break; 615 | case SIGTSTP: 616 | fprintf(stderr, "[TRACE ERROR]: pid %5d : killed by signal SIGTSTP\n", pid); 617 | break; 618 | case SIGCONT: 619 | fprintf(stderr, "[TRACE ERROR]: pid %5d : killed by signal SIGCONT\n", pid); 620 | break; 621 | case SIGTTIN: 622 | fprintf(stderr, "[TRACE ERROR]: pid %5d : killed by signal SIGTTIN\n", pid); 623 | break; 624 | case SIGTTOU: 625 | fprintf(stderr, "[TRACE ERROR]: pid %5d : killed by signal SIGTTOU\n", pid); 626 | break; 627 | case SIGXFSZ: 628 | fprintf(stderr, "[TRACE ERROR]: pid %5d : killed by signal SIGXFSZ\n", pid); 629 | break; 630 | case SIGXCPU: 631 | fprintf(stderr, "[TRACE ERROR]: pid %5d : killed by signal SIGXCPU\n", pid); 632 | break; 633 | case SIGVTALRM: 634 | fprintf(stderr, "[TRACE ERROR]: pid %5d : killed by signal SIGVTALRM\n", pid); 635 | break; 636 | case SIGPROF: 637 | fprintf(stderr, "[TRACE ERROR]: pid %5d : killed by signal SIGPROF\n", pid); 638 | break; 639 | case SIGUSR1: 640 | fprintf(stderr, "[TRACE ERROR]: pid %5d : killed by signal SIGUSR1\n", pid); 641 | break; 642 | case SIGUSR2: 643 | fprintf(stderr, "[TRACE ERROR]: pid %5d : killed by signal SIGUSR2\n", pid); 644 | break; 645 | case SIGWINCH: 646 | fprintf(stderr, "[TRACE ERROR]: pid %5d : killed by signal SIGWINCH\n", pid); 647 | break; 648 | default: 649 | fprintf(stderr, "[TRACE ERROR]: pid %5d : killed by signal %d (%#x)\n", pid, WTERMSIG(wstatus), WTERMSIG(wstatus)); 650 | break; 651 | } 652 | return 0; 653 | } 654 | 655 | int main(int argc, char **argv) 656 | { 657 | int pid, wstatus, i, result; 658 | char *result_ptr; 659 | int newpid; 660 | #define MAXPATH 0x1000 661 | char *path_buf, *path; 662 | size_t point_max = 0x400, point_count = 0; 663 | char **point; 664 | 665 | check_tty(); 666 | setlinebuf(stdout); 667 | 668 | if (argc < 2) 669 | { 670 | printf("Usage: %s command\n", argv[0]); 671 | exit(EXIT_SUCCESS); 672 | } 673 | 674 | path_buf = malloc(MAXPATH); 675 | CHECK(path_buf != NULL); 676 | path = malloc(MAXPATH); 677 | CHECK(path != NULL); 678 | 679 | CHECK((pid = fork()) != -1); 680 | 681 | // Child process 682 | if (pid == 0) 683 | { 684 | CHECK(prctl(PR_SET_PTRACER, getppid()) != -1); 685 | raise(SIGSTOP); 686 | 687 | DPRINTF("[TRACE DEBUG]: Child pid %d\n", getpid()); 688 | return execve_with_args(argv + 1); 689 | } 690 | 691 | point = malloc(sizeof(char *) * point_max); 692 | CHECK(point != NULL); 693 | 694 | CHECK(ptrace(PTRACE_SEIZE, pid, NULL, 695 | PTRACE_O_EXITKILL | PTRACE_O_TRACESYSGOOD | 696 | PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK | 697 | PTRACE_O_TRACECLONE | PTRACE_O_TRACEEXEC | 698 | PTRACE_O_TRACEEXIT) != -1); 699 | 700 | for (wstatus = 0; pid != -1; wstatus = 0) 701 | { 702 | if(ptrace(PTRACE_SYSCALL, pid, 0, 0) == -1) 703 | { 704 | // Wait 705 | CHECK(errno == ESRCH); 706 | } 707 | 708 | pid = wait(&wstatus); 709 | 710 | if (WIFEXITED(wstatus)) 711 | { 712 | DPRINTF("[TRACE DEBUG]: pid %5d : exited, status=%d\n", pid, WEXITSTATUS(wstatus)); 713 | } 714 | else if (WIFSIGNALED(wstatus)) 715 | { 716 | handle_killed_signal(pid, wstatus); 717 | } 718 | else if (WIFSTOPPED(wstatus)) 719 | { 720 | handle_stopped_signal(pid, wstatus); 721 | } 722 | else if (WIFCONTINUED(wstatus)) 723 | { 724 | DPRINTF("[TRACE DEBUG]: pid %5d : continued\n", pid); 725 | } 726 | } 727 | 728 | return 0; 729 | } 730 | --------------------------------------------------------------------------------