RWMemory.h
/********************************************************************************
-- Read Write Memory Tools
Copyright © 2011 Jesus7Freak
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************
File: RWMemory.h
Project: Read Write Memory Tools
Author: Jesus7Freak
Date: 10/29/2011
Version: 2.30
*********************************************************************************/
#pragma once
// Exclude rarely-used stuff from Windows headers
#define WIN32_LEAN_AND_MEAN
#define NOCOMM
#include <windows.h>
#include <Tlhelp32.h>
#include <vector>
//#if defined(_WIN64)
typedef unsigned __int64 QWORD;
//#endif
//call types for CallRemoteFunction:
#define __CDECL 0
#define __STDCALL 1
#define __FASTCALL 2
#define __THISCALL 3
#define __X64FASTCALL 4
#define HEXNUM_LENGTH ((sizeof(ULONG_PTR) * 2) + 1)
//saves space from type casting
#define TO_BYTES(type, byte_array, value) (*(type*)byte_array = (type)value)
namespace ReadWriteMemoryTools
{
static const int version = 230;
struct ADDRESS_SIG
{
BYTE pattern[25];
char mask[25];
char offset;
};
bool str_cmpA(char *str1, char *str2, int length = -1);
bool str_cmpW(wchar_t *str1, wchar_t *str2, int length = -1);
class RWMemory
{
private:
tagPROCESSENTRY32W* P;
HANDLE hProcess;
public:
int LastWin32Error;
RWMemory() { P = NULL; hProcess = NULL; LastWin32Error = 0; }
RWMemory(wchar_t* process_name, DWORD process_to_use = 0);
RWMemory(DWORD process_id);
RWMemory(tagPROCESSENTRY32W process);
~RWMemory();
static std::vector<tagPROCESSENTRY32> GetProcessesA();
static std::vector<tagPROCESSENTRY32W> GetProcessesW();
static std::vector<tagPROCESSENTRY32> GetProcessesByNameA(
char* process_name
);
static std::vector<tagPROCESSENTRY32W> GetProcessesByNameW(
wchar_t* process_name
);
static tagPROCESSENTRY32 GetProcessByID_A(DWORD process_ID);
static tagPROCESSENTRY32W GetProcessByID_W(DWORD process_ID);
HANDLE GetProcessHandle()
{ return hProcess; }
tagPROCESSENTRY32W GetProcessEntry()
{ return *P; }
std::vector<tagMODULEENTRY32> GetProcessModulesA();
std::vector<tagMODULEENTRY32W> GetProcessModulesW();
tagMODULEENTRY32 GetProcessModuleByNameA(char* module_name);
tagMODULEENTRY32W GetProcessModuleByNameW(wchar_t* module_name);
void ModuleSectionAddr_Size(
HMODULE hModule,
ULONG_PTR &Section_Address,
SIZE_T &Section_Size,
BYTE SectionName[IMAGE_SIZEOF_SHORT_NAME],
bool x64_module
);
LPVOID GetRemoteProcAddress(
HMODULE hModule,
LPCSTR lpProcName,
bool x64_module
);
ULONG_PTR FindMemPattern(
ULONG_PTR MemoryAddress,
SIZE_T Len,
BYTE *Pattern,
const char* Mask
);
ULONG_PTR FindMemPattern(
ULONG_PTR MemoryAddress,
SIZE_T Len,
ADDRESS_SIG addr_sig)
{
ULONG_PTR address = FindMemPattern(
MemoryAddress,
Len,
addr_sig.pattern,
addr_sig.mask);
//so that other non-zero checks will work
if (address) address += addr_sig.offset;
return address;
}
template <typename T> inline
T ReadMem(LPVOID MemoryAddress)
{
T buffer; SIZE_T BytesRead;
if (!::ReadProcessMemory(
hProcess,
MemoryAddress,
&buffer,
sizeof(T),
&BytesRead))
LastWin32Error = ::GetLastError();
return buffer;
}
template <typename T> inline
bool ReadMemArray(LPVOID MemoryAddress, LPVOID obj, SIZE_T read_length)
{
bool succeded = true; SIZE_T BytesRead;
if (!::ReadProcessMemory(
hProcess,
MemoryAddress,
obj,
sizeof(T) * read_length,
&BytesRead))
{
LastWin32Error = ::GetLastError();
succeded = false;
}
return succeded;
}
//use this will keep reading until it hits the null terminator
//use ReadMemArray to read a certain length
bool ReadMemString(LPVOID MemoryAddress, char str[]);
bool ReadMemString(LPVOID MemoryAddress, wchar_t str[]);
template <typename T> inline
bool WriteMem(LPVOID MemoryAddress, T obj)
{
bool succeeded = true; SIZE_T BytesWritten; T buffer = obj;
if (!::WriteProcessMemory(
hProcess,
MemoryAddress,
&buffer,
sizeof(T),
&BytesWritten))
{
LastWin32Error = ::GetLastError();
succeeded = false;
}
return succeeded;
}
template <typename T> inline
bool WriteMemArray(LPVOID MemoryAddress, LPVOID obj, SIZE_T write_length = 1)
{
bool succeeded = true; SIZE_T BytesWritten;
if (!::WriteProcessMemory(
hProcess,
MemoryAddress,
obj,
sizeof(T) * write_length,
&BytesWritten))
{
LastWin32Error = ::GetLastError();
succeeded = false;
}
return succeeded;
}
//for null terminated strings, use WriteMemArray if no null terminator
bool WriteMemString(LPVOID MemoryAddress, const char* str);
bool WriteMemString(LPVOID MemoryAddress, const wchar_t* str);
bool WriteMemJMP(
LPVOID JMPLocMemAddress,
LPVOID JMPToMemAddress,
BYTE size = 5
);
LPVOID AllocateMemory(SIZE_T size);
bool FreeMemory(LPVOID MemoryAddress);
//can call functions with multiple parameter, x86 and x64
//call types, based off of visual studio 2008 compiler
ULONG_PTR CallRemoteFunction(
LPTHREAD_START_ROUTINE lpStartAddress,
DWORD call_type,
ULONG_PTR *lpParameters = NULL,
DWORD num_of_params = 0
);
//x86 apps cant inject into x64, instead make it x64
//can return a 64-bit value
HMODULE InjectDLL(const void* DLLPath, bool bUnicode, bool is_x64_dll);
bool UnloadDLL(HMODULE hLibModule, bool is_x64_dll);
};
namespace CurrentProcess
{
ULONG_PTR FindMemPattern(
ULONG_PTR MemoryAddress,
SIZE_T Len,
BYTE *Pattern,
char* Mask
);
ULONG_PTR FindMemPattern(
ULONG_PTR MemoryAddress,
SIZE_T Len,
ADDRESS_SIG addr_sig);
LPVOID AllocateMemory(SIZE_T size);
bool FreeMemory(LPVOID MemoryAddress);
}
}
RWMemory.cpp
/********************************************************************************
-- Read Write Memory Tools
Copyright © 2011 Jesus7Freak
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************
File: RWMemory.cpp
Project: Read Write Memory Tools
Author: Jesus7Freak
Date: 10/29/2011
Version: 2.30
*********************************************************************************/
//uses both ASCII and UNICODE functions
#ifdef UNICODE
#undef UNICODE
#endif
#include "RWMemory.h"
namespace ReadWriteMemoryTools
{
bool str_cmpA(char *str1, char *str2, int length)
{
bool match = true;
if (length >= 0)
{
//specific length comparison
for (int i = 0; i < length; i++)
{
if (str1[i] != str2[i])
{
match = false;
break;
}
}
}
else
{
//compare until null terminator
int i = 0;
char _char1; char _char2;
do//compare the null terminator as well
{
_char1 = str1[i];
_char2 = str2[i];
if (_char1 != _char2)
{
match = false;
break;
}
i++;
}while(_char1 && _char2);
}
return match;
}
bool str_cmpW(wchar_t *str1, wchar_t *str2, int length)
{
bool match = true;
if (length >= 0)
{
//specific length comparison
for (int i = 0; i < length; i++)
{
if (str1[i] != str2[i])
{
match = false;
break;
}
}
}
else
{
//compare until null terminator
int i = 0;
wchar_t _wchar1; wchar_t _wchar2;
do//compare the null terminator as well
{
_wchar1 = str1[i];
_wchar2 = str2[i];
if (_wchar1 != _wchar2)
{
match = false;
break;
}
i++;
}while(_wchar1 && _wchar2);
}
return match;
}
#pragma region Constructors / Deconstructor
RWMemory::RWMemory(wchar_t* process_name, DWORD process_to_use)
{
P = NULL;
P = new tagPROCESSENTRY32W; LastWin32Error = 0;
std::vector<tagPROCESSENTRY32W> process =
GetProcessesByNameW(process_name);
//to prevent array out of bounds error when the process is killed
if (!process.empty())
*P = process[process_to_use];
hProcess = ::OpenProcess(
PROCESS_CREATE_THREAD |
PROCESS_QUERY_INFORMATION |
PROCESS_VM_OPERATION |
PROCESS_VM_WRITE |
PROCESS_VM_READ,
false,
P->th32ProcessID
);
if (!hProcess)
{
LastWin32Error = ::GetLastError();
//if this is spamming messageboxes, disable timer first
//then re-enable after messagebox returns
wchar_t Message[27 + HEXNUM_LENGTH] =
{
'O','p','e','n','P','r','o','c','e','s','s',':',' ',
'E','r','r','o','r',' ','C','o','d','e',':',' ','0','x'
};
::swprintf_s(&Message[27], HEXNUM_LENGTH, L"%lX", LastWin32Error);
::MessageBoxW(
NULL,
Message,
L"Error",
MB_OK | MB_ICONWARNING | MB_TASKMODAL
);
}
}
RWMemory::RWMemory(DWORD process_id)
{
P = NULL;
P = new tagPROCESSENTRY32W(GetProcessByID_W(process_id));
LastWin32Error = 0;
hProcess = ::OpenProcess(
PROCESS_CREATE_THREAD |
PROCESS_QUERY_INFORMATION |
PROCESS_VM_OPERATION |
PROCESS_VM_WRITE |
PROCESS_VM_READ,
false,
P->th32ProcessID
);
if (!hProcess)
{
LastWin32Error = ::GetLastError();
wchar_t Message[27 + HEXNUM_LENGTH] =
{
'O','p','e','n','P','r','o','c','e','s','s',':',' ',
'E','r','r','o','r',' ','C','o','d','e',':',' ','0','x'
};
::swprintf_s(&Message[27], HEXNUM_LENGTH, L"%lX", LastWin32Error);
::MessageBoxW(
NULL,
Message,
L"Error",
MB_OK | MB_ICONWARNING | MB_TASKMODAL
);
}
}
RWMemory::RWMemory(tagPROCESSENTRY32W process)
{
P = NULL;
P = new tagPROCESSENTRY32W(process);
LastWin32Error = 0;
hProcess = ::OpenProcess(
PROCESS_CREATE_THREAD |
PROCESS_QUERY_INFORMATION |
PROCESS_VM_OPERATION |
PROCESS_VM_WRITE |
PROCESS_VM_READ,
false,
P->th32ProcessID
);
if (!hProcess)
{
LastWin32Error = ::GetLastError();
wchar_t Message[27 + HEXNUM_LENGTH] =
{
'O','p','e','n','P','r','o','c','e','s','s',':',' ',
'E','r','r','o','r',' ','C','o','d','e',':',' ','0','x'
};
::swprintf_s(&Message[27], HEXNUM_LENGTH, L"%lX", LastWin32Error);
::MessageBoxW(
NULL,
Message,
L"Error",
MB_OK | MB_ICONWARNING | MB_TASKMODAL
);
}
}
RWMemory::~RWMemory()
{
if (P)
{
delete P;
P = NULL;
}
if (hProcess)
{
if (! ::CloseHandle(hProcess))
LastWin32Error = ::GetLastError();
hProcess = NULL;
}
}
#pragma endregion
std::vector<tagPROCESSENTRY32> RWMemory::GetProcessesA()
{
tagPROCESSENTRY32 pe32;
std::vector<tagPROCESSENTRY32> pe32_list;
//DWORD lpBinaryType = 0;
try
{
// Take a snapshot of all processes in the system.
HANDLE hProcessSnap =
::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hProcessSnap != INVALID_HANDLE_VALUE)
{
// Set the size of the structure before using it.
pe32.dwSize = sizeof(tagPROCESSENTRY32);
if (::Process32First(hProcessSnap, &pe32))
{
do
{
//::GetBinaryType(pe32.szExeFile, lpBinaryType);
//if (sizeof(ULONG_PTR) ==
pe32_list.push_back(pe32);
}
while (::Process32Next(hProcessSnap, &pe32));
}
}
::CloseHandle(hProcessSnap);
}
catch(...) {}
return pe32_list;
}
std::vector<PROCESSENTRY32W> RWMemory::GetProcessesW()
{
tagPROCESSENTRY32W pe32;
std::vector<tagPROCESSENTRY32W> pe32_list;
//DWORD lpBinaryType = 0;
try
{
// Take a snapshot of all processes in the system.
HANDLE hProcessSnap =
::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hProcessSnap != INVALID_HANDLE_VALUE)
{
// Set the size of the structure before using it.
pe32.dwSize = sizeof(tagPROCESSENTRY32W);
if (::Process32FirstW(hProcessSnap, &pe32))
{
do
{
//::GetBinaryType(pe32.szExeFile, lpBinaryType);
//if (sizeof(ULONG_PTR) ==
pe32_list.push_back(pe32);
}
while (::Process32NextW(hProcessSnap, &pe32));
}
}
::CloseHandle(hProcessSnap);
}
catch(...) {}
return pe32_list;
}
std::vector<tagPROCESSENTRY32> RWMemory::GetProcessesByNameA(
char* process_name)
{
std::vector<tagPROCESSENTRY32> pe32_list = GetProcessesA(), processes;
DWORD pe32_list_size = pe32_list.size();
for (DWORD pe32_i = 0; pe32_i < pe32_list_size; pe32_i++)
{
if (str_cmpA(process_name, pe32_list[pe32_i].szExeFile))
processes.push_back(pe32_list[pe32_i]);
}
return processes;
}
std::vector<tagPROCESSENTRY32W> RWMemory::GetProcessesByNameW(
wchar_t* process_name)
{
std::vector<tagPROCESSENTRY32W> pe32_list = GetProcessesW(), processes;
DWORD pe32_list_size = pe32_list.size();
for (DWORD pe32_i = 0; pe32_i < pe32_list_size; pe32_i++)
{
if (str_cmpW(process_name, pe32_list[pe32_i].szExeFile))
processes.push_back(pe32_list[pe32_i]);
}
return processes;
}
tagPROCESSENTRY32 RWMemory::GetProcessByID_A(DWORD process_ID)
{
std::vector<tagPROCESSENTRY32> pe32_list = GetProcessesA();
tagPROCESSENTRY32 process;
process.dwSize = 0;//test if this is still zero before using
DWORD pe32_list_size = pe32_list.size();
for (unsigned int pe32_i = 0; pe32_i < pe32_list_size; pe32_i++)
{
if (process_ID == pe32_list[pe32_i].th32ProcessID)
{
process = pe32_list[pe32_i];
break;
}
}
return process;
}
tagPROCESSENTRY32W RWMemory::GetProcessByID_W(DWORD process_ID)
{
std::vector<tagPROCESSENTRY32W> pe32_list = GetProcessesW();
tagPROCESSENTRY32W process;
process.dwSize = 0;//test if this is still zero before using
DWORD pe32_list_size = pe32_list.size();
for (unsigned int pe32_i = 0; pe32_i < pe32_list_size; pe32_i++)
{
if (process_ID == pe32_list[pe32_i].th32ProcessID)
{
process = pe32_list[pe32_i];
break;
}
}
return process;
}
std::vector<tagMODULEENTRY32> RWMemory::GetProcessModulesA()
{
tagMODULEENTRY32 me32;
std::vector<tagMODULEENTRY32> me32_list;
try
{
// Take a snapshot of all modules in the process.
HANDLE hModuleSnap = ::CreateToolhelp32Snapshot(
TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32,
P->th32ProcessID
);
if (hModuleSnap != INVALID_HANDLE_VALUE)
{
// Set the size of the structure before using it.
me32.dwSize = sizeof(tagMODULEENTRY32);
if (::Module32First(hModuleSnap, &me32))
{
do
{
me32_list.push_back(me32);
}
while (::Module32Next(hModuleSnap, &me32));
}
}
else
LastWin32Error = ::GetLastError();
if (!::CloseHandle(hModuleSnap))
LastWin32Error = ::GetLastError();
}
catch(...) {}
return me32_list;
}
std::vector<tagMODULEENTRY32W> RWMemory::GetProcessModulesW()
{
tagMODULEENTRY32W me32;
std::vector<tagMODULEENTRY32W> me32_list;
try
{
// Take a snapshot of all modules in the process.
HANDLE hModuleSnap = ::CreateToolhelp32Snapshot(
TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32,
P->th32ProcessID
);
if (hModuleSnap != INVALID_HANDLE_VALUE)
{
// Set the size of the structure before using it.
me32.dwSize = sizeof(tagMODULEENTRY32W);
if (::Module32FirstW(hModuleSnap, &me32))
{
do
{
me32_list.push_back(me32);
}
while (::Module32NextW(hModuleSnap, &me32));
}
}
else
LastWin32Error = ::GetLastError();
if (!::CloseHandle(hModuleSnap))
LastWin32Error = ::GetLastError();
}
catch(...) {}
return me32_list;
}
tagMODULEENTRY32 RWMemory::GetProcessModuleByNameA(
char* module_name)
{
std::vector<tagMODULEENTRY32> me32_list = GetProcessModulesA();
tagMODULEENTRY32 module;
module.dwSize = 0;//test if this is still zero before using
DWORD me32_list_size = me32_list.size();
for (unsigned int me32_i = 0; me32_i < me32_list_size; me32_i++)
{
if (str_cmpA(module_name, me32_list[me32_i].szModule))
{
module = me32_list[me32_i];
break;
}
}
return module;
}
tagMODULEENTRY32W RWMemory::GetProcessModuleByNameW(
wchar_t* module_name)
{
std::vector<tagMODULEENTRY32W> me32_list = GetProcessModulesW();
tagMODULEENTRY32W module;
module.dwSize = 0;//test if this is still zero before using
DWORD me32_list_size = me32_list.size();
for (unsigned int me32_i = 0; me32_i < me32_list_size; me32_i++)
{
if (str_cmpW(module_name, me32_list[me32_i].szModule))
{
module = me32_list[me32_i];
break;
}
}
return module;
}
void RWMemory::ModuleSectionAddr_Size(
HMODULE hModule,
ULONG_PTR &Section_Address,
SIZE_T &Section_Size,
BYTE SectionName[IMAGE_SIZEOF_SHORT_NAME],
bool x64_module)
{
//Offset to PE sig
DWORD PE_sig_offset = ReadMem<DWORD>((LPVOID)(
(ULONG_PTR)hModule + FIELD_OFFSET(IMAGE_DOS_HEADER, e_lfanew)));
WORD num_of_sections = ReadMem<WORD>((LPVOID)(
//offset to NumberOfSections
(ULONG_PTR)hModule + PE_sig_offset +
FIELD_OFFSET(IMAGE_NT_HEADERS32, FileHeader) +
FIELD_OFFSET(IMAGE_FILE_HEADER, NumberOfSections)));
//add the rest of the PE header size and base of module
ULONG_PTR sections = (ULONG_PTR)hModule + PE_sig_offset ;
if (x64_module)
sections += sizeof(IMAGE_NT_HEADERS64);
else
sections += sizeof(IMAGE_NT_HEADERS32);
for (int i = 0; i < num_of_sections; i++)
{
int sect_index = i * sizeof(IMAGE_SECTION_HEADER);
BYTE buffer[IMAGE_SIZEOF_SHORT_NAME] = {0};
ReadMemArray<BYTE>(
(LPVOID)(sections + sect_index),
buffer,
IMAGE_SIZEOF_SHORT_NAME);
if (str_cmpA((char*)SectionName,(char*)buffer, IMAGE_SIZEOF_SHORT_NAME))
{
Section_Address = (ULONG_PTR)hModule + ReadMem<DWORD>((LPVOID)(
sections + sect_index +
FIELD_OFFSET(IMAGE_SECTION_HEADER, VirtualAddress)));
Section_Size = ReadMem<DWORD>((LPVOID)(
sections + sect_index +
RTL_FIELD_SIZE(IMAGE_SECTION_HEADER, Name)));
break;
}
}
}
LPVOID RWMemory::GetRemoteProcAddress(HMODULE hModule, LPCSTR lpProcName, bool x64_module)
{
char func_name[64]; WORD func_index = 0; ULONG_PTR func_address = NULL;
/*using defined data structs method to get Export Table address offset
IMAGE_DOS_HEADER *IDH = (IMAGE_DOS_HEADER*)hModule;
IMAGE_NT_HEADERS *INH = (IMAGE_NT_HEADERS*)(hModule + IDH->e_lfanew);
IMAGE_EXPORT_DIRECTORY *IED = (IMAGE_EXPORT_DIRECTORY*)(
hModule + INH->OptionalHeader.DataDirectory[0].VirtualAddress);
*/
DWORD PE_sig_offset = ReadMem<DWORD>(//IMAGE_DOS_HEADER->e_lfanew
(LPVOID)((ULONG_PTR)hModule + FIELD_OFFSET(IMAGE_DOS_HEADER, e_lfanew))
);
//IMAGE_NT_HEADERS->OptionalHeader.DataDirectory[0].VirtualAddress
DWORD offset_to_ET = RTL_FIELD_SIZE(IMAGE_NT_HEADERS, Signature) +
RTL_FIELD_SIZE(IMAGE_NT_HEADERS, FileHeader);
if (x64_module)
offset_to_ET += FIELD_OFFSET(IMAGE_OPTIONAL_HEADER64, DataDirectory);
else
offset_to_ET += FIELD_OFFSET(IMAGE_OPTIONAL_HEADER32, DataDirectory);
DWORD Export_Table_offset = ReadMem<DWORD>(
(LPVOID)((ULONG_PTR)hModule + (ULONG_PTR)PE_sig_offset + offset_to_ET)
);
::IMAGE_EXPORT_DIRECTORY IED = ReadMem< ::IMAGE_EXPORT_DIRECTORY>(
(LPVOID)((ULONG_PTR)hModule + Export_Table_offset)
);
bool found = false;
if ((DWORD)lpProcName >> 16 != 0)
{
for (DWORD name_i = 0; name_i < IED.NumberOfNames && !found; name_i++)
{
DWORD str_offset = ReadMem<DWORD>(
(LPVOID)((ULONG_PTR)hModule + IED.AddressOfNames
+ (name_i * sizeof(DWORD)))
);
ReadMemString((LPVOID)((ULONG_PTR)hModule + str_offset), func_name);
if (str_cmpA((char*)lpProcName, (char*)func_name))
{
func_index = ReadMem<WORD>((LPVOID)((ULONG_PTR)hModule
+ IED.AddressOfNameOrdinals + (name_i * sizeof(WORD))));
found = true;
}
}
}
else
{
func_index = (WORD)(lpProcName - IED.Base);
found = true;
}
if (found)
func_address = (ULONG_PTR)hModule + ReadMem<DWORD>((LPVOID)(
(ULONG_PTR)hModule + IED.AddressOfFunctions
+ (func_index * sizeof(DWORD))));
return (LPVOID)func_address;
}
ULONG_PTR RWMemory::FindMemPattern(
ULONG_PTR MemoryAddress,
SIZE_T Len,
BYTE *Pattern,
const char* Mask)
{
ULONG_PTR PatterAddress = 0;
BYTE* buffer = new BYTE[Len]();
ReadMemArray<BYTE>((LPVOID)MemoryAddress, buffer, Len);
for(ULONG_PTR i = 0; i < Len && !PatterAddress; i++)
{
//while Mask[i2] isnt the null terminator
for(ULONG_PTR i2 = 0; Mask[i2]; i2++)
{
//make sure its not at the end of the mask before continuing
if (Mask[i2] == '?' && Mask[i2 + 1])
continue;
//if the bytes don't match exit loop
if (Mask[i2] == 'x' && buffer[i + i2] != Pattern[i2])
break;
//when it reaches the end, it must be the address we're looking for
if (!Mask[i2 + 1])
PatterAddress = MemoryAddress + i;
}
}
delete[] buffer;
return PatterAddress;
}
bool RWMemory::ReadMemString(LPVOID MemoryAddress, char str[])
{
bool succeded = true; SIZE_T BytesRead;
long i = 0;
do
{
if (!::ReadProcessMemory(
hProcess,
(LPVOID)((ULONG_PTR)MemoryAddress + (i * sizeof(char))),
&str[i],
sizeof(char),
&BytesRead))
{
LastWin32Error = ::GetLastError();
succeded = false;
}
}while(str[i++] != 0);
return succeded;
}
bool RWMemory::ReadMemString(LPVOID MemoryAddress, wchar_t str[])
{
bool succeded = true; SIZE_T BytesRead;
long i = 0;
do
{
if (!::ReadProcessMemory(
hProcess,
(LPVOID)((ULONG_PTR)MemoryAddress + (i * sizeof(wchar_t))),
&str[i], sizeof(wchar_t),
&BytesRead))
{
LastWin32Error = ::GetLastError();
succeded = false;
}
}while(str[i++] != 0);
return succeded;
}
bool RWMemory::WriteMemString(LPVOID MemoryAddress, const char* str)
{
bool succeeded = true; SIZE_T BytesWritten;
//c string length
int length = 0; do length++; while(str[length]);
if (!::WriteProcessMemory(
hProcess,
MemoryAddress,
(void*)str, length * sizeof(char),
&BytesWritten))
{
LastWin32Error = ::GetLastError();
succeeded = false;
}
return succeeded;
}
bool RWMemory::WriteMemString(LPVOID MemoryAddress, const wchar_t* str)
{
bool succeeded = true; SIZE_T BytesWritten;
//c string length
int length = 0; do length++; while(str[length]);
if (!::WriteProcessMemory(
hProcess,
MemoryAddress,
(void*)str, length * sizeof(wchar_t),
&BytesWritten))
{
LastWin32Error = ::GetLastError();
succeeded = false;
}
return succeeded;
}
bool RWMemory::WriteMemJMP(
LPVOID JMPLocMemAddress,
LPVOID JMPToMemAddress,
BYTE size)
{
bool succeeded = false;
BYTE* bytes = new BYTE[size]();
ULONG_PTR JMP_to_code = (ULONG_PTR)JMPToMemAddress
- ((ULONG_PTR)JMPLocMemAddress + 5);
bytes[0] = 0xE9;//JMP
TO_BYTES(UINT_PTR, &bytes[1], JMP_to_code);
for (BYTE i = 5; i < size; i++)
bytes[i] = 0x90;//NOP
if (WriteMemArray<BYTE>(JMPLocMemAddress, bytes, size))
succeeded = true;
delete[] bytes;
return succeeded;
}
LPVOID RWMemory::AllocateMemory(SIZE_T size)
{
LPVOID address_of_alloc = ::VirtualAllocEx(
hProcess,
NULL,
size,
MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE
);
if (!address_of_alloc)
LastWin32Error = ::GetLastError();
return address_of_alloc;
}
bool RWMemory::FreeMemory(LPVOID MemoryAddress)
{
bool succeded = false;
if (!::VirtualFreeEx(hProcess, MemoryAddress, NULL, MEM_RELEASE))
LastWin32Error = GetLastError();
else
succeded = true;
return succeded;
}
ULONG_PTR RWMemory::CallRemoteFunction(
LPTHREAD_START_ROUTINE lpStartAddress,
DWORD call_type,
ULONG_PTR *lpParameters,
DWORD num_of_params
)
{
int size; BYTE *asmfunc; ULONG_PTR asmfunc_loc;
//x86 calls
if (call_type != __X64FASTCALL)
{
size = 11 + (5 * num_of_params);
if (call_type == __CDECL)
size += 3;
asmfunc = new BYTE[size]();
//allocate memory for the calling function and a DWORD var
asmfunc_loc = (ULONG_PTR)AllocateMemory(size + sizeof(DWORD));
/* asmfunc x86 template
?68 xxxxxxxx //push xxxxxxxx parameters?
...
?BA xxxxxxxx //mov edx,xxxxxxxx fastcall param2
?B9 xxxxxxxx //mov ecx,xxxxxxxx fastcall param1 or thiscall ptr
E8 xxxxxxxx //call xxxxxxxx
?83 C4 xx //add esp,xx cdecl stack clean up
A3 xxxxxxxx //mov [xxxxxxxx],eax
C3 //ret
*/
int byte_loc = 0;
int pushed_params = num_of_params;
if (call_type == __FASTCALL)
pushed_params -= 2;
else if (call_type == __THISCALL)
pushed_params--;
//write the parameters in the function
for (int param_i = 0; param_i < pushed_params; param_i++)
{
asmfunc[byte_loc++] = 0x68; //push param@i
TO_BYTES(
DWORD,
&asmfunc[byte_loc],
lpParameters[num_of_params - 1 - param_i]);
byte_loc += sizeof(DWORD);
}
if (call_type == __FASTCALL && num_of_params > 1)
{
asmfunc[byte_loc++] = 0xBA; //mov edx,xxxxxxxx
TO_BYTES(DWORD, &asmfunc[byte_loc], lpParameters[1]);
byte_loc += sizeof(DWORD);
}
if (call_type == __FASTCALL && num_of_params > 0
|| call_type == __THISCALL)
{
asmfunc[byte_loc++] = 0xB9; //mov ecx,xxxxxxxx
TO_BYTES(DWORD, &asmfunc[byte_loc], lpParameters[0]);
byte_loc += sizeof(DWORD);
}
//calculate destination function offset
asmfunc[byte_loc++] = 0xE8; //call <function address>
TO_BYTES(
DWORD,
&asmfunc[byte_loc],
(DWORD)lpStartAddress - ((DWORD)asmfunc_loc + byte_loc + 4));
byte_loc += sizeof(DWORD);
if (call_type == __CDECL)
{
asmfunc[byte_loc++] = 0x83; //add esp,num_of_params * sizeof(DWORD)
asmfunc[byte_loc++] = 0xC4;
asmfunc[byte_loc++] = (BYTE)(num_of_params * sizeof(DWORD));
}
//store the return val at the end the the func
//could also use 0x89 0x05 ?
asmfunc[byte_loc++] = 0xA3; //mov [ret_val_address],eax
TO_BYTES(DWORD, &asmfunc[byte_loc], (DWORD)asmfunc_loc + size);
byte_loc += sizeof(DWORD);
asmfunc[byte_loc++] = 0xC3; //ret
}
//x64 call
else
{
size = 22 + sizeof(ULONG_PTR);
for (DWORD i = 0; i < num_of_params; i++)
{
if (i < 4)
size += 10;
else
size += 15;
}
asmfunc = new BYTE[size]();
//allocate memory for the calling function and a QWORD var
asmfunc_loc = (ULONG_PTR)AllocateMemory(size + sizeof(QWORD));
/* asmfunc x64 template
48 83 EC xx //sub rsp,xx
...
48 B8 xxxxxxxxxxxxxxxx //mov rax,xxxxxxxxxxxxxxxx
48 89 44 24 xx //mov [rsp+xx],rax
49 B9 xxxxxxxxxxxxxxxx //mov r9,xxxxxxxxxxxxxxxx
49 B8 xxxxxxxxxxxxxxxx //mov r8,xxxxxxxxxxxxxxxx
48 BA xxxxxxxxxxxxxxxx //mov rdx,xxxxxxxxxxxxxxxx
48 89 xxxxxxxxxxxxxxxx //mov rcx,xxxxxxxxxxxxxxxx
FF 15 xxxxxxxx //call qword ptr [xxxxxxxx]
48 89 05 xxxxxxxx //mov [xxxxxxxx],rax
48 83 C4 xx //add rsp,xx
C3 //ret
*/
int byte_loc = 0;
BYTE stack_alloc_size = 0;
//8(the return address) + 32(reserved space for 4 arguments)
if (num_of_params > 4)
stack_alloc_size += ((BYTE)num_of_params - 4) * 8;
stack_alloc_size += 8 + 32;
//stack pointer RSP must be aligned on a 16-byte boundary
//before a next function call.
stack_alloc_size += stack_alloc_size % 16;
asmfunc[byte_loc++] = 0x48; //sub rsp,xx
asmfunc[byte_loc++] = 0x83;
asmfunc[byte_loc++] = 0xEC;
asmfunc[byte_loc++] = stack_alloc_size;
//write the parameters in the function
for (int i = 0; num_of_params - i > 4; i++)
{
asmfunc[byte_loc++] = 0x48; ////mov rax,xxxxxxxxxxxxxxxx
asmfunc[byte_loc++] = 0xB8;
TO_BYTES(QWORD, &asmfunc[byte_loc], lpParameters[num_of_params - 1 - i]);
byte_loc += sizeof(QWORD);
asmfunc[byte_loc++] = 0x48;
asmfunc[byte_loc++] = 0x89;
asmfunc[byte_loc++] = 0x44;
asmfunc[byte_loc++] = 0x24;
asmfunc[byte_loc++] = (BYTE)(((num_of_params - 1) * sizeof(QWORD)) -
(i * sizeof(QWORD)));
}
if (num_of_params >= 4)
{
asmfunc[byte_loc++] = 0x49; //mov r9,param4
asmfunc[byte_loc++] = 0xB9;
TO_BYTES(QWORD, &asmfunc[byte_loc], lpParameters[3]);
byte_loc += sizeof(QWORD);
}
if (num_of_params >= 3)
{
asmfunc[byte_loc++] = 0x49; //mov r8,param3
asmfunc[byte_loc++] = 0xB8;
TO_BYTES(QWORD, &asmfunc[byte_loc], lpParameters[2]);
byte_loc += sizeof(QWORD);
}
if (num_of_params >= 2)
{
asmfunc[byte_loc++] = 0x48; //mov rdx,param2
asmfunc[byte_loc++] = 0xBA;
TO_BYTES(QWORD, &asmfunc[byte_loc], lpParameters[1]);
byte_loc += sizeof(QWORD);
}
if (num_of_params >= 1)
{
asmfunc[byte_loc++] = 0x48; //mov rcx,param1
asmfunc[byte_loc++] = 0xB9;
TO_BYTES(QWORD, &asmfunc[byte_loc], lpParameters[0]);
byte_loc += sizeof(QWORD);
}
//calculate destination function offset
asmfunc[byte_loc++] = 0xFF; //call qword ptr [xxxxxxxx]
asmfunc[byte_loc++] = 0x15;
asmfunc[byte_loc++] = 0x0C;
byte_loc += 3;
//next 3 are already zero
//store the return val at the end the the func
asmfunc[byte_loc++] = 0x48; //mov [ret_val_address],rax
asmfunc[byte_loc++] = 0x89;
asmfunc[byte_loc++] = 0x05;
asmfunc[byte_loc++] = 0x0D;
byte_loc += 3;
//next 3 are already zero
asmfunc[byte_loc++] = 0x48; //add rsp,xx
asmfunc[byte_loc++] = 0x83;
asmfunc[byte_loc++] = 0xC4;
asmfunc[byte_loc++] = stack_alloc_size;
asmfunc[byte_loc++] = 0xC3; //ret
TO_BYTES(QWORD, &asmfunc[byte_loc], lpStartAddress);
}
//write the calling function to allocated space
WriteMemArray<BYTE>((LPVOID)asmfunc_loc, asmfunc, size);
//call the injected function
HANDLE NewThreadhnd = ::CreateRemoteThread(
hProcess,
NULL,
0,
(LPTHREAD_START_ROUTINE)asmfunc_loc,
NULL,
0,
NULL
);
if (NewThreadhnd)
{
::WaitForSingleObject(NewThreadhnd, 1000);
::CloseHandle(NewThreadhnd);
}
else
LastWin32Error = ::GetLastError();
//get the return val
ULONG_PTR return_val = ReadMem<ULONG_PTR>((LPVOID)(asmfunc_loc + size));
//DWORD pointer return, doesn't work with x64 values
//::GetExitCodeThread(NewThreadhnd, &return_val);
//free allocated memory for the calling function and a UINT_PTR var
FreeMemory((LPVOID)asmfunc_loc);
delete[] asmfunc;
return return_val;
}
//code help from http://www.codeproject.com/KB/threads/winspy.aspx
HMODULE RWMemory::InjectDLL(const void* DLLPath, bool bUnicode, bool is_x64_dll)
{
HMODULE hLibModule = NULL;
int type_size, length = 0;
char *tLoadLibrary;
if (!bUnicode)
{
type_size = sizeof(char);
//c string length
char *DLLPathA = (char*)DLLPath;
do length++; while(DLLPathA[length]);
tLoadLibrary = "LoadLibraryA";
}
else
{
type_size = sizeof(wchar_t);
//c string length
wchar_t *DLLPathW = (wchar_t*)DLLPath;
do length++; while(DLLPathW[length]);
tLoadLibrary = "LoadLibraryW";
}
tagMODULEENTRY32 hKernel32 = GetProcessModuleByNameA("kernel32.dll");
if (hKernel32.dwSize)
{
LPTHREAD_START_ROUTINE LoadLibrary_address =
(LPTHREAD_START_ROUTINE)GetRemoteProcAddress(
hKernel32.hModule,
tLoadLibrary,
is_x64_dll
);
if (LoadLibrary_address)
{
//Allocate then write DLLPath to memory
int mem_size = type_size * length;
LPVOID pLibRemote = AllocateMemory(mem_size);
SIZE_T BytesWritten;
if (!::WriteProcessMemory(
hProcess,
pLibRemote,
DLLPath,
mem_size,
&BytesWritten)
)
LastWin32Error = ::GetLastError();
DWORD call_type;
if (is_x64_dll)
call_type = __X64FASTCALL;
else
call_type = __STDCALL;
//Load DLL into remote process, return base of loaded module
ULONG_PTR parameters[] = { (ULONG_PTR)pLibRemote };
hLibModule = (HMODULE)CallRemoteFunction(
LoadLibrary_address,
call_type,
parameters,
1
);
FreeMemory(pLibRemote);
}
}
return hLibModule;
}
/*concept based off of Joachim Bauch's MemoryModule
HMODULE RWMemory::InjectMemoryModule(const LPVOID DLLData)
{
PIMAGE_DOS_HEADER dos_header;
PIMAGE_NT_HEADERS nt_header;
BYTE *code, *headers;
SIZE_T locationDelta;
DllEntryProc DllEntry;
BOOL successfull;
still working on...
return hLibModule;
}*/
bool RWMemory::UnloadDLL(HMODULE hLibModule, bool is_x64_dll)
{
bool succeded = false;
tagMODULEENTRY32 hKernel32 = GetProcessModuleByNameA("kernel32.dll");
LPTHREAD_START_ROUTINE FreeLibrary_address =
(LPTHREAD_START_ROUTINE)GetRemoteProcAddress(
hKernel32.hModule,
"FreeLibrary",
is_x64_dll
);
DWORD call_type;
if (is_x64_dll)
call_type = __X64FASTCALL;
else
call_type = __STDCALL;
//Unload DLL from remote process
ULONG_PTR parameters[] = { (ULONG_PTR)hLibModule };
succeded = CallRemoteFunction(
FreeLibrary_address,
call_type,
parameters,
1
) != 0;
return succeded;
}
namespace CurrentProcess
{
ULONG_PTR FindMemPattern(
ULONG_PTR MemoryAddress,
SIZE_T Len,
BYTE *Pattern,
char* Mask)
{
ULONG_PTR PatterAddress = 0;
BYTE* data = (BYTE*)MemoryAddress;
for(ULONG_PTR i = 0; i < Len && !PatterAddress; i++)
{
//while Mask[i2] isnt the null terminator
for(ULONG_PTR i2 = 0; Mask[i2]; i2++)
{
//make sure its not at the end of the mask before continuing
if (Mask[i2] == '?' && Mask[i2 + 1])
continue;
//if the bytes don't match exit loop
if (Mask[i2] == 'x' && data[i + i2] != Pattern[i2])
break;
//if it reaches the end, it must be the address your looking for
if (!Mask[i2 + 1])
PatterAddress = MemoryAddress + i;
}
}
return PatterAddress;
}
ULONG_PTR FindMemPattern(
ULONG_PTR MemoryAddress,
SIZE_T Len,
ADDRESS_SIG addr_sig)
{
return FindMemPattern(
MemoryAddress,
Len,
addr_sig.pattern,
addr_sig.mask) + addr_sig.offset;
}
LPVOID AllocateMemory(SIZE_T size)
{
int LastWin32Error = 0;
LPVOID address_of_alloc = ::VirtualAlloc(NULL, size,
MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!address_of_alloc)
LastWin32Error = ::GetLastError();
return address_of_alloc;
}
bool FreeMemory(LPVOID MemoryAddress)
{
int LastWin32Error = 0;
bool succeded = false;
if (!::VirtualFree(MemoryAddress, NULL, MEM_RELEASE))
LastWin32Error = GetLastError();
else
succeded = true;
return succeded;
}
}
}