恶意软件开发——内存相关API

恶意软件开发——内存相关API

一、前言

Windows操作系统的内存有三种属性,分别为:可读、可写、可执行,并且操作系统将每个进程的内存都隔离开来,当进程运行时,创建一个虚拟的内存空间,系统的内存管理器将虚拟内存空间映射到物理内存上,所以每个进程的内存都是等大的。

操作系统给予每个进程申请内存的权利,使用不同的API,申请的内存具有不同的涵义。

在进程申请时,需要声明这块内存的基本信息:申请内存大小、申请内存起始内存基址、申请内存属性、申请内存对外的权限等。

二、相关API介绍

1.VirtualAlloc
该函数的功能是在调用进程的虚地址空间,预定或者提交一部分页,如果用于内存分配的话,并且分配类型未指定MEM_RESET,则系统将自动设置为0;其函数原型:

LPVOID VirtualAlloc{ LPVOID lpAddress, // 要分配的内存区域的地址 DWORD dwSize, // 分配的大小 DWORD flAllocationType, // 分配的类型 DWORD flProtect // 该内存的初始保护属性 };

参数说明:
1.LPVOID lpAddress, 分配内存区域的地址。当你使用VirtualAlloc来提交一块以前保留的内存块的时候,lpAddress参数可以用来识别以前保留的内存块。如果这个参数是NULL,系统将会决定分配内存区域的位置,并且按64-KB向上取整(roundup)。
2.SIZE_T dwSize, 要分配或者保留的区域的大小。这个参数以字节为单位,而不是页,系统会根据这个大小一直分配到下页的边界DWORD
3.flAllocationType, 分配类型 ,你可以指定或者合并以下标志:MEM_COMMIT,MEM_RESERVE和MEM_TOP_DOWN。
4.DWORD flProtect 指定了被分配区域的访问保护方式:PAGE_EXECUTE_READ,PAGE_EXECUTE_READWRITE
小结:
VirtualAlloc可以通过并行多次调用提交一个区域的部分或全部来保留一个大的内存区域。多重调用提交同一块区域不会引起失败。这使得一个应用程 序保留内存后可以随意提交将被写的页。当这种方式不在有效的时候,它会释放应用程序通过检测被保留页的状态看它是否在提交调用之前已经被提交。
VirtualAlloc对应的释放函数为VirtualFree。

2.HeapAlloc
该函数是从堆上分配一块内存,且分配的内存是不可移动的(即如果没有连续的空间能满足分配的大小,程序不能将其他零散的空间利用起来,从而导致分配失败)。该分配方法是从一指定地址开始分配,而不像GloabalAlloc是从全局堆上分配,这个有可能是全局,也有可能是局部,其函数原型:

LPVOID HeapAlloc( HANDLE hHeap, //要分配堆的句柄 DWORD dwFlags, //堆分配时的可选参数 SIZE_T dwBytes, //要分配堆的字节数 );

参数说明:
1.HANDLE hHeap,要分配堆的句柄,可以通过HeapCreate()函数或GetProcessHeap()函数获得。
2.DWORD dwFlags,堆分配时的可选参数,其值可以为以下的一种或多种:HEAP_GENERATE_EXCEPTIONS(如果分配错误将会抛出异常,而不是返回NULL。异常值可能是STATUS_NO_MEMORY, 表示获得的内存容量不足,或是STATUS_ACCESS_VIOLATION,表示存取不合法),HEAP_NO_SERIALIZE(不使用连续存取),HEAP_ZERO_MEMORY(将分配的内存全部清零)。
3.SIZE_T dwBytes,要分配堆的字节数。
小结:
hHeap是进程堆内存开始位置,dwFlags是分配堆内存的标志。包括HEAP_ZERO_MEMORY,即使分配的空间清零,dwBytes是分配堆内存的大小,其对应的释放空间函数为HeapFree。

3.GlobalAlloc
该函数用于从全局堆中分配出内存供程序使用,函数原型为:

HGLOBALGlobalAlloc( UINTuFlags, // 分配属性(方式) DWORDdwBytes, // 分配的字节数 );

参数说明:
1.UINTuFlags,指定如何分配内存,若指定为0,则是默认的GMEM_FIXED.这个值可以是下面其中一个或几个位标识(那些指明不兼容的组合除外),标识:GHND(为GMEM_MOVEABLE 和 GMEM_ZEROINIT的组合),GMEM_FIXED(分配固定的内存,返回值是一个指针),GMEM_MOVEABLE(分配可移动的内存,在Win32中内存块在物理内存中是不可移动的,但在缺省堆中可以. 返回值是该内存对象的句柄,可使用函数 GlobalLock 将该句柄转换为一个指针,这个标识不能与 GMEM_FIXED 组合使用),GMEM_ZEROINIT(将所申请内存初始化为0),GPTR(为GMEM_FIXED和GMEM_ZEROINIT组合)。
2.DWORDdwBytes,指定要申请的字节数.若该参数为 0 且参数 uFlags 指定为 GMEM_MOVEABLE 则该函数返回一个内存对象的句柄,该内存对象被标识为discarded(可抛弃的)
小结:
使用此函数分配内存可以保证8字节的边界.所有的内存均在执行访问时创建;不需要特别的函数来动态执行所产生的代码,若函数调用成功,将至少分配所需内存.若实际分配量超过所需,则内存仍然能够充分利用之.可用函数 GlobalSize 来确定实际所分配的字节数,可使用 GlobalFree 来释放内存。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zysxyf.html