Root Me (in progress)

Très amusant, et instructif ! Encore quelques challenges, puis un article…
Une note pour les utilisateurs de l’excellent volatility qui en ont ras-le-bol d’avoir à extraire tous les VAD avec vaddump, pour faire en suite le tri en se référant au résultat généré par vadtree pour ne retenir que les heaps. J’ai indiqué ici sur le site Reverse Engineering de Stack Exchange comment créer un plugin à partir de vadinfo pour faire cela automatiquement. Cela revient donc à produire le fameux plugin heaps, dont il est question dans l’incontournable The Art of Memory Forensics, mais qui n’a jamais existé.
Une petite aide pour ceux qui cherchent à rédiger leur premier outil de forensics, avec l’exemple suivant d’un petit programme Python. Il permet d’extraire d’un dump volumineux tout ce qui pourrait s’apparenter à une image PNG ou JFIF (ie : JPEG).
Le fonctionnement est vraiment basique, puisqu’il faut modifier une constante DUMP_FORMAT dans le code pour indiquer ce qu’il convient d’extraire : PNG ou JFIF. De là, le programme parcourt le dump DUMP_FILE par bloc de BLOCKSIZE octets, dressant la liste des offsets des headers et la liste des offsets des trailers qu’il y trouve. Au terme de parcours, il rapproche ces listes pour décider d’extraire ou non dans DUMP_PATH des données sous forme d’un fichier pouvant constituer une image, la condition étant que la distance entre un header et un trailer ne dépasse pas FILESIZE_MAX octets.
J’aurais sans doute l’occasion de revenir sur ce programme pour en faire un plugin pour Volatility, si jamais il n’en existe pas de tel – ce dont je doute.
import os

# Extraire touts les PNG et JFIF potentiels d'un dump.
# Codé pour Stash of Code (http://www.stashofcode.fr) en octobre 2019.

BLOCKSIZE=1024*1024		# 1MB
FILESIZE_MAX= 1024 * 1024
DUMP_FILE= '../dump'
DUMP_PATH= '../pictures/'
DUMP_FORMAT_PNG=0
DUMP_FORMAT_JFIF=1
DUMP_FORMAT=DUMP_FORMAT_JFIF

extensions = [
	'png',
	'jpeg'
]
headers = [
	b'\x89\x50\x4E\x47',	# En fait 0xFFE0 suivi de 2 octets, puis de cette chaîne
	b'\x4A\x46\x49\x46'
]
trailers = [
	b'\x49\x45\x4E\x44\xAE\x42\x60\x82',
	b'\xFF\xD9'
]
filestat = os.stat (DUMP_FILE)
dump = open (DUMP_FILE, 'rb')
offset = 0
blocksize = BLOCKSIZE
if blocksize > filestat.st_size:
	blocksize = filestat.st_size
chunks = []
nbHeaders = 0
nbTrailers = 0
while offset < filestat.st_size:
	# print (f'{offset:09}-{(offset + blocksize):09}')
	block = dump.read (blocksize)
	start = 0
	while True:
		start = block.find(headers[DUMP_FORMAT], start)
		if start == -1:
			break
		if DUMP_FORMAT == DUMP_FORMAT_PNG:
			# print (f'Header at {(offset + start):09}')
			chunks.append ({'offset':offset + start, 'isHeader':True})
		elif DUMP_FORMAT == DUMP_FORMAT_JFIF:
			# print (f'Header at {(offset + start - 4):09}')
			chunks.append ({'offset': offset + start - 4, 'isHeader': True})
		nbHeaders += 1
		start += len (headers[DUMP_FORMAT])
	start = 0
	while True:
		start = block.find(trailers[DUMP_FORMAT], start)
		if start == -1:
			break
		# print (f'Trailer at {(offset + start):09}')
		chunks.append ({'offset':offset + start + len (trailers[DUMP_FORMAT]) - 1, 'isHeader':False})
		nbTrailers += 1
		start += len (trailers[DUMP_FORMAT])
	offset += blocksize
	if (offset + blocksize) > filestat.st_size:
		blocksize = filestat.st_size - offset
print (f'{nbHeaders} headers and {nbTrailers} trailers found...')
if (nbHeaders != 0) and (nbTrailers != 0):
	chunks.sort(key=lambda chunk : chunk['offset'])
	i = 0
	while True:
		if not chunks[i]['isHeader']:
			i += 1
		elif chunks[i +1]['isHeader']:
			i += 1
		else:
			start = chunks[i]['offset']
			end = chunks[i + 1]['offset']
			if (end - start) < FILESIZE_MAX:
				picture = open (f'{DUMP_PATH}{start:09}-{end:09}.{extensions[DUMP_FORMAT]}', 'wb')
				dump.seek (start)
				data = dump.read (end - start + 1)
				picture.write (data)
				picture.close ()
				print (f'Picture {start:09}-{end:09}.{extensions[DUMP_FORMAT]} dumped in {DUMP_PATH}')
			i += 2
		if i >= (len(chunks) - 1):
			break
dump.close ()
print ('DONE!')
Root Me (in progress)