함수포인터를 이용한 유용한 기법중 하나인 “메세지 기법”에 대하서 정리했다.
struct MFT_Entry_Attribute_Type
{
unsigned short usNum;
const char * cDes;
void (*fp)(void *);
} MFT_Attr_Type[] = {
{ 16, "$STANDARD_INFORMATION", Content_STD_INFO}
,{ 32, "$ATTRIBUTE_LIST",0}
,{ 48, "$FILE_NAME",Content_FILE_NAME}
,{ 64, "$VOLUME_VERSION or $OBJECT_ID",0}
,{ 80, "$SECURITY_DESCRIPTOR",0}
,{ 96, "$VOLUME_NAME",0}
,{112, "$VOLUME_INFORMATION",0}
,{128, "$DATA",0}
,{144, "$INDEX_ROOT",0}
,{160, "$INDEX_ALLOCATION",0}
,{176, "$BITMAP",0}
,{192, "$SYMBOLICK_LINK or REPARSE_POINT",0}
,{208, "$EA_INFORMATION",0}
,{224, "$EA",0}
,{256, "$LOGGED_UTILITY_STREAM",0}
,{257, "Unknown",0}
};
MFT_Entry_Attribute_Type 구조체는
- 직접적인 비교에 쓰일 변수 한 개와
- 메세지 출력을 위한 const char * 형의 변수 한 개,
- 필요에 따라 함수를 호출할 수 있도록 함수 포인터 선언
으로 이루어져 있으며 소스에서 보는 바와 같이 구조체 선언과 동시에 구조체 배열 변수를 선언해 두었다.
이것을 어떻게 사용하는지 아래 소스에서 살펴보면,
void * test(void *p) /* 213 페이지 */
{
struct MFT_Entry_Attribute_Type * stpAttType;
printf("========================= MFT Entry Attribute Analysis =========================\n");
printf("Attribute Type : ");
stpAttType = MFT_Attr_Type;
while(1)
{
if(257 == (stpAttType->usNum))
{
break;
}
else if ((*((U32*)((U8*)p+0))) == stpAttType->usNum) /* 이동은 U8만큼으로 하고 보는건 U32로 보겠다 */
{
break;
}
++stpAttType;
}
printf("%s\n", stpAttType->cDes);
printf("Lenth of Attribute : %dBytes\n", *((U32*)((U8*)p+4))); /* 이 길이를 알아내면 #2의 위치를 알 수 있다. */
printf("Non-Resident Attribute : %s\n", 1==(*((U8*)p+8)) ? "Yes":"No");
printf("Lenth of Name : %d\n", *((U8*)p+9));
printf("Offset to Name : %d\n", *((U16*)((U8*)p+10)));
printf("Attribute Flags : ");
if ( 0 != (0x0001 & (*((U16*)((U8*)p+12)))) )
{
printf("Compressed ");
}
if ( 0 != (0x4000 & (*((U16*)((U8*)p+12)))) )
{
printf("Encrypted ");
}
if ( 0 != (0x8000 & (*((U16*)((U8*)p+12)))) )
{
printf("Sparse ");
}
if ( 0 == (0xC001 & (*((U16*)((U8*)p+12)))) )
{
printf("Nothing");
}
putchar('\n');
printf("Attribute Identifier : 0x%04X\n", *((U16*)((U8*)p+14)));
if(0==(*((U8*)p+8))) // Resident Attribute
{
printf("=== Resident Attribute========================\n");
printf("====== Size of Content : %d\n", *((U32*)((U8*)p+16)));
printf("====== Offset to Content : %d\n", *((U16*)((U8*)p+20)));
printf("====== Index Flag : %s\n", 1==(*((U8*)p+22)) ? "Yes":"No");
printf("====== Padding : 0x%02X\n", *((U8*)p+23)); /* Reserve ㅇ */
printf("==============================================\n");
}
else // Non-Resident Attribute
{
}
if(0!=(stpAttType->fp)) /* 호출 함수가 있다면 호출 한다. */
{
(stpAttType->fp)( (U8*)p + (*((U8*)p+20)) ); /* 함수 포인터 */
}
return (U8*)p + (*((U32*)((U8*)p+4))) ;
}
- 3번 줄에서 위에서 선언한 MFT_Entry_Attribute_Type * stpAttType 포인터 변수 선언
- 7번에서 전역으로 선언된 MFT_Attr_Type을 stpAttType에 대입
- 8번줄에서 무한 루프를 돌면서 해당하는 값이 있는지 찾고 없으면 다음 값으로
- 20번줄에서 해당 메세지를 출력
- 58번줄에서 함수포인터 사용여부를 검사하여 호출 또는 넘어간다.
위와 같은 기법을 이용하면 메뉴 호출또는 메세지등을 손쉽게 할 수 있다.