Programación en Lenguaje Ensamblador

-El Verdadero Lenguaje de las Máquinas-

Darwin Digital

–Evolución y Extinción Tecnológica–

Alguna vez alguien me dijo que los mas poderosos sistemas de computación solo existen al interior de las grandes empresas de desarrollo de software y algunos centros de investigación y que lejos de ser estáticos cambian y evolucionan con el paso del tiempo. Esto se relaciona con una interesante y blasfema discusión sobre la evolución de las especies.

Hay extremistas que dicen que los seres vivos actuales fueron creados tal y como los conocemos. Esta teoría se conoce como la “Teoría del Mínimo Absoluto” y dice que si retrocedemos en la evolución, quitándole cosas, llega un momento en que una entidad deja de existir como tal. Esto aunque parece tener algo de lógica, no tiene nada que ver con la realidad, pues precisamente la evolución consiste en el cambio constante de las especies. Donde pequeños y constantes cambios (microevolución) son las piezas de los cambios mas grandes (macroevolución). Con el tiempo el cambio es tan grande que el ejemplar final ya no tiene nada que ver con lo que alguna vez fue.

Pero bueno, este es un blog sobre lenguaje Ensamblador, no de biología y mucho menos de religión. De lo que quiero hablar en esta entrada es sobre la evolución del software en la computadora de un programador. A diferencia de los usuarios que se limitan a descargar y usar paquetes que tienen que ser reinstalados, a veces con todo y computadora, cada cierto tiempo; los programadores hacen herramientas pequeñas y funcionales que modifican conforme los requerimientos a los que se enfrentan cambian. Estos cambios pueden parecer insignificantes pero con el tiempo llegan a ser tantos y tan frecuentes que el software original cambia por completo y al paso de los años es tan grande, complejo y poderoso que parece haber sido creado por los mismísimos dioses o al menos por algún tipo de genio loco de la computación.

En este caso, quiero hacer la prueba para ver si esto es cierto y quiero aplicarlo al desarrollo de una herramienta que permita mantener bajo control el desarrollo de programas muy grandes (y del que ya hablé en una nota hace meses). Por ahora apenas codifiqué una pequeña aplicación que toma el contenido de un archivo de texto llamado ‘input.txt’ y lo copia a otro llamado ‘output.txt‘. El programa, aunque está hecho en Ensamblador para Windows de 32 bits no tiene interfaz gráfica (aunque puede adaptársele una). En pocas horas, este programita será capaz de leer un texto cualquiera y decir que palabras diferentes contiene y en que renglón se encuentran. Esto es lo bastante sencillo para ser codificado en un fin de semana.

Si alguno de ustedes lee el código y no nada mas lo copia a la IDE del FASM verá una estructura muy rara llamada “aceptor” un aceptor es un maldito ciclo con una o mas condiciones de parada enmedio que sirve para detectar patrones en secuencias lineales de entrada, como lo son las palabras en un texto. Los aceptores merecen una o dos notas aparte para explicarlos pero por ahora no son mas que un ciclo con uno o dos saltos. No quiero adelantar nada sin haberlo programado primero, pero algo tan elemental como ver que palabras contiene un texto y donde están es muy util a la hora de programar, pues puedes llevar mejor control de tus variables y estructuras sin tener que moverte a traves del mar de instrucciones en que se convierte un programa en Ensamblador. Aquí les dejo lo que llevo del código, que por supuesto funciona (copia el contenido de un texto llamado input.txt a otro llamado output.txt).


;Se supone que este programa debe de evolucionar para
;convertirse en una herramienta de desarrollo y control de
;codigos complejos. No tengo idea de como va a ser pero
;por ahora lo unico que hace es copiar el contenido de un
;archivo de texto llamado 'input.txt' y escribirlo en otro
;archivo llamado 'output.txt'. Solo compilalo y haz doble click
;para ejecutarlo.
;
;para ver como sigue la evolucion entra a:
;
; https://asm86.wordpress.com
format PE GUI
entry start

section '.code' code readable executable

  start:

;;      AQUI EMPIEZA EL SHOW

                        call abrir_archivo_fuente
                        call medir_archivo_fuente
                        call leer_archivo_fuente

                        call procesar_archivo_fuente

                        call crear_archivo_salida
                        call escribir_archivo_salida

                        call cerrar_handles_archivos
;;      AQUI ACABA EL SHOW
        push    0
        push    _caption
        push    buffer_provisional
        push    0
        call    [MessageBoxA]

        push    0
        call    [ExitProcess]
    ;fin de la ejecucion

;aqui comienzan los procesos propios
abrir_archivo_fuente:

                       push    0
                       push    20h; archivo
                       push    3; abrir existente OPEN_EXISTING
                       push    0;seguridad
                       push    3;lectura y escritura compartida
                       push    0c0000000h;lectura y escritura generica
                       push    input_file_name
                       call    [CreateFile]
                       mov     [input_handle], eax
                    ;abrir archivo fuente a analizar

                        ret
medir_archivo_fuente:
                        push 0          ;posicion del dword mas alto en caso de que el archivo supere los 4gbytes
                        push [input_handle];handle del archivo abierto
                        call [GetFileSize]
                        mov  [input_size], eax
                    ;tomarle la medida al archivo

                        ret

leer_archivo_fuente:

                        push    0                 ;no overlap
                        push    indice            ;# de bytes leidos
                        push    [input_size]           ;leer n bites
                        push    buffer_provisional ;guardar aqui
                        push    [input_handle]               ;handle de archivo
                        call    [ReadFile]
                    ;leer del archivo para su analisis

                        ret

crear_archivo_salida:
                       push    0
                       push    20h; archivo
                       push    2;crear nuevo
                       push    0;seguridad
                       push    3;lectura y escritura compartida
                       push    0c0000000h;lectura y escritura generica
                       push    output_file_name
                       call    [CreateFile]
                       mov     [output_handle],eax
                    ;crear archivo de salida, si ya esta,
                    ;crearlo de todos modos

                        ret
escribir_archivo_salida:
                        push    0      ;no overlapped
                        push    indice ;posicion de numero de bytes transferidos
                        push    [input_size]  ;cantidad de bytes a transferir
                        push    buffer_provisional;posicion de buffer
                        push    [output_handle]    ;handle de archivo
                        call    [WriteFile]
                    ;escribir al archivo
                    ;#copiar 20 bytes a un archivo de texto

                        ret

cerrar_handles_archivos:
                       push     [output_handle]
                       call     [CloseHandle]
                       push     [input_handle]
                       call     [CloseHandle]
                   ;aqui se cierra el acceso a ambos archivos
                       ret
;procesar_archivo_fuente(char *cadena, aceptor *aceptor);
;toma como parametros la posicion de inicio de la cadena y la
;de la estructura del aceptor, seria bueno que tambien recibiera la
;longitud de la cadena
procesar_archivo_fuente:

                        ret

;/// fin de los procedimientos propios

section '.data' data readable writeable

  output_handle dd      0
  input_handle  dd      0
  input_size    dd      0       ;longitud del archivo a leer

  indice        dd      0

  _caption db 'Buffer de texto:',0
  _message db 'hello world!',0

input_file_name   db 'input.txt',0
output_file_name  db 'output.txt',0

;////aqui empieza el aceptor ascii
;es una matriz cuadrada de valores de 8 bits,
;que mide 128 por la cantidad de estados
;la entrada es el indice y compone los bits mas
;bajos del indice. Los bits mas altos indican el estado presente
;a cada estado corresponde la ejecucion de un proceso y
aceptor:
.entradas db 80h ;entradas admitidas
.estados  db 2   ;posibles estados del aceptor
.proc_array dd 0 ;posicion del arreglo de funciones asociadas
.numero_de_procesos dd 0; cantidad de funciones asociadas
aceptor_matrix: times 80h db 0    ;

;### SECCION DE DEBUG, INICIO

        ;simbolos ascii

buffer_provisional:times 10000 db 0;darle cran a esto con virtualalloc

buffer_de_palabra: times 100h db 0; aqui se guarda una palabra individual

section '.idata' import data readable writeable

  dd 0,0,0,RVA kernel_name,RVA kernel_table
  dd 0,0,0,RVA user_name,RVA user_table
  dd 0,0,0,0,0

  kernel_table:
    ExitProcess dd RVA _ExitProcess
    CreateFile  dd RVA _CreateFileA
    CloseHandle dd RVA _CloseHandle
    ReadFile    dd RVA _ReadFile
    WriteFile   dd RVA _WriteFile
    GetFileSize dd RVA _GetFileSize

    dd 0

  user_table:
    MessageBoxA dd RVA _MessageBoxA
    dd 0

  kernel_name db 'KERNEL32.DLL',0
  user_name db 'USER32.DLL',0

  _ExitProcess dw       0
               db       'ExitProcess',0

  _MessageBoxA dw       0
               db       'MessageBoxA',0

  _CreateFileA  dw      0
                db      'CreateFileA',0

  _CloseHandle  dw      0
                db      'CloseHandle',0

  _ReadFile     dw      0
                db      'ReadFile',0

  _WriteFile    dw      0
                db      'WriteFile',0

  _GetFileSize  dw      0
                db      'GetFileSize',0

section '.reloc' fixups data readable discardable

Por ahora sigue terminar el aceptor y averiguar una manera de construir una estructura que permita representar en forma de red las interacciones entre los símbolos. Pero eso ya se verá cuando este programa evolucione un poco mas.

Lo interesante de este tipo de evolución es que no depende del tiempo real sino de las horas que los programadores le invierten y de los retos o depredadores a los que el programa se tiene que enfrentar. Lo mas interesante de este sistema es la parte de la reproducción, pues luego de que un software ha evolucionado a cierto nivel puede heredarle algunas de sus nuevas capacidades a sus descendientes. Por ejemplo, hace mucho mientras investigaba como programar en Windows hice unas funcioncitas que desplegaban el contenido de los registros generales y de secciones de memoria que hasta la fecha les implanto a los programas mas nuevos para encontrar los errores mas rápido. En este caso, por simplicidad quité estas rutinas pero el ejemplo es perfectamente funcional sin ellas.

El siguiente paso es reconocer y ubicar cada palabra en un texto y mas adelante que distinga exactamente que es cada símbolo (instrucciones, macros, variables, etc.)No se como lo voy a hacer, lo único que importa ahora es que la evolución no se detenga porque eso significaría la extinción tanto del programa como mía. Aunque creo que va a llegar un momento en que este sistema deba de ser capaz de aprender. Pero eso solo la evolución, o la extinción lo dirán. Por cierto, para que cuente como evolución, el software debe de tener una utilidad real, por insignificante que esta sea, en todas sus etapas.

Anuncios

julio 25, 2009 - Posted by | Uncategorized | , ,

2 comentarios »

  1. De hecho es muy buena idea, a mi forma de ver una de las ventajas que te da un IDE (OJO: solamente estoy hablando como herramienta de desarrollo) del .net en contra del fasm es eso, la localización rapida de variables, fragmentos de código, deteccion de warnings y errores antes de compilar, etc… ya que cuando tienes un programa que empieza a superar las mil lineas, esto ya empieza a complicarse a la hora de localizar dichas detalles.

    Creo que si lograras integrar mejoras de este tipo, en el IDE del fasm o en tu propio editor de código (no la clasica opcion de BUSCAR), sería una buena evolución.

    Saludos

    Comentario por El Julio | julio 27, 2009 | Responder

    • De hecho la idea no es solo localizar y destruir codigo sino que el propio IDE sepa que hacen las rutinas, algo asi como hace el OllyDbg para detectar las llamadas al sistema y las operaciones con Strings Ascii. Estoy trabajando en una estructura general de aceptores para poder reconocer patrones de instrucciones en el codigo.

      Comentario por asm86 | julio 27, 2009 | Responder


Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: