Skip to content

Instantly share code, notes, and snippets.

@vadimpiven
Last active October 29, 2023 16:48
Show Gist options
  • Save vadimpiven/0f6e50474eee21909026a3a5c7abf1ce to your computer and use it in GitHub Desktop.
Save vadimpiven/0f6e50474eee21909026a3a5c7abf1ce to your computer and use it in GitHub Desktop.
Executable self delete (WinAPI, C++ 17) - works only if executable is located on NTFS partition
// SPDX-License-Identifier: MIT
// MIT Software License: https://opensource.org/licenses/MIT
// Copyright Vadim Piven <[email protected]>
#include <Windows.h>
#include <algorithm>
#include <array>
#include <cstddef>
#include <filesystem>
#include <iostream>
#include <iterator>
#include <memory>
#include <stdexcept>
#include <string>
#include <vector>
namespace {
[[nodiscard]] inline std::filesystem::path GetExecutablePath()
{
std::vector<wchar_t> path(MAX_PATH);
while (!::GetModuleFileNameW(nullptr, path.data(), static_cast<DWORD>(path.size())))
path.resize(2 * path.size());
return {path.data()};
}
inline void UnbindNtfsDataStream(const std::filesystem::path & path)
{
auto const handle = ::CreateFileW(path.c_str(), DELETE | SYNCHRONIZE, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr);
if (INVALID_HANDLE_VALUE == handle)
throw std::runtime_error("CreateFileW failed, error: " + std::to_string(::GetLastError()));
const auto file = std::unique_ptr<void, decltype(&::CloseHandle)>(handle, &::CloseHandle);
constexpr wchar_t const Label[]{L":UNBOUND"};
std::array<std::byte, sizeof(FILE_RENAME_INFO) + sizeof(Label)> info{};
auto renameInfo = new(info.data()) FILE_RENAME_INFO({.FileNameLength = sizeof(Label) - sizeof(L'\0')});
std::copy(std::begin(Label), std::end(Label), std::begin(renameInfo->FileName));
if (!::SetFileInformationByHandle(file.get(), FileRenameInfo, renameInfo, static_cast<DWORD>(info.size())))
throw std::runtime_error("SetFileInformationByHandle failed, error: " + std::to_string(::GetLastError()));
}
} // namespace
void TryDeleteExecutable() noexcept
{
try
{
const auto path = GetExecutablePath();
UnbindNtfsDataStream(path);
std::filesystem::remove(path);
}
catch (const std::exception & err)
{
std::clog << err.what();
}
}
@vadimpiven
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment