diff --git a/generation.c b/generation.c index e0ea3d3..65b0632 100644 --- a/generation.c +++ b/generation.c @@ -1,128 +1,69 @@ +/* +@file generation.c +*/ #include #include -#include -#include #include #include #include -int reproduce(unsigned char *pic_address, int pic_size) +int reproduce(void *pic_address, int *pic_size) { - int return_value = 0; + int status = 0; - for (int iter = 0; iter < pic_size; iter++) - { - printf("%02X", pic_address[iter]); - } + printf("{\"address\": \"%p\",\"length\": \"%d\"}\n", pic_address, + *pic_size); - return_value = 1; + status = 1; CLONE_CLEANUP: - if (NULL != pic_address) - { - munmap(pic_address, pic_size); - } - exit(0); + return status; } -int hex_ascii_to_bin(char *hex_string, int hex_len, unsigned char *hex_bin) +int generation(void *child, int *child_len) { - if (hex_bin == NULL || hex_string == NULL || hex_len % 2 != 0) - { - return 0; - } - - char *position = hex_string; - - for (int index = 0; index - 1 < hex_len; index++) - { - if (*position == NULL) break; - - for (int offset = 0; offset < 2; offset++, position++) - { - unsigned char hex_sort = *position | 0x20; - - if (hex_sort >= '0' && hex_sort <= '9') - { - hex_sort -= 0x30; - } - else if (hex_sort <= 'f' && hex_sort >= 'a') - { - hex_sort -= 0x57; - } - else - { - return 0; - } - if (!offset) - { - hex_bin[index] = (hex_sort << 4); - } - else - { - hex_bin[index] |= hex_sort; - } - } - } - - return 1; -} - -int generation(char *parent_hex, int rand_offset, char rand_flip) -{ - int return_value = 0; - int parent_hex_len = strlen(parent_hex); - int parent_bin_len = parent_hex_len / 2; + int status = 0; int prot = (PROT_READ | PROT_WRITE | PROT_EXEC); int flags = (MAP_ANON | MAP_PRIVATE); - unsigned char *pic_buffer = mmap(NULL, parent_bin_len, prot, flags, -1, 0); + void *pic_buffer = mmap(NULL, child_len, prot, flags, -1, 0); + if (MAP_FAILED == pic_buffer) { - return_value = errno; + status = errno; goto GEN_CLEANUP; } - hex_ascii_to_bin(parent_hex, parent_hex_len, pic_buffer); + memcpy(child, pic_buffer, *child_len); - pic_buffer[rand_offset] = pic_buffer[rand_offset] ^ rand_flip; + int (*reproduce_function)(void *, int) = reproduce; + void (*pic_function)(void *, int *, void *) = pic_buffer; - int (*reproduce_function)(unsigned char *, int) = reproduce; - void (*pic_function)(void *, int, void *) = pic_buffer; + pic_function(pic_buffer, child_len, reproduce_function); - pic_function(pic_buffer, parent_bin_len, reproduce_function); - - return_value = 1; + status = 1; GEN_CLEANUP: - if (NULL != pic_buffer) - { - munmap(pic_buffer, parent_bin_len); - } - return return_value; + return status; } -int main(int argc, const char **argv) +int gen_fork(void *child, int *child_len) { - if (3 > argc || argv[1] == NULL || argv[2] == NULL || argv[3] == NULL) - { - exit(1); - } - - char *hex_string = argv[1]; - int rand_offset = atoi(argv[2]); - char rand_flip = atoi(argv[3]); pid_t process_id; - int return_value = 0; + int status = 0; + + *child_len = 999; + + return 0; process_id = fork(); - if(0 == process_id) + if (0 == process_id) { - return_value = generation(hex_string, rand_offset, rand_flip); - if (return_value) + status = generation(child, child_len); + if (status) { - exit(0); + return 0; } } diff --git a/list.h b/list.h deleted file mode 100644 index 850f8c8..0000000 --- a/list.h +++ /dev/null @@ -1,517 +0,0 @@ -/** - * - * I grub it from linux kernel source code and fix it for user space - * program. Of course, this is a GPL licensed header file. - * - * Here is a recipe to cook list.h for user space program - * - * 1. copy list.h from linux/include/list.h - * 2. remove - * - #ifdef __KERNE__ and its #endif - * - all #include line - * - prefetch() and rcu related functions - * 3. add macro offsetof() and container_of - * - * - kazutomo@mcs.anl.gov - */ -#ifndef _LINUX_LIST_H -#define _LINUX_LIST_H - -/** - * @name from other kernel headers - */ -/*@{*/ - -/** - * Get offset of a member - */ -#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) - -/** - * Casts a member of a structure out to the containing structure - * @param ptr the pointer to the member. - * @param type the type of the container struct this is embedded in. - * @param member the name of the member within the struct. - * - */ -#define container_of(ptr, type, member) ({ \ - const typeof( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) -/*@}*/ - - -/* - * These are non-NULL pointers that will result in page faults - * under normal circumstances, used to verify that nobody uses - * non-initialized list entries. - */ -#define LIST_POISON1 ((void *) 0x00100100) -#define LIST_POISON2 ((void *) 0x00200200) - -/** - * Simple doubly linked list implementation. - * - * Some of the internal functions ("__xxx") are useful when - * manipulating whole lists rather than single entries, as - * sometimes we already know the next/prev entries and we can - * generate better code by using them directly rather than - * using the generic single-entry routines. - */ -struct list_head { - struct list_head *next, *prev; -}; - -#define LIST_HEAD_INIT(name) { &(name), &(name) } - -#define LIST_HEAD(name) \ - struct list_head name = LIST_HEAD_INIT(name) - -#define INIT_LIST_HEAD(ptr) do { \ - (ptr)->next = (ptr); (ptr)->prev = (ptr); \ -} while (0) - -/* - * Insert a new entry between two known consecutive entries. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -static inline void __list_add(struct list_head *new, - struct list_head *prev, - struct list_head *next) -{ - next->prev = new; - new->next = next; - new->prev = prev; - prev->next = new; -} - -/** - * list_add - add a new entry - * @new: new entry to be added - * @head: list head to add it after - * - * Insert a new entry after the specified head. - * This is good for implementing stacks. - */ -static inline void list_add(struct list_head *new, struct list_head *head) -{ - __list_add(new, head, head->next); -} - -/** - * list_add_tail - add a new entry - * @new: new entry to be added - * @head: list head to add it before - * - * Insert a new entry before the specified head. - * This is useful for implementing queues. - */ -static inline void list_add_tail(struct list_head *new, struct list_head *head) -{ - __list_add(new, head->prev, head); -} - - -/* - * Delete a list entry by making the prev/next entries - * point to each other. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -static inline void __list_del(struct list_head * prev, struct list_head * next) -{ - next->prev = prev; - prev->next = next; -} - -/** - * list_del - deletes entry from list. - * @entry: the element to delete from the list. - * Note: list_empty on entry does not return true after this, the entry is - * in an undefined state. - */ -static inline void list_del(struct list_head *entry) -{ - __list_del(entry->prev, entry->next); - entry->next = LIST_POISON1; - entry->prev = LIST_POISON2; -} - - - -/** - * list_del_init - deletes entry from list and reinitialize it. - * @entry: the element to delete from the list. - */ -static inline void list_del_init(struct list_head *entry) -{ - __list_del(entry->prev, entry->next); - INIT_LIST_HEAD(entry); -} - -/** - * list_move - delete from one list and add as another's head - * @list: the entry to move - * @head: the head that will precede our entry - */ -static inline void list_move(struct list_head *list, struct list_head *head) -{ - __list_del(list->prev, list->next); - list_add(list, head); -} - -/** - * list_move_tail - delete from one list and add as another's tail - * @list: the entry to move - * @head: the head that will follow our entry - */ -static inline void list_move_tail(struct list_head *list, - struct list_head *head) -{ - __list_del(list->prev, list->next); - list_add_tail(list, head); -} - -/** - * list_empty - tests whether a list is empty - * @head: the list to test. - */ -static inline int list_empty(const struct list_head *head) -{ - return head->next == head; -} - -static inline void __list_splice(struct list_head *list, - struct list_head *head) -{ - struct list_head *first = list->next; - struct list_head *last = list->prev; - struct list_head *at = head->next; - - first->prev = head; - head->next = first; - - last->next = at; - at->prev = last; -} - -/** - * list_splice - join two lists - * @list: the new list to add. - * @head: the place to add it in the first list. - */ -static inline void list_splice(struct list_head *list, struct list_head *head) -{ - if (!list_empty(list)) - __list_splice(list, head); -} - -/** - * list_splice_init - join two lists and reinitialise the emptied list. - * @list: the new list to add. - * @head: the place to add it in the first list. - * - * The list at @list is reinitialised - */ -static inline void list_splice_init(struct list_head *list, - struct list_head *head) -{ - if (!list_empty(list)) { - __list_splice(list, head); - INIT_LIST_HEAD(list); - } -} - -/** - * list_entry - get the struct for this entry - * @ptr: the &struct list_head pointer. - * @type: the type of the struct this is embedded in. - * @member: the name of the list_struct within the struct. - */ -#define list_entry(ptr, type, member) \ - container_of(ptr, type, member) - -/** - * list_for_each - iterate over a list - * @pos: the &struct list_head to use as a loop counter. - * @head: the head for your list. - */ - -#define list_for_each(pos, head) \ - for (pos = (head)->next; pos != (head); \ - pos = pos->next) - -/** - * __list_for_each - iterate over a list - * @pos: the &struct list_head to use as a loop counter. - * @head: the head for your list. - * - * This variant differs from list_for_each() in that it's the - * simplest possible list iteration code, no prefetching is done. - * Use this for code that knows the list to be very short (empty - * or 1 entry) most of the time. - */ -#define __list_for_each(pos, head) \ - for (pos = (head)->next; pos != (head); pos = pos->next) - -/** - * list_for_each_prev - iterate over a list backwards - * @pos: the &struct list_head to use as a loop counter. - * @head: the head for your list. - */ -#define list_for_each_prev(pos, head) \ - for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \ - pos = pos->prev) - -/** - * list_for_each_safe - iterate over a list safe against removal of list entry - * @pos: the &struct list_head to use as a loop counter. - * @n: another &struct list_head to use as temporary storage - * @head: the head for your list. - */ -#define list_for_each_safe(pos, n, head) \ - for (pos = (head)->next, n = pos->next; pos != (head); \ - pos = n, n = pos->next) - -/** - * list_for_each_entry - iterate over list of given type - * @pos: the type * to use as a loop counter. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry(pos, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) - -/** - * list_for_each_entry_reverse - iterate backwards over list of given type. - * @pos: the type * to use as a loop counter. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry_reverse(pos, head, member) \ - for (pos = list_entry((head)->prev, typeof(*pos), member); \ - &pos->member != (head); \ - pos = list_entry(pos->member.prev, typeof(*pos), member)) - -/** - * list_prepare_entry - prepare a pos entry for use as a start point in - * list_for_each_entry_continue - * @pos: the type * to use as a start point - * @head: the head of the list - * @member: the name of the list_struct within the struct. - */ -#define list_prepare_entry(pos, head, member) \ - ((pos) ? : list_entry(head, typeof(*pos), member)) - -/** - * list_for_each_entry_continue - iterate over list of given type - * continuing after existing point - * @pos: the type * to use as a loop counter. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry_continue(pos, head, member) \ - for (pos = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) - -/** - * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry - * @pos: the type * to use as a loop counter. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry_safe(pos, n, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member), \ - n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/** - * list_for_each_entry_safe_continue - iterate over list of given type - * continuing after existing point safe against removal of list entry - * @pos: the type * to use as a loop counter. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry_safe_continue(pos, n, head, member) \ - for (pos = list_entry(pos->member.next, typeof(*pos), member), \ - n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/** - * list_for_each_entry_safe_reverse - iterate backwards over list of given type safe against - * removal of list entry - * @pos: the type * to use as a loop counter. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry_safe_reverse(pos, n, head, member) \ - for (pos = list_entry((head)->prev, typeof(*pos), member), \ - n = list_entry(pos->member.prev, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.prev, typeof(*n), member)) - - - - -/* - * Double linked lists with a single pointer list head. - * Mostly useful for hash tables where the two pointer list head is - * too wasteful. - * You lose the ability to access the tail in O(1). - */ - -struct hlist_head { - struct hlist_node *first; -}; - -struct hlist_node { - struct hlist_node *next, **pprev; -}; - -#define HLIST_HEAD_INIT { .first = NULL } -#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL } -#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) -#define INIT_HLIST_NODE(ptr) ((ptr)->next = NULL, (ptr)->pprev = NULL) - -static inline int hlist_unhashed(const struct hlist_node *h) -{ - return !h->pprev; -} - -static inline int hlist_empty(const struct hlist_head *h) -{ - return !h->first; -} - -static inline void __hlist_del(struct hlist_node *n) -{ - struct hlist_node *next = n->next; - struct hlist_node **pprev = n->pprev; - *pprev = next; - if (next) - next->pprev = pprev; -} - -static inline void hlist_del(struct hlist_node *n) -{ - __hlist_del(n); - n->next = LIST_POISON1; - n->pprev = LIST_POISON2; -} - - -static inline void hlist_del_init(struct hlist_node *n) -{ - if (n->pprev) { - __hlist_del(n); - INIT_HLIST_NODE(n); - } -} - -static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) -{ - struct hlist_node *first = h->first; - n->next = first; - if (first) - first->pprev = &n->next; - h->first = n; - n->pprev = &h->first; -} - - - -/* next must be != NULL */ -static inline void hlist_add_before(struct hlist_node *n, - struct hlist_node *next) -{ - n->pprev = next->pprev; - n->next = next; - next->pprev = &n->next; - *(n->pprev) = n; -} - -static inline void hlist_add_after(struct hlist_node *n, - struct hlist_node *next) -{ - next->next = n->next; - n->next = next; - next->pprev = &n->next; - - if(next->next) - next->next->pprev = &next->next; -} - - - -#define hlist_entry(ptr, type, member) container_of(ptr,type,member) - -#define hlist_for_each(pos, head) \ - for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \ - pos = pos->next) - -#define hlist_for_each_safe(pos, n, head) \ - for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \ - pos = n) - -/** - * hlist_for_each_entry - iterate over list of given type - * @tpos: the type * to use as a loop counter. - * @pos: the &struct hlist_node to use as a loop counter. - * @head: the head for your list. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry(tpos, pos, head, member) \ - for (pos = (head)->first; \ - pos && ({ prefetch(pos->next); 1;}) && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ - pos = pos->next) - -/** - * hlist_for_each_entry_continue - iterate over a hlist continuing after existing point - * @tpos: the type * to use as a loop counter. - * @pos: the &struct hlist_node to use as a loop counter. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry_continue(tpos, pos, member) \ - for (pos = (pos)->next; \ - pos && ({ prefetch(pos->next); 1;}) && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ - pos = pos->next) - -/** - * hlist_for_each_entry_from - iterate over a hlist continuing from existing point - * @tpos: the type * to use as a loop counter. - * @pos: the &struct hlist_node to use as a loop counter. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry_from(tpos, pos, member) \ - for (; pos && ({ prefetch(pos->next); 1;}) && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ - pos = pos->next) - -/** - * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry - * @tpos: the type * to use as a loop counter. - * @pos: the &struct hlist_node to use as a loop counter. - * @n: another &struct hlist_node to use as temporary storage - * @head: the head for your list. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ - for (pos = (head)->first; \ - pos && ({ n = pos->next; 1; }) && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ - pos = n) - - -#endif diff --git a/provision-ubuntu.sh b/provision-ubuntu.sh index b9ffcb4..4ab296a 100644 --- a/provision-ubuntu.sh +++ b/provision-ubuntu.sh @@ -1,2 +1,5 @@ #! /usr/bin/env sh -apt-get install -y clang libssl-dev nasm +apt-get install -y \ + clang \ + libssl-dev \ + nasm diff --git a/run.py b/run.py old mode 100644 new mode 100755 index 137c0c3..7a20037 --- a/run.py +++ b/run.py @@ -1,51 +1,44 @@ #! /usr/bin/env python3 -# encoding: utf-8 + +from random import randint +import binascii +import ctypes import logging import os -import shutil import subprocess -import binascii -import random +logging.getLogger(__name__) -class Sins(): - logger = logging.getLogger() +class Sins: + seed = bytes() - def __init__(self, parent, seed=None, run_dir=None): - self.parent = os.path.abspath(parent) - if not os.path.isfile(parent): - raise ValueError('Invalid executable image path.') + def __init__(self, *, parent: str, seed: str=str(), run_dir: str=str()): + self.parent = ctypes.CDLL(parent) + self.parent.gen_fork.restype = ctypes.c_int + self.parent.gen_fork.argtypes = [ctypes.c_void_p, ctypes.c_void_p] - self.seed = os.path.abspath(seed) + if seed: + with open(seed, 'rb') as seed_file: + self.seed = seed_file.read() - self.run_dir = os.path.abspath(run_dir) + try: + os.mkdir(run_dir) + except FileNotFoundError or PermissionError: + run_dir = os.path.dirname(self.seed) + except FileExistsError: + pass - if not os.path.isdir(self.run_dir): - try: - os.mkdir(self.run_dir) - except: - self.run_dir = os.path.dirname(self.seed) + self.run_dir = run_dir - shutil.copy2(self.seed, self.run_dir) + child = self.generation( + parent=self.parent, + scrap=self.seed, + cwd=self.run_dir) - parsed = (self.parent, self.seed, self.run_dir) - self.logger.info('init path: {}'.format(parsed)) + if child: + logging.info(child) - paths = (self.seed,) - while True: - for path in paths: - scrap_path = os.path.join(self.run_dir, path) - if os.path.isfile(scrap_path): - child = self.generation( - self.parent, - scrap_path, - self.run_dir - ) - if child: - print(child) - # paths = sorted(os.listdir(self.run_dir)) - - def scrap_recent(self, run_dir): + def scrap_recent(self, *, run_dir: str)->str: scraps = sorted(os.listdir(run_dir)) if scraps: @@ -53,27 +46,20 @@ class Sins(): return None - def generation(self, parent, scrap, cwd): - with open(scrap, 'rb') as scrap_file: - scrap_bin = scrap_file.read() + def generation(self, *, parent: ctypes.CDLL, scrap: bytes, cwd: str): + offset = randint(0, len(scrap)) + flip = randint(0, 255) + scrap_len = len(scrap) - scrap_hex = binascii.b2a_hex(scrap_bin).upper() - offset = random.randint(0, len(scrap_hex)) - flip = random.randint(0, 255) + logging.info('scrap_length [{}]'.format(scrap_len)) + logging.info('scrap\n{}'.format(binascii.b2a_hex(scrap))) - self.logger.debug( - 'generation: {}'.format((parent, scrap_hex, offset, flip, cwd)) - ) + status = parent.gen_fork(scrap, scrap_len) - proc = subprocess.run( - [parent, scrap_hex, str(offset), str(flip)], - cwd=cwd, - stdout=subprocess.PIPE - ) + logging.info('status {}'.format(status)) + logging.info('scrap_length [{}]'.format(scrap_len)) + logging.info('scrap\n{}'.format(binascii.b2a_hex(scrap))) - if proc.stdout: - child_hex = binascii.a2b_hex(proc.stdout) - return child_hex def hex_dumps(scrap_dir): @@ -103,8 +89,7 @@ if __name__ == '__main__': import sys parser = argparse.ArgumentParser( - description='position independent code (PIC) mutation experiment.' - ) + description='position independent code (PIC) mutation experiment.') parser.add_argument('--verbose', '-v', action='count') parser.add_argument('-build', action='store_true', help='build parent and seed PIC image, exit.') @@ -113,8 +98,8 @@ if __name__ == '__main__': parser.add_argument('-logfile', help='log to file.') parser.add_argument('-seed', default='build/seed.asm.2.o', help='path to PIC image.') - parser.add_argument('-parent', default='build/generation', - help='path to parent process.') + parser.add_argument('-parent', default='build/libgeneration.so', + help='path to generation lib.') parser.add_argument('-dir', default='sandbox', help='path to execution directory.') parser.add_argument('-dumps', action='store_true', @@ -122,27 +107,19 @@ if __name__ == '__main__': args = parser.parse_args() logger = logging.getLogger() - formatter = logging.Formatter( - '# %(asctime)s %(levelname)s\n%(message)s\n' - ) + logger.setLevel(logging.DEBUG) if args.verbose else logger.setLevel(logging.INFO) + formatter = logging.Formatter('# %(filename)s:%(lineno)s\n%(message)s') - if args.verbose: - logger.setLevel(logging.DEBUG) - else: - print('Verbose not set, running in silence.') + stream_handler = logging.StreamHandler() + stream_handler.setFormatter(formatter) + logger.addHandler(stream_handler) if args.logfile: file_handler = logging.FileHandler(args.logfile, 'a') file_handler.setFormatter(formatter) - logger.setLevel(logging.DEBUG) logger.addHandler(file_handler) - else: - stream_handler = logging.StreamHandler() - stream_handler.setFormatter(formatter) - logger.setLevel(logging.INFO) - logger.addHandler(stream_handler) - logger.info('run: {}'.format(args)) + logging.info(args) if args.provision: provision = ['sudo', 'sh', 'provision-ubuntu.sh'] @@ -155,9 +132,10 @@ if __name__ == '__main__': elif args.build: waf = [sys.executable, 'waf.py', 'build'] waf_proc = subprocess.run(waf) - logger.info(waf_proc.stdout) + logging.info(waf_proc.stdout) elif args.dumps: hex_dumps(args.dir) + else: sins = Sins(parent=args.parent, seed=args.seed, run_dir=args.dir) diff --git a/wscript b/wscript index d677c1a..682663d 100644 --- a/wscript +++ b/wscript @@ -14,7 +14,7 @@ def configure(conf): def build(bld): - bld.program( + bld.shlib( source='generation.c', target='generation', cflags=['-g', '-std=gnu11']