当前位置: 首页 > news >正文

【C++】:使用ACL给你的文件夹加锁

一、引言

某些业务场景下,我们会在计算机本地磁盘中创建文件夹目录,用于保存跟当前程序相关的业务数据(这很常见);极端情况下,为了防止客户篡改某些配置,我们设置不希望客户可以访问这些文件夹。于是有了如下所示的应用场景:如何给自己的文件夹加锁,并只允许指定的进程访问该文件夹!
如图所示:
在这里插入图片描述
在这里插入图片描述
当然,我们记住一个前提, 所有的安全保护措施都是只防君子,不防小人的!!

二、代码示例

  • 以下代码某些功能待优化,只作为参考使用。
  • ACL使用场景可能需要提权,建议使用管理员权限运行你的进程,或者你的IDE
#include <iostream>
#include <fstream>
#include <string>
#include <windows.h>

#include <windows.h>
#include <aclapi.h>
#include <sddl.h>
#include <iostream>
#include <string>
#include <tlhelp32.h>


#pragma comment(lib, "Advapi32.lib") // Link to Advapi32.lib

// Function to get the SID of a specified user
std::wstring GetUserSID(DWORD processId) {
	HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, processId);
	if (hProcess == NULL) {
		std::cerr << "Failed to open process. Error: " << GetLastError() << std::endl;
		return L"";
	}

	HANDLE hToken;
	if (!OpenProcessToken(hProcess, TOKEN_QUERY, &hToken)) {
		std::cerr << "Failed to open process token. Error: " << GetLastError() << std::endl;
		CloseHandle(hProcess);
		return L"";
	}

	DWORD tokenInfoLength = 0;
	GetTokenInformation(hToken, TokenUser, NULL, 0, &tokenInfoLength);
	PTOKEN_USER pTokenUser = (PTOKEN_USER)LocalAlloc(LPTR, tokenInfoLength);
	if (!GetTokenInformation(hToken, TokenUser, pTokenUser, tokenInfoLength, &tokenInfoLength)) {
		std::cerr << "Failed to get token information. Error: " << GetLastError() << std::endl;
		LocalFree(pTokenUser);
		CloseHandle(hToken);
		CloseHandle(hProcess);
		return L"";
	}

	LPWSTR sidString;
	if (ConvertSidToStringSidW(pTokenUser->User.Sid, &sidString)) {
		std::wstring result(sidString);
		LocalFree(sidString); // Free the string allocated by ConvertSidToStringSid
		LocalFree(pTokenUser);
		CloseHandle(hToken);
		CloseHandle(hProcess);
		return result; // Return the SID as a string
	}
	else {
		std::cerr << "Failed to convert SID to string. Error: " << GetLastError() << std::endl;
		LocalFree(pTokenUser);
		CloseHandle(hToken);
		CloseHandle(hProcess);
		return L"";
	}
}

// Function to set directory access
void SetDirectoryAccess(const std::string& directoryPath, DWORD processId) {
	// Convert the directory path to a wide string
	std::wstring wDirectoryPath(directoryPath.begin(), directoryPath.end());

	// Create a security descriptor
	PSECURITY_DESCRIPTOR pSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
	if (pSD == nullptr) {
		std::cerr << "Failed to allocate memory for security descriptor." << std::endl;
		return;
	}

	// Initialize the security descriptor
	if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION)) {
		std::cerr << "Failed to initialize security descriptor." << std::endl;
		LocalFree(pSD);
		return;
	}

	// Get the SID for the allowed process
	std::wstring sidString = GetUserSID(processId); // Get the SID for the allowed process
	if (sidString.empty()) {
		std::cerr << "Failed to retrieve SID for the allowed process." << std::endl;
		LocalFree(pSD);
		return;
	}

	PSID pSID = nullptr;
	if (!ConvertStringSidToSid(sidString.c_str(), &pSID)) {
		std::cerr << "Failed to convert SID string to SID." << std::endl;
		LocalFree(pSD);
		return;
	}

	// Create an access mask
	DWORD accessMask = GENERIC_READ | GENERIC_WRITE; // Allow read and write access

	// Create an access control entry for the allowed process
	EXPLICIT_ACCESS ea;
	ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS)); // Initialize the structure to zero
	ea.grfAccessPermissions = accessMask; // Set the access permissions
	ea.grfAccessMode = SET_ACCESS; // Set the access mode
	ea.grfInheritance = NO_INHERITANCE; // No inheritance
	ea.Trustee.TrusteeForm = TRUSTEE_IS_SID; // The trustee is a SID
	ea.Trustee.TrusteeType = TRUSTEE_IS_USER; // The trustee is a user
	ea.Trustee.ptstrName = (LPWSTR)pSID; // Set the SID

	PACL pACL = nullptr;
	// Call SetEntriesInAcl with the correct parameters
	if (SetEntriesInAcl(1, &ea, NULL, &pACL) != ERROR_SUCCESS) {
		std::cerr << "Failed to set entries in ACL." << std::endl;
		LocalFree(pSID);
		LocalFree(pSD);
		return;
	}

	// Create an access control entry for denying access to everyone
	EXPLICIT_ACCESS denyAccess;
	ZeroMemory(&denyAccess, sizeof(EXPLICIT_ACCESS)); // Initialize the structure to zero
	denyAccess.grfAccessPermissions = GENERIC_ALL; // Deny all access
	denyAccess.grfAccessMode = DENY_ACCESS; // Set the access mode to deny
	denyAccess.grfInheritance = NO_INHERITANCE; // No inheritance
	denyAccess.Trustee.TrusteeForm = TRUSTEE_IS_NAME; // The trustee is a well-known group
	denyAccess.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; // The trustee is a group
	denyAccess.Trustee.ptstrName = (LPWSTR)L"Everyone"; // Deny access to everyone

	// Add the deny entry to the ACL
	PACL pNewACL = nullptr;
	if (SetEntriesInAcl(1, &denyAccess, pACL, &pNewACL) != ERROR_SUCCESS) {
		std::cerr << "Failed to set deny entry in ACL." << std::endl;
		LocalFree(pSID);
		LocalFree(pSD);
		return;
	}

	// Set the DACL in the security descriptor
	if (!SetSecurityDescriptorDacl(pSD, TRUE, pNewACL, FALSE)) {
		std::cerr << "Failed to set DACL in security descriptor." << std::endl;
		LocalFree(pSID);
		LocalFree(pSD);
		return;
	}

	// Apply the security descriptor to the directory
	if (SetNamedSecurityInfoW((LPWSTR)wDirectoryPath.c_str(),
		SE_FILE_OBJECT,
		DACL_SECURITY_INFORMATION, NULL, NULL, pNewACL, NULL) != ERROR_SUCCESS) {
		DWORD error = GetLastError(); // Get the last error code
		std::cerr << "Failed to set security info on directory. Error code: " << error << std::endl;
	}
	else {
		std::cout << "Successfully set security info on directory." << std::endl;
	}

	// Clean up
	LocalFree(pSID);
	LocalFree(pSD);
}

DWORD GetProcessIdByName(const std::wstring& processName) {
	HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
	if (hSnapshot == INVALID_HANDLE_VALUE) {
		return 0;
	}

	PROCESSENTRY32W pe32;
	pe32.dwSize = sizeof(PROCESSENTRY32W);

	if (Process32FirstW(hSnapshot, &pe32)) {
		do {
			if (processName == pe32.szExeFile) {
				CloseHandle(hSnapshot);
				return pe32.th32ProcessID;
			}
		} while (Process32NextW(hSnapshot, &pe32));
	}

	CloseHandle(hSnapshot);
	return 0; // Process not found
}

bool test_read() {
	std::string filePath = "D:\\Video\\ProtectedDirectory\\test_file.txt";
	std::ifstream inFile(filePath);
	if (!inFile) {
		std::cerr << "Error: Could not create file at " << filePath << std::endl;
		return false;
	}
	std::string s;
	inFile >> s;
	inFile.close();

	std::cout << "File read successfully at " << filePath << ":" << s << std::endl;
	return true;
}

bool test_write() {
	std::string filePath = "D:\\Video\\ProtectedDirectory\\test_file.txt";
	std::ofstream outFile(filePath);
	if (!outFile) {
		std::cerr << "Error: Could not create file at " << filePath << std::endl;
		return false;
	}
	outFile << "hello,world!" << std::endl;
	outFile.close();

	std::cout << "File read successfully at " << filePath << std::endl;
	return true;
}

bool EnablePrivilege(LPCWSTR privilege) {
	HANDLE token;
	TOKEN_PRIVILEGES tp;
	LUID luid;

	if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) {
		std::cerr << "Failed to open process token. Error: " << GetLastError() << std::endl;
		return false;
	}

	if (!LookupPrivilegeValueW(NULL, privilege, &luid)) {
		std::cerr << "Failed to lookup privilege value. Error: " << GetLastError() << std::endl;
		CloseHandle(token);
		return false;
	}

	tp.PrivilegeCount = 1;
	tp.Privileges[0].Luid = luid;
	tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

	if (!AdjustTokenPrivileges(token, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL)) {
		std::cerr << "Failed to adjust token privileges. Error: " << GetLastError() << std::endl;
		CloseHandle(token);
		return false;
	}

	CloseHandle(token);
	return GetLastError() == ERROR_SUCCESS;
}



int main() {
	std::string directoryPath = "D:\\Video\\ProtectedDirectory1"; // Specify the directory path
	std::wstring allowedProcessName = L"ConsoleApplication1.exe"; // Specify the allowed process name

	// Enable the SE_RESTORE_NAME privilege
	if (!EnablePrivilege(SE_RESTORE_NAME)) {
		std::cerr << "Failed to enable privilege." << std::endl;
		return 1;
	}

	// Create the directory if it does not exist
	if (CreateDirectoryA(directoryPath.c_str(), NULL) || GetLastError() == ERROR_ALREADY_EXISTS) {
		// Set the directory as hidden
		if (!SetFileAttributesA(directoryPath.c_str(), FILE_ATTRIBUTE_HIDDEN)) {
			DWORD error = GetLastError();
			std::cerr << "Failed to set directory attributes. Error: " << error << std::endl;
			// Handle specific errors
			if (error == ERROR_ACCESS_DENIED) {
				std::cerr << "Access denied. Please check your permissions." << std::endl;
			}
			else if (error == ERROR_FILE_NOT_FOUND) {
				std::cerr << "File not found. Please check the path." << std::endl;
			}
			// Add more error handling as needed
		}
		else {
			std::cout << "Directory attributes set to hidden successfully." << std::endl;
		}
	}
	else {
		std::cerr << "Failed to create directory. Error: " << GetLastError() << std::endl;
		return 1;
	}


	// Get the process ID of the allowed process
	DWORD processId = GetProcessIdByName(allowedProcessName);
	if (processId == 0) {
		std::wcerr << "Process not found: " << allowedProcessName << std::endl;
		return 1; // Exit if the process is not found
	}

	SetDirectoryAccess(directoryPath, processId);

	// 测试
	test_read();

	return 0;
}

相关文章:

  • 直线画法-Bresenham‘s algorithm原理和最优实现
  • SSRF 攻击与防御:从原理到落地实践
  • 什么是Ecovadis认证(埃科瓦迪斯认证)?​Ecovadis认证(埃科瓦迪斯认证)的等级划分!
  • 【Zephyr】【二】学习笔记【RTOS系统架构】
  • VLAN综合实验
  • Linux|fork命令及其使用的写时拷贝技术
  • HyperAD:学习弱监督音视频暴力检测在双曲空间中的方法
  • id: ‘dev.flutter.flutter-plugin-loader‘, version: ‘1.0.0‘怎么解决
  • The Illustrated Stable Diffusion
  • [贪心算法]买卖股票的最佳时机 买卖股票的最佳时机Ⅱ K次取反后最大化的数组和 按身高排序 优势洗牌(田忌赛马)
  • 基础篇结束纪念——Java抽象类 模板类 static接口
  • 基于springboot的校园周边美食探索及分享平台(021)
  • 基于生成对抗网络(GAN)的图像超分辨率重建:技术与应用
  • 【深度】JADC2的层级结构以及全域Mesh网络
  • K8S集群新增和删除Node节点(K8s Cluster Adds and Removes Node Nodes)
  • 【动态规划】矩阵连乘问题 C++(附代码实例和复杂度分析)
  • 3. 轴指令(omron 机器自动化控制器)——>MC_SetOverride
  • react 常用插件
  • axios 请求的底层依赖是什么?
  • 系统思考—啤酒游戏经营决策沙盘模拟
  • 做贸易的都有什么网站/南安网站建设
  • 移动互联网技术就业前景/郑州seo顾问
  • 武汉建站网站公司/提高工作效率英语
  • 海阔天空网站建设/如何制作网页广告
  • 申请个网站/郑州网站排名优化公司
  • 做美女网站有哪些/线上推广的渠道和方法