The solution, as far as I've understood it, is to add a security descriptor, so I worked along the example given here. At first I thought I would just deny access to NT AUTHORITY\NETWORK, but the problem is that once you set up a security descriptor, everything goes from allowed by default to denied by default, so that essentially broke my application. My solution was to allow only the user the process is running under, and deny NT AUTHORITY\NETWORK.
Full disclosure: I am by no means an expert on this, so I am not (yet) marking it as the accepted answer, since I am anything other than sure that this actually seals it up. But from what I've read, it should. Please let me know if I got something wrong, or if everything is right and I can mark this as the accepted answer.
Essentially, I ended up adding this before the code above:
HANDLE processToken;
//get Token of the process this is running in
OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &processToken);
PSID currentUser;
// GetLogonSID method from https://learn.microsoft.com/en-us/previous-versions//aa446670(v=vs.85)
GetLogonSID(processToken, ¤tUser);
EXPLICIT_ACCESS ea[2];
//give the user the process is running under read and write access
ea[0].grfAccessPermissions = GENERIC_WRITE | GENERIC_READ;
ea[0].grfAccessMode = SET_ACCESS;
ea[0].grfInheritance = INHERIT_NO_PROPAGATE;
ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea[0].Trustee.TrusteeType = TRUSTEE_IS_USER;
ea[0].Trustee.ptstrName = (LPTSTR)currentUser;
PSID network;
//Initialize NT AUTHORITY\SYSTEM and deny all rights
SID_IDENTIFIER_AUTHORITY sidNTAUTHORITY = SECURITY_NT_AUTHORITY;
AllocateAndInitializeSid(
&sidNTAUTHORITY,
1,
SECURITY_NETWORK_RID,
0, 0, 0, 0, 0, 0, 0,
&network
);
ea[1].grfAccessPermissions = STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL;
ea[1].grfAccessMode = DENY_ACCESS;
ea[1].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea[1].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
ea[1].Trustee.ptstrName = (LPTSTR)network;
//set the entries and create the security descriptor
PACL pACL = NULL;
SetEntriesInAcl(2, ea, NULL, &pACL);
PSECURITY_DESCRIPTOR descriptor = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
InitializeSecurityDescriptor(descriptor, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(descriptor, TRUE, pACL, FALSE);
Once that is taken care of, the descriptor can then be set as the lpSecurityDescriptor
member of SECURITY_ATTRIBUTES
:
SECURITY_ATTRIBUTES attr;
attr.nLength = sizeof(SECURITY_ATTRIBUTES);
attr.lpSecurityDescriptor = descriptor;
attr.bInheritHandle = TRUE;
(If anyone is interested in the full working code or if I should post it as part of the answer, please let me know)