def putchar(self, addr, data): """ Concrete/Symbolic putchar implementation @param addr: the address to put a concrete or symbolic content @param data: the content to put in C{addr} @todo: if addr is Readable/Executable? Double checked when accesing parent class!!! """ if issymbolic(addr): logger.debug("Write to symbolic address %s", addr) addr_min, addr_max = self.solver.minmax(addr) logger.debug("Range: %x <-> %x", addr_min, addr_max) #Mark and intialize symbolic range for i in xrange(addr_min, addr_max+1): if not self.isWriteable(i): raise MemoryException("No Access Writting", i) for i in xrange(addr_min, addr_max+1): if not i in self.addr2symbol: self.symbol[i] = self.getchar(i) self.addr2symbol.add(i) self.symbol[addr] = chr(data) else: #concrete addr case if not self.isWriteable(addr): raise MemoryException("No Access Writting", addr) if issymbolic(data): self.symbol[addr] = chr(data) self.addr2symbol.add(addr) else: #both concrete self.addr2symbol.discard(addr) super(SMemory, self).putchar(addr, data)
def testMultiSymbolic(self): my_solver = Solver() mem = SMemory(my_solver, 32, 12) #alloc/map a little mem size = 0x10000 addr = mem.mmap(None, size, 'rwx') #initialize first 10 bytes as [100, 101, 102, .. 109] for i in xrange(addr, addr+10): mem.putchar(i, chr(100+i-addr)) #Make a char that ranges from 'A' to 'Z' v = my_solver.mkBitVec(32) my_solver.add(v>=ord('A')) my_solver.add(v<=ord('Z')) #assign it to the firt 10 bytes mem.putchar(addr+5, chr(v)) #mak a free symbol of 32 bits x = my_solver.mkBitVec(32) #constraint it to range into [addr, addr+10) my_solver.add(x>=addr) my_solver.add(x<addr+10) #so now lets ask the memory for values pointed by addr c = mem.getchar(x) for val in my_solver.getallvalues(c,1000): self.assertTrue(val>=100 and val<110 or val >= ord('A') and val <= ord('Z'))
def testBasicMappingsLimits(self): mem = SMemory(Solver(), 32, 12) #start with no maps self.assertEqual(len(mem.mappings()), 0) #Check the search gives basically any value as the mem is free self.assertEqual(mem._search(0x1000, 0x20000000), 0x20000000) #alloc/map a litlle mem size = 0x1000 addr = mem.mmap(None, size, 'rwx') #Okay 1 map self.assertEqual(len(mem.mappings()), 1) #positive tests self.assertTrue(mem.isValid(addr)) self.assertTrue(mem.isValid(addr+size-1)) for i in xrange(addr, addr+size): self.assertTrue(mem.isValid(i)) #negative tests self.assertFalse(mem.isValid(0)) self.assertFalse(mem.isValid(0xffffffff)) self.assertFalse(mem.isValid(-1)) self.assertFalse(mem.isValid(0xfffffffffffffffffffffffffff)) self.assertFalse(mem.isValid(addr-1)) self.assertFalse(mem.isValid(addr+0x1000)) #check all characters go and come back the same... for c in xrange(0, 0x100): mem.putchar(addr+0x800, chr(c)) self.assertEqual(mem.getchar(addr+0x800), chr(c))
def getchar(self, addr): """ Concrete/Symbolic getchar implementation @rtype: str[1] or BitVec[8] @param addr: the address to obtain its content @return: a character or a symbol stored in C{addr} @todo: if addr is Readable/Executable? Double checked when accesing parebnt class!!! """ if issymbolic(addr): logger.debug("Read from symbolic address %s", str(addr).replace("\n","")) addr_min, addr_max = self.solver.minmax(addr) self.solver.add(addr.uge(addr_min)) self.solver.add(addr.ule(addr_max)) logger.debug("Range: %x <-> %x", addr_min, addr_max) if addr_max-addr_min > 0x10000000: raise MemoryException("Dangling symbolic pointer[0x%08x-0x%08x]"%(addr_min, addr_max), addr) #Symbolic address case for i in xrange(addr_min, addr_max+1): if not self.isReadable(i): raise MemoryException("No Access Reading", i) if not i in self.addr2symbol: self.symbol[i] = self.getchar(i) self.addr2symbol.add(i) return chr(self.solver.simplify(self.symbol[addr])) if not self.isReadable(addr): raise MemoryException("No Access Reading", addr) #if the pointed value is a symbol... if self.isSymbolic(addr): return chr(self.solver.simplify(self.symbol[addr])) return super(SMemory, self).getchar(addr)
def sys_access(self, cpu, buf, mode): ''' Checks real user's permissions for a file @rtype: int @param cpu: current CPU. @param buf: a buffer containing the pathname to the file to check its permissions. @param mode: the access permissions to check. @return: - C{0} if the calling process can access the file in the desired mode. - C{-1} if the calling process can not access the file in the desired mode. ''' filename = "" for i in xrange(0,255): c = chr(cpu.load(buf+i,8)) if c == '\x00': break filename += c #if path.isfile(PATH) and access(PATH, MODE): # print "File exists and is readable" #else: # print "Either file is missing or is not readable" if os.access(filename, mode): return 0 else: return -1
def testBasicSymbolic(self): my_solver = Solver() mem = SMemory(my_solver, 32, 12) #alloc/map a little mem size = 0x10000 addr = mem.mmap(None, size, 'rwx') #initialize first 10 bytes as [100, 101, 102, .. 109] for i in xrange(addr, addr+10): mem.putchar(i, chr(100+i-addr)) #mak a free symbol of 32 bits x = my_solver.mkBitVec(32) #constraint it to range into [addr, addr+10) my_solver.add(x>=addr) my_solver.add(x<addr+10) #Well.. x is symbolic self.assertTrue(issymbolic(x)) #It shall be a solution self.assertTrue(my_solver.check(), 'sat') #if we ask for a possible solution (an x that comply with the constraints) sol = my_solver.getvalue(x) #it should comply.. self.assertTrue(sol >= addr and sol<addr+10) #min and max value should be addr and addr+9 m, M = my_solver.minmax(x) self.assertEqual(m, addr) self.assertEqual(M, addr+9) #If we ask for all possible solutions... for val in my_solver.getallvalues(x): #any solution must comply.. self.assertTrue(sol >= addr and sol<addr+10) #so now lets ask the memory for values pointed by addr c = mem.getchar(x) for val in my_solver.getallvalues(c): self.assertTrue(val>=100 and val<110) #constarint the address a litlle more my_solver.add(x<=addr) #It shall be a solution self.assertTrue(my_solver.check(), 'sat') #if we ask for a possible solution sol = my_solver.getvalue(x) #it must be addr self.assertTrue(sol == addr) #lets ask the memory for the value under that address c = mem.getchar(x) sol = my_solver.getvalue(c) self.assertTrue(sol==100)
def _read_string(self, cpu, buf): """ Reads a null terminated concrete buffer form memory @todo: FIX. move to cpu or memory """ filename = "" for i in xrange(0,1024): c = chr(cpu.load(buf+i,8)) if c == '\x00': break filename += c return filename
def testBasicAnonMap(self): m = MMapAnon(0x10000000, 0x2000, 'rwx') #Check the size self.assertEqual(len(m), 0x2000) #check the outside limits self.assertRaises(MemoryException, m.putchar, 0x10000000-1, 'A') self.assertRaises(MemoryException, m.putchar, 0x10002000, 'A') self.assertRaises(MemoryException, m.getchar, 0x10000000-1) self.assertRaises(MemoryException, m.getchar, 0x10002000) #check it is initialized with zero self.assertEqual(m.getchar(0x10000000), chr(0)) self.assertEqual(m.getchar(0x10002000-1), chr(0)) #check all characters go and come back the same... #at the first byte of the mapping addr = 0x10000000 for c in xrange(0, 0x100): m.putchar(addr, chr(c)) self.assertEqual(m.getchar(addr), chr(c)) #at the last byte of the mapping addr = 0x10002000-1 for c in xrange(0, 0x100): m.putchar(addr, chr(c)) self.assertEqual(m.getchar(addr), chr(c))
def generate_testcase(linux): global test_case_no test_case_no += 1 solver = linux.solver assert solver.check() == 'sat' for symbol,size in solver.input_symbols: if isinstance(symbol, Array): buf = '' for i in range(size): buf += chr(solver.getvalue(symbol[i])) print "%s: "%symbol.name, repr(buf) else: print symbol, type(symbol) raise NotImplemented file(folder+os.sep+'test_%d.txt'%test_case_no,'a').write("%s: %s\n"%(symbol.name, repr(buf)))
def sys_write(self, cpu, fd, buf, size): ''' Writes to a file descriptor @rtype: int @param cpu: current CPU. @param fd: the file descriptor of the file to write. @param buf: the buffer where the bytes to write are taken. @param size: it writes up to C{size} bytes from the buffer C{buf} to the file referred to by the file descriptor C{fd}. @return: the amount of bytes written. @todo: Out eax number of bytes actually sent | EAGAIN | EBADF | EFAULT | EINTR | EINVAL | EIO | ENOSPC | EPIPE ''' for i in xrange(0, size): value = chr(cpu.load(buf+i,8)) if not isinstance(value, str): logger.warning("Writing symbolic values to file %s", self.files[fd].name) value = str(value) self.files[fd].write(value) return size
def sys_writev32(self, cpu, fd, iov, count): ''' Works just like C{sys_write} except that multiple buffers are written out. (32 bit version) @rtype: int @param cpu: current CPU. @param fd: the file descriptor of the file to write. @param iov: the buffer where the the bytes to write are taken. @param count: amount of C{iov} buffers to write into the file. @return: the amount of bytes written in total. ''' total = 0 for i in xrange(0, count): buf = cpu.load(iov+i*8,32) size = cpu.load(iov+i*8+4,32) #data = "" for i in xrange(0,size): #data += chr() self.files[fd].write(chr(cpu.load(buf+i,8))) total+=size return total
def sys_writev(self, cpu, fd, iov, count): ''' Works just like C{sys_write} except that multiple buffers are written out (for Linux 64 bits). @rtype: int @param cpu: current CPU. @param fd: the file descriptor of the file to write. @param iov: the buffer where the the bytes to write are taken. @param count: amount of C{iov} buffers to write into the file. @return: the amount of bytes written in total. ''' total = 0 for i in xrange(0, count): buf = cpu.load(iov+i*16,64) size = cpu.load(iov+i*16+8,64) data = "" for i in xrange(0,size): data += chr(cpu.load(buf+i,8)) self.files[fd].write(data) total+=size return total
else: argv.append(args.argv[i]) env = [ '%s=%s' % (key, val) for (key,val) in os.environ.items() ] for i in range(len(args.env)): if WILDCARD in args.env[i]: print "Environment variable %d has simbols"%i name = "ENV%d"%i size = len(args.env[i]) senv = linux.solver.mkArray(name=name, is_input=True, max_size=size) for j in range(size): if args.env[i][j] != WILDCARD: senv[j] = args.env[i][j] input_symbols.append((name, size)) env.append([chr(senv[j]) for j in range(size)]) #pass stdin, stdout, stderr as kw arguments to exe linux.exe(args.program, argv, env, stdin=args.stdin, stdout=args.stdout, stderr=args.stderr) del env del argv pickle.dump(linux,file(folder+os.sep+'dump_init.pkl','w+'),2) time_start = time.clock() count = 0 test_case_no = 0 states = ['dump_init.pkl'] def get_state(): nnstates = {} for nn in states: