feat: add --firewall (#57)

This commit is contained in:
Arsenii es3n1n
2026-08-15 16:37:25 +02:00
committed by GitHub
parent 0c9be5724f
commit 2acdf7724a
7 changed files with 61 additions and 18 deletions

View File

@@ -13,7 +13,7 @@ permissions:
jobs: jobs:
build: build:
runs-on: windows-latest runs-on: windows-2022
strategy: strategy:
matrix: matrix:
platform: [x64, x86, ARM64] platform: [x64, x86, ARM64]

View File

@@ -43,7 +43,7 @@ Download the [latest](https://github.com/es3n1n/defendnot/releases/latest) relea
## Usage ## Usage
```commandline ```commandline
Usage: defendnot-loader [--help] [--version] [--name VAR] [--disable] [--verbose] [--silent] [--autorun-as-user] [--disable-autorun] Usage: defendnot-loader [--help] [--version] [--name VAR] [--disable] [--verbose] [--firewall] [--silent] [--autorun-as-user] [--disable-autorun]
Optional arguments: Optional arguments:
-h, --help prints help message and exits -h, --help prints help message and exits
@@ -51,6 +51,7 @@ Optional arguments:
-n, --name av display name [default: "dnot.sh"] -n, --name av display name [default: "dnot.sh"]
-d, --disable disable defendnot -d, --disable disable defendnot
-v, --verbose verbose logging -v, --verbose verbose logging
--firewall also register a fake firewall
--silent do not allocate console --silent do not allocate console
--autorun-as-user create autorun task as currently logged in user --autorun-as-user create autorun task as currently logged in user
--disable-autorun disable autorun task creation --disable-autorun disable autorun task creation

View File

@@ -6,6 +6,7 @@
#include "shared/util.hpp" #include "shared/util.hpp"
#pragma pack(push, 1)
namespace shared { namespace shared {
constexpr std::size_t kMaxNameLength = 128; constexpr std::size_t kMaxNameLength = 128;
constexpr std::string_view kCtxPath = "ctx.bin"; constexpr std::string_view kCtxPath = "ctx.bin";
@@ -28,6 +29,7 @@ namespace shared {
State state = State::ON; State state = State::ON;
bool verbose = false; bool verbose = false;
std::array<char, kMaxNameLength + 1> name = {0}; // +1 for the nullterm std::array<char, kMaxNameLength + 1> name = {0}; // +1 for the nullterm
bool register_firewall = false;
void serialize() const { void serialize() const {
std::ofstream stream(detail::ctx_path(), std::ios::binary); std::ofstream stream(detail::ctx_path(), std::ios::binary);
@@ -50,3 +52,4 @@ namespace shared {
static_assert(std::is_trivially_copyable_v<Context>); static_assert(std::is_trivially_copyable_v<Context>);
} // namespace shared } // namespace shared
#pragma pack(pop)

View File

@@ -2,6 +2,8 @@
#include <string> #include <string>
#include <string_view> #include <string_view>
#include "shared/ctx.hpp"
#include <Windows.h> #include <Windows.h>
namespace loader { namespace loader {
@@ -16,9 +18,17 @@ namespace loader {
bool disable; bool disable;
bool alloc_console; bool alloc_console;
bool verbose; bool verbose;
bool register_firewall;
bool from_autorun; bool from_autorun;
AutorunType autorun_type; AutorunType autorun_type;
bool enable_autorun; bool enable_autorun;
Config& operator=(const shared::Context& ctx) {
verbose = ctx.verbose;
register_firewall = ctx.register_firewall;
name = ctx.name.data();
return *this;
}
}; };
[[nodiscard]] HANDLE inject(std::string_view dll_path, std::string_view proc_name); [[nodiscard]] HANDLE inject(std::string_view dll_path, std::string_view proc_name);

View File

@@ -25,6 +25,7 @@ namespace {
shared::ctx.state = config.disable ? shared::State::OFF : shared::State::ON; shared::ctx.state = config.disable ? shared::State::OFF : shared::State::ON;
shared::ctx.verbose = config.verbose; shared::ctx.verbose = config.verbose;
shared::ctx.register_firewall = config.register_firewall;
std::ranges::copy(config.name, shared::ctx.name.data()); std::ranges::copy(config.name, shared::ctx.name.data());
/// No need to overwrite ctx if we are called from autorun /// No need to overwrite ctx if we are called from autorun
@@ -100,6 +101,7 @@ int main(int argc, char* argv[]) try {
program.add_argument("-n", "--name").help("av display name").default_value(std::string(strings::kDefaultAVName)).nargs(1); program.add_argument("-n", "--name").help("av display name").default_value(std::string(strings::kDefaultAVName)).nargs(1);
program.add_argument("-d", "--disable").help(std::format("disable {}", strings::kProjectName)).default_value(false).implicit_value(true); program.add_argument("-d", "--disable").help(std::format("disable {}", strings::kProjectName)).default_value(false).implicit_value(true);
program.add_argument("-v", "--verbose").help("verbose logging").default_value(false).implicit_value(true); program.add_argument("-v", "--verbose").help("verbose logging").default_value(false).implicit_value(true);
program.add_argument("--firewall").help("also register a fake firewall").default_value(false).implicit_value(true);
program.add_argument("--silent").help("do not allocate console").default_value(false).implicit_value(true); program.add_argument("--silent").help("do not allocate console").default_value(false).implicit_value(true);
program.add_argument("--autorun-as-user").help("create autorun task as currently logged in user").default_value(false).implicit_value(true); program.add_argument("--autorun-as-user").help("create autorun task as currently logged in user").default_value(false).implicit_value(true);
program.add_argument("--disable-autorun").help("disable autorun task creation").default_value(false).implicit_value(true); program.add_argument("--disable-autorun").help("disable autorun task creation").default_value(false).implicit_value(true);
@@ -120,6 +122,7 @@ int main(int argc, char* argv[]) try {
.disable = program.get<bool>("-d"), .disable = program.get<bool>("-d"),
.alloc_console = !program.get<bool>("--silent"), .alloc_console = !program.get<bool>("--silent"),
.verbose = program.get<bool>("-v"), .verbose = program.get<bool>("-v"),
.register_firewall = program.get<bool>("--firewall"),
.from_autorun = program.get<bool>("--from-autorun"), .from_autorun = program.get<bool>("--from-autorun"),
.autorun_type = program.get<bool>("--autorun-as-user") ? /// As system on boot is the default value .autorun_type = program.get<bool>("--autorun-as-user") ? /// As system on boot is the default value
loader::AutorunType::AS_CURRENT_USER_ON_LOGIN : loader::AutorunType::AS_CURRENT_USER_ON_LOGIN :
@@ -130,7 +133,7 @@ int main(int argc, char* argv[]) try {
/// When running from autorun, we'll be missing all the cli arguments, so lets load some relevant ones /// When running from autorun, we'll be missing all the cli arguments, so lets load some relevant ones
if (config.from_autorun) { if (config.from_autorun) {
shared::ctx.deserialize(); shared::ctx.deserialize();
config.verbose = shared::ctx.verbose; config = shared::ctx;
} }
if (!config.alloc_console && config.verbose) { if (!config.alloc_console && config.verbose) {

View File

@@ -8,27 +8,41 @@
namespace defendnot { namespace defendnot {
namespace { namespace {
void activate(const auto& step, IWscASStatus* inst) {
step("update", inst->UpdateStatus(WSCSecurityProductState::ON, TRUE));
}
void activate(const auto& step, IWscAVStatus4* inst) {
step("update", inst->UpdateStatus(WSCSecurityProductState::ON, TRUE));
step("scan_update", inst->UpdateScanSubstatus(WSCSecurityProductSubStatus::NO_ACTION));
step("settings_update", inst->UpdateSettingsSubstatus(WSCSecurityProductSubStatus::NO_ACTION));
step("prot_update", inst->UpdateProtectionUpdateSubstatus(WSCSecurityProductSubStatus::NO_ACTION));
}
void activate(const auto& step, IWscFWStatus2* inst) {
step("update", inst->UpdateStatus(WSCSecurityProductState::ON));
step("domain_update", inst->UpdateDomainProfileSubstatus(WSCSecurityProductSubStatus::NO_ACTION));
step("private_update", inst->UpdatePrivateProfileSubstatus(WSCSecurityProductSubStatus::NO_ACTION));
step("public_update", inst->UpdatePublicProfileSubstatus(WSCSecurityProductSubStatus::NO_ACTION));
}
template <com::ComObject Ty> template <com::ComObject Ty>
void apply(const std::string_view log_prefix, const BSTR name) { void apply(const std::string_view log_prefix, const BSTR name, const bool should_register) {
/// Get the WSC interface /// Get the WSC interface
auto inst = com::query<Ty>(); auto inst = com::query<Ty>();
/// This can fail if we dont have any products registered so no com_checked /// This can fail if we dont have any products registered so no com::checked
logln("{}_unregister: {:#x}", log_prefix, com::retry_while_pending([&inst]() -> HRESULT { return inst->Unregister(); }) & 0xFFFFFFFF); logln("{}_unregister: {:#x}", log_prefix, com::retry_while_pending([&inst]() -> HRESULT { return inst->Unregister(); }) & 0xFFFFFFFF);
if (shared::ctx.state == shared::State::OFF) { if (!should_register) {
return; return;
} }
/// Register and activate /// Register and activate
logln("{}_register: {:#x}", log_prefix, com::checked(inst->Register(name, name, 0, 0))); const auto step = [&](const std::string_view what, const HRESULT hr) -> void {
logln("{}_update: {:#x}", log_prefix, com::checked(inst->UpdateStatus(WSCSecurityProductState::ON, static_cast<BOOL>(true)))); logln("{}_{}: {:#x}", log_prefix, what, com::checked(hr));
};
/// Update the substatuses, if the interface supports this step("register", inst->Register(name, name, 0, 0));
if constexpr (std::is_same_v<Ty, IWscAVStatus4>) { activate(step, inst.get());
logln("{}_scan_update: {:#x}", log_prefix, com::checked(inst->UpdateScanSubstatus(WSCSecurityProductSubStatus::NO_ACTION)));
logln("{}_settings_update: {:#x}", log_prefix, com::checked(inst->UpdateSettingsSubstatus(WSCSecurityProductSubStatus::NO_ACTION)));
logln("{}_prot_update: {:#x}", log_prefix, com::checked(inst->UpdateProtectionUpdateSubstatus(WSCSecurityProductSubStatus::NO_ACTION)));
}
} }
} // namespace } // namespace
@@ -45,12 +59,14 @@ namespace defendnot {
/// Convert to BSTR /// Convert to BSTR
auto name = SysAllocString(name_w.c_str()); auto name = SysAllocString(name_w.c_str());
defer->void { defer {
SysFreeString(name); SysFreeString(name);
}; };
/// Register our stuff in the WSC interfaces /// Register our stuff in the WSC interfaces
apply<IWscASStatus>("IWscASStatus", name); const bool enabled = shared::ctx.state != shared::State::OFF;
apply<IWscAVStatus4>("IWscAVStatus4", name); apply<IWscASStatus>("IWscASStatus", name, enabled);
apply<IWscAVStatus4>("IWscAVStatus4", name, enabled);
apply<IWscFWStatus2>("IWscFWStatus2", name, enabled && shared::ctx.register_firewall);
} }
} // namespace defendnot } // namespace defendnot

View File

@@ -69,4 +69,14 @@ namespace defendnot {
virtual HRESULT COM_CALLCONV Unregister() = 0; virtual HRESULT COM_CALLCONV Unregister() = 0;
virtual HRESULT COM_CALLCONV UpdateStatus(WSCSecurityProductState state, BOOL unk) = 0; virtual HRESULT COM_CALLCONV UpdateStatus(WSCSecurityProductState state, BOOL unk) = 0;
}; };
class IWscFWStatus2 : public com::IBaseObject<detail::CLSID_WscIsv, detail::IID_IWscFWStatus2> {
public:
virtual HRESULT COM_CALLCONV Register(BSTR path_to_signed_product_exe, BSTR display_name, std::uint32_t, std::uint32_t) = 0;
virtual HRESULT COM_CALLCONV Unregister() = 0;
virtual HRESULT COM_CALLCONV UpdateStatus(WSCSecurityProductState state) = 0;
virtual HRESULT COM_CALLCONV UpdateDomainProfileSubstatus(WSCSecurityProductSubStatus status) = 0;
virtual HRESULT COM_CALLCONV UpdatePrivateProfileSubstatus(WSCSecurityProductSubStatus status) = 0;
virtual HRESULT COM_CALLCONV UpdatePublicProfileSubstatus(WSCSecurityProductSubStatus status) = 0;
};
} // namespace defendnot } // namespace defendnot