Dia: 13/08/2012

A import\342ncia do questionamento Sexta-feira, 10/08/2012 \340s 11h00, por Roger Hughes

Um dos meus coment\341rios sobre um artigo que escrevi - Emperor\u2019s New Clothes e Catch 22 (ingl\352s) - foi que "uma das coisas mais valiosas que esses padr\365es oferecem \351 o vocabul\341rio. Eles d\343o nome a algo.\u201d, o que \351 um ponto importante que acho que deixei passar. A ideia \351 que, uma vez algo possui um nome, voc\352 pode comunicar facilmente sobre esse algo. Por exemplo, \351 mais f\341cil dizer "Eu usei um Singleton" em vez de "Eu criei esta classe, onde h\341 sempre apenas uma inst\342ncia e essa inst\342ncia est\341 dispon\355vel para todas as outras classes no aplicativo".

Sempre pensei que a nomea\347\343o, em geral, \351 crucial para escrever um bom software e que eu definitivamente vou escrever um artigo (ou dois) sobre o assunto algum dia. Por enquanto, basta dizer que, quando voc\352 v\352 um m\351todo ou uma classe que est\341 mal nomeada, seja corajoso: corra e aperte o bot\343o direito, Refatorar e renomear... Menu Op\347\365es, mas lembre-se: o truque consiste em encontrar o nome mais significativo.

Lendo artigo que citei acima, voc\352 pode ter a impress\343o de que sou contra padr\365es. Isso n\343o pode estar mais distante da verdade, j\341 que ao mesmo tempo que sou muito anti-anti-padr\365es, eu sou totalmente a favor deles, se eles forem exatamente de acordo com os padr\365es \u201cGang Of Four\u201d, \u201cMartin Fowler\u2019s Patterns of Enterprise Application Architecture\u201d ou qualquer outro padr\343o, mas eu ainda penso que o uso correto de padr\365es \351 tamb\351m muito importante.

Uma das observa\347\365es que deveriam ser feitas a respeito dos padr\365es GOF \351 que eles podem ser ranqueados em termos de utilidade, import\342ncia e popularidade. Por exemplo, praticamente todo desenvolvedor conhece Singleton (talvez por ele ser o mais simples?) e, caso j\341 tenha usado o Spring, ent\343o voc\352 j\341 se deparou com Strategy.

Se voc\352 n\343o usa Spring, ent\343o suspeito que \351 mais prov\341vel que voc\352 conhe\347a os padr\365es de cria\347\343o: Abstract Factory, Factory Method e Builder. Se voc\352 j\341 fez algum trabalho JEE (conhecido como J2EE), ent\343o com certeza voc\352 j\341 viu Facade sendo usado como interface para um EJB2.

Al\351m disso, voc\352 pode usar ou ter usado Observer para informar um grupo de objetos sobre a mudan\347a de estado de um, ou usado Template para definir um algoritmo estrutural, mas h\341 aqueles padr\365es que voc\352 n\343o costuma achar a necessidade de usar.

Pegue o Memento, a maioria dos desenvolvedores j\341 se deparou com isso na forma de Serializable, mas n\343o me lembro de ter que implementar isso sozinho, exceto como um exerc\355cio de aprendizagem de Memento e ent\343o existe a State Machine.

Vi esse padr\343o pela primeira vez em 1989, cinco anos antes de o GOF ter publicado seu livro. Ele estava sendo usado em um emulador de terminal VT escrito em "C" no Windows 2.1 como parte de um projeto j\341 extinto chamado CityDesk, produzido por uma empresa extinta chamada Apricot Computers. State Machine \351 muito \372til na an\341lise de fluxos de bytes de entrada, um byte de cada vez, para descobrir que a\347\365es tomar e, apenas para a posteridade, h\341 uma parte do c\363digo CityDesk abaixo: n\343o \351 bonito, n\343o \351 Java, n\343o \351 OO, mas \351 uma State Machine e que \351 anterior a GOF.

No entanto, voltando aos trilho... Enquanto State Machine \351 realmente \372til para fazer os tipos de trabalho descritos acima, agora existem maneiras mais modernas de processamento de fluxos de bytes, que no caso do Java s\343o fornecidos pela String do SDK, Streams e classes associadas como Pattern Matcher e etc. Ent\343o, State Machine est\341 se tornando mais obsoleta ou existem bons outros usos para ela? Para concluir este artigo, acho que devo reiterar que sou pr\363-padr\365es: um padr\343o utilizado no lugar apropriado fornece uma solu\347\343o muito \372til para um problema comum, mas acho que eles devem ser questionados de tempos em tempos. Padr\365es GOF t\352m estado por a\355 por muito tempo: eles podem ser melhorados? Eles ainda s\343o t\343o relevantes hoje como eram quando o livro foi escrito? Questionar coisas \351 uma habilidade importante, se voc\352 n\343o o fizer, ent\343o \351 prov\341vel que voc\352 se torne um programador Cargo Cult.

Voc\352 realmente n\343o quer ver isto:
/*****************************************************************************/
/*                                                                           */
/* Program / Project Name      Vt320 Terminal Emulation Package              */
/*                                                                           */
/* Module Name                 Vt220.c                                       */
/*                                                                           */
/* Description     Much changed but still compatible version of the earlier  */
/*                 version of the Term220 file                               */
/*  Contains the Vt320/220/100/52 State machine functions                    */
/*                                                                           */
/* Procedures Included  EmulateVT100  CheckForEscSequence  VT100Cntl         */
/*  VT100Esc  VT100Private                                                   */
/*                                                                           */
/* Updates       None                                                        */
/*     MID 11.07.1989 2.00.02   Cursor up and down now checks       */
/*            for cursor movement beyond the     */
/*            screen bounds.         */
/*                       */
/* Va 2.00.05 4:35pm 14/7/89                                                 */
/* Mod to clear the Status line of data if in HostWrite mode                 */
/*                       */
/* Vb 2.00.01 9:40am 22/8/89  Mods around line 547 on EndRow resetting     */
/*                       */
/* Vb 2.00.01 10:20am 22/8/89                                               */
/*   - Mod to new line action so that if the scroll region is smaller than   */
/*   the screen then the cursor cannot LF past the bottom of the screen      */
/*                       */
/*****************************************************************************/

/************************************************************************
*
        EmulateVT220 - VT220 Emulator
*
*************************************************************************/



#include 
#include 
#include 
#include 

#include 
#include 
#include 
#include 
#include 
#include 
#include     /* Imports for grafs */
#include 

#include "term220.h"
#include "Scroll.h"

#include "externs.h"



VOID    EmulateVT100 (lpCharBuff, Cnt)
LPSTR   lpCharBuff;
int     Cnt;
{
#ifdef TERM320
  extern BOOL tWatch;
#endif
  extern BOOL DisplayControls;
  extern UTC utc;
   BYTE   c;

   while (Cnt--)    /* For all the characters in the buffer loop around and sort them out */
   {
        c = *lpCharBuff++;  /* make c the next char to process */



      /* Allow the VT320 double height stuff to work
       * in the clearing screen bit
       */
      if(DecDWLHoldOff)
      {
      DWLReset(ScreenVars.CurrentRow,ScreenVars.EndRow);
         DecDWLHoldOff = FALSE;
      }

    if(utc.Mode != UTC_NORMAL)
        ProcessTheMessage(c); /* call this if we're in Unit trust mode */
    else
     {

      if(DisplayControls)    /* for control characters display every thing */
         {
         BufferCharacters(c);
         continue;
         }
    if(PrintController(c))  /* sort out any printing we may be doing */
      continue;


       switch (c)  /*  Check for control characters  */
        {
        case NULL:    /*  11.07.1989  MID  2.00.02  */
          break;    /* this is here to stop the output th the screen when print controller is on */
        case 11:
        case '\\n':      /* NEWLINE */
        AddToScrollScreen(ScreenVars.CurrentRow);    /* put the line in the scrolling screen region */
           AddLineAutoPrint(c);    /* put this line in the file */
        if (fCaptureLine)
            CaptureLine ();
            if (ScreenVars.CurrentRow == ScreenVars.ScrollBottom)
         {
            //ScrollVEx (&ScreenImage[0][0],
             //      &AttributeMap[0][0],
             //    NULL,
             //      (LPSCREENVARS)&ScreenVars,
             //      hWndMain,
             //    ScreenVars.ScrollTop,
             //    ScreenVars.ScrollBottom,
             //    1,
               //      (BUTTONDATA FAR *)&bd,
             //    (LPFONTVARS)&FontVars);
            ScrollVEx (
                   hWndMain,
                 ScreenVars.ScrollTop,
                 ScreenVars.ScrollBottom,
                 1);

          DWLScroll(ScreenVars.ScrollTop,ScreenVars.ScrollBottom,1);
         }
        else if(ScreenVars.CurrentRow < ScreenVars.EndRow)  /* RH 22/8/89 Vb 2.0.01 */
            ++ScreenVars.CurrentRow;

        /*  IF SEQUENCE LNM IS ACTIVE MOVE CURSOR TO COL 0  */
        if (fLFCR)
            ScreenVars.CurrentCol = 0;
             faNewLine = FALSE;
          break;

            case '\\07':     /* BELL */
          MessageBeep (0);
        break;

            case '\\r':      /* CARRIAGE RETURN */
        ScreenVars.CurrentCol = 0;
        faNewLine = FALSE;
                break;

            case '\\b':      /* BACKSPACE */
          if (ScreenVars.CurrentCol)
          --ScreenVars.CurrentCol;
                break;

            case '\\t':      /* TAB */
            if (ScreenVars.CurrentCol < ScreenVars.EndCol)
         {
            for (++ScreenVars.CurrentCol; ScreenVars.CurrentCol <= ScreenVars.EndCol; ScreenVars.CurrentCol++)
             {
              if (ScreenVars.TabStops[ScreenVars.CurrentCol])
                break;
             }
         }
                break;

            case 0x7f:      /* Ignore delete character */
          if(bd.Terminal.TermOptions.MapBackSpaceToDel && ScreenVars.CurrentCol)
            --ScreenVars.CurrentCol;
                break;

        case 5:  /* ENQ  */
         if(tWatch)
           SendDataBlock(bd.Data2,lstrlen(bd.Data2),FALSE);
            SendAnswerBack();
        break;

        case SO: /* move G1 on to GL */
            CurrentSet = &CharacterSet1;
            break;

        case SI:  /* move G0 into GL */
            CurrentSet = &CharacterSet0;
            break;

      default:   /*  Check for Escape sequences  */
        CheckForEscSequence (c);
            break;
        }
    }
    } 
}

/************************************************************************
*  This function checks for escape sequences. If one is found it is
   processed. If not then it is a normal character and is displayed.
*
*************************************************************************/

VOID CheckForEscSequence (c)

BYTE    c;

{
  extern BOOL DecUKKeyBoard;
   extern BYTE PoundSign;

    switch (State)
   {
        case NORMAL:
        /*  CHANGE STATE TO LOOK OF ESCAPE SEQUENCE IF ESCAPE RECEIVED  */
      if (c == ESC)
            State = ESCED;
                    /* check for an 8 bit escape sequence */
        else if(bd.Terminal.TermOptions.Bits87 && ((c >= 0x80)&&(c <= 0x9f)))
          {
        State = ESCED;      /* c - 0x40 puts the char back into the correct range */
            c -= (BYTE)0x40;
        CheckForEscSequence(c);  /* ie. 0x9b - 0x40 = 0x5b or'['. hence respond to an ESC [ call */
          }
        /*  NORMAL CHARACTER THEN PUT INTO SCREEN BUFFER  */
        else if (c >= 32)
         {
            if(DecUKKeyBoard && (c == PoundSign))
               c = 0x9c;
           BufferCharacters (c);
         }
           break;

    case POSS_DECSTR:  /* a possible soft reset is on the way */
      if(c == ESC)
        {
             State = ESCED;
        break;
        }
      else if((c == 'p') && (bd.Terminal.TermOptions.TermType != CDK_VT100))  
           DecStr();u
      if(c != 'p')
        State = SQU_ERROR;
      else
          State = NORMAL;
        break;

        case ESCED:
      if(c == ESC)
        {
             State = ESCED;
        break;
        }
      else if (c == '(')
               State = CHARSET_G0;
          else if (c == ')')
               State = CHARSET_G1;
          else if (c == 'P')
          {
           ClrParam();
           State = PARAMS;
           Pnum2 = 0;
          }
        else  /* CONTROL SEQUENCE INTRODUCER */
            if (c == '[')
             {
              ClrParam ();
              State = PARAMS;
             }
        else /* INTERMEDIATE CHARACTERS */
            if (c > 0x20 && c <= 0x2f)
              State = ESCSQU;
        else if(c == ' ')  /* check for an ESC' ' input to switch mode */
        State = CONTROLXMIT;
        else if (c >= 0x30 && c <= 0x7e)
              VT100Esc (c);
        else
               State = SQU_ERROR;
         break;

      case ESCSQU:
      if(c == ESC)
        {
             State = ESCED;
        break;
        }
      else if (c >= 0x30 && c <= 0x7e)
              VT100Esc (c);
            break;

       case PARAMS: /* PARAMETER CHARACTERS */      /*NEWBIT*/
          if (Pnum == 0 && c >= 0x3c && c <= 0x3f)
              fPrivate = TRUE;
          else if (c == IMMED)
              State = NORMAL;
        else if ((c == '|')&&(Pnum2 < NO2PARAMS))
         {
          FlagDCS = TRUE;
          Param2[Pnum2++] = c;
         }
        else if ((FlagDCS == TRUE) && (c == 0x1b))
             FlagDCS = FALSE;
           else if((c == 0x22) && (Pnum2 < NO2PARAMS))
            Param2[Pnum2] = c;
        else if (c >= '0' && c <= '9')
             {
              if (Pnum2 < NO2PARAMS)
              Param2[Pnum2++] = c;
        if(Pnum < NOPARAMS)
          {
               Param[Pnum] *= 10;
                 Param[Pnum] += (c - '0');
          }
             }
            else if (c == ';')
             {
               if(++Pnum > (NOPARAMS - 1))
                     State = NORMAL;
          if(++Pnum2 < NO2PARAMS)
                Param2[Pnum2] = c;
             }
        else if ((FlagDCS == TRUE)&&(Pnum2 < NO2PARAMS))
           Param2[Pnum2++] = c;
        else if(c == '      )  /* a dollar sign for the status line Escape sequences */
        State = STATUSLINE_ESCSEQ;
        else if(c == '!')        
        State = POSS_DECSTR;     /* a possible soft reset is on the way */
      else if(c == ESC)
        State = ESCED;      /* an unterminated esc sequence */
        else
             {
            if (fPrivate || (c >= 0x70 && c <= 0x7e))
                VT100Private (c);
                else
                    VT100Cntl (c);
               fPrivate = FALSE;
              }
     
             break;

      case CHARSET_G1:
      if(c == ESC)
        {
             State = ESCED;
        break;
        }
        else if (c == '0')
            CharacterSet1 = TRUE;   /*  move Dec Graphics in to G1 */
      else              /* this covers A and B */
            CharacterSet1 = FALSE;  /*  ASCII into G1 */

          State = NORMAL;
        break;   

    case CHARSET_G0:
      if(c == ESC)
        {
             State = ESCED;
        break;
        }
          else if (c == '0')
            CharacterSet0 = TRUE;   /*  Graphics  */
      else              /* this covers A and B */
            CharacterSet0 = FALSE;  /*  ASCII  */

          State = NORMAL;
          break;

    case STATUSLINE_ESCSEQ:    /* act on a status line esacpe sequence */
      if(c == ESC)
        {
             State = ESCED;
        break;
        }
        VT100Cntl(c);
        break;
    case CONTROLXMIT:  /* a possible change of control code bits is on the way */
      if(c == ESC)
        {
             State = ESCED;
        break;
        }
        SelectTransmissionStyle(c);
        break;
    case SQU_ERROR:
      if(c == ESC)
        State = ESCED;
      else if ((c >= '@') && (c < 0x7f))
        State = NORMAL;
       
      break;
    default:
      if(c == ESC)
             State = ESCED;
      else
              State = NORMAL;
        break;
    }
}












/************************************************************************
*
        VT100Cntl - Check for VT100 Control escape sequences
*
*************************************************************************/

VOID    VT100Cntl (c)
BYTE    c;
{
#ifdef TERM320
   extern BOOL tWatch;
#endif
    int    lines;



  State = NORMAL;
    switch (c)
     {
        /*
           INSERT PARAM[0] BLANK CHARS AT CURSOR POSITION
           WITH THE CHARACTER ATTRIBUTES SET TO NORMAL
        */
        case ICH:  /* Vt200 and greater */
        if(bd.Terminal.TermOptions.TermType != CDK_VT100)
          {
          /*  INSERT AT LEAST 1 CHARACTER  */
          if (Param[0] == 0)
            Param[0] = 1;
          InsertCharacterEx (&ScreenImage[0][0],
                 &AttributeMap[0][0],
               NULL,
               (LPSCREENVARS)&ScreenVars,
               Param[0]);
          }
        break;

        /*
            DELETE PARAM[0] CHARACTERS STARTING AT THE CURSOR POSITION
        */
        case DCH:
        /*  DELETE AT LEAST 1 CHARACTER  */
        if (Param[0] == 0)
          Param[0] = 1;
        DeleteCharacterEx (&ScreenImage[0][0],
               &AttributeMap[0][0],
             NULL,
             (LPSCREENVARS)&ScreenVars,
             Param[0]);
        break;

        /*
           INSERT PARAM[0] LINES
        */
        case IL:
        /*  INSERT AT LEAST 1 LINE  */
        if (Param[0] == 0)
            Param[0] = 1;

        InsertLineEx (&ScreenImage[0][0],
                     &AttributeMap[0][0],
            NULL,
            (LPSCREENVARS)&ScreenVars,
            Param[0]);
        SetCursorPosition ((LPSCREENVARS)&ScreenVars,
                     (LPVTFLAGS)&VTFlags,
                   ScreenVars.CurrentRow,
                   0,
                   2);
        break;

        /*
            DELETE PARAM[0] LINES STARTING AT THE LINE WITH CURSOR
        */
    case DL:
        /*  DELETE AT LEAST 1 LINE  */
        if (Param[0] == 0)
            Param[0] = 1;

        DeleteLineEx (&ScreenImage[0][0],
                  &AttributeMap[0][0],
            NULL,
            (LPSCREENVARS)&ScreenVars,
            Param[0]);
        SetCursorPosition ((LPSCREENVARS)&ScreenVars,
                     (LPVTFLAGS)&VTFlags,
                   ScreenVars.CurrentRow,
                   0,
                   2);
            break;

    case 0x5c: /* DECUDK   VT220 ONLY */
        SetupFunctionKeys (Param2);
        break;

        /* CURSOR MOVEMENT */
        case CUB:       /* LEFT */
        if (ScreenVars.CurrentCol)
         {
            if (Param[0] == 0)
          Param[0] = 1;
        if ((ScreenVars.CurrentCol - Param[0]) >= 0)
                  ScreenVars.CurrentCol = ScreenVars.CurrentCol - Param[0];
        else
            ScreenVars.CurrentCol = 0;
         }
            break;

        case CUF:       /* RIGHT */
        if (ScreenVars.CurrentCol < ScreenVars.EndCol)
         {
            if (Param[0] == 0)
          Param[0] = 1;
        if ((ScreenVars.CurrentCol + Param[0]) <= ScreenVars.EndCol)
                  ScreenVars.CurrentCol = ScreenVars.CurrentCol + Param[0];
        else
            ScreenVars.CurrentCol = ScreenVars.EndCol;
         }
            break;

        case CUU:       /* UP */
        if(!bSLWrite)
          {
          AddToScrollScreen(ScreenVars.CurrentRow);    /* put the line in the scrolling screen region */
          if (fCaptureLine)
            CaptureLine ();
            AddLineAutoPrint(LF);    /* put this line in the file */
        /****  MID 11.07.1989 2.00.02  */
          if (ScreenVars.CurrentRow > ScreenVars.ScrollTop)
           {
              if (Param[0] == 0)
              Param[0] = 1;
              ScreenVars.CurrentRow = ScreenVars.CurrentRow - Param[0];

            if (ScreenVars.CurrentRow < ScreenVars.ScrollTop)
            ScreenVars.CurrentRow = ScreenVars.ScrollTop;
           }
          }
             break;

        case CUD:       /* DOWN */
        if(!bSLWrite)
         {
          AddToScrollScreen(ScreenVars.CurrentRow);    /* put the line in the scrolling screen region */
          if (fCaptureLine)
            CaptureLine ();
            AddLineAutoPrint(LF);    /* put this line in the file */
        /****  MID 11.07.1989 2.00.02  */
          if (ScreenVars.CurrentRow < ScreenVars.ScrollBottom)
           {
                if (Param[0] == 0)
              Param[0] = 1;
                ScreenVars.CurrentRow = ScreenVars.CurrentRow + Param[0];

            if (ScreenVars.CurrentRow > ScreenVars.ScrollBottom)
            ScreenVars.CurrentRow = ScreenVars.ScrollBottom;
           }
          }
            break;
        case CUP:       /* CURSOR POSITION (HOME) */
        case HVP:       /* HORIZONTAL & VERTICAL POSITION */
        /* RH Vb 2.00.01 Save the current value */
        lines = ScreenVars.EndRow;    /* save the current end row in a convenient store */
        if (fCaptureLine)
            CaptureLine ();

            AddLineAutoPrint(LF);    /* put this line in the file */
        AddToScrollScreen(ScreenVars.CurrentRow);    /* put the line in the scrolling screen region */
        if (Param[0] > 0)
            --Param[0];
        if (Param[1] > 0)
            --Param[1];

        /* if a VT320 term and in host write mode with the SL accessed then only the columns are affected */
        if((bd.Terminal.TermOptions.TermType == CDK_VT320)&& bSLWrite)
        ScreenVars.EndRow = Param[0] = LASTLINE;

        SetCursorPosition ((LPSCREENVARS)&ScreenVars,
                  (LPVTFLAGS)&VTFlags,
                Param[0],
                Param[1],
                2);
        faNewLine = FALSE;


        /* RH Vb 2.00.01 added the ifdef */
        ScreenVars.EndRow = lines;    /* reset the bottom row */
        break;


    case 'i':
        switch (Param[0])
         {
          case 0:    /*  PRINT SCREEN  */
               ScreenPrint();
            break;

        case 5:    /*  ACTIVATE PRINTER CONTROLLER  Esc[5i */
            DoPrintControl();
            break;
         }
        break;

    case 'h':
        switch (Param[0])
         {
            case 20: /* CAUSES LINE FEED TO DO A CR.  RETURN - CR & LF  */
                fLFCR = TRUE;
            break;

        case 4:  /*  IRM  Insert mode  */ /*NEWBIT*/
                VTFlags.WriteMode = TRUE; 
            break;

        case 12: /*  SRM  Local echo off  */
            bd.Terminal.TermOptions.LocalEcho = FALSE;
            break;
        case 2:  /*  KAM  Lock keyboard  */
            fKeyLock = TRUE;
            break;
        }
        break;

    case 'l':  /* SWITCH ABOVE OFF */
        switch (Param[0])
         {
            case 20: /* LINE FEED TO JUST LF  */
                fLFCR = FALSE;
          break;

        case 4:  /*  IRM  Replace mode  */
                  VTFlags.WriteMode = FALSE; 
            break;

        case 12: /*  SRM  Local echo on  */
            bd.Terminal.TermOptions.LocalEcho = TRUE;
            break;

        case 2:  /*  KAM  Unlock keyboard  */
            fKeyLock = FALSE;
            break;

         }
        break;

        case ECH:  /* ERASE CHARACTER  VT220 ONLY */
        if (Param[0] == 0)
             Param[0] = 1;
     
        if (Param[0] <= (BYTE)(((ScreenVars.EndCol + 1) - ScreenVars.CurrentCol)))
          ClearEx (&ScreenImage[0][0],
                  &AttributeMap[0][0],
                  NULL,
                  hWndMain,
                      (LPSCREENVARS)&ScreenVars,
                  (LPFONTVARS)&FontVars,
                  ScreenVars.CurrentRow,
                  ScreenVars.CurrentCol,
                  ScreenVars.CurrentRow,
                  ScreenVars.CurrentCol + Param[0] - 1,
                  FALSE);
        else
         {
          Param[0] = Param[0] - ((ScreenVars.EndCol + 1) - ScreenVars.CurrentCol);
        lines = Param[0] / (ScreenVars.EndCol + 1);
        Param[0] = Param[0] - ((ScreenVars.EndCol + 1) * lines);
        ClearEx (&ScreenImage[0][0],
               &AttributeMap[0][0],
               NULL,
               hWndMain,
                   (LPSCREENVARS)&ScreenVars,
               (LPFONTVARS)&FontVars,
               ScreenVars.CurrentRow,
               ScreenVars.CurrentCol,
               ScreenVars.CurrentRow + lines + 1,
               Param[0],
               FALSE);
         }
        break;

        case ED:   /* DISPLAY */
      if (Param[0] == 0)  /*  Erase from cursor to end of screen  */
     {
        ClearEx (&ScreenImage[0][0],
           &AttributeMap[0][0],
           NULL,
           hWndMain,
               (LPSCREENVARS)&ScreenVars,
           (LPFONTVARS)&FontVars,
           ScreenVars.CurrentRow,
           ScreenVars.CurrentCol,
           ScreenVars.EndRow,
           ScreenVars.EndCol,
           FALSE);
         DecDWLHoldOff = TRUE;  
     }
      else
      if (Param[0] == 1)  /* Erase from screen start to cursor  */
     {
        ClearEx (&ScreenImage[0][0],
           &AttributeMap[0][0],
           NULL,
           hWndMain,
               (LPSCREENVARS)&ScreenVars,
           (LPFONTVARS)&FontVars,
           0,
           0,
           ScreenVars.CurrentRow,
           ScreenVars.CurrentCol,
           FALSE);
      DWLReset(0,ScreenVars.CurrentRow);
     }
      else
      if (Param[0] == 2)  /*  Erase all of screen  */
       {
        ClearEx (&ScreenImage[0][0],
           &AttributeMap[0][0],
           NULL,
           hWndMain,
               (LPSCREENVARS)&ScreenVars,
           (LPFONTVARS)&FontVars,
           0,
           0,
           ScreenVars.EndRow,
           ScreenVars.EndCol,
           FALSE);
      DWLReset(0,ScreenVars.EndRow);
       }
      break;

        case EL: /* LINE */
        if (Param[0] == 0)  /*  Erase from cursor to EOL  */
          ClearEx (&ScreenImage[0][0],
                 &AttributeMap[0][0],
                 NULL,
                 hWndMain,
                     (LPSCREENVARS)&ScreenVars,
                 (LPFONTVARS)&FontVars,
                 ScreenVars.CurrentRow,
                 ScreenVars.CurrentCol,
                 ScreenVars.CurrentRow,
                 ScreenVars.EndCol,
                 FALSE);
        else
        if (Param[0] == 1)  /*  Erase from line start to cursor  */
          ClearEx (&ScreenImage[0][0],
               &AttributeMap[0][0],
               NULL,
               hWndMain,
                   (LPSCREENVARS)&ScreenVars,
               (LPFONTVARS)&FontVars,
               ScreenVars.CurrentRow,
               0,
               ScreenVars.CurrentRow,
               ScreenVars.CurrentCol,
               FALSE);
        else
        if (Param[0] == 2)  /*  Erase whole line  */
          ClearEx (&ScreenImage[0][0],
             &AttributeMap[0][0],
             NULL,
             hWndMain,
                 (LPSCREENVARS)&ScreenVars,
             (LPFONTVARS)&FontVars,
             ScreenVars.CurrentRow,
             0,
             ScreenVars.CurrentRow,
             ScreenVars.EndCol,
             FALSE);
        break;
        case TBC:       /* TABULATION CLEAR */
        if (Param[0] == 0)
            /*  CLEAR TAB STOP AT CURSOR POSITION  */
            ClearTabStop ((LPSCREENVARS)&ScreenVars, ScreenVars.CurrentCol);
        else if (Param[0] == 3)
          /*  CLEAR ALL TAB STOPS  */
          ClearTabStop ((LPSCREENVARS)&ScreenVars, -1);
       
        break;

    case DA:
        if (Param[0] == 0)
         {
#ifdef TERM320
         if(tWatch)
           SendDataBlock(IdentifyString,16,FALSE);
#endif
        PutComm(hWndMain,(LPSTR)IdentifyString, 16,(LPBUTTONDATA)&bd,(LPCOMMSVARS)&CommsVars,(BOOL FAR *)&fWaitingConnection);
         }
        break;

   

    case DECSSDT:    /* if the status line is being talked to then switch it off */
        SLReset();
        SetSLMode();  /* switch the status line mode */
        break;

    case DECSASD:
        SwitchStatusLine();
        break;

    case SGR:       /* Select Graphic Rendition */
        Sgr();
      break;

    default:
      if((c < '@') || (c > 0x7e))
        State = SQU_ERROR;
        break;
   }
}






/************************************************************************
*
        VT100Esc - Check for VT100 normal escape sequences
*
*************************************************************************/

VOID    VT100Esc (c)
BYTE    c;
{
#ifdef TERM320
   extern BOOL tWatch;
#endif
   int i;


  State = NORMAL;

   switch (c)
   {
        case RIS:
        ResetTerminal();
        break;

        case '=':
        VTFlags.fAppKeypad = TRUE;
            break;

        case '>':
        VTFlags.fAppKeypad = FALSE;
            break;

        case DECID:    /* Device attributes (WHAT ARE YOU) */
#ifdef TERM320
      if(tWatch)
         SendDataBlock(IdentifyString,16,FALSE);
#endif
        PutComm(hWndMain,(LPSTR)IdentifyString, 16,(LPBUTTONDATA)&bd,(LPCOMMSVARS)&CommsVars,(BOOL FAR *)&fWaitingConnection);
         break;

        case IND:    /* CURSOR DOWN WITH SCROLL */
        if (ScreenVars.CurrentRow < ScreenVars.ScrollBottom)
            ++ScreenVars.CurrentRow;
        else
        if (ScreenVars.CurrentRow == ScreenVars.ScrollBottom)
        {
            //ScrollVEx (&ScreenImage[0][0],
          //     &AttributeMap[0][0],
          //     NULL,
          //     (LPSCREENVARS)&ScreenVars,
            //   hWndMain,
         //  ScreenVars.ScrollTop,
         //  ScreenVars.ScrollBottom,
         //  1,
            //   (BUTTONDATA FAR *)&bd,
        //   (LPFONTVARS)&FontVars);
            ScrollVEx (
                   hWndMain,
                 ScreenVars.ScrollTop,
                 ScreenVars.ScrollBottom,
                 1);

          DWLScroll(ScreenVars.ScrollTop,ScreenVars.ScrollBottom,1);
        }
            break;

        case RI:     /* CURSOR UP WITH SCROLL */
        if (ScreenVars.CurrentRow > ScreenVars.ScrollTop)
            --ScreenVars.CurrentRow;
        else
        if (ScreenVars.CurrentRow == ScreenVars.ScrollTop)
        {
        //ScrollVEx (&ScreenImage[0][0],
          //       &AttributeMap[0][0],
          //       NULL,
         //    (LPSCREENVARS)&ScreenVars,
         //    hWndMain,
         //    ScreenVars.ScrollTop,
         //    ScreenVars.ScrollBottom,
         //    -1,
            //      (BUTTONDATA FAR *)&bd,
        //      (LPFONTVARS)&FontVars);
          ScrollVEx (hWndMain,
                    ScreenVars.ScrollTop,
                    ScreenVars.ScrollBottom,
                    -1);

         DWLScroll(ScreenVars.ScrollTop,ScreenVars.ScrollBottom,-1);
         }
            break;

        case NEL:    /* NEXT LINE WITH SCROLL */
        if (ScreenVars.CurrentRow == ScreenVars.ScrollBottom)
        {
            //ScrollVEx (&ScreenImage[0][0],
          //       &AttributeMap[0][0],
          //       NULL,
         //    (LPSCREENVARS)&ScreenVars,
           //       hWndMain,
         //    ScreenVars.ScrollTop,
         //    ScreenVars.ScrollBottom,
         //    1,
            //      (BUTTONDATA FAR *)&bd,
        //      (LPFONTVARS)&FontVars);
          ScrollVEx(hWndMain,
                    ScreenVars.ScrollTop,
                   ScreenVars.ScrollBottom,
                   1);


          DWLScroll(ScreenVars.ScrollTop,ScreenVars.ScrollBottom,1);
       }
        else
            ++ScreenVars.CurrentRow;
        ScreenVars.CurrentCol = 0;
            break;

    case DECSC:
        DecSc();  /*NEWBIT*/
            break;

        case DECRC:
        if(!CurSaveDone)    /* if not save was done then we use the default settings */
          SaveCursor = DefaultCursor;

        CurSaveDone = FALSE;
        ScreenVars.CurrentCol = SaveCursor.Col;
        ScreenVars.CurrentRow = SaveCursor.Row;
        bd.Terminal.TermOptions.Autowrap = SaveCursor.Wrap;
        VTFlags.fOrigin = SaveCursor.Origin;
        VTFlags.SelectErasable = SaveCursor.SelectErase;
        CharacterSet0 = SaveCursor.Chars0;
        CharacterSet1 = SaveCursor.Chars1;
      if(SaveCursor.CurrentSet)
        CurrentSet = &CharacterSet1;
      else
        CurrentSet = &CharacterSet0;
        fBold = SaveCursor.Bold;
        fUnderscore = SaveCursor.Under;
        fBlink = SaveCursor.Blink;
        fReverse = SaveCursor.Reverse;
            break;

        case HTS:
        ScreenVars.TabStops[ScreenVars.CurrentCol] = 1;
      break;

    case 'N':
    case 'O':
        fOneNormal = TRUE;
        break;

    case 'Z':
#ifdef TERM320
      if(tWatch)
         SendDataBlock(IdentifyString,16,FALSE);
#endif
        PutComm(hWndMain,(LPSTR)IdentifyString, 16,(LPBUTTONDATA)&bd,(LPCOMMSVARS)&CommsVars,(BOOL FAR *)&fWaitingConnection);
        break;    
    case DECSWL:    /* reset to a single width line */
        DecDWL[ScreenVars.CurrentRow].LineUsed = FALSE;
      DecDWL[ScreenVars.CurrentRow].LineType = ZERO;
         ScreenVars.LineUpdate[ScreenVars.CurrentRow] = TRUE;
        break;

    case DECDHLTOP:
    case DECDHLBOT:
    case DECDWL:    /* set up for single height double width */
        if(!DecDWL[ScreenVars.CurrentRow].LineUsed)
          ClearEx (&ScreenImage[0][0],            /* clear the 2nd hlaf of the line */
                 &AttributeMap[0][0],
                 NULL,
                 hWndMain,
                   (LPSCREENVARS)&ScreenVars,
                 (LPFONTVARS)&FontVars,
                 ScreenVars.CurrentRow,
                 ScreenVars.EndCol/2,
                 ScreenVars.CurrentRow,
                 ScreenVars.EndCol,
                 FALSE);

         ScreenVars.LineUpdate[ScreenVars.CurrentRow] = FALSE;
      DecDWL[ScreenVars.CurrentRow].LineUsed = TRUE;
      DecDWL[ScreenVars.CurrentRow].LineType = c;  /* the type of line */
         break;
    default:
      if((c < '@') || (c > 0x7e))
          State = SQU_ERROR;
        break;
   }
}







/************************************************************************
*
        VT100Private - Check for VT100 private sequences
*
*************************************************************************/

VOID    VT100Private (c)

BYTE    c;

{
    extern     WORD fOldTermType;
    extern  BOOL ReverseScreen;
    int    line,col;
    BYTE  forecolor,
         backcolor;
    LPBYTE tAttri;
    WORD  temp;

#define DECSCL    0x70  /* 'p' Selects Terminal type */

#define VT100MODE  61   
#define VT200MODE  62  /* the two possible modes */

  State = NORMAL;

    switch (c)
     {
    case DECSCL:      /* 'p' Terminal type set up */
        if(Param[0] == VT100MODE)  /* 61 */
          {
        SelectTransmissionStyle('F');
          bd.Terminal.TermOptions.TermType = CDK_VT100;
          }
        else  /* this is 62 but assume any other numer gives us back a VT320 */
          { 
          bd.Terminal.TermOptions.TermType = CDK_VT320;
            if(Param[1] == (BYTE)1)
           SelectTransmissionStyle('F');
            else
           SelectTransmissionStyle('G');
          }
        break;
           
    case 'q': /* DECSCA SELECT CHARACTER ATTRIBUTES VT220 */
        if(bd.Terminal.TermOptions.TermType != CDK_VT100)
          {
          if((Param[0] == 0) || (Param[0] == 2))
              VTFlags.SelectErasable = FALSE;
          else /* if (Param[0] == 1) */
              VTFlags.SelectErasable = TRUE;
          }
        break;

        case ED: /* SELECTIVE DISPLAY ERASE VT220 */
        if (Param[0] == 0)  /*  Erase from cursor to end of screen  */
          ClearEx (&ScreenImage[0][0],
               &AttributeMap[0][0],
               NULL,
               hWndMain,
                   (LPSCREENVARS)&ScreenVars,
               (LPFONTVARS)&FontVars,
               ScreenVars.CurrentRow,
               ScreenVars.CurrentCol,
               ScreenVars.EndRow,
               ScreenVars.EndCol,
               TRUE);
        else
        if (Param[0] == 1)  /* Erase from screen start to cursor  */
          ClearEx (&ScreenImage[0][0],
               &AttributeMap[0][0],
               NULL,
               hWndMain,
                   (LPSCREENVARS)&ScreenVars,
               (LPFONTVARS)&FontVars,
               0,
               0,
               ScreenVars.CurrentRow,
               ScreenVars.CurrentCol - 1,
               TRUE);
        else
        if (Param[0] == 2)  /*  Erase all of screen  */
          ClearEx (&ScreenImage[0][0],
               &AttributeMap[0][0],
               NULL,
               hWndMain,
                   (LPSCREENVARS)&ScreenVars,
               (LPFONTVARS)&FontVars,
               0,
               0,
               ScreenVars.EndRow,
               ScreenVars.EndCol,
               TRUE);
        break;

        case EL: /* SELECTIVE LINE ERASE VT220 */
        if (Param[0] == 0)  /*  Erase from cursor to EOL  */
          ClearEx (&ScreenImage[0][0],
               &AttributeMap[0][0],
               NULL,
               hWndMain,
                   (LPSCREENVARS)&ScreenVars,
               (LPFONTVARS)&FontVars,
               ScreenVars.CurrentRow,
               ScreenVars.CurrentCol,
               ScreenVars.CurrentRow,
               ScreenVars.EndCol,
               TRUE);
        else
        if (Param[0] == 1)  /*  Erase from line start to cursor  */
          ClearEx (&ScreenImage[0][0],
               &AttributeMap[0][0],
               NULL,
               hWndMain,
                   (LPSCREENVARS)&ScreenVars,
               (LPFONTVARS)&FontVars,
               ScreenVars.CurrentRow,
               0,
               ScreenVars.CurrentRow,
               ScreenVars.CurrentCol,
               TRUE);
        else
        if (Param[0] == 2)  /*  Erase whole line  */
          ClearEx (&ScreenImage[0][0],
               &AttributeMap[0][0],
               NULL,
               hWndMain,
                   (LPSCREENVARS)&ScreenVars,
               (LPFONTVARS)&FontVars,
               ScreenVars.CurrentRow,
               0,
               ScreenVars.CurrentRow,
               ScreenVars.EndCol,
               TRUE);
        break;

        case DECSTBM:
        NewScrollSet(TRUE);  /* SET Scrolling Region */
        break;

        case 'l':
        case 'h':
        case 'i':
            switch (Param[0])
             {
                case DECCKM:    /* APPLICATION / CURSOR MODES */
            DecCkm(c);
            break;
        case DECANM:      /* VT52 Mode */
            if (c == 'l')
              {
               fOldTermType = bd.Terminal.TermOptions.TermType;
            bd.Terminal.TermOptions.TermType = CDK_VT52;
              }
            break;
        case DECCOLM:     /* COLUMN */
            if (!bd.Terminal.TermOptions.Cursor)
                       HideCaret (NULL);
            if((bd.Terminal.TermOptions.TermType == CDK_VT320)&&(bd.Terminal.TermOptions.StatusLine == CDK_HOSTWRITE))
              {
               tEndRow = ScreenVars.EndRow;
              ScreenVars.EndRow = LASTLINE;
              }

            if (c == 'h')
             {
                ChangeColMode (&ScreenImage[0][0],
                          &AttributeMap[0][0],
                          NULL,
                     hWndMain,
                     (LPFONTVARS)&FontVars,
                     (LPSCREENVARS)&ScreenVars,
                     (LPVTFLAGS)&VTFlags,
                     LASTCOL,(LPBUTTONDATA)&bd);
            if (VTFlags.fMaximized)    /* if we're maximized then add the scroll bar */
                SetScrollBars (TRUE);

                ChangeVTFont(hWndMain,AutoFontSelection((LPFONTSIZE)&FontSize[0],     /*  MID  29/06/1989  */
                 hWndMain,
                 (LPSCREENVARS)&ScreenVars,
                 FontVars.FontsLoaded)); 

              InvalidateRect(hWndMain,NULL,TRUE);
               }
            else
            if (c == 'l')
             {
                ChangeColMode (&ScreenImage[0][0],
                          &AttributeMap[0][0],
                          NULL,
                     hWndMain,
                         (LPFONTVARS)&FontVars,
                     (LPSCREENVARS)&ScreenVars,
                     (LPVTFLAGS)&VTFlags,
                     ID_80COL,(LPBUTTONDATA)&bd);

            if (VTFlags.fMaximized)    /* if we're maximized then remove the scroll bar */
                SetScrollBars (FALSE);

                   ChangeVTFont(hWndMain,AutoFontSelection((LPFONTSIZE)&FontSize[0],     /*  MID  29/06/1989  */
                 hWndMain,
                 (LPSCREENVARS)&ScreenVars,
                 FontVars.FontsLoaded));

              InvalidateRect(hWndMain,NULL,TRUE);
             }

            if((bd.Terminal.TermOptions.TermType == CDK_VT320)&&(bd.Terminal.TermOptions.StatusLine == CDK_HOSTWRITE))
            ScreenVars.EndRow = tEndRow;

            if(!bd.Terminal.TermOptions.Cursor && (GetFocus() == hWndMain))
              {
              SetCaretPos (CaretXPos(), CaretYPos());
            ShowCaret(NULL);
              }
            /* set Param array before resetting the scroll region */
            Param[0] = 1;
            Param[1] = 24;  /* default vals */
            Pnum = 2;
            NewScrollSet(TRUE);  
                   break;
                case DECSCNM:   /* SCREEN REVERSE / NORMAL */
            if (c == 'i')
              StartAutoPrint(DO_TITLE);  /* Start the auto print mode */
            else
             { 
            if((!ReverseScreen && (c == 'h')) || (ReverseScreen && (c == 'l')))
              {
                     ReverseScreenEx((LPSTR)bd.Data,(LPSTR)AttributeMap,(LPSCREENVARS)&ScreenVars);

                     for (line = 0; line < LASTLINE; line++)
                        if(!DecDWL[line].LineUsed)
                       ScreenVars.LineUpdate[line] = TRUE;
                    
                if(c == 'h')
                  ReverseScreen = TRUE;     /* set up for soft terminal reset */
                else
                  ReverseScreen = FALSE;
            }
              }
                  break;

                case DECOM:     /* ORIGIN */
            DecOm(c);
                     break;

                 case DECAWM:    /* AUTOWRAP */
               DecAwm(c);
                     break;

                 case DECTCEM:  /*  Hide and show cursor  */
            DecTcem(c);
            break;

                 case AUTOPRNOFF:  /* Auto Print Off */
            if(c == 'i')
            EndAutoPrint(DO_TITLE);  /* End the auto print mode */
                     break;

        case DECPFF:  /*  MID  12/09/1988   FF after print screen  */
            if (c == 'h')
                VTFlags.fFormFeed = TRUE;
            else
            if (c == 'l')
                VTFlags.fFormFeed = FALSE;
            break;

        case DECPEX:  /*  MID  12/09/1988   Print region  */
            if (c == 'h')
                VTFlags.fPrintExtent = FALSE;
            else
            if (c == 'l')
                VTFlags.fPrintExtent = TRUE;
            break;

             }
      break;
    default:
      if((c < '@') || (c > 0x7e))
        State = SQU_ERROR;
      break;
     }
} 
\u2042 Texto original dispon\355vel em http://www.captaindebug.com/2012/04/importance-of-questioning-design.html

Desenvolvimento Advanced DLL Injection
Segunda-feira, 13/08/2012 \340s 11h00, por Alexey Lyashko

Neste artigo, irei abordar um assunto trivial (como pode parecer) como a inje\347\343o de DLL. Por alguma raz\343o, a maioria dos tutoriais na web nos d\341 apenas uma breve pincelada do tema, principalmente se limitando \340 chamada da fun\347\343o LoadLibraryA/W da API do Windows no espa\347o de endere\347o de outro processo. Embora n\343o seja de todo ruim, isso nos fornece a solu\347\343o menos flex\355vel. O que significa que toda a l\363gica deve ser codificada no DLL que queremos injetar. Por outro lado, podemos incorporar toda a gest\343o de configura\347\343o (carregar os arquivos de configura\347\343o, a an\341lise do mesmo etc.) em nossa DLL. Isso \351 melhor, mas ainda a enche com c\363digo que s\363 vai ser executado uma vez.

Vamos tentar outra abordagem. O que faremos \351 escrever um carregador (um execut\341vel que vai injetar nossa DLL em outro processo) e uma DLL pequeno, que ser\341 injetada. Para simplificar, o carregador tamb\351m criar\341 o processo que ser\341 o alvo. Sendo um usu\341rio do Linux, eu usei Flat Assembler e mingw32 para essa tarefa, mas voc\352 pode ajustar o c\363digo para qualquer ambiente que preferir. Uma breve observa\347\343o para os nerds antes de come\347armos. O c\363digo neste artigo n\343o cont\351m quaisquer verifica\347\365es de seguran\347a (por exemplo, corre\347\343o de verifica\347\343o do valor retornado pela fun\347\343o espec\355fica), a menos que seja necess\341rio como um exemplo. Caso decida experiment\341-lo, voc\352 estar\341 fazendo isso por sua pr\363pria conta e risco.

Ent\343o, vamos come\347ar a divers\343o. Cria\347\343o do processo que ser\341 o alvo Vamos supor que o carregador j\341 passou a fase de carregamento e an\341lise de arquivos de configura\347\343o e est\341 pronto para iniciar o trabalho real.

O Windows nos fornece todas as ferramentas que precisamos para iniciar um processo. H\341 mais de uma maneira de fazer isso, mas vamos usar a mais simples: a fun\347\343o de API do CreateProcess. Sua declara\347\343o parece muito assustadora, mas vamos faz\352-la da maneira mais f\341cil poss\355vel:

   BOOL WINAPI CreateProcess(
      __in_opt    LPCTSTR lpApplicationName,
      __inout_opt LPTSTR lpCommandLine,
      __in_opt    LPSECURITY_ATTRIBUTES lpProcessAttributes,
      __in_opt    LPSECURITY_ATTRIBUTES lpThreadAttributes,
      __in        BOOL bInheritHandles,
      __in        DWORD dwCreationFlags,
      __in_opt    LPVOID lpEnvironment,
      __in_opt    LPCTSTR lpCurrentDirectory,
      __in        LPSTARTUPINFO lpStartupInfo,
      __out       LPPROCESS_INFORMATION lpProcessInformation
   );

Ao chamar essa fun\347\343o, n\363s s\363 temos que especificar metade dos par\342metros e definir todo o resto para NULL. Essa fun\347\343o possui duas variantes CreateProcessA e CreateProcessW como vers\365es ASCII e Unicode, respectivamente. Vamos continuar fi\351is ao ASCII o tempo todo, ent\343o, o nosso c\363digo ficaria assim (devido ao fato de que "CreateProcess" \351 mais um macro do que nome de fun\347\343o, devemos especificar a vers\343o A, pois alguns compiladores tendem a usar como padr\343o a vers\343o W):

CreateProcessA(nameOfTheFile, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startupInfo, &processInformation);
N\343o se esque\347a de definir o campo cb do startupInfo para (DWORD) sizeof (STARTUPINFO), caso contr\341rio ele n\343o ir\341 funcionar.

Se a fun\347\343o tiver \352xito, obteremos todas as informa\347\365es sobre o processo (handles e IDs) na estrutura processInformation, que tem o seguinte prot\363tipo:

 typedef struct _PROCESS_INFORMATION
{
   HANDLE hProcess;    //Handle to the process
   HANDLE hThread;     //Handle to the main thread of the process
   DWORD  dwProcessId; //ID of the new process
   DWORD  dwThreadId;  //ID of the main thread of the process
}PROCESS_INFORMATION, *LPPROCESS_INFORMATION;

A essa altura, o processo foi criado, mas est\341 suspenso. Isso significa que ele ainda n\343o iniciou a sua execu\347\343o e n\343o vai at\351 chamarmos ResumeThread (processInformation.dwThreadId) dizendo ao sistema operacional para retomar a thread principal do processo, mas essa vai ser a \372ltima a\347\343o realizada pelo nosso carregador.

Lancet

Pode-se cham\341-lo de shellcode, mas n\343o tem nada a ver com a carga viral ou qualquer outra inten\347\343o maliciosa (a menos que algu\351m diga que invadir o espa\347o de endere\347os de outro processo \351 malicioso). \311 o c\363digo que injetaremos no processo que ser\341 o alvo. Ele, teoricamente, pode ser escrito em qualquer linguagem, desde que seja independente da posi\347\343o e compilado em instru\347\365es nativas (em nosso caso, instru\347\365es x86), mas eu prefiro fazer essas coisas em linguagem Assembly. \311 sempre uma boa ideia pensar no que o seu c\363digo se destina a fazer antes de escrever uma \372nica linha dele. Nesse caso, \351 uma ideia de ouro. O c\363digo precisa ser pequeno, de prefer\352ncia r\341pido e est\341vel, pois pode dar um pouco de dor de cabe\347a para depurar, uma vez que tiver sido injetado.

Existem duas tarefas b\341sicas que voc\352 vai querer atribuir a esse c\363digo:

  1. Carregar a nossa DLL
  2. Chamar o procedimento de inicializa\347\343o exportado pela nossa DLL e uma condi\347\343o inevit\341vel - ele tem que ser uma fun\347\343o declarada como callback ThreadProc, devido ao fato de que usaremos a fun\347\343o CreateRemoteThread para lan\347\341-lo. O prot\363tipo de uma fun\347\343o callback ThreadProc se parece com isto:
    DWORD WINAPI ThreadProc( __in LPVOID lpParameter);
    
    o que significa que ele tem que retornar um valor do tipo DWORD. Ele aceita um par\342metro, que pode ser um valor real (mas voc\352 precisa convert\352-lo para tipo LPVOID) ou um ponteiro para um array de par\342metros. S\363 mais uma coisa sobre essa fun\347\343o (a \372ltima mas n\343o menos importante!): \351 uma fun\347\343o stdcall macro WINAPI definida como __declspec (stdcall). Isso significa que nossa fun\347\343o precisa cuidar da limpeza da pilha antes do retorno. No nosso caso, \351 muito f\341cil, basta usar ret 0x04 (assumindo que o tamanho de LPVOID seja de 4 bytes).

Outra coisa importante a mencionar - voc\352 vai, obviamente, precisar saber quantos bytes sua fun\347\343o ocupa, a fim de alocar mem\363ria no espa\347o de endere\347o do processo que ser\341 o alvo e mover seu c\363digo corretamente l\341. Al\351m da aloca\347\343o de um bloco de mem\363ria execut\341vel para nossa fun\347\343o, voc\352 precisa alocar um bloco de dados - defini\347\365es de configura\347\343o a serem passadas para a DLL injetada. \311 f\341cil passar o endere\347o dos par\342metros como um argumento para a nossa ThreadProc.

O esqueleto da fun\347\343o ficaria assim:

 lancet:
   push  ebp
   mov   ebp, esp
   sub   esp, as_much_space_as_you_need_for_variables
   push  registers_you_are_planning_to_use

   ;function body

   pop   registers_you_used
   mov   esp, ebp
   pop   ebp
   ret   0x04
lancet_size = $-lancet

A \372ltima linha nos d\341 o tamanho exato da fun\347\343o em bytes. A seguir est\341 o template de c\363digo fonte:

format MS COFF ;as we are going to link this file with our loader
public lancet as '_lancet'
section '.text' readable executable
lancet:
   ;our function goes here
   ;followed by data
   loadLibraryA  db 'LoadLibraryA',0
   init          db 'name_of_the_initialization_function',0
   ourDll        db 'name_of_our_dll',0
   kernel32      db 'kernel32.dll',0
lancet_size = $-lancet
public lsize as '_lancet_size'
section '.data' readable writeable
   lsize         dd lancet_size

Ent\343o, o que \351 que vamos inserir no "corpo da fun\347\343o"? Primeiramente, como o nosso c\363digo, uma vez injetado, n\343o tem ideia de onde ele est\341 na mem\363ria, devemos salvar o nosso "endere\347o base" e calcular todas os offsets relativos a esse endere\347o. Isso \351 feito de uma maneira simples. Chamamos o pr\363ximo endere\347o e colocamos o endere\347o de retorno em nossa vari\341vel local.

   call @f
  @@:
   pop  dword [ebp-4]
   sub  dword [ebp-4], @b-lancet

\311 isso. Agora a vari\341vel em [ebp-4] cont\351m o nosso "endere\347o base". Cada vez quisermos chamar outra fun\347\343o ou acessar nossos dados (strings com nomes, lembra?) n\363s devemos fazer o seguinte:

   mov  ebx, [ebp-4]
   add  ebx, ourDll-lancet
   push ebx
   mov  ebx, [ebp-8] ;assume that we stored the address of LoadLibraryA at [ebp-8]
   call dword ebx

O c\363digo acima \351 um equivalente a LoadLibraryA ("name_of_our_dll"). Agora vamos falar sobre a execu\347\343o propriamente dita. Embora saibamos onde estamos, n\343o temos idsia de qual \351 o endere\347o de LoadLibraryA. H\341, pelo menos, duas maneiras de obter o endere\347o direitinho. A primeira foi descrita neste meu artigo. A segunda tamb\351m \351 interessante - PEB. Sim, n\363s estamos indo acessar o Process Environment Block, encontrar a estrutura LDR_MODULE que se refere ao KERNEL32.DLL, e obter o seu endere\347o de base (que \351 tamb\351m um handle para a biblioteca). Alguns podem dizer que essa forma n\343o \351 confi\341vel, n\343o \351 est\341vel e que \351 at\351 perigosa, mas eu digo que declara\347\365es como essas n\343o s\343o s\351rias. N\343o vamos mudar nada nessas estruturas. N\363s s\363 vamos analis\341-las. De que jeito podemos encontrar o PEB? Isso \351 muito simples. Ele est\341 localizado em [FS:0x30]. Uma vez que o temos, estamos a caminho do endere\347o PEB_LDR_DATA, que est\341 no PEB+0x0C. A fim de analisar a estrutura PEB_LDR_DATA, devemos declarar o seguinte em nosso c\363digo Assembly:

struc list_entry
{
   .flink dd ?   ;pointer to next list_entry structure
   .blink dd ?   ;pointer to previous list_entry structure
}


struc peb_ldr_data
{
   .length      dd ?
   .initialized db ?
                db ?
                db ?
                db ?
   .ssHandle    dd ?
   .inLoadOrderModuleList list_entry ;we are going to use this list
   .inMemoryOrderModuleList list_entry
   .inInitializationOrderModuleList list_entry
}


struc ldr_module
{
   .inLoadOrderModuleList list_entry ;pointers to previous and next modules in list
   .inMemoryOrderModuleList list_entry
   .inInitializationOrderModuleList list_entry
   .baseAddress   dd ?           ;This is what we need!
   .entryPoint    dd ?
   .sizeOfImage   dd ?
   .fullDllName   unicode_string ;full path to the module file
   .baseDllName   unicode_string ;name of the module file
   .flags         dd ?
   .loadCount     dw ?
   .tlsIndex      dw ?
   .hashTable     list_entry
   .timeDateStamp dd ?
}

Vou deixar a implementa\347\343o da fun\347\343o de an\341lise de m\363dulo de lista pra voc\352. Voc\352 s\363 tem que manter em mente que a string que voc\352 vai verificar \351 representada pela estrutura UNICODE_STRING (descrita no artigo mencionado acima). Outra coisa para lembrar \351 que \351 melhor implementar a fun\347\343o case insensitive de compara\347\343o de strings. Depois de encontrar o LDR_MODULE, cuja baseDllName \351 "kernel32.dll", voc\352 tem seu handle (apenas no campo baseAddress). Voc\352 pode usar a fun\347\343o _get_proc_address do mesmo artigo (mencionado acima) para obter o endere\347o da fun\347\343o LoadLibraryA. Tendo esse endere\347o, voc\352 est\341 pronto para carregar sua DLL (fa\347a a inje\347\343o real). Sugest\343o pessoal - n\343o colocar um monte de c\363digo para a fun\347\343o DllMain.

LoadLibraryA retorna um handle para a DLL rec\351m-carregada, que voc\352 pode usar para localizar a fun\347\343o de inicializa\347\343o (lembre que ela tem que ser exportada por sua DLL e de prefer\352ncia usar a conven\347\343o stdcall). Depois que voc\352 usar _get_proc_address em sua fun\347\343o de inicializa\347\343o, chame-a e passe o endere\347o do bloco de dados como um par\342metro (que foi passado para a nossa fun\347\343o lancet como um par\342metro na pilha):

   push dword [ebp+8]  ;parameter passed to lancet is here
   call dword [ebp-12] ;assume that you stored the address of the initialization 
                       ;function here

\311 isso a\355. O seu c\363digo agora pode retornar. A DLL foi injetada e inicializada. Inje\347\343o

De alguma forma, perdemos o empolgante processo de inje\347\343o de nosso c\363digo lancet. N\343o se preocupe, n\343o me esqueci disso. Como j\341 mencionei acima, temos que alocar dois blocos - para c\363digo e para dados. Isso pode ser feito chamando a fun\347\343o VirtualAllocEx, o que permite aloca\347\365es de mem\363ria no espa\347o de endere\347o de outro processo.

LPVOID WINAPI VirtualAllocEx(
   __in     HANDLE hProcess,
   __in_opt LPVOID lpAddress,
   __in     SIZE_T dwSize,
   __in     DWORD  flAllocationType,
   __in     DWORD  flProtect
);

Use MEM_COMMIT como flAllocationType, e PAGE_EXECUTE_READWRITE e PAGE_READWRITE para aloca\347\343o de c\363digo e bloco de dados, respectivamente. Essa fun\347\343o retorna o endere\347o do bloco alocado no espa\347o de endere\347o do processo especificado ou NULL. A fun\347\343o WriteProcessMemory da API \351 usada para copiar o c\363digo e os dados no espa\347o de endere\347o do processo que ser\341 o alvo.

BOOL WINAPI WriteProcessMemory(
   __in  HANDLE  hProcess,
   __in  LPVOID  lpBaseAddress,
   __in  LPCVOID lpBuffer,
   __in  SIZE_T nSize,
   __out SIZE_T*lpNumberOfBytesWritten
);

Depois de ter copiado tanto o dado quanto o c\363digo, voc\352 vai querer chamar sua fun\347\343o thread. A \372nica maneira de chamar uma fun\347\343o que reside na mem\363ria de outro processo \351 chamando a API CreateRemoteThread.

HANDLE WINAPI CreateRemoteThread(
   __in  HANDLE hProcess, //the handle to our process
   __in  LPSECURITY_ATTRIBUTES lpThreadAttributes, //may be NULL
   __in  SIZE_T dwStackSize, //may be 0
   __in  LPTHREAD_START_ROUTINE, //the address of our code block
   __in  LPVOID lpParameter, //the address of our data block
   __in  DWORD  dwCreationFlags, //may be 0
   __out LPDWORD lpThreadId  //may be NULL
);

Essa fun\347\343o retorna um handle para a thread remota, que, por sua vez, pode ser passada para a fun\347\343o WaiForSingleObject da API, para que possamos receber uma notifica\347\343o em seu retorno.

Eu decidi n\343o abordar as possibilidades que sua DLL pode fazer enquanto estiver anexada ao processo que ser\341 o alvo. Deixo isso pra voc\352. Espero que este artigo n\343o tenha sido muito confuso, e sim \372til.

\u2042
Texto original dispon\355vel em http://syprog.blogspot.com.br/2011/11/advanced-dll-injection.html


. Dia: 14/08/2012

http://syprog.blogspot.com.br/?m=1

System Programming

This blog is dedicated to low level programming in Assembler and C/C++ (although, C++ is unwelcome) in either *Nix or Windows based operating systems.

Saturday, November 26, 2011


.NET Melhorando desempenho de aplicativos .NET Parte 12
Segunda-feira, 13/08/2012 \340s 10h30, por Hovhannes Avoyan

Em nosso artigo anterior, n\363s discutimos sobre \u201cItera\347\343o e Looping\u201d. Hoje iremos nos concentrar na otimiza\347\343o de opera\347\365es de string.

O Framework .NET fornece o tipo de dado System.String para representar uma string. A manipula\347\343o intensiva de strings pode degradar o desempenho. Toda vez que voc\352 executar uma opera\347\343o para mudar os dados da strings, a string original na mem\363ria \351 descartada para um coletor de lixo posterior e uma nova \351 criada para armazenar os dados de sequ\352ncia de novos caracteres. Observe tamb\351m que o tipo String \351 um tipo de refer\352ncia, por isso os conte\372dos dela s\343o armazenados em um heap gerenciado. Como resultado, as strings devem ser coletadas para serem limpas.

Esta se\347\343o resume as recomenda\347\365es que voc\352 deve levar em conta quando se trabalha com strings.

Evite concatena\347\343o de string ineficiente A concatena\347\343o excessiva de strings resulta em muitas opera\347\365es de aloca\347\343o e desaloca\347\343o, pois cada vez que voc\352 realiza uma opera\347\343o para alterar a string, uma nova \351 criada e a antiga \351 posteriormente coletada pelo coletor de lixo.

Se voc\352 concatenar strings literais, o compilador ir\341 concaten\341-las no tempo de compila\347\343o. //\u2019Hello\u2019 and \u2018world\u2019 are string literals String str = \u201cHello\u201d + \u201cworld\u201d;

Se voc\352 concatenar as sequ\352ncias n\343o-literais, fa\347a uma concatena\347\343o neles em tempo de execu\347\343o. Ent\343o, usar o operador + cria v\341rios objetos strings no heap gerenciado. Use o StringBuilder para manipula\347\365es de strings complexas e tamb\351m quando precisar concatenar strings v\341rias vezes.

// using String and \u2018+\u2019 to append
String str = \u201cSome Text\u201d;
for ( \u2026 loop several times to build the string \u2026) {
  str = str + \u201d additional text \u201c;
}
// using String and .Append method to append
StringBuilder strBuilder = new StringBuilder(\u201cSome Text \u201c);
for ( \u2026 loop several times to build the string \u2026) {
  strBuilder.Append(\u201d additional text \u201c);
}

Use + quando o n\372mero de Appends for conhecido

Se voc\352 souba o n\372mero de appends a ser feito e voc\352 est\341 concatenando as strings de uma vez s\363, prefira o operador + para a concatena\347\343o. String str = str1+str2+str3;

Caso voc\352 concatene as strings em uma \372nica express\343o, ent\343o ser\341 preciso fazer apenas uma chamada para String.Concat. Isso n\343o resulta em nenhuma string tempor\341ria (para combina\347\365es parciais das strings a serem concatenadas).

Evite usar + em strings dentro de um loop ou de m\372ltiplas itera\347\365es. Use StringBuilder no lugar. Use StringBuilder quando o n\372mero de Appends for desconhecido

Se voc\352 n\343o souber o n\372mero de appends que precisa ser feito, o que poderia ser o caso quando iterar por um loop ou a constru\347\343o de pesquisas din\342micas de SQL, use a classe StringBuilder, como mostrado no exemplo seguinte:

for (int i=0; i< Results.Count; i++)
{
  StringBuilder.Append (Results[i]);
} 

A classe StringBuilder come\347a com uma capacidade inicial padr\343o de 16. Strings inferiores a capacidade inicial s\343o armazenadas no objeto StringBuilder. A capacidade inicial do buffer pode ser definida usando o seguinte construtor sobrecarregado.

public StringBuilder (int capacidade); Voc\352 pode continuar a concatenar sem aloca\347\365es adicionais at\351 voc\352 consumir o buffer alocado pr\351viamente. Como resultado, usar um objeto StringBuilder \351 muitas vezes mais eficiente do que usar objetos string para concatena\347\343o. Se voc\352 concatenar mais ainda, a classe StringBuilder vai gerar um novo buffer com o dobro da da capacidade atual.

Ent\343o, se voc\352 come\347ar com um StringBuilder de tamanho 16 e exceder o limite, o StringBuilder vai aloca um novo buffer de tamanho 32 e copiar a sequ\352ncia antiga para o novo buffer. O antigo ser\341 inacess\355vel e se tornar\341 eleg\355vel para garbage collection. Voc\352 deve tentar configurar a capacidade inicial do StringBuilder a um valor ideal para reduzir o custo de novas atribui\347\365es. A melhor maneira para controlar o consumo de mem\363ria usando o CLR Profiler \351 determinar o valor ideal para o seu caso.

Trate StringBuilder como um acumulador Voc\352 pode tratar o StringBuilder como um acumulador ou buffer reutiliz\341vel. Isso ajuda a evitar as aloca\347\365es de sequ\352ncias tempor\341rias durante as m\372ltiplas itera\347\365es append. Aqui est\343o algumas das situa\347\365es onde isso pode ajudar: