2011년6월13일_이상한 나라의 이상한 CM샘의 이상한 소스(HexaViewer)를 이상하게 분석하는 이상한 보고서를 이상한 나

 

 

 

 

이상한 CM샘의 이상한 소스(Hexa Viewer) 전체


소스코드…수업 마치고 갑자기 들어 오셔서 던져 주신 이상한 소스코드...


   1:  #include <stdio.h>
   2:   
   3:  #define    ROW_LINE        16    // 메모리 출력 행 수
   4:   
   5:   
   6:  void MSDFunction(void *, unsigned int);
   7:   
   8:  int main()
   9:  {
  10:      int iNum = 0x12345678;
  11:      MSDFunction(&iNum, 10);
  12:   
  13:      return 0;
  14:  }
  15:   
  16:  void MSDFunction(void *vAddr, unsigned int print_line)
  17:  // Memory Status Display Function
  18:  /*******************************************************************************
  19:  기능   : 인수로 넘겨받은 주소로부터 ROW_LINE개 단위를 1줄로 print_line의 숫자 만큼
  20:  화면에 출력
  21:  인수   : 출력할 대상이 있는 곳의 주소값, 메모리 출력시 출력 라인 수
  22:  반환값   : void
  23:  *******************************************************************************/
  24:  {
  25:    unsigned char        *addr = (unsigned char *)vAddr;
  26:    unsigned int        loop_temp   = 0;     // 반복문을 위한 임시 변수 선언
  27:    unsigned char        memory_dump[ROW_LINE];     // 반환된 메모리값을 임시로 저장
  28:   
  29:    if (0 == *addr)
  30:    {
  31:        return;
  32:    }
  33:    else
  34:    {
  35:      printf(" Address   ");         // 화면 상단 자리 표시를 위한 출력
  36:    }
  37:    
  38:    while (loop_temp < ROW_LINE)       // Hex 부분 출력
  39:    {
  40:      printf("%02X ", loop_temp++);
  41:    }
  42:   
  43:    putchar(' ');
  44:    loop_temp = 0;
  45:   
  46:    while (loop_temp < ROW_LINE)       // ASCII 부분 출력
  47:    {
  48:      printf("%X", loop_temp++);
  49:    }
  50:   
  51:    putchar('\n');
  52:   
  53:    while (0 < print_line)           // Data 부분 출력 루프 시작
  54:    {
  55:      loop_temp = 0;
  56:      printf("0x%08X ", addr);     // 메모리 주소 출력
  57:   
  58:      while (1)                 // 메모리 읽어 오기 및 hex 출력 시작
  59:      {
  60:        // 메모리 주소에 위치한 값을 배열에 저장
  61:        *(memory_dump + loop_temp) = *addr;
  62:   
  63:        // 배열에 저장된 값 출력
  64:        printf("%02X ", *(memory_dump + loop_temp));
  65:   
  66:        ++loop_temp;
  67:        ++addr;
  68:   
  69:        if (0 == (loop_temp % ROW_LINE))  // ROW_LINE개를 출력하였으면 loop 종료
  70:        {
  71:          break;
  72:        }
  73:        else
  74:        {
  75:        }
  76:      }                   // 메모리 읽어 오기 및 hex 출력 끝
  77:   
  78:      putchar(' ');
  79:      loop_temp = 0;
  80:   
  81:      while (1)               // ASCII 부분 출력 루프 시작
  82:      {
  83:        if (0 == *(memory_dump + loop_temp))
  84:        {
  85:          putchar('.');         // 널 문자 대치
  86:        }
  87:        else if (32 > *(memory_dump + loop_temp))
  88:        {
  89:          putchar('*');         // 제어 문자 대치
  90:        }
  91:        else if (127 <= *(memory_dump + loop_temp))
  92:        {
  93:          putchar('*');         // 그래픽 문자 대치
  94:        }
  95:        else
  96:        {
  97:          putchar(*(memory_dump + loop_temp));
  98:        }
  99:   
 100:        ++loop_temp;
 101:   
 102:        if (0 == (loop_temp % ROW_LINE))  // ROW_LINE개를 출력하였으면 loop 종료
 103:        {
 104:          break;
 105:        }
 106:        else
 107:        {
 108:        }
 109:      }                   // ASCII 부분 출력 루프 끝
 110:   
 111:      putchar('\n');
 112:      --print_line;
 113:    }                     // Data 출력 루프 끝
 114:   
 115:    putchar('\n');
 116:  }
 117:   

 

 

 

 

분석

 

 

전처리부

 

   1:  #include <stdio.h>
   2:   
   3:  #define    ROW_LINE    16    // 메모리 출력 행 수
   4:   
   5:  void MSDFunction(void *, unsigned int);


표준 입출력 라이브러리는 다들 아실거고…
ROW_LINE은 화면에 출력되는 메모리값의 행의 수라고 주석에 명시되어 있으나…
실제 아래의 소스를 들을 보면 행의 수가 아닌 열의 수이다.

그러니 COL_LINE으로 명칭변경을 하여야 할 것이다.

처음부터 이상한 나라의 이상한 CM샘의 이상한 소스 코드가 시작되었다.


MSDFunction( ) 함수의 원형이 선언이 되었다. 함수의 원형에 있는 인수리스트에는 자료형만 적어도 된다.
MSD이름만 봐선 무슨일을 하는 함수인지 전혀 모르겠다.

이상해! 이상해!

 

 

 

main( ) 프로그램의 시작

 

   1:  int main()
   2:  {
   3:      int iNum = 0x12345678;
   4:      MSDFunction(&iNum, 10);
   5:   
   6:      return 0;
   7:  }


iNum에 HEXA값을 확인하기 쉽도록 16진수 12345678을 넣고 그 주소와 화면에 출력할 행의 수 10을 인자로 넣는다.
여기서 첫 번째 인자자리가 함수의 원형을 보면 void*로 특정한 형태가 없는 포인터형이다.

void* (void 포인터)란?

가리키는 곳의 크기를 모른다. void와는 완전 다른 개념으로 char인지 short인지 int인지 알 수 없다는 뜻이다.
즉, 가리키는 곳이 1Byte가 될 수도 2Bytes가 될 수도 있다. 마치 포커에서 조커와 비슷하다고 볼 수 있다.

예를 들어 아래와 같이,

   1:  int A = 100;
   2:  int *ip;
   3:  char *cp;
   4:  float *fp;
   5:  void *vp;
   6:   
   7:  ip = &A;
   8:  cp = ip;          //경고메세지를 출력하나 포인터라 크기는 같아 대입은 된다.
   9:  vp = ip;         //경고메세지가 출력되지 않고 잘 된다.
  10:  vp = cp;        //경고메세지가 출력되지 않고 잘 된다. (vp는 아무 타입이나 다 받아 들임,)
  11:                       //혈액형 AB형과 비슷하군...A, B ,O형 어느 혈액형이나 수혈가능함.
  12:  *ip = 3;                //A의 값을 3으로 바꿈.
  13:  *vp = 9;              //에러!  쓸 곳의 크기를 몰라. 
  14:  *vp = (int *)9;    //int형 포인터로 캐스팅하면 됨.
  15:   
  16:  ip = vp;               //역은 안 됨.  ip는 크기가 정해져 있으나 vp는 크기를 몰라
  17:  int B  = *vp;        /* *를 붙여 값을 읽어와 대입하려 해도 안 됨. */

void *vp는 AB형 혈액형과 같아 여러 혈액형의 혈액을 받을 수 있으나 다른 혈액형을 가진 사람에게 줄 수 없다.
(상기의 코드는 테스트를 해보지 못 하였으니 100%신뢰하지 말 것)

 

   1:  int iNum = 0x12345678;
   2:  char cNum = 100;
   3:  short sNum = 65000;
   4:   
   5:  MSDFuntion(&iNum, 10);         //int형을 받아 들였고,
   6:  MSDFuntion(&cNum, 10);         //char형을 받아 들였고,
   7:  MSDFuntion(&sNum, 10);         /*short형을 받아 들여 어떤 자료형이든 다 받아 들인다.*/

하나의 함수로 여러 자료형의 변수를 받아 들일 수 있어 매우 편리해 보인다.

 

 

Memory Status Display Function


   1:  void MSDFunction(void *vAddr, unsigned int print_line)
   2:  // Memory Status Display Function
   3:  /*******************************************************************************
   4:  기능   : 인수로 넘겨받은 주소로부터 ROW_LINE개 단위를 1줄로 print_line의 숫자 만큼
   5:  화면에 출력
   6:  인수   : 출력할 대상이 있는 곳의 주소값, 메모리 출력시 출력 라인 수
   7:  반환값   : void
   8:  *******************************************************************************/


MSD가 옛날 라면에 첨가된 화학조미료 이름인줄 알았는데,
그게 아니라 메모리 상태를 화면에 출력하는 함수다. HexaView( )과 같다고 할 수 있다.
이렇게 함수에 박스주석을 달아 주면 오랜 시간이 흘러도 자신이 만든 소스를 쉽게 파악할 수 있다.
즉, 외계인코드를 방지할 수 있다.


   1:    unsigned char        *addr = (unsigned char *)vAddr;
   2:    unsigned int        loop_temp   = 0;     // 반복문을 위한 임시 변수 선언
   3:    unsigned char        memory_dump[ROW_LINE];     /* 반환된 메모리값을 임시로 저장 */

unsigned char형 포인터 변수 addr을 선언하고 인수받은 void포인터변수 vAddr의

//여기서 부터 편집하면 됨.