20140826 (작성 중인 프로그램)

127일차








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

작성 중인 프로그램

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




------- 현재 작성 중인 프로그램은 windows loader 같은 프로그램이다.


새로운 프로그램을 불러 올 때마다 heap을 할당 받고,

할당 받은 stack에 ESP를 위치하게 한다.






data 영역은 0x2000 만큼 떨어져 있다고 한다.


그래서 우리가 받은 자료 t1.exe를 link 한 프로그램으로 돌리면 뻑이 났다.

link /subsystem:console /entry:init /nodefaultlib /out:t1.exe /base:0x520000 init.obj monitor.obj t1.obj


이래 고치면 뻑이 안난다.

->link /subsystem:console /entry:init /nodefaultlib /out:t1.exe /base:0x430000 init.obj monitor.obj t1.obj







추가한 함수






20140826.zip


설정

트랙백

댓글

20140825 (다른 프로그램 실행 분석 프로그램 작성)

126일차











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

현재 작성 중인 프로그램

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


------- 진행 상황




"현재" 처럼 프로그램을 구현하였는데

"수정" 으로 프로그램을 구현할 것이다.








------- 추가된 소스






--- 설명을 위해 임시로 추가한 소스 실행 전 상태이다.






--- LDST(&temp) 호출



EIP가 code 주소를 가리키게 되면서 main 에서 불러온 t1.exe 를 실행하게 된다.












--- t1.exe 에 inti.asm 코드







LDST(&status)가 호출되면서 STST()가 실행된 지점으로 돌아간다.











------- bzero


리눅스에서 사용가능 함수

#include <string.h>


void   bzero(void * s , size_t n);


바이트 스트링 s 의 처음 n 바이트를 0으로 채운다. memset(3)과 마찬가지로 메모리를 초기화하기 위한 목적으로 주로 사용된다. 그러나 이 함수는 구식이 되으므로 bzero 대신 memset(3) 을 사용하도록 한다.


반환값 없음.





















설정

트랙백

댓글

20140822 (다른 프로그램 실행 분석 프로그램 작성)

125일차









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

실행 파일 분석 프로그램 작성

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
















소스


#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <windows.h>

#define  MAX_PROGRAM_SIZE  0x10000

typedef struct _context
{
  unsigned int EFL;
  unsigned int EIP;
  unsigned int EDI;
  unsigned int ESI;
  unsigned int EBP;
  unsigned int ESP;
  unsigned int EBX;
  unsigned int EDX;
  unsigned int ECX;
  unsigned int EAX;
}Context;

static unsigned char * Mem;    // 동적 메모리 시작 주소
static unsigned char * Mem_End;  // 동적 메모리 끝 주소
static unsigned char * code;    // 프로그램 저장공간의 시작 위치 - Code
int File_DS;      // 저수준 파일의 데스크립터

extern void STST(Context *);  // Reg 상태 저장
extern void LDST(Context *);
extern void MM(void *, unsigned char);// Memory 수정
extern unsigned char MD(void *);  // Memory 보기

void load();
void HexaView(void *);
void Print_Register(Context *);
void Memory_Clear();

int main()
{
  Context status;
  unsigned int uiNum;

  Mem = malloc(MAX_PROGRAM_SIZE*2);

  if(0 == Mem)
  {
    printf("동적 할당을 받을 수 없습니다.\n");
    printf("프로그램을 종료합니다.\n");
    return 0;
  }
  else
  {
    code = (unsigned char *)(((unsigned int)Mem + MAX_PROGRAM_SIZE) & 0xFFFF0000);
    Mem_End = Mem + MAX_PROGRAM_SIZE*2 - 1;
    printf("Dynamic Memory area\t: 0x%08X to 0x%08X (128KBytes)\n", Mem, Mem_End);
  }

  printf("Code Start Address\t: 0x%08X\n", code);

  STST(&status);
  Print_Register(&status);

  load();
  HexaView(code);

  printf("1: 프로그램 재시작, 2 : 프로그램 종료\n");
  printf("선택하세요 : ");
  scanf("%d"&uiNum);

  if(uiNum == 1)
  {
    LDST(&status);
  }

  free(Mem);

  return 0;
}

void load()
{
  int Read_Num;
  int Header_Size;
  unsigned int uiSection_Size;
  IMAGE_DOS_HEADER * stpDH;
  IMAGE_NT_HEADERS * stpPH;
  IMAGE_FILE_HEADER * stpFH;
  IMAGE_OPTIONAL_HEADER32 * stpOH;  

  File_DS = open("t1.exe", O_RDONLY);

  if(File_DS < 0)
  {
    printf("파일 열기 실패.\n");
    return;
  }


  Read_Num = read(File_DS, Mem, MAX_PROGRAM_SIZE*2);

  if(0 >= Read_Num)
  {
    printf("파일 읽기 실패(1).\n");
    close(File_DS);
    return;
  }

  stpDH = (IMAGE_DOS_HEADER *)Mem;
  stpPH = (IMAGE_NT_HEADERS *)(Mem + stpDH->e_lfanew-1);
  stpFH = (IMAGE_FILE_HEADER *)( ((char *)(stpPH)) + 4 );
  stpOH = (IMAGE_OPTIONAL_HEADER32 *)( ((char *)(stpFH)) + sizeof(IMAGE_FILE_HEADER));

  Header_Size = stpOH->SizeOfHeaders;  // Header size
  uiSection_Size = stpOH->FileAlignment;    // Section size

  Memory_Clear();    // Memory clear

  lseek(File_DS, Header_Size, SEEK_SET);  // 파일 포인터 위치 이동
  Read_Num = read(File_DS, code, uiSection_Size);

  if(0 >= Read_Num)
  {
    printf("파일 읽기 실패(2).\n");
    close(File_DS);
    return;
  }

  close(File_DS);
}

void HexaView(void * vpData)
{  
  int iCnt;
  int iCnt2;
  
  printf("===============================================================================\n");
  printf("= ADDRESS                         HEXA                             ASCII      =\n");
  printf("=-----------------------------------------------------------------------------=\n");
  
  for(iCnt2=020>iCnt2; ++iCnt2)
  {

//---  Address Part Start

    printf("= %08X  ", vpData );

//---  Address Part End

  

//--- Hexa View Part Start

    for(iCnt=016>iCnt; ++iCnt)
    {
      if(7 == iCnt)
      {
        printf("%02X  ", (*((unsigned char *)vpData)) );
      }
      else
      {
        printf("%02X ", (*((unsigned char *)vpData)) );
      }
      ++((unsigned char *)vpData);
    }

//--- Hexa View Part End




//---   ASCII Part Start

    ((unsigned char *)vpData) = ((unsigned char *)vpData) - iCnt;
    for(iCnt=016>iCnt; ++iCnt)
    {
      if(0x20 <= (*((unsigned char *)vpData)) && 0x80 > (*((unsigned char *)vpData)))
      {
        printf("%c", (*((unsigned char *)vpData)));
      }
      else
      {
        printf(".");
      }
      ++((unsigned char *)vpData);
    }
    printf(=\n");

//---   ASCII Part End



  }  
  printf("===============================================================================\n");

  return ;
}

void Print_Register(Context * status)
{
  printf("EAX : %08X \n", status->EAX);
  printf("ECX : %08X \n", status->ECX);
  printf("EDX : %08X \n", status->EDX);
  printf("EBX : %08X \n", status->EBX);
  printf("ESP : %08X \n", status->ESP);
  printf("EBP : %08X \n", status->EBP);
  printf("ESI : %08X \n", status->ESI);
  printf("EDI : %08X \n", status->EDI);
  printf("EIP : %08X \n", status->EIP);
  printf("EFL : %08X \n\n", status->EFL);
}

void Memory_Clear()
{
  unsigned char * ucData;

  ucData = Mem;

  while(1)
  {
    MM(ucData, 0x00);
    ++ucData;

    if(ucData > Mem_End)
    {
      break;
    }
  }
}







외부 함수 Asm 코드


.386
.MODEL FLAT
.STACK 4096

PUBLIC  _LDST
PUBLIC  _STST
PUBLIC  _MM
PUBLIC  _MD

.CODE
_LDST   PROC   NEAR32   ; LoaD STatus Procedure Start
  push  ebp    ; Entry Code
  mov  ebp, esp    ; Entry Code

  add  esp, 12    ; load EFL
  popfd

  pop  eax    ; load EIP
  mov  [esp-16], eax

  popad      ; load Reg
  
  mov  esp, ebp    ; Exit Code
  pop  ebp    ; Exit Code
  ret      ; Exit Code
_LDST   EndP     ; LoaD STatus Procedure End


_STST  PROC  NEAR32
  push  ebp    ; Entry Code
  mov  ebp, esp    ; Entry Code


  pushfd      ; save temp EFL

  add  esp, 56

  pushad      ; save Reg

  mov  eax, [ebp+4]  ; save EIP
  push  eax

  mov  eax, [ebp-4]  ; save EFL
  push  eax


  mov  esp, ebp    ; Exit Code
  pop  ebp    ; Exit Code
  ret      ; Exit Code
_STST  ENDP


_MM   PROC   NEAR32    ; Memory Modify
  push  ebp    ; Entry Code
  mov  ebp, esp    ; Entry Code

  mov  al, [ebp+12]
  mov  esp, [ebp+8]
  mov  [esp], al
  
  mov  esp, ebp    ; Exit Code
  pop  ebp    ; Exit Code
  ret      ; Exit Code
_MM   EndP      ; Memory Modify


_MD   PROC   NEAR32    ; Memory Display
  push  ebp    ; Entry Code
  mov  ebp, esp    ; Entry Code

  mov  esp, [ebp+8]
  mov  al, [esp]
  
  mov  esp, ebp    ; Exit Code
  pop  ebp    ; Exit Code
  ret      ; Exit Code
_MD   EndP      ; Memory Display

END

설정

트랙백

댓글

20140820 (PE 구조)

123일차









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

PE 구조

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







--- Dos Header

Dos와 호환용으로 있는 부분으로

항상 64 byte 크기이며 안에 여러 구조체 멤버가 있는데, 

e_magic, e_lfanew 이 두 멤버가 가장 중요하고 나머지는 0으로 채워도 돌아간다.

magic은 항상 아스키값으로 MZ를 나타내야 하고, 

e_lfanew 는 PE 헤더의 시작 점을 나타내고 있다.


--- Dos stub

가변적인 크기로 dos 모드에서 실행되는 것을 방지하기 위한 곳이라고 한다.

가끔 바이러스 코드를 이 곳에 넣기도 한다고 한다.



--- 각 구조체


typedef struct _IMAGE_NT_HEADERS {
  DWORD                 Signature;
  IMAGE_FILE_HEADER     FileHeader;
  IMAGE_OPTIONAL_HEADER OptionalHeader;
} IMAGE_NT_HEADERS, *PIMAGE_NT_HEADERS;

Signature 의 값은 항상 50 45 00 00 값으로 PE구조라고 부른다.




typedef struct _IMAGE_FILE_HEADER {
  WORD  Machine;
  WORD  NumberOfSections;
  DWORD TimeDateStamp;
  DWORD PointerToSymbolTable;
  DWORD NumberOfSymbols;
  WORD  SizeOfOptionalHeader;
  WORD  Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

Machine 은 이 파일이 실행 가능한 cpu의 타입 정보를 갖고 있다.




typedef struct _IMAGE_OPTIONAL_HEADER {
  WORD                 Magic;
  BYTE                 MajorLinkerVersion;
  BYTE                 MinorLinkerVersion;
  DWORD                SizeOfCode;
  DWORD                SizeOfInitializedData;
  DWORD                SizeOfUninitializedData;
  DWORD                AddressOfEntryPoint;
  DWORD                BaseOfCode;
  DWORD                BaseOfData;
  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_HEADER, *PIMAGE_OPTIONAL_HEADER;




typedef struct _IMAGE_DATA_DIRECTORY {
  DWORD VirtualAddress;
  DWORD Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

http://msdn.microsoft.com/en-us/library/windows/desktop/ms680305(v=vs.85).aspx




typedef struct _IMAGE_SECTION_HEADER {
  BYTE  Name[IMAGE_SIZEOF_SHORT_NAME];
  union {
    DWORD PhysicalAddress;
    DWORD VirtualSize;
  } Misc;
  DWORD VirtualAddress;
  DWORD SizeOfRawData;
  DWORD PointerToRawData;
  DWORD PointerToRelocations;
  DWORD PointerToLinenumbers;
  WORD  NumberOfRelocations;
  WORD  NumberOfLinenumbers;
  DWORD Characteristics;
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

http://msdn.microsoft.com/en-us/library/windows/desktop/ms680341(v=vs.85).aspx









--- PEViewer 프로그램


PEview.exe






--- 실습


PE.zip






설정

트랙백

댓글

20140818 (Assembly CDECL, STDCALL, PE구조)

121일차








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

Assembly

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





------- CDECL & STDCALL 방식


CDECL , STDCALL 방식은 함수 호출 후 인수를 정리하는 방식으로

호출한 곳에서 인수를 정리하면 CDECL 방식, 

호출당한 곳에서 인수를 정리하면 STDCALL 방식이다.




--- CDECL 방식 예제코드





aaa() 함수를 호출한 main() 함수에서 add   esp ,  8 로 인수를 정리하고 있다.






--- STDCALL 방식 예제코드





호출당한 aaa() 함수에서 마지막에 ret   8 로 인수를 정리하고 있다.







위의 소스에서 확인할 수 있듯이 __stdcall을 붙이면 STDCALL 방식으로 되고

생략 시 CDECL 방식으로 작성된다.



STDCALL 방식이 1byte 더 아낄 수 있다고 하는데...




얼마 전에 배운 ARM 같은 경우, 인수 4개까지 Reg에 저장한다고 한다.

적절히 사용할 경우 더 효율적으로 사용할 수 있다.










------- STST 함수와 LDST 함수



STST() 함수는 Register들을 저장하는 것이고,

LDST() 함수는 STST() 함수를 저장할 당시 Register 들의 상태로 되돌리고

STST() 이후로 돌아가는 함수이다.


















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

PE 구조

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


PE(Portable Executable)파일은 말 그대로 옮겨다니면서 실행시킬수 있는 파일을 말합니다.

Microsoft가 다른 운영체제와 이식성을 좋게 하기 위해서 만든 파일 포멧입니다.
그러면 Microsoft가 이런 PE파일을 만들기 위해 제작한 PE 파일 구조에 대해서 공부를 해보겠습니다.

1. PE 파일
공식적으로 PE파일의 종류는
 실행 계열 : EXE, SCR 드라이버 계열 : SYS, VXD
 라이브러리 계열 : DLL, OCX, CPL, DRV 오브젝트 파일 계열 : OBJ
이렇게 OBJ를 제외한 나머지는 모두 실행 가능한 파일로 이루어져 있습니다.

2. 배우는 이유
PE파일 구조를 배우면 파일이 실행되기 위한 모든 정보를 얻을 수 있습니다.
예를 들어 어느 메모리의 주소에 로딩이 되는지, 프로그램이 사용하는 API의 정보 등 등을 얻을 수 있습니다.

3. PE 파일 구조



이런식으로 파일과 메모리에 영역이 구분되어서 PE파일들이 메모리에 맵핑이됩니다.
앞으로 이 PE구조 안에 있는 작은 DOS header, DOS stub 등 등을 공부해보겠습니다.

4. PE 헤더
PE헤더란 PE파일 구조중에서 DOS header부터 Section header까지를 말합니다.
그러면 PE헤더에 있는 각각의 부분에 대해서 가르쳐 드리겠습니다.
1) DOS header
typedef struct _IMAGE_DOS_HEADER {     
    WORD   e_magic;          // DOS signature : 4D5A ("MZ")
    WORD   e_cblp;                     
    WORD   e_cp;                       
    WORD   e_crlc;                     
    WORD   e_cparhdr;                  
    WORD   e_minalloc;                 
    WORD   e_maxalloc;                 
    WORD   e_ss;                       
    WORD   e_sp;                       
    WORD   e_csum;                     
    WORD   e_ip;                       
    WORD   e_cs;                       
    WORD   e_lfarlc;                   
    WORD   e_ovno;                     
    WORD   e_res[4];                   
    WORD   e_oemid;                    
    WORD   e_oeminfo;                  
    WORD   e_res2[10];                  
    LONG   e_lfanew;         // offset to NT header 
  } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

여기서 중요한 값은 e_magic, e_lfanew 이렇게 2개가 있습니다.

여기서 e_magic의 값은 DOS signature로 MZ라는 문자열입니다.

(MZ는 Mark Zbikowski라고 DOS실행파일을 설계한 사람의 이니셜입니다.)

또한 e_lfanew의 값은 NT header의 RVA형태의 주소값을 가지고있습니다.

(이 값은 꼭 40이상의 크기를 가질 필요는 없습니다.)





_IMAGE_DOS_HEADER 확인 예제 코드)


#include <windows.h>
#include <stdio.h>
#include <fcntl.h>

#define READ_EXE_FILE_SIZE  256

int main()
{
  IMAGE_DOS_HEADER * stpExe;
  unsigned char ucBuff[READ_EXE_FILE_SIZE];
  int iFile;

  iFile = open("print_test.bin", O_RDONLY);

  if(0 > iFile)
  {
    fprintf(stderr, "File open error!\n");
    return 0;
  }

  read(iFile, &ucBuff, READ_EXE_FILE_SIZE);

  stpExe = (IMAGE_DOS_HEADER *)ucBuff;

  printf("e_magic\t\t\t\t: [ %c%c ]\n", ucBuff[0], ucBuff[1]);
  printf("bytes on last page of file\t: [ %d ]\n", stpExe->e_cblp);
  printf("Pages in file\t\t\t: [ %d ]\n", stpExe->e_cp);
  printf("Relocations\t\t\t: [ %d ]\n", stpExe->e_crlc);
  printf("Size of header in paragraphs\t: [ %d ]\n", stpExe->e_cparhdr);
  printf("Minimum extra paragraphs needed\t: [ %d ]\n", stpExe->e_minalloc);
  printf("Maximum extra paragraphs needed\t: [ %d ]\n", stpExe->e_maxalloc);
  printf("Initial (relative) SS value\t: [ %d ]\n", stpExe->e_ss);
  printf("Initial SP value\t\t: [ %d ]\n", stpExe->e_sp);
  printf("Checksum\t\t\t: [ %d ]\n", stpExe->e_csum);
  printf("Initial IP value\t\t: [ %d ]\n", stpExe->e_ip);
  printf("Initial (relative) CS value\t: [ %d ]\n", stpExe->e_cs);
  printf("File address of relocation table : [ %d ]\n", stpExe->e_lfarlc);
  printf("Overlay number\t\t\t: [ %d ]\n", stpExe->e_ovno);
  printf("Reserved words\t\t\t: [ %d ]\n", stpExe->e_res[4]);
  printf("OEM identifier (for e_oeminfo)\t: [ %d ]\n", stpExe->e_oemid);
  printf("OEM information; e_oemid specific : [ %d ]\n", stpExe->e_oeminfo);
  printf("Reserved words\t\t\t: [ %d ]\n", stpExe->e_res2[10]);
  printf("File address of new exe header\t: [ %d ]\n", stpExe->e_lfanew);

  return 0;
}



실행 결과












설정

트랙백

댓글

20140805 (Assembly 함수 return 값, 인수)

117일차







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

Assembly

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




------- Procedure


--- return 비교







--- 지역 변수 선언



중복이 되므로 중복을 최대한 피해야 최적화 할 수 있다.


ESP가 88 byte만큼 움직인다. 즉,  88 byte 만큼 확보.


그런데 이상한게 int a, a0 ~ a9 까지 11개 44 byte.

int b[10] 은 40 byte  합 84 byte가 나와야 하는데 88 byte 이다.



확인한 결과 [2] -> [3]으로 바뀔 때 4 byte를 더 할당 받는다.

이유는 모르겠다.





--- 함수 호출시 인수 값을 바꾸는 asm 코드 예제 1)


iNum이란 초기화 되지 않은 변수를

smart 함수에 인수로 넣으면

초기화 시켜주는 소스.


- C 소스



- C 소스에서 호출할 asm 함수.




mov    eax ,  [ebp+8]  이 코드는

eax 가 &iNum을 가리키기 하기 위해 ebp+8을 하였다.

아래 그림을 참고.









--- 함수 호출시 인수 값을 바꾸는 asm 코드 예제 2)


현재 EAX, EBX, ECX, EDX를 출력하는 소스


- C 소스






- C 소스에서 호출할 asm 함수.



mov    eax ,  [ebp-4]

이 코드는

mov    mem ,  mem  이런 mov operand가 없기 때문에

mov    mem ,  reg 로 넣기 위해서 이다.







--- ???



설정

트랙백

댓글

20140804 (Assembly procedure(함수 구현), call, ret, 지역변수, Entry Code, Exit Code)

116일차









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

Assembly

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




------- Procedure and Function


보통 void 형 함수를 Procedure(프로시저)라 부르고

return 값이 있는 함수는 Function이라 부르는데

굳이 구별하는 언어도 있고 하지 않는 언어도 있다.



--- 아래 예제 소스를 통해 함수 구현.











------- call Instruction


함수 호출, EIP를 Intel 에서는 건들 수 없지만

간접적으로 조작하는 명령어가 몇 가지 있는데

call 이 그 중 하나이다.


call 의 실행 순서

1. push   eip

2. mov   eip ,  함수 주소




near 은 32 bit 주소 체계

far 은 64? bit 주소 체계


relative 는 현재로 부터 얼마나 떨어졌는지,

indirect 는 포인터 같은 개념이고,

direct 는 그 주소를 바로 가리킨다.




--- 위의 소스를 예제로 어떻게 돌아가는지 자세히 보기로 한다.




1. EIP를 보면 다음 실행 주소가 _start의 시작 주소이다.


2. 시작 주소(0x0040103E)를 보면 E8 CD FF FF FF (call Initialize)를 실행한다.


3. E8은 call 명령어에 operand 값이 near relative를 가리키는데

현재부터 얼마나 떨어져 있는지를 가리킨다.


4. Little Endian 이니 FF FF FF CD -> -51 만큼 떨어져 있다는 소리인데

어디서부터 떨어졌는지 기준점은 다음 실행 주소이니

다음 실행 주소 0x00401043으로 부터 -51(-0x33) 만큼 빼면 0x00401010이다.


5. 그래서 Initialize 가 실행된다.








------- ret Instruction





ret 는 다음을 수행한다.

- pop eip


ret   0   (C에서는 반환 값을 return 뒤에 넣는데,

Assembly에서는 무슨 sp?뭐시기 al 뭐시기 뭔 값이 들어간다고

C에서 하는 반환 값과는 좀 다르다고 하는데 아직은 잘 모르겠다.)







다음 실행 주소가 저장된다.










------- 지역변수



위의 그림과 같이 인수가 뒤에서 부터 스택에 들어간다.

인수가 많으면 많을수록 스택도 많이 차지하고 느려진다.

따라서 최적화를 위해선 구조체를 선언하여 그 주소 값을 넘기는 형식으로 하면 좋다.







------- Entry Code , Exit Code





- Entry Code

   함수 호출시 stack 확보 등 준비 코드


- Exit Code

   함수 해제시 stack 해제 등 마무리 코드








--- 예제를 통해 C에서 ASM 함수를 호출



- main.c




- main.c의 중간 .asm 파일




- smart()함수가 정의 된 smart1.asm




- 메모리 구조




return 값은 eax에 저장되어 있다.


main.asm에 call 명령어 다음에 add esp, 12 가 뭘 의미하는지 몰랐는데

smart() 함수를 호출 후 원래 esp 위치로 돌려주는 역할이다.






설정

트랙백

댓글

20140801 (Assembly push, pop, pushad, popad, pushfd, popfd)

115일차











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

Assembly

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





------- Stack 영역


ESP Reg가 Stack영역의 주소를 갖고 있다.

Stack 영역은 높은 주소에서 낮은 주소로 움직인다.




------- push Instruction


stack 영역에 값을 넣는 명령어


push   [저장할 값]




- push 100

이 명령어가 실행되는 과정.

1.   ESP = ESP - 4;

2.   *ESP = 100;




예제)



Stack은 메모리 영역이기에 little endian이라서

값이 거꾸로 들어간다.

차례대로 들어갔다.

(0x0012FFC0 인지 주소를 어떻게 알았냐면은

ESP에 값을 확인하면 된다.)







1 byte로는 들어가지 않고 4 byte로 들어간다.

부호에 맞게 남는 값이 채워져 들어갔다.

2 byte는 2 byte씩 들어간다.







2 byte가 들어가고 4 byte가 이어서 계속 들어가고

2 byte가 들어갔다.

C 컴파일어 같은 경우는

4 byte씩 끊어 넣기 때문에

줄줄 이어지지 않는 반면

어셈블리는 그대로 이어서 준다.








------- pop Instruction


Stack 영역에 값을 빼오는 명령


pop   [저장할 곳]




- pop eax

이 명령어가 실행되는 과정.

1.   eax = *ESP;

2.   ESP = ESP + 4;









------- pushad, popad


--- pushad

Reg 값 저장

EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI

순으로 저장.


--- popad

Reg 값 불러오기

EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI 중에

ESP만 제외하고 다 불러온다.





pusha

=> push 16bit reg


pushad

=> push 32bit reg


popa

=> pop 16bit reg


popad

=> pop 32bit reg






--- pushad 예제)






--- popad 예제)










------- pushfd , popfd


flags 값을 저장한다.


- pushfd 예제)




a96인데 b96으로 저장된다.

TF flag가 켜지고 저장이된다.






- popfd 예제)






설정

트랙백

댓글

20140731 (Assembly loop, 배열, lea, pipe line)

114일차








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

Assembly

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





------- Conditional Jump Instruction 종류









--- 숫자 맞추기 게임을 통한 Assembly 예제 소스






example10.asm


example10.exe







------- loop Instruction


반복문

점프문과 비슷하나 일정 반복에 더 강점을 갖고 있다.

점프 범위는 -128 ~ 127 byte 이다.



이런식으로 사용한다.


ECX Reg와 관련이 있다.


(EAX, EDX는 계산 관련, EBX는 주소 관련 Reg이다.)


ECX의 값이 0이 될 때까지 계속 돈다.








--- 배열


지금까지 소스에서 문자열 배열을 가끔 봐 왔고

숫자 배열도 문자열 배열과 마찬가지로 선언한다.


Array DWORD 10 DUP (?)


C =>  int    Array[10];


이렇게 사용한다.






--- lea Instruction


주소 값을 대입한다.

lea   ebx ,  number1

C => ebx = &number1;






배열과 점프, lea 예제)
















------- Pipe line


CPU가 명령을 실행하는 과정이 3가지가 있다.


- Fetch an instruction from memory 명령을 가져옴

- Decode the instruction 명령을 해석

- Execute the instruction 명령 실행


이것이 이어지는 것을 pipe line 이라고 한다.


그런데 여기서 문제가 jump문이 나올 때 이 pipe line이 깨지기 때문에

반복문, 제어문을 많이 사용하면 CPU의 효율이 떨어진다.

그렇다고 반복문, 제어문을 사용하지 않을 수 없으니

반복문과 제어문을 사용할 때 이런 것을 생각하고 작성해야 한다.



설정

트랙백

댓글

20140730 (rounding factor, adc, sbb, clc, stc, cmc, jmp, cmp)

113일차








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

Assembly

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





------- rounding factor


라운딩 팩터




섭씨를 화씨로 변환하는 프로그램인데

변환 공식이 F = (9 / 5) * C + 32 이다.

그런데 소스 중에 빨간 줄이 쳐진 곳을 보면 2를 더한다.

왜 2 를 더할까?


rounding factor라고 하는데

9 / 5 = 1.8 이다.

정수간에 연산이기에 소수점 아래는 다 버리게 된다.

그래서 반올림 하여 2로 만들어 주어서 차이가 적게 만드려고 한다.

(9 + 2) / 5 = 2.2 로 2에 가깝게 만들어 주었다.


2 / 5 = 0.4 로 소수점 어떤 값에 0.4를 더해주게 되면

반올림된 값으로 쳐줄 수 있다. 그래서 정수 계산에서 2를 더해준다.









------- adc , sbb Instruction


adc (덧셈)

adc   A ,  B

==> A = A + B + carry


sbb (뺄셈)

sbb   A ,  B

==> A = A - B - carry












------- clc , stc , cmc Instruction


carry flag 셋팅.















------- jmp Instruction


무조건 점프



jmp   offset(상대값)









------- 조건에 따른 점프


jz   endwhile

zero flag 가 set 됐으면 endwhile로 점프


jnz   startwhile

zero flag 가 0 이면 (연산 결과가 0이 아니다) startwhile로 점프


js   endprg

sign flag 가 set 됐으면 (음수이면)  endprg로 점프


jns   smart

sign flag 가 0 이면 (양수이면)  smart로 점프














------- cmp Instruction


비교

cmp   operand1 ,  operand2



operand1 에서 operand2 를 뺀다.



뺀 값이 저장되는건 아니고 flags가 바뀐다.



그 flag가 바뀐 값으로 조건에 맞게 점프를 한다.


설정

트랙백

댓글