反编译以修复旧程序可能会很痛苦。
由于我是C#开发人员,我有些奇怪的事情我不明白。 我需要一个C ++技巧专家来帮助我理解“memcpy()”的行为。
以下是我玩的内容:
unsigned char sdata[] = { 0x54,
... many values (=4100) ...,
0x00 };
然后
unsigned char BF_PTransformed[4*18] = { 0xC6,
... many values (=72) ...,
0x7B };
和
struct BLOWFISH_CTX
{
unsigned long P[16 + 2];
unsigned long S[4][256];
};
以下是memcpy()
来电:
void BFInit()
{
BLOWFISH_CTX* ctx = &this->BlowfishContext;
memcpy((void*)ctx->P, this->BF_PTransformed, 18*4);
memcpy((void*)ctx->S, (void*)this->sdata, 0x100*4*4);
}
我不明白这是如何使用比数组目标长度更多的字节数。 这是关于数据类型吗?
有人可以解释一下,C#开发人员可以理解吗?
(甚至不要提到Blowfish这个词。这个“特殊”实施的2天让我生病了)
答案 0 :(得分:5)
memcpy length参数以字节为单位,而不是数组元素。
代码最好写成:
memcpy((void*)ctx->P, this->BF_PTransformed, 18 * sizeof(unsigned long));
memcpy((void*)ctx->S, (void*)this->sdata, 0x100 * 4 * sizeof(unsigned long));
答案 1 :(得分:5)
我并不认为如何使用比数组目标长度更多的字节数来表现这一点 这是关于数据类型吗?
首先,memcpy
对字节进行操作,而不是数组元素。因此,例如,如果要复制数组int[10]
,则告诉memcpy
复制40个字节(10*sizeof(int)
)。因此传递给memcpy的参数(本例中为40)可能大于数组元素(10)的数量,因为每个数组元素占用的字节数不止一个。
其次,如果你真的告诉memcpy
复制超过数组的末尾(例如,如果我们在上面的例子中将43作为参数传递给memcpy
),那么你将拥有未定义的行为。
在C和C ++中,不需要在编译时或运行时检测到许多错误条件。在C#中,如果您在运行时尝试了非法操作,则会抛出异常。
在C ++中,这也发生在一些案例中。但在许多其他情况下,根本检测不到错误,发生的情况是 undefined 。应用程序可能崩溃,或者它可能继续在损坏的状态下运行。它可能会成为一个安全漏洞,或者它(理论上)可能使恶魔飞出你的鼻子。语言规范简单地说 nothing 关于应该发生什么。
读取数组的末尾(如果你告诉memcpy
复制超过数组的长度就行了)就是这样一个场合。如果您尝试这样做,您的应用程序有一个错误,但没有说它在您尝试运行它时会如何表现。如果你幸运,它会崩溃。在最坏的情况下,它将继续运行,因为它将处于不一致的状态,并且它可能会在以后崩溃(使错误更难以诊断),或者它可能会,而不是崩溃,只是产生错误的结果,或者在您的计算机上运行它时似乎可以正常工作,但在客户运行您的应用程序时会出现任何这些行为。
未定义的行为很糟糕。不惜一切代价避免。