1 import re
2 import struct
3
4 import envi
5
6 """
7 A module containing memory utilities and the definition of the
8 memory access API used by all vtoys trace/emulators/workspaces.
9 """
10
11
12 MM_NONE = 0x0
13 MM_READ = 0x4
14 MM_WRITE = 0x2
15 MM_EXEC = 0x1
16 MM_SHARED = 0x08
17
18 MM_READ_WRITE = MM_READ | MM_WRITE
19 MM_READ_EXEC = MM_READ | MM_EXEC
20 MM_RWX = MM_READ | MM_WRITE | MM_EXEC
21
22 pnames = ['No Access', 'Execute', 'Write', None, 'Read']
24 '''
25 Return the human readable name for a *single* memory
26 perm enumeration value.
27 '''
28 return pnames[perm]
29
31 plist = ['-','-','-','-']
32 if mask & MM_SHARED:
33 plist[0] = 's'
34 if mask & MM_READ:
35 plist[1] = 'r'
36 if mask & MM_WRITE:
37 plist[2] = 'w'
38 if mask & MM_EXEC:
39 plist[3] = 'x'
40
41 return "".join(plist)
42
44 ret = 0
45 if pstr.find('s') != -1: ret |= MM_SHARED
46 if pstr.find('r') != -1: ret |= MM_READ
47 if pstr.find('w') != -1: ret |= MM_WRITE
48 if pstr.find('x') != -1: ret |= MM_EXEC
49 return ret
50
52 """
53 This is the interface spec (and a few helper utils)
54 for the unified memory object interface.
55
56 NOTE: If your actual underlying memory format is such
57 that over-riding anything (like isValidPointer!) can
58 be faster than the default implementation, DO IT!
59 """
60
62 self.imem_psize = struct.calcsize("P")
63 self.imem_arch = archmod
64
65 if archmod != None:
66 self.imem_psize = archmod.getPointerSize()
67
70
72 """
73 Read memory from the specified virtual address for size bytes
74 and return it as a python string.
75
76 Example: mem.readMemory(0x41414141, 20) -> "A..."
77 """
78 raise Exception("must implement readMemory!")
79
81 """
82 Write the given bytes to the specified virtual address.
83
84 Example: mem.writeMemory(0x41414141, "VISI")
85 """
86 raise Exception("must implement writeMemory!")
87
89 """
90 Change the protections for the given memory map. On most platforms
91 the va/size *must* exactly match an existing memory map.
92 """
93 raise Exception("must implement protectMemory!")
94
96 """
97 Check to be sure that the given virtual address and size
98 is contained within one memory map, and check that the
99 perms are contained within the permission bits
100 for the memory map. (MM_READ | MM_WRITE | MM_EXEC | ...)
101
102 Example probeMemory(0x41414141, 20, envi.memory.MM_WRITE)
103 (check if the memory for 20 bytes at 0x41414141 is writable)
104 """
105 map = self.getMemoryMap(va)
106 if map == None:
107 return False
108 mapva, mapsize, mapperm, mapfile = map
109 mapend = mapva+mapsize
110 if va+size >= mapend:
111 return False
112 if mapperm & perm != perm:
113 return False
114 return True
115
117 raise Exception("must implement allocateMemory!")
118
120 raise Exception("must implement addMemoryMap!")
121
123 raise Exception("must implement getMemoryMaps!")
124
125
137
139 return (0,0xffffffff)
140
142 bytes = self.readMemory(addr, size)
143 if bytes == None:
144 return None
145
146 if len(bytes) != size:
147 raise Exception("Read Gave Wrong Length At 0x%.8x (va: 0x%.8x wanted %d got %d)" % (self.getProgramCounter(),addr, size, len(bytes)))
148 if size == 1:
149 return struct.unpack("B", bytes)[0]
150 elif size == 2:
151 return struct.unpack("<H", bytes)[0]
152 elif size == 4:
153 return struct.unpack("<I", bytes)[0]
154 elif size == 8:
155 return struct.unpack("<Q", bytes)[0]
156
157
172
174 """
175 Return a tuple of mapva,size,perms,filename for the memory
176 map which contains the specified address (or None).
177 """
178 for mapva,size,perms,mname in self.getMemoryMaps():
179 if va >= mapva and va < (mapva+size):
180 return (mapva,size,perms,mname)
181 return None
182
185
187 maptup = self.getMemoryMap(va)
188 if maptup == None:
189 return False
190 return bool(maptup[2] & MM_READ)
191
193 maptup = self.getMemoryMap(va)
194 if maptup == None:
195 return False
196 return bool(maptup[2] & MM_WRITE)
197
199 maptup = self.getMemoryMap(va)
200 if maptup == None:
201 return False
202 return bool(maptup[2] & MM_EXEC)
203
205 maptup = self.getMemoryMap(va)
206 if maptup == None:
207 return False
208 return bool(maptup[2] & MM_SHAR)
209
210
212 """
213 A quick cheater way to searchMemoryRange() for each
214 of the current memory maps.
215 """
216 results = []
217 for va,size,perm,fname in self.getMemoryMaps():
218 try:
219 results.extend(self.searchMemoryRange(needle, va, size, regex=regex))
220 except:
221 pass
222
223 return results
224
226 """
227 Search the specified memory range (address -> size)
228 for the string needle. Return a list of addresses
229 where the match occurs.
230 """
231 results = []
232 memory = self.readMemory(address, size)
233 if regex:
234 for match in re.finditer(needle, memory):
235 off = match.start()
236 results.append(address+off)
237 else:
238 offset = 0
239 while offset < size:
240 loc = memory.find(needle, offset)
241 if loc == -1:
242 break
243 results.append(address+loc)
244 offset = loc+len(needle)
245
246 return results
247
249 '''
250 Parse an opcode from the specified virtual address.
251
252 Example: op = m.parseOpcode(0x7c773803)
253 '''
254 if self.imem_arch == None:
255 raise Exception('IMemory got no architecture module (%s)' % (self.__class__.__name__))
256 b = self.readMemory(va, 16)
257 return self.imem_arch.makeOpcode(b, 0, va)
258
260
262 """
263 Take a set of memory maps (va, perms, fname, bytes) and put them in
264 a sparse space finder. You may specify your own page-size to optimize
265 the search for an architecture.
266 """
267 IMemory.__init__(self, archmod=archmod)
268 self._map_defs = []
269
270
271
273 '''
274 Add a memory map to this object...
275 '''
276 msize = len(bytes)
277 map = (va, msize, perms, fname)
278 hlpr = [va, va+msize, map, bytes]
279 self._map_defs.append(hlpr)
280 return
281
283 '''
284 Take a memory snapshot which may be restored later.
285
286 Example: snap = mem.getMemorySnap()
287 '''
288 return [ list(mdef) for mdef in self._map_defs ]
289
291 '''
292 Restore a previously saved memory snapshot.
293
294 Example: mem.setMemorySnap(snap)
295 '''
296 self._map_defs = [list(md) for md in snap]
297
299 """
300 Get the va,size,perms,fname tuple for this memory map
301 """
302 for mva, mmaxva, mmap, mbytes in self._map_defs:
303 if va >= mva and va < mmaxva:
304 return mmap
305 return None
306
308 return [ mmap for mva, mmaxva, mmap, mbytes in self._map_defs ]
309
311
312 for mva, mmaxva, mmap, mbytes in self._map_defs:
313 if va >= mva and va < mmaxva:
314 mva, msize, mperms, mfname = mmap
315 if not mperms & MM_READ:
316 raise envi.SegmentationViolation(va)
317 offset = va - mva
318 return mbytes[offset:offset+size]
319 raise envi.SegmentationViolation(va)
320
322 for mapdef in self._map_defs:
323 mva, mmaxva, mmap, mbytes = mapdef
324 if va >= mva and va < mmaxva:
325 mva, msize, mperms, mfname = mmap
326 if not mperms & MM_WRITE:
327 raise envi.SegmentationViolation(va)
328 offset = va - mva
329 mapdef[3] = mbytes[:offset] + bytes + mbytes[offset+len(bytes):]
330 return
331
332 raise envi.SegmentationViolation(va)
333
335 """
336 An optimized routine which returns the existing
337 segment bytes sequence without creating a new
338 string object *AND* an offset of va into the
339 buffer. Used internally for optimized memory
340 handling. Returns (offset, bytes)
341 """
342 for mapdef in self._map_defs:
343 mva, mmaxva, mmap, mbytes = mapdef
344 if va >= mva and va < mmaxva:
345 offset = va - mva
346 return (offset, mbytes)
347 raise envi.SegmentationViolation(va)
348
350 '''
351 A file like object to wrap around a memory object.
352 '''
354 self.baseaddr = baseaddr
355 self.offset = baseaddr
356 self.memobj = memobj
357
358 - def seek(self, offset):
359 self.offset = self.baseaddr + offset
360
361 - def read(self, size):
362 ret = self.memobj.readMemory(self.offset, size)
363 self.offset += size
364 return ret
365
367 self.memobj.writeMemory(self.offset, bytes)
368 self.offset += len(bytes)
369
370
372 '''
373 Return a list of (offset, size) tuples showing any memory
374 differences between the given bytes.
375 '''
376
377 size = len(bytes1)
378 if size != len(bytes2):
379 raise Exception('memdiff *requires* same size bytes')
380 ret = []
381 offset = 0
382 while offset < size:
383 if bytes1[offset] != bytes2[offset]:
384 beginoff = offset
385
386 while ( offset < size and
387 bytes1[offset] != bytes2[offset]):
388 offset += 1
389 ret.append((beginoff, offset-beginoff))
390 offset += 1
391 return ret
392