mirror of
https://github.com/Adamcake/Bolt.git
synced 2026-05-18 22:24:28 -04:00
library: inject plugin lib and luajit from stub
This commit is contained in:
@@ -14,31 +14,41 @@ if (WIN32)
|
||||
set(BOLT_STUB_ENTRYNAME entry)
|
||||
set(BOLT_STUB_ENTRYORDINAL 1)
|
||||
file(GENERATE OUTPUT stub.def CONTENT "LIBRARY STUB\nEXPORTS\n${BOLT_STUB_ENTRYNAME} @${BOLT_STUB_ENTRYORDINAL}\n")
|
||||
add_library(stub SHARED dll/stub.c "${CMAKE_CURRENT_BINARY_DIR}/stub.def")
|
||||
file(GENERATE OUTPUT plugin.def CONTENT "LIBRARY BOLT-PLUGIN\nEXPORTS\n${BOLT_STUB_ENTRYNAME} @${BOLT_STUB_ENTRYORDINAL}\n")
|
||||
|
||||
add_library(${BOLT_PLUGIN_LIB_NAME} SHARED dll/main.c plugin/plugin.c gl.c
|
||||
rwlock/rwlock_win32.c ipc_win32.c plugin/plugin_win32.c ../../modules/hashmap/hashmap.c
|
||||
../miniz/miniz.c ../../modules/spng/spng/spng.c "${CMAKE_CURRENT_BINARY_DIR}/plugin.def")
|
||||
target_compile_definitions(${BOLT_PLUGIN_LIB_NAME} PUBLIC BOLT_STUB_ENTRYNAME=${BOLT_STUB_ENTRYNAME})
|
||||
target_link_libraries(${BOLT_PLUGIN_LIB_NAME} PUBLIC "${BOLT_LUAJIT_DIR}/lua51.lib")
|
||||
target_include_directories(${BOLT_PLUGIN_LIB_NAME} PUBLIC "${BOLT_LUAJIT_DIR}" "${BOLT_ZLIB_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/../miniz")
|
||||
|
||||
add_executable(dll_inject_generator dll/dll_inject_generator.cxx)
|
||||
target_compile_definitions(dll_inject_generator PUBLIC BOLT_STUB_ENTRYORDINAL=${BOLT_STUB_ENTRYORDINAL})
|
||||
set_target_properties(dll_inject_generator PROPERTIES CXX_STANDARD 20 CXX_EXTENSIONS OFF)
|
||||
add_custom_command(
|
||||
OUTPUT dll_inject_cmake_gen.c
|
||||
DEPENDS ${BOLT_PLUGIN_LIB_NAME} dll_inject_generator
|
||||
COMMAND dll_inject_generator $<TARGET_FILE:${BOLT_PLUGIN_LIB_NAME}> "${BOLT_LUAJIT_DIR}/lua51.dll" "${CMAKE_CURRENT_SOURCE_DIR}/dll/dll_inject.h" ">dll_inject_cmake_gen.c"
|
||||
)
|
||||
|
||||
add_library(stub SHARED dll/stub.c dll_inject_cmake_gen.c "${CMAKE_CURRENT_BINARY_DIR}/stub.def")
|
||||
target_compile_definitions(stub PUBLIC BOLT_STUB_ENTRYNAME=${BOLT_STUB_ENTRYNAME})
|
||||
add_executable(stub_inject_generator dll/stub_inject_generator.cxx)
|
||||
target_compile_definitions(stub_inject_generator PUBLIC BOLT_STUB_ENTRYORDINAL=${BOLT_STUB_ENTRYORDINAL})
|
||||
set_target_properties(stub_inject_generator PROPERTIES CXX_STANDARD 20 CXX_EXTENSIONS OFF)
|
||||
add_custom_command(
|
||||
OUTPUT stub_inject_cmake_gen.cxx
|
||||
DEPENDS stub stub_inject_generator
|
||||
COMMAND stub_inject_generator $<TARGET_FILE:stub> "${CMAKE_CURRENT_SOURCE_DIR}/dll/stub_inject.hxx" ">stub_inject_cmake_gen.cxx"
|
||||
COMMAND stub_inject_generator $<TARGET_FILE:stub> "${CMAKE_CURRENT_SOURCE_DIR}/dll/stub_inject.h" ">stub_inject_cmake_gen.cxx"
|
||||
)
|
||||
add_custom_target(BOLT_STUB_INJECT_DEPENDENCY DEPENDS stub_inject_cmake_gen.cxx)
|
||||
set(BOLT_STUB_INJECT_CXX "${CMAKE_CURRENT_BINARY_DIR}/stub_inject_cmake_gen.cxx" PARENT_SCOPE)
|
||||
|
||||
add_library(${BOLT_PLUGIN_LIB_NAME} SHARED dll/main.c plugin/plugin.c gl.c
|
||||
rwlock/rwlock_win32.c ipc_win32.c plugin/plugin_win32.c ../../modules/hashmap/hashmap.c
|
||||
../miniz/miniz.c ../../modules/spng/spng/spng.c)
|
||||
target_link_libraries(${BOLT_PLUGIN_LIB_NAME} PUBLIC "${BOLT_LUAJIT_DIR}/lua51.lib")
|
||||
target_include_directories(${BOLT_PLUGIN_LIB_NAME} PUBLIC "${BOLT_LUAJIT_DIR}" "${BOLT_ZLIB_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/../miniz")
|
||||
install(TARGETS ${BOLT_PLUGIN_LIB_NAME} DESTINATION "${BOLT_CEF_INSTALLDIR}/bolt-launcher")
|
||||
install(FILES "${BOLT_LUAJIT_DIR}/lua51.dll" DESTINATION "${BOLT_CEF_INSTALLDIR}/bolt-launcher")
|
||||
|
||||
if(MSVC)
|
||||
set_property(TARGET stub PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
|
||||
set_property(TARGET stub_inject_generator PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
|
||||
set_property(TARGET ${BOLT_PLUGIN_LIB_NAME} PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
|
||||
set_property(TARGET stub PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
|
||||
set_property(TARGET dll_inject_generator PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
|
||||
set_property(TARGET stub_inject_generator PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
|
||||
else()
|
||||
target_compile_options(stub_inject_generator PUBLIC ${BOLT_WINDOWS_NONMSVC_OPTIONS})
|
||||
target_link_options(stub_inject_generator PUBLIC ${BOLT_WINDOWS_NONMSVC_LINKOPTIONS})
|
||||
|
||||
9
src/library/dll/dll_inject.h
Normal file
9
src/library/dll/dll_inject.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#include <Windows.h>
|
||||
|
||||
struct PluginInjectParams {
|
||||
HMODULE kernel32;
|
||||
HMODULE(__stdcall* pGetModuleHandleW)(LPCWSTR);
|
||||
FARPROC(__stdcall* pGetProcAddress)(HMODULE, LPCSTR);
|
||||
};
|
||||
|
||||
void InjectPluginDll(HANDLE process, HMODULE kernel32, HMODULE(__stdcall* pGetModuleHandleW)(LPCWSTR), FARPROC(__stdcall* pGetProcAddress)(HMODULE, LPCSTR));
|
||||
224
src/library/dll/dll_inject_generator.cxx
Normal file
224
src/library/dll/dll_inject_generator.cxx
Normal file
@@ -0,0 +1,224 @@
|
||||
#include "stub_inject.h"
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
DWORD perms_for_characteristics(DWORD characteristics) {
|
||||
const bool readp = (characteristics & IMAGE_SCN_MEM_READ);
|
||||
const bool writep = (characteristics & IMAGE_SCN_MEM_WRITE);
|
||||
const bool execp = (characteristics & IMAGE_SCN_MEM_EXECUTE);
|
||||
return
|
||||
readp ?
|
||||
writep ?
|
||||
execp ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE
|
||||
:
|
||||
execp ? PAGE_EXECUTE_READ : PAGE_READONLY
|
||||
:
|
||||
writep ?
|
||||
execp ? PAGE_EXECUTE_WRITECOPY : PAGE_WRITECOPY
|
||||
:
|
||||
execp ? PAGE_EXECUTE : PAGE_NOACCESS;
|
||||
}
|
||||
|
||||
/// This program is run by the build system on Windows. It manually maps the plugin DLL, then outputs some C code which
|
||||
/// writes that DLL into a target process, invokes the payload on a remote thread, and blocks until that thread returns.
|
||||
/// The function generated by this code will be called by the stub DLL during a CreateProcessW hook.
|
||||
int wmain(int argc, const wchar_t **argv) {
|
||||
if (argc != 4) {
|
||||
std::cerr << "dll_inject_generator must be called with exactly three arguments: the absolute path to the "
|
||||
"plugin dll, the absolute path to lua51.dll, and the absolute path to dll_inject.h." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
HANDLE plugin_file = CreateFileW(argv[1], GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
if (plugin_file == INVALID_HANDLE_VALUE) {
|
||||
std::cerr << "dll_inject_generator could not open the dll file: ";
|
||||
std::wcerr << argv[1];
|
||||
std::cerr << std::endl;
|
||||
return 1;
|
||||
}
|
||||
DWORD plugin_file_size = GetFileSize(plugin_file, NULL);
|
||||
PVOID plugin_dll = VirtualAlloc(NULL, plugin_file_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
||||
if (!ReadFile(plugin_file, plugin_dll, plugin_file_size, nullptr, nullptr)) {
|
||||
std::cerr << "dll_inject_generator could not read the dll file: " << GetLastError() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
HANDLE luajit_file = CreateFileW(argv[2], GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
if (luajit_file == INVALID_HANDLE_VALUE) {
|
||||
std::cerr << "dll_inject_generator could not open the lua dll file: ";
|
||||
std::wcerr << argv[2];
|
||||
std::cerr << std::endl;
|
||||
return 1;
|
||||
}
|
||||
DWORD luajit_file_size = GetFileSize(luajit_file, NULL);
|
||||
PVOID luajit_dll = VirtualAlloc(NULL, luajit_file_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
||||
if (!ReadFile(luajit_file, luajit_dll, luajit_file_size, nullptr, nullptr)) {
|
||||
std::cerr << "dll_inject_generator could not read the lua dll file: " << GetLastError() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
PIMAGE_DOS_HEADER plugin_dos_header = (PIMAGE_DOS_HEADER)plugin_dll;
|
||||
PIMAGE_NT_HEADERS plugin_nt_headers = (PIMAGE_NT_HEADERS)((LPBYTE)plugin_dll + plugin_dos_header->e_lfanew);
|
||||
PIMAGE_SECTION_HEADER plugin_section_header = (PIMAGE_SECTION_HEADER)(plugin_nt_headers + 1);
|
||||
PIMAGE_DOS_HEADER luajit_dos_header = (PIMAGE_DOS_HEADER)luajit_dll;
|
||||
PIMAGE_NT_HEADERS luajit_nt_headers = (PIMAGE_NT_HEADERS)((LPBYTE)luajit_dll + luajit_dos_header->e_lfanew);
|
||||
PIMAGE_SECTION_HEADER luajit_section_header = (PIMAGE_SECTION_HEADER)(luajit_nt_headers + 1);
|
||||
|
||||
// find a function in the export table with ordinal value 1, so we can hard-code its RVA.
|
||||
// this assumes the whole export table of plugin.dll is in one section.
|
||||
DWORD entry_point_rva = 0;
|
||||
IMAGE_DATA_DIRECTORY plugin_export_virtual_details = plugin_nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
|
||||
for (size_t i = 0; i < plugin_nt_headers->FileHeader.NumberOfSections; i += 1) {
|
||||
if (plugin_section_header[i].VirtualAddress > plugin_export_virtual_details.VirtualAddress) continue;
|
||||
if (plugin_section_header[i].VirtualAddress + plugin_section_header[i].Misc.VirtualSize <= plugin_export_virtual_details.VirtualAddress) continue;
|
||||
const DWORD export_section_offset = plugin_section_header[i].PointerToRawData - plugin_section_header[i].VirtualAddress;
|
||||
PIMAGE_EXPORT_DIRECTORY plugin_exports = (PIMAGE_EXPORT_DIRECTORY)((LPBYTE)plugin_dll + (plugin_export_virtual_details.VirtualAddress + export_section_offset));
|
||||
PDWORD export_address_list = (PDWORD)((LPBYTE)plugin_dll + (plugin_exports->AddressOfFunctions + export_section_offset));
|
||||
entry_point_rva = export_address_list[BOLT_STUB_ENTRYORDINAL - plugin_exports->Base];
|
||||
break;
|
||||
}
|
||||
if (!entry_point_rva) {
|
||||
std::cerr << "dll_inject_generator could not locate entry point" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// output file header and #include lines
|
||||
std::cout << "// This file was created programmatically by Bolt's build system. Don't change this file - change the code that generated it." << std::endl;
|
||||
std::cout << "#include <Windows.h>" << std::endl << "#include <stdint.h>" << std::endl << "#include \"";
|
||||
std::wcout << argv[3];
|
||||
std::cout << "\"" << std::endl;
|
||||
// embed dll headers
|
||||
std::cout << "static const uint8_t plugin_dll_headers[] = {";
|
||||
for (size_t i = 0; i < plugin_nt_headers->OptionalHeader.SizeOfHeaders; i += 1) {
|
||||
if (i != 0) std::cout << ",";
|
||||
std::cout << (WORD)((LPBYTE)plugin_dll)[i];
|
||||
}
|
||||
std::cout << "};" << std::endl;
|
||||
std::cout << "static const uint8_t luajit_dll_headers[] = {";
|
||||
for (size_t i = 0; i < luajit_nt_headers->OptionalHeader.SizeOfHeaders; i += 1) {
|
||||
if (i != 0) std::cout << ",";
|
||||
std::cout << (WORD)((LPBYTE)luajit_dll)[i];
|
||||
}
|
||||
std::cout << "};" << std::endl;
|
||||
// embed dll sections
|
||||
for (size_t i = 0; i < plugin_nt_headers->FileHeader.NumberOfSections; i += 1) {
|
||||
std::cout << "static const uint8_t psect" << i << "[] = {";
|
||||
LPBYTE section_start = (LPBYTE)plugin_dll + plugin_section_header[i].PointerToRawData;
|
||||
for (size_t j = 0; j < plugin_section_header[i].SizeOfRawData; j += 1) {
|
||||
if (j != 0) std::cout << ",";
|
||||
std::cout << (WORD)section_start[j];
|
||||
}
|
||||
std::cout << "};" << std::endl;
|
||||
}
|
||||
for (size_t i = 0; i < luajit_nt_headers->FileHeader.NumberOfSections; i += 1) {
|
||||
std::cout << "static const uint8_t luasect" << i << "[] = {";
|
||||
LPBYTE section_start = (LPBYTE)luajit_dll + luajit_section_header[i].PointerToRawData;
|
||||
for (size_t j = 0; j < luajit_section_header[i].SizeOfRawData; j += 1) {
|
||||
if (j != 0) std::cout << ",";
|
||||
std::cout << (WORD)section_start[j];
|
||||
}
|
||||
std::cout << "};" << std::endl;
|
||||
}
|
||||
// embed the amount of zeroes we'll need (WriteProcessMemory needs actual memory to copy from)
|
||||
std::cout << "static const uint8_t zeroes["
|
||||
<< max(plugin_nt_headers->OptionalHeader.SizeOfHeaders, luajit_nt_headers->OptionalHeader.SizeOfHeaders)
|
||||
<< "] = {0};" << std::endl;
|
||||
|
||||
std::cout << "void InjectPluginDll(HANDLE process, HMODULE kernel32, HMODULE(__stdcall* pGetModuleHandleW)(LPCWSTR), FARPROC(__stdcall* pGetProcAddress)(HMODULE, LPCSTR)) {" << std::endl;
|
||||
// we can't call imported functions at this point, so lookup the ones we need from kernel32
|
||||
#define DEFLOOKUP(RET, FN, ARGS) #RET "(__stdcall* p" #FN ")" ARGS "=(" #RET "(__stdcall*)" ARGS ")pGetProcAddress(kernel32, \"" #FN "\");"
|
||||
std::cout <<
|
||||
DEFLOOKUP(LPVOID, VirtualAllocEx, "(HANDLE, LPVOID, SIZE_T, DWORD, DWORD)")
|
||||
DEFLOOKUP(BOOL, VirtualFreeEx, "(HANDLE, LPVOID, SIZE_T, DWORD)")
|
||||
DEFLOOKUP(BOOL, WriteProcessMemory, "(HANDLE, LPVOID, LPCVOID, SIZE_T, SIZE_T*)")
|
||||
DEFLOOKUP(BOOL, ReadProcessMemory, "(HANDLE, LPCVOID, LPVOID, SIZE_T, SIZE_T*)")
|
||||
DEFLOOKUP(BOOL, VirtualProtectEx, "(HANDLE, LPVOID, SIZE_T, DWORD, PDWORD)")
|
||||
DEFLOOKUP(HANDLE, CreateRemoteThread, "(HANDLE, LPSECURITY_ATTRIBUTES, SIZE_T, LPTHREAD_START_ROUTINE, LPVOID, DWORD, LPDWORD)")
|
||||
DEFLOOKUP(DWORD, WaitForSingleObject, "(HANDLE, DWORD)")
|
||||
<< std::endl;
|
||||
#undef DEFLOOKUP
|
||||
// allocate memory in the remote process
|
||||
std::cout << "LPBYTE dll_plugin = (LPBYTE)pVirtualAllocEx(process, NULL, " << plugin_nt_headers->OptionalHeader.SizeOfImage << ", MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);" << std::endl;
|
||||
std::cout << "LPBYTE dll_lua = (LPBYTE)pVirtualAllocEx(process, NULL, " << luajit_nt_headers->OptionalHeader.SizeOfImage << ", MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);" << std::endl;
|
||||
// copy DLL headers to the target process
|
||||
std::cout << "pWriteProcessMemory(process, dll_plugin, (PVOID)plugin_dll_headers, " << plugin_nt_headers->OptionalHeader.SizeOfHeaders << ", NULL);" << std::endl;
|
||||
std::cout << "pWriteProcessMemory(process, dll_lua, (PVOID)luajit_dll_headers, " << luajit_nt_headers->OptionalHeader.SizeOfHeaders << ", NULL);" << std::endl;
|
||||
// copy each section to the target process
|
||||
for (size_t i = 0; i < plugin_nt_headers->FileHeader.NumberOfSections; i += 1) {
|
||||
std::cout << "pWriteProcessMemory(process, (PVOID)(dll_plugin + " << plugin_section_header[i].VirtualAddress << "), (PVOID)psect" << i << ", " << plugin_section_header[i].SizeOfRawData << ", NULL);" << std::endl;
|
||||
}
|
||||
for (size_t i = 0; i < luajit_nt_headers->FileHeader.NumberOfSections; i += 1) {
|
||||
std::cout << "pWriteProcessMemory(process, (PVOID)(dll_lua + " << luajit_section_header[i].VirtualAddress << "), (PVOID)luasect" << i << ", " << luajit_section_header[i].SizeOfRawData << ", NULL);" << std::endl;
|
||||
}
|
||||
// fix relocations
|
||||
std::cout <<
|
||||
"ptrdiff_t reloc_delta = (ptrdiff_t)(dll_plugin - " << plugin_nt_headers->OptionalHeader.ImageBase << ");"
|
||||
"PIMAGE_BASE_RELOCATION remote_reloc_address = (PIMAGE_BASE_RELOCATION)(dll_plugin + " << plugin_nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress << ");"
|
||||
"WORD offset;"
|
||||
"DWORD ptr;"
|
||||
"while (1) {"
|
||||
"IMAGE_BASE_RELOCATION remote_reloc;"
|
||||
"pReadProcessMemory(process, (LPCVOID)remote_reloc_address, (LPVOID)&remote_reloc, sizeof(remote_reloc), NULL);"
|
||||
"if (!remote_reloc.VirtualAddress) break;"
|
||||
"if (remote_reloc.SizeOfBlock > sizeof(remote_reloc)) {"
|
||||
"PWORD list = (PWORD)(remote_reloc_address + 1);"
|
||||
"for (size_t i = 0; i < (remote_reloc.SizeOfBlock - sizeof(remote_reloc)) / sizeof(WORD); i += 1) {"
|
||||
"pReadProcessMemory(process, (LPCVOID)(list + i), (LPVOID)&offset, sizeof(offset), NULL);"
|
||||
"if (!offset) continue;"
|
||||
"LPVOID remote_ptr_address = (LPVOID)(dll_plugin + remote_reloc.VirtualAddress + (offset & 0xFFF));"
|
||||
"pReadProcessMemory(process, (LPCVOID)remote_ptr_address, (LPVOID)&ptr, sizeof(ptr), NULL);"
|
||||
"ptr += reloc_delta;"
|
||||
"pWriteProcessMemory(process, remote_ptr_address, (LPCVOID)&ptr, sizeof(ptr), NULL);"
|
||||
"}"
|
||||
"}"
|
||||
"remote_reloc_address = (PIMAGE_BASE_RELOCATION)((LPBYTE)remote_reloc_address + remote_reloc.SizeOfBlock);"
|
||||
"}"
|
||||
"reloc_delta = (ptrdiff_t)(dll_lua - " << luajit_nt_headers->OptionalHeader.ImageBase << ");"
|
||||
"remote_reloc_address = (PIMAGE_BASE_RELOCATION)(dll_lua + " << luajit_nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress << ");"
|
||||
"while (1) {"
|
||||
"IMAGE_BASE_RELOCATION remote_reloc;"
|
||||
"pReadProcessMemory(process, (LPCVOID)remote_reloc_address, (LPVOID)&remote_reloc, sizeof(remote_reloc), NULL);"
|
||||
"if (!remote_reloc.VirtualAddress) break;"
|
||||
"if (remote_reloc.SizeOfBlock > sizeof(remote_reloc)) {"
|
||||
"PWORD list = (PWORD)(remote_reloc_address + 1);"
|
||||
"for (size_t i = 0; i < (remote_reloc.SizeOfBlock - sizeof(remote_reloc)) / sizeof(WORD); i += 1) {"
|
||||
"pReadProcessMemory(process, (LPCVOID)(list + i), (LPVOID)&offset, sizeof(offset), NULL);"
|
||||
"if (!offset) continue;"
|
||||
"LPVOID remote_ptr_address = (LPVOID)(dll_lua + remote_reloc.VirtualAddress + (offset & 0xFFF));"
|
||||
"pReadProcessMemory(process, (LPCVOID)remote_ptr_address, (LPVOID)&ptr, sizeof(ptr), NULL);"
|
||||
"ptr += reloc_delta;"
|
||||
"pWriteProcessMemory(process, remote_ptr_address, (LPCVOID)&ptr, sizeof(ptr), NULL);"
|
||||
"}"
|
||||
"}"
|
||||
"remote_reloc_address = (PIMAGE_BASE_RELOCATION)((LPBYTE)remote_reloc_address + remote_reloc.SizeOfBlock);"
|
||||
"}" << std::endl;
|
||||
// set rwx permissions for each section
|
||||
std::cout << "DWORD oldp;" << std::endl;
|
||||
for (size_t i = 0; i < plugin_nt_headers->FileHeader.NumberOfSections; i += 1) {
|
||||
DWORD permission = perms_for_characteristics(plugin_section_header[i].Characteristics);
|
||||
std::cout << "pVirtualProtectEx(process, (LPVOID)(dll_plugin + " << plugin_section_header[i].VirtualAddress << "), " << plugin_section_header[i].Misc.VirtualSize << ", " << permission << ", &oldp);" << std::endl;
|
||||
}
|
||||
for (size_t i = 0; i < luajit_nt_headers->FileHeader.NumberOfSections; i += 1) {
|
||||
DWORD permission = perms_for_characteristics(luajit_section_header[i].Characteristics);
|
||||
std::cout << "pVirtualProtectEx(process, (LPVOID)(dll_lua + " << luajit_section_header[i].VirtualAddress << "), " << luajit_section_header[i].Misc.VirtualSize << ", " << permission << ", &oldp);" << std::endl;
|
||||
}
|
||||
// invoke entrypoint
|
||||
std::cout << "struct PluginInjectParams params = {.kernel32=kernel32, .pGetModuleHandleW=pGetModuleHandleW, .pGetProcAddress=pGetProcAddress};" << std::endl;
|
||||
std::cout << "struct PluginInjectParams* remote_params = (struct PluginInjectParams*)pVirtualAllocEx(process, NULL, sizeof(params), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);" << std::endl;
|
||||
std::cout << "pWriteProcessMemory(process, remote_params, ¶ms, sizeof(params), NULL);" << std::endl;
|
||||
std::cout << "HANDLE remote_thread = pCreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)(dll_plugin + " << entry_point_rva << "), remote_params, 0, NULL);" << std::endl;
|
||||
std::cout << "pWaitForSingleObject(remote_thread, INFINITE);" << std::endl;
|
||||
std::cout << "pVirtualFreeEx(process, remote_params, 0, MEM_RELEASE);" << std::endl;
|
||||
|
||||
// wipe dll headers from remote process
|
||||
std::cout << "pWriteProcessMemory(process, dll_plugin, (PVOID)zeroes, " << plugin_nt_headers->OptionalHeader.SizeOfHeaders << ", NULL);" << std::endl;
|
||||
std::cout << "pWriteProcessMemory(process, dll_lua, (PVOID)zeroes, " << luajit_nt_headers->OptionalHeader.SizeOfHeaders << ", NULL);" << std::endl;
|
||||
|
||||
std::cout << "}" << std::endl;
|
||||
|
||||
CloseHandle(luajit_file);
|
||||
CloseHandle(plugin_file);
|
||||
VirtualFree(luajit_dll, luajit_file_size, MEM_RELEASE);
|
||||
VirtualFree(plugin_dll, plugin_file_size, MEM_RELEASE);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <windows.h>
|
||||
|
||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
|
||||
#include <Windows.h>
|
||||
#include "dll_inject.h"
|
||||
|
||||
DWORD __stdcall BOLT_STUB_ENTRYNAME(struct PluginInjectParams* data) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
#include "stub_inject.hxx"
|
||||
#include "stub_inject.h"
|
||||
#include "dll_inject.h"
|
||||
|
||||
//typedef HANDLE(__stdcall* CREATEFILEW)(LPCWSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE);
|
||||
//typedef FARPROC(__stdcall* CLOSEHANDLE)(HANDLE);
|
||||
//typedef BOOL(__stdcall* WRITEFILE)(HANDLE, LPCVOID, DWORD, LPDWORD, LPOVERLAPPED);
|
||||
typedef BOOL(__stdcall* CREATEPROCESSW)(LPCWSTR, LPWSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, LPCWSTR, LPSTARTUPINFOW, LPPROCESS_INFORMATION);
|
||||
typedef BOOL(__stdcall* VIRTUALPROTECT)(LPVOID, SIZE_T, DWORD, PDWORD);
|
||||
typedef DWORD(__stdcall* RESUMETHREAD)(HANDLE);
|
||||
|
||||
//static CREATEFILEW real_CreateFileW;
|
||||
//static CLOSEHANDLE real_CloseHandle;
|
||||
//static WRITEFILE real_WriteFile;
|
||||
static RESUMETHREAD real_ResumeThread;
|
||||
|
||||
static CREATEPROCESSW real_CreateProcessW;
|
||||
BOOL hook_CreateProcessW(LPCWSTR, LPWSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, LPCWSTR, LPSTARTUPINFOW, LPPROCESS_INFORMATION);
|
||||
|
||||
struct StubInjectParams params;
|
||||
|
||||
// true if match, false if not, for case-insensitive mode a2 must be all lowercase
|
||||
BOOL bolt_cmp(const char* a1, const char* a2, BOOL case_sensitive) {
|
||||
while (1) {
|
||||
@@ -33,10 +32,9 @@ BOOL bolt_cmp(const char* a1, const char* a2, BOOL case_sensitive) {
|
||||
// process passes us its function pointers for GetModuleHandleW and GetProcAddress. using those, we
|
||||
// can find the game's imported modules and use them for ourselves.
|
||||
DWORD __stdcall BOLT_STUB_ENTRYNAME(struct StubInjectParams* data) {
|
||||
params = *data;
|
||||
VIRTUALPROTECT pVirtualProtect = (VIRTUALPROTECT)data->pGetProcAddress(data->kernel32, "VirtualProtect");
|
||||
//real_CreateFileW = (CREATEFILEW)data->pGetProcAddress(data->kernel32, "CreateFileW");
|
||||
//real_CloseHandle = (CLOSEHANDLE)data->pGetProcAddress(data->kernel32, "CloseHandle");
|
||||
//real_WriteFile = (WRITEFILE)data->pGetProcAddress(data->kernel32, "WriteFile");
|
||||
real_ResumeThread = (RESUMETHREAD)data->pGetProcAddress(data->kernel32, "ResumeThread");
|
||||
|
||||
HMODULE main_module = data->pGetModuleHandleW(NULL);
|
||||
PIMAGE_DOS_HEADER dos_header = (PIMAGE_DOS_HEADER)main_module;
|
||||
@@ -78,17 +76,24 @@ BOOL hook_CreateProcessW(
|
||||
LPSTARTUPINFOW lpStartupInfo,
|
||||
LPPROCESS_INFORMATION lpProcessInformation
|
||||
) {
|
||||
// CreateProcessW hook, check if we're starting rs2client and if so, inject bolt-plugin.dll
|
||||
return real_CreateProcessW(
|
||||
// CreateProcessW hook - the game launcher downloads a new version of the game client, if any,
|
||||
// then runs it using CreateProcessW. it's the only time it uses this function, so we don't need
|
||||
// to check what the child process is. just inject the plugin loader into it.
|
||||
const BOOL is_already_suspended = dwCreationFlags & CREATE_SUSPENDED ? TRUE : FALSE;
|
||||
BOOL ret = real_CreateProcessW(
|
||||
lpApplicationName,
|
||||
lpCommandLine,
|
||||
lpProcessAttributes,
|
||||
lpThreadAttributes,
|
||||
bInheritHandles,
|
||||
dwCreationFlags,
|
||||
dwCreationFlags | CREATE_SUSPENDED,
|
||||
lpEnvironment,
|
||||
lpCurrentDirectory,
|
||||
lpStartupInfo,
|
||||
lpProcessInformation
|
||||
);
|
||||
if (!ret) return 0;
|
||||
InjectPluginDll(lpProcessInformation->hProcess, params.kernel32, params.pGetModuleHandleW, params.pGetProcAddress);
|
||||
if (!is_already_suspended) real_ResumeThread(lpProcessInformation->hThread);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "stub_inject.hxx"
|
||||
#include "stub_inject.h"
|
||||
#include <iostream>
|
||||
|
||||
/// This program is run by the build system on Windows. It manually maps the stub DLL, then outputs some C++ code which
|
||||
|
||||
Reference in New Issue
Block a user