diff --git a/CMakeLists.txt b/CMakeLists.txt index e094757..5fd02dc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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=$) @@ -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}) diff --git a/include/builder.hh b/include/builder.hh index 7f30847..9207115 100644 --- a/include/builder.hh +++ b/include/builder.hh @@ -4,4 +4,5 @@ namespace fs = std::filesystem; -void buildResult(const fs::path& dllPath, const fs::path& outFile, Architecture architecture, const std::vector& exports); +void buildResultHeader(const fs::path& dllPath, const fs::path& outFile, Architecture architecture, const std::vector& exports); +void buildResultDefinition(const fs::path& dllPath, const fs::path& outFile, const std::vector& exports); diff --git a/include/forwarder.hh b/include/forwarder.hh index cb24e78..c2f1d54 100644 --- a/include/forwarder.hh +++ b/include/forwarder.hh @@ -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); diff --git a/include/boilerplate/bottom.inl b/include/headerboilerplate/bottom.inl similarity index 100% rename from include/boilerplate/bottom.inl rename to include/headerboilerplate/bottom.inl diff --git a/include/boilerplate/top.inl b/include/headerboilerplate/top.inl similarity index 87% rename from include/boilerplate/top.inl rename to include/headerboilerplate/top.inl index e40d85e..43baebc 100644 --- a/include/boilerplate/top.inl +++ b/include/headerboilerplate/top.inl @@ -1,4 +1,4 @@ -"// DLL Forward by itisluiz v" PROJECT_VERSION R"( +"// DLLForward by itisluiz v" PROJECT_VERSION R"( #pragma once #include #include diff --git a/include/parser.hh b/include/parser.hh index 2357d4a..5d1e943 100644 --- a/include/parser.hh +++ b/include/parser.hh @@ -28,3 +28,4 @@ public: Architecture parseArchitecture(const fs::path& path); std::vector parseExports(const fs::path& path); +std::string parseMangled(const std::string& mangledName); diff --git a/res/app.ico b/res/app.ico new file mode 100644 index 0000000..0fa35f6 Binary files /dev/null and b/res/app.ico differ diff --git a/res/app.rc b/res/app.rc new file mode 100644 index 0000000..80624c3 --- /dev/null +++ b/res/app.rc @@ -0,0 +1 @@ +IDI_ICON1 ICON DISCARDABLE "app.ico" diff --git a/src/builder.cc b/src/builder.cc index c8d04e0..bd7d6f5 100644 --- a/src/builder.cc +++ b/src/builder.cc @@ -9,13 +9,13 @@ #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& exports) +void buildResultHeader(const fs::path& dllPath, const fs::path& outFile, Architecture architecture, const std::vector& exports) { std::ofstream file(outFile); file.exceptions(std::ifstream::failbit | std::ifstream::badbit); file << -#include +#include << '\n'; file << "// Proxy header generated for " << dllPath.filename().string() << " (" << (architecture == Architecture::kI386 ? "32" : "64") << " bit)" "\n"; @@ -23,7 +23,7 @@ void buildResult(const fs::path& dllPath, const fs::path& outFile, Architecture 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); } @@ -38,7 +38,25 @@ void buildResult(const fs::path& dllPath, const fs::path& outFile, Architecture file << " };\n"; file << "}\n" -#include +#include ; } + +void buildResultDefinition(const fs::path& dllPath, const fs::path& outFile, const std::vector& 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'; + } + +} diff --git a/src/forwarder.cc b/src/forwarder.cc index 3fe4542..c254d66 100644 --- a/src/forwarder.cc +++ b/src/forwarder.cc @@ -4,7 +4,7 @@ #include #include -bool makeProxy(const fs::path& dllPath, const fs::path& outFile) +bool makeHeader(const fs::path& dllPath, const fs::path& outFile) { try { @@ -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) @@ -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 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; +} diff --git a/src/main.cc b/src/main.cc index 5e2479d..e23a61d 100644 --- a/src/main.cc +++ b/src/main.cc @@ -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(), "The DLL that will be proxied, be mindful of the DLL's architecture/bitness.") - ("o,output", "Output header file path", cxxopts::value()->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(), "The DLL that will be proxied, be mindful of the DLL's architecture/bitness.") + ("o,output", "Output header file path", cxxopts::value()->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(); - argOutput = result["output"].as(); - } - catch (const cxxopts::exceptions::exception& e) - { - std::cerr << options.help() << '\n' << e.what(); - return ExitCodes::kBadArgs; - } + argInput = result["input"].as(); + argOutput = result["output"].as(); + 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; } diff --git a/src/parser.cc b/src/parser.cc index cdbd8b9..7603c58 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -60,7 +60,7 @@ std::vector parseExports(const fs::path& path) char* exportName = reinterpret_cast( ImageRvaToVa(LoadedImage.FileHeader, LoadedImage.MappedAddress, dNameRVAs[i], nullptr)); - Export exportEntry{ exportName, dOrdinals[i] + 1, static_cast(dFunctions[dOrdinals[i]]) }; + Export exportEntry{ exportName, static_cast(dOrdinals[i] + 1), static_cast(dFunctions[dOrdinals[i]]) }; exportVector.push_back(exportEntry); } } @@ -68,3 +68,19 @@ std::vector parseExports(const fs::path& path) 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(unmangledName.size()), UNDNAME_COMPLETE) }; + if (writtenChars) + { + unmangledName.resize(writtenChars); + unmangledName.shrink_to_fit(); + return unmangledName; + } + else + return mangledName; +}