elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.

 

 


Tema destacado: Arreglado, de nuevo, el registro del warzone (wargame) de EHN


  Mostrar Temas
Páginas: 1 [2] 3 4
11  Seguridad Informática / Análisis y Diseño de Malware / [Taller en construcción]Secciones en archivos PE. en: 23 Mayo 2012, 18:44 pm

Un saludo a todos los foreros, hoy les traigo un taller práctico-teórico sobre secciones de archivos ejecubles (PE).
Creo que será conveniente recordar conceptos y estructuras básicas sobre el formato PE, si desean profundizar no duden en leer otro documento que he realizado anteriormente sobre el tema "Formato PE bajo Windows", está en español y lo pueden encontrar en el siguiente enlace:
Código:
http://foro.elhacker.net/empty-t332157.0.html

O preferiblemente el documento que muchos llamamos la bíblia del Formato PE, el PECOFF que es la documentación oficial de Microsoft sobre el tema:
Código:
http://msdn.microsoft.com/en-us/library/windows/hardware/gg463119.aspx

Herramientas de práctica:
HexWorkShop v6.0.1: Editor hexadecimal.
Código:
http://dl.dropbox.com/u/26610132/HexWorkShop%206.rar

OllyDBG 1.10: Depurador.
Código:
http://dl.dropbox.com/u/26610132/OllyDGB%201.10.rar

Temas que tratará el taller:
  • Conceptos básicos y repaso sobre la estructura PE.
  • Agregando una sección.
  • El problema de la BOUND_IMPORT_TABLE.
  • Desorden en datos de secciones.
  • Ampliando el tamaño de una sección.
  • Datos entre secciones (no mapeados).
  • Secciones "Dummy".
  • Archivos sin ninguna sección.
  • Lo que realmente hace el TinyPE.
  • Explicación de medios de inyección (RunPE e inyección dependiente de relocaciones). -> A pedido de mi amigo _Enko

Repaso de conceptos y estructuras:
Bueno, nuestro enfoque es hacia los archivos ejecutables y su estructura. Un archivo ejecutable, ahora en adelante lo llamaré PE (Portable Executable) y presenta la siguiente estructura:


Estructuras:
IMAGE_DOS_HEADER:
  • DOS_SIGNATURE = 'MZ' -> WORD
  • [29 WORDS] -> Aquí abreviaremos son campos poco utilizados.
  • l_fanew = Apunta hacia IMAGE_NT_HEADERS -> DWORD

IMAGE_NT_HEADERS:
  • Signature = PEx0x0 -> Firma de validación de archivos PE. DWORD
  • IMAGE_FILE_HEADER 0x20
  • IMAGE_OPTIONAL_HEADER 0xE0

IMAGE_FILE_HEADER:
  • Machine: WORD -> Define la arquitectura del computador o emulador para ejecutar el programa
  • NumberOfSections: WORD -> Este valor numerico define la cantidad de secciones que tendrá el archivo.
  • TimeDateStamp: DWORD -> Fecha de creación del archivo.
  • PointerToSymbolTable: DWORD -> Utilizado solo en archivos COFF (.obj)
  • NumberOfSymbols: DWORD -> -> Utilizado solo en archivos COFF (.obj)
  • SizeOfOptinalHeader: WORD -> "Contiene el tamaño del IMAGE_OPTIONAL_HEADER"
  • Characteristics: DWORD -> Atributos u opciones que puede tener el archivo.

IMAGE_OPTIONAL_HEADER:
  • Magic: WORD -> Determina si el programa es para 32 o 64 bits.
  • MajorLinkerVersion: BYTE Versión más alta del linker.
  • MinorLinkerVersion: BYTE Versión más baja del linker.
  • SizeOfCode: DWORD Tamaño de la sección de código generalmente .text o .code.
  • SizeOfInitializedData: DWORD -> Tamaño de datos inicializados.
  • SizeOfUninitializedData: DWORD -> Tamaño de datos no inicializados.
  • AddressOfEntryPoint: DWORD -> RVA del punto de entrada del programa.
  • BaseOfCode: DWORD -> RVA Base de la sección de código.
  • BaseOfData: DWORD -> RVA Base de la sección de datos.
  • ImageBase: DWORD -> VA Base donde se cargará el PE.
  • SectionAlignment: DWORD -> Tamaño de alineación de datos en memoria.
  • FileAlignment: DWORD -> Tamaño de alineación de datos en disco.
  • MajorOperatingSystemVersion: WORD -> Versión principal del S.O requerido.
  • MinorOperatingSystemVersion: WORD -> Versión mínima del S.O requerido.
  • MajorImageVersion: WORD -> Versión principal del PE.
  • MinorImageVersion: WORD -> Versión mínima del PE.
  • MajorSubsystemVersion: WORD -> Versión principal del subsistema requerido.
  • MinorSubsystemVersion: WORD -> Versión mínima del subsistema requerido.
  • Win32VersionValue: DWORD -> Reservado.
  • SizeOfImage: DWORD -> Tamaño que ocupará el ejecutable en memoria, multiplo del SectionAlignment.
  • SizeOfHeaders: DWORD -> Tamaño de toda la cabecera PE.
  • CheckSum: DWORD -> Valor de comprobación por suma.
  • Subsystem: WORD -> Subsistema (consola, gráfico, etc).
  • DllCharacteristics: WORD -> Atributos u opciones pero en caso de librerías DLL.
  • SizeOfStackReserve: DWORD -> Tamaño de reserva para la pila.
  • SizeOfStackCommit: DWORD -> Tamaño de datos de la pila comprometidos.
  • SizeOfHeapReserve: DWORD -> Tamaño de reserva del montículo.
  • SizeOfHeapCommit: DWORD -> Tamaño de datos comprometidos del montículo.
  • LoaderFlags: DWORD -> Parámetros pasados al Loader.
  • NumberOfRvaAndSizes: DWORD -> Número de directorios en IMAGE_DATA_DIRECTORY.
  • IMAGE_DATA_DIRECTORY[NumberOfRVAAndSizes] -> Directorios de datos, conocidos como Tablas, donde tenemos otras estructuras como las importaciones y demás.

IMAGE_SECTION_HEADER
  • Name: (BYTE*8) -> Nombre de la sección.
  • VirtualSize: DWORD -> Tamaño de la sección en memoria.
  • VirtualAddress: DWORD -> RVA donde se carga la sección en memoria.
  • SizeOfRawData: DWORD -> Tamaño de la sección en disco.
  • PointerToRawData: DWORD -> Ubicación de la sección en disco.
  • PointerToRelocations: DWORD -> Campo ya no utilizado, reemplazado por uno de los directorios de datos.
  • PointerToLineNumbers: DWORD -> Solo usado en COFF (.obj).
  • NumberOfRelocations: WORD -> Campo no utilizado ya reemplazado.
  • NumberOfLineNumbers: WORD -> Solo usado en COFF (.obj).
  • Characteristics: DWORD -> Características de la sección (opciones).

Direcciones físicas, virtuales relativas y virtuales:
Antes de continuar quiero también recordar un poco del tema, ya que será necesario que tengan claro que es cada una de estas direcciones para el desarrollo práctico del taller.

Direcciones físicas:
También podemos llamar posición física y corresponden a los valores del archivo en disco osea físicamente al archivo. Va en rango de (0, Tamaño del archivo).

Direcciones virtuales relativas:
Decimos que son relativas porque son el desplazamiento respecto a una dirección virtual. Como se explicará a continuación cuando el archivo es cargado en memoria cambia mucho respecto a como esta en disco. Las direcciones virtuales relativas funcionan como lo sería una dirección física pero en memoria y además son relativas al ImageBase que recordemos es donde se carga el ejecutable. Si hablamos por ejemplo de un RVA 0x3000 en memoria correspondderá a ImageBase + 0x3000, si os verificáis sería muy distinto en obtener el mismo dato en dicha posición.

Direcciones virtuales:
Son direcciones que directamente se encuentran en el rango ImageBase, (ImageBase + SizeOfImage). En escencia sería eso, por ejemplo 0x401000 teniendo como ImageBase 0x400000 estaríamos dentro de dicho rango. Estas hacen referencia directa a una posición en memoria.

Un archivo cargado en memoria:
Bueno justamente quería hacer énfasis en como se vería un archivo cargado en memoria, podemos saber que será distinto que en disco empezando por el detalle de que en memoria será más "grande". Si miramos el SizeOfImage y comparamos en disco tendremos un valor relativamente más grande. Cabe decir que la carga de un archivo en memoria depende su un factor importante y es el campo "SectionAligment" No lo olvidéis.

Lo primero que hará es reservar el espacio, y justo en el ImageBase empezará a "plasmar" el archivo en memoria.

Lo primero que mapeará será la cabecera, cuyo tamaño está determinado por el campo SizeOfHeaders.
Posteriormente tendrá que cargar el cuerpo del archivo, pero es aquí donde entran las alineaciones. Generalmente el SectionAligment tiene el valor correspondiente al tamaño de una página en memoria (0x1000), entonces el mínimo tamaño que tendrá una sección en memoria será el valor del SectionAlignment asi en disco tenga 1 solo byte. Si es mayor entonces su tamaño corresponderá a (VirtualAddress + VirtualSize) redondeado al múltiplo mayor inmediato del SectionAligment.

Ejemplo:
VirtualAddress = 0x1000
VirtualSize = 0x250

Recueden que vamos en múltiplos del SectionAlignment generalmente 0x1000 entonces 0x1000 + 0x250 = 0x1250 el múltiplo mayor inmediato sería 0x2000. El resto será plasmado con muchos 00 hasta completar el tamaño.

Todo lo de la alineación es con el fin de tener orden y fácilidad de acceso a los datos. Entonces las secciones van cargadas en orden de su VirtualAddres sin importar el orden en que se encuentren en el IMAGE_SECTION_HEADER.

Os ilustro con u pequeño gráfico con el que os aclararéis un poco:


Si comprendiste seguramente se te van vieniendo ideas respecto a las secciones.

Nuestro trabajo con secciones:
Bueno esta será la parte que más agradará seguramente, aquí trataremos teoría y práctica de cosas que podemos hacer con las secciones de un archivo.


Parte teórica:
Espero si si estáis leyendo esto tengas los conceptos anteriores muy claros, serán bastante necesarios para que no te confundas.

¿Que define una sección?
Bueno hablemos sobre los campos involucrados en una sección.
  • NumerOfSections: Este campo contiene el número de secciones del ejecutable. Si agregamos una sección deberemos modificarle.
  • SizeOfImage: Este valor contiene el tamaño del ejecutable en memoria, si añadimos una sección entonces agregaremos datos, necesitamos sumar el valor "físico" de la sección al SizeOfImage.
Ahora hay unos campos que entran de manera opcional de acuerdo al campo "Characteristics" de la sección que agregaremos. Por ejemplo si utilizamos las opciones de InitializedData, deberemos actualizar el valor SizeOfInitializedData perteneciente al IMAGE_OPTIONAL_HEADER.

Parte práctica involucrando teoría:

Creando los datos para nuestra sección:
Ahora necesitaremos armar una sección aplicando la parte conceptual vista más arriba. Miremos los campos de una sección:

  • Name.
  • VirtualSize.
  • VirtualAddress.
  • SizeOfRawData.
  • PointerToRawData.
  • PointerToRelocations.
  • PointerToLineNumbers.
  • NumberOfRelocations.
  • NumberOfLineNumbers.
  • Characteristics.

Hay valores que deberemos calcular y otros que simplemente deberemos utilizarlos. Antes de pasar a como obtener los valores quiero mencionar que el IMAGE_FILE_HEADER tiene la declaración de NumberOfSections secciones. Todas las sección ubicada de manera consecutiva y todas utilizando la estructura standard ya mencionada. Cada sección tiene un tamaño de 0x28 bytes, entonces nuestra sección irá al final de la última sección.

De la sección necesitamos:
  • Su definición.
  • Su contenido.

Su definición es lo que va en IMAGE_SECTION_HEADERS donde proporciona todos los datos para que se cargue con el ejecutable.

Bueno para trabajar lo haremos con un pequeño EXE standard para todos nos podamos ubicar correctamente y puedamos seguir este taller.

Es un ejecutable de 1.5k y solo muestra un mensaje y se cierra, será suficiente por ahora.

Descarga:
Código:
http://dl.dropbox.com/u/26610132/Practica%201.exe
Para armar nuestra sección necesitaremos leer información del archivo, donde estan ubicadas las secciones, etc. Vamos!

Utilizaremos un editor hexadecimal y nada más.
Comencemos:
  • Primero deberemos ubicarnos al inicio y comprobar que es un archivo ejecutable válido, para ello comparamos los 2 primeros bytes con 'MZ'. (Está con azul en la imagen).
  • Ahora deberemos proceder a encontrar el campo l_fanew recueden ver la estructura, lo conseguimos así:
    El campo se encuentra despues de justo 30 WORDs y un WORD equivale a 2 bytes. Entonces 30*2 = 60, ahí se encuentra el campo l_fanew. (Está con rojo en la imagen).


Citar
¿Ey, se han dado cuenta?
Justo en el offset 60 en decimal, se encuentra este valor "80 00 00 00", recueden que el campo es de tamaño DWORD -> 4 bytes. Pero y este campo ¿no apuntaba a la firma 'PE\x0\x0'?
Bueno si, contiene el valor donde empieza la firma 'PE\x0\x0' y posteriormente las demás estructuras. Pero ese valor ¿no es muy grande? Bueno, en realidad no. En windows se utiliza algo llamado Orden Little Endian, donde los bytes se organizan por decirlo al "reves", esto sucede con valores numericos y no con cadenas. Es cuestión de arquitectura y demás, en memoria este valor "80 00 00 00" será equivalente a "00 00 00 80" Vén como ahora tiene sentido? Ah una cosa, todos los valores de la cabecera PE estarán en formato Hexadecimal, y para que nos entendamos, cuando les menciones 60d = 60 en decimal y si menciono 0x80 = 80 en hexadecimal. Con la calculadora de Windows podréis hacer las conversiones.

Bien, ahora tenemos que PE\x0\x0 estará ubicado en el offset: 0x80 o 128d. ¿Es cierto?, bueno podemos darnos cuenta de que sí!. Ahora posterior a esta firma tendremos el IMAGE_FILE_HEADER, justo 4 bytes más adelante, osea en 0x84 o 132d. Tomemos nota con los valores reales:
  • Machine: 01 4C -> Posición: 0x84 o 132d
  • NumberOfSections: 00 02 -> Posición 0x86 o 134d
  • TimeDateStamp: 4F BD 28 3D -> Posición: 0x88 o 136d
  • PointerToSymbolTable: 00 00 00 00 -> Posición: 0x8C o 140d
  • NumberOfSymbols: 00 00 00 00 -> Posición: 0x90 o 144d
  • SizeOfOptionalHeader: 00 E0 -> Posición: 0x94 o 148d
  • Characteristics: 01 0F -> Posición: 0x96 o 150d

Tenemos el primer directorio, vamos con el segundo (?). Bueno era broma quería que vieran el mecanismo. Tienen que leer muy bien la estructura y sus tamaños recuerden:
  • BYTE = 1 byte
  • WORD = 2 bytes
  • DWORD = 4 bytes
  • BYTE * X = X bytes

Haremos exáctamente lo mismo, nos ubicamos al principio de cada directorio y así podemos obtener los datos que necesitamos. Entonces nos ubicamos en 0x98, porque Characteristics está en 0x96 y su tamaño es WORD, entonces el otro campo empieza en 0x98.
De IMAGE_OPTIONAL_HEADER necesitamos por ahora:
  • SizeOfImage -> Lo encontramos con 0x98 + 0x38 = 0xD0 y tiene un valor de 00 30 00 00 (real: 00 00 30 00)
  • SectionAlignment: -> Lo encontramos con 0x98(base IMAGE_OPTIONAL_HEADER) + 0x20 = 0xB8 y tiene un valor 00 10 00 00 (real: 00 00 10 00).
  • FileAlignment: -> Lo encontramos con 0x98 + 0x24 = 0xBC y tiene un valor 00 02 00 00 (real: 00 00 02 00).

Bien lo tenemos, ahora necesitamos ubicarnos en el inicio de IMAGE_SECTION_HEADER. Para ello utilizaremos el inicio del IMAGE_OPTIONAL_HEADER y sumaremos el valor de SizeOfOptionalHeader = 0xE0. Tenemos como resultado: 0x178, como podéis ver estamos en la primera sección. Pero necesitamos la estar parados justo al final de la última para escribir nuestra sección no? Bueno es fácil conseguirla, les había mencionado que el tamaño de esta estructura es 0x28, lo multiplicamos por el valor de NumberOfSections = 2 y tenemos que el final de la última sección está en: 0x178 + (0x28*2) = 0x1C8.

Pero que cerca estamos ahora deberemos generar los datos de nuestra sección, agregaremos una simple cadena "TALLER DE SECCIONES EHN" cuyo tamaño de 0x17 + :
  • Name: El que ustedes quieran que contenga 8 bytes. Usemos '.EHN' sin comillas.
  • VirtualSize: Corresponderá al tamaño de los datos de la sección, nuestro caso es 0x17 bytes
  • VirtualAddress: Corresponderá a la dirección virtual relativa donde se cargará la sección. Como sabemos nuestra sección esta justo al final, si tomamos el Valor del VirtualSize y el VirtualAddress de la sección anterior a nosotros, los sumamos y lo alineamos al SectionAligment podremos calcular nuestro VirtualAddress. Entonces:
    - Tendremos que ubicarnos en la sección anterior, recuerdan que estamos en el final? si restamox 0x28 a 0x1C8 estaremos parados justo en la sección anterior: 0x1A0. Ahora utilizando el mismo procedimiento obtendremos lo valores VirtualSize: 00 00 00 17 y VirtualAddress: 00 00 20 00, procedemos a sumarlos: 0x2017 y alineamos, recuerden el múltiplo mayor inmediato es 0x3000 y listo, tenemos nuestro VirtualAddress.
  • SizeOfRawData: Corresponderá al tamaño de los datos de la sección en disco, piensan que 0x17? Bueno pues no!, En disco al igual que en memoria todo debe ser alineado, y como en disco no hay nadie que nos alineé los datos deberemos hacerlo. ¿Como? Igual que como hacíamos antes solo que ahora alineamos al múltiplo mayor inmediato del FileAlignment. Ya lo habíamos conseguido entonces sería 0x17 y su múltiplo mayor inmediato es 0x200. Esos será el total de datos que deberemos agregar en disco al final del archivo, correspondientes a los datos de nuestra nueva sección.
  • PointerToRawData: Corresponderá a la ubicación o posición en el archivo físicamente de los datos de nuestra nueva sección. Tenemos 2 formas de conseguir dicho valor, una es con el tamaño exácto del archivo y ya, y la otra es sumando los valores PointerToRawData + SizeOfRawData de la sección anterior. De ambas formas llegamos a que es: 0x600, si se dan cuenta es múltiplo del FileAlignment por lo cúal constatamos que la sección anterior a nosotros está alineada.
  • PointerToRelocations: Como ya habíamos mencionado no se utiliza, lo dejamos a 0.
  • PointerToLineNumbers: Como ya lo habíamos mencionado no se utiliza, lo dejamos a 0.
  • NumberOfRelocations: Tampoco se utiliza, lo dejamos a 0.
  • NumberOfLineNumbers: Tampoco se utiliza lo dejamos a 0.
  • Characteristics: Sabía que este momento llegaría  :¬¬. Bueno habíamos mencionado ya algo de este campo en las secciones y era sobre atributos u opciones. Aquí podremos definir que atributos tendrá nuestra sección. Entre los atributos tenemos: Lectura, Escritura, Ejecución y demas. Para referencia exácta de estos valores consulte en las 2 fuentes mencionadas al principio. Por ahora utilizaremos 0xC0 00 00 00 el cual corresponde a atributos de Lectura y escritura.

Datos concretos y legíbles:
  • Name: .EHN -> Valor a plasmar: 2E 45 48 4E 00 00 00 00
  • VirtualSize: 0x17 -> Valor a plasmar: 17 00 00 00
  • VirtualAddress: 0x3000 -> Valor a plasmar: 00 30 00 00
  • SizeOfRawData: 0x200 -> Valor a plasmar: 00 02 00 00
  • PointerToRawData: 0x600 -> Valor a plasmar: 00 06 00 00
  • PointerToRelocations: 00 00 00 00
  • PointerToLineNumbers: 00 00 00 00
  • NumberOfRelocations: 00 00
  • NumberOfLineNumbers: 00 00
  • Characteristics: C0 00 00 00 -> Valor a plasmar: 00 00 00 C0

Cuando digo plasmar no me refiero a "INSERTAR" bytes sino a sobreescribir los 00 suficientes, si insertamos dañamos el ejecutable.
Quedará así:


Ahora nos restan los siguientes detalles:
  • Actualizar el valor del SizeOfImage.
  • Actualizar el valor del NumberOfSections.
  • Añadir los datos de la sección justo al final.

Nuevos valores:
  • SizeOfImage: SizeOfImage + SizeOfRawData de nuestra sección =  0x3200 y lo alineamos al SectionAlignment dando como resultado: 0x4000. Editarlo como 00 40 00 00 recordad lo del Little Endian.
  • NumberOfSections: NumberOfSections +1 = 3 Editarlo como 03 00
  • Añadimos al final 0x200 bytes, entre esos al principio estará nuestra cadena: "TALLER DE SECCIONES EHN", osea la cadena + 0x1E9 byes en 00.

Nuestro ejecutable ya tiene su sección y debe funcionar correctamente. Podemos constatar que la función se agregó con éxito si al cargarlo en OllyDBG e ir a la ventana Memory (M) ver la ImageBase de nuestro ejecutable y constatar que está cargada la otra sección, veamos:

Sección en memoria:


Datos de la sección mapeados en memoria:


Descarga archivo de práctica con sección agregada:
Código:
http://dl.dropbox.com/u/26610132/Practica%201-With%20section.exe

Con esto finalizamos la introducción en las secciones, posteriormente veremos otras situaciones en las que agregar una sección se puede complicar un poco, podéis empezar a seguir el taller con confianza.


Anteriormente había mencionado que se nos vendrían un par de obstáculos, que si no los miramos bien nos pueden dejar algo perdidos. Uno de ellos es el Directorio de datos #12 conocido como BOUND_IMPORT_TABLE.

Descarga archivo de practica #2:
Código:
http://dl.dropbox.com/u/26610132/Practica%202.exe

¿Que problema me puede causar este directorio?
Analicemos un poco las secciones, tiene 3 secciones código, datos y recursos. Es un ejecutable normal compilado en Visual Basic. Se preguntarán ¿Por qué lo elegí?, bueno por que la mayoría de los ejecutables Visual Basic tienen la BOUND_IMPORT_TABLE.
Ustedes se preguntarán ¿Que bronca me traigo con esa estructura?, no es solo mi bronca será la suya también  :D, Me interesa que nos ubiquemos en el final de la última sección (ya sabemos como, sino sabes vuelve a leer la parte superior del taller).


Si miramos nuestro anterior archivo de práctica veremos una gran diferencia, y es que hay algo despues de la última sección, bueno es la BOUND_IMPORT_TABLE.

Te cuento..
Te cuento que necesitas ese espacio para agregar la declaración de tu sección, pero alguien más ya lo está ocupando. Si intentamos escribir encima de ello nos toparemos con esto:


En realidad es fácil explicar el porque nuestro programa termina explotando, mirando el error:
  • 0xC0000005 - STATUS_ACCESS_VIOLATION
En realidad corresponde a una violación por acceso a un lugar al cúal no se puede acceder, cómo punteros nulos o valores inaccesibles en nuestro anillo de permisos. Todo se dá cuando se trata de validar el BOUND_IMPORT_DIRECTORY.

¿Hay solución?
Si, te cuento que hay 2 una menos ortodoxa que la otra pero ambas funcionan. Una preservadora y otra no presevadora.
  • Primera solución: Yoda(creador de LordPE) alguna vez mencionó que se puede establecer el RVA del directorio BOUND_IMPORT_DIRECTORY a 00 porque este era poco importante. Mi amigo karmany opinó al respecto y estoy de acuerdo con él, este directorio tiene como utilidad optimizar entonces me parece que importa. El ejecutable no deja de funcionar pero no preserva el estado original del ejecutable.
  • Segunda solución: Personalmente me parece la mejor y consiste en mover de sitio el BOUND_IMPORT_DIRECTORY. Si sabemos que está justo despues de la última sección, tranquilamente lo desplazamos 0x28 bytes y así tenemos espacio para una función. Posteriormente se actualiza el RVA en el Directorio de datos y lo habríamos solucionado.

Manos a la obra!
Bueno, probemos que todo lo que hemos dicho es cierto e intentemos añadir una sección al ejecutable de práctica teniendo en cuenta las 2 soluciones.

Creo que necesito hacer un breve recuerdo sobre el IMAGE_DATA_DIRECTORY asi que nombraré algunas de sus características.
  • Se ubíca justo antes de IMAGE_SECTION_HEADER.
  • Tiene como tamaño (8*IMAGE_OPTIONAL_HEADER.NumberOfRvaAndSizes).
  • Cuenta con un total de 16 directorios generalmente (aunque puede alterarse).
  • Cada directorio tiene 2 entradas, RVA(DWORD) y Size(DWORD).

Ya les había mencionado que el directorio correspondiente al BOUND_IMPORT_TABLE es el número 12, si aplicamos un poco de matemáticas y nos paramos justo al inicio de IMAGE_SECTION_HEADER y restamos (5*8) estaremos justo en la declaración del directorio. 0x1B0 - 0x28 = 0x188 -> BOUND_IMPORT_DIRECTORY, leamos los valores del directorio.
  • RVA: 0x228
  • Size: 0x20


Relizamos los desplazamientos:
Lo unico que deberemos hacer es cambiar el RVA del BOUND_IMPORT_DIRECTORY por RVA + 0x28 y posteriormente desplazar los datos en el archivo (Con desplazar me refiero a correr, nada de insertar.)

Nuevos datos:
  • RVA: 0x250
  • Size: 0x20


Y desplazando los datos tendríamos algo así:


Si miramos quedó desplazado y los bytes que quedaron en color rojo vendrá a ser el espacio para nuestra sección. Aún si no la agregasemos el ejecutable de igual forma quedaría funcionando y se preservaría.

Igual ya teníamos los datos sobre el archivo de práctica original, para aplicar el segundo método cambiamos el RVA por 00 00 00 00 y el Size por 00 00 00 00 y listo.

Descarga práctica con sección y método de desplazamiento de la BOUND_IMPORT_TABLE:
Código:
http://dl.dropbox.com/u/26610132/Metodo%20desplazamiento.exe

Descarga práctica con sección y método de eliminación de la BOUND_IMPORT_TABLE:
Código:
http://dl.dropbox.com/u/26610132/Metodo%20de%20eliminacion.exe

Con esto habríamos terminado la parte de agregar secciones aunque agregaré lo siguiente:
El otro problema sería para más que un problema un caso de profundización y vendría a ser el siguiente. Primero habría que hablar de un límite de secciones que si mal no recuerdo en Windows XP es de 96 y en >= Windows Vista es de 0xFFFF, todo cuestion de versión del Loader. Ahora si físicamente te quedas sin espacio porque por ejemplo ya tienes enseguida de la última sección la primera sección del ejecutable.

¿No se pueden agregar más?
Claro que se puede y tienes que tener en cuenta el SizeOfHeaders, lo puedes expandir y seguir agregando secciones. Solo que deberás tener un factor en cuenta, si aumentaste el tamaño ahí deberías arreglar nuevamente los datos de todas las secciones, VirtualAddress y PointerToRawData de cada una.

Esto es todo sobre agregar secciones, practiquen y si tienen dudas para eso estamos, disfrutenlo!, hasta el siguiente tema.


Bueno hablaremos sobre el orden de las secciones en el cuerpo del archivo. Si hemos visto determinada cantidad de archivos ejecutables nos daremos cuenta que en el cuerpo del archivo se preserva el orden en el que están declaradas las secciones.

¿Es necesario que se respete este orden?
No, realmente las secciones en disco pueden estar ubicadas en completo desorden mientras cumplan el requisito de estar bien referenciadas en su declaración (IMAGE_SECTION_HEADER). Me refiero a que todos los punteros deben estar correctos.

¿Por que no afecta el orden de las secciones?
En realidad como mencioné las secciones en disco se ven referenciadas o "apuntadas" por su definición en el IMAGE_SECTION_HEADER, el mapeo en memoria no se verá afectado ya que igual esta mapeando datos que provienen de distintias posiciones en el archivo. Si os preguntáis por qué no se puede cambiar el orden de las secciones en su declaración? En realidad por problemas de fragmentación y garantía, no se puede asegurar si no se escriben en orden posicional no se pisen entre sí.

¿No entiendes lo de desorden?
Bueno espero este gráfico te ilustre un poco:


Si lo llevamos a la parte práctica podríamos sacar las siguientes conclusiones:
  • El orden del IMAGE_SECTION_HEADER no se debe alterar.
  • Tendremos que modificar el orden del contenido de las secciones.
  • Tendremos que actualizar los campos PointerToRawData y SizeOfRawdata de las secciones.

Descar archivo de práctica número #3:
Código:
http://dl.dropbox.com/u/26610132/Practica%203.exe

Nuestro archivo:
  • Tiene 3 secciones (.text, .idata y .data).
  • Intercambiaremos .text y .data en el cuerpo del archivo.

Manos a la obra!
  • Primero obtendremos datos de las secciones, recordad lo siguiente: los cambios serán en físico con el hecho de que en memoria el archivo se cargará igual siempre.
    • Sección .text: PointerToRawData: 0x200 SizeOfRawData: 0x200
    • Sección .idata: PointerToRawData: 0x400 SizeOfRawData: 0x200
    • Sección .data: PointerToRawData: 0x600 SizeOfRawData: 0x200
  • Todas las secciones tienen el mismo tamaño, lo cual nos facilitará las cosas.
  • Nuevos datos:
    • Sección .text: PointerToRawData: 0x600 SizeOfRawData: 0x200
    • Sección .idata: PointerToRawData: 0x400 SizeOfRawData: 0x200
    • Sección .data: PointerToRawData: 0x200 SizeOfRawData: 0x200

Declaración de IMAGE_SECTION_HEADER antes:


Declaración de IMAGE_SECTION_HEADER después:


En disco debemos cambiar todos los 0x200 bytes de una sección por otra:

Nueva ubicación sección .text:


Nueva ubicación sección .data

Eso es todo, lo considero uno de esos detallitos que son importantes resaltar. Ya podéis prácticar cualquier duda pregunta!, Hasta el siguiente tema.


Hola chicos, en este nuevo capitulo hablaremos sobre como ampliar la sección de un archivo ejecutable. Requiere todo lo visto previamente, algo de cuidado y solo un poquito de imaginación, eso es todo.

¿Por qué podemos querer ampliar una sección?
Podemos verlo desde distintas perspectivas pero siempre llegando a la conclusión de que nos crearemos un espacio en el archivo. Al agregar una sección agregamos datos en un espacio que nosotros mismos previamente creamos, al ampliar una sección con seguridad queremos meter datos y nuevamente nos estamos haciendo un espacio, solo que ahora es "compartido".

¿Que debemos hacer para ampliar una sección?
Debemos tener claro que ampliaremos el rango de los valores de una sección física y virtualmente. Hay que tener especial cuidado si ampliamos una sección que se encuentra en medio de otras 2, puesto que tendremos que modificar los valores de la siguiente sección para no desalinear el ejecutable.

Ilustración de una sección ampliada:


Descargar archivo de práctica #4:
Código:
https://dl.dropbox.com/u/26610132/Practica%204.exe

Manos a la obra!
Ampliaremos las sección .idata 0x150 bytes en el archivo de práctica.

Debemos:
  • Obtener los siguientes valores de la sección que ampliaremos:
    • VirtualSize: 0x98
    • PointerToRawData: 0x400
    • SizeOfRawData: 0x200
  • Si hay una sección posterior a la que ampliaremos obtedremos de dicha sección (.data) los siguientes valores:
    • VirtualAddress: 0x3000
    • VirtualSize: 0x4
    • PointerToRawData: 0x600
    • SizeOfRawData: 0x200
  • Debemos alinear la cantidad de bytes que ampliaremos en base al FileAlignmente: 0x150 Alineado 0x200 : 0x200 y será la cantidad que ampliaremos.
  • Nos ubicamos al final de la sección que ampliaremos: PointerToRawData + SizeOfRawData: 0x600.
  • Añadimos la cantidad de bytes ya caculada.
  • Actualizaremos valores de la sección de la siguiente manera:
    • VirtualSize: Teniendo en cuenta que este tamaño corresponde a los bytes que se mapearán en memoria debemos saber cuanto espacio usaremos. Podemos escribir en el nuevo espacio generado y modificar este campo en base hasta donde queremos que mapee. En este caso pongámoslo a 0x400 para que cubra todos los bytes de la sección.
    • SizeOfRawData: Aumentaremos el valor de bytes alineados que agregamos: 0x200 + 0x200 : 0x400.
  • Debemos actualizar de la sección posterior (si la hay) los siguientes valores:
    • VirtualAddress: Se actualizará unicamente si al sumar VirtualAddress + SizeOfRawData de la sección ampliada el resultado es mayor que el VirtualAddress de esta sección. En nuestro caso no se cumple y no modificamos el valor.
    • PointerToRawData: Se actualizará con el valor resultante de la suma de los valores PointerToRawData + SizeOfRawData de la sección ampliada, en nuestro caso 0x400 + 0x400 : 0x800.
  • Debemos actualizar el SizeOfImage con el valor equivalente a: VirtualAddress + (VirtualSize Alineado a SectionAlignment): 0x3000 + (0x400 Alineado 0x1000 = 0x1000) = 0x4000.

Con esto ya debebemos tener nuestro ejecutable funcionando y totalmente alineado.
Nota: Cuando la sección que se amplíe también este referenciada por el directorio de datos, debes actualizar el tamaño en el mismo.


Nuevos bytes en disco:


Nuevos bytes en memoria:


Descarga archivo resultante (con una pequeña modificación):
Código:
https://dl.dropbox.com/u/26610132/Practica%204%20Resultado.exe

Con esto terminamos este capitulo, practiquen y no olviden poner sus dudas, Nos vemos en el próximo.


12  Programación / Ingeniería Inversa / [WarScriptZone]Manual IsDebuggerPresent en: 8 Enero 2012, 01:09 am
Código
  1. /*----------------------------------------------------
  2. - Small script for undetect IsDebuggerPresent
  3. - The Swash
  4. - WarScriptZone
  5. ------------------------------------------------------*/
  6. exec
  7. mov eax, dword ptr fs:[30]
  8. ende
  9. cmp [eax+2], 1, 1
  10. jnz Exit
  11. MSGYN "Debugger detected, want unable detection?"
  12. mov [eax+2], 0, 1
  13. Exit:
  14. ret

Un saludo ;)
13  Sistemas Operativos / GNU/Linux / [Solucionado] Problema con instalación WLAN Debian en: 24 Diciembre 2011, 00:14 am
Buenas tardes tegáis vosotros,
Vengo a molestarles con un problema que tengo a la hora de la compilación e instalación del WLAN de mi notebook COMPAQ MINI C10-811LA.

He descargado mi driver de realtek cuyo README dice que para instalarlo hay que usar.
make
make install

Lo extraño es que anteriormente con Ubuntu 10.10 había compilado e instalado perfecto pero con Debian cargo el siguiente drama:

Código:
root@personal:/home/ivan/drivers/rtl92ce# make
make -C /lib/modules/2.6.32-5-686/build M=/home/ivan/drivers/rtl92ce modules
make[1]: se ingresa al directorio `/usr/src/linux-headers-2.6.32-5-686'
  CC [M]  /home/ivan/drivers/rtl92ce/base.o
/home/ivan/drivers/rtl92ce/base.c: In function ‘_rtl_init_mac80211’:
/home/ivan/drivers/rtl92ce/base.c:320: error: ‘IEEE80211_HW_CONNECTION_MONITOR’ undeclared (first use in this function)
/home/ivan/drivers/rtl92ce/base.c:320: error: (Each undeclared identifier is reported only once
/home/ivan/drivers/rtl92ce/base.c:320: error: for each function it appears in.)
/home/ivan/drivers/rtl92ce/base.c: In function ‘rtl_watchdog_wq_callback’:
/home/ivan/drivers/rtl92ce/base.c:1258: error: implicit declaration of function ‘ieee80211_connection_loss’
make[4]: *** [/home/ivan/drivers/rtl92ce/base.o] Error 1
make[3]: *** [_module_/home/ivan/drivers/rtl92ce] Error 2
make[2]: *** [sub-make] Error 2
make[1]: *** [all] Error 2
make[1]: se sale del directorio `/usr/src/linux-headers-2.6.32-5-686'
make: *** [all] Error 2

Busque bastante en google y probé hasta el cansancio distintas soluciones sin éxito.
Uso Debian Squeeze 6.0.0:
Linux personal 2.6.32-5-686 #1 SMP Wed Jan 12 04:01:41 UTC 2011 i686 GNU/Linux

y el dispositivo WLAN es:
Network controller: Realtek Semiconductor Co., Ltd. RTL8188CE 802.11b/g/n WiFi Adapter (rev 01)


Un saludo y gracias por vuestra ayuda.

PD: Instalé la 6.0.0 por el problema con el kernel 2.6.38 y superiores con baterias de laptops.
Encontré algo que no supe interpretar bien pero depronto sea de ayuda:
Código:
http://www.spinics.net/lists/linux-wireless/msg78220.html
14  Programación / Scripting / [Python] Little Script Codepad en: 2 Noviembre 2011, 03:35 am
Código
  1. #------------------------------------------------------------------------------
  2. # Pequeño script de escritorio para utilizar Codepad.org
  3. # Programmer: The Swash
  4. # Website: http://h-sec.org
  5. #------------------------------------------------------------------------------
  6.  
  7. import urllib, urllib2, re
  8.  
  9. def GetResponse(lang, code):
  10.    code = urllib.urlencode({'lang':lang, 'code':code,'run':'True','submit':'Submit'})
  11.    web = urllib2.urlopen('http://codepad.org',code)
  12.    source = web.read()
  13.  
  14.    resp = re.findall('<td width="100%" style="vertical-align: top">\n<div class="highlight">\n<pre>\n([^\b]+)</pre>', source)
  15.    temp = resp[0]
  16.    if re.findall('<a href="#line-[\d]">(.+)</a>', temp):
  17.        err = re.findall('<a href="#line-[0-9]">(.+)</a>', temp)
  18.        val = re.sub('<a href="#line-[0-9]">(.+)</a>', err[0], temp)
  19.        return val
  20.    else:
  21.        return temp
  22.  
  23. langs = ('Python','C','C++','PHP','Perl','Ruby')
  24. lang = 0
  25. print "Bienvenido, lenguajes disponibles: \n"
  26. length = len(langs)
  27. for i in range(length):
  28.    print str(i+1) + '- ' + langs[i]
  29.  
  30. while not((ord(str(lang)) >= 49) and (ord(str(lang)) <= 54)):
  31.    print "Elige el numero correspondiente: "
  32.    lang = input()
  33.  
  34. try:
  35.    path = raw_input("Ingrese la ubicacion completa del archivo: ")
  36.    lfile = open(path, "r")
  37.    buff = lfile.read()
  38.    lfile.close()
  39.  
  40. except:
  41.    print "Error al procesar archivo"
  42.    exit()
  43.  
  44. Resp = GetResponse(langs[lang-1], buff)
  45. print "Output:\n"
  46. print Resp
  47. raw_input("Presione enter para salir..")

Un pequeño script para gestión con Codepad.
Acepto críticas.

Un saludo.
15  Programación / Scripting / [Python] Goo - Acorta tu URL en: 24 Octubre 2011, 06:37 am
Código
  1. #----------------------------------------------------------
  2. # Obtener URL acortada mediante http://goo.gl
  3. # Programador: The Swash
  4. # Agradecimientos: Psymera, 11Sep, [Zero] y todo h-sec
  5. # Website: http://h-sec.org
  6. #----------------------------------------------------------
  7.  
  8. import socket, urllib, re
  9. def GetGooURL(url):
  10.    header = ['POST /api/shorten HTTP/1.1\r\n',
  11.              'Host: goo.gl\r\n',
  12.              'Content-Type: application/x-www-form-urlencoded;charset=utf-8\r\n',
  13.              'Content-Length: 41\r\n',
  14.              'Connection: close\r\n\r\n',
  15.              'URLENCODE']
  16.    if re.match('^http://', url):
  17.        url2 = url
  18.    else:
  19.        url2 = 'http://' + url
  20.    address = socket.gethostbyname('goo.gl')
  21.    link = urllib.urlencode({'url':url2})
  22.    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  23.    header[5] = link + '&security_token\r\n'
  24.    length = len(header)
  25.    try:
  26.        sock.connect((address,80))
  27.        for i in range(length):
  28.            sock.send(header[i])
  29.        buff = sock.recv(1024)
  30.    except:
  31.        return 'Error de conexion'
  32.  
  33.    sock.close()
  34.    data = re.findall('Location: (.+)\r\n', buff)
  35.    return data[0]
  36.  
  37. url = GetGooURL('h-sec.org')
  38. print url
  39. raw_input()

Hola amigos, les traigo este pequeño código que me llevó largo rato por los encabezados HTTP. Como dijo 11Sep puede acortarse mucho usando urllib, pero en definitiva no era mi intención.

Cualquier critica constructiva es bien recibida.

Un saludo.
16  Programación / Programación C/C++ / [C] Listas enlazadas. en: 15 Octubre 2011, 02:09 am

Información general:
Las listas enlazadas son un recurso dinámico muy potente que nos permite realizar tareas que generalmente podríamos requerir con arrays, pero se impide en objetos estáticos y en dinámicos sería muy complicado.
Una lista enlazada se basa en una estructura, la cual será el esqueleto o prototipo del contenido, y al final requerirá tener un puntero hacia la siguiente estructura del mismo tipo, es decir están enlazadas por su ubicación (dirección de memoria).


Funcionamiento y estructura:
Primero debemos tener la estructura o prototipo en el cual definiremos los datos que emplearemos y como debe ser, un puntero a otra estructura del mismo tipo:

Código
  1. typedef struct _nodo
  2. {
  3.    int valor;
  4.    struct _nodo * pNext;
  5. }_Nodo;

Utilizamos typedef para evitar estar utilizando struct _nodo para todo, así abreviamos y hacemos el código más legible.
Código
  1. typedef _Nodo * _pNodo;

Hay unas bases a tener en cuenta para trabajar con listas enlazadas:
  • El final de una lista será determinada por un puntero con valor NULL, es decir el último elemento tendrá como siguiente elemento a NULL.
  • Los elementos se pueden recorrer en un solo sentido (Inicio - Final), debido a que solo tenemos un apuntador al siguiente y no al anterior, las listas que cuentan con esta opción se conocen como doblemente enlazadas. Las trataremos en otro tema.
  • Es muy importante mantener siempre el valor inicial de la lista, en caso de perderle sería muy difícil de recuperar.
  • Es muy importante controlar muy bien los punteros hacia los elementos, un simple número distinto y podríamos causar perdida de control sobre el programa.

Recordemos, cada elemento tiene un apuntador al siguiente, por ello se llaman enlazados:



Para trabajar con listas, deberemos implementar una serie de funciones y procedimientos para el manejo de sus elementos entre ellas:
  • Crear lista nueva.
  • Insertar elemento (Al inicio, al final y posterior al otro elemento).
  • Buscar elemento.
  • Eliminar elementos(El primer elemento, un elemento en base a su dirección).
  • Imprimir contenido de listas (Este uso ya depende del usuario).

Creación de una lista nueva:
Para crear una nueva lista teniendo en cuenta el prototipo lo que utilizaremos son punteros, por lo cual suele ser más cómodo utilizar un typedef para más comodidad. En cuanto a teoría para crear una nueva lista deberíamos:
  • Crear una función cuyo tipo de valor de retorno será el mismo del prototipo.
  • La función creará una estructura dinámica con el tamaño del prototipo (malloc).
  • Se establecerá un valor inicial para los elementos de la estructura.
  • El apuntador al siguiente elemento será NULL, esto identificará la lista como vacía.
  • La función retornará la dirección de la lista creada (valor retornado por malloc).
Código
  1. _pNodo CrearLista(int valor)
  2. {
  3.    _pNodo Lista;
  4.  
  5.    Lista = (_pNodo) malloc (sizeof(_Nodo));
  6.    Lista->valor = valor;
  7.    Lista->pNext = NULL;
  8.  
  9.    return Lista;
  10. }

Inserción de elementos:
Para insertar nuevos elementos deberemos tener una lista previamente creada y contar con su referencia para acceder a ella, además se deberán hacer múltiples comparaciones con fines de prevenir errores, como cuando la lista está vacía, o el lugar donde se va a ingresar el nuevo elemento, etc.

Insertar elemento al final:
  • La función requerirá el valor del elemento a ingresar y el inicio de la lista.
  • Crear un nuevo prototipo de estructura, lo llamaremos Nodo.
  • Comprobar si la lista está vacía, en tal caso simplemente modificar la dirección a la que apunta por el nodo creado (NULL x Dirección nuevo Nodo). En caso de no estar vacía deberemos recorrer todos los elementos hasta reconocer al que apunta al NULL y editar por la dirección del nuevo Nodo.
  • En caso de recorrer la lista no olvidar utilizar una variable auxiliar para no perder la lista principal.
  • Al ser un elemento que va al final, estará obligado a tener su campo de siguiente estructura a NULL.
  • En mi caso bajo utilice la idea de retornar la dirección del nuevo elemento insertado, muchos códigos retornan la misma lista ingresada, cuando en realidad esta no sufre modificaciones y no es útil.
Código
  1. _pNodo InsertarElementoAlFinal(int valor, _pNodo ListaInicial)
  2. {
  3.    _pNodo NuevoNodo;
  4.    _pNodo Auxiliar = ListaInicial;
  5.    NuevoNodo =  malloc(sizeof(_Nodo));
  6.  
  7.    NuevoNodo->valor = valor;
  8.    NuevoNodo->pNext = NULL;
  9.  
  10.    if (ListaInicial->pNext == NULL)
  11.    {
  12.        ListaInicial->pNext = NuevoNodo;
  13.    }
  14.    else
  15.    {
  16.        while(Auxiliar->pNext != NULL)
  17.        {
  18.            Auxiliar =  Auxiliar->pNext;
  19.        }
  20.        Auxiliar->pNext = NuevoNodo;
  21.    }
  22.  
  23.    return NuevoNodo; /* Retornamos dirección del elemento insertado */
  24. }

Inserción de elementos al principio:
  • La función requerirá el valor del elemento a ingresar y el inicio de la lista.
  • Crear un nuevo Nodo, asignar el valor correspondiente.
  • El valor del campo siguiente elemento del Nodo creado deberá ser correspondiente al valor principal de la lista.
  • Retornamos el nuevo inicio de lista, correspondiente al nuevo Nodo.
Código
  1. _pNodo InsertarElementoAlInicio(int valor, _pNodo ListaInicial)
  2. {
  3.    _pNodo NuevoNodo;
  4.    NuevoNodo = malloc(sizeof(_Nodo));
  5.    NuevoNodo->valor = valor;
  6.    NuevoNodo->pNext = ListaInicial;
  7.  
  8.    return NuevoNodo; /* Retornamos nueva lista inicial */
  9. }

Inserción de un elemento posterior a otro:
  • La función requerirá el valor del elemento a ingresar y la dirección del elemento anterior a donde ingresaremos el nuevo.
  • Creamos el nuevo nodo y asignamos los valores correspondientes.
  • El nuevo Nodo creado ahora apuntará al elemento que apuntaba el Nodo anterior a este.
  • El Nodo anterior apuntará al nuevo Nodo insertado.
  • Retornamos la dirección del nuevo Nodo.
Código
  1. _pNodo InsertarElementoPosterior(int valor, _pNodo ElementoAnterior)
  2. {
  3.    _pNodo NuevoNodo;
  4.    NuevoNodo = malloc(sizeof(_Nodo));
  5.  
  6.    NuevoNodo->valor = valor;
  7.    NuevoNodo->pNext = ElementoAnterior->pNext;
  8.  
  9.    ElementoAnterior->pNext = NuevoNodo;
  10.  
  11.    return NuevoNodo; /* Retornamos dirección del elemento insertado */
  12. }

Eliminación de elementos:
La eliminación de elementos también es una función muy importante a la hora de trabajar con listas, sus implementaciones pueden ser muchas debido a la gran cantidad de casos posibles, como eliminar el primer o último elemento, eliminar un elemento según su dirección, posterior a otro, o buscando por valor (Eliminar primero, último o todos). Yo mostraré 2 casos, eliminando el primer elemento y eliminando por dirección del elemento.

Eliminación del primer elemento:
  • Para esta función únicamente necesitaremos el inicio de lista.
  • Usaremos una variable auxiliar la cual nos ayudará a almacenar datos temporalmente.
  • Comprobamos si la lista está vacía, en tal caso dejamos todo igual.
  • Almacenamos el elemento inicial de lista en la variable auxiliar.
  • Ahora el inicio de lista apuntará tendrá como valor el elemento al cual apuntaba.
  • Liberamos el espacio de memoria que contiene la variable auxiliar con free().
Código
  1. _pNodo EliminarPrimerElemento(_pNodo Lista)
  2. {
  3.    _pNodo Auxiliar;
  4.    Auxiliar = Lista;
  5.  
  6.    if (Auxiliar->pNext == NULL)
  7.    {
  8.        return Lista; /* Si no hay más elementos dejamos todo igual */
  9.    }
  10.    Lista = Auxiliar->pNext;
  11.    free(Auxiliar);
  12.  
  13.    return Lista; /* Retornamos la nueva base de la lista */
  14. }

Eliminar elemento por su dirección:
  • Necesitaremos inicio de lista y dirección del elemento a eliminarla.
  • Utilizamos una variable auxiliar para buscar el elemento anterior al elemento a eliminar recorriendo toda la lista.
  • En caso de no encontrar el elemento comparando su dirección retornamos 0 (FALSE)
  • Comprobamos si el elemento a eliminar es el último, en tal caso el elemento anterior apuntará a NULL, de lo contrario el elemento anterior al que eliminamos apuntará al elemento que apuntaba el elemento que eliminamos.
  • Liberamos la memoria del elemento a eliminar.
  • Retornamos 1(TRUE).
Código
  1. int EliminarElemento(_pNodo Elemento, _pNodo Lista)
  2. {
  3.    _pNodo Auxiliar;
  4.    Auxiliar = Lista;
  5.    while (Auxiliar != NULL)
  6.    {
  7.        if (Auxiliar->pNext == Elemento)
  8.        {
  9.            break;
  10.        }
  11.        Auxiliar = Auxiliar->pNext;
  12.    }
  13.    if (Auxiliar == NULL)
  14.    {
  15.        return 0;
  16.    }
  17.    else
  18.    {
  19.        if (Elemento->pNext == NULL)
  20.        {
  21.            Auxiliar->pNext = NULL;
  22.        }
  23.        else
  24.        {
  25.            Auxiliar->pNext = Elemento->pNext;
  26.        }
  27.  
  28.        free(Elemento);
  29.        return 1;
  30.    }
  31. }

Búsqueda de elementos:
La búsqueda de elementos generalmente se realiza para localizar la posición de un objeto comparando su valor, ya que si se tiene su dirección simplemente haciendo referencia podríamos acceder a su contenido.

Búsqueda por valor:
  • Necesitaremos el valor a buscar y el inicio de lista.
  • Utilizaremos una variable auxiliar para no perder el inicio de la lista.
  • Recorremos toda la lista y vamos comparando si cada elemento es igual al buscado.
  • Una vez localizado simplemente retornamos la dirección del elemento.
  • Si no se lo encuentra se retornará NULL.
Código
  1. _pNodo BuscarElemento(int valor, _pNodo Lista)
  2. {
  3.    _pNodo Auxiliar;
  4.  
  5.    Auxiliar = Lista;
  6.    while(Auxiliar != NULL)
  7.    {
  8.        if (Auxiliar->valor == valor)
  9.        {
  10.            break;
  11.        }
  12.        Auxiliar = Auxiliar->pNext;
  13.    }
  14.    return Auxiliar; /* Retornamos dirección del elemento encontrado */
  15. }

Bueno, espero hayan comprendido el articulo y prometo trabajar más estructuras de datos.
Hasta la próxima.

Saludos.
17  Programación / Programación C/C++ / [C] Variación cifrado ROT. en: 3 Octubre 2011, 04:13 am
Buenas noches,
Creo que a Zero le había comentado de mi idea de darle una pequeña variación al cifrado ROT común.

Idea:
  • Utilizar una contraseña numérica con la cual se hará la rotación.
  • Se operará en bloques igual a la longitud de números de la contraseña.
  • Individualmente actuará cada número a la hora de cifrar.
  • Si el dígito actual es menor que 5 se suma, de lo contrario se resta.
  • El tercer parámetro es para evitar prácticamente replicar la función para descifrar.

Les dejo un pequeño ejemplo, lo pueden adaptar y optimizar. Si quieren adaptarlo a binarios deberán añadir comprobación del límite ASCII y no usar strlen.

Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4.  
  5. char * ROTPassword(char * String, int password,int descifrar);
  6.  
  7.  
  8. int main()
  9. {
  10.    printf("%s ", ROTPassword("hsec",152,0));
  11.    printf("%s ", ROTPassword("jnfe",152,1));
  12.    getchar();
  13.    return 0;
  14. }
  15.  
  16. char * ROTPassword(char * String, int password, int descifrar)
  17. {
  18.    int array[10] = {0};
  19.    int passcopy = password, counter = 0,i,strlength, passlength = 0;
  20.    char * cifrado;
  21.  
  22.    strlength = strlen(String);
  23.    while(passcopy >= 1)
  24.    {
  25.        array[counter] = (passcopy % 10);
  26.        passcopy /= 10;
  27.        counter++;
  28.    }
  29.  
  30.    cifrado = (char*) malloc(strlength+1);
  31.    memset(cifrado,0,strlength+1);
  32.  
  33.    for (i = 0; i < strlength; i++)
  34.    {
  35.        if (array[passlength] < 5)
  36.        {
  37.            (descifrar == 1)?cifrado[i] = String[i] - array[passlength]: (cifrado[i] = String[i] + array[passlength]);
  38.        }
  39.        else
  40.        {
  41.            (descifrar == 1)?cifrado[i] = String[i] + array[passlength]: (cifrado[i] = String[i] - array[passlength]);
  42.        }
  43.        passlength++;
  44.        if (passlength >= counter) passlength = 0;
  45.  
  46.    }
  47.  
  48.    return cifrado;
  49. }

Un saludo, Gracias Zero.
18  Seguridad Informática / Análisis y Diseño de Malware / [MASM][UserMode]Hook OpenProcess en: 11 Julio 2011, 23:55 pm
Código
  1. .386
  2. .model flat, stdcall
  3. option casemap:none
  4.  
  5. include C:\masm32\include\windows.inc
  6. include C:\masm32\include\kernel32.inc
  7. includelib C:\masm32\lib\kernel32.lib
  8.  
  9. .data
  10. ProcessId        dd 0
  11. ProcessProtect   dd 0
  12. hProcess         dd 0
  13. APIAddress       dd 0
  14. SnapshotHandle   dd 0
  15. DistanceFunc     dd 0
  16. fAddress         dd 0
  17. Bytesw           dd 0
  18. _JMP             db 5 dup(?)
  19. Diference        dd 0
  20. Buff             db 0
  21. _PROCESSENTRY32  PROCESSENTRY32 <?>
  22. Process          db "taskmgr.exe",0   ;Process to Hook
  23. API              db "OpenProcess",0
  24. lLibrary         db "kernel32.dll",0
  25. Protect          db "notepad.exe",0   ;Process to Protect
  26.  
  27. .code
  28. start:
  29. mov dword ptr[_PROCESSENTRY32.dwSize], 0128h
  30.  
  31. _Begin:
  32. invoke CreateToolhelp32Snapshot,TH32CS_SNAPPROCESS,0
  33. mov dword ptr[SnapshotHandle],eax
  34.  
  35. _Cmp:
  36.    invoke Process32Next,dword ptr[SnapshotHandle], addr _PROCESSENTRY32
  37.    mov edi, eax
  38.    invoke lstrcmp,addr Process, addr _PROCESSENTRY32.szExeFile
  39.    or eax, eax
  40.    jz _GetPID2
  41.    invoke lstrcmp,addr Protect, addr _PROCESSENTRY32.szExeFile
  42.    or eax, eax
  43.    jz _GetPID
  44.  
  45. _Continue:    
  46.    or edi, edi
  47.    jz _Exit
  48.    jnz _Cmp
  49.  
  50. _Proc:    
  51.    invoke GetModuleHandle, addr lLibrary
  52.    invoke GetProcAddress, eax, addr API
  53.    mov dword ptr[APIAddress], eax
  54.  
  55.    mov eax, offset _EndHook
  56.    mov ebx, offset _Hook
  57.    sub eax, ebx
  58.    mov dword ptr[DistanceFunc], eax
  59.  
  60.    invoke OpenProcess,PROCESS_ALL_ACCESS,FALSE,dword ptr [ProcessId]
  61.    mov dword ptr [hProcess], eax
  62.    invoke ReadProcessMemory,dword ptr[hProcess], dword ptr [APIAddress], addr Buff, 1, addr Bytesw
  63.    cmp byte ptr [Buff], 0E9h
  64.    jz _Exit
  65.    invoke VirtualAllocEx,dword ptr [hProcess],NULL,dword ptr[DistanceFunc],MEM_RESERVE or             MEM_COMMIT,PAGE_EXECUTE_READWRITE
  66.    mov dword ptr [fAddress], eax
  67.    mov ecx, offset _Hook
  68.    invoke VirtualProtect,ecx,10,PAGE_EXECUTE_READWRITE,addr Bytesw
  69.    mov ebx, dword ptr[APIAddress]
  70.    add ebx, 5
  71.    mov dword ptr[_Hook + 1], ebx
  72.    mov ebx, dword ptr[ProcessProtect]
  73.    mov dword ptr[_Hook + 6], ebx
  74.    mov ecx, offset _Hook
  75.    invoke WriteProcessMemory,dword ptr[hProcess], dword ptr [fAddress], ecx, dword ptr [DistanceFunc], addr Bytesw
  76.    invoke VirtualProtectEx,dword ptr[hProcess],dword ptr [APIAddress], 5, PAGE_EXECUTE_READWRITE, addr Bytesw
  77.    mov byte ptr [_JMP], 0E9h
  78.    mov edx, dword ptr [fAddress]
  79.    add dword ptr [APIAddress],5
  80.    sub edx, dword ptr [APIAddress]
  81.    mov dword ptr [_JMP +1], edx
  82.    sub dword ptr [APIAddress], 5
  83.    invoke WriteProcessMemory,dword ptr [hProcess], dword ptr[APIAddress], addr _JMP, 5, addr Bytesw
  84.    invoke CloseHandle, dword ptr [hProcess]
  85.  
  86. _Exit:
  87.    invoke ExitProcess,0
  88.  
  89. _Hook:
  90.    mov eax, 00000000h ; API Address
  91.    mov ecx, 00000000h ; PID
  92.  
  93.    push ebp           ; Stack frame
  94.    mov ebp, esp
  95.  
  96.    pushad
  97.    cmp ecx, dword ptr [ebp + 10h]
  98.    jz _Hooked                     ; If is equal jump to Hooked
  99.    popad                          ; Restaure registers
  100.    jmp eax                        ; Jump to API + 5
  101.  
  102. _Hooked:
  103.    popad
  104.    mov esp, ebp
  105.    pop ebp
  106.    mov eax, 0
  107.    retn 0Ch
  108. _EndHook:    
  109.  
  110. _GetPID:
  111.    mov eax, dword ptr [_PROCESSENTRY32.th32ProcessID]
  112.    mov dword ptr[ProcessProtect],eax
  113.    jmp _Found
  114.  
  115. _GetPID2:
  116.    mov eax, dword ptr [_PROCESSENTRY32.th32ProcessID]
  117.    mov dword ptr[ProcessId],eax
  118.    jmp _Cmp2
  119.  
  120. _Found:
  121.    cmp [ProcessId],0
  122.    jz _Cmp
  123.    jmp _Cmp2
  124.  
  125. _Cmp2:
  126.    cmp dword ptr[ProcessProtect],0
  127.    jnz _Proc
  128.    jmp _Cmp
  129.  
  130. end start

Información:
Este es el pequeño ejemplo de enganchar(Hookear) a la función Kernel32.OpenProcess la cual permite abrir un proceso por muchos motivos (Cerrarlo, obtener información, modificar, etc).

¿Que hace exactamente?
Sencillamente enganchamos esa función y así podemos verificar si quieren abrir el proceso que nosotros designemos a proteger.

Ustedes pueden hacerle su respectiva adaptación a condiciones etc, pero me enfoque en un ejemplo y en aprender.

Mis mayores agradecimientos a Lelouch (Como me soportaste xD) y a [Zero].
Dedicado a todos mis mentores :P (Sobra mencionarlos)
Saludos.

19  Seguridad Informática / Análisis y Diseño de Malware / [Documento]Formato PE bajo Windows - Español en: 30 Junio 2011, 19:15 pm

Información:
Este documento trata de explicar la mayor parte de la estructura de los archivos ejecutables de Windows, esta basado en la información oficial de microsoft y su ventaja es que esta en lengua española bien graficado y explicado.

Descarga - Lectura online:
http://www.box.net/shared/4156t5rfv8tr5v4bgo19
20  Seguridad Informática / Análisis y Diseño de Malware / [Tutorial]Relocaciones en ejecutables en: 5 Junio 2011, 01:36 am
Que tal amigos, les traigo un pequeño tutorial que me quedo algo corto porque no me pude extender más en el tema pero traté de explicarlo lo mejor posible.
Espero les guste.

Link:
Código:
http://www.box.net/shared/v9pcb3bzzv
Páginas: 1 [2] 3 4
WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines