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;
}



실행 결과












설정

트랙백

댓글