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)파일은 말 그대로 옮겨다니면서 실행시킬수 있는 파일을 말합니다.
실행 계열 : EXE, SCR | 드라이버 계열 : SYS, VXD |
라이브러리 계열 : DLL, OCX, CPL, DRV | 오브젝트 파일 계열 : OBJ |
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;
}
실행 결과