> 文章列表 > 3.27~~~~

3.27~~~~

3.27~~~~

使用内存分配函数,分别在堆,栈,和进程虚拟空间,分别申请三块内存,大小为下0x10,0x30,0x50。每一块内存,写入特定的数据,释放后再申请另一块新的内存。一共9次申请和释放操作。(编程所用到的头文件和函数参数自己查)还包括使用OD观察内存情况

先看看第一次模仿学习写出来的代码

#include<stdio.h>
#include<malloc.h>
#include <stdlib.h>
#include<windows.h>
int main()
{char *str;str = (char *) malloc(16);strcpy(str, "runoob");printf("String = %s,  Address = %u\\n", str, str);str = (char *) realloc(str, 48);strcat(str, ".com");printf("String = %s,  Address = %u\\n", str, str);str = (char *) alloca(80);strcat(str, ".cyy");printf("String = %s,  Address = %u\\n", str, str);free(str);char* pByte = (char*)VirtualAlloc(NULL, 16 ,MEM_RESERVE,PAGE_READWRITE);strcpy(pByte, "runoob");if (pByte != NULL){printf("申请内存成功!");}VirtualFree(pByte,0,MEM_RELEASE);DWORD dwProcessId = GetCurrentProcessId();HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);char*	m_pTextBuffer = (char *)VirtualAllocEx(hProcess, NULL,48, MEM_COMMIT, PAGE_READWRITE ); if(m_pTextBuffer == NULL){printf("申请内失败!");}char* pInt=(char *)GlobalAlloc(GMEM_ZEROINIT,48);GlobalFree(pInt);return 0;}void MemHeap(void){const int nHeapSize = 80;PBYTE pNewHeap = (PBYTE) ::HeapAlloc(GetProcessHeap(), 0, nHeapSize);if (pNewHeap){ZeroMemory(pNewHeap, nHeapSize);BOOL bRes = ::HeapFree(GetProcessHeap(), 0, pNewHeap);}  }

这个代码在编译里运行没有任何问题
然后我没有往申请的内存里写内容
然后补一下内容

#include<windows.h>
int main()
{char *str;str = (char *) malloc(16);strcpy(str, "runoob");printf("String = %s,  Address = %u\\n", str, str);str = (char *) realloc(str, 48);strcat(str, ".com");printf("String = %s,  Address = %u\\n", str, str);str = (char *) alloca(80);strcat(str, ".cyy");printf("String = %s,  Address = %u\\n", str, str);free(str);char* pByte = (char*)VirtualAlloc(NULL, 16 ,MEM_RESERVE,PAGE_READWRITE);strcpy(pByte, "runoob");if (pByte != NULL){printf("申请内存成功!");}VirtualFree(pByte,0,MEM_RELEASE);DWORD dwProcessId = GetCurrentProcessId();HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);char*	m_pTextBuffer = (char *)VirtualAllocEx(hProcess, NULL,48, MEM_COMMIT, PAGE_READWRITE );strcpy(m_pTextBuffer, "runoob"); char* pInt=(char *)GlobalAlloc(GMEM_ZEROINIT,48);strcpy(pInt, "runoob"); GlobalFree(pInt);return 0;}void MemHeap(void){const int nHeapSize = 80;PBYTE pNewHeap = (PBYTE) ::HeapAlloc(GetProcessHeap(), 0, nHeapSize);if (pNewHeap){ZeroMemory(pNewHeap, nHeapSize);memcpy(pNewHeap," 分配堆内存成功 ",sizeof(" 分配堆内存成功")); BOOL bRes = ::HeapFree(GetProcessHeap(), 0, pNewHeap);}  }

然后编一个bin出来,这里我就不上上传了

要求:用OD ,主要观察,每次释放内存后,之前写入内存中的内容,是否依然存在?
先定位到代码然后观察,申请内存的函数,F7进入看看,底层函数到底是调用哪个API

3.27~~~~第一个错误出来了,写入内容后的一个bin在OD中完全跑不了

问题,出错的原因,栈内存,释放用了堆的释放函数
3.27~~~~

我们再次调整

#include<malloc.h>
#include <stdlib.h>
#include<windows.h>#pragma warning(disable:4996)
int main()
{char* str;str = (char*)malloc(16);strcpy(str, "runoob");printf("String = %s,  Address = %u\\n", str, str);free(str);str = (char*)_alloca(80);strcat(str, ".cyy");printf("String = %s,  Address = %u\\n", str, str);_freea(str);char* pByte = (char*)VirtualAlloc(NULL, 16, MEM_RESERVE, PAGE_READWRITE);strcpy(pByte, "runoob");if (pByte != NULL){printf("申请内存成功!");}VirtualFree(pByte, 0, MEM_RELEASE);DWORD dwProcessId = GetCurrentProcessId();HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);char* m_pTextBuffer = (char*)VirtualAllocEx(hProcess, NULL, 48, MEM_COMMIT, PAGE_READWRITE);strcpy(m_pTextBuffer, "runoob");char* pInt = (char*)GlobalAlloc(GMEM_ZEROINIT, 48);strcpy(pInt, "runoob");GlobalFree(pInt);return 0;}void MemHeap(void)
{const int nHeapSize = 80;PBYTE pNewHeap = (PBYTE) ::HeapAlloc(GetProcessHeap(), 0, nHeapSize);if (pNewHeap){ZeroMemory(pNewHeap, nHeapSize);memcpy(pNewHeap, " 分配堆内存成功 ", sizeof(" 分配堆内存成功"));BOOL bRes = ::HeapFree(GetProcessHeap(), 0, pNewHeap);}}

我们再编译一个bin出来
还是有问题

3.27~~~~跳不过去
找到问题后发现

3.27~~~~
3.27~~~~
3.27~~~~

参数错误!!

改一下以后得到的bin

重点观察,内存在释放后,之前写入的内容,是否有变化

3.27~~~~3.27~~~~
malloc 会变成非0但非原始数据的内容
栈上的 不会改变
virtualAlloc释放后整个内存页都没了
VirtualAllocEx没有看到释放函数
globalAlloc释放后和malloc一样
另外就是virtualAllocEx尽管用的是允许系统自动分配
但是刚好分配在了上一个virtualAlloc申请的内存那里(当然数据已经全部置0了)
原因目前系统给当前进程的内存资源很充足
而且我们只是模拟小规模的申请操作,所以分配到一样的地址,很正常
正常程序,会有很多处内存申请的,不一定下一次还会拿到相同的地址

在这个代码中我没有写VirtualAllocFreeEx

总结一下问题:

  1. 代码问题
    strcat 是从\\x0开始拷贝内容的, 所以.cyy 打印会有乱码
  2. .目前系统的接口,在释放后,大多会对原始内存中的内容进行处理
  3. 但是,有些程序内部封装的内存释放接口,对原始内存内容,并没有进行处理,这样如果内存中的内容,涉及敏感地址,当释放后的地址,被再次使用时,会对之前的地址空间造成泄露

市面上的漏洞类型:UAF (use after free)
就是内存释放处理时,内存内容没有进行清零或者特殊处理,导致被重复使用,导致,最近一次保存的敏感地址被访问,导致问题

  1. 内存再次分配问题获得相同的内存块,如果是自定义的内存函数,就有可能把上次的内容,全部暴露
    防护意见:就是对使用过的内存块,进行清理。
    攻击侧:尝试寻找使用过对象句柄,看看有没有残留地址,构造UAF漏洞进行

系统函数已经自动把这个地方全部置0了,那不使用系统的函数如何申请内存呢?

有自建的内存管理函数,申请的时候,第一次会跟系统申请一大块内存,只不过自己的内存管理函数,内部再次细分,进行管理而已

假设:我搞了一个内存管理函数,一次申请了1MB内存,然后我内部函数申请,我就从这1MB 上再给你,而且,系统的内存回收算法,效力不一定使用所有场景

另一个问题,正常程序,为什么不推荐使用栈内存呢?

容易造成溢出
攻击者可以利用函数的溢出用rop拿到想要的地址

提问8086CPU(16位架构的)除了多了E成了32位,再用法上有什么区别呢?

默认用法: ESI 源内存地址 EDI 目的内存地址
EAX 主要用于函数返回值
ECX 一般是用存,循环的次数
ESP 主要是用于局部变量寻址
EBP 是函数外的变量寻址
EDX ,EBX 用法很多,没有固定的
注意观察寄存器,注意 寄存器–》[EXX] 或者 [EXX] <–寄存器,这种指令

拷贝内容的汇编代码定位

3.27~~~~
3.27到这儿