2014. 7. 16. 17:47

VirtualSize와 SizeOfRawData 차이점?

PE Image에서 각각의 주요 정보는 Section으로 분리되어 있습니다. 이러한 Section 정보는 아래와 같은 IMAGE_SECTION_HEADER 라는 구조체 형식의 meta-data로 저장되어 있습니다.

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;


일반적으로 VirtualSize < SizeOfRawData인데, 만약 그 반대인 경우에는, 0으로 채워진 Section을 의미한다고 SND(링크)에 나타나 있습니다.


여하튼, 일상적인 VirtualSize < SizeOfRawData 상황에서, 둘다 Section의 크기를 의미하기도 합니다. 메모리와 File, 두개의 개념으로 인해 두개의 값으로 관리된 듯 합니다. 이러한 애매함이 있어서, OllyDbg(Windows XP)로 VirtualSize와 SizeOfRawData의 정확한 사용에 대해 알아본 것을 정리하겠습니다.


우선, sample 실행파일이 있는데(DetectFileLength255.exe), 이것의 Memory Map과 Section 정보는 다음과 같습니다.


...
003D0000   00001000                                       Priv   RW        RW
00400000   00001000   DetectFi              PE header     Imag   R         RWE
00401000   00002000   DetectFi   .text      code          Imag   R         RWE
00403000   00001000   DetectFi   .rdata     imports       Imag   R         RWE
00404000   00001000   DetectFi   .data      data          Imag   R         RWE
00405000   00002000   DetectFi   .rsrc      resources     Imag   R         RWE
00410000   00002000                                       Map    R E       R E
...


.text section의 Size는 0x2000으로 표기됩니다.


위 Memory map에서 PE header 부분(0x400000)을 더블 클릭하여 dump에 들어가면, header 정보를 볼 수 있습니다.


004001DC 00000000 DD 00000000 ; Reserved 004001E0 2E 74 65 78 >ASCII ".text" ; SECTION 004001E8 35160000 DD 00001635 ; VirtualSize = 1635 (5685.) 004001EC 00100000 DD 00001000 ; VirtualAddress = 1000 004001F0 00200000 DD 00002000 ; SizeOfRawData = 2000 (8192.) 004001F4 00100000 DD 00001000 ; PointerToRawData = 1000 004001F8 00000000 DD 00000000 ; PointerToRelocations = 0 004001FC 00000000 DD 00000000 ; PointerToLineNumbers = 0 00400200 0000 DW 0000 ; NumberOfRelocations = 0 00400202 0000 DW 0000 ; NumberOfLineNumbers = 0 00400204 20000060 DD 60000020 ; Characteristics = CODE|EXECUTE|READ 00400208 2E 72 64 61 >ASCII ".rdata" ; SECTION 00400210 060F0000 DD 00000F06 ; VirtualSize = F06 (3846.)

즉, VirtualSize < SizeOfRawData 상태입니다.


이제, 위 Memory map의 .text 부분을 더블클릭하여, Dump를 확인해 봅니다.


VirtualSize가 0x1635이니, 그 경계선(0x401000+0x1635) 부분을 보겠습니다.


즉, 위와 같이 0x402635 부터는 0으로 채워져 있습니다.

즉, VirtualSize가 0x1635로 세팅되어 있기 떄문에, 0x1635까지 로드된것 같습니다.

그러나, PointerToRawData가 0x1000이라서, 실제 파일은 어떠한지 확인해 보겠습니다.

즉, 해당 파일의 0x1000+0x1635 부분을 확인해 보겠습니다.


File 역시 0으로 채워져 있어, 0x1635까지 읽은 것인지 아닌지 더 애매해집니다.

그래서, 아래와 같이 0x2635 부분을 AB CD EF로 변경하고 다시 OllyDbg로 실행해 보겠습니다.


수정된 .exe를 가지고 실행하면, 아래와 같이 0x402635부터 AB CD EF 값이 들어가 있음이 확인됩니다.


즉, VirtualSize가 0x1235 이지만, 실제로는 그 이상 로드된것 같습니다. 즉, VirtualSize 보다는 SizeOfRawData 만큼 File에서 읽고, Section의 크기가 잡히는듯 합니다.