├── .gitignore ├── Examples ├── basic │ ├── a.out │ ├── ctf_import.c │ ├── ctf_import.h │ ├── example.c │ └── fib.c └── lost_decryption │ ├── cipher │ ├── ctf_import.c │ ├── ctf_import.h │ ├── flag.enc │ ├── key.bin │ ├── libencrypt.so │ └── lost.c ├── README.md ├── ctf_import.c └── ctf_import.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Libraries 12 | *.lib 13 | *.a 14 | *.la 15 | *.lo 16 | 17 | # Shared objects (inc. Windows DLLs) 18 | *.dll 19 | *.so 20 | *.so.* 21 | *.dylib 22 | 23 | # Executables 24 | *.exe 25 | *.out 26 | *.app 27 | *.i*86 28 | *.x86_64 29 | *.hex 30 | 31 | # Debug files 32 | *.dSYM/ 33 | *.su 34 | 35 | .DS_Store -------------------------------------------------------------------------------- /Examples/basic/a.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sciencemanx/ctf_import/127e2aa7cab80039ab7ed7212cfadafe27dc4497/Examples/basic/a.out -------------------------------------------------------------------------------- /Examples/basic/ctf_import.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | struct binary { 11 | char *name; 12 | uint8_t *code; 13 | struct binary *next; 14 | }; 15 | 16 | struct binary *binaries; 17 | 18 | void error(char *msg) { 19 | puts(msg); 20 | exit(1); 21 | } 22 | 23 | uint8_t *load_file(char *file) { 24 | struct stat st; 25 | int fd; 26 | uint8_t *mem; 27 | 28 | fd = open(file, O_RDONLY); 29 | if (fd == -1) { 30 | if (errno == ENOENT) error("the binary you requested does not exist"); 31 | error("an error occured opening the binary"); 32 | } 33 | fstat(fd, &st); 34 | 35 | return mmap(NULL, st.st_size, PROT_EXEC, MAP_PRIVATE, fd, 0); 36 | } 37 | 38 | struct binary *get_binary(char *name) { 39 | struct binary *b; 40 | 41 | b = binaries; 42 | while (b != NULL && strcmp(name, b->name) != 0) b = b->next; 43 | return b; 44 | } 45 | 46 | void add_binary(struct binary *b) { 47 | b->next = binaries; 48 | binaries = b; 49 | } 50 | 51 | struct binary *new_binary(char *name) { 52 | struct binary *b; 53 | 54 | b = malloc(sizeof(*b)); 55 | b->name = name; 56 | b->code = load_file(name); 57 | b->next = NULL; 58 | 59 | return b; 60 | } 61 | 62 | void *import(char *file, size_t offset) { 63 | struct binary *b; 64 | 65 | b = get_binary(file); 66 | 67 | if (b == NULL) { 68 | b = new_binary(file); 69 | add_binary(b); 70 | } 71 | 72 | return &b->code[offset]; 73 | } -------------------------------------------------------------------------------- /Examples/basic/ctf_import.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // returns a generic function pointer to the offset within the binary 4 | void *import(char *file, size_t offset); -------------------------------------------------------------------------------- /Examples/basic/example.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "ctf_import.h" 4 | 5 | 6 | int main() { 7 | int (* fib)(int); 8 | 9 | // a.out is a binary with a fibonacci function at offset 0xf00 10 | fib = (int (*)(int)) import("a.out", 0xf00); 11 | 12 | printf("%d %d %d %d %d\n", fib(1), fib(2), fib(3), fib(4), fib(5)); 13 | } -------------------------------------------------------------------------------- /Examples/basic/fib.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int fib(int n) { 4 | int a,b,tmp; 5 | 6 | a = 0; 7 | b = 1; 8 | 9 | for (; n > 0; n--) { 10 | tmp = b; 11 | b = a + b; 12 | a = tmp; 13 | } 14 | 15 | return a; 16 | } 17 | 18 | int main() { 19 | printf("nothing to see here!\n"); 20 | return 0; 21 | } -------------------------------------------------------------------------------- /Examples/lost_decryption/cipher: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sciencemanx/ctf_import/127e2aa7cab80039ab7ed7212cfadafe27dc4497/Examples/lost_decryption/cipher -------------------------------------------------------------------------------- /Examples/lost_decryption/ctf_import.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | struct binary { 11 | char *name; 12 | uint8_t *code; 13 | struct binary *next; 14 | }; 15 | 16 | struct binary *binaries; 17 | 18 | void error(char *msg) { 19 | puts(msg); 20 | exit(1); 21 | } 22 | 23 | uint8_t *load_file(char *file) { 24 | struct stat st; 25 | int fd; 26 | uint8_t *mem; 27 | 28 | fd = open(file, O_RDONLY); 29 | if (fd == -1) { 30 | if (errno == ENOENT) error("the binary you requested does not exist"); 31 | error("an error occured opening the binary"); 32 | } 33 | fstat(fd, &st); 34 | 35 | return mmap(NULL, st.st_size, PROT_EXEC, MAP_PRIVATE, fd, 0); 36 | } 37 | 38 | struct binary *get_binary(char *name) { 39 | struct binary *b; 40 | 41 | b = binaries; 42 | while (b != NULL && strcmp(name, b->name) != 0) b = b->next; 43 | return b; 44 | } 45 | 46 | void add_binary(struct binary *b) { 47 | b->next = binaries; 48 | binaries = b; 49 | } 50 | 51 | struct binary *new_binary(char *name) { 52 | struct binary *b; 53 | 54 | b = malloc(sizeof(*b)); 55 | b->name = name; 56 | b->code = load_file(name); 57 | b->next = NULL; 58 | 59 | return b; 60 | } 61 | 62 | void *import(char *file, size_t offset) { 63 | struct binary *b; 64 | 65 | b = get_binary(file); 66 | 67 | if (b == NULL) { 68 | b = new_binary(file); 69 | add_binary(b); 70 | } 71 | 72 | return &b->code[offset]; 73 | } -------------------------------------------------------------------------------- /Examples/lost_decryption/ctf_import.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // returns a generic function pointer to the offset within the binary 4 | void *import(char *file, size_t offset); -------------------------------------------------------------------------------- /Examples/lost_decryption/flag.enc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sciencemanx/ctf_import/127e2aa7cab80039ab7ed7212cfadafe27dc4497/Examples/lost_decryption/flag.enc -------------------------------------------------------------------------------- /Examples/lost_decryption/key.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sciencemanx/ctf_import/127e2aa7cab80039ab7ed7212cfadafe27dc4497/Examples/lost_decryption/key.bin -------------------------------------------------------------------------------- /Examples/lost_decryption/libencrypt.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sciencemanx/ctf_import/127e2aa7cab80039ab7ed7212cfadafe27dc4497/Examples/lost_decryption/libencrypt.so -------------------------------------------------------------------------------- /Examples/lost_decryption/lost.c: -------------------------------------------------------------------------------- 1 | // Author: Adam Van Prooyen [@docileninja, @scienceman] 2 | // Solution for SECCON 'Lost Decryption'; requires key.bin, flag.enc, and 3 | // libencrypt.so in the same directory. 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "ctf_import.h" 13 | 14 | #define ROUNDS 14 15 | 16 | uint64_t (* f)(uint64_t, uint64_t); // round function for the fiestel network 17 | 18 | uint64_t keys[ROUNDS]; // key schedule for decryption (reverse of encryption schedule) 19 | uint64_t c = 0x9104F95DE694DC50; // constant from binary for generating next key 20 | 21 | void swap(uint64_t *a, uint64_t *b) { 22 | uint64_t tmp = *a; 23 | *a = *b; 24 | *b = tmp; 25 | } 26 | 27 | void load_keys(uint64_t *k_L1, uint64_t *k_R1) { 28 | int fd; 29 | char buf[16]; 30 | 31 | fd = open("key.bin", O_RDONLY); 32 | read(fd, buf, 16); 33 | 34 | *k_L1 = *(uint64_t *) buf; 35 | *k_R1 = *((uint64_t *) buf + 1); 36 | } 37 | 38 | void load_ct(char ct[48]) { 39 | int fd; 40 | 41 | fd = open("flag.enc", O_RDONLY); 42 | 43 | read(fd, ct, 48); 44 | } 45 | 46 | void gen_keys(uint64_t k_L, uint64_t k_R) { 47 | int i; 48 | 49 | for (i = 0; i < ROUNDS; i++) { 50 | keys[ROUNDS - i - 1] = k_R; 51 | k_R = f(k_R, c); 52 | swap(&k_L, &k_R); 53 | } 54 | } 55 | 56 | void decrypt(char *ct) { 57 | uint64_t k_n, L, R; 58 | int i; 59 | 60 | L = *(uint64_t *) ct; 61 | R = *((uint64_t *) ct + 1); 62 | for (i = 0; i < ROUNDS; i++) { 63 | k_n = keys[i]; 64 | L ^= f(R, k_n); 65 | swap(&L, &R); 66 | } 67 | *(uint64_t *) ct = L; 68 | *((uint64_t *) ct + 1) = R; 69 | } 70 | 71 | int main() { 72 | int i; 73 | uint64_t k_L1, k_R1; 74 | char ct[49]; 75 | 76 | f = (uint64_t (*)(uint64_t, uint64_t)) import("libencrypt.so", 0x700); 77 | load_ct(ct); 78 | load_keys(&k_L1, &k_R1); 79 | gen_keys(k_L1, k_R1); 80 | 81 | printf("k_L1: %016llx k_R1: %016llx\n", k_L1, k_R1); 82 | printf("keys:\n"); 83 | for (i = 0; i < ROUNDS; i++) { 84 | printf(" %2d: %016llx\n", i+1, keys[i]); 85 | } 86 | 87 | for (i = 0; i < 3; i++) { 88 | decrypt(&ct[i * 16]); 89 | } 90 | ct[48] = 0; 91 | printf("Flag: %s\n", ct); 92 | 93 | return 0; 94 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ctf_import 2 | 3 | > A small library that allows you to run basic functions from stripped binaries cross platform 4 | 5 | [Website](http://van.prooyen.com/projects/#ctfimport) 6 | 7 | ## Usage 8 | 9 | This library is designed for you to be able to quickly call functions from a stripped binary. All you need is the file name, the function offset, and the function signature. You can get these by reverse engineering the binary in IDA or Binary Ninja. 10 | 11 | > void *import(char *file, size_t offset) 12 | 13 | ``` c 14 | #include "ctf_import.h" 15 | 16 | int main() { 17 | int (* fib)(int); 18 | 19 | // a.out is a binary with a fibonacci function at offset 0xf00 20 | fib = (int (*)(int)) import("a.out", 0xf00); 21 | 22 | printf("%d %d %d %d %d\n", fib(1), fib(2), fib(3), fib(4), fib(5)); 23 | } 24 | ``` 25 | 26 | To compile: 27 | 28 | ``` bash 29 | $ gcc example.c ctf_import.c -o example 30 | $ ./example 31 | > 1 1 2 3 5 32 | ``` 33 | 34 | ## Notes 35 | 36 | Although the code will run "cross-OS", it will not run cross architecture. Additionally, this does not handle syscalls and anything that interacts with globals. -------------------------------------------------------------------------------- /ctf_import.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | struct binary { 11 | char *name; 12 | uint8_t *code; 13 | struct binary *next; 14 | }; 15 | 16 | struct binary *binaries; 17 | 18 | void error(char *msg) { 19 | puts(msg); 20 | exit(1); 21 | } 22 | 23 | uint8_t *load_file(char *file) { 24 | struct stat st; 25 | int fd; 26 | uint8_t *mem; 27 | 28 | fd = open(file, O_RDONLY); 29 | if (fd == -1) { 30 | if (errno == ENOENT) error("the binary you requested does not exist"); 31 | error("an error occured opening the binary"); 32 | } 33 | fstat(fd, &st); 34 | 35 | return mmap(NULL, st.st_size, PROT_EXEC, MAP_PRIVATE, fd, 0); 36 | } 37 | 38 | struct binary *get_binary(char *name) { 39 | struct binary *b; 40 | 41 | b = binaries; 42 | while (b != NULL && strcmp(name, b->name) != 0) b = b->next; 43 | return b; 44 | } 45 | 46 | void add_binary(struct binary *b) { 47 | b->next = binaries; 48 | binaries = b; 49 | } 50 | 51 | struct binary *new_binary(char *name) { 52 | struct binary *b; 53 | 54 | b = malloc(sizeof(*b)); 55 | b->name = name; 56 | b->code = load_file(name); 57 | b->next = NULL; 58 | 59 | return b; 60 | } 61 | 62 | void *import(char *file, size_t offset) { 63 | struct binary *b; 64 | 65 | b = get_binary(file); 66 | 67 | if (b == NULL) { 68 | b = new_binary(file); 69 | add_binary(b); 70 | } 71 | 72 | return &b->code[offset]; 73 | } -------------------------------------------------------------------------------- /ctf_import.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // returns a generic function pointer to the offset within the binary 4 | void *import(char *file, size_t offset); --------------------------------------------------------------------------------