29.动态内存申请

文章介绍了C语言中动态内存分配的概念,包括静态分配与动态分配的区别,以及动态分配函数如malloc、calloc、realloc和free的使用方法。动态分配允许根据需要在运行时分配内存,而free函数用于释放不再使用的内存。文章还提到了内存泄漏问题及其解决方法,强调了及时释放内存的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.动态内存分配的概念

在数组一章中,介绍过数组的长度是预先定义好的,在整个程序中固定不变,但是在实际的编程中,往往所需的内存空间取决于实际输入的数据,而无法预先确定。为了解决上述问题,C语言提供了一些内存管理函数,这些内存管理函数可以按需要动态的分派内存空间,也可以把不再使用的空间回收再利用

2.静态分配,动态分配

静态分配
  • 在程序编译或运行过程中,按事先规定的大小分配内存空间的分配形式。int a[10]
  • 必须事先知道所需空间的大小。
  • 分配在栈区或全局变量区,一般以数组的形式。
  • 按计划分配
动态分配
  • 在程序的运行过程中,根据需要的大小自由分配所需空间。
  • 按需分配。
  • 分配在堆区,一般使用特定的函数进行分配。

3.动态分配函数

stdlib.h

1.malloc函数

void* malloc(unsigned int size);

  • 在内存的动态存储区(堆区)中分配一块长度为size字节的连续区域,用来存放类型说明符指定的类型。
  • 函数原型返回void* 指针,使用时必须做相应的强制类型转换,分配的内存空间内容不确定,一般使用memset初始化。
  • 返回值:分配空间的初试地址(分配成功)NULL (分配失败)
    在这里插入图片描述
#include<stdio.h>
#include<stdlib.h>
int main()
{
	int* p;
	int i, n;
	printf("请输入您要申请int数组的元素个数\n");
	scanf_s("%d", &n,4);
	p = (int*)malloc(n * 4);
	if (p == NULL)
	{
		printf("malloc error");
		return 0;
	}
	for (i = 0; i < n; i++)
	{
		p[i] = i;
	}
	for (i = 0; i < n; i++)
	{
		printf("p[%d]=%d\n", i, p[i]);
	}
	free(p);
	return 0;
}

在这里插入图片描述

2.free函数(释放内存函数)
  • 头文件 #include<stdlib.h>
  • 函数定义 void free(void* ptr)
  • 函数说明 free函数释放ptr指向的内存。

注意:
1)ptr指向的内存必须是malloc calloc relloc动态申请的内存
2)free后,因为没有给ptr赋值,所以ptr还是指向原来动态申请的内存,但是内存已经不能再用了,ptr变成野指针了。
3)一块动态申请的内存只能free一次,不能多次free。

3.calloc函数
  • 头文件 #include<stdlib.h>

  • 函数定义 void* calloc(size_t nmemb, size_t size);

  • size_t实际是无符号整型,它在头文件中用typedef定义出来的。

  • 函数功能:在内存的堆中,申请nmemb块,每块的大小为size个字节的连续区域。

  • 函数的返回值:申请的内存的首地址(申请成功)返回NULL(申请失败)

注意:
malloc和calloc函数都是用来申请内存的。
区别:
1)函数的名字不同。
2)参数的个数不同。
3)malloc申请的内存,内存中存放的内容是随机的,不确定的。而calloc函数申请的内存中的内容为0.

#include<stdio.h>
#include<stdlib.h>
int main()
{
	int* p;
	int i, n;
	printf("请输入您要申请int数组的元素个数\n");
	scanf_s("%d", &n, 4);
	p = (int*)calloc(n , 4);
	if (p == NULL)
	{
		printf("malloc error");
		return 0;
	}
	for (i = 0; i < n; i++)
	{
		p[i] = i;
	}
	for (i = 0; i < n; i++)
	{
		printf("p[%d]=%d\n", i, p[i]);
	}
	free(p);
	return 0;
}

在堆中申请了n块,每块的大小为4字节,即4*n个字节连续的区域。
在这里插入图片描述

4.realloc 函数(重新申请内存)

调用malloc函数和calloc函数,单次申请的内存是连续的,但两次申请的两块内存不一定连续。有些时候有这种需求,即先用malloc函数或者calloc函数申请了一块内存,还想在原先内存的基础上挨着继续申请内存。或者释放后边一部分内存。这是可以使用realloc函数。

  • 头文件 #include<stdlib.h>
  • 函数的定义 void* realloc(void* s,unsigned int newsize);
  • 函数的功能:在原先s指向的内存基础上重新申请内存,新的内存的大小为newsize个字节,如果原先内存后面有足够大的空间,就追加,如果后面的内存不够用,则realloc函数会在堆区找一个newsize字节大小的内存申请,将原先内存中的内容拷贝过来,然后释放原先的内存,最后返回新的内存地址。

char* p;
p=(char*)malloc(100)
//想要重新申请申请内存,新的大小为50个字节
p=(char*)realloc(p,50);
//p指向的内存新的大小为50个字节,100个字节后50个字节的存储空间就被释放了。
在这里插入图片描述
在这里插入图片描述
注意:malloc calloc realloc动态申请的内存,只有在free或程序结束的时候才释放。

4.内存泄漏

  • 内存泄漏的概念:申请的内存,首地址丢失,再也无法使用,也无法释放,这块内存就被泄露了。

例1:

int main()
{
char *p;
p=(char*)malloc(100);
//p指向内存了
p=“hello world”;
//从此以后,再也找不到申请的100个字节了。则动态申请的100个字节就被泄露了
return 0;
}

例2:

void fun()
{
char* p;
p=(char*)malloc(100);
//p指向内存了
}
int main()
{
fun();
fun();
return 0;
}
//每调用一次fun泄露100个字节

解决方法1

void fun()
{
char* p;
p=(char*)malloc(100);
//p指向内存了
free(p);
}
int main()
{
fun();
fun();
return 0;
}

解决方法2

void fun()
{
char* p;
p=(char*)malloc(100);
//p指向内存了
return p;
}
int main()
{
char* q;
q=fun();
free(q);
return 0;
}

总结:申请的内存,在不用的时候一定要释放内存。

.注入的基本原理是内存注入加执行shell code的方式。 2.通过找到重定位shell code的方式,实现注入。 01:52 内核 APC劫持 1.内核APC劫持是通过插一个内核APC来实现用户模式的执行。 2.内核APC在内核模式执行,可以修改RIPRBP。 03:29 实验环境兼容性说明 1.实验仅兼容Windows 10及以后版本,不支持Windows 7。 2.Windows 7不兼容的原因包括隐藏内存导出函数的问题。 07:37 导入导出函数日志记录 1.引入必要的头文件导出函数。 2.使用log宏记录错误信息。 09:33 设置APC函数 1.设置APC函数,参数包括进程ID注入路由。 2.函数内部实现包括获取线程、插入APC等步骤。 18:34 创建插入APC 1.创建APC,使用no configure putsize of APC。 2.判断APC是否成功创建,并关闭句柄。1.成功执行内核APC,确认PID为5916,TID为4988。 2.通过主线程注入APC,验证内核APC的执行过程。 04:04 寻找KTRAP_FRAME的方法 1.利用堆栈布局寻找KTRAP_FRAME,确保全系统兼容性。 2.通过initial stack、TSS、KPCRB等方式寻找KTRAP_FRAME。 3.选择initial stack方法,因其位置偏移在所有系统上一致。 06:55 获取Initial Stack的方法 1.使用PsGetCurrentProcess()获取current process。 2.通过initial stack减去KTRAP_FRAME大小找到KTRAP_FRAME。 3.验证找到的KTRAP_FRAME是否正确,通过修改地址并断点验证。 11:06 蓝屏问题的解决 1.在尝试修改KTRAP_FRAME时遇到蓝屏问题。 2.通过调试确认蓝屏原因,发现RKL过高导致问题。 3.调整RKL值并重新测试,确认问题解决。.在驱动中申请内存,直接使用 ZwAllocateVirtualMemory 函数。 2.申请内存前需要隐藏 PID 分配大小。 3.定义函数 Ta,传入 PID 分配大小。 4.调用 PsLookupProcessById ZwAllocateVirtualMemory。 06:34 读写文件操作 1.读写文件操作使用 ZwGetFileBuffer 函数。 2.传入文件名、二级指针文件大小。 3.初始化 Unicode 字符串表示文件名。 4.使用 ZwCreateFile 创建文件句柄。 5.查询文件信息,获取文件大小。 6.根据文件大小申请内存,并读取文件内容到内存中。 7.使用 ZwReadFile 读取文件内容。 8.读取完成后,使用 ZwClose ZwFlushBuffersFile 关闭文件并释放内存。该视频主要讲述了完善APC注入的shell code的过程。首先,复制了之前编写的shell code,并强调了其稳定性参数填写的必要性。接着,提到了在使用share code时需要注意关闭一些安全检查防护流保护,以确保代码能够正常生成。然后,复制了manual mapping data函数指针,并补充了缺少的nt image重定位标志。最后,通过复制修改代码,解决了hit memory文件映射的问题,完成了shell code的完善工作。 分段总结 00:12 ShellCode编写与K_routine修改实验完成 1.完善apc注入的shell code,通过复制已有的shell code作为基础。 2.介绍修改K_routine的步骤,包括关闭安全检查防护流保护等。 3.通过链接器设置增量链接,确保shell code的正确生成注入。 4.复制必要的函数指针图像文件,以支持shell code的执行。 5.通过重定位标志复制,完成shell code的最终准备。 08:17 ShellCode注入与测试 1.介绍注入shell code的过程,包括手动映射数据设置APC。 2.提供注入参数的设置方法,包括调用名、路径、PID等。 3.通过复制修改内核实验中的hit memory代码,实现内存注入申请。 4.详细讲解shell code的执行流程,包括寄存器保存、堆栈对齐重定位数据的传递。 5.测试注入的shell code,确保其能在目标系统中正确执行。 28:22 ShellCode稳定性与商用考虑 1.讨论shell code的稳定性,以及在商用环境中的应用考虑。 2.建议在使用shell code后及时卸载,以避免被检测到使用过期签名。 3.介绍在商用环境中,通过事件单对象等待函数来确保注入的稳定性安全性。1.实验目的:实现无驱动附加的读写功能,验证无需读写技术的可行性。 2.实验原理:通过修改内存指令,实现无驱动的读写操作。 3.实验环境:Windows操作系统,WinDbg调试工具。这个是无驱注入。你看看能不能无驱
最新发布
07-22
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

oo0day

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值