//有漏洞 并且开启了随机基址的程序 溢出点VerifyPassword返回地址
#include<windows.h>
#include<tchar.h>
#include <iostream>
#define PASSWORD "1234"
void* VerifyPassword(byte* pRet, void* pszPassword, int nSize) {
char szBuffer[50] = { 0 };
*pRet = strcmp(PASSWORD, (char*)pszPassword);
return memcpy(szBuffer, pszPassword, nSize); //通过拷贝溢出
}
int _tmain(int argc, _TCHAR* argv[]) {
void* pszPassword = NULL;
int nFileSize = 0;
byte bFlag = FALSE;
FILE* fp;
LoadLibraryA("user32.dll");
if (fopen_s(&fp, "password.txt", "rb")) {
MessageBoxA(NULL, "打开文件失败", "error", NULL);
return 0;
}
fseek(fp, 0, SEEK_END);
nFileSize = ftell(fp);
rewind(fp);
pszPassword = ZeroMemory(malloc(nFileSize), nFileSize);
fread(pszPassword, nFileSize, 1, fp);
VerifyPassword(&bFlag, pszPassword, nFileSize);
if (bFlag) printf("密码错误\n");
else printf("密码正确\n");
fclose(fp);
system("pause");
return 0;
}
此次绕过随机基址的方法是覆盖RVA 首先看基址为FE0000 在函数返回前 看返回地址基址是可以变化的 但是他的RVA是无法改变的 119e 所以我们只要覆盖两个字节的rva就达到了执行我们代码的目的
看上图的eax寄存器 就是我们memcpy的返回值 也就是拷贝缓冲区的首地址 我们只要精心构造文件 让他刚好覆盖RVA那两个字节的同时 最后拼接好的地址里的指令是call eax或jmp eax,push eax ret这样的指令 也就达到了执行shellcode的条件
由于我重新运行了程序 所以基址到00EE0000了 必须在本模块查找我们需要的指令 FFE0(jmp eax)
找到指令 rva为1122
构造文件用1122替换函数返回地址的rva
再次走到函数返回的地方 会返回到我们填写的地址去执行
eax就是缓冲区首地址
于是就成功的跑到我们预想的位置执行代码了