Assembly

2013.09.30 _ ASM _( 메모리 영역 Context Switching )

성엽이 2013. 9. 30. 22:05


 MemtoCPU.c Source

#include <stdio.h>

#include <windows.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <WinNT.h>

#define  MAX_PROGRAM_SIZE  0x10000    // 64Kbyte
#define  SECTION_SIZE    512

typedef struct  _CONTEXT1
{
  int   efl;
  int  eip;
  int  edi;
  int  esi;
  int  ebp;
  int  esp;
  int  ebx;
  int  edx;
  int  ecx;
  int  eax;
}CONTEXT1;

void PrintCODE(void);
void PrintDATA(void);
void PrintSTACK(void);
void EXIT(void);
void HELP(void);
void PrintLOAD(void);
void Clear_mem(void);
void GO(void);

typedef struct _CmdMap
{
  void *vpCmd;
  void (*fp)(void);
}CmdMap;

CmdMap stCmdList[] =  {
      {"CODE" , PrintCODE},
      {"DATA" , PrintDATA},
      {"STACK", PrintSTACK},
      {"LOAD" , PrintLOAD},
      {"HELP" , HELP},  
      {"EXIT" , EXIT},
      {"MC", Clear_mem},
      {"GO", GO},
      {0,0}      
      };

static unsigned char sucMem[MAX_PROGRAM_SIZE*2];  // 128Kbyte , 동적할당 시작위치
static unsigned char *sucMem_end;      // 동적할당 끝 위치
static unsigned char *sucCODE;        // CODE 의 시작위치
static unsigned char *sucDATA;        // DATA 의 시작위치
static unsigned char *sucSTACK;        // STACK 의 시작위치
static unsigned char Load_Flag;        // 로드유무 표시
static unsigned char Display_Flag;      // 메모리값 출력시 계속해서
              // 출력하는 경우를 위해
static  int    iFd;          // 파일 입출력을 위한 파일디스크립션
static  CONTEXT1  stat_old;        // 기존의 레지스터값 저장

void HexaView(unsigned char *, unsigned int);
void PrintReg(CONTEXT1 *);
void STST(CONTEXT1 *);
void LDST(CONTEXT1 *);

void Command(void * vpCmd);

//int ASKY();      // 반환값 받기
unsigned char   MD(void *);  // Momory Display Function By Assembly
void     MM(void *, char);  // Momory Modify Function By Assembly

CONTEXT1  stOldreg;

int main()
{
  int A = 0x12345678;
  static unsigned char ucBuff[31];
  static unsigned char ucCnt = 0;
  int iRet;

  sucMem_end  = sucMem + sizeof(sucMem);
  sucCODE    = (unsigned char *)(((unsigned int)sucMem+MAX_PROGRAM_SIZE) & 0xFFFF0000);
  sucDATA    = sucCODE + 0x2000;
  sucSTACK  = (unsigned char *)sucCODE + MAX_PROGRAM_SIZE-1;  

  printf("Memory Start Add : %08x\n", sucMem);
  printf("Memory End Add   : %08x\n", sucMem_end);
  printf("Memory Code Add  : %08x\n", sucCODE);
  printf("Memory DATA Add  : %08x\n", sucDATA);
  printf("Memory Stack Add : %08x\n", sucSTACK);
  
  //HexaView((unsigned char *)&A , 159);
  
  printf("-------------------- 초기화 상태 --------------------\n");
  PrintReg(&stOldreg);
  STST(&stOldreg);
  printf("-------------------- 저장 상태 ----------------------\n");
  PrintReg(&stOldreg);
  
  while(1)
  {
    printf("\n>");
    iRet = read(0,ucBuff,sizeof(ucBuff));
    for(ucCnt=0 ; ucCnt < iRet-1 ; ++ucCnt) 
    {
      ucBuff[ucCnt] = toupper((int)ucBuff[ucCnt]);
    }
    ucBuff[ucCnt]= '\0';

    Command(ucBuff);
  }

  getchar();

  LDST(&stOldreg);  // STST로 가게해줌. while 문 역할
        // 메모리안에 있는 정보를 CPU 로 옮겨준다.

  return 0;
}

void Clear_mem()
{
  unsigned int uiCnt;

  for(uiCnt=0 ; uiCnt < (int)sucMem_end - (int)sucCODE ; ++uiCnt)
  {
    *(sucCODE+uiCnt) = 0;    
  }
  return;  
}

void PrintLOAD()
{
  
  IMAGE_DOS_HEADER  *stpDOS;// windows.h -> 구조체 IMAGE_DOS_HEADER
  IMAGE_NT_HEADERS  *stpNT;  // NT Header
  IMAGE_FILE_HEADER  *stpFH;  // File Header
  IMAGE_OPTIONAL_HEADER  *stpOH; // Optional Header
  unsigned char    File_Name[255];  // 파일이름 임시저장
  int      Total_Read=0;
  int      Read_Num=0;
  int      Header_Size;
  int      iRet;
  unsigned int    uiCnt;

  Clear_mem();

  printf("\n읽어들일 파일이름을 입력하세요 : ");
  
  iRet = read(0,File_Name,sizeof(File_Name));
  
  for(uiCnt=0 ; uiCnt < iRet-1 ; ++uiCnt) 
  {
    File_Name[uiCnt] = toupper((int)File_Name[uiCnt]);
  }
  
  File_Name[uiCnt]= '\0';

  
  iFd = open( File_Name , O_RDONLY | O_BINARY);

  if0 > iFd )
  {
    printf("File Open Error\n");
    return;
  }

  iRet = read(iFd , sucCODE , SECTION_SIZE);

  if0 > iFd )
  {  
    printf("File was Readed\n");
    close(iFd);
    return;
  }
  else
  {
    stpDOS = (IMAGE_DOS_HEADER *)sucCODE;
    stpNT  = (IMAGE_NT_HEADERS *)(sucCODE + (stpDOS->e_lfanew));
    stpFH  = (IMAGE_FILE_HEADER *)((unsigned char *)stpNT + sizeof(stpNT->Signature));
    stpOH  = (IMAGE_OPTIONAL_HEADER *)((unsigned char *)stpFH + sizeof(IMAGE_FILE_HEADER));
    Header_Size = stpOH->SizeOfHeaders;
    Clear_mem();
  }

  if0 > lseek(iFd, Header_Size, SEEK_SET) )
  {
    printf("파일의 헤더정보 Skip 실패!!\n");
    printf("파일을 적재할 수 없습니다..\n");
    close(iFd);
  }
  else
  {
    Read_Num = read(iFd, sucCODE, SECTION_SIZE);  // Code 영역에 SECTION_SIZE 만큼 읽어들임
  }

  if0 > Read_Num )
  {
    printf("파일이 존재하지만 읽을 수 없습니다.\n");
    close(iFd);
    return;
  }
  else
  {
    Total_Read = Total_Read + Read_Num;
        Read_Num = read(iFd, sucDATA, SECTION_SIZE);  // DATA 영역에 SECTION_SIZE 만큼    
  }              // 읽어 들임

  close(iFd);

  if(0 > Read_Num)
  {
    printf("파일이 존재하지만 읽을 수 없습니다.\n");
    return;
  }
  else
  {
    Total_Read = Total_Read + Read_Num;
       iFd   = 0;
        Load_Flag = 1;
        printf("파일을 성공적으로 메모리에 적재하였습니다.\n");
        printf("읽어 들인 파일의 크기는 [%d]Bytes입니다.\n\n", Total_Read);
  }

  return;
}

void GO(void)
{
  CONTEXT1 stNewreg = {0,};  

  stNewreg.eax = (int)&stOldreg;
  stNewreg.eip = (int)sucCODE;
  stNewreg.esp = (int)(sucSTACK+4);  // 메모리 끝의 한칸 아래 집어줌 Push 할때를 대비
  
  LDST(&stNewreg);
  
  
  printf("Kernel Panic\n");
}

void PrintCODE()
{
  printf("\nCODE Field\n\n");
  HexaView(sucCODE,160);
}

void PrintDATA()
{
  printf("\nDATA Field\n\n");
  HexaView(sucDATA,160);
}

void PrintSTACK()
{  
  printf("\nSTACK Field\n\n");
  HexaView(sucSTACK-159,160);
}

/*void PrintLOAD()
{
  int iRet;
  int fd;
  int *ip;
  unsigned char ucBuff[31];
  unsigned int uiCnt = 0;  
  unsigned char ucBuff_Mem[MAX_PROGRAM_SIZE];

  printf("\n읽어들일 파일이름을 입력하세요 : ");
  
  iRet = read(0,ucBuff,sizeof(ucBuff));
  
  for(uiCnt=0 ; uiCnt < iRet-1 ; ++uiCnt) 
  {
    ucBuff[uiCnt] = toupper((int)ucBuff[uiCnt]);
  }
  
  ucBuff[uiCnt]= '\0';

  fd = open( ucBuff , O_RDONLY | O_BINARY);

  iRet = read(fd , ucBuff_Mem , sizeof(ucBuff_Mem));

  for(uiCnt=0 ; uiCnt < iRet ; uiCnt++)
  {
    MM(sucCODE+uiCnt,ucBuff_Mem[uiCnt]);
  }

  close(fd);  
}*/


void PrintReg(CONTEXT1 *stpReg)
{
  printf("EAX VALUE : 0x%08x   ECX VALUE : 0x%08x\n", stpReg->eax, stpReg->ecx);
  printf("EDX VALUE : 0x%08x   EBX VALUE : 0x%08x\n", stpReg->edx, stpReg->ebx);
  printf("ESP VALUE : 0x%08x   EBP VALUE : 0x%08x\n", stpReg->esp, stpReg->ebp);
  printf("ESI VALUE : 0x%08x   EDI VALUE : 0x%08x\n", stpReg->esi, stpReg->edi);
  printf("EIP VALUE : 0x%08x   EFL VALUE : 0x%08x\n", stpReg->eip, stpReg->efl);
}

void EXIT()
{  
  exit(0);
}

void HELP()
{
  printf("CODE  : CODE Area Display\n");
  printf("DATA  : DATA Area Display\n");
  printf("STACK : STACK Area Display\n");
  printf("HELP  : Help massage Display\n");
  printf("EXIT  : EXIT Program\n");
  printf("MC    : Memory Clear\n");
  printf("LOAD  : Program Load\n");
}


void Command(void * vpCmd)
{
  CmdMap *stpCmd = stCmdList;

  while(1)
  {
    if0 == stpCmd->fp )  // 함수 포인터
    {
      break;
    }

    if0 == My_strcmp( vpCmd , stpCmd->vpCmd ) )
    {
      // 함수 포인터를 이용한 함수 호출
      (stpCmd->fp)();
      break;
    }
    ++stpCmd;
  }

  return;
}

int My_strcmp(void *vpSrc, void *vpDst)
{
  while(1)
  {
    if0 == *((unsigned char *)vpSrc) )
    {  
      break;
    }

    if0 == *((unsigned char *)vpDst) )
    {
      break;
    }

    if( *((unsigned char *)vpSrc) != *((unsigned char *)vpDst) )
    {
      break;
    }

    vpSrc = ((unsigned char *)vpSrc) + 1;
    vpDst = ((unsigned char *)vpDst) + 1;
  }

  return ( *((unsigned char *)vpSrc) - *((unsigned char *)vpDst) );  // 동일한 문자열일때(참일때) 반환값이 0 이 반환
                            // 동일하지 않으면(거짓일때) 0 이 아닌 값이 반환 
}

void HexaView(unsigned char *ucP, unsigned int isize)
{
  int iCnt;
  int iloop;
  unsigned int iSizeNum;

  iSizeNum = 0;
  
  printf("----------------------------------------"
  
  "----------------------------------\n");
  printf("Address  \t\t\tHexa\t\t\t      ASCII\n"); 
  printf("\t ");

  
  for(iCnt=0 ; iCnt <= 15 ; iCnt++)
  {
    printf("%02X ", iCnt);
  }

  putchar('\n');

  printf("----------------------------------------"
  
  "----------------------------------\n");
  
  if0 == isize%16 )
  {
    isize = isize / 16;  
  }
  else
  {
    iSizeNum = isize%16;
    isize = (isize/16);    
  }
  
  for(iloop=0; iloop < isize ; iloop++)
  {
    printf("%08X ", ucP); 
  
    for( iCnt=0 ; iCnt <= 15 ; iCnt++)
    {
      printf("%02X ", MD(ucP+iCnt));
    }
  
    for( iCnt=0 ; iCnt <= 15 ; iCnt++ )
    {
      if(0 == MD(ucP+iCnt))
      {
        printf(".");
      }
      else if32 > MD(ucP+iCnt))
      {
        printf(".");
      }
      else if127 < MD(ucP+iCnt))
      {
        printf(".");      
      }
      else
      {
        printf("%c", MD(ucP+iCnt)); 
      }
    }
  
    putchar('\n');
    ucP = ucP + 16;


  }

  if( iSizeNum != 0 )
  {
    printf("%08X ", ucP); 
  
    for( iCnt=0 ; iCnt <= iSizeNum-1 ; iCnt++)
    {
      printf("%02X ", MD(ucP+iCnt));
    }
    
    for( iCnt=0 ; iCnt <= 15-iSizeNum ; iCnt++ )
    {
      printf("   ");
    }    
    

    for( iCnt=0 ; iCnt <= iSizeNum-1 ; iCnt++ )
    {
      if(0 == MD(ucP+iCnt))
      {
        printf(".");
      }
      else if32 > MD(ucP+iCnt))
      {
        printf(".");
      }
      else if127 < MD(ucP+iCnt))
      {
        printf(".");      
      }
      else
      {
        printf("%c", MD(ucP+iCnt)); 
      }
    }
  
    putchar('\n');

  }  
}


실행파일 링크시 보안체크 설정해서 .obj 확장자 만들기

ex] cl /c /GS- t1.c



링크시에 오브젝트 파일중 Entry Point 의 오브젝트 파일이 제일 먼저 나와야 한다.

ex] link /subsystem:console /entry:INIT /nodefaultlib /out:t1.exe /base:0x00410000 init.obj Monitor.obj t1.obj


▶ base 는 CODE 영역 시작 주소를 넣어준다.

▶ init.obj 가 먼저 나오도록 해야 메모리 영역에 제대로 적재 된다.





▶ STST 함수를 호출 : CPU->메모리에 적재 , LDST 함수 호출 : 메모리->CPU에 적재 

.asm 파일안에서 LDST 는 호출전 eip 를 가져와서 STST 로 점프할 수 있도록 하여 무한 반복이 가능하게 하였고, 추후 소스에서는 

이 둘의 무한반복 관계를 끊어서 도중에 Old Regisger EAX, EIP ,ESP 를 저장을 하고 asm 안에서 함수 test() 를 호출하고 실행되고나서  LDST 를 다시호출하여 STST가 호출하면 실행후 도중에 무엇이 바뀌었는지 확인이 가능하다.


---- 소스 -----------------------

20130917_ASM-2013-09-30.zip

--------------------------------