Skip to content

Commit

Permalink
.def creation support
Browse files Browse the repository at this point in the history
Allows the use of the -d (--def) switch for generating a module definition file instead of a proxy header, along with many other tweaks:
- Files now default to being generated with the same name as the input DLL instead of 'dllforward', along with the proper extension.
- Show the current filename in the usage / help prompt.
- Changes the format with which the export comments are generated in the header files, now displaying the ordinal, export name, and demangled export name.
- Some other tiny formatting changes.
- Added icon resource file configured to add icons to the output binaries when built.
  • Loading branch information
itisluiz committed Nov 29, 2023
1 parent 57d7dfa commit a9b5803
Show file tree
Hide file tree
Showing 12 changed files with 138 additions and 59 deletions.
9 changes: 6 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.21)
project("dllforward" VERSION 1.0 LANGUAGES CXX)
project("dllforward" VERSION 1.1 LANGUAGES CXX)

## QoL definitions
add_compile_definitions(-DPROJECT_VERSION="${PROJECT_VERSION}" -DBUILD_SHARED_LIBS=$<BOOL:${BUILD_SHARED_LIBS}>)
Expand All @@ -22,8 +22,11 @@ file(GLOB_RECURSE PROJECT_SOURCES "src/*.cpp" "src/*.cxx" "src/*.cc")
list(FILTER PROJECT_SOURCES EXCLUDE REGEX "src/main.cc$")
target_sources(${PROJECT_BASE} INTERFACE ${PROJECT_SOURCES})

## Project's resource files
set(PROJECT_RESOURCES "res/app.rc" "res/app.ico")

## Project output, end-product
set(PROJECT_TARGET ${PROJECT_NAME})
# add_library(${PROJECT_TARGET} "src/main.cc")
add_executable(${PROJECT_TARGET} "src/main.cc")
# add_library(${PROJECT_TARGET} "src/main.cc" ${PROJECT_RESOURCES})
add_executable(${PROJECT_TARGET} "src/main.cc" ${PROJECT_RESOURCES})
target_link_libraries(${PROJECT_TARGET} PUBLIC ${PROJECT_BASE})
3 changes: 2 additions & 1 deletion include/builder.hh
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@

namespace fs = std::filesystem;

void buildResult(const fs::path& dllPath, const fs::path& outFile, Architecture architecture, const std::vector<Export>& exports);
void buildResultHeader(const fs::path& dllPath, const fs::path& outFile, Architecture architecture, const std::vector<Export>& exports);
void buildResultDefinition(const fs::path& dllPath, const fs::path& outFile, const std::vector<Export>& exports);
3 changes: 2 additions & 1 deletion include/forwarder.hh
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@

namespace fs = std::filesystem;

bool makeProxy(const fs::path& dllPath, const fs::path& outFile);
bool makeHeader(const fs::path& dllPath, const fs::path& outFile);
bool makeDefinition(const fs::path& dllPath, const fs::path& outFile);
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"// DLL Forward by itisluiz v" PROJECT_VERSION R"(
"// DLLForward by itisluiz v" PROJECT_VERSION R"(
#pragma once
#include <cstdint>
#include <Windows.h>
Expand Down
1 change: 1 addition & 0 deletions include/parser.hh
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@ public:

Architecture parseArchitecture(const fs::path& path);
std::vector<Export> parseExports(const fs::path& path);
std::string parseMangled(const std::string& mangledName);
Binary file added res/app.ico
Binary file not shown.
1 change: 1 addition & 0 deletions res/app.rc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
IDI_ICON1 ICON DISCARDABLE "app.ico"
26 changes: 22 additions & 4 deletions src/builder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,21 @@

#define BUILD_EXPORT_ENTRY(name, ordinal, rva) "{ " << BUILD_EXPORT_IDENTIFIER(ordinal) << ", \"" << name << "\", " << ordinal << ", 0x" << std::hex << rva << std::dec << " }, "

void buildResult(const fs::path& dllPath, const fs::path& outFile, Architecture architecture, const std::vector<Export>& exports)
void buildResultHeader(const fs::path& dllPath, const fs::path& outFile, Architecture architecture, const std::vector<Export>& exports)
{
std::ofstream file(outFile);
file.exceptions(std::ifstream::failbit | std::ifstream::badbit);

file <<
#include <boilerplate/top.inl>
#include <headerboilerplate/top.inl>
<< '\n';

file << "// Proxy header generated for " << dllPath.filename().string() << " (" << (architecture == Architecture::kI386 ? "32" : "64") << " bit)" "\n";
file << "static_assert(sizeof(void*) == " << (architecture == Architecture::kI386 ? 4 : 8) << ", \"The proxied DLL must match the architecture of the proxy DLL\");" "\n\n";

for (const Export& exportEntry : exports)
{
file << "// " << exportEntry << '\n';
file << "// #" << exportEntry.ordinal << ": " << exportEntry.name << " (" << parseMangled(exportEntry.name) << ")" "\n";
file << BUILD_EXPORT_DUMMY(exportEntry.name, exportEntry.ordinal);
}

Expand All @@ -38,7 +38,25 @@ void buildResult(const fs::path& dllPath, const fs::path& outFile, Architecture
file << " };\n";

file << "}\n"
#include <boilerplate/bottom.inl>
#include <headerboilerplate/bottom.inl>
;

}

void buildResultDefinition(const fs::path& dllPath, const fs::path& outFile, const std::vector<Export>& exports)
{
std::ofstream file(outFile);
file.exceptions(std::ifstream::failbit | std::ifstream::badbit);

file << "; DLLForward by itisluiz v" PROJECT_VERSION << '\n';

file << "LIBRARY " << dllPath.filename().replace_extension().string() << '\n';
file << "EXPORTS";

for (const Export& exportEntry : exports)
{
file << "\n" ";\t#" << exportEntry.ordinal << ": " << parseMangled(exportEntry.name) << '\n';
file << '\t' << exportEntry.name << '\n';
}

}
35 changes: 33 additions & 2 deletions src/forwarder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#include <iostream>
#include <fstream>

bool makeProxy(const fs::path& dllPath, const fs::path& outFile)
bool makeHeader(const fs::path& dllPath, const fs::path& outFile)
{
try
{
Expand All @@ -25,7 +25,7 @@ bool makeProxy(const fs::path& dllPath, const fs::path& outFile)
std::cout << '\t' << exportEntry << '\n';
}

buildResult(dllPath, outFile, architecture, exports);
buildResultHeader(dllPath, outFile, architecture, exports);
std::cout << "Generated output at \"" << fs::absolute(outFile).string() << "\"" "\n";
}
catch (const std::system_error& e)
Expand All @@ -41,3 +41,34 @@ bool makeProxy(const fs::path& dllPath, const fs::path& outFile)

return true;
}

bool makeDefinition(const fs::path& dllPath, const fs::path& outFile)
{
try
{
std::vector<Export> exports{ parseExports(dllPath) };

std::cout << "There are " << exports.size() << " exports:" "\n";

for (size_t hint{ 0 }; hint < exports.size(); ++hint)
{
const Export& exportEntry{ exports[hint] };
std::cout << '\t' << exportEntry << '\n';
}

buildResultDefinition(dllPath, outFile, exports);
std::cout << "Generated output at \"" << fs::absolute(outFile).string() << "\"" "\n";
}
catch (const std::system_error& e)
{
std::cerr << e.what() << " [" << e.code() << "]" "\n";
return false;
}
catch (const std::runtime_error& e)
{
std::cerr << e.what() << '\n';
return false;
}

return true;
}
99 changes: 53 additions & 46 deletions src/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,63 +7,70 @@ namespace fs = std::filesystem;

struct ExitCodes
{
enum
{
kSuccess = 0,
kFailed = 1,
kBadArgs = 2
};
enum
{
kSuccess = 0,
kFailed = 1,
kBadArgs = 2
};
};

int main(int argc, char* argv[])
{
cxxopts::Options options("DLLForward", "Generate files for creating a DLL Proxy (Man in the middle) to any other DLL.");
cxxopts::Options options(fs::path(argv[0]).filename().string(), "Generate files for creating a DLL Proxy (Man in the middle) to any other DLL.");

options.add_options()
("i,input", "Input DLL path", cxxopts::value<std::string>(), "The DLL that will be proxied, be mindful of the DLL's architecture/bitness.")
("o,output", "Output header file path", cxxopts::value<std::string>()->default_value("./"), "Output path of the resulting header file used to build the proxy DLL.")
("h,help", "Print usage");
options.add_options()
("i,input", "Input DLL path", cxxopts::value<std::string>(), "The DLL that will be proxied, be mindful of the DLL's architecture/bitness.")
("o,output", "Output header file path", cxxopts::value<std::string>()->default_value("./"), "Output path of the resulting file generated from the input DLL.")
("d,def", "Create a module definition (.def file) instead of a header for proxying.")
("h,help", "Print usage");

options.parse_positional({ "input", "output" });
options.positional_help("input output");
options.show_positional_help();
options.parse_positional({ "input", "output" });
options.positional_help("input output");
options.show_positional_help();

fs::path argInput,argOutput;
try
{
cxxopts::ParseResult result{ options.parse(argc, argv) };
bool argDef;
fs::path argInput,argOutput;
try
{
cxxopts::ParseResult result{ options.parse(argc, argv) };

if (result["help"].count())
{
std::cout << options.help();
return ExitCodes::kSuccess;
}
if (result["help"].count())
{
std::cout << options.help();
return ExitCodes::kSuccess;
}

argInput = result["input"].as<std::string>();
argOutput = result["output"].as<std::string>();
}
catch (const cxxopts::exceptions::exception& e)
{
std::cerr << options.help() << '\n' << e.what();
return ExitCodes::kBadArgs;
}
argInput = result["input"].as<std::string>();
argOutput = result["output"].as<std::string>();
argDef = result["def"].count();
}
catch (const cxxopts::exceptions::exception& e)
{
std::cerr << options.help() << '\n' << e.what();
return ExitCodes::kBadArgs;
}

if (!fs::is_regular_file(argInput))
{
std::cerr << "Invalid input DLL path " << argInput << '\n';
return ExitCodes::kBadArgs;
}
if (!fs::is_regular_file(argInput))
{
std::cerr << "Invalid input DLL path " << argInput << '\n';
return ExitCodes::kBadArgs;
}

if (!fs::is_directory(argOutput.parent_path()))
{
std::cerr << "Invalid output path " << argOutput << '\n';
return ExitCodes::kBadArgs;
}
if (!fs::is_directory(argOutput.parent_path()))
{
std::cerr << "Invalid output path " << argOutput << '\n';
return ExitCodes::kBadArgs;
}

if (fs::is_directory(argOutput))
argOutput /= "dllforwarder.h";
else if (!argOutput.has_extension())
argOutput.replace_extension(".h");
if (fs::is_directory(argOutput))
argOutput /= argInput.filename().replace_extension();

return makeProxy(argInput, argOutput) ? ExitCodes::kSuccess : ExitCodes::kFailed;
if (!argOutput.has_extension())
argOutput.replace_extension(argDef ? ".def" : ".h");

if (argDef)
return makeDefinition(argInput, argOutput) ? ExitCodes::kSuccess : ExitCodes::kFailed;
else
return makeHeader(argInput, argOutput) ? ExitCodes::kSuccess : ExitCodes::kFailed;
}
18 changes: 17 additions & 1 deletion src/parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,27 @@ std::vector<Export> parseExports(const fs::path& path)
char* exportName = reinterpret_cast<char*>(
ImageRvaToVa(LoadedImage.FileHeader, LoadedImage.MappedAddress, dNameRVAs[i], nullptr));

Export exportEntry{ exportName, dOrdinals[i] + 1, static_cast<uint32_t>(dFunctions[dOrdinals[i]]) };
Export exportEntry{ exportName, static_cast<uint16_t>(dOrdinals[i] + 1), static_cast<uint32_t>(dFunctions[dOrdinals[i]]) };
exportVector.push_back(exportEntry);
}
}
UnMapAndLoad(&LoadedImage);

return exportVector;
}

std::string parseMangled(const std::string& mangledName)
{
std::string unmangledName;
unmangledName.resize(512);

DWORD writtenChars{ UnDecorateSymbolName(mangledName.c_str(), unmangledName.data(), static_cast<DWORD>(unmangledName.size()), UNDNAME_COMPLETE) };
if (writtenChars)
{
unmangledName.resize(writtenChars);
unmangledName.shrink_to_fit();
return unmangledName;
}
else
return mangledName;
}

0 comments on commit a9b5803

Please sign in to comment.