如何使黑客合法化,该黑客假定派生的类变量的相邻存储



在分析第三方代码时,我遇到了一个hack,该黑客假定基类中的变量偶尔存储在该类的另一个变量中,该变量是从中衍生而来的。派生的类添加了一个校验和一个函数,该函数计算了与派生类中校验和校验和校验和的数据的哈希。

这个hack有效,但似乎不能依靠它做出的假设。以下列出了说明这一点的删节代码(请参阅评论:"丑陋hack!"(:

template<unsigned int BYTES>
class BaseClass {
protected:
        unsigned char xdata[BYTES];
public:
        BaseClass() { memset(&xdata[0], 0, sizeof(xdata));  };
        void FooFn() {};
        unsigned char* BigFn() {};
};

template<unsigned int BYTES>
class DerivedClass : public BaseClass<BYTES> {
protected:
    __int64 checksum;
    __int64 CalcChecksum(unsigned char* pBegin, unsigned char* pEnd);
public:
    DerivedClass();
    void HashOfDataAndChecksum(unsigned __int64* outputhash);
};    
//-----------------------------------------------------------------------
template<unsigned int BYTES>
__int64 DerivedClass<BYTES>::CalcChecksum(unsigned char* pBegin, unsigned char* pEnd) {
    __int64 sum = 0;
    while (pBegin++ < pEnd)
        sum += *pBegin;
    return ~sum;
}
template<unsigned int BYTES>
DerivedClass<BYTES>::DerivedClass() {
    checksum = CalcChecksum(&BaseClass<BYTES>::xdata[0], &BaseClass<BYTES>::xdata[sizeof(BaseClass<BYTES>::xdata)]);
}
template<unsigned int BYTES>
void DerivedClass<BYTES>::HashOfDataAndChecksum(unsigned __int64* outputhash) {
    int i;
    unsigned char* pBegin = &BaseClass<BYTES>::xdata[0];
    unsigned char* pEnd = (unsigned char*)(&checksum) + sizeof(checksum);  //UGLY HACK!  Works only if the checksum immediately follows xdata[] in memory.
    unsigned char* x = pBegin;
    while (x < pBegin + ( (pEnd-pBegin) & 0xFFFFFFFFFFFFFFC0) )
    {
        for (i = 0; i < 29; i++)
        {
            XCOMPRESS(x[0], x[8], x[16], x[24], x[32], x[40], x[48], x[56]);
            XCOMPRESS(x[24], x[16], x[8], x[0], x[56], x[48], x[40], x[32]);
            XCOMPRESS(x[32], x[48], x[0], x[16], x[24], x[40], x[56], x[8]);
            XCOMPRESS(x[8], x[32], x[56], x[48], x[40], x[0], x[24], x[16]);
            XCOMPRESS(x[48], x[40], x[56], x[0], x[32], x[24], x[16], x[8]);
            XCOMPRESS(x[16], x[40], x[8], x[48], x[24], x[56], x[0], x[16]);
            XCOMPRESS(x[56], x[48], x[24], x[16], x[8], x[0], x[32], x[40]);
            XCOMPRESS(x[8], x[24], x[40], x[56], x[0], x[16], x[32], x[48]);
            CROSS_NORMALIZE(&x[0]);
        }
        x += 64;
    }
    for (i=0; i < ((pEnd-pBegin) & (size_t)0x3f); i++ )
    {
        //A lot more hashing code
    }
};

int main()
{
    BaseClass<1048576> b;
    assert(sizeof(b) == 1048576);  //This must be true because the code that uses the BaseClass relies on sizeof() this way a lot.
    DerivedClass<1048576> d;
    assert( sizeof(d) == 1048576 + sizeof(__int64) ); //This must be true because the code that uses the DerivedClass relies on sizeof() to be the sum of the BaseClass and DerivedClass storages.
    unsigned __int64 h[8];
    d.FooFn();  //This function operates only on the xdata of the BaseClass
    d.HashOfDataAndChecksum(&h[0]);  //This function calculates a hash of the xdata in the BaseClass concatenated with the checksum in the DerivedClass
}

如何在不诉诸于复制XDATA并将校验和校验和3个变量复制的情况下合法化?...并且不修改哈希算法或基类的大小?

我将使用offsetof,并断言checksum的偏移位于预期的位置。您的代码可能会在任何地方工作,但是如果有人弄乱了基类,则您的代码可能不再起作用。最安全的是困难的方法。

使此合法的最简单方法是将基类更改为 xdata[BYTES + sizeof(std::int64_t)]。这样,您就无需将xdatachecksum同时复制到第三个变量。相反,您只需将checksum复制到xdata末尾的保留空间。

最新更新