2011년7월6일_구조체의 관점에서 배열을 엑세스와 이 기법을 사용하여 실행파일(PE구조, ELF구조)의 매직코드만 추출해보자. HexaView 프로젝트...
★ 함수를 반환하는 함수와 함수를 인자로 받는 함수..그리고 그 함수의 주소를 받을 수 있는 함수포인터와 같이 복잡한 고급문법을 아는 것 보다 저급문법이라도 활용을 잘 하는 것이 중요하다. ★ 잘 하든 못 하든 표현을 잘하면 점점 더 잘하게 된다. 못 하는 부분이 있으면 회피하지 말고 하는 것이 중요하다. ★ 커뮤니케이션 능력이 떨어지면 사회에서 도태된다. |
파일을 만들 때 구조 그대로 읽어 들이려면 그 파일의 구조(format)을 알아야 한다. ● 배열을 가리키는 구조체로 일정 양식에 맞춰 엑세스하는 법 |
PE(Portable Executable) header |
● 구글 검색
● DOS header의 구조 (dos.h파일로 저장)
1: typedef unsigned short WORD;
2: typedef unsigned int LONG;
3:
4:
5: typedef struct _IMAGE_DOS_HEADER {
6: WORD e_magic; // DOS signature : 4D5A ("MZ")
7: WORD e_cblp;
8: WORD e_cp;
9: WORD e_crlc;
10: WORD e_cparhdr;
11: WORD e_minalloc;
12: WORD e_maxalloc;
13: WORD e_ss;
14: WORD e_sp;
15: WORD e_csum;
16: WORD e_ip;
17: WORD e_cs;
18: WORD e_lfarlc;
19: WORD e_ovno;
20: WORD e_res[4];
21: WORD e_oemid;
22: WORD e_oeminfo;
23: WORD e_res2[10];
24: LONG e_lfanew; // offset to NT header
25: } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
WORD와 LONG 자료형이 없으므로 typedef으로 각 부호없는 short와 int로 정의하자.
● main.c 파일
1: #include <stdio.h>
2: #include <string.h>
3: #include "dos.h"
4: //#include <fcntl.h> //oflag 저수준시 필요한 헤더파일
5: //#include <sys/types.h>
6: //#include <sys/stat.h>
7: #include "HexaView.h"
8:
9: #define BUFFERSIZE sizeof(IMAGE_DOS_HEADER) //16 * 16line
10:
11: int main(int argc, char *argv[])
12: {
13: FILE *fp;
14: int iBytes;
15: unsigned int iPage = 0; //256Bytes단위의 page
16: unsigned char ucBuffer[BUFFERSIZE];
17: PIMAGE_DOS_HEADER p;
18:
19: printf("%d\n", sizeof(IMAGE_DOS_HEADER));
20: printf("%d\n", sizeof(p));
21:
22: if(2 != argc)
23: {
24: fprintf(stderr, "파일이 없삼.\n");
25: return -100; //명령줄 문제
26: }
27:
28: //파일오픈
29: fp = fopen(argv[1], "rb");
30:
31: if(NULL == fp)
32: {
33: fprintf(stderr, "파일열기 실패!\n");
34: fclose(fp);
35: return -99; //파일열기 문제
36: }
37:
38: memset(ucBuffer, 0xFF, BUFFERSIZE);
39:
40: iBytes = fread(ucBuffer, 1, BUFFERSIZE, fp); //64Bytes읽어옴
41: p = (IMAGE_DOS_HEADER *)ucBuffer; //구조체포인터가 버퍼를 가리킴.
42: HexaView(ucBuffer, iBytes); //Hexa값 확인
43:
44: fclose(fp);
45:
46: printf("매직넘버 %04X\n", p->e_magic);
47: printf("e_cblp? %04X\n", p->e_cblp);
48:
49:
50: return 0;
51: }
<실행결과>
매직넘버는 0x5A4D로 Big endian 표시이다. 실제 메모리에는 little endian으로 저장된다.
나머지 변수도 모두 출력해 보는 것이 좋으나 각자 무엇을 의미하는지 몰라 ㅠㅠ
ELF(Executable and Linkable Format) header |
● /usr/include/elf.h 파일
1: /* The ELF file header. This appears at the start of every ELF file. */
2:
3: #define EI_NIDENT (16)
4:
5: typedef struct
6: {
7: unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
8: Elf32_Half e_type; /* Object file type */
9: Elf32_Half e_machine; /* Architecture */
10: Elf32_Word e_version; /* Object file version */
11: Elf32_Addr e_entry; /* Entry point virtual address */
12: Elf32_Off e_phoff; /* Program header table file offset */
13: Elf32_Off e_shoff; /* Section header table file offset */
14: Elf32_Word e_flags; /* Processor-specific flags */
15: Elf32_Half e_ehsize; /* ELF header size in bytes */
16: Elf32_Half e_phentsize; /* Program header table entry size */
17: Elf32_Half e_phnum; /* Program header table entry count */
18: Elf32_Half e_shentsize; /* Section header table entry size */
19: Elf32_Half e_shnum; /* Section header table entry count */
20: Elf32_Half e_shstrndx; /* Section header string table index */
21: } Elf32_Ehdr;
32비트와 64비트 두개가 있는데 32비트를 사용하자.
● main.c
1: #include <stdio.h>
2: #include <string.h>
3: #include <elf.h>
4: #include "HexaView.h"
5:
6: #define BUFFERSIZE sizeof(Elf32_Ehdr) //ELF파일 구조체의 크기
7:
8: int main(int argc, char *argv[])
9: {
10: FILE *fp;
11: int iBytes;
12: int iLoop;
13: unsigned int iPage = 0; //단위 page
14: unsigned char ucBuffer[BUFFERSIZE];
15: Elf32_Ehdr *p;
16:
17: printf("%d\n", sizeof(Elf32_Ehdr));
18: printf("%d\n", sizeof(p));
19:
20: if(2 != argc)
21: {
22: fprintf(stderr, "파일이 없삼.\n");
23: return -100; //명령줄 문제
24: }
25:
26: //파일오픈
27: fp = fopen(argv[1], "rb");
28:
29: if(NULL == fp)
30: {
31: fprintf(stderr, "파일열기 실패!\n");
32: fclose(fp);
33: return -99; //파일열기 문제
34: }
35:
36: memset(ucBuffer, 0xFF, BUFFERSIZE);
37:
38: //파일의 내용을 읽어와 버퍼에 저장
39: iBytes = fread(ucBuffer, 1, BUFFERSIZE, fp);
40: //구조체포인터p가 버퍼를 가리키도록함.
41: p = (Elf32_Ehdr *)ucBuffer;
42: //page출력
43: printf("page.%-100d\n", ++iPage);
44: //헥사값을 보기 좋게 출력
45: HexaView(ucBuffer, iBytes);
46: fclose(fp);
47:
48: //매직넘버출력 ELF
49: printf("매직넘버 : ");
50: for(iLoop = 0 ; EI_NIDENT > iLoop ; ++iLoop)
51: {
52: printf("%02X ", p->e_ident[iLoop]);
53: }
54:
55: putchar('\n');
56:
57: return 0;
58: }
<실행결과>
unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
매직넘버가 char형이니 big/little endian을 구분할 필요가 없다.
16개의 코드 중 “ELF”를 제외한 나머지 13개의 코드는 무엇을 의미하는지 모르겠당.
아래와 같이 ,
# readelf –h HexaView
실행파일의 header정보를 보기 좋게 표시하는 프로그램을 만들어야 한다.
● log.txt
ELF Header:
|
참조(Reference) |