#include "windows.h" #define PHDRF_CONTAINER_RELATIVE (0x00000001) typedef struct _PIC_OBJECT_HEADER { ULONG ulFlags; ULONG ulSize; ULONG ulType; } PIC_OBJECT_HEADER, *PPIC_OBJECT_HEADER; typedef struct _PIC_CONTAINER { PIC_OBJECT_HEADER Header; // Header blob ULONG ulTotalPicSize; // How many bytes long is this PIC region? ULONG ulIndexTableOffset; // Index table offset from PIC header } PIC_CONTAINER, *PPIC_CONTAINER; #define PSTF_ITEMS_SORTED_BY_STRING (0x00010000) #define PSTF_ITEMS_SORTED_BY_IDENT (0x00020000) #define PSTF_ITEM_IDENT_IS_HASH (0x00040000) typedef struct _PIC_STRING_TABLE { PIC_OBJECT_HEADER Header; ULONG ulStringCount; // Object header ULONG ulTableItemsOffset; // Offset to the table of string items ULONG ulContainerBlobOffset; // Offset to the blob of string data } PIC_STRING_TABLE, *PPIC_STRING_TABLE; typedef struct _PIC_STRING_TABLE_ENTRY { ULONG ulStringIdent; ULONG ulStringLength; ULONG ulOffsetIntoBlob; } PIC_STRING_TABLE_ENTRY, *PPIC_STRING_TABLE_ENTRY; #define PBLBF_DATA_FOLLOWS (0x00010000) // Data follows this object directly typedef struct _PIC_DATA_BLOB { PIC_OBJECT_HEADER Header; ULONG ulSize; ULONG ulOffsetToObject; } PIC_DATA_BLOB, *PPIC_DATA_BLOB; // // An object table acts as an index into a blob of PIC items. Think of it like a // top-level directory that you can index into with some pretty trivial functions. // You can store things by name, identifier, etc. Type information is also available // typedef struct _PIC_OBJECT_TABLE { PIC_OBJECT_HEADER Header; // Header blob ULONG ulEntryCount; // How many objects? ULONG ulTableOffset; // Offset in the container to the entry table ULONG ulStringTableOffset; // Offset to the stringtable that matches this in container } PIC_OBJECT_TABLE, *PPIC_OBJECT_TABLE; #define PIC_OBJTYPE_STRING ((ULONG)'rtsP') // Object is a string #define PIC_OBJTYPE_TABLE ((ULONG)'lbtP') // Object is a string table #define PIC_OBJTYPE_DIRECTORY ((ULONG)'ridP') // Object is a directory blob #define PIC_OBJTYPE_BLOB ((ULONG)'blbP') // Object is an anonymous blob of data #define POBJTIF_HAS_STRING (0x00010000) // The object table entry string offset is valid #define POBJTIF_KEY_VALID (0x00020000) // The object key value is valid #define POBJTIF_STRING_IS_INDEX (0x00040000) // The string value is an index into the table #define PBOJTIF_STRING_IS_IDENT (0x00080000) // The string value is an identifier typedef struct _PIC_OBJECT_TABLE_ENTRY { ULONG ulObjectKey; // integral key of this object ULONG ulObjectType; // Object type (PIC_OBJ_*) ULONG ulStringIdent; // Identifier in the matching stringtable for this objecttable, if ULONG ulObjectOffset; // Offset to the object from the table's indicated base addy } PIC_OBJECT_TABLE_ENTRY, *PPIC_OBJECT_TABLE_ENTRY; #define PSTRF_UNICODE (0x00010000) #define PSTRF_MBCS (0x00020000) typedef struct _PIC_STRING { PIC_OBJECT_HEADER Header; // Header blob ULONG ulLength; // Length, in bytes, of the string ULONG ulContentOffset; // Relative to either the containing object or the table base. // Zero indicates that the data is immediately following. } PIC_STRING, *PPIC_STRING; // // C++ analogues to the above structures for easier access // class CPicIndexTable; class CPicHeaderObject; class CPicReference; class CPicObject { protected: PVOID m_pvObjectBase; PPIC_OBJECT_HEADER m_pObjectHeader; CPicHeaderObject *m_pParentContainer; ULONG m_ulObjectOffset; PVOID GetObjectPointer() { return m_pvObjectBase; } public: CPicObject(CPicHeaderObject* pOwningObject, ULONG ulOffsetFromParentBase); CPicObject(CPicReference pr); ULONG GetType() const { return m_pObjectHeader->ulType; } ULONG GetSize() const { return m_pObjectHeader->ulSize; } ULONG GetFlags() const { return m_pObjectHeader->ulFlags; } CPicHeaderObject *GetContainer() const { return m_pParentContainer; } CPicReference GetSelfReference(); friend CPicReference; }; // // This is the object that represents the root of a PI object tree. // You may construct it based on just a PVOID, in which case it assumes // that there's at least sizeof(PIC_CONTAINER) there to gather details // from to load the rest of the tree into memory. Things are created on- // demand, to optimize for things like memory-mapped files. // // PI headers may contain an 'index table' like a card catalog to find // objects in the structure. // class CPicHeaderObject : public CPicObject { PPIC_CONTAINER m_pPicContainerBase; // m_pvBaseOfPic, just cast for easy access CPicIndexTable *m_pIndexTable; // Index table, if present public: CPicHeaderObject(PVOID pvBaseOfCollection); CPicHeaderObject(CPicReference objectReference); const CPicIndexTable* GetIndexTable(); friend CPicReference; }; // // Index table of objects in this PI blob, referrable by name or key. // class CPicIndexTable : public CPicObject { PPIC_OBJECT_TABLE m_pObject; // Pointer to the actual object table PPIC_OBJECT_TABLE_ENTRY m_pObjectList; // Pointer to the list of object table entries public: CPicIndexTable(CPicReference object); // Construct this index table based on the object bool FindObject(ULONG ulObjectIdent, CPicReference *reference) const; bool FindObject(PCWSTR pcwszString, CPicReference *reference) const; bool FindObjects(ULONG ulObjectType, ULONG *pulObjectKeys, SIZE_T *cObjectKeys) const; ULONG GetObjectCount() const; }; // // This reference object can be carted around and be passed from object to // object. The CPicObject class works well off these, and every other CPic* // class has constructors for a reference object. Basically, this works like // a pointer ... there's an object base, and an offset into the object. // class CPicReference { ULONG m_ulObjectOffsetFromParent; CPicHeaderObject *m_pParentObject; public: CPicReference(CPicHeaderObject *pParent, ULONG ulOffset); const PVOID GetRawPointer() const; ULONG GetOffset() const; CPicObject GetObject() const { return CPicObject(m_pParentObject, m_ulObjectOffsetFromParent); } void Clear(); }; // // String table // class CPicStringTable : public CPicObject { PPIC_STRING_TABLE m_pObject; public: CPicStringTable(CPicReference object); bool GetString(ULONG ulFlags, ULONG ulIdent, WCHAR* pwsStringData, ULONG *ulCbString); }; CPicIndexTable::CPicIndexTable(CPicReference object) : CPicObject(object) { if (this->GetType() != PIC_OBJTYPE_DIRECTORY) DebugBreak(); // This is just "self" m_pObject = (PPIC_OBJECT_TABLE)this->GetObjectPointer(); // This is the list of objects m_pObjectList = (PPIC_OBJECT_TABLE_ENTRY)CPicReference(this->GetContainer(), m_pObject->ulTableOffset).GetRawPointer(); } // // Search for an object by its identifier // bool CPicIndexTable::FindObject(ULONG ulObjectIdent, CPicReference *reference) const { if (reference) reference->Clear(); ULONG ul; PPIC_OBJECT_TABLE_ENTRY pHere = this->m_pObjectList; for (ul = 0; ul < m_pObject->ulEntryCount; ul++, pHere++) { if (pHere->ulObjectKey == ulObjectIdent) { if (reference) *reference = CPicReference(this->GetContainer(), pHere->ulObjectOffset); return true; } } return false; }