#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";
}