Change Tab Order in an Executable

An application called Cardiology PACS was recently packaged for a Citrix XenApp environment. The functional tester reported a strange problem at the logon screen: after entering the username it was not possible to go to the password field with the TAB key.

This was a strange observation since I cannot imagine XenApp interfering with tab stops. So what was going on?

In the old situation the user was starting the application on his local pc. The application remembered the last username and pre-filled this, therefore the cursor was already in the Password field. The user simply entered his password and hit the Enter key:

image

On XenApp the Username field is not pre-filled because the last username is kept globally per machine. Therefore the user has to enter both the username and the password:

image

I tested the Tab key behavior in both situations and as I expected it didn’t work in both situations. This happens because the Tab Order has been messed up by the programmer (if you press Tab 9 times you do end up in the Username field).

Because this is something that would annoy me if I were the user I decided to fix it.

Identify Compiler

I first identified the compiler using a tool called PEiD which identified “Microsoft Visual Basic”, my favorite Crapplication Creator:

image

Modify the binary

Modifying VB executables is fairly easy so let’s do it! We need the VB Decompiler tool (free lite edition will do) and a HEX Editor (I use 010 Editor).

Decompile

Start VB Decompiler and go to Tools | Options screen check Forms | Show Offsets and Advanced Features | Decompile only forms:

image

Then I decompiled the executable (PicomPowerClient.exe) and in the Forms node I found the form frmServerLogon. I opened the form and inspected it’s properties:

    Begin TextBox txtPassword2 'Offset: 001430D7
      Left = 2813
      Top = 1870
      Width = 3645
      Height = 405
      TabIndex = 0
      PasswordChar = "*"
    End
    Begin TextBox txtUsername2 'Offset: 00143114
      Left = 2813
      Top = 700
      Width = 3645
      Height = 405
      TabIndex = 21
      BeginProperty Font
        Name = "Arial"
        Size = 12
        Charset = 0
        Weight = 700
        Underline = 0 'False
        Italic = 0 'False
        Strikethrough = 0 'False
      EndProperty
      Appearance = 0 'Flat
    End

As you can see the Username field (Labeled txtUsername2) has TabIndex 21 but txtPassword2 has TabIndex 0 (but should have 22).

Before we are going to change the TabIndex we need to verify that no other control has this TabIndex. I simply searched (Ctrl-F) for “TabIndex = 22” and the Label Label2 had it (That’s why we didn’t see it get focus):

    Begin Label Label2 'Offset: 001431B9
      Caption = "Username:"
      BackColor = &H80000005&
      ForeColor = &H80000008&
      Left = 1133
      Top = 700
      Width = 1335
      Height = 375
      TabIndex = 22
      BackStyle = 0 'Transparent
      BeginProperty Font
        Name = "Arial"
        Size = 12
        Charset = 0
        Weight = 700
        Underline = 0 'False
        Italic = 0 'False
        Strikethrough = 0 'False
      EndProperty
      Appearance = 0 'Flat
    End
  End

We now have the Offsets of the controls we want to edit: 001430D7 for txtPassword2 and 001431B9 for Label2.

Binary Template

To make editing a little easier I wrote a “Binary Template” in 010 Editor (Binary Templates is an awesome feature that makes working with Hex Data a lot easier).

This is my Template for a VB TextBox Control:

local uchar Id[2];

// Jump to the Cursor Position
struct VBSTRING {
    ushort Length;
    char String[Length];
    char Terminator;
};

enum  VBBOOL { VBFALSE = 00, VBTRUE = 0xff };

FSeek(GetCursorPos());

struct TEXTBOX {
    FSkip(3);
    byte Index;
    VBSTRING Caption;
    FSkip(1);
    while( FTell() < FileSize() )
    {
        ReadBytes(Id, FTell(), sizeof(Id));
        FSkip(1);
        switch ( Id[0] )
        {
            case 0x09: VBBOOL Visible; break;
            case 0x1F: byte Appearance; break;
            case 0x22: VBSTRING PasswordChar; break;
            case 0x2E: VBSTRING DataMember; break;
            case 0x04: ushort Left; ushort Top; ushort Width; ushort Height; break;
            case 0x12: ushort TabIndex; break;
            case 0x1F: byte BackStyle; break;
            case 0x27: byte Appearance; break;

            // FF 03 is end of control
            case 0xFF: if ( Id[1] = 0x03 ) FSkip(2); return 0;
            // Enable the line below for debugging...
            //default: Printf("Unknown Id: 0x%.2x at 0x%.8x\n", Id[0], FTell()-1); break;
        }
    }
};

TEXTBOX TextBox;

Swap the Tab Indexes

Now I simply jump (Ctrl-G) to Label 2 Offset  001431B9 and Execute the Binary Template. This gives us a nice, structured view on the data:

SNAGHTMLb81835e

Now we change the TabIndex from 22 to 0:

image

Save the changes (you did make a backup, right?), go to txtPassword2 Offset and change the TabIndex from 0 to 22:

image

Fixed

Save and Launch the new executable. And now Tab nicely takes us to the Password Field:

image

Note that for similar changes to Applications written in C/C++ you can Resource Hacker.

0 replies

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply

Your email address will not be published. Required fields are marked *