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:
build:
runs-on: windows-latest
runs-on: windows-2022
strategy:
matrix:
platform: [x64, x86, ARM64]

View File

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

View File

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

View File

@@ -2,6 +2,8 @@
#include <string>
#include <string_view>
#include "shared/ctx.hpp"
#include <Windows.h>
namespace loader {
@@ -16,9 +18,17 @@ namespace loader {
bool disable;
bool alloc_console;
bool verbose;
bool register_firewall;
bool from_autorun;
AutorunType autorun_type;
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);

View File

@@ -25,6 +25,7 @@ namespace {
shared::ctx.state = config.disable ? shared::State::OFF : shared::State::ON;
shared::ctx.verbose = config.verbose;
shared::ctx.register_firewall = config.register_firewall;
std::ranges::copy(config.name, shared::ctx.name.data());
/// 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("-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("--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("--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);
@@ -120,6 +122,7 @@ int main(int argc, char* argv[]) try {
.disable = program.get<bool>("-d"),
.alloc_console = !program.get<bool>("--silent"),
.verbose = program.get<bool>("-v"),
.register_firewall = program.get<bool>("--firewall"),
.from_autorun = program.get<bool>("--from-autorun"),
.autorun_type = program.get<bool>("--autorun-as-user") ? /// As system on boot is the default value
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
if (config.from_autorun) {
shared::ctx.deserialize();
config.verbose = shared::ctx.verbose;
config = shared::ctx;
}
if (!config.alloc_console && config.verbose) {

View File

@@ -8,27 +8,41 @@
namespace defendnot {
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>
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
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);
if (shared::ctx.state == shared::State::OFF) {
if (!should_register) {
return;
}
/// Register and activate
logln("{}_register: {:#x}", log_prefix, com::checked(inst->Register(name, name, 0, 0)));
logln("{}_update: {:#x}", log_prefix, com::checked(inst->UpdateStatus(WSCSecurityProductState::ON, static_cast<BOOL>(true))));
/// Update the substatuses, if the interface supports this
if constexpr (std::is_same_v<Ty, IWscAVStatus4>) {
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)));
}
const auto step = [&](const std::string_view what, const HRESULT hr) -> void {
logln("{}_{}: {:#x}", log_prefix, what, com::checked(hr));
};
step("register", inst->Register(name, name, 0, 0));
activate(step, inst.get());
}
} // namespace
@@ -45,12 +59,14 @@ namespace defendnot {
/// Convert to BSTR
auto name = SysAllocString(name_w.c_str());
defer->void {
defer {
SysFreeString(name);
};
/// Register our stuff in the WSC interfaces
apply<IWscASStatus>("IWscASStatus", name);
apply<IWscAVStatus4>("IWscAVStatus4", name);
const bool enabled = shared::ctx.state != shared::State::OFF;
apply<IWscASStatus>("IWscASStatus", name, enabled);
apply<IWscAVStatus4>("IWscAVStatus4", name, enabled);
apply<IWscFWStatus2>("IWscFWStatus2", name, enabled && shared::ctx.register_firewall);
}
} // namespace defendnot

View File

@@ -69,4 +69,14 @@ namespace defendnot {
virtual HRESULT COM_CALLCONV Unregister() = 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