would be stupid to waste time all writing the same tools for ourselves right?
Code:
#include "stdafx.h"
#include <Windows.h>
#include <TlHelp32.h>
#include <psapi.h>
#include <iostream>
#include <string>
#include <vector>
bool strEndsWith(const std::wstring& s1, const std::wstring& s2)
{
if (s1.size() >= s2.size() && s1.substr(s1.size() - s2.size()) == s2)
return true;
else
return false;
}
DWORD GetProcessId(const wchar_t* name)
{
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
DWORD pid = 0;
PROCESSENTRY32 entry;
entry.dwSize = sizeof(PROCESSENTRY32);
if (Process32First(snapshot, &entry) == TRUE)
{
while (Process32Next(snapshot, &entry) == TRUE)
{
if (wcscmp(name, entry.szExeFile) == 0)
{
CloseHandle(snapshot);
return entry.th32ProcessID;
}
}
}
CloseHandle(snapshot);
return 0;
}
HMODULE GetProcessModuleHandle(HANDLE hProcess, const std::wstring& name)
{
std::vector<HMODULE> hMods(200);
DWORD cbNeeded = 0;
DWORD cb = hMods.size() * sizeof(HMODULE);
if (EnumProcessModules(hProcess, &hMods[0], cb, &cbNeeded))
{
if (cb < cbNeeded)
throw std::exception();
for (int i = 0; i < (cbNeeded / sizeof(HMODULE)); i++)
{
TCHAR szModName[MAX_PATH];
// Get the full path to the module's file.
if (GetModuleFileNameEx(hProcess, hMods[i], szModName, MAX_PATH))
{
std::wcout << L"found module : " << szModName << std::endl;
// Print the module name and handle value.
if (strEndsWith(szModName, name))
return hMods[i];
}
}
}
return NULL;
}
int main()
{
DWORD pid = GetProcessId(L"Wow.exe");
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
HMODULE hModule = GetProcessModuleHandle(hProcess, L"Wow.exe");
unsigned char* ptr = reinterpret_cast<unsigned char*>(hModule);
ptr += 0x1000;
std::vector<byte> buffer(0xC50387);
DWORD bytesRead = 0;
ReadProcessMemory(hProcess, ptr, &buffer[0], buffer.size(), &bytesRead);
HANDLE hFile = CreateFile(L"dump.bin", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
DWORD bytesWritten = 0;
WriteFile(hFile, &buffer[0], buffer.size(), &bytesWritten, NULL);
CloseHandle(hFile);
return 0;
}
c# require PeNet
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using PeNet;
namespace WowMemoryDump
{
class Program
{
static PeNet.Structures.IMAGE_SECTION_HEADER GetSectionHeader(PeFile file, string name)
{
foreach(var section in file.ImageSectionHeaders)
{
string section_name = Encoding.UTF8.GetString(section.Name).TrimEnd('\0'); ;
if (section_name == name)
{
return section;
}
}
throw new Exception("section not found");
}
static void Main(string[] args)
{
UInt64 oldBase = 0x00F60000;
PeFile peFile = new PeFile("C:\\Program Files (x86)\\World of Warcraft\\Wow.exe");
PeNet.Structures.IMAGE_SECTION_HEADER text_section = GetSectionHeader(peFile, ".text");
System.IO.FileStream text_dump_file = System.IO.File.OpenRead("dump.bin");
byte[] text_dump = new byte[text_dump_file.Length];
text_dump_file.Read(text_dump, 0, (int)text_dump_file.Length);
System.IO.BinaryReader reader = new System.IO.BinaryReader(new System.IO.MemoryStream(text_dump));
System.IO.BinaryWriter writer = new System.IO.BinaryWriter(new System.IO.MemoryStream(text_dump));
System.IO.StreamWriter log = new System.IO.StreamWriter("log.txt");
foreach (var block in peFile.ImageRelocationDirectory)
{
foreach(var offset in block.TypeOffsets)
{
UInt64 rva = offset.Offset + block.VirtualAddress;
log.WriteLine("relocation : 0x" + rva.ToString("X4"));
if (rva >= text_section.VirtualAddress && rva < text_section.VirtualAddress + text_section.VirtualSize)
{
switch(offset.Type)
{
case 3:
int file_ofs = (int)(rva - text_section.VirtualAddress);
reader.BaseStream.Seek(file_ofs, System.IO.SeekOrigin.Begin);
UInt32 oldOffset = reader.ReadUInt32();
writer.Seek(file_ofs, System.IO.SeekOrigin.Begin);
writer.Write((UInt32)(oldOffset - oldBase + peFile.ImageNtHeaders.OptionalHeader.ImageBase));
break;
case 0:
break;
default:
throw new Exception("wrong relocation offset type");
}
}
}
}
int text_size = Math.Min(text_dump.Length, (int)text_section.SizeOfRawData);
System.IO.FileStream wow_file = System.IO.File.OpenRead("C:\\Program Files (x86)\\World of Warcraft\\Wow.exe");
byte[] wow_data = new byte[wow_file.Length];
wow_file.Read(wow_data, 0, (int)wow_file.Length);
writer = new System.IO.BinaryWriter(new System.IO.MemoryStream(wow_data));
writer.Seek((int)text_section.PointerToRawData, System.IO.SeekOrigin.Begin);
writer.Write(text_dump);
System.IO.File.Open("C:\\Program Files (x86)\\World of Warcraft\\Wow_dumped.exe", System.IO.FileMode.CreateNew).Write(wow_data, 0, wow_data.Length);
}
}
}
thats fucking horrible code but i dont wanna waste time on that
edit: in fact... that wont work... aslr makes the base address being random. UInt64 oldBase = 0x00F60000 must be the same base address as used when dumping in the other program. So gotta update it