这次给大家介绍的是memmove,同样还是看不懂英文在说什么,还是看一下百度给我们的通俗易懂的解释。
这就是之前我所说到的,memcpy的一个函数漏洞,他库函数本身就不能避免这个漏洞,所以在进行模仿的时候虽然发现了这个问题但是还是没有将这个问题弥补,因为有让你弥补的地方,那就是来模仿这个memmove函数。
再给大家来说一下memcpy函数的漏洞是哪个,就是上图这样,如果你开始将原始区域的内容复制到目标区域的时候,会将你后半部分的原始区域的数据进行覆盖,造成你原始数据的丢失,所以,你在模仿memmove函数的时候就需要对你操作的两个空间进行判断,看你所要操作的两个数据区域是不是上图的重合情况,如果是的话那你就需要进行特殊的操作。
那特殊的操作是什么呢?期初我是想将原始区域后半部分的数据提前存储起来,之后再对其进行使用,后来我才发现了一个更好的办法就是将你发的复制操作变成从后开始复制,而不是我们正常的从前往后复制。
下边就来写一个这个模拟库函数的代码:
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
void *my_memmove(void *det, const void *src, int n)
{
void *ret = det;
if ((char*)det <= (char *)src || (char *)det >= (char *)src + n)
{
while (n--)
{
*(char *)det = *(char *)src;
det = (char *)det + 1;
src = (char *)src + 1;
}
}
else
{
det = (char *)det + n - 1;
src = (char *)src + n - 1;
while (n--)
{
*(char *)det = *(char *)src;
det = (char *)det -1;
src = (char *)src - 1;
}
}
return ret;
}
int main()
{
char arr[10] = "abcd";
my_memmove(arr + 2, arr, 4);
printf("内存覆盖:%s\n", arr + 2);
system("pause");
return 0;
}
很多人纳闷为什么在你的函数开头要将
*(char *)det = *(char *)src;
det = (char *)det + 1;
src = (char *)src + 1;
这些数据都强制转化成一个char*类型,并不是说你操作的对象是字符串,是因为你操作的单位是一个字符,因为char类型的占用的内存大小就是一个字符,所以这里需要将你的内容变成一个char*类型以对字符进行操作。
这里再进入函数的时候你就需要对这两个操作空间进行一个简单的判断,判断是不是出现了之前所说的那种情况。如果出现了就要对这个数据拷贝进行反向拷贝
所以上述程序中即使两个操作区域进行了覆盖依然可以进行正常的拷贝操作。对一些库函数的模仿暂时就这些了,之后如果还有那些经典的值得大家来模仿一下深究的库函数,我会继续更新给大家。