.Net Core CLR FileFormat Call Method( Include MetaData, Stream, #~)

#include "pch.h"
#include <iostream>
#include <Windows.h>

#define VAL32(x) x
#define VAL16(x) x
#define DPTR(type) type*
typedef DPTR(IMAGE_DOS_HEADER)      PTR_IMAGE_DOS_HEADER;
typedef DPTR(IMAGE_NT_HEADERS)      PTR_IMAGE_NT_HEADERS;
typedef DPTR(IMAGE_NT_HEADERS64)    PTR_IMAGE_NT_HEADERS64;
typedef ULONG_PTR TADDR;
typedef DPTR(IMAGE_DATA_DIRECTORY)  PTR_IMAGE_DATA_DIRECTORY;
typedef void* PTR_VOID;
typedef DPTR(IMAGE_COR20_HEADER)    PTR_IMAGE_COR20_HEADER;
typedef CONST void far      *LPCVOID;


template <typename Tgt, typename Src>
inline Tgt dac_cast(Src src)
{
#ifdef DACCESS_COMPILE
    // In DAC builds, first get a TADDR for the source, then create the
    // appropriate destination instance.
    TADDR addr = dac_imp::getTaddr(src);
    return dac_imp::makeDacInst<Tgt>::fromTaddr(addr);
#else
    // In non-DAC builds, dac_cast is the same as a C-style cast because we need to support:
    //  - casting away const
    //  - conversions between pointers and TADDR
    // Perhaps we should more precisely restrict it's usage, but we get the precise 
    // restrictions in DAC builds, so it wouldn't buy us much.
    return (Tgt)(src);
#endif
}
TADDR m_base;
TADDR m_b;

#define ALIGN4BYTE(val) (((val) + 3) & ~0x3)

struct STORAGEHEADER
{
public:
    BYTE        fFlags;                 // STGHDR_xxx flags.
    BYTE        pad;
    USHORT      iStreams;               // How many streams are there.
public:
    BYTE GetFlags()
    {
        return fFlags;
    }
    void SetFlags(BYTE flags)
    {
        fFlags = flags;
    }
    void AddFlags(BYTE flags)
    {
        fFlags |= flags;
    }


    USHORT GetiStreams()
    {
        return VAL16(iStreams);
    }
    void SetiStreams(USHORT iStreamsCount)
    {
        iStreams = VAL16(iStreamsCount);
    }
};

struct STORAGESIGNATURE
{
public:
    ULONG       lSignature;             // "Magic" signature.
    USHORT      iMajorVer;              // Major file version.
    USHORT      iMinorVer;              // Minor file version.
    ULONG       iExtraData;             // Offset to next structure of information 
    ULONG       iVersionString;         // Length of version string
public:
    BYTE        pVersion[0];            // Version string
    ULONG GetSignature()
    {
        return VAL32(lSignature);
    }
    void SetSignature(ULONG Signature)
    {
        lSignature = VAL32(Signature);
    }

    USHORT GetMajorVer()
    {
        return VAL16(iMajorVer);
    }
    void SetMajorVer(USHORT MajorVer)
    {
        iMajorVer = VAL16(MajorVer);
    }

    USHORT GetMinorVer()
    {
        return VAL16(iMinorVer);
    }
    void SetMinorVer(USHORT MinorVer)
    {
        iMinorVer = VAL16(MinorVer);
    }

    ULONG GetExtraDataOffset()
    {
        return VAL32(iExtraData);
    }
    void SetExtraDataOffset(ULONG ExtraDataOffset)
    {
        iExtraData = VAL32(ExtraDataOffset);
    }

    ULONG GetVersionStringLength()
    {
        return VAL32(iVersionString);
    }
    void SetVersionStringLength(ULONG VersionStringLength)
    {
        iVersionString = VAL32(VersionStringLength);
    }
};

struct PSTORAGESIGNATURE
{
   public:
    ULONG       lSignature;             // "Magic" signature.
    USHORT      iMajorVer;              // Major file version.
    USHORT      iMinorVer;              // Minor file version.
    ULONG       iExtraData;             // Offset to next structure of information 
    ULONG       iVersionString;         // Length of version string
public:
    BYTE        pVersion[0];            // Version string
    ULONG GetSignature()
    {
        return VAL32(lSignature);
    }
    void SetSignature(ULONG Signature)
    {
        lSignature = VAL32(Signature);
    }

    USHORT GetMajorVer()
    {
        return VAL16(iMajorVer);
    }
    void SetMajorVer(USHORT MajorVer)
    {
        iMajorVer = VAL16(MajorVer);
    }

    USHORT GetMinorVer()
    {
        return VAL16(iMinorVer);
    }
    void SetMinorVer(USHORT MinorVer)
    {
        iMinorVer = VAL16(MinorVer);
    }

    ULONG GetExtraDataOffset()
    {
        return VAL32(iExtraData);
    }
    void SetExtraDataOffset(ULONG ExtraDataOffset)
    {
        iExtraData = VAL32(ExtraDataOffset);
    }

    ULONG GetVersionStringLength()
    {
        return VAL32(iVersionString);
    }
    void SetVersionStringLength(ULONG VersionStringLength)
    {
        iVersionString = VAL32(VersionStringLength);
    }
};

struct STORAGESTREAM;
typedef STORAGESTREAM UNALIGNED * PSTORAGESTREAM;


struct STORAGESTREAM
{
public:
    ULONG       iOffset;                // Offset in file for this stream.
    ULONG       iSize;                  // Size of the file.
    char        rcName[32];  // Start of name, null terminated.
public:
    // Returns pointer to the next stream. Doesn't validate the structure.
    inline PSTORAGESTREAM NextStream()
    {
        int         iLen = (int)(strlen(rcName) + 1);
        iLen = ALIGN4BYTE(iLen);
        return ((PSTORAGESTREAM)(((BYTE*)this) + (sizeof(ULONG) * 2) + iLen));
    }
    // Returns pointer to the next stream.
    // Returns NULL if the structure has invalid format.
    inline PSTORAGESTREAM NextStream_Verify()
    {
        // Check existence of null-terminator in the name
        if (memchr(rcName, 0, 32) == NULL)
        {
            return NULL;
        }
        return NextStream();
    }

    inline ULONG GetStreamSize()
    {
        return (ULONG)(strlen(rcName) + 1 + (sizeof(STORAGESTREAM) - sizeof(rcName)));
    }

    inline char* GetName()
    {
        return rcName;
    }
    inline LPCWSTR GetName(__inout_ecount(iMaxSize) LPWSTR szName, int iMaxSize)
    {
        //VERIFY(::WszMultiByteToWideChar(CP_ACP, 0, rcName, -1, szName, iMaxSize));
        return (szName);
    }
    inline void SetName(LPCWSTR szName)
    {
        int size;
        //size = WszWideCharToMultiByte(CP_ACP, 0, szName, -1, rcName, MAXSTREAMNAME, 0, 0);
        _ASSERTE(size > 0);
    }

    ULONG GetSize()
    {
        return VAL32(iSize);
    }
    void SetSize(ULONG Size)
    {
        iSize = VAL32(Size);
    }

    ULONG GetOffset()
    {
        return VAL32(iOffset);
    }
    void SetOffset(ULONG Offset)
    {
        iOffset = VAL32(Offset);
    }
};


#define UI64_HELPER(x) x ## ui64
#define UI64(x)        UI64_HELPER(x)

class CMiniMdSchemaBase
{
public:
    ULONG       m_ulReserved;           // Reserved, must be zero.
    BYTE        m_major;                // Version numbers.
    BYTE        m_minor;
    BYTE        m_heaps;                // Bits for heap sizes.
    BYTE        m_rid;                  // log-base-2 of largest rid.

    // Bits for heap sizes.
    enum {
        HEAP_STRING_4 = 0x01,
        HEAP_GUID_4 = 0x02,
        HEAP_BLOB_4 = 0x04,

        PADDING_BIT = 0x08,       // Tables can be created with an extra bit in columns, for growth.

        DELTA_ONLY = 0x20,       // If set, only deltas were persisted.
        EXTRA_DATA = 0x40,       // If set, schema persists an extra 4 bytes of data.
        HAS_DELETE = 0x80,       // If set, this metadata can contain _Delete tokens.
    };

    unsigned __int64    m_maskvalid;            // Bit mask of present table counts.

    unsigned __int64    m_sorted;               // Bit mask of sorted tables.
    FORCEINLINE bool IsSorted(ULONG ixTbl)
    {
        return m_sorted & BIT(ixTbl) ? true : false;
    }
    void SetSorted(ULONG ixTbl, int bVal)
    {
        if (bVal) m_sorted |= BIT(ixTbl);
        else      m_sorted &= ~BIT(ixTbl);
    }

#if BIGENDIAN
    // Verify that the size hasn't changed (Update if necessary)
    void ConvertEndianness()
    {
        _ASSERTE(sizeof(CMiniMdSchemaBase) == 0x18);
        m_ulReserved = VAL32(m_ulReserved);
        m_maskvalid = VAL64(m_maskvalid);
        m_sorted = VAL64(m_sorted);
    }
#else
    // Nothing to do on little endian machine
    void ConvertEndianness() { return; }
#endif

private:
    FORCEINLINE unsigned __int64 BIT(ULONG ixBit)
    {
        _ASSERTE(ixBit < (sizeof(__int64)*CHAR_BIT));
        return UI64(1) << ixBit;
    }

};

typedef enum MetadataVersion
{
    MDVersion1 = 0x00000001,
    MDVersion2 = 0x00000002,

    // @TODO - this value should be updated when we increase the version number
    MDDefaultVersion = 0x00000002
} MetadataVersion;
class CMiniMdSchema : public CMiniMdSchemaBase
{
public:
    // These are not all persisted to disk.  See LoadFrom() for details.
    ULONG       m_cRecs[45];     // Counts of various tables.

    ULONG       m_ulExtra;              // Extra data, only persisted if non-zero.  (m_heaps&EXTRA_DATA flags)

    ULONG LoadFrom(const void*, ULONG); // Load from a compressed version.  Return bytes consumed.
    ULONG SaveTo(void *);               // Store a compressed version.  Return bytes used in buffer.
    __checkReturn
        HRESULT InitNew(MetadataVersion);
};
#define GET_UNALIGNED_32(_pObject)  (*(UINT32 UNALIGNED *)(_pObject))
#define GET_UNALIGNED_VAL32(_pObject) VAL32(GET_UNALIGNED_32(_pObject))

//template<typename T> class ClrSafeInt
//{
//public:
//    // Default constructor - 0 value by default
//    ClrSafeInt() :
//        m_value(0),
//        m_overflow(false)
//        COMMA_INDEBUG(m_checkedOverflow(false))
//    {
//    }
//
//    // Value constructor
//    // This is explicit because otherwise it would be harder to 
//    // differentiate between checked and unchecked usage of an operator.
//    // I.e. si + x + y  vs. si + ( x + y )
//    //
//    // Set the m_checkedOverflow bit to true since this is being initialized
//    // with a constant value and we know that it is valid. A scenario in
//    // which this is useful is when an overflow causes a fallback value to
//    // be used:
//    //      if (val.IsOverflow())
//    //          val = ClrSafeInt<T>(some_value);
//    /*explicit ClrSafeInt(T v) :
//        m_value(v),
//        m_overflow(false)
//        COMMA_INDEBUG(m_checkedOverflow(true))
//    {
//    }*/
//
//    template <typename U>
//    explicit ClrSafeInt(U u) :
//        m_value(0),
//        m_overflow(false)
//        COMMA_INDEBUG(m_checkedOverflow(false))
//    {
//        if (!FitsIn<T>(u))
//        {
//            m_overflow = true;
//        }
//        else
//        {
//            m_value = (T)u;
//        }
//    }
//
//    template <typename U>
//    ClrSafeInt(ClrSafeInt<U> u) :
//        m_value(0),
//        m_overflow(false)
//        COMMA_INDEBUG(m_checkedOverflow(false))
//    {
//        if (u.IsOverflow() || !FitsIn<T>(u.Value()))
//        {
//            m_overflow = true;
//        }
//        else
//        {
//            m_value = (T)u.Value();
//        }
//    }
//
//    // Note: compiler-generated copy constructor and assignment operator
//    // are correct for our purposes.
//
//    // Note: The MS compiler will sometimes silently perform value-destroying 
//    // conversions when calling the operators below.  
//    // Eg. "ClrSafeInt<unsigned> s(0); s += int(-1);" will result in s
//    // having the value 0xffffffff without generating a compile-time warning.
//    // Narrowing conversions are generally level 4 warnings so may or may not
//    // be visible.
//    //
//    // In the original SafeInt class, all operators have an 
//    // additional overload that takes an arbitrary type U and then safe 
//    // conversions are performed (resulting in overflow whenever the value
//    // cannot be preserved).
//    // We could do the same thing, but currently don't because: 
//    //  - we don't believe there are common cases where this would result in a 
//    //    security hole.
//    //  - the extra complexity isn't worth the benefits
//    //  - it would prevent compiler warnings in the cases we do get warnings for.
//
//
//    // true if there has been an overflow leading up to the creation of this
//    // value, false otherwise.
//    // Note that in debug builds we track whether our client called this,
//    // so we should not be calling this method ourselves from within this class.
//    inline bool IsOverflow() const
//    {
//        INDEBUG(m_checkedOverflow = true; )
//            return m_overflow;
//    }
//
//    // Get the value of this integer.  
//    // Must only be called when IsOverflow()==false.  If this is called 
//    // on overflow we'll assert in Debug and return 0 in release.
//    inline T Value() const
//    {
//        _ASSERTE_SAFEMATH(m_checkedOverflow);  // Ensure our caller first checked the overflow bit
//        _ASSERTE_SAFEMATH(!m_overflow);
//        return m_value;
//    }
//
//    // force the value into the overflow state.  
//    inline void SetOverflow()
//    {
//        INDEBUG(this->m_checkedOverflow = false; )
//            this->m_overflow = true;
//        // incase someone manages to call Value in release mode - should be optimized out
//        this->m_value = 0;
//    }
//
//
//    //
//    // OPERATORS
//    // 
//
//    // Addition and multiplication.  Only permitted when both sides are explicitly
//    // wrapped inside of a ClrSafeInt and when the types match exactly.  
//    // If we permitted a RHS of type 'T', then there would be differences
//    // in correctness between mathematically equivalent expressions such as 
//    // "si + x + y" and "si + ( x + y )".  Unfortunately, not permitting this
//    // makes expressions involving constants tedius and ugly since the constants
//    // must be wrapped in ClrSafeInt instances.  If we become confident that 
//    // our tools (PreFast) will catch all integer overflows, then we can probably
//    // safely add this.
//    inline ClrSafeInt<T> operator +(ClrSafeInt<T> rhs) const
//    {
//        ClrSafeInt<T> result;       // value is initialized to 0
//        if (this->m_overflow ||
//            rhs.m_overflow ||
//            !addition(this->m_value, rhs.m_value, result.m_value))
//        {
//            result.m_overflow = true;
//        }
//
//        return result;
//    }
//
//    inline ClrSafeInt<T> operator -(ClrSafeInt<T> rhs) const
//    {
//        ClrSafeInt<T> result;       // value is initialized to 0
//        if (this->m_overflow ||
//            rhs.m_overflow ||
//            !subtraction(this->m_value, rhs.m_value, result.m_value))
//        {
//            result.m_overflow = true;
//        }
//
//        return result;
//    }
//
//    inline ClrSafeInt<T> operator *(ClrSafeInt<T> rhs) const
//    {
//        ClrSafeInt<T> result;       // value is initialized to 0
//        if (this->m_overflow ||
//            rhs.m_overflow ||
//            !multiply(this->m_value, rhs.m_value, result.m_value))
//        {
//            result.m_overflow = true;
//        }
//
//        return result;
//    }
//
//    // Accumulation operators
//    // Here it's ok to have versions that take a value of type 'T', however we still
//    // don't allow any mixed-type operations.
//    inline ClrSafeInt<T>& operator +=(ClrSafeInt<T> rhs)
//    {
//        INDEBUG(this->m_checkedOverflow = false; )
//            if (this->m_overflow ||
//                rhs.m_overflow ||
//                !ClrSafeInt<T>::addition(this->m_value, rhs.m_value, this->m_value))
//            {
//                this->SetOverflow();
//            }
//        return *this;
//    }
//
//    inline ClrSafeInt<T>& operator +=(T rhs)
//    {
//        INDEBUG(this->m_checkedOverflow = false; )
//            if (this->m_overflow ||
//                !ClrSafeInt<T>::addition(this->m_value, rhs, this->m_value))
//            {
//                this->SetOverflow();
//            }
//        return *this;
//    }
//
//    inline ClrSafeInt<T>& operator *=(ClrSafeInt<T> rhs)
//    {
//        INDEBUG(this->m_checkedOverflow = false; )
//            if (this->m_overflow ||
//                rhs.m_overflow ||
//                !ClrSafeInt<T>::multiply(this->m_value, rhs.m_value, this->m_value))
//            {
//                this->SetOverflow();
//            }
//        return *this;
//    }
//
//    inline ClrSafeInt<T>& operator *=(T rhs)
//    {
//        INDEBUG(this->m_checkedOverflow = false; )
//            if (this->m_overflow ||
//                !ClrSafeInt<T>::multiply(this->m_value, rhs, this->m_value))
//            {
//                this->SetOverflow();
//            }
//
//        return *this;
//    }
//
//    //
//    // STATIC HELPER METHODS
//    //these compile down to something as efficient as macros and allow run-time testing 
//    //of type by the developer
//    // 
//
//    template <typename U> static bool IsSigned(U)
//    {
//        return std::is_signed<U>::value;
//    }
//
//    static bool IsSigned()
//    {
//        return std::is_signed<T>::value;
//    }
//
//    static bool IsMixedSign(T lhs, T rhs)
//    {
//        return ((lhs ^ rhs) < 0);
//    }
//
//    static unsigned char BitCount() { return (sizeof(T) * 8); }
//
//    static bool Is64Bit() { return sizeof(T) == 8; }
//    static bool Is32Bit() { return sizeof(T) == 4; }
//    static bool Is16Bit() { return sizeof(T) == 2; }
//    static bool Is8Bit() { return sizeof(T) == 1; }
//
//    //both of the following should optimize away
//    static T MaxInt()
//    {
//        if (IsSigned())
//        {
//            return (T)~((T)1 << (BitCount() - 1));
//        }
//        //else
//        return (T)(~(T)0);
//    }
//
//    static T MinInt()
//    {
//        if (IsSigned())
//        {
//            return (T)((T)1 << (BitCount() - 1));
//        }
//        else
//        {
//            return ((T)0);
//        }
//    }
//
//    // Align a value up to the nearest boundary, which must be a power of 2
//    inline void AlignUp(T alignment)
//    {
//        _ASSERTE_SAFEMATH(IsPowerOf2(alignment));
//        *this += (alignment - 1);
//        if (!this->m_overflow)
//        {
//            m_value &= ~(alignment - 1);
//        }
//    }
//
//    //
//    // Arithmetic implementation functions
//    //
//
//    //note - this looks complex, but most of the conditionals 
//    //are constant and optimize away
//    //for example, a signed 64-bit check collapses to:
///*
//    if(lhs == 0 || rhs == 0)
//        return 0;
//
//    if(MaxInt()/+lhs < +rhs)
//    {
//        //overflow
//        throw SafeIntException(ERROR_ARITHMETIC_OVERFLOW);
//    }
//    //ok
//    return lhs * rhs;
//
//    Which ought to inline nicely
//*/
Returns true if safe, false for overflow.
//    static bool multiply(T lhs, T rhs, T &result)
//    {
//        if (Is64Bit())
//        {
//            //fast track this one - and avoid DIV_0 below
//            if (lhs == 0 || rhs == 0)
//            {
//                result = 0;
//                return true;
//            }
//
//            //we're 64 bit - slow, but the only way to do it
//            if (IsSigned())
//            {
//                if (!IsMixedSign(lhs, rhs))
//                {
//                    //both positive or both negative
//                    //result will be positive, check for lhs * rhs > MaxInt
//                    if (lhs > 0)
//                    {
//                        //both positive
//                        if (MaxInt() / lhs < rhs)
//                        {
//                            //overflow
//                            return false;
//                        }
//                    }
//                    else
//                    {
//                        //both negative
//
//                        //comparison gets tricky unless we force it to positive
//                        //EXCEPT that -MinInt is undefined - can't be done
//                        //And MinInt always has a greater magnitude than MaxInt
//                        if (lhs == MinInt() || rhs == MinInt())
//                        {
//                            //overflow
//                            return false;
//                        }
//
//#ifdef _MSC_VER
//#pragma warning( disable : 4146 )   // unary minus applied to unsigned is still unsigned
//#endif
//                        if (MaxInt() / (-lhs) < (-rhs))
//                        {
//                            //overflow
//                            return false;
//                        }
//#ifdef _MSC_VER
//#pragma warning( default : 4146 )
//#endif
//                    }
//                }
//                else
//                {
//                    //mixed sign - this case is difficult
//                    //test case is lhs * rhs < MinInt => overflow
//                    //if lhs < 0 (implies rhs > 0), 
//                    //lhs < MinInt/rhs is the correct test
//                    //else if lhs > 0 
//                    //rhs < MinInt/lhs is the correct test
//                    //avoid dividing MinInt by a negative number, 
//                    //because MinInt/-1 is a corner case
//
//                    if (lhs < 0)
//                    {
//                        if (lhs < MinInt() / rhs)
//                        {
//                            //overflow
//                            return false;
//                        }
//                    }
//                    else
//                    {
//                        if (rhs < MinInt() / lhs)
//                        {
//                            //overflow
//                            return false;
//                        }
//                    }
//                }
//
//                //ok
//                result = lhs * rhs;
//                return true;
//            }
//            else
//            {
//                //unsigned, easy case
//                if (MaxInt() / lhs < rhs)
//                {
//                    //overflow
//                    return false;
//                }
//                //ok
//                result = lhs * rhs;
//                return true;
//            }
//        }
//        else if (Is32Bit())
//        {
//            //we're 32-bit
//            if (IsSigned())
//            {
//                INT64 tmp = (INT64)lhs * (INT64)rhs;
//
//                //upper 33 bits must be the same
//                //most common case is likely that both are positive - test first
//                if ((tmp & 0xffffffff80000000LL) == 0 ||
//                    (tmp & 0xffffffff80000000LL) == 0xffffffff80000000LL)
//                {
//                    //this is OK
//                    result = (T)tmp;
//                    return true;
//                }
//
//                //overflow
//                return false;
//
//            }
//            else
//            {
//                UINT64 tmp = (UINT64)lhs * (UINT64)rhs;
//                if (tmp & 0xffffffff00000000ULL) //overflow
//                {
//                    //overflow
//                    return false;
//                }
//                result = (T)tmp;
//                return true;
//            }
//        }
//        else if (Is16Bit())
//        {
//            //16-bit
//            if (IsSigned())
//            {
//                INT32 tmp = (INT32)lhs * (INT32)rhs;
//                //upper 17 bits must be the same
//                //most common case is likely that both are positive - test first
//                if ((tmp & 0xffff8000) == 0 || (tmp & 0xffff8000) == 0xffff8000)
//                {
//                    //this is OK
//                    result = (T)tmp;
//                    return true;
//                }
//
//                //overflow
//                return false;
//            }
//            else
//            {
//                UINT32 tmp = (UINT32)lhs * (UINT32)rhs;
//                if (tmp & 0xffff0000) //overflow
//                {
//                    return false;
//                }
//                result = (T)tmp;
//                return true;
//            }
//        }
//        else //8-bit
//        {
//            _ASSERTE_SAFEMATH(Is8Bit());
//
//            if (IsSigned())
//            {
//                INT16 tmp = (INT16)lhs * (INT16)rhs;
//                //upper 9 bits must be the same
//                //most common case is likely that both are positive - test first
//                if ((tmp & 0xff80) == 0 || (tmp & 0xff80) == 0xff80)
//                {
//                    //this is OK
//                    result = (T)tmp;
//                    return true;
//                }
//
//                //overflow
//                return false;
//            }
//            else
//            {
//                UINT16 tmp = ((UINT16)lhs) * ((UINT16)rhs);
//
//                if (tmp & 0xff00) //overflow
//                {
//                    return false;
//                }
//                result = (T)tmp;
//                return true;
//            }
//        }
//    }
//
//    // Returns true if safe, false on overflow
//    static inline bool addition(T lhs, T rhs, T &result)
//    {
//        if (IsSigned())
//        {
//            //test for +/- combo
//            if (!IsMixedSign(lhs, rhs))
//            {
//                //either two negatives, or 2 positives
//#ifdef __GNUC__
//                // Workaround for GCC warning: "comparison is always
//                // false due to limited range of data type."
//                if (!(rhs == 0 || rhs > 0))
//#else                
//                if (rhs < 0)
//#endif // __GNUC__ else
//                {
//                    //two negatives
//                    if (lhs < (T)(MinInt() - rhs)) //remember rhs < 0
//                    {
//                        return false;
//                    }
//                    //ok
//                }
//                else
//                {
//                    //two positives
//                    if ((T)(MaxInt() - lhs) < rhs)
//                    {
//                        return false;
//                    }
//                    //OK
//                }
//            }
//            //else overflow not possible
//            result = lhs + rhs;
//            return true;
//        }
//        else //unsigned
//        {
//            if ((T)(MaxInt() - lhs) < rhs)
//            {
//                return false;
//
//            }
//            result = lhs + rhs;
//            return true;
//        }
//    }
//
//    // Returns true if safe, false on overflow
//    static inline bool subtraction(T lhs, T rhs, T& result)
//    {
//        T tmp = lhs - rhs;
//
//        if (IsSigned())
//        {
//            if (IsMixedSign(lhs, rhs)) //test for +/- combo
//            {
//                //mixed positive and negative
//                //two cases - +X - -Y => X + Y - check for overflow against MaxInt()
//                //            -X - +Y - check for overflow against MinInt()
//
//                if (lhs >= 0) //first case
//                {
//                    //test is X - -Y > MaxInt()
//                    //equivalent to X > MaxInt() - |Y|
//                    //Y == MinInt() creates special case
//                    //Even 0 - MinInt() can't be done
//                    //note that the special case collapses into the general case, due to the fact
//                    //MaxInt() - MinInt() == -1, and lhs is non-negative
//                    //OR tmp should be GTE lhs
//
//                    // old test - leave in for clarity
//                    //if(lhs > (T)(MaxInt() + rhs)) //remember that rhs is negative
//                    if (tmp < lhs)
//                    {
//                        return false;
//                    }
//                    //fall through to return value
//                }
//                else
//                {
//                    //second case
//                    //test is -X - Y < MinInt()
//                    //or      -X < MinInt() + Y
//                    //we do not have the same issues because abs(MinInt()) > MaxInt()
//                    //tmp should be LTE lhs
//
//                    //if(lhs < (T)(MinInt() + rhs)) // old test - leave in for clarity
//                    if (tmp > lhs)
//                    {
//                        return false;
//                    }
//                    //fall through to return value
//                }
//            }
//            // else 
//            //both negative, or both positive
//            //no possible overflow
//            result = tmp;
//            return true;
//        }
//        else
//        {
//            //easy unsigned case
//            if (lhs < rhs)
//            {
//                return false;
//            }
//            result = tmp;
//            return true;
//        }
//    }
//
//private:
//    // Private helper functions
//    // Note that's it occasionally handy to call the arithmetic implementation
//    // functions above so we leave them public, even though we almost always use
//    // the operators instead.
//
//    // True if the specified value is a power of two.
//    static inline bool IsPowerOf2(T x)
//    {
//        // find the smallest power of 2 >= x
//        T testPow = 1;
//        while (testPow < x)
//        {
//            testPow = testPow << 1;           // advance to next power of 2
//            if (testPow <= 0)
//            {
//                return false;       // overflow 
//            }
//        }
//
//        return(testPow == x);
//    }
//
//    //
//    // Instance data
//    //
//
//    // The integer value this instance represents, or 0 if overflow.
//    T m_value;
//
//    // True if overflow has been reached.  Once this is set, it cannot be cleared.
//    bool m_overflow;
//
//    // In debug builds we verify that our caller checked the overflow bit before 
//    // accessing the value.  This flag is cleared on initialization, and whenever 
//    // m_value or m_overflow changes, and set only when IsOverflow
//    // is called.
//    INDEBUG(mutable bool m_checkedOverflow; )
//};

ULONG
CMiniMdSchema::LoadFrom(
    const void *pvData,     // Data to load from.
    ULONG       cbData)     // Amount of data available.
{
    ULONG ulData;   // Bytes consumed.

    ulData = sizeof(CMiniMdSchemaBase);

    // Be sure we can get the base part.
    if (cbData < ulData)
        return (ULONG)(-1);

    // Transfer the fixed fields. The (void*) casts prevents the compiler 
    // from making bad assumptions about the alignment.
    memcpy((void *)this, (void *)pvData, sizeof(CMiniMdSchemaBase));
    static_cast<CMiniMdSchemaBase*>(this)->ConvertEndianness();

    unsigned __int64 maskvalid = m_maskvalid;

    // Transfer the variable fields.
    memset(m_cRecs, 0, sizeof(m_cRecs));
    int iDst;
    for (iDst = 0; iDst < 45; ++iDst, maskvalid >>= 1)
    {
        if ((maskvalid & 1) != 0)
        {
            // Check integer overflow for: ulData + sizeof(UINT32)
            ULONG ulDataTemp;
        /*    if (!ClrSafeInt<ULONG>::addition(ulData, sizeof(UINT32), ulDataTemp))
            {
                return (ULONG)(-1);
            }*/
            // Verify that the data is there before touching it.
            if (cbData < (ulData + sizeof(UINT32)))
                return (ULONG)(-1);

            m_cRecs[iDst] = GET_UNALIGNED_VAL32((const BYTE *)pvData + ulData);
            // It's safe to sum, because we checked integer overflow above
            ulData += sizeof(UINT32);
        }
    }
    // Also accumulate the sizes of any counters that we don't understand.


    // Retrieve the extra 4 bytes data.
    // Did we go past end of buffer?
    if (cbData < ulData)
        return (ULONG)(-1);

    return ulData;
} // CMiniMdSchema::LoadFrom
#define COMPRESSED_MODEL_STREAM_A   "#~"

template<class T> inline T Align4(T p)
{
    /*LIMITED_METHOD_CONTRACT;
*/
    INT_PTR i = (INT_PTR)p;
    i = (i + (3)) & ~3;
    return (T)i;
}

struct CMiniColDef
{
    BYTE        m_Type;                 // Type of the column.
    BYTE        m_oColumn;              // Offset of the column.
    BYTE        m_cbColumn;             // Size of the column.
};

struct CMiniTableDef
{
    CMiniColDef *m_pColDefs;            // Array of field defs.
    BYTE        m_cCols;                // Count of columns in the table.
    BYTE        m_iKey;                 // Column which is the key, if any.
    USHORT      m_cbRec;                // Size of the records.
};

struct CMiniTableDefEx
{
    CMiniTableDef   m_Def;              // Table definition.
    const char  * const *m_pColNames;   // Array of column names.
    const char  *m_pName;               // Name of the table.
};

const BYTE s_ModuleCol[] = { 2,
  97,0,2,  101,2,2,  102,4,2,  102,6,2,  102,8,2,
  97,0,2,  101,2,4,  102,6,2,  102,8,2,  102,10,2,
};
const BYTE s_TypeRefCol[] = { 2,
  75,0,2,  101,2,2,  101,4,2,
  75,0,2,  101,2,4,  101,6,4,
};
const BYTE s_TypeDefCol[] = { 2,
  99,0,4,  101,4,2,  101,6,2,  64,8,2,  4,10,2,  6,12,2,
  99,0,4,  101,4,4,  101,8,4,  64,12,2,  4,14,2,  6,16,2,
};
const BYTE s_FieldPtrCol[] = { 1,
  4,0,2,
};
const BYTE s_FieldCol[] = { 3,
  97,0,2,  101,2,2,  103,4,2,
  97,0,2,  101,2,4,  103,6,4,
  97,0,2,  101,2,4,  103,6,2,
};
const BYTE s_MethodPtrCol[] = { 1,
  6,0,2,
};
const BYTE s_MethodCol[] = { 3,
  99,0,4,  97,4,2,  97,6,2,  101,8,2,  103,10,2,  8,12,2,
  99,0,4,  97,4,2,  97,6,2,  101,8,4,  103,12,4,  8,16,2,
  99,0,4,  97,4,2,  97,6,2,  101,8,4,  103,12,2,  8,14,2,
};
const BYTE s_ParamPtrCol[] = { 1,
  8,0,2,
};
const BYTE s_ParamCol[] = { 2,
  97,0,2,  97,2,2,  101,4,2,
  97,0,2,  97,2,2,  101,4,4,
};

class ModuleRec
{
public:
    USHORT  m_Generation;               // ENC generation.
public:
    enum {
        COL_Generation,

        COL_Name,
        COL_Mvid,
        COL_EncId,
        COL_EncBaseId,
        COL_COUNT,
        COL_KEY
    };
    USHORT GetGeneration()
    {
        //LIMITED_METHOD_CONTRACT;

        //return GET_UNALIGNED_VAL16(&m_Generation);
    }
    void SetGeneration(USHORT Generation)
    {
        //LIMITED_METHOD_CONTRACT;

        m_Generation = VAL16(Generation);
    }
};

#define offsetof(s,m)   (size_t)( (ptrdiff_t)&reinterpret_cast<const char&>((((s *)0)->m)) )


static CMiniColDef rModuleCols[] = {
        {97,offsetof(ModuleRec,m_Generation),sizeof(((ModuleRec*)(0))->m_Generation)},
        {101,0,0},
        {102,0,0},
        {102,0,0},
        {102,0,0},
};

static const char *rModuleColNames[] = {
    "Generation",
    "Name",
    "Mvid",
    "Encld",
    "EncBaseld",
};

CMiniTableDef   m_TableDefs[9];

# define lengthof(x) (sizeof(x)/sizeof((x)[0]))
#define STRING_POOL_STREAM_A        "#Strings"
const CMiniTableDefEx g_Tables[9] = {
    { {rModuleCols,lengthof(rModuleCols),ModuleRec::COL_KEY,0},rModuleColNames,"Module" }
};

#define BYTEARRAY_TO_COLDES(bytearray) (CMiniColDef*)((bytearray) + 1)

struct dllmodulename {
public:
    char ModuleName[4];
};

typedef dllmodulename *modulename;


struct ModuleIndex
{
    USHORT Generation;
    USHORT Name;
    USHORT Mvid;
    USHORT EncId;
    USHORT EncBaseId;
};

typedef ModuleIndex *MIndex;


struct MethodIndex
{
    DWORD  RVA;
    USHORT ImpFlags;
    USHORT Flags;
    USHORT Name;
    USHORT Signature;
    USHORT ParamList;
};

typedef MethodIndex *TIndex;


struct TypeRefIndex 
{
    USHORT    ResolutionScope;
    USHORT Name;
    USHORT NameSpace;
};

typedef TypeRefIndex * TFIndex;

struct TypeDefIndex
{
    ULONG Flags;
    USHORT Name;
    USHORT NameSpace;
    USHORT Extends;
    USHORT FieldList;
    USHORT MethodList;
};
typedef TypeDefIndex *TDIndex;

typedef void (STDMETHODCALLTYPE MainMethodMp)(LPCWSTR* args);
typedef int (STDMETHODCALLTYPE Add)(int ,int y);


typedef DPTR(IMAGE_IMPORT_DESCRIPTOR)    PTR_IMAGE_IMPORT_DESCRIPTOR;

typedef DPTR(IMAGE_EXPORT_DIRECTORY)     PTR_IMAGE_EXPORT_DIRECTORY;


_IMAGE_SECTION_HEADER section_header;
//
//DWORD RVAToFOA(DWORD imageAddr)
//{
//    /*
//     * 相对虚拟地址转文件偏移地址
//     * ①获取Section数目
//     * ②获取SectionAlignment
//     * ③判断需要转换的RVA位于哪个Section中(section[n]),
//     * offset = 需要转换的RVA-VirtualAddress,计算出RVA相对于本节的偏移地址
//     * ④section[n].PointerToRawData + offset就是RVA转换后的FOA
//    */
//
//    /*if (imageAddr > imageSize) {
//        printf("RVAToFOA in_addr is error!%08X\n", imageAddr);
//        exit(EXIT_FAILURE);
//    }*/
//    if (imageAddr < section_header[0].PointerToRawData) {
//        return imageAddr;//在头部(包括节表与对齐)则直接返回
//    }
//    IMAGE_SECTION_HEADER * section = section_header;
//    DWORD offset = 0;
//    for (int i = 0; i < sectionNum; i++) {
//        DWORD lower = section[i].VirtualAddress;//该节下限
//        DWORD upper = section[i].VirtualAddress + section[i].Misc.VirtualSize;//该节上限
//        if (imageAddr >= lower && imageAddr <= upper) {
//            offset = imageAddr - lower + section[i].PointerToRawData;//计算出RVA的FOA
//            break;
//        }
//    }
//    return offset;
//}

typedef struct IMPR2 {
    union {
        DWORD   Characteristics;            // 0 for terminating null import descriptor
        DWORD   OriginalFirstThunk;         // RVA to original unbound IAT (PIMAGE_THUNK_DATA)
    } DUMMYUNIONNAME;
    DWORD   TimeDateStamp;                  // 0 if not bound,
                                            // -1 if bound, and real date\time stamp
                                            //     in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)
                                            // O.W. date/time stamp of DLL bound to (Old BIND)

    DWORD   ForwarderChain;
}IMPTR2;

typedef struct IMPR3 {
    char*   Name;
    DWORD   FirstThunk;                     // RVA to IAT (if bound this IAT has actual addresses)
} IMPTR3;

typedef struct IMPR1 {
    union {
        DWORD   Characteristics;            // 0 for terminating null import descriptor
        DWORD   OriginalFirstThunk;         // RVA to original unbound IAT (PIMAGE_THUNK_DATA)
    } DUMMYUNIONNAME;
    DWORD   TimeDateStamp;                  // 0 if not bound,
                                            // -1 if bound, and real date\time stamp
                                            //     in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)
                                            // O.W. date/time stamp of DLL bound to (Old BIND)

    DWORD   ForwarderChain;                 // -1 if no forwarders
    char*   Name;
    DWORD   FirstThunk;                     // RVA to IAT (if bound this IAT has actual addresses)
} IMPTR1;

int main()
{
    HMODULE HE=LoadLibraryExW(L"C:\\Users\\Administrator\\Desktop\\Consletest\\ConsoleApp5.dll", NULL, 8);
    //0x00007ff82c940000
    //0x00007ff82e1c0000
    m_base=TADDR((void *)HE);
    IMAGE_DOS_HEADER *SR =dac_cast<PTR_IMAGE_DOS_HEADER>(PTR_IMAGE_DOS_HEADER(HE));
    IMAGE_NT_HEADERS *HR =dac_cast<PTR_IMAGE_NT_HEADERS64>(PTR_IMAGE_NT_HEADERS(m_base + VAL32(SR->e_lfanew)));
    IMAGE_DATA_DIRECTORY *pDir=dac_cast<PTR_IMAGE_DATA_DIRECTORY>(dac_cast<TADDR>(dac_cast<PTR_IMAGE_NT_HEADERS64>(PTR_IMAGE_NT_HEADERS(m_base + VAL32(PTR_IMAGE_DOS_HEADER(HE)->e_lfanew)))) +
        offsetof(IMAGE_NT_HEADERS64, OptionalHeader.DataDirectory) + 14 * sizeof(IMAGE_DATA_DIRECTORY));


    IMAGE_DATA_DIRECTORY *Import = dac_cast<PTR_IMAGE_DATA_DIRECTORY>(dac_cast<TADDR>(dac_cast<PTR_IMAGE_NT_HEADERS64>(PTR_IMAGE_NT_HEADERS(m_base + VAL32(PTR_IMAGE_DOS_HEADER(HE)->e_lfanew)))) +
        offsetof(IMAGE_NT_HEADERS64, OptionalHeader.DataDirectory) +  sizeof(IMAGE_DATA_DIRECTORY));
    IMAGE_IMPORT_DESCRIPTOR *IY= PTR_IMAGE_IMPORT_DESCRIPTOR(m_base + VAL32(Import->VirtualAddress));
    BYTE * te1 = (BYTE*)(VAL32(m_base+IY->Name));
    modulename te = (modulename)te1;
    /*BYTE* me1 = ((BYTE*)pvCurrentData + 401);
    modulename te = (modulename)me1;*/
    PIMAGE_THUNK_DATA IA = PIMAGE_THUNK_DATA64(m_base +VAL32(IY->OriginalFirstThunk));
    PIMAGE_THUNK_DATA IAaddress = PIMAGE_THUNK_DATA(m_base + VAL32(IY->FirstThunk));
    PIMAGE_IMPORT_BY_NAME PE = NULL;
    while (0 != IY->Name)
    {
        while (true)
        {
            if (0 == IA->u1.AddressOfData)
            {
                break;
            }
            PE = (PIMAGE_IMPORT_BY_NAME)(m_base + IA->u1.AddressOfData);

            IA++;
            IAaddress++;
        }
        IY++;
    }


   


    IMAGE_COR20_HEADER *OR = PTR_IMAGE_COR20_HEADER(m_base + VAL32(pDir->VirtualAddress));
    IMAGE_DATA_DIRECTORY  *DR =&(OR->MetaData);
    const void* pMeta = NULL;
    pMeta=dac_cast<PTR_VOID>(VAL32(m_base+DR->VirtualAddress));
    ULONG cbStreamBuffer;
    const BYTE *pbMd;
    pbMd = (const BYTE *)pMeta;
    pbMd += sizeof(STORAGESIGNATURE);
    ULONG cbVersionString = ((STORAGESIGNATURE *)pMeta)->GetVersionStringLength();

    pbMd += cbVersionString;
    pbMd += sizeof(STORAGEHEADER);
    PSTORAGESTREAM pStream;
    pStream = (PSTORAGESTREAM)pbMd;    
    int i;
    CMiniMdSchema   m_Schema;
    ULONG   cbData;
    ULONG   cb;
    BYTE *FF;
    for (i = 0; i < 5; i++)
    {
        void *pvCurrentData = (void *)((BYTE *)pMeta + pStream->GetOffset());
        //BYTE *E= (BYTE *)pMeta + pStream->GetOffset();
        ULONG cbCurrentData = pStream->GetSize();
        BYTE   *pBuf = reinterpret_cast<BYTE*>(pvCurrentData);

        PSTORAGESTREAM pNext = pStream->NextStream_Verify();

        if (strcmp(pStream->GetName(), COMPRESSED_MODEL_STREAM_A) == 0)
        {
            cbData = sizeof(CMiniMdSchemaBase);
            cb=m_Schema.LoadFrom(pvCurrentData, cbCurrentData);
            FF= pBuf + Align4(cb);

            {
                m_TableDefs[0] = g_Tables[0].m_Def;
                m_TableDefs[0].m_pColDefs = BYTEARRAY_TO_COLDES(s_ModuleCol);

                CMiniColDef pCols[9];
                BYTE        iOffset;
                BYTE        iSize;
                iOffset = 0;
                BYTE * FFF;
                {
                    //for (ULONG ixCol = 0; ixCol < m_TableDefs->m_cCols; ++ixCol)
                    //{
                    //    pCols[ixCol] = m_TableDefs->m_pColDefs[ixCol];

                    //    switch (pCols[ixCol].m_Type)
                    //    {
                    //    case 100:
                    //        iSize = 1;
                    //        _ASSERTE(pCols[ixCol].m_cbColumn == iSize);
                    //        _ASSERTE(pCols[ixCol].m_oColumn == iOffset);
                    //        break;
                    //    case 96:
                    //    case 97:
                    //        iSize = 2;
                    //        _ASSERTE(pCols[ixCol].m_cbColumn == iSize);
                    //        _ASSERTE(pCols[ixCol].m_oColumn == iOffset);
                    //        break;
                    //    case 98:
                    //    case 99:
                    //        iSize = 4;
                    //        _ASSERTE(pCols[ixCol].m_cbColumn == iSize);
                    //        _ASSERTE(pCols[ixCol].m_oColumn == iOffset);
                    //        break;
                    //    case 101:
                    //        iSize = 4;
                    //        break;
                    //    case 102:
                    //        iSize = (m_Schema.m_heaps & CMiniMdSchema::HEAP_GUID_4) ? 4 : 2;
                    //        break;
                    //    case 103:
                    //        iSize = (m_Schema.m_heaps & CMiniMdSchema::HEAP_BLOB_4) ? 4 : 2;
                    //        break;
                    //    default:
                    //        _ASSERTE(!"Unexpected schema type");
                    //        iSize = 0;
                    //        break;
                    //    }

                    //    pCols[ixCol].m_oColumn = iOffset;
                    //    pCols[ixCol].m_cbColumn = iSize;

                    //    // Align to 2 bytes.
                    //    iSize += iSize & 1;

                    //    iOffset += iSize;
                    //}
                }

                m_TableDefs->m_cbRec = 12;
                m_TableDefs[1].m_cbRec = 10;
                m_TableDefs[2].m_cbRec = 18;
                m_TableDefs[3].m_cbRec = 2;
                m_TableDefs[4].m_cbRec = 10;
                m_TableDefs[5].m_cbRec = 2;
                m_TableDefs[6].m_cbRec = 18;
                m_TableDefs[7].m_cbRec = 2;
                m_TableDefs[8].m_cbRec = 8;

                int cbtablesize=0;
                int FX = 0;
                for (int i = 0; i < 6; i++)
                {
                     cbtablesize = (m_TableDefs[i].m_cbRec)*(m_Schema.m_cRecs[i]);
                     FX += cbtablesize;
                }


                MIndex EX = (MIndex)FF;//Module
                TFIndex TX = (TFIndex)(FF + 10);//TypeRef
                TDIndex TD = (TDIndex)(FF +10+72+6);// TypeDef

                
                //TIndex MX = (TIndex)(FF + 10 + 72 + 6 + 30-4-2+4);
                TIndex MX = (TIndex)(FF +116);//Method

        /*        const void *MMM = dac_cast<PTR_VOID>(VAL32(m_base+MX->RVA));
                MainMethodMp *MN = (MainMethodMp*)MMM;

                MN(NULL);*/

                CMiniColDef sColumn = m_TableDefs[0].m_pColDefs[ModuleRec::COL_Name];
                ULONG cRecs = m_Schema.m_cRecs[0];

                BYTE* EF = FF + (cRecs - 1)*m_TableDefs[0].m_cbRec + sColumn.m_oColumn;
            }

            int i = 0;
            int e = 0;
            int d = 0;

        }
        if (strcmp(pStream->GetName(), STRING_POOL_STREAM_A) == 0)
        {
            
        
            BYTE *Consoledll= ((BYTE*)pvCurrentData+406);


            BYTE* me1 = ((BYTE*)pvCurrentData +401);
            modulename te = (modulename)me1;


            modulename me= (modulename)Consoledll;

            char *m = me->ModuleName;

            int i = 0;
            int e = 0;
            int d = 0;

        }
        pStream = pNext;
    }
    std::cout << "Hello World!\n"; 
}

猜你喜欢

转载自blog.csdn.net/tangyanzhi1111/article/details/98150572
CLR