lunes, 17 de febrero de 2014

Edición de binarios con Python

Por: ThE InSpEcToR

Introducción

Cuando se maneja contenido distinto al de texto plano, específicamente me refiero a datos binarios, y mas cuando debemos interpretar partes de ese contenido, es común utilizar para ello un editor hexadecimal, sin embargo, suele suceder que el uso de este editor no siempre es suficiente, pues el editor no siempre interpretará la información por nosotros, es decir, existen editores que tienen la opción que le permite al usuario seleccionar determinada cantidad de bytes y el mostrará diferentes interpretaciones para esos bytes seleccionados, solo que en algunas ocasiones cuando nos enfrentamos a este tipo de contenido, debemos hacer una interpretación mas compleja de los datos y es ahí cuando es importante manejar un buen lenguaje de scripts que nos ayude con esta tarea.



En un articulo anterior se describió una forma sencilla pero útil, sobre el manejo de archivos con contenido binario en Python, este artículo se tomará como una continuación para referirse a algunas funciones que podrían se útiles en el manejo de este tipo de contenido.
Pueden existir diferentes métodos para visualizar este tipo de datos, sin embargo, desde mi punto de vista, creé una función que genera una lista con los bytes del archivo, de tal forma que luego puedo referirme a ellos por medio de indices, separar parte del contenido ya sea para analizarlo en profundidad, y si es necesario reemplazar en la lista original los elementos modificados.
def genLista(nombre_de_archivo):
 ''' Genera una lista con el contenido hexadecimal del archivo especificado '''
 lista = []

 archivo = open(nombre_de_archivo, 'rb')
 datos = archivo.read()
 archivo.close()

 for i in datos:
  lista.append(hex(ord(i))[2:].upper().zfill(2))

 return lista

Una función para hacer búsquedas en la lista devuelta por la función anterior podría ser:
def buscar(lista, sec):
 '''Busca la secuencia sec en lista y devuelve su ubicacion'''
 buscado = []
 encontrados = []
 
 if isinstance(sec, str):
  if sec[:2] == '0x':
   for i in range(2,len(sec),2):
    buscado.append(sec[i:i+2].upper())
  else:
   for i in sec:
    buscado.append(hex(ord(i))[2:].zfill(2).upper())
 elif isinstance(sec, list):
  buscado = sec
  cBytes = len(buscado)
  for i in range(len(lista)-cBytes):
   lec = lista[i:i+cBytes]
   if lec == buscado:
    encontrados.append(i)
 return encontrados
Con la función anterior se pueden buscar cadenas, listas, o secuencias hexadecimales. Ahora un par de funciones para convertir cadenas a secuencia hexadecimales y viceversa.
def hex2cad(sec):
 cad = ''
 for i in sec:
  cad+= chr(int('0x'+i,16))
 return cad

def cad2hex(cad):
  sec = []
  for i in range(len(cad)):
   sec.append(hex(ord(cad[i]))[2:].upper())
 return sec
No debe faltar una función que convierta en enteros una secuencia hexadecimal y por ende viceversa.
def hex2ent(sec, tipo='B'):
 '''Convierte una lista con valores hexadecimales a enteros especificando si es BigEndian o LittleEdian'''
 lista = sec
 if tipo=='b' or tipo=='B':
  cad = '0x' + ''.join(lista)
 elif tipo=='l' or tipo=='L':
  lista.reverse()
  cad = '0x' + ''.join(lista)
 return int(cad,16)

def ent2hex(num, Bytes=1, tipo='B'):
 '''Convierte un numero decimal a hexadecimal y genera una lista con los bytes BigEndian o LittleEndian'''
 cad = hex(num)[2:].upper().zfill(Bytes*2)
 sec = []
 for i in range(0,len(cad),2):
  sec.append(cad[i:i+2])
  if tipo=='l' or tipo=='L':
   sec.reverse()
 return sec
Ahora una función para generar el archivo con la lista que tengamos.
def genArchivo(nombre_de_archivo, lista):
 cad = ''
 for i in lista:
  cad+= chr(int('0x'+i,16))
  archivo = open(nombre_de_archivo, 'wb')
  archivo.write(cad)
 archivo.close()
En ocasiones puede ser importante, calcular el CRC32 de una cantidad de elementos de nuestra lista, para ello sería necesario la importación de la librería binascii y una función que puede ayudar en este tema sería:
def CRC32(sec):
 '''Calcula el CRC32 de la lista sec y devuelve la lista con el CRC32'''
 cal = hex(binascii.crc32(binascii.a2b_hex(''.join(sec))) & 0xffffffff)[2:-1].upper()
 crc32 = []
 for i in range(0,len(cal),2):
  crc32.append(cal[i:i+2])

 return crc32

No hay comentarios.:

Publicar un comentario