mirror of
https://github.com/ineedbots/cod2m.git
synced 2025-04-19 16:02:53 +00:00
Init iw4x base
This commit is contained in:
commit
0c2c478990
4
.gitattributes
vendored
Normal file
4
.gitattributes
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
*.hpp eol=crlf
|
||||||
|
*.cpp eol=crlf
|
||||||
|
*.lua eol=crlf
|
||||||
|
*.proto eol=crlf
|
153
.gitignore
vendored
Normal file
153
.gitignore
vendored
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
### Windows
|
||||||
|
|
||||||
|
# Windows image file caches
|
||||||
|
Thumbs.db
|
||||||
|
ehthumbs.db
|
||||||
|
|
||||||
|
# Folder config file
|
||||||
|
Desktop.ini
|
||||||
|
|
||||||
|
# Recycle Bin used on file shares
|
||||||
|
$RECYCLE.BIN/
|
||||||
|
|
||||||
|
# Windows Installer files
|
||||||
|
*.cab
|
||||||
|
*.msi
|
||||||
|
*.msm
|
||||||
|
*.msp
|
||||||
|
|
||||||
|
# Shortcuts
|
||||||
|
*.lnk
|
||||||
|
|
||||||
|
### OSX
|
||||||
|
|
||||||
|
.DS_Store
|
||||||
|
.AppleDouble
|
||||||
|
.LSOverride
|
||||||
|
|
||||||
|
# Icon must end with two \r
|
||||||
|
Icon
|
||||||
|
|
||||||
|
# Thumbnails
|
||||||
|
._*
|
||||||
|
|
||||||
|
# Files that might appear on external disk
|
||||||
|
.Spotlight-V100
|
||||||
|
.Trashes
|
||||||
|
|
||||||
|
# Directories potentially created on remote AFP share
|
||||||
|
.AppleDB
|
||||||
|
.AppleDesktop
|
||||||
|
Network Trash Folder
|
||||||
|
Temporary Items
|
||||||
|
.apdisk
|
||||||
|
|
||||||
|
### Visual Studio
|
||||||
|
|
||||||
|
# User-specific files
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.userosscache
|
||||||
|
*.sln.docstates
|
||||||
|
|
||||||
|
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||||
|
*.userprefs
|
||||||
|
|
||||||
|
# Build results
|
||||||
|
build
|
||||||
|
|
||||||
|
# Visual Studio 2015 cache/options directory
|
||||||
|
.vs/
|
||||||
|
|
||||||
|
# MSTest test Results
|
||||||
|
[Tt]est[Rr]esult*/
|
||||||
|
[Bb]uild[Ll]og.*
|
||||||
|
|
||||||
|
*_i.c
|
||||||
|
*_p.c
|
||||||
|
*_i.h
|
||||||
|
*.ilk
|
||||||
|
*.meta
|
||||||
|
*.obj
|
||||||
|
*.pch
|
||||||
|
*.pdb
|
||||||
|
*.pgc
|
||||||
|
*.pgd
|
||||||
|
*.rsp
|
||||||
|
*.sbr
|
||||||
|
*.tlb
|
||||||
|
*.tli
|
||||||
|
*.tlh
|
||||||
|
*.tmp
|
||||||
|
*.tmp_proj
|
||||||
|
*.log
|
||||||
|
*.vspscc
|
||||||
|
*.vssscc
|
||||||
|
.builds
|
||||||
|
*.pidb
|
||||||
|
*.svclog
|
||||||
|
*.scc
|
||||||
|
|
||||||
|
# Visual C++ cache files
|
||||||
|
ipch/
|
||||||
|
*.aps
|
||||||
|
*.ncb
|
||||||
|
*.opendb
|
||||||
|
*.opensdf
|
||||||
|
*.sdf
|
||||||
|
*.cachefile
|
||||||
|
|
||||||
|
# Visual Studio profiler
|
||||||
|
*.psess
|
||||||
|
*.vsp
|
||||||
|
*.vspx
|
||||||
|
*.sap
|
||||||
|
|
||||||
|
# TFS 2012 Local Workspace
|
||||||
|
$tf/
|
||||||
|
|
||||||
|
# Guidance Automation Toolkit
|
||||||
|
*.gpState
|
||||||
|
|
||||||
|
# Visual Studio cache files
|
||||||
|
# files ending in .cache can be ignored
|
||||||
|
*.[Cc]ache
|
||||||
|
# but keep track of directories ending in .cache
|
||||||
|
!*.[Cc]ache/
|
||||||
|
|
||||||
|
# Others
|
||||||
|
~$*
|
||||||
|
*~
|
||||||
|
*.dbmdl
|
||||||
|
*.dbproj.schemaview
|
||||||
|
*.pfx
|
||||||
|
*.publishsettings
|
||||||
|
|
||||||
|
# Backup & report files from converting an old project file
|
||||||
|
# to a newer Visual Studio version. Backup files are not needed,
|
||||||
|
# because we have git ;-)
|
||||||
|
_UpgradeReport_Files/
|
||||||
|
Backup*/
|
||||||
|
UpgradeLog*.XML
|
||||||
|
UpgradeLog*.htm
|
||||||
|
|
||||||
|
# SQL Server files
|
||||||
|
*.mdf
|
||||||
|
*.ldf
|
||||||
|
|
||||||
|
### IDA
|
||||||
|
*.id0
|
||||||
|
*.id1
|
||||||
|
*.id2
|
||||||
|
*.nam
|
||||||
|
*.til
|
||||||
|
*.idb
|
||||||
|
*.i64
|
||||||
|
ida/*
|
||||||
|
|
||||||
|
### Custom user files
|
||||||
|
# User scripts
|
||||||
|
user*.bat
|
||||||
|
|
||||||
|
# Premake binary
|
||||||
|
#premake5.exe
|
4
generate.bat
Normal file
4
generate.bat
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
@echo off
|
||||||
|
echo Updating submodules...
|
||||||
|
call git submodule update --init --recursive
|
||||||
|
call tools\premake5 %* vs2019
|
317
premake5.lua
Normal file
317
premake5.lua
Normal file
@ -0,0 +1,317 @@
|
|||||||
|
gitVersioningCommand = "git describe --tags --dirty --always"
|
||||||
|
gitCurrentBranchCommand = "git symbolic-ref -q --short HEAD"
|
||||||
|
|
||||||
|
-- Quote the given string input as a C string
|
||||||
|
function cstrquote(value)
|
||||||
|
result = value:gsub("\\", "\\\\")
|
||||||
|
result = result:gsub("\"", "\\\"")
|
||||||
|
result = result:gsub("\n", "\\n")
|
||||||
|
result = result:gsub("\t", "\\t")
|
||||||
|
result = result:gsub("\r", "\\r")
|
||||||
|
result = result:gsub("\a", "\\a")
|
||||||
|
result = result:gsub("\b", "\\b")
|
||||||
|
result = "\"" .. result .. "\""
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Converts tags in "vX.X.X" format to an array of numbers {X,X,X}.
|
||||||
|
-- In the case where the format does not work fall back to old {4,2,REVISION}.
|
||||||
|
function vertonumarr(value, vernumber)
|
||||||
|
vernum = {}
|
||||||
|
for num in string.gmatch(value, "%d+") do
|
||||||
|
table.insert(vernum, tonumber(num))
|
||||||
|
end
|
||||||
|
if #vernum < 3 then
|
||||||
|
return {4,2,tonumber(vernumber)}
|
||||||
|
end
|
||||||
|
return vernum
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Option to allow copying the DLL file to a custom folder after build
|
||||||
|
newoption {
|
||||||
|
trigger = "copy-to",
|
||||||
|
description = "Optional, copy the DLL to a custom folder after build, define the path here if wanted.",
|
||||||
|
value = "PATH"
|
||||||
|
}
|
||||||
|
|
||||||
|
newoption {
|
||||||
|
trigger = "no-new-structure",
|
||||||
|
description = "Do not use new virtual path structure (separating headers and source files)."
|
||||||
|
}
|
||||||
|
|
||||||
|
newoption {
|
||||||
|
trigger = "copy-pdb",
|
||||||
|
description = "Copy debug information for binaries as well to the path given via --copy-to."
|
||||||
|
}
|
||||||
|
|
||||||
|
newaction {
|
||||||
|
trigger = "version",
|
||||||
|
description = "Returns the version string for the current commit of the source code.",
|
||||||
|
onWorkspace = function(wks)
|
||||||
|
-- get current version via git
|
||||||
|
local proc = assert(io.popen(gitVersioningCommand, "r"))
|
||||||
|
local gitDescribeOutput = assert(proc:read('*a')):gsub("%s+", "")
|
||||||
|
proc:close()
|
||||||
|
local version = gitDescribeOutput
|
||||||
|
|
||||||
|
proc = assert(io.popen(gitCurrentBranchCommand, "r"))
|
||||||
|
local gitCurrentBranchOutput = assert(proc:read('*a')):gsub("%s+", "")
|
||||||
|
local gitCurrentBranchSuccess = proc:close()
|
||||||
|
if gitCurrentBranchSuccess then
|
||||||
|
-- We got a branch name, check if it is a feature branch
|
||||||
|
if gitCurrentBranchOutput ~= "develop" and gitCurrentBranchOutput ~= "master" then
|
||||||
|
version = version .. "-" .. gitCurrentBranchOutput
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
print(version)
|
||||||
|
os.exit(0)
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
newaction {
|
||||||
|
trigger = "generate-buildinfo",
|
||||||
|
description = "Sets up build information file like version.h.",
|
||||||
|
onWorkspace = function(wks)
|
||||||
|
-- get revision number via git
|
||||||
|
local proc = assert(io.popen("git rev-list --count HEAD", "r"))
|
||||||
|
local revNumber = assert(proc:read('*a')):gsub("%s+", "")
|
||||||
|
|
||||||
|
-- get current version via git
|
||||||
|
local proc = assert(io.popen(gitVersioningCommand, "r"))
|
||||||
|
local gitDescribeOutput = assert(proc:read('*a')):gsub("%s+", "")
|
||||||
|
proc:close()
|
||||||
|
|
||||||
|
-- get whether this is a clean revision (no uncommitted changes)
|
||||||
|
proc = assert(io.popen("git status --porcelain", "r"))
|
||||||
|
local revDirty = (assert(proc:read('*a')) ~= "")
|
||||||
|
if revDirty then revDirty = 1 else revDirty = 0 end
|
||||||
|
proc:close()
|
||||||
|
|
||||||
|
-- get current tag name
|
||||||
|
proc = assert(io.popen("git describe --tags --abbrev=0"))
|
||||||
|
local tagName = assert(proc:read('*l'))
|
||||||
|
|
||||||
|
-- get old version number from version.hpp if any
|
||||||
|
local oldVersion = "(none)"
|
||||||
|
local oldVersionHeader = io.open(wks.location .. "/src/version.h", "r")
|
||||||
|
if oldVersionHeader ~= nil then
|
||||||
|
local oldVersionHeaderContent = assert(oldVersionHeader:read('*l'))
|
||||||
|
while oldVersionHeaderContent do
|
||||||
|
m = string.match(oldVersionHeaderContent, "#define GIT_DESCRIBE (.+)%s*$")
|
||||||
|
if m ~= nil then
|
||||||
|
oldVersion = m
|
||||||
|
end
|
||||||
|
|
||||||
|
oldVersionHeaderContent = oldVersionHeader:read('*l')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- generate version.hpp with a revision number if not equal
|
||||||
|
gitDescribeOutputQuoted = cstrquote(gitDescribeOutput)
|
||||||
|
if oldVersion ~= gitDescribeOutputQuoted then
|
||||||
|
print ("Update " .. oldVersion .. " -> " .. gitDescribeOutputQuoted)
|
||||||
|
local versionHeader = assert(io.open(wks.location .. "/src/version.h", "w"))
|
||||||
|
versionHeader:write("/*\n")
|
||||||
|
versionHeader:write(" * Automatically generated by premake5.\n")
|
||||||
|
versionHeader:write(" * Do not touch, you fucking moron!\n")
|
||||||
|
versionHeader:write(" */\n")
|
||||||
|
versionHeader:write("\n")
|
||||||
|
versionHeader:write("#define GIT_DESCRIBE " .. gitDescribeOutputQuoted .. "\n")
|
||||||
|
versionHeader:write("#define GIT_DIRTY " .. revDirty .. "\n")
|
||||||
|
versionHeader:write("#define GIT_TAG " .. cstrquote(tagName) .. "\n")
|
||||||
|
versionHeader:write("\n")
|
||||||
|
versionHeader:write("// Legacy definitions (needed for update check)\n")
|
||||||
|
versionHeader:write("#define REVISION " .. revNumber .. "\n")
|
||||||
|
versionHeader:write("\n")
|
||||||
|
versionHeader:write("// Version transformed for RC files\n")
|
||||||
|
versionHeader:write("#define VERSION_RC " .. table.concat(vertonumarr(tagName, revNumber), ",") .. "\n")
|
||||||
|
versionHeader:write("\n")
|
||||||
|
versionHeader:write("// Alias definitions\n")
|
||||||
|
versionHeader:write("#define VERSION GIT_DESCRIBE\n")
|
||||||
|
versionHeader:write("#define SHORTVERSION " .. cstrquote(table.concat(vertonumarr(tagName, revNumber), ".")) .. "\n")
|
||||||
|
versionHeader:close()
|
||||||
|
local versionHeader = assert(io.open(wks.location .. "/src/version.hpp", "w"))
|
||||||
|
versionHeader:write("/*\n")
|
||||||
|
versionHeader:write(" * Automatically generated by premake5.\n")
|
||||||
|
versionHeader:write(" * Do not touch, you fucking moron!\n")
|
||||||
|
versionHeader:write(" *\n")
|
||||||
|
versionHeader:write(" * This file exists for reasons of complying with our coding standards.\n")
|
||||||
|
versionHeader:write(" *\n")
|
||||||
|
versionHeader:write(" * The Resource Compiler will ignore any content from C++ header files if they're not from STDInclude.hpp.\n")
|
||||||
|
versionHeader:write(" * That's the reason why we now place all version info in version.h instead.\n")
|
||||||
|
versionHeader:write(" */\n")
|
||||||
|
versionHeader:write("\n")
|
||||||
|
versionHeader:write("#include \".\\version.h\"\n")
|
||||||
|
versionHeader:close()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
workspace "cod2m"
|
||||||
|
startproject "cod2m"
|
||||||
|
location "./build"
|
||||||
|
objdir "%{wks.location}/obj"
|
||||||
|
targetdir "%{wks.location}/bin/%{cfg.buildcfg}"
|
||||||
|
buildlog "%{wks.location}/obj/%{cfg.architecture}/%{cfg.buildcfg}/%{prj.name}/%{prj.name}.log"
|
||||||
|
configurations { "Debug", "Release" }
|
||||||
|
architecture "x86"
|
||||||
|
platforms "x86"
|
||||||
|
--exceptionhandling ("SEH")
|
||||||
|
|
||||||
|
staticruntime "On"
|
||||||
|
|
||||||
|
configuration "windows"
|
||||||
|
defines { "_WINDOWS", "WIN32" }
|
||||||
|
|
||||||
|
configuration "Release*"
|
||||||
|
defines { "NDEBUG" }
|
||||||
|
flags { "MultiProcessorCompile", "LinkTimeOptimization", "No64BitChecks" }
|
||||||
|
optimize "On"
|
||||||
|
rtti ("Off")
|
||||||
|
|
||||||
|
configuration "Debug*"
|
||||||
|
defines { "DEBUG", "_DEBUG" }
|
||||||
|
flags { "MultiProcessorCompile", "No64BitChecks" }
|
||||||
|
optimize "Debug"
|
||||||
|
if symbols ~= nil then
|
||||||
|
symbols "On"
|
||||||
|
else
|
||||||
|
flags { "Symbols" }
|
||||||
|
end
|
||||||
|
|
||||||
|
project "d3d9"
|
||||||
|
kind "SharedLib"
|
||||||
|
language "C++"
|
||||||
|
files {
|
||||||
|
"./src/**.rc",
|
||||||
|
"./src/**.hpp",
|
||||||
|
"./src/**.cpp",
|
||||||
|
--"./src/**.proto",
|
||||||
|
}
|
||||||
|
includedirs {
|
||||||
|
"%{prj.location}/src",
|
||||||
|
"./src",
|
||||||
|
"./lib/include",
|
||||||
|
}
|
||||||
|
syslibdirs {
|
||||||
|
"./lib/bin",
|
||||||
|
}
|
||||||
|
resincludedirs {
|
||||||
|
"$(ProjectDir)src" -- fix for VS IDE
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
-- Pre-compiled header
|
||||||
|
pchheader "STDInclude.hpp" -- must be exactly same as used in #include directives
|
||||||
|
pchsource "src/STDInclude.cpp" -- real path
|
||||||
|
buildoptions { "/Zm200" }
|
||||||
|
|
||||||
|
-- fix vpaths for protobuf sources
|
||||||
|
vpaths
|
||||||
|
{
|
||||||
|
["*"] = { "./src/**" },
|
||||||
|
--["Proto/Generated"] = { "**.pb.*" }, -- meh.
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Virtual paths
|
||||||
|
if not _OPTIONS["no-new-structure"] then
|
||||||
|
vpaths
|
||||||
|
{
|
||||||
|
["Headers/*"] = { "./src/**.hpp" },
|
||||||
|
["Sources/*"] = { "./src/**.cpp" },
|
||||||
|
["Resource/*"] = { "./src/**.rc" },
|
||||||
|
--["Proto/Definitions/*"] = { "./src/Proto/**.proto" },
|
||||||
|
--["Proto/Generated/*"] = { "**.pb.*" }, -- meh.
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
vpaths
|
||||||
|
{
|
||||||
|
["Docs/*"] = { "**.txt","**.md" },
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Pre-build
|
||||||
|
prebuildcommands
|
||||||
|
{
|
||||||
|
"pushd %{_MAIN_SCRIPT_DIR}",
|
||||||
|
"tools\\premake5 generate-buildinfo",
|
||||||
|
"popd",
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Post-build
|
||||||
|
if _OPTIONS["copy-to"] then
|
||||||
|
saneCopyToPath = string.gsub(_OPTIONS["copy-to"] .. "\\", "\\\\", "\\")
|
||||||
|
postbuildcommands {
|
||||||
|
"if not exist \"" .. saneCopyToPath .. "\" mkdir \"" .. saneCopyToPath .. "\"",
|
||||||
|
}
|
||||||
|
|
||||||
|
if _OPTIONS["copy-pdb"] then
|
||||||
|
postbuildcommands {
|
||||||
|
"copy /y \"$(TargetDir)*.pdb\" \"" .. saneCopyToPath .. "\"",
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
-- This has to be the last one, as otherwise VisualStudio will succeed building even if copying fails
|
||||||
|
postbuildcommands {
|
||||||
|
"copy /y \"$(TargetDir)*.dll\" \"" .. saneCopyToPath .. "\"",
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Specific configurations
|
||||||
|
flags { "UndefinedIdentifiers" }
|
||||||
|
warnings "Extra"
|
||||||
|
|
||||||
|
if symbols ~= nil then
|
||||||
|
symbols "On"
|
||||||
|
else
|
||||||
|
flags { "Symbols" }
|
||||||
|
end
|
||||||
|
|
||||||
|
configuration "Release*"
|
||||||
|
flags {
|
||||||
|
"FatalCompileWarnings",
|
||||||
|
"FatalLinkWarnings",
|
||||||
|
}
|
||||||
|
configuration {}
|
||||||
|
|
||||||
|
--[[
|
||||||
|
-- Generate source code from protobuf definitions
|
||||||
|
rules { "ProtobufCompiler" }
|
||||||
|
|
||||||
|
-- Workaround: Consume protobuf generated source files
|
||||||
|
matches = os.matchfiles(path.join("src/Proto/**.proto"))
|
||||||
|
for i, srcPath in ipairs(matches) do
|
||||||
|
basename = path.getbasename(srcPath)
|
||||||
|
files
|
||||||
|
{
|
||||||
|
string.format("%%{prj.location}/src/proto/%s.pb.h", basename),
|
||||||
|
string.format("%%{prj.location}/src/proto/%s.pb.cc", basename),
|
||||||
|
}
|
||||||
|
end
|
||||||
|
includedirs
|
||||||
|
{
|
||||||
|
"%{prj.location}/src/proto",
|
||||||
|
}
|
||||||
|
filter "files:**.pb.*"
|
||||||
|
flags {
|
||||||
|
"NoPCH",
|
||||||
|
}
|
||||||
|
buildoptions {
|
||||||
|
"/wd4100", -- "Unused formal parameter"
|
||||||
|
"/wd4389", -- "Signed/Unsigned mismatch"
|
||||||
|
"/wd6011", -- "Dereferencing NULL pointer"
|
||||||
|
"/wd4125", -- "Decimal digit terminates octal escape sequence"
|
||||||
|
}
|
||||||
|
defines {
|
||||||
|
"_SCL_SECURE_NO_WARNINGS",
|
||||||
|
}
|
||||||
|
filter {}
|
||||||
|
]]
|
||||||
|
|
||||||
|
workspace "*"
|
||||||
|
buildoptions {
|
||||||
|
"/std:c++latest"
|
||||||
|
}
|
||||||
|
systemversion "latest"
|
||||||
|
defines { "_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS" }
|
9
src/Game/MP.cpp
Normal file
9
src/Game/MP.cpp
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
|
namespace MP
|
||||||
|
{
|
||||||
|
void PatchT4()
|
||||||
|
{
|
||||||
|
MessageBoxA(nullptr, "MP", "DEBUG", 0);
|
||||||
|
}
|
||||||
|
}
|
6
src/Game/MP.hpp
Normal file
6
src/Game/MP.hpp
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace MP
|
||||||
|
{
|
||||||
|
void PatchT4();
|
||||||
|
}
|
0
src/Game/MP/Functions.hpp
Normal file
0
src/Game/MP/Functions.hpp
Normal file
0
src/Game/MP/Structs.hpp
Normal file
0
src/Game/MP/Structs.hpp
Normal file
9
src/Game/SP.cpp
Normal file
9
src/Game/SP.cpp
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
|
namespace SP
|
||||||
|
{
|
||||||
|
void PatchT4()
|
||||||
|
{
|
||||||
|
MessageBoxA(nullptr, "SP", "DEBUG", 0);
|
||||||
|
}
|
||||||
|
}
|
6
src/Game/SP.hpp
Normal file
6
src/Game/SP.hpp
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace SP
|
||||||
|
{
|
||||||
|
void PatchT4();
|
||||||
|
}
|
0
src/Game/SP/Functions.hpp
Normal file
0
src/Game/SP/Functions.hpp
Normal file
0
src/Game/SP/Structs.hpp
Normal file
0
src/Game/SP/Structs.hpp
Normal file
89
src/Main.cpp
Normal file
89
src/Main.cpp
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
|
namespace Main
|
||||||
|
{
|
||||||
|
static BYTE originalCode[5];
|
||||||
|
static PBYTE originalEP = 0;
|
||||||
|
|
||||||
|
void UnprotectModule(HMODULE hModule)
|
||||||
|
{
|
||||||
|
PIMAGE_DOS_HEADER header = (PIMAGE_DOS_HEADER)hModule;
|
||||||
|
PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((DWORD)hModule + header->e_lfanew);
|
||||||
|
|
||||||
|
// unprotect the entire PE image
|
||||||
|
SIZE_T size = ntHeader->OptionalHeader.SizeOfImage;
|
||||||
|
DWORD oldProtect;
|
||||||
|
VirtualProtect((LPVOID)hModule, size, PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DoInit()
|
||||||
|
{
|
||||||
|
// return to the original EP
|
||||||
|
memcpy(originalEP, &originalCode, sizeof(originalCode));
|
||||||
|
|
||||||
|
// unprotect our entire PE image
|
||||||
|
HMODULE hModule;
|
||||||
|
if (SUCCEEDED(GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCWSTR)DoInit, &hModule)))
|
||||||
|
{
|
||||||
|
UnprotectModule(hModule);
|
||||||
|
}
|
||||||
|
|
||||||
|
// detect which executable's patches to apply
|
||||||
|
DWORD dataStrData = Utils::Hook::Get<DWORD>(0x881CAC);
|
||||||
|
if (dataStrData == 0x62616E55)
|
||||||
|
MP::PatchT4();
|
||||||
|
else
|
||||||
|
SP::PatchT4();
|
||||||
|
|
||||||
|
hModule = GetModuleHandle(NULL);
|
||||||
|
PIMAGE_DOS_HEADER header = (PIMAGE_DOS_HEADER)hModule;
|
||||||
|
PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((DWORD)hModule + header->e_lfanew);
|
||||||
|
|
||||||
|
// back up original code
|
||||||
|
originalEP = (PBYTE)((DWORD)hModule + ntHeader->OptionalHeader.AddressOfEntryPoint);
|
||||||
|
|
||||||
|
__asm
|
||||||
|
{
|
||||||
|
jmp originalEP
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetSafeInit()
|
||||||
|
{
|
||||||
|
// find the entry point for the executable process, set page access, and replace the EP
|
||||||
|
HMODULE hModule = GetModuleHandle(NULL); // passing NULL should be safe even with the loader lock being held (according to ReactOS ldr.c)
|
||||||
|
|
||||||
|
if (hModule)
|
||||||
|
{
|
||||||
|
PIMAGE_DOS_HEADER header = (PIMAGE_DOS_HEADER)hModule;
|
||||||
|
PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((DWORD)hModule + header->e_lfanew);
|
||||||
|
|
||||||
|
UnprotectModule(hModule);
|
||||||
|
|
||||||
|
// back up original code
|
||||||
|
PBYTE ep = (PBYTE)((DWORD)hModule + ntHeader->OptionalHeader.AddressOfEntryPoint);
|
||||||
|
memcpy(originalCode, ep, sizeof(originalCode));
|
||||||
|
|
||||||
|
// patch to call our EP
|
||||||
|
int newEP = (int)DoInit - ((int)ep + 5);
|
||||||
|
ep[0] = 0xE9; // for some reason this doesn't work properly when run under the debugger
|
||||||
|
memcpy(&ep[1], &newEP, 4);
|
||||||
|
|
||||||
|
originalEP = ep;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool APIENTRY DllMain(HMODULE, DWORD dwReason, LPVOID)
|
||||||
|
{
|
||||||
|
if (dwReason == DLL_PROCESS_ATTACH)
|
||||||
|
{
|
||||||
|
DWORD textSegData = Utils::Hook::Get<DWORD>(0x401000);
|
||||||
|
|
||||||
|
// detect for all executables to hook into
|
||||||
|
//if (textSegData == 0x9EF490B8 || textSegData == 0x83EC8B55)
|
||||||
|
Main::SetSafeInit();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
97
src/Resource.rc
Normal file
97
src/Resource.rc
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
// Microsoft Visual C++ generated resource script.
|
||||||
|
//
|
||||||
|
#pragma code_page(65001)
|
||||||
|
|
||||||
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
|
#define APSTUDIO_READONLY_SYMBOLS
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Generated from the TEXTINCLUDE 2 resource.
|
||||||
|
//
|
||||||
|
#include "windows.h"
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
#undef APSTUDIO_READONLY_SYMBOLS
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
// English (United States) resources
|
||||||
|
|
||||||
|
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||||
|
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||||
|
|
||||||
|
#ifdef APSTUDIO_INVOKED
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// TEXTINCLUDE
|
||||||
|
//
|
||||||
|
|
||||||
|
1 TEXTINCLUDE
|
||||||
|
BEGIN
|
||||||
|
"#include ""windows.h""\r\n"
|
||||||
|
"\0"
|
||||||
|
END
|
||||||
|
|
||||||
|
2 TEXTINCLUDE
|
||||||
|
BEGIN
|
||||||
|
"\r\n"
|
||||||
|
"\0"
|
||||||
|
END
|
||||||
|
|
||||||
|
#endif // APSTUDIO_INVOKED
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Version
|
||||||
|
//
|
||||||
|
|
||||||
|
VS_VERSION_INFO VERSIONINFO
|
||||||
|
FILEFLAGSMASK 0x3fL
|
||||||
|
#ifdef _DEBUG
|
||||||
|
FILEFLAGS 0x1L
|
||||||
|
#else
|
||||||
|
FILEFLAGS 0x0L
|
||||||
|
#endif
|
||||||
|
FILEOS 0x40004L
|
||||||
|
FILETYPE VFT_DLL
|
||||||
|
FILESUBTYPE 0x0L
|
||||||
|
BEGIN
|
||||||
|
BLOCK "StringFileInfo"
|
||||||
|
BEGIN
|
||||||
|
BLOCK "040904b0"
|
||||||
|
BEGIN
|
||||||
|
VALUE "CompanyName", "CoD2m"
|
||||||
|
#ifdef _DEBUG
|
||||||
|
VALUE "FileDescription", "CoD2 client/server modification (DEBUG)"
|
||||||
|
#else
|
||||||
|
VALUE "FileDescription", "CoD2 client/server modification"
|
||||||
|
#endif
|
||||||
|
VALUE "FileVersion", SHORTVERSION
|
||||||
|
VALUE "InternalName", "cod2m"
|
||||||
|
VALUE "LegalCopyright", "All rights reserved."
|
||||||
|
VALUE "OriginalFilename", "d3d9.dll"
|
||||||
|
VALUE "ProductName", "CoD2m"
|
||||||
|
VALUE "ProductVersion", SHORTVERSION
|
||||||
|
END
|
||||||
|
END
|
||||||
|
BLOCK "VarFileInfo"
|
||||||
|
BEGIN
|
||||||
|
VALUE "Translation", 0x409, 1200
|
||||||
|
END
|
||||||
|
END
|
||||||
|
|
||||||
|
#endif // English (United States) resources
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef APSTUDIO_INVOKED
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Generated from the TEXTINCLUDE 3 resource.
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif // not APSTUDIO_INVOKED
|
||||||
|
|
90
src/SDLLP.cpp
Normal file
90
src/SDLLP.cpp
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
// --------------------------------------+
|
||||||
|
// System Dynamic Link Library Proxy
|
||||||
|
// by momo5502
|
||||||
|
// --------------------------------------+
|
||||||
|
|
||||||
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
|
// Macro to declare an export
|
||||||
|
// --------------------------------------+
|
||||||
|
#define EXPORT(_export) extern "C" __declspec(naked) __declspec(dllexport) void _export() { static FARPROC function = 0; if(!function) function = SDLLP::GetExport(__FUNCTION__, LIBRARY); __asm { jmp function } }
|
||||||
|
|
||||||
|
// Static class
|
||||||
|
// --------------------------------------+
|
||||||
|
class SDLLP
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
static std::map<std::string, HINSTANCE> mLibraries;
|
||||||
|
|
||||||
|
static void Log(const char* message, ...);
|
||||||
|
static void LoadLibrary(const char* library);
|
||||||
|
static bool IsLibraryLoaded(const char* library);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static FARPROC GetExport(const char* function, const char* library);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Class variable declarations
|
||||||
|
// --------------------------------------+
|
||||||
|
std::map<std::string, HINSTANCE> SDLLP::mLibraries;
|
||||||
|
|
||||||
|
// Load necessary library
|
||||||
|
// --------------------------------------+
|
||||||
|
void SDLLP::LoadLibrary(const char* library)
|
||||||
|
{
|
||||||
|
Log("[SDLLP] Loading library '%s'.", library);
|
||||||
|
|
||||||
|
CHAR mPath[MAX_PATH];
|
||||||
|
|
||||||
|
GetSystemDirectoryA(mPath, MAX_PATH);
|
||||||
|
strcat_s(mPath, "\\");
|
||||||
|
strcat_s(mPath, library);
|
||||||
|
|
||||||
|
mLibraries[library] = ::LoadLibraryA(mPath);
|
||||||
|
|
||||||
|
if (!IsLibraryLoaded(library)) Log("[SDLLP] Unable to load library '%s'.", library);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if export already loaded
|
||||||
|
// --------------------------------------+
|
||||||
|
bool SDLLP::IsLibraryLoaded(const char* library)
|
||||||
|
{
|
||||||
|
return (mLibraries.find(library) != mLibraries.end() && mLibraries[library]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get export address
|
||||||
|
// --------------------------------------+
|
||||||
|
FARPROC SDLLP::GetExport(const char* function, const char* library)
|
||||||
|
{
|
||||||
|
Log("[SDLLP] Export '%s' requested from %s.", function, library);
|
||||||
|
|
||||||
|
if (!IsLibraryLoaded(library)) LoadLibrary(library);
|
||||||
|
|
||||||
|
FARPROC address = GetProcAddress(mLibraries[library], function);
|
||||||
|
|
||||||
|
if (!address) Log("[SDLLP] Unable to load export '%s' from library '%s'.", function, library);
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write debug string
|
||||||
|
// --------------------------------------+
|
||||||
|
void SDLLP::Log(const char* message, ...)
|
||||||
|
{
|
||||||
|
CHAR buffer[1024];
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, message);
|
||||||
|
vsprintf(buffer, message, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
OutputDebugStringA(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------+
|
||||||
|
// Adapt export functions and library
|
||||||
|
// --------------------------------------+
|
||||||
|
|
||||||
|
#define LIBRARY "d3d9.dll"
|
||||||
|
EXPORT(D3DPERF_BeginEvent)
|
||||||
|
EXPORT(D3DPERF_EndEvent)
|
||||||
|
EXPORT(Direct3DCreate9)
|
115
src/STDInclude.cpp
Normal file
115
src/STDInclude.cpp
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
|
// Rename sections
|
||||||
|
#ifndef DEBUG
|
||||||
|
#pragma comment(linker, "/merge:.text=.UPX0")
|
||||||
|
#pragma comment(linker, "/merge:.data=.UPX1")
|
||||||
|
#pragma comment(linker, "/merge:.rdata=.UPX2")
|
||||||
|
#pragma comment(linker, "/merge:.tls=.UPX3")
|
||||||
|
#pragma comment(linker, "/merge:.gfids=.UPX4")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#pragma comment(linker,"\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
|
||||||
|
|
||||||
|
// Do necessary assertions here
|
||||||
|
// Some compilers treat them differently which causes a size mismatch
|
||||||
|
|
||||||
|
// WinAPI types
|
||||||
|
AssertSize(DWORD, 4);
|
||||||
|
AssertSize(WORD, 2);
|
||||||
|
AssertSize(BYTE, 1);
|
||||||
|
|
||||||
|
// 128 bit integers (only x64)
|
||||||
|
//AssertSize(__int128, 16);
|
||||||
|
//AssertSize(unsigned __int128, 16);
|
||||||
|
|
||||||
|
// 64 bit integers
|
||||||
|
AssertSize(__int64, 8);
|
||||||
|
AssertSize(unsigned __int64, 8);
|
||||||
|
AssertSize(long long, 8);
|
||||||
|
AssertSize(unsigned long long, 8);
|
||||||
|
AssertSize(int64_t, 8);
|
||||||
|
AssertSize(uint64_t, 8);
|
||||||
|
AssertSize(std::int64_t, 8);
|
||||||
|
AssertSize(std::uint64_t, 8);
|
||||||
|
|
||||||
|
// 64 bit double precision floating point numbers
|
||||||
|
AssertSize(double, 8);
|
||||||
|
|
||||||
|
// 32 bit integers
|
||||||
|
AssertSize(__int32, 4);
|
||||||
|
AssertSize(unsigned __int32, 4);
|
||||||
|
AssertSize(int, 4);
|
||||||
|
AssertSize(unsigned int, 4);
|
||||||
|
AssertSize(long, 4);
|
||||||
|
AssertSize(unsigned long, 4);
|
||||||
|
AssertSize(int32_t, 4);
|
||||||
|
AssertSize(uint32_t, 4);
|
||||||
|
AssertSize(std::int32_t, 4);
|
||||||
|
AssertSize(std::uint32_t, 4);
|
||||||
|
|
||||||
|
// 32 bit single precision floating point numbers
|
||||||
|
AssertSize(float, 4);
|
||||||
|
|
||||||
|
// 16 bit integers
|
||||||
|
AssertSize(__int16, 2);
|
||||||
|
AssertSize(unsigned __int16, 2);
|
||||||
|
AssertSize(short, 2);
|
||||||
|
AssertSize(unsigned short, 2);
|
||||||
|
AssertSize(int16_t, 2);
|
||||||
|
AssertSize(uint16_t, 2);
|
||||||
|
AssertSize(std::int16_t, 2);
|
||||||
|
AssertSize(std::uint16_t, 2);
|
||||||
|
|
||||||
|
// 8 bit integers
|
||||||
|
AssertSize(bool, 1);
|
||||||
|
AssertSize(__int8, 1);
|
||||||
|
AssertSize(unsigned __int8, 1);
|
||||||
|
AssertSize(char, 1);
|
||||||
|
AssertSize(unsigned char, 1);
|
||||||
|
AssertSize(int8_t, 1);
|
||||||
|
AssertSize(uint8_t, 1);
|
||||||
|
AssertSize(std::int8_t, 1);
|
||||||
|
AssertSize(std::uint8_t, 1);
|
||||||
|
|
||||||
|
// Ensure pointers are 4 bytes in size (32-bit)
|
||||||
|
// ReSharper disable CppRedundantBooleanExpressionArgument
|
||||||
|
static_assert(sizeof(intptr_t) == 4 && sizeof(void*) == 4 && sizeof(size_t) == 4, "This doesn't seem to be a 32-bit environment!");
|
||||||
|
// ReSharper restore CppRedundantBooleanExpressionArgument
|
||||||
|
|
||||||
|
#if !defined(_M_IX86)
|
||||||
|
#error "Invalid processor achritecture!"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
// Disable telemetry data logging
|
||||||
|
void __cdecl __vcrt_initialize_telemetry_provider() {}
|
||||||
|
void __cdecl __telemetry_main_invoke_trigger() {}
|
||||||
|
void __cdecl __telemetry_main_return_trigger() {}
|
||||||
|
void __cdecl __vcrt_uninitialize_telemetry_provider() {}
|
||||||
|
|
||||||
|
// Enable 'High Performance Graphics'
|
||||||
|
__declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
|
||||||
|
|
||||||
|
// Tommath fixes
|
||||||
|
int s_read_arc4random(void*, size_t)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int s_read_getrandom(void*, size_t)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int s_read_urandom(void*, size_t)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int s_read_ltm_rng(void*, size_t)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
};
|
120
src/STDInclude.hpp
Normal file
120
src/STDInclude.hpp
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Version number
|
||||||
|
#include "version.h"
|
||||||
|
|
||||||
|
#ifndef RC_INVOKED
|
||||||
|
|
||||||
|
#define _HAS_CXX17 1
|
||||||
|
#define _HAS_CXX20 1
|
||||||
|
#define VC_EXTRALEAN
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#define _CRT_SECURE_NO_WARNINGS
|
||||||
|
|
||||||
|
// Requires Visual Leak Detector plugin: http://vld.codeplex.com/
|
||||||
|
#define VLD_FORCE_ENABLE
|
||||||
|
//#include <vld.h>
|
||||||
|
#pragma warning(disable: 4740)
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include <timeapi.h>
|
||||||
|
#include <shellapi.h>
|
||||||
|
#include <Wininet.h>
|
||||||
|
#include <Aclapi.h>
|
||||||
|
#include <Psapi.h>
|
||||||
|
#include <tlhelp32.h>
|
||||||
|
#include <Shlwapi.h>
|
||||||
|
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable: 4091)
|
||||||
|
#pragma warning(disable: 4244)
|
||||||
|
#include <dbghelp.h>
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <cctype>
|
||||||
|
#include <regex>
|
||||||
|
#include <thread>
|
||||||
|
#include <future>
|
||||||
|
#include <map>
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
|
// Experimental C++17 features
|
||||||
|
#include <filesystem>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
#pragma warning(pop)
|
||||||
|
|
||||||
|
// Usefull for debugging
|
||||||
|
template <size_t S> class Sizer { };
|
||||||
|
#define BindNum(x, y) Sizer<x> y;
|
||||||
|
#define Size_Of(x, y) BindNum(sizeof(x), y)
|
||||||
|
#define Offset_Of(x, y, z) BindNum(offsetof(x, y), z)
|
||||||
|
|
||||||
|
// Submodules
|
||||||
|
// Ignore the warnings, it's not our code!
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable: 4005)
|
||||||
|
#pragma warning(disable: 4091)
|
||||||
|
#pragma warning(disable: 4100)
|
||||||
|
#pragma warning(disable: 4244)
|
||||||
|
#pragma warning(disable: 4389)
|
||||||
|
#pragma warning(disable: 4702)
|
||||||
|
#pragma warning(disable: 4800)
|
||||||
|
#pragma warning(disable: 4996) // _CRT_SECURE_NO_WARNINGS
|
||||||
|
#pragma warning(disable: 5054)
|
||||||
|
#pragma warning(disable: 6001)
|
||||||
|
#pragma warning(disable: 6011)
|
||||||
|
#pragma warning(disable: 6031)
|
||||||
|
#pragma warning(disable: 6255)
|
||||||
|
#pragma warning(disable: 6258)
|
||||||
|
#pragma warning(disable: 6386)
|
||||||
|
#pragma warning(disable: 6387)
|
||||||
|
|
||||||
|
#ifdef max
|
||||||
|
#undef max
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef min
|
||||||
|
#undef min
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#pragma warning(pop)
|
||||||
|
|
||||||
|
#include "Utils/Hooking.hpp"
|
||||||
|
|
||||||
|
#include "Game/MP.hpp"
|
||||||
|
#include "Game/SP.hpp"
|
||||||
|
|
||||||
|
// Libraries
|
||||||
|
#pragma comment(lib, "Winmm.lib")
|
||||||
|
#pragma comment(lib, "Crypt32.lib")
|
||||||
|
#pragma comment(lib, "Ws2_32.lib")
|
||||||
|
#pragma comment(lib, "Wininet.lib")
|
||||||
|
#pragma comment(lib, "shlwapi.lib")
|
||||||
|
#pragma comment(lib, "Urlmon.lib")
|
||||||
|
#pragma comment(lib, "Advapi32.lib")
|
||||||
|
#pragma comment(lib, "rpcrt4.lib")
|
||||||
|
#pragma comment(lib, "dbghelp.lib")
|
||||||
|
|
||||||
|
// Enable additional literals
|
||||||
|
using namespace std::literals;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define STRINGIZE_(x) #x
|
||||||
|
#define STRINGIZE(x) STRINGIZE_(x)
|
||||||
|
|
||||||
|
#define AssertSize(x, size) static_assert(sizeof(x) == size, STRINGIZE(x) " structure has an invalid size.")
|
||||||
|
#define AssertOffset(x, y, offset) static_assert(offsetof(x, y) == offset, STRINGIZE(x) "::" STRINGIZE(y) " is not at the right offset.")
|
||||||
|
|
||||||
|
// Resource stuff
|
||||||
|
#ifdef APSTUDIO_INVOKED
|
||||||
|
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||||
|
// Defines below make accessing the resources from the code easier.
|
||||||
|
#define _APS_NEXT_RESOURCE_VALUE 102
|
||||||
|
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||||
|
#define _APS_NEXT_CONTROL_VALUE 1001
|
||||||
|
#define _APS_NEXT_SYMED_VALUE 101
|
||||||
|
#endif
|
||||||
|
#endif
|
256
src/Utils/Hooking.cpp
Normal file
256
src/Utils/Hooking.cpp
Normal file
@ -0,0 +1,256 @@
|
|||||||
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
|
namespace Utils
|
||||||
|
{
|
||||||
|
std::map<void*, void*> Hook::Interceptor::IReturn;
|
||||||
|
std::map<void*, void(*)()> Hook::Interceptor::ICallbacks;
|
||||||
|
|
||||||
|
void Hook::Signature::process()
|
||||||
|
{
|
||||||
|
if (this->signatures.empty()) return;
|
||||||
|
|
||||||
|
char* _start = reinterpret_cast<char*>(this->start);
|
||||||
|
|
||||||
|
unsigned int sigCount = this->signatures.size();
|
||||||
|
Hook::Signature::Container* containers = this->signatures.data();
|
||||||
|
|
||||||
|
for (size_t i = 0; i < this->length; ++i)
|
||||||
|
{
|
||||||
|
char* address = _start + i;
|
||||||
|
|
||||||
|
for (unsigned int k = 0; k < sigCount; ++k)
|
||||||
|
{
|
||||||
|
Hook::Signature::Container* container = &containers[k];
|
||||||
|
|
||||||
|
unsigned int j;
|
||||||
|
for (j = 0; j < strlen(container->mask); ++j)
|
||||||
|
{
|
||||||
|
if (container->mask[j] != '?' &&container->signature[j] != address[j])
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (j == strlen(container->mask))
|
||||||
|
{
|
||||||
|
container->callback(address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hook::Signature::add(Hook::Signature::Container& container)
|
||||||
|
{
|
||||||
|
Hook::Signature::signatures.push_back(container);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hook::Interceptor::Install(void* place, void* stub)
|
||||||
|
{
|
||||||
|
return Hook::Interceptor::Install(place, static_cast<void(*)()>(stub));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hook::Interceptor::Install(void* place, void(*stub)())
|
||||||
|
{
|
||||||
|
return Hook::Interceptor::Install(reinterpret_cast<void**>(place), stub);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hook::Interceptor::Install(void** place, void(*stub)())
|
||||||
|
{
|
||||||
|
Hook::Interceptor::IReturn[place] = *place;
|
||||||
|
Hook::Interceptor::ICallbacks[place] = stub;
|
||||||
|
*place = Hook::Interceptor::InterceptionStub;
|
||||||
|
}
|
||||||
|
|
||||||
|
__declspec(naked) void Hook::Interceptor::InterceptionStub()
|
||||||
|
{
|
||||||
|
__asm
|
||||||
|
{
|
||||||
|
sub esp, 4h // Reserve space on the stack for the return address
|
||||||
|
pushad // Store registers
|
||||||
|
|
||||||
|
lea eax, [esp + 20h] // Load initial stack pointer
|
||||||
|
push eax // Push it onto the stack
|
||||||
|
|
||||||
|
call Hook::Interceptor::RunCallback // Run the callback based on the given stack pointer
|
||||||
|
call Hook::Interceptor::PopReturn // Get the initial return address according to the stack pointer
|
||||||
|
|
||||||
|
add esp, 4h // Clear the stack
|
||||||
|
|
||||||
|
mov [esp + 20h], eax // Store the return address at the reserved space
|
||||||
|
popad // Restore the registers
|
||||||
|
|
||||||
|
retn // Return (jump to our return address)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hook::Interceptor::RunCallback(void* place)
|
||||||
|
{
|
||||||
|
auto iCallback = Hook::Interceptor::ICallbacks.find(place);
|
||||||
|
if (iCallback != Hook::Interceptor::ICallbacks.end())
|
||||||
|
{
|
||||||
|
iCallback->second();
|
||||||
|
Hook::Interceptor::ICallbacks.erase(iCallback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void* Hook::Interceptor::PopReturn(void* _place)
|
||||||
|
{
|
||||||
|
void* retVal = nullptr;
|
||||||
|
|
||||||
|
auto iReturn = Hook::Interceptor::IReturn.find(_place);
|
||||||
|
if (iReturn != Hook::Interceptor::IReturn.end())
|
||||||
|
{
|
||||||
|
retVal = iReturn->second;
|
||||||
|
Hook::Interceptor::IReturn.erase(iReturn);
|
||||||
|
}
|
||||||
|
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
Hook::~Hook()
|
||||||
|
{
|
||||||
|
if (this->initialized)
|
||||||
|
{
|
||||||
|
this->uninstall();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Hook* Hook::initialize(DWORD _place, void(*_stub)(), bool _useJump)
|
||||||
|
{
|
||||||
|
return this->initialize(_place, reinterpret_cast<void*>(_stub), _useJump);
|
||||||
|
}
|
||||||
|
|
||||||
|
Hook* Hook::initialize(DWORD _place, void* _stub, bool _useJump)
|
||||||
|
{
|
||||||
|
return this->initialize(reinterpret_cast<void*>(_place), _stub, _useJump);
|
||||||
|
}
|
||||||
|
|
||||||
|
Hook* Hook::initialize(void* _place, void* _stub, bool _useJump)
|
||||||
|
{
|
||||||
|
if (this->initialized) return this;
|
||||||
|
this->initialized = true;
|
||||||
|
|
||||||
|
this->useJump = _useJump;
|
||||||
|
this->place = _place;
|
||||||
|
this->stub = _stub;
|
||||||
|
|
||||||
|
this->original = static_cast<char*>(this->place) + 5 + *reinterpret_cast<DWORD*>((static_cast<char*>(this->place) + 1));
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Hook* Hook::install(bool unprotect, bool keepUnprotected)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> _(this->stateMutex);
|
||||||
|
|
||||||
|
if (!this->initialized || this->installed)
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->installed = true;
|
||||||
|
|
||||||
|
if (unprotect) VirtualProtect(this->place, sizeof(this->buffer), PAGE_EXECUTE_READWRITE, &this->protection);
|
||||||
|
std::memcpy(this->buffer, this->place, sizeof(this->buffer));
|
||||||
|
|
||||||
|
char* code = static_cast<char*>(this->place);
|
||||||
|
|
||||||
|
*code = static_cast<char>(this->useJump ? 0xE9 : 0xE8);
|
||||||
|
|
||||||
|
*reinterpret_cast<size_t*>(code + 1) = reinterpret_cast<size_t>(this->stub) - (reinterpret_cast<size_t>(this->place) + 5);
|
||||||
|
|
||||||
|
if (unprotect && !keepUnprotected) VirtualProtect(this->place, sizeof(this->buffer), this->protection, &this->protection);
|
||||||
|
|
||||||
|
FlushInstructionCache(GetCurrentProcess(), this->place, sizeof(this->buffer));
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hook::quick()
|
||||||
|
{
|
||||||
|
if (Hook::installed)
|
||||||
|
{
|
||||||
|
Hook::installed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Hook* Hook::uninstall(bool unprotect)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> _(this->stateMutex);
|
||||||
|
|
||||||
|
if (!this->initialized || !this->installed)
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->installed = false;
|
||||||
|
|
||||||
|
if (unprotect) VirtualProtect(this->place, sizeof(this->buffer), PAGE_EXECUTE_READWRITE, &this->protection);
|
||||||
|
|
||||||
|
std::memcpy(this->place, this->buffer, sizeof(this->buffer));
|
||||||
|
|
||||||
|
if (unprotect) VirtualProtect(this->place, sizeof(this->buffer), this->protection, &this->protection);
|
||||||
|
|
||||||
|
FlushInstructionCache(GetCurrentProcess(), this->place, sizeof(this->buffer));
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* Hook::getAddress()
|
||||||
|
{
|
||||||
|
return this->place;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hook::Nop(void* place, size_t length)
|
||||||
|
{
|
||||||
|
DWORD oldProtect;
|
||||||
|
VirtualProtect(place, length, PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||||
|
|
||||||
|
memset(place, 0x90, length);
|
||||||
|
|
||||||
|
VirtualProtect(place, length, oldProtect, &oldProtect);
|
||||||
|
FlushInstructionCache(GetCurrentProcess(), place, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hook::Nop(DWORD place, size_t length)
|
||||||
|
{
|
||||||
|
Nop(reinterpret_cast<void*>(place), length);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hook::SetString(void* place, const char* string, size_t length)
|
||||||
|
{
|
||||||
|
DWORD oldProtect;
|
||||||
|
VirtualProtect(place, length + 1, PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||||
|
|
||||||
|
strncpy_s(static_cast<char*>(place), length, string, length);
|
||||||
|
|
||||||
|
VirtualProtect(place, length + 1, oldProtect, &oldProtect);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hook::SetString(DWORD place, const char* string, size_t length)
|
||||||
|
{
|
||||||
|
Hook::SetString(reinterpret_cast<void*>(place), string, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hook::SetString(void* place, const char* string)
|
||||||
|
{
|
||||||
|
Hook::SetString(place, string, strlen(static_cast<char*>(place)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hook::SetString(DWORD place, const char* string)
|
||||||
|
{
|
||||||
|
Hook::SetString(reinterpret_cast<void*>(place), string);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hook::RedirectJump(void* place, void* stub)
|
||||||
|
{
|
||||||
|
char* operandPtr = static_cast<char*>(place) + 2;
|
||||||
|
int newOperand = reinterpret_cast<int>(stub) - (reinterpret_cast<int>(place) + 6);
|
||||||
|
Utils::Hook::Set<int>(operandPtr, newOperand);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hook::RedirectJump(DWORD place, void* stub)
|
||||||
|
{
|
||||||
|
Hook::RedirectJump(reinterpret_cast<void*>(place), stub);
|
||||||
|
}
|
||||||
|
}
|
185
src/Utils/Hooking.hpp
Normal file
185
src/Utils/Hooking.hpp
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define HOOK_JUMP true
|
||||||
|
#define HOOK_CALL false
|
||||||
|
|
||||||
|
namespace Utils
|
||||||
|
{
|
||||||
|
class Hook
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
class Signature
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct Container
|
||||||
|
{
|
||||||
|
const char* signature;
|
||||||
|
const char* mask;
|
||||||
|
std::function<void(char*)> callback;
|
||||||
|
};
|
||||||
|
|
||||||
|
Signature(void* _start, size_t _length) : start(_start), length(_length) {}
|
||||||
|
Signature(DWORD _start, size_t _length) : Signature(reinterpret_cast<void*>(_start), _length) {}
|
||||||
|
Signature() : Signature(0x400000, 0x800000) {}
|
||||||
|
|
||||||
|
void process();
|
||||||
|
void add(Container& container);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void* start;
|
||||||
|
size_t length;
|
||||||
|
std::vector<Container> signatures;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Interceptor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void Install(void* place, void* stub);
|
||||||
|
static void Install(void* place, void(*stub)());
|
||||||
|
static void Install(void** place, void(*stub)());
|
||||||
|
|
||||||
|
private:
|
||||||
|
static std::map<void*, void*> IReturn;
|
||||||
|
static std::map<void*, void(*)()> ICallbacks;
|
||||||
|
|
||||||
|
static void InterceptionStub();
|
||||||
|
static void RunCallback(void* place);
|
||||||
|
static void* PopReturn(void* place);
|
||||||
|
};
|
||||||
|
|
||||||
|
Hook() : initialized(false), installed(false), place(nullptr), stub(nullptr), original(nullptr), useJump(false), protection(0) { ZeroMemory(this->buffer, sizeof(this->buffer)); }
|
||||||
|
|
||||||
|
Hook(void* place, void* stub, bool useJump = true) : Hook() { this->initialize(place, stub, useJump); }
|
||||||
|
Hook(void* place, void(*stub)(), bool useJump = true) : Hook(place, reinterpret_cast<void*>(stub), useJump) {}
|
||||||
|
|
||||||
|
Hook(DWORD place, void* stub, bool useJump = true) : Hook(reinterpret_cast<void*>(place), stub, useJump) {}
|
||||||
|
Hook(DWORD place, DWORD stub, bool useJump = true) : Hook(reinterpret_cast<void*>(place), reinterpret_cast<void*>(stub), useJump) {}
|
||||||
|
Hook(DWORD place, void(*stub)(), bool useJump = true) : Hook(reinterpret_cast<void*>(place), reinterpret_cast<void*>(stub), useJump) {}
|
||||||
|
|
||||||
|
~Hook();
|
||||||
|
|
||||||
|
Hook* initialize(void* place, void* stub, bool useJump = true);
|
||||||
|
Hook* initialize(DWORD place, void* stub, bool useJump = true);
|
||||||
|
Hook* initialize(DWORD place, void(*stub)(), bool useJump = true); // For lambdas
|
||||||
|
Hook* install(bool unprotect = true, bool keepUnprotected = false);
|
||||||
|
Hook* uninstall(bool unprotect = true);
|
||||||
|
|
||||||
|
void* getAddress();
|
||||||
|
void quick();
|
||||||
|
|
||||||
|
template <typename T> static std::function<T> Call(DWORD function)
|
||||||
|
{
|
||||||
|
return std::function<T>(reinterpret_cast<T*>(function));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> static std::function<T> Call(FARPROC function)
|
||||||
|
{
|
||||||
|
return Call<T>(reinterpret_cast<DWORD>(function));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> static std::function<T> Call(void* function)
|
||||||
|
{
|
||||||
|
return Call<T>(reinterpret_cast<DWORD>(function));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SetString(void* place, const char* string, size_t length);
|
||||||
|
static void SetString(DWORD place, const char* string, size_t length);
|
||||||
|
|
||||||
|
static void SetString(void* place, const char* string);
|
||||||
|
static void SetString(DWORD place, const char* string);
|
||||||
|
|
||||||
|
static void Nop(void* place, size_t length);
|
||||||
|
static void Nop(DWORD place, size_t length);
|
||||||
|
|
||||||
|
static void RedirectJump(void* place, void* stub);
|
||||||
|
static void RedirectJump(DWORD place, void* stub);
|
||||||
|
|
||||||
|
template <typename T> static void Set(void* place, T value)
|
||||||
|
{
|
||||||
|
DWORD oldProtect;
|
||||||
|
VirtualProtect(place, sizeof(T), PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||||
|
|
||||||
|
*static_cast<T*>(place) = value;
|
||||||
|
|
||||||
|
VirtualProtect(place, sizeof(T), oldProtect, &oldProtect);
|
||||||
|
FlushInstructionCache(GetCurrentProcess(), place, sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> static void Set(DWORD place, T value)
|
||||||
|
{
|
||||||
|
return Set<T>(reinterpret_cast<void*>(place), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> static void Xor(void* place, T value)
|
||||||
|
{
|
||||||
|
DWORD oldProtect;
|
||||||
|
VirtualProtect(place, sizeof(T), PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||||
|
|
||||||
|
*static_cast<T*>(place) ^= value;
|
||||||
|
|
||||||
|
VirtualProtect(place, sizeof(T), oldProtect, &oldProtect);
|
||||||
|
FlushInstructionCache(GetCurrentProcess(), place, sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> static void Xor(DWORD place, T value)
|
||||||
|
{
|
||||||
|
return Xor<T>(reinterpret_cast<void*>(place), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> static void Or(void* place, T value)
|
||||||
|
{
|
||||||
|
DWORD oldProtect;
|
||||||
|
VirtualProtect(place, sizeof(T), PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||||
|
|
||||||
|
*static_cast<T*>(place) |= value;
|
||||||
|
|
||||||
|
VirtualProtect(place, sizeof(T), oldProtect, &oldProtect);
|
||||||
|
FlushInstructionCache(GetCurrentProcess(), place, sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> static void Or(DWORD place, T value)
|
||||||
|
{
|
||||||
|
return Or<T>(reinterpret_cast<void*>(place), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> static void And(void* place, T value)
|
||||||
|
{
|
||||||
|
DWORD oldProtect;
|
||||||
|
VirtualProtect(place, sizeof(T), PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||||
|
|
||||||
|
*static_cast<T*>(place) &= value;
|
||||||
|
|
||||||
|
VirtualProtect(place, sizeof(T), oldProtect, &oldProtect);
|
||||||
|
FlushInstructionCache(GetCurrentProcess(), place, sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> static void And(DWORD place, T value)
|
||||||
|
{
|
||||||
|
return And<T>(reinterpret_cast<void*>(place), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> static T Get(void* place)
|
||||||
|
{
|
||||||
|
return *static_cast<T*>(place);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> static T Get(DWORD place)
|
||||||
|
{
|
||||||
|
return Get<T>(reinterpret_cast<void*>(place));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool initialized;
|
||||||
|
bool installed;
|
||||||
|
|
||||||
|
void* place;
|
||||||
|
void* stub;
|
||||||
|
void* original;
|
||||||
|
char buffer[5];
|
||||||
|
bool useJump;
|
||||||
|
|
||||||
|
DWORD protection;
|
||||||
|
|
||||||
|
std::mutex stateMutex;
|
||||||
|
};
|
||||||
|
}
|
BIN
tools/premake5.exe
Normal file
BIN
tools/premake5.exe
Normal file
Binary file not shown.
BIN
tools/protoc.exe
Normal file
BIN
tools/protoc.exe
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user