星期二, 5月 31, 2005

[資訊雜記]如何判別是否為 DRM 的 ASF 檔案?

如何判別一個 ASF 檔案是否為 DRM 的 ASF 檔案?

詳情資料可以參考微軟提供的 Specification: Advanced Systems Format (ASF) Specification

大致上很簡單,一個 ASF 檔案主要有三個部分: Header Object, Data Object, Index Object.
而每個部分又各由不同的 Object 所組成.

要分辨是否為 DRM,主要是在 Header Object 裡面找尋是否有 Content Encryption Object.
那麼要怎麼找尋呢?? OK, 每個 Object 的最前面有唯一的 GUID,你可以依據 GUID 來找到.
而這些,你都可以在 Specification 的後面幾張找到 ( 或者你可以搜尋 ASF GUIDs ).

至此,寫起來並不太困難.程式碼如下:
typedef unsigned long UINT32;
typedef unsigned short UINT16;
typedef unsigned char UINT8;
typedef int BOOL;

enum BOOLEAN
{
FALSE = 0,
TRUE
};

typedef struct GUID_s
{
UINT32 id1;
UINT16 id2;
UINT16 id3;
UINT16 id4;
UINT8 id5[6];
}GUID;

//Content Encryption Object
GUID ASF_Content_Encryption_Object_guid =
{
0x2211b3fb,
0xbd23,
0x11d2,
0xb7b4,
{
0x00, 0xa0, 0xc9, 0x55, 0xfc, 0x6e
}
};

/*
typedef struct ContentEncryptionObject_s
{
GUID objectID;
UINT32 objectSize; // objectSize should be QWORD, 8 bytes, but CCS has not this type.
UINT32 objectSize1;
UINT32 secretDataLength;
BYTE* secretData; // according secretDataLength
UINT32 protectionTypeLength;
char* protectionType;
UINT32 keyIDLength;
char* keyID;
UINT32 licenseURLLength;
char* licenseURL;
}ContentEncryptionObject_t;
*/

//extern CF_FILE* filePtrR;
typedef FILE CF_FILE;
CF_FILE* filePtrR;

long
FILEr_ftell()
{
return ftell( filePtrR );
}

int
FILEr_fseek( long filepos, int whence)
{
return fseek( filePtrR, filepos, whence );
}

long
FILEr_fread( UINT8* ptr, long length )
{
return fread( ptr, 1, length, filePtrR );
}

char* SDRAM_HOLE = NULL;

BOOL
isASFDRM( )
{
long filePos;
char* spaceForParsing = (char*)( SDRAM_HOLE + 0x800000 ); // use the space after 8 MB, prevent conflict
int GUIDLen = sizeof( GUID );
int iter, len = 0;
BOOL bFound = FALSE, bResult = FALSE;
UINT32 headerObjectSize = 0;
UINT32 secretDataLength=0;
UINT32 protectionTypeLength=0;
char* protectionType=NULL;
long readLen=0;
char* encryptionPos = NULL;

// save file position
filePos = FILEr_ftell();

// seek to the start position
FILEr_fseek( 16, 0); //SEEK_SET
FILEr_fread( (UINT8*)&headerObjectSize, 4 ); // we should read 8 here, but ....

// read all header object
// then search the specified GUID, use pattern compare
FILEr_fseek( 0, 0 ); // SEEK_SET
readLen = FILEr_fread( spaceForParsing, headerObjectSize );
len = headerObjectSize - GUIDLen;

// searching.
for( iter = 0; iter < len; iter++ )
{
if( memcmp( (char*)&ASF_Content_Encryption_Object_guid, (spaceForParsing + iter ), GUIDLen ) == 0 )
{
bFound = TRUE;
break;
}
}
if( bFound == FALSE )
{
// this is not a DRM file.
bResult = FALSE;
goto OnFinally;
}

// if we got it, start to process it.
// ( encryptionPos ) ==> objectID
encryptionPos = spaceForParsing + iter;
// ( encryptionPos + GUIDLen ) ==> objectSize
// ( encryptionPos + GUIDLen + 8 ) ==> secretDataLength
secretDataLength = (UINT32) *( encryptionPos + GUIDLen + 8 );
// ( spaceForParsing + iter + GUIDLen + 8 + 4 ) ==> secretData
// ( spaceForParsing + iter + GUIDLen + 12 + secretDataLength ) ==> protectionTypeLength;
protectionTypeLength = (UINT32) *(encryptionPos + GUIDLen + 12 + secretDataLength );
protectionType = (char*) (encryptionPos + GUIDLen + 12 + secretDataLength + 4 );
if( strncmp( protectionType, "DRM", 3 ) == 0 )
bResult = TRUE;

OnFinally:
// restore file position
FILEr_fseek( filePos, 0); //SEEK_SET

// return result.
return bResult;
}

int main(int argc, char* argv[])
{
SDRAM_HOLE = (char*) malloc( 0x800000 * 2 );
filePtrR = fopen( "00 Cannot Play.wma", "rb" );

if( isASFDRM() )
printf("is a drm file.\n");
else
printf("not a drm file.\n");

fclose( filePtrR );
return 0;
}


ok, 程式裡面你會發現一些奇怪的地方,是的,因為我需要在 embedded 環境下運作,所以為了符合環境,所以做了一些調整,不過你還是可以在 Visual C++ 上來運行這段代碼.
看不順眼的,就自己調整吧...

這份 specification 其實斷斷續續看一陣子了,都沒怎麼專心看,不過昨天看的時候,突然開竅了,於是就把這麼一段代碼搞定了.
真神奇啊....

沒有留言: