【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;
}