def __init__ (self, block_name, request, min_reps=0, max_reps=None, step=1, variable=None, fuzzable=True, name=None): ''' Repeat the rendered contents of the specified block cycling from min_reps to max_reps counting by step. By default renders to nothing. This block modifier is useful for fuzzing overflows in table entries. This block modifier MUST come after the block it is being applied to. @type block_name: String @param block_name: Name of block to apply sizer to @type request: s_request @param request: Request this block belongs to @type min_reps: Integer @param min_reps: (Optional, def=0) Minimum number of block repetitions @type max_reps: Integer @param max_reps: (Optional, def=None) Maximum number of block repetitions @type step: Integer @param step: (Optional, def=1) Step count between min and max reps @type variable: Sulley Integer Primitive @param variable: (Optional, def=None) Repititions will be derived from this variable, disables fuzzing @type fuzzable: Boolean @param fuzzable: (Optional, def=True) Enable/disable fuzzing of this primitive @type name: String @param name: (Optional, def=None) Specifying a name gives you direct access to a primitive ''' self.block_name = block_name self.request = request self.variable = variable self.min_reps = min_reps self.max_reps = max_reps self.step = step self.fuzzable = fuzzable self.name = name self.value = self.original_value = "" # default to nothing! self.rendered = "" # rendered value self.fuzz_complete = False # flag if this primitive has been completely fuzzed self.fuzz_library = [] # library of static fuzz heuristics to cycle through. self.mutant_index = 0 # current mutation number self.current_reps = min_reps # current number of repetitions # ensure the target block exists. if self.block_name not in self.request.names: raise sex.SullyRuntimeError("CAN NOT ADD REPEATER FOR NON-EXISTANT BLOCK: %s" % self.block_name) # ensure the user specified either a variable to tie this repeater to or a min/max val. if self.variable == None and self.max_reps == None: raise sex.SullyRuntimeError("REPEATER FOR BLOCK %s DOES NOT HAVE A MIN/MAX OR VARIABLE BINDING" % self.block_name) # if a variable is specified, ensure it is an integer type. if self.variable and not isinstance(self.variable, primitives.bit_field): print self.variable raise sex.SullyRuntimeError("ATTEMPT TO BIND THE REPEATER FOR BLOCK %s TO A NON INTEGER PRIMITIVE" % self.block_name) # if not binding variable was specified, propogate the fuzz library with the repetition counts. if not self.variable: self.fuzz_library = range(self.min_reps, self.max_reps + 1, self.step) # otherwise, disable fuzzing as the repitition count is determined by the variable. else: self.fuzzable = False
def post_fail(self, logger, *args, **kwargs): """Tries to reset device over HTTP and wait before returning. After sending HTTP request and receiving response, wait self._reset_delay + self._dut_reset_time seconds. If the outlet does not respond (after self._timeout seconds), this method will raise an exception. This method will log actions associated with HTTP communication. It assumes that a test step is already opened. Args: logger (ifuzz_logger.IFuzzLogger): For logging communications with outlet device. *args: Kept for forward-compatibility. **kwargs: Kept for forward-compatibility. Raises: sex.SulleyRuntimeError: If the reset fails due to: - no response in self._timeout seconds or - unexpected response contents (see EzOutletReset.EXPECTED_RESPONSE_CONTENTS) """ _ = args # only for forward-compatibility _ = kwargs # only for forward-compatibility logger = logger url = _build_url(self._hostname, self.RESET_URL_PATH) logger.log_info(self.LOG_REQUEST_MSG.format(url)) try: opened_url = urllib2.urlopen(url, timeout=self._timeout) except urllib2.URLError: if logger is not None: logger.log_info(self.NO_RESPONSE_MSG.format(self._timeout)) raise sex.SullyRuntimeError(self.NO_RESPONSE_MSG.format(self._timeout)), \ None, \ sys.exc_info()[2] received = opened_url.read() logger.log_recv(received) if received != self.EXPECTED_RESPONSE_CONTENTS: raise sex.SullyRuntimeError( self.UNEXPECTED_RESPONSE_MSG.format(received)) time.sleep(self._reset_delay + self._dut_reset_time)
def push(self, item): ''' Push an item into the block structure. If no block is open, the item goes onto the request stack. otherwise, the item goes onto the last open blocks stack. ''' # if the item has a name, add it to the internal dictionary of names. if hasattr(item, "name") and item.name: # ensure the name doesn't already exist. if item.name in self.names.keys(): raise sex.SullyRuntimeError("BLOCK NAME ALREADY EXISTS: %s" % item.name) self.names[item.name] = item # if there are no open blocks, the item gets pushed onto the request stack. # otherwise, the pushed item goes onto the stack of the last opened block. if not self.block_stack: self.stack.append(item) else: self.block_stack[-1].push(item) # add the opened block to the block stack. if isinstance(item, block): self.block_stack.append(item)
def post_fail(self, logger, *args, **kwargs): """Call reset() and log actions. See reset() docstring for details. This method will log actions associated with HTTP communication. It assumes that a test step is already opened. Args: logger (ifuzz_logger.IFuzzLogger): For logging communications with outlet device. *args: Kept for forward-compatibility. **kwargs: Kept for forward-compatibility. Raises: sex.SullyRuntimeError: If the reset fails due to: - no response in self._timeout seconds or - unexpected response contents (see EzOutletReset.EXPECTED_RESPONSE_CONTENTS) """ _ = args # only for forward-compatibility _ = kwargs # only for forward-compatibility logger.log_info(self.LOG_REQUEST_MSG.format(self.url)) try: response = self.reset() logger.log_recv(response) except EzOutletResetError as e: logger.log_info(e.message) raise sex.SullyRuntimeError(e.message), \ None, \ sys.exc_info()[2]
def pop (self): ''' The last open block was closed, so pop it off of the block stack. ''' if not self.block_stack: raise sex.SullyRuntimeError("BLOCK STACK OUT OF SYNC") self.block_stack.pop()
def __init__ (self, name, request, group=None, encoder=None, dep=None, dep_value=None, dep_values=[], dep_compare="=="): ''' The basic building block. Can contain primitives, sizers, checksums or other blocks. @type name: String @param name: Name of the new block @type request: s_request @param request: Request this block belongs to @type group: String @param group: (Optional, def=None) Name of group to associate this block with @type encoder: Function Pointer @param encoder: (Optional, def=None) Optional pointer to a function to pass rendered data to prior to return @type dep: String @param dep: (Optional, def=None) Optional primitive whose specific value this block is dependant on @type dep_value: Mixed @param dep_value: (Optional, def=None) Value that field "dep" must contain for block to be rendered @type dep_values: List of Mixed Types @param dep_values: (Optional, def=[]) Values that field "dep" may contain for block to be rendered @type dep_compare: String @param dep_compare: (Optional, def="==") Comparison method to apply to dependency (==, !=, >, >=, <, <=) ''' self.name = name self.request = request self.group = group self.encoder = encoder self.dep = dep self.dep_value = dep_value self.dep_values = dep_values self.dep_compare = dep_compare self.s_type = "block" if not name: raise sex.SullyRuntimeError("'%s' requires a name" % self.s_type) if name and not type(name) is str: raise sex.SullyRuntimeError("'%s' name has to be of type str" % self.s_type) self.stack = [] # block item stack. self.rendered = "" # rendered block contents. self.fuzzable = True # blocks are always fuzzable because they may contain fuzzable items. self.group_idx = 0 # if this block is tied to a group, the index within that group. self.fuzz_complete = False # whether or not we are done fuzzing this block. self.mutant_index = 0 # current mutation index.
def __init__(self, block_name, request, algorithm="crc32", length=0, endian="<", name=None): ''' Create a checksum block bound to the block with the specified name. You *can not* create a checksm for any currently open blocks. @type block_name: String @param block_name: Name of block to apply sizer to @type request: s_request @param request: Request this block belongs to @type algorithm: String @param algorithm: (Optional, def=crc32) Checksum algorithm to use. (crc32, adler32, md5, sha1) @type length: Integer @param length: (Optional, def=0) Length of checksum, specify 0 to auto-calculate @type endian: Character @param endian: (Optional, def=LITTLE_ENDIAN) Endianess of the bit field (LITTLE_ENDIAN: <, BIG_ENDIAN: >) @type name: String @param name: Name of this checksum field ''' self.block_name = block_name self.request = request self.algorithm = algorithm self.length = length self.endian = endian self.name = name self.s_type = "checksum" if not block_name: raise sex.SullyRuntimeError("'%s' requires a block_name" % self.s_type) if block_name and not type(block_name) is str: raise sex.SullyRuntimeError("'%s' requires block_name to be of type str" % self.s_type) if algorithm and not type(algorithm) is str: raise sex.SullyRuntimeError("'%s' requires algorithm to be of type str" % self.s_type) if length and not type(length) is int: raise sex.SullyRuntimeError("'%s' requires length to be of type int" % self.s_type) if endian != ">" and endian != "<": raise sex.SullyRuntimeError("'%s' requires endian to be '>' or '<'" % self.s_type) self.rendered = "" self.fuzzable = False if not self.length and self.checksum_lengths.has_key(self.algorithm): self.length = self.checksum_lengths[self.algorithm]
def checksum(self, data): ''' Calculate and return the checksum (in raw bytes) over the supplied data. @type data: Raw @param data: Rendered block data to calculate checksum over. @rtype: Raw @return: Checksum. ''' if type(self.algorithm) is str: if self.algorithm == "crc32": return struct.pack(self.endian + "L", (zlib.crc32(data) & 0xFFFFFFFFL)) elif self.algorithm == "adler32": return struct.pack(self.endian + "L", (zlib.adler32(data) & 0xFFFFFFFFL)) elif self.algorithm == "md5": digest = hashlib.md5(data).digest() # TODO: is this right? if self.endian == ">": (a, b, c, d) = struct.unpack("<LLLL", digest) digest = struct.pack(">LLLL", a, b, c, d) return digest elif self.algorithm == "sha1": digest = hashlib.sha1(data).digest() # TODO: is this right? if self.endian == ">": (a, b, c, d, e) = struct.unpack("<LLLLL", digest) digest = struct.pack(">LLLLL", a, b, c, d, e) return digest elif self.algorithm == "crc16": return struct.pack(self.endian + "H", CRC16(data).intchecksum()) else: raise sex.SullyRuntimeError( "INVALID CHECKSUM ALGORITHM SPECIFIED: %s" % self.algorithm) else: return self.algorithm(data)
def render (self): ''' Nothing fancy on render, simply return the value. ''' # if the target block for this sizer is not closed, raise an exception. if self.block_name not in self.request.closed_blocks: raise sex.SullyRuntimeError("CAN NOT APPLY REPEATER TO UNCLOSED BLOCK: %s" % self.block_name) # if a variable-bounding was specified then set the value appropriately. if self.variable: block = self.request.closed_blocks[self.block_name] self.value = block.rendered * self.variable.value self.rendered = self.value return self.rendered
def render(self): ''' @desc: 获取测试数据的字符流 @type: String @return: 返回测试用例 ''' # ensure there are no open blocks lingering. if self.block_stack: raise sex.SullyRuntimeError("UNCLOSED BLOCK: %s" % self.block_stack[-1].name) # render every item in the stack. for item in self.stack: item.render() # process remaining callbacks. for key in self.callbacks.keys(): for item in self.callbacks[key]: item.render() def update_size(stack, name): # walk recursively through each block to update its size blocks = [] for item in stack: if isinstance(item, size): item.render() elif isinstance(item, block): blocks += [item] for b in blocks: update_size(b.stack, b.name) b.render() # call update_size on each block of the request for item in self.stack: if isinstance(item, block): update_size(item.stack, item.name) item.render() # now collect, merge and return the rendered items. self.rendered = "" for item in self.stack: self.rendered += item.rendered return self.rendered
def mutate(self): ''' Mutate the primitive by stepping through the fuzz library, return False on completion. If variable-bounding is specified then fuzzing is implicitly disabled. Instead, the render() routine will properly calculate the correct repitition and return the appropriate data. @rtype: Boolean @return: True on success, False otherwise. ''' # render the contents of the block we are repeating. self.request.names[self.block_name].render() # if the target block for this sizer is not closed, raise an exception. if self.block_name not in self.request.closed_blocks: raise sex.SullyRuntimeError( "CAN NOT APPLY REPEATER TO UNCLOSED BLOCK: %s" % self.block_name) # if we've run out of mutations, raise the completion flag. if self.mutant_index == self.num_mutations(): self.fuzz_complete = True # if fuzzing was disabled or complete, and mutate() is called, ensure the original value is restored. if not self.fuzzable or self.fuzz_complete: self.value = self.original_value self.current_reps = self.min_reps return False if self.variable: self.current_reps = self.variable.value else: self.current_reps = self.fuzz_library[self.mutant_index] # set the current value as a multiple of the rendered block based on the current fuzz library count. block = self.request.closed_blocks[self.block_name] self.value = block.rendered * self.fuzz_library[self.mutant_index] # increment the mutation count. self.mutant_index += 1 return True
def fuzz (self, this_node=None, path=[]): ''' Call this routine to get the ball rolling. No arguments are necessary as they are both utilized internally during the recursive traversal of the session graph. @type this_node: request (node) @param this_node: (Optional, def=None) Current node that is being fuzzed. @type path: List @param path: (Optional, def=[]) Nodes along the path to the current one being fuzzed. ''' # if no node is specified, then we start from the root node and initialize the session. if not this_node: # we can't fuzz if we don't have at least one target and one request. if not self.targets: raise sex.SullyRuntimeError("NO TARGETS SPECIFIED IN SESSION") if not self.edges_from(self.root.id): raise sex.SullyRuntimeError("NO REQUESTS SPECIFIED IN SESSION") this_node = self.root try: self.server_init() except: return # TODO: complete parallel fuzzing, will likely have to thread out each target target = self.targets[0] # step through every edge from the current node. for edge in self.edges_from(this_node.id): # the destination node is the one actually being fuzzed. self.fuzz_node = self.nodes[edge.dst] num_mutations = self.fuzz_node.num_mutations() # keep track of the path as we fuzz through it, don't count the root node. # we keep track of edges as opposed to nodes because if there is more then one path through a set of # given nodes we don't want any ambiguity. path.append(edge) current_path = " -> ".join([self.nodes[e.src].name for e in path[1:]]) current_path += " -> %s" % self.fuzz_node.name self.logger.info("current fuzz path: %s" % current_path) self.logger.info("fuzzed %d of %d total cases" % (self.total_mutant_index, self.total_num_mutations)) done_with_fuzz_node = False crash_count = 0 # loop through all possible mutations of the fuzz node. while not done_with_fuzz_node: # if we need to pause, do so. self.pause() # if we have exhausted the mutations of the fuzz node, break out of the while(1). # note: when mutate() returns False, the node has been reverted to the default (valid) state. if not self.fuzz_node.mutate(): self.logger.error("all possible mutations for current fuzz node exhausted") done_with_fuzz_node = True continue # make a record in the session that a mutation was made. self.total_mutant_index += 1 # if we've hit the restart interval, restart the target. if self.restart_interval and self.total_mutant_index % self.restart_interval == 0: self.logger.error("restart interval of %d reached" % self.restart_interval) self.restart_target(target) # exception error handling routine, print log message and restart target. def error_handler (e, msg, target, sock=None): if sock: sock.close() msg += "\nException caught: %s" % repr(e) msg += "\nRestarting target and trying again" self.logger.critical(msg) self.restart_target(target) # if we don't need to skip the current test case. if self.total_mutant_index > self.skip: self.logger.info("fuzzing %d of %d" % (self.fuzz_node.mutant_index, num_mutations)) # attempt to complete a fuzz transmission. keep trying until we are successful, whenever a failure # occurs, restart the target. while 1: # instruct the debugger/sniffer that we are about to send a new fuzz. if target.procmon: try: target.procmon.pre_send(self.total_mutant_index) except Exception, e: error_handler(e, "failed on procmon.pre_send()", target) continue if target.netmon: try: target.netmon.pre_send(self.total_mutant_index) except Exception, e: error_handler(e, "failed on netmon.pre_send()", target) continue try: # establish a connection to the target. sock = socket.socket(socket.AF_INET, self.proto) except Exception, e: error_handler(e, "failed creating socket", target) continue if self.bind: try: sock.bind(self.bind) except Exception, e: error_handler(e, "failed binding on socket", target, sock) continue try: sock.settimeout(self.timeout) # Connect is needed only for TCP stream if self.proto == socket.SOCK_STREAM: sock.connect((target.host, target.port)) except Exception, e: error_handler(e, "failed connecting on socket", target, sock) continue
def __init__( self, session_filename=None, skip=0, sleep_time=1.0, log_level=logging.INFO, logfile=None, logfile_level=logging.DEBUG, proto="tcp", bind=None, restart_interval=0, timeout=5.0, web_port=26000, crash_threshold=3, restart_sleep_time=300 ): ''' Extends pgraph.graph and provides a container for architecting protocol dialogs. @type session_filename: String @kwarg session_filename: (Optional, def=None) Filename to serialize persistant data to @type skip: Integer @kwarg skip: (Optional, def=0) Number of test cases to skip @type sleep_time: Float @kwarg sleep_time: (Optional, def=1.0) Time to sleep in between tests @type log_level: Integer @kwarg log_level: (Optional, def=logger.INFO) Set the log level @type logfile: String @kwarg logfile: (Optional, def=None) Name of log file @type logfile_level: Integer @kwarg logfile_level: (Optional, def=logger.INFO) Set the log level for the logfile @type proto: String @kwarg proto: (Optional, def="tcp") Communication protocol ("tcp", "udp", "ssl") @type bind: Tuple (host, port) @kwarg bind: (Optional, def=random) Socket bind address and port @type timeout: Float @kwarg timeout: (Optional, def=5.0) Seconds to wait for a send/recv prior to timing out @type restart_interval: Integer @kwarg restart_interval (Optional, def=0) Restart the target after n test cases, disable by setting to 0 @type crash_threshold: Integer @kwarg crash_threshold (Optional, def=3) Maximum number of crashes allowed before a node is exhaust @type restart_sleep_time: Integer @kwarg restart_sleep_time: Optional, def=300) Time in seconds to sleep when target can't be restarted @type web_port: Integer @kwarg web_port: (Optional, def=26000) Port for monitoring fuzzing campaign via a web browser ''' # run the parent classes initialization routine first. pgraph.graph.__init__(self) self.session_filename = session_filename self.skip = skip self.sleep_time = sleep_time self.proto = proto.lower() self.bind = bind self.ssl = False self.restart_interval = restart_interval self.timeout = timeout self.web_port = web_port self.crash_threshold = crash_threshold self.restart_sleep_time = restart_sleep_time # Initialize logger self.logger = logging.getLogger("Sulley_logger") self.logger.setLevel(log_level) formatter = logging.Formatter('[%(asctime)s] [%(levelname)s] -> %(message)s') if logfile != None: filehandler = logging.FileHandler(logfile) filehandler.setLevel(logfile_level) filehandler.setFormatter(formatter) self.logger.addHandler(filehandler) consolehandler = logging.StreamHandler() consolehandler.setFormatter(formatter) consolehandler.setLevel(log_level) self.logger.addHandler(consolehandler) self.total_num_mutations = 0 self.total_mutant_index = 0 self.fuzz_node = None self.targets = [] self.netmon_results = {} self.procmon_results = {} self.protmon_results = {} self.pause_flag = False self.crashing_primitives = {} if self.proto == "tcp": self.proto = socket.SOCK_STREAM elif self.proto == "ssl": self.proto = socket.SOCK_STREAM self.ssl = True elif self.proto == "udp": self.proto = socket.SOCK_DGRAM else: raise sex.SullyRuntimeError("INVALID PROTOCOL SPECIFIED: %s" % self.proto) # import settings if they exist. self.import_file() # create a root node. we do this because we need to start fuzzing from a single point and the user may want # to specify a number of initial requests. self.root = pgraph.node() self.root.name = "__ROOT_NODE__" self.root.label = self.root.name self.last_recv = None self.add_node(self.root)
class session (): def __init__( self, loop_sleep_time=0.0, #每次循环fuzz的时间间隔 proto="tcp", #使用的连接协议 sock_timeout=None, #socket超时时间 send_iface="eth0", #发送数据包使用的网卡 sniff_iface="eth0", #进行网络监听的网卡 sniff_stop_filter=None, #设置网络监视器的stop_filter sniff_timout=None, #网络监视器超时间隔 sniff_switch=False, #是否启动网络监视器 sniff_filter="", #设置数据包过滤 keep_alive=False, #是否保持socket连接 send_sleep_time=0.0, #发送每个测试用例的时间间隔 fuzz_store_limit=None, #存储生成的fuzz数据最大数量 pinger_threshold=None, #是否开启ping检测crash tcpScan_threshold=None, #是否开启tcp scan检测crash udpScan_threshold=None, #是否开启udp scan检测crash cusDect_threshold=None, #是否开启自定义callback函数检测crash procDect_threshold=None #是否开启procmon检测crash ): log_level=logging.INFO logfile=None logfile_level=logging.DEBUG self.loop_sleep_time = loop_sleep_time self.send_sleep_time = send_sleep_time self.proto = proto.lower() self.timeout = sock_timeout self.total_mutant_index = 0 self.fuzz_targets = [] self.fuzz_blocks = [] self.afl_fuzz_blocks = [] self.procmon_results = {} self.protmon_results = {} self.pause_flag = False self.crashing_primitives = {} self.keep_alive = keep_alive self.layer2 = False self.custom = False self.iface = send_iface self.message = '' self.sniff_iface = sniff_iface self.sniff_thread = None self.sniff_switch = sniff_switch self.sniff_filter = sniff_filter self.sniff_stop_filter = sniff_stop_filter self.sniff_timeout = sniff_timout self.cur_mutate_frame = None self.fuzz_store_list = [] self.fuzz_store_limit = fuzz_store_limit self.fuzz_send_count = 0 self.pinger_threshold = pinger_threshold self.tcpScan_threshold = tcpScan_threshold self.udpScan_threshold = udpScan_threshold self.cusDect_threshold = cusDect_threshold self.procDect_threshold = procDect_threshold #创建网络监视器 if self.sniff_switch: try: self.sniff_thread = SniffThread.Sniffer(self.sniff_iface,self.sniff_filter,self.sniff_stop_filter,self.sniff_timeout) except Exception, e: print "sniff thread create failed. Exception: %s" % str(e) os.kill(0 - os.getpid(), signal.SIGKILL) #初始化日志 self.logger = logging.getLogger("NetFuzzer_logger") self.logger.setLevel(log_level) formatter = logging.Formatter('[%(asctime)s] [%(levelname)s] -> %(message)s') if logfile != None: filehandler = logging.FileHandler(logfile) filehandler.setLevel(logfile_level) filehandler.setFormatter(formatter) self.logger.addHandler(filehandler) consolehandler = logging.StreamHandler() consolehandler.setFormatter(formatter) consolehandler.setLevel(log_level) self.logger.addHandler(consolehandler) #判断用户使用的连接协议 if self.proto == "tcp": self.proto = socket.SOCK_STREAM elif self.proto == "udp": self.proto = socket.SOCK_DGRAM elif self.proto == "layer2": self.layer2 = True elif self.proto == "custom": self.custom = True else: raise sex.SullyRuntimeError("INVALID PROTOCOL SPECIFIED: %s" % self.proto)
def __init__ (self, block_name, request, offset=0, length=4, endian="<", format="binary", synchsafe=False, inclusive=False, signed=False, math=None, fuzzable=False, name=None): ''' Create a sizer block bound to the block with the specified name. You *can not* create a sizer for any currently open blocks. @type block_name: String @param block_name: Name of block to apply sizer to @type request: s_request @param request: Request this block belongs to @type offset: Integer @param offset: (Optional, def=0) Offset for calculated size value @type length: Integer @param length: (Optional, def=4) Length of sizer @type endian: Character @param endian: (Optional, def=LITTLE_ENDIAN) Endianess of the bit field (LITTLE_ENDIAN: <, BIG_ENDIAN: >) @type format: String @param format: (Optional, def=binary) Output format, "binary" or "ascii" @type inclusive: Boolean @param inclusive: (Optional, def=False) Should the sizer count its own length? @type signed: Boolean @param signed: (Optional, def=False) Make size signed vs. unsigned (applicable only with format="ascii") @type math: Function @param math: (Optional, def=None) Apply the mathematical operations defined in this function to the size @type fuzzable: Boolean @param fuzzable: (Optional, def=False) Enable/disable fuzzing of this sizer @type name: String @param name: Name of this sizer field @type synchsafe: Boolean @param synchsafe: (Optional, def=False) Synchsafe (https://en.wikipedia.org/wiki/Synchsafe) ''' self.block_name = block_name self.request = request self.offset = offset self.length = length self.endian = endian self.format = format self.inclusive = inclusive self.signed = signed self.math = math self.fuzzable = fuzzable self.name = name self.synchsafe = synchsafe self.s_type = "size" if not block_name: raise sex.SullyRuntimeError("'%s' requires a block_name" % self.s_type) if block_name and not type(block_name) is str: raise sex.SullyRuntimeError("'%s' requires block_name to be of type str" % self.s_type) if name and not type(name) is str: raise sex.SullyRuntimeError("'%s' requires name to be of type str" % self.s_type) if fuzzable != True and fuzzable != False: raise sex.SullyRuntimeError("'%s' requires fuzzable to be of type boolean" % self.s_type) if not type(offset) is int: raise sex.SullyRuntimeError("'%s' requires offset to be of type int" % self.s_type) if not type(length) is int: raise sex.SullyRuntimeError("'%s' requires length to be of type int" % self.s_type) if endian != ">" and endian != "<": raise sex.SullyRuntimeError("'%s' requires endian to be '>' or '<'" % self.s_type) if not type(format) is str: raise sex.SullyRuntimeError("'%s' requires format to be of type str" % self.s_type) if synchsafe != True and synchsafe != False: raise sex.SullyRuntimeError("'%s' requires synchsafe to be of type boolean" % self.s_type) if inclusive != True and inclusive != False: raise sex.SullyRuntimeError("'%s' requires inclusive to be of type boolean" % self.s_type) if signed != True and signed != False: raise sex.SullyRuntimeError("'%s' requires signed to be of type boolean" % self.s_type) self.original_value = "N/A" # for get_primitive self.s_type = "size" # for ease of object identification self.bit_field = primitives.bit_field(0, self.length*8, endian=self.endian, format=self.format, signed=self.signed, synchsafe=self.synchsafe) self.rendered = "" self.fuzz_complete = self.bit_field.fuzz_complete self.fuzz_library = self.bit_field.fuzz_library self.mutant_index = self.bit_field.mutant_index self.value = self.bit_field.value if self.math == None: self.math = lambda (x): x