Escribiendo Aplicaciones de Consola en Visual Basic 6

Seguro muchos de nosotros alguna vez habremos pensado en escribir programas de consola en Visual Basic pero hemos tenido que migrar a lenguajes como C o Pascal por que como su nombre lo indica este lenguaje es “Visual”.


La realidad es distinta y en este post, les mostraré la forma de crear aplicaciones que corran en modo Consola sin mostrar el formulario, asumiré que se tienen los siguientes conocimientos:

  • Visual Basic 6.
  • Uso de las Win32 API’s.
  • PE (Portable Executable) Header.

Herramientas Utilizadas

  • Editor Hexadecimal.
  • PE Editor.
  • Visual Basic 6.

Aplicaciones de Consola y la PE Header.

El formato PE es basicamente una estructura de datos que encapsula la información necesaria para el cargador de Windows para gestionar el código de un ejecutable.

Dentro de un Ejecutable PE, podemos encontrar una estructura que nos servirá para nuestro fin (Crear ejecutables de consola).
La estructura “IMAGE_OPTIONAL_HEADER”.

typedef struct _IMAGE_OPTIONAL_HEADER {
    //
    // Standard fields.
    //

    WORD    Magic;
    BYTE    MajorLinkerVersion;
    BYTE    MinorLinkerVersion;
    DWORD   SizeOfCode;
    DWORD   SizeOfInitializedData;
    DWORD   SizeOfUninitializedData;
    DWORD   AddressOfEntryPoint;
    DWORD   BaseOfCode;
    DWORD   BaseOfData;

    //
    // NT additional fields.
    //

    DWORD   ImageBase;
    DWORD   SectionAlignment;
    DWORD   FileAlignment;
    WORD    MajorOperatingSystemVersion;
    WORD    MinorOperatingSystemVersion;
    WORD    MajorImageVersion;
    WORD    MinorImageVersion;
    WORD    MajorSubsystemVersion;
    WORD    MinorSubsystemVersion;
    DWORD   Win32VersionValue;
    DWORD   SizeOfImage;
    DWORD   SizeOfHeaders;
    DWORD   CheckSum;
    WORD    Subsystem;
    WORD    DllCharacteristics;
    DWORD   SizeOfStackReserve;
    DWORD   SizeOfStackCommit;
    DWORD   SizeOfHeapReserve;
    DWORD   SizeOfHeapCommit;
    DWORD   LoaderFlags;
    DWORD   NumberOfRvaAndSizes;
    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

De toda esta estructura el único dato que nos interesa es el valor “Subsystem” de 16 bits (2 bytes).
Subsystem puede llevar distintos valores, el valor que contienen las aplicaciones GUI es 2 y las consolas tienen el valor 3.

#define IMAGE_SUBSYSTEM_WINDOWS_GUI          2   // Image runs in the Windows GUI subsystem.
#define IMAGE_SUBSYSTEM_WINDOWS_CUI          3   // Image runs in the Windows character subsystem.

Por lo tanto modificaremos el valor de los ejecutables que compilemos en Visual Basic, para ello necesitaremos un editor de archivos PE para ubicar el offset del Subsytem y un editor Hexadecimal para modificarlo.

Creando la aplicación de Consola

Haremos algo sencillo, utilizaremos las APIS para manejar la consola y escribiremos en ella “Hello Override – Algoritmatica has you” y el texto cambiará de color a Verde.

Apis necesarias:

Private Declare Function FreeConsole Lib "kernel32" () As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Declare Function GetStdHandle Lib "kernel32" (ByVal nStdHandle As Long) As Long
Private Declare Function WriteConsole Lib "kernel32" Alias "WriteConsoleA" (ByVal hConsoleOutput As Long, lpBuffer As Any, ByVal nNumberOfCharsToWrite As Long, lpNumberOfCharsWritten As Long, lpReserved As Any) As Long
Private Declare Function SetConsoleTextAttribute Lib "kernel32" (ByVal hConsoleOutput As Long, ByVal wAttributes As Long) As Long
Private Declare Function SetConsoleTitle Lib "kernel32" Alias "SetConsoleTitleA" (ByVal lpConsoleTitle As String) As Long

Constantes

Private Const STD_OUTPUT_HANDLE = -11&
Private Const FOREGROUND_GREEN = &H2

Código


Private Sub Form_Load()
Form1.Hide ' Ocultamos el formulario
    Dim hConsoleOut As Long
    hConsoleOut = GetStdHandle(STD_OUTPUT_HANDLE) ' Obtenemos el handle de la consola
    If (hConsoleOut) Then
        Dim sTexto As String
        Dim lWritten As Long
        sTexto = "Hello Override - Algorimatica has you!"  ' Texto a mostrar en la consola
        SetConsoleTitle ("Algoritmatica.com")                    ' Cambiamos el titulo de la consola
        SetConsoleTextAttribute hConsoleOut, FOREGROUND_GREEN  ' Cambiamos el color de texto de las letras
        WriteConsole hConsoleOut, ByVal sTexto, Len(sTexto), lWritten, ByVal 0&   ' Mostramos el texto en la consola
    End If
    'Matamos la consola

    CloseHandle hConsoleOut
    FreeConsole
    End ' fin de ejecución
End Sub

Compilando Código

Ahora compilamos nuestro código como lo haríamos de manera normal y generamos nuestro ejecutable, en mi caso lo he llamado test2.exe.
Una vez compilado necesitaremos nuestro Editor Pe, en este caso, yo he usado la herramienta “PEview”.

Buscando Subsystem

Abrimos nuestro archivo compilado (Test2.exe) en el Peview y expandemos el árbol “IMAGE_NT_HEADERS” y seleccionamos “IMAGE_OPTIONAL_HEADER” ahora del lado derecho buscamos
“Subsystem” y encontramos que se encuentra en el offset 0×00000114.

PE VIEW

Editando fichero y cambiando el valor de Subsystem

Ahora abriremos nuestro fichero compilado en un editor hexadecimal, yo he usado WinHex.
Buscaremos la offset 0×00000114 y vemos que tiene el valor 0×02, modificaremos el valor y colocaremos 0×03 lo que hará que el ejecutable corra en modo Consola.

Hexadecimal editing
Salvamos el fichero y ahora lo corremos desde el cmd.exe o command.com

El resultado final es:

Ejecutable vb6 en consola

Notas finales

Como nota final, se podría crear una función que escriba en la consola y otra función que espere por entrada de datos algo así como funciones equivalentes en C como son printf y scanf.
Con esas dos funciones podríamos ya empezar a programar nuestra aplicación en consola

insolente dice:

esto no me sirve es muy superficial a ver si se ponen abusados e investiguen mas para que no les den fierro otros cabrones

Amir dice:

@Insolente
Te agradecemos tu comentario insolente, pero si crees que el artículo no está al nivel de tí y de otros, te invito a participar activamente y colaborar con algún artículo..

De nueva cuenta agradecemos tu comentario y que pases buen día.

Diego dice:

Excelente aportación. Necesitaba convertir una aplicación VB6 en aplicación de consola pero me abría una consola nueva en lugar de usar la existente. Con esta modificación del ejecutable al arrancar lo hace en la consola actual.

Gracias,

Andrew dice:

Excelente aporte, pero puedes utilizar envez de entrar a modificar la aplicacion desde su naturaleza hexagesimal, puedes utilizar este codigo en VBScrip:

Dim StrLINK ,StrEXE ,WSHShell

‘Ruta del LINK.exe de la carpeta VB
StrLINK = “”"C:\Archivos de programa\Microsoft Visual Studio\VB98\LINK.EXE”"”
‘Ruta del ejecutable que arrastras
StrEXE = “”"C:\Proyecto1.exe”"”
Set WSHShell = CreateObject(“WScript.Shell”)

WSHShell.Run StrLINK & ” /EDIT /SUBSYSTEM:CONSOLE ” & StrEXE , 0

Set WSHShell = Nothing
WScript.Echo “Finalizado!!”

Sergio dice:

Muy interesante tu aporte, me resulta muy útil paraun proceso batch que tengo que hacer para un trabajo.
Para hacer más facil el proceso se puede usarun edit de ecabezados PE como PEEditor, de esta manera se evita usar un editor hexa.
http://www.softpedia.com/progDownload/PEditor-Download-28.html