I have used the same plain text, same public key, but get different result in Wincrypt and openssl.
My enviroment is win7 64bit and VS 2010 and openssl 1.1.1S.
here is the code:
/*
* An example of using PEM encoded RSA private keys with CAPI
* - Modified on March 29th 2014 to show how to use PEM encoded RSA public key
*
* Copyright (c) 2012 Mounir IDRASSI <mounir.idrassi#idrix.fr>. All rights reserved.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE.
*
*/
//
//#ifndef _WIN32_WINNT
//#define _WIN32_WINNT 0x0501
//#endif
//
//#include <windows.h>
//#include <wincrypt.h>
//#include <stdio.h>
//
//#pragma comment(lib, "Crypt32.lib")
//
//const char* szPemPrivKey =
// "-----BEGIN RSA PRIVATE KEY-----"
// "MIICXAIBAAKBgQCf6YAJOSBYPve1jpYDzq+w++8YVoATI/YCi/RKZaQk+l2ZfoUQ"
// "g0qrYrfkzeoOa/qd5VLjTTvHEgwXnlDXMfo+vSgxosUxDOZXMTBqJGOViv5K2QBv"
// "k8A1wi4k8tuo/7OWya29HvcfavUk3YXaV2YFe8V6ssaZjNcVWmDdjqNkXwIDAQAB"
// "AoGALrd+ijNAOcebglT3ioE1XpUbUpbir7TPyAqvAZUUESF7er41jY9tnwgmBRgL"
// "Cs+M1dgLERCdKBkjozrDDzswifFQmq6PrmYrBkFFqCoLJwepSYdWnK1gbZ/d43rR"
// "2sXzSGZngscx0CxO7KZ7xUkwENGd3+lKXV7J6/vgzJ4XnkECQQDTP6zWKT7YDckk"
// "We04hbhHyBuNOW068NgUUvoZdBewerR74MJx6nz28Tp+DeNvc0EveiQxsEnbV8u+"
// "NRkX5y0xAkEAwcnEAGBn5kJd6SpU0ALA9XEpUv7tHTAGQYgCRbfTT59hhOq6I22A"
// "ivjOCNG9c6E7EB2kcPVGuCpYUhy7XBIGjwJAK5lavKCqncDKoLwGn8HJdNcyCIWv"
// "q5iFoDw37gTt1ricg2yx9PzmabkDz3xiUmBBNeFJkw/FToXiQRGIakyGIQJAJIem"
// "PPPvYgZssYFbT4LVYO8d/Rk1FWVyKHQ9CWtnmADRXz7oK7l+m7PfEuaGsf9YpOcR"
// "koGJ/TluQLxNzUNQnQJBAImwr/yYFenIx3HQ6UX/fCt6qpGDv0VfOLyR64MNeegx"
// "o7DhNxHbFkIGzk4lKhMKcHKDrawZbdJtS9ie2geSwVQ="
// "-----END RSA PRIVATE KEY-----";
//
//const char* szPemPubKey =
// "-----BEGIN RSA PUBLIC KEY-----"
// "MIGJAoGBAJ/pgAk5IFg+97WOlgPOr7D77xhWgBMj9gKL9EplpCT6XZl+hRCDSqti"
// "t+TN6g5r+p3lUuNNO8cSDBeeUNcx+j69KDGixTEM5lcxMGokY5WK/krZAG+TwDXC"
// "LiTy26j/s5bJrb0e9x9q9STdhdpXZgV7xXqyxpmM1xVaYN2Oo2RfAgMBAAE="
// "-----END RSA PUBLIC KEY-----";
//
//const char* szDataToSign = "Data to be signed by the private key";
//
//
//
//
//
//int main(int argc, char* argv[])
//{
// DWORD dwBufferLen = 0, cbKeyBlob = 0, cbSignature = 0,i;
// LPBYTE pbBuffer = NULL, pbKeyBlob = NULL, pbSignature = NULL;
// HCRYPTPROV hProv = NULL;
// HCRYPTKEY hKey = NULL;
// HCRYPTHASH hHash = NULL;
//
// if (!CryptStringToBinaryA(szPemPrivKey, 0, CRYPT_STRING_BASE64HEADER, NULL, &dwBufferLen, NULL, NULL))
// {
// printf("Failed to convert BASE64 private key. Error 0x%.8X\n", GetLastError());
// goto main_exit;
// }
//
// pbBuffer = (LPBYTE) LocalAlloc(0, dwBufferLen);
// if (!CryptStringToBinaryA(szPemPrivKey, 0, CRYPT_STRING_BASE64HEADER, pbBuffer, &dwBufferLen, NULL, NULL))
// {
// printf("Failed to convert BASE64 private key. Error 0x%.8X\n", GetLastError());
// goto main_exit;
// }
//
// if (!CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, PKCS_RSA_PRIVATE_KEY, pbBuffer, dwBufferLen, 0, NULL, NULL, &cbKeyBlob))
// {
// printf("Failed to parse private key. Error 0x%.8X\n", GetLastError());
// goto main_exit;
// }
//
// pbKeyBlob = (LPBYTE) LocalAlloc(0, cbKeyBlob);
// if (!CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, PKCS_RSA_PRIVATE_KEY, pbBuffer, dwBufferLen, 0, NULL, pbKeyBlob, &cbKeyBlob))
// {
// printf("Failed to parse private key. Error 0x%.8X\n", GetLastError());
// goto main_exit;
// }
//
// // Create a temporary and volatile CSP context in order to import
// // the key and use for signing
// if (!CryptAcquireContext(&hProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
// {
// printf("CryptAcquireContext failed with error 0x%.8X\n", GetLastError());
// goto main_exit;
// }
//
// if (!CryptImportKey(hProv, pbKeyBlob, cbKeyBlob, NULL, 0, &hKey))
// {
// printf("CryptImportKey for private key failed with error 0x%.8X\n", GetLastError());
// goto main_exit;
// }
//
// // Hash the data
// if (!CryptCreateHash(hProv, CALG_SHA1, NULL, 0, &hHash))
// {
// printf("CryptCreateHash failed with error 0x%.8X\n", GetLastError());
// goto main_exit;
// }
//
// if (!CryptHashData(hHash, (LPCBYTE) szDataToSign, strlen(szDataToSign), 0))
// {
// printf("CryptHashData failed with error 0x%.8X\n", GetLastError());
// goto main_exit;
// }
//
// // Sign the hash using our imported key
// if (!CryptSignHash(hHash, AT_KEYEXCHANGE, NULL, 0, NULL, &cbSignature))
// {
// printf("CryptSignHash failed with error 0x%.8X\n", GetLastError());
// goto main_exit;
// }
//
// pbSignature = (LPBYTE) LocalAlloc(0, cbSignature);
// if (!CryptSignHash(hHash, AT_KEYEXCHANGE, NULL, 0, pbSignature, &cbSignature))
// {
// printf("CryptSignHash failed with error 0x%.8X\n", GetLastError());
// goto main_exit;
// }
//
// printf("Signature = ");
// for (i = 0; i < cbSignature; i++)
// {
// printf("%.2X", pbSignature[i]);
// }
// printf("\n\n");
//
// /***************************************************
// * Import the public key and verify the signature
// ***************************************************/
//
// if (!CryptStringToBinaryA(szPemPubKey, 0, CRYPT_STRING_BASE64HEADER, NULL, &dwBufferLen, NULL, NULL))
// {
// printf("Failed to convert BASE64 public key. Error 0x%.8X\n", GetLastError());
// goto main_exit;
// }
//
// LocalFree(pbBuffer);
// pbBuffer = (LPBYTE) LocalAlloc(0, dwBufferLen);
// if (!CryptStringToBinaryA(szPemPubKey, 0, CRYPT_STRING_BASE64HEADER, pbBuffer, &dwBufferLen, NULL, NULL))
// {
// printf("Failed to convert BASE64 public key. Error 0x%.8X\n", GetLastError());
// goto main_exit;
// }
//
// if (!CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, RSA_CSP_PUBLICKEYBLOB, pbBuffer, dwBufferLen, 0, NULL, NULL, &cbKeyBlob))
// {
// printf("Failed to parse public key. Error 0x%.8X\n", GetLastError());
// goto main_exit;
// }
//
// LocalFree(pbKeyBlob);
// pbKeyBlob = (LPBYTE) LocalAlloc(0, cbKeyBlob);
// if (!CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, RSA_CSP_PUBLICKEYBLOB, pbBuffer, dwBufferLen, 0, NULL, pbKeyBlob, &cbKeyBlob))
// {
// printf("Failed to parse public key. Error 0x%.8X\n", GetLastError());
// goto main_exit;
// }
//
// CryptDestroyHash(hHash);
// CryptDestroyKey(hKey);
// CryptReleaseContext(hProv, 0);
//
// if (!CryptAcquireContext(&hProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
// {
// printf("CryptAcquireContext failed with error 0x%.8X\n", GetLastError());
// goto main_exit;
// }
//
// if (!CryptImportKey(hProv, pbKeyBlob, cbKeyBlob, NULL, 0, &hKey))
// {
// printf("CryptImportKey for public key failed with error 0x%.8X\n", GetLastError());
// goto main_exit;
// }
//
// // Hash the data
// if (!CryptCreateHash(hProv, CALG_SHA1, NULL, 0, &hHash))
// {
// printf("CryptCreateHash failed with error 0x%.8X\n", GetLastError());
// goto main_exit;
// }
//
// if (!CryptHashData(hHash, (LPCBYTE) szDataToSign, strlen(szDataToSign), 0))
// {
// printf("CryptHashData failed with error 0x%.8X\n", GetLastError());
// goto main_exit;
// }
//
// // Sign the hash using our imported key
// if (!CryptVerifySignature(hHash, pbSignature, cbSignature, hKey, NULL, 0))
// {
// printf("Signature verification failed with error 0x%.8X\n", GetLastError());
// goto main_exit;
// }
//
// printf("Signature verified successfully!\n\n");
//
//main_exit:
// if (pbBuffer) LocalFree(pbBuffer);
// if (pbKeyBlob) LocalFree(pbKeyBlob);
// if (pbSignature) LocalFree(pbSignature);
// if (hHash) CryptDestroyHash(hHash);
// if (hKey) CryptDestroyKey(hKey);
// if (hProv) CryptReleaseContext(hProv, 0);
//
// system("pause");
// return 0;
//}
#include <stdio.h>
#include <string>
//openssl
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/sha.h>
#include <openssl/crypto.h>
#pragma comment(lib, "libcrypto.lib")
#pragma comment(lib, "libssl.lib")
#pragma comment(lib, "ws2_32.lib")
int main()
{
FILE *fp = NULL;
RSA *pubRsa = NULL;
unsigned char buf[128] = { 0 };
int nOutLen = sizeof(buf);
char * p_KeyPath = "D:/PublicKey.pem";
printf("PublicKeyPath[%s]\n", p_KeyPath);
/* 打开密钥文件 */
if (NULL == (fp = fopen(p_KeyPath, "r")))
{
printf("fopen[%s] \n", p_KeyPath);
return NULL;
}
/* 获取公钥 */
if (NULL == (pubRsa = PEM_read_RSA_PUBKEY(fp, NULL, NULL, NULL)))
{
printf("PEM_read_RSA_PUBKEY error\n");
fclose(fp);
return NULL;
}
fclose(fp);
char * message = "BFEBFBFF000906E9:L1HF73P055S";
unsigned char md[SHA256_DIGEST_LENGTH];
SHA256((unsigned char *)message, strlen(message), md);
int nRet = RSA_verify(NID_sha256, md, SHA256_DIGEST_LENGTH, buf, nOutLen, pubRsa);
if (nRet != 1)
{
printf("RSA_verify err !!! \n");
}
printf("RSA_verify Success !!! \n");
system("pause");
return 0;
}
The wincrypt method is commented. and the openssl method is presented. you can toggle the comment to reproduce both results.
PS: I don't have the public pem directly. I converted the xml file to pem by BouncyCastle.Crypto API in C#.
The original xml public key is
<RSAKeyValue><Modulus>wz1A5Neh5XiRPa+FDdqpVxQGpNSoz4GWj4D4iYC1w4Lf8quQ73iz8iHz9x+U/Ep+EJtdQyBCOveT0999uQuvH6/GDIAX9QXr5+uE7Koxbh680hCMqDE7DP3VR2UVzluVLVVqfdSQZIFad5+xKAnpgVHBWFxPgRjijHSDHnHnEVU=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>
Related
I'm trying to create a elevated SYSTEM token, but the code below fails:
#include <windows.h>
#include <stdio.h>
BOOL Elevate()
{
PSID pSID = NULL;
HANDLE hToken = NULL, hToken2 = NULL;
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken))
{
fprintf(stderr, "OpenProcessToken(): %d\n", GetLastError());
goto done;
}
if (!DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL, SecurityImpersonation, TokenPrimary, &hToken2))
{
fprintf(stderr, "DuplicateTokenEx(): %d\n", GetLastError());
goto done;
}
if (!AllocateAndInitializeSid(
&NtAuthority,
1,
SECURITY_MANDATORY_SYSTEM_RID,
0,
0, 0, 0, 0, 0, 0,
&pSID))
{
fprintf(stderr, "AllocateAndInitializeSid(): %d\n", GetLastError());
goto done;
}
if (!SetTokenInformation(hToken2, TokenIntegrityLevel, &pSID, sizeof(pSID)))
{
fprintf(stderr, "SetTokenInformation(): %d\n", GetLastError());
goto done;
}
done:
if (pSID)
{
FreeSid(pSID);
pSID = NULL;
}
CloseHandle(hToken);
CloseHandle(hToken2);
return TRUE;
}
int main(int argc, char** argv)
{
Elevate();
}
It fails on SetTokenInformation, and the error code is 24: ERROR_BAD_LENGTH. Does anyone know what's wrong?
EDIT
Remy Lebeau was right, and I found an example here: https://wiki.sei.cmu.edu/confluence/display/c/WIN02-C.+Restrict+privileges+when+spawning+child+processes
Per the TOKEN_INFORMATION_CLASS documentation
TokenIntegrityLevel
The buffer receives a TOKEN_MANDATORY_LABEL structure that specifies the token's integrity level.
Where TOKEN_MANDATORY_LABEL is defined as:
typedef struct _SID_AND_ATTRIBUTES {
#if ...
PISID Sid;
#else
PSID Sid;
#endif
DWORD Attributes;
} SID_AND_ATTRIBUTES, *PSID_AND_ATTRIBUTES;
typedef struct _TOKEN_MANDATORY_LABEL {
SID_AND_ATTRIBUTES Label;
} TOKEN_MANDATORY_LABEL, *PTOKEN_MANDATORY_LABEL;
So, you need to give SetTokenInformation() a pointer to a TOKEN_MANDATORY_LABEL, not a pointer to a SID, eg:
#include <windows.h>
#include <stdio.h>
BOOL Elevate()
{
TOKEN_MANDATORY_LABEL tml = {};
HANDLE hToken = NULL, hToken2 = NULL;
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
BOOL result = FALSE;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken))
{
fprintf(stderr, "OpenProcessToken(): %ul\n", GetLastError());
goto done;
}
if (!DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL, SecurityImpersonation, TokenPrimary, &hToken2))
{
fprintf(stderr, "DuplicateTokenEx(): %ul\n", GetLastError());
goto done;
}
if (!AllocateAndInitializeSid(
&NtAuthority,
1,
SECURITY_MANDATORY_SYSTEM_RID,
0,
0, 0, 0, 0, 0, 0,
&(tml.Label.SID)))
{
fprintf(stderr, "AllocateAndInitializeSid(): %ul\n", GetLastError());
goto done;
}
tml.Label.Attributes = ...; // desired integrity level
if (!SetTokenInformation(hToken2, TokenIntegrityLevel, &tml, sizeof(tml)))
{
fprintf(stderr, "SetTokenInformation(): %ul\n", GetLastError());
goto done;
}
result = TRUE;
done:
if (tml.Label.SID) FreeSid(tml.Label.SID);
if (hToken) CloseHandle(hToken);
if (hToken2) CloseHandle(hToken2);
return result;
}
int main(int argc, char** argv)
{
Elevate();
}
Suppose I have a usb drive with two partition e:, f:. How do I know from which offset the partition e: or f: starts so that I can write raw data starting from that offset. I could not find any function that would provide me the offset in c++. In Dos I could easily get this with wmic partition get Index, Name, StartingOffset.
To get the StartingOffset of partitions in a Physical Drive(such as \\\\.\\PhysicalDrive1), you could use IOCTL_DISK_GET_DRIVE_LAYOUT_EX to get PARTITION_INFORMATION_EX arrays for each partition:
#include <windows.h>
#include <stdio.h>
#define wszDrive L"\\\\.\\PhysicalDrive1"
int wmain(int argc, wchar_t* argv[])
{
HANDLE hDevice = INVALID_HANDLE_VALUE; // handle to the drive to be examined
BOOL bResult = FALSE; // results flag
DWORD junk = 0; // discard results
DWORD error;
DWORD szNewLayout = sizeof(DRIVE_LAYOUT_INFORMATION_EX) + sizeof(PARTITION_INFORMATION_EX) * 4 * 25;
hDevice = CreateFileW(wszDrive, // drive to open
GENERIC_READ, // no access to the drive
FILE_SHARE_READ,
NULL, // default security attributes
OPEN_EXISTING, // disposition
0, // file attributes
0); // do not copy file attributes
if (hDevice == INVALID_HANDLE_VALUE) // cannot open the drive
{
error = GetLastError();
printf("CreateFileW error: %d\n", error);
return -1;
}
DRIVE_LAYOUT_INFORMATION_EX* pdg = (DRIVE_LAYOUT_INFORMATION_EX*)malloc(szNewLayout);
if (pdg == NULL)
{
error = GetLastError();
printf("malloc error: %d\n", error);
CloseHandle(hDevice);
return -1;
}
ZeroMemory(pdg, szNewLayout);
bResult = DeviceIoControl(hDevice, // device to be queried
IOCTL_DISK_GET_DRIVE_LAYOUT_EX, // operation to perform
NULL, 0, // no input buffer
pdg, szNewLayout,// sizeof(*pdg)*2, // output buffer
&junk, // # bytes returned
(LPOVERLAPPED)NULL); // synchronous I/O
if (!bResult)
{
error = GetLastError();
printf("DeviceIoControl error: %d\n", error);
free(pdg);
CloseHandle(hDevice);
return -1;
}
for (int i = 0; i < pdg->PartitionCount; i++) {
printf("partition %d: %lld\n", i, pdg->PartitionEntry[i].StartingOffset.QuadPart);
}
free(pdg);
CloseHandle(hDevice);
return 0;
}
To get the StartingOffset of a specified partition(such as \\\\.\\E:), you could use IOCTL_DISK_GET_PARTITION_INFO_EX:
#include <windows.h>
#include <stdio.h>
#define wszDrive L"\\\\.\\E:"
int wmain(int argc, wchar_t* argv[])
{
HANDLE hDevice = INVALID_HANDLE_VALUE; // handle to the drive to be examined
BOOL bResult = FALSE; // results flag
DWORD junk = 0; // discard results
DWORD error;
PARTITION_INFORMATION_EX piex;
ZeroMemory(&piex, sizeof(PARTITION_INFORMATION_EX));
hDevice = CreateFileW(wszDrive, // drive to open
GENERIC_READ, // no access to the drive
FILE_SHARE_READ,
NULL, // default security attributes
OPEN_EXISTING, // disposition
0, // file attributes
0); // do not copy file attributes
if (hDevice == INVALID_HANDLE_VALUE) // cannot open the drive
{
error = GetLastError();
printf("CreateFileW error: %d\n", error);
return -1;
}
bResult = DeviceIoControl(hDevice,
IOCTL_DISK_GET_PARTITION_INFO_EX,
NULL, 0,
&piex, sizeof(PARTITION_INFORMATION_EX),
&junk,
(LPOVERLAPPED)NULL);
if (!bResult)
{
error = GetLastError();
printf("DeviceIoControl error: %d\n", error);
CloseHandle(hDevice);
return -1;
}
wprintf(L"%s StartingOffset: %lld\n", wszDrive, piex.StartingOffset.QuadPart);
CloseHandle(hDevice);
return 0;
}
I have a project which you can create named pipes in c# or c++ and this program will work as a middle man and simply pass the data on. Used to maintain integrity. Though in one of my while loops when I debug it I step on the while loop then it will cancel the steps and not process the while loop. It reaches line 107 of this code. If you need more of my files I will be happy to post them if needed.
//Information\\
//----------------------------------------\\
//File Name: NamedPipes.cpp
//Date Of Creation: 03/12/2019
//Purpose
/*
This file is to handle the interprocess communication
between the pipes.
*/
//----------------------------------------\\
//Internal Includes\\
//----------------------------------------\\
#include "NamedPipes.h"
#include "MiddleMan.h"
//----------------------------------------\\
//Global Variables\\
//----------------------------------------\\
struct Connection NamedPipes::Server;
struct Connection NamedPipes::Client;
//----------------------------------------\\
//Functions\\
//----------------------------------------\\
int NamedPipes::CreateServer()
{
try
{
LPTSTR lpszPipename = (LPTSTR)"\\\\.\\pipe\\Omni3";
LPTSTR lpszPipename2 = (LPTSTR)"\\\\.\\pipe\\Omni4";
while (1) {
Server.Write = CreateNamedPipe(lpszPipename, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 1024 * 16, 1024 * 16, NMPWAIT_USE_DEFAULT_WAIT, NULL);
Server.Read = CreateNamedPipe(lpszPipename2, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 1024 * 16, 1024 * 16, NMPWAIT_USE_DEFAULT_WAIT, NULL);
if (Server.Write == INVALID_HANDLE_VALUE)
{
return -1;
}
if (ConnectNamedPipe(Server.Write, NULL) != FALSE) // wait for someone to connect to the pipe
{
Server.Connected = true;
DWORD dwThreadId = 0;
HANDLE hThread = CreateThread(
NULL, // no security attribute
0, // default stack size
(LPTHREAD_START_ROUTINE)MiddleMan::Pass, // thread proc
(LPVOID)&Server, // thread parameter
0, // not suspended
&dwThreadId); // returns thread ID
}
}
return 1;
}
catch (exception ex)
{
}
return 0;
}
int NamedPipes::CreateClient()
{
try
{
DWORD last_error;
unsigned int elapsed_seconds = 0;
const unsigned int timeout_seconds = 5;
LPTSTR lpszPipename = (LPTSTR)"\\\\.\\pipe\\Omni1";
LPTSTR lpszPipename2 = (LPTSTR)"\\\\.\\pipe\\Omni2";
Client.Read = CreateFile(lpszPipename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
Client.Write = CreateFile(lpszPipename2, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
while (INVALID_HANDLE_VALUE == Client.Read &&
elapsed_seconds < timeout_seconds)
{
last_error = GetLastError();
if (last_error != ERROR_PIPE_BUSY)
{
break;
}
Sleep(1000);
elapsed_seconds++;
Client.Read = CreateFile(lpszPipename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
Client.Write = CreateFile(lpszPipename2, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
}
if (INVALID_HANDLE_VALUE == Client.Read)
{
std::cerr << "Failed to connect to pipe " << lpszPipename <<
": last_error=" << last_error << "\n";
return 0;
}
else
{
std::cout << "Connected to pipe " << lpszPipename << "\n";
}
DWORD dwThreadId = 0;
Client.Connected = true;
HANDLE hThread = CreateThread(
NULL, // no security attribute
0, // default stack size
(LPTHREAD_START_ROUTINE)MiddleMan::Pass, // thread proc
(LPVOID)&Client, // thread parameter
0, // not suspended
&dwThreadId); // returns thread ID
return 1;
}
catch (exception ex)
{
}
return 0;
}
/*
This function will loop until it recieves a transmission from the external UI.
*/
string NamedPipes::RecieveInformation(HANDLE Pipe)
{
BOOL fSuccess;
char chBuf[2048];
DWORD cbRead;
int i;
try
{
while (true)
{
if (Pipe) {
fSuccess = ReadFile(Pipe, chBuf, 2048, &cbRead, NULL);
if (cbRead != NULL && fSuccess)
{
string s(chBuf);
s.resize(cbRead);
printf("Pipe Recieved: %s\n", s.c_str());
return s;
}
printf("Error: Couldn't Read Pipe\n");
Sleep(500);
}
else
{
printf("Error: Invalid Pipe\n");
}
}
return "";
}
catch (exception ex)
{
printf("Error: %s\n", ex.what());
}
catch (...)
{
printf("Error Unknown\n");
}
}
int NamedPipes::SendInformation(HANDLE Pipe, string Information)
{
char buf[2048];
DWORD cbWritten;
try
{
strcpy(buf, Information.c_str());
if (!WriteFile(Pipe, buf, (DWORD)strlen(buf), &cbWritten, NULL))
{
printf("Message Sending Failed. Error: %d\n", GetLastError());
}
}
catch (exception ex)
{
}
return 1;
}
//----------------------------------------\\
EDIT: If it helps this is MiddleMan::Pass
void MiddleMan::Pass(LPVOID Pipe2)
{
Connection Pipe = *(Connection *)Pipe2;
while (1)
{
string Information = NamedPipes::RecieveInformation(Pipe.Read);
if (Information != "") {
if (Pipe.Read == NamedPipes::Server.Read)
{
if (NamedPipes::Client.Connected) {
NamedPipes::SendInformation(NamedPipes::Client.Write, Information);
}
}
else if (Pipe.Read == NamedPipes::Client.Read)
{
if (NamedPipes::Server.Connected) {
NamedPipes::SendInformation(NamedPipes::Server.Write, Information);
}
}
}
}
}
My Windows has several accounts like "test1", "test2" and "test3" that belong to the Administrators group. I am developing an application program and I want that program to know if itself is run under an account that belong to the Administrators group by designing a boolean function: isCurrentUserAdminMember(), the isCurrentUserAdminMember() funtion should only return TRUE if the process is run by "test1", "test2", "test3" or the built-in Administrator account no matter whether the process is elevated.
I found some code in http://www.codeproject.com/Articles/320748/Haephrati-Elevating-during-runtime as below, but it seems only to check if the current process is elevated as an Administrator. I don't care if the process is elevated, I just want to know if the start account of the process is a member of Administrators group. And I hope the determination itself is not privilege required. Is that possible? thanks.
BOOL IsAppRunningAsAdminMode()
{
BOOL fIsRunAsAdmin = FALSE;
DWORD dwError = ERROR_SUCCESS;
PSID pAdministratorsGroup = NULL;
// Allocate and initialize a SID of the administrators group.
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
if (!AllocateAndInitializeSid(
&NtAuthority,
2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&pAdministratorsGroup))
{
dwError = GetLastError();
goto Cleanup;
}
// Determine whether the SID of administrators group is enabled in
// the primary access token of the process.
if (!CheckTokenMembership(NULL, pAdministratorsGroup, &fIsRunAsAdmin))
{
dwError = GetLastError();
goto Cleanup;
}
Cleanup:
// Centralized cleanup for all allocated resources.
if (pAdministratorsGroup)
{
FreeSid(pAdministratorsGroup);
pAdministratorsGroup = NULL;
}
// Throw the error if something failed in the function.
if (ERROR_SUCCESS != dwError)
{
throw dwError;
}
return fIsRunAsAdmin;
}
At last, we achieved the goal to check the Administrators group membership as the code below, however it is USELESS as the answer and comment said, just leave here for reference in case anybody needs it for other use.
// PermTest.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "stdio.h"
#include "iostream"
using namespace std;
#include "windows.h"
#include <lm.h>
#pragma comment(lib, "netapi32.lib")
BOOL IsUserInGroup(const wchar_t* groupe)
{
BOOL result = FALSE;
SID_NAME_USE snu;
WCHAR szDomain[256];
DWORD dwSidSize = 0;
DWORD dwSize = sizeof szDomain / sizeof * szDomain;
if ((LookupAccountNameW(NULL, groupe, 0, &dwSidSize, szDomain, &dwSize, &snu) == 0)
&& (ERROR_INSUFFICIENT_BUFFER == GetLastError()))
{
SID* pSid = (SID*)malloc(dwSidSize);
if (LookupAccountNameW(NULL, groupe, pSid, &dwSidSize, szDomain, &dwSize, &snu))
{
BOOL b;
if (CheckTokenMembership(NULL, pSid, &b))
{
if (b == TRUE)
{
result = TRUE;
}
}
else
{
result = FALSE;
}
}
//Si tout vas bien (la presque totalitée des cas), on delete notre pointeur
//avec le bon operateur.
free(pSid);
}
return result;
}
void getUserInfo(WCHAR *domainName, WCHAR *userName)
{
LPUSER_INFO_3 pBuf = NULL;
int j = 0;
DWORD nStatus = NetUserGetInfo(domainName, userName, 3, (LPBYTE *) &pBuf);
LPUSER_INFO_2 pBuf2 = NULL;
pBuf2 = (LPUSER_INFO_2) pBuf;
if (pBuf)
{
wprintf(L"User account name: %s\\%s\n", domainName, pBuf2->usri2_name);
wprintf(L"Privilege level: %d\n\n", pBuf2->usri2_priv);
}
// wprintf(L"\tPassword: %s\n", pBuf2->usri2_password);
// wprintf(L"\tPassword age (seconds): %d\n",
// pBuf2->usri2_password_age);
// wprintf(L"Privilege level: %d\n\n", pBuf2->usri2_priv);
// #define USER_PRIV_GUEST 0
// #define USER_PRIV_USER 1
// #define USER_PRIV_ADMIN 2
// wprintf(L"\tHome directory: %s\n", pBuf2->usri2_home_dir);
// wprintf(L"\tComment: %s\n", pBuf2->usri2_comment);
// wprintf(L"\tFlags (in hex): %x\n", pBuf2->usri2_flags);
// wprintf(L"\tScript path: %s\n", pBuf2->usri2_script_path);
// wprintf(L"\tAuth flags (in hex): %x\n",
// pBuf2->usri2_auth_flags);
// wprintf(L"\tFull name: %s\n", pBuf2->usri2_full_name);
// wprintf(L"\tUser comment: %s\n", pBuf2->usri2_usr_comment);
// wprintf(L"\tParameters: %s\n", pBuf2->usri2_parms);
// wprintf(L"\tWorkstations: %s\n", pBuf2->usri2_workstations);
// wprintf
// (L"\tLast logon (seconds since January 1, 1970 GMT): %d\n",
// pBuf2->usri2_last_logon);
// wprintf
// (L"\tLast logoff (seconds since January 1, 1970 GMT): %d\n",
// pBuf2->usri2_last_logoff);
// wprintf
// (L"\tAccount expires (seconds since January 1, 1970 GMT): %d\n",
// pBuf2->usri2_acct_expires);
// wprintf(L"\tMax storage: %d\n", pBuf2->usri2_max_storage);
// wprintf(L"\tUnits per week: %d\n",
// pBuf2->usri2_units_per_week);
// wprintf(L"\tLogon hours:");
// for (j = 0; j < 21; j++)
// {
// printf(" %x", (BYTE) pBuf2->usri2_logon_hours[j]);
// }
// wprintf(L"\n");
// wprintf(L"\tBad password count: %d\n",
// pBuf2->usri2_bad_pw_count);
// wprintf(L"\tNumber of logons: %d\n",
// pBuf2->usri2_num_logons);
// wprintf(L"\tLogon server: %s\n", pBuf2->usri2_logon_server);
// wprintf(L"\tCountry code: %d\n", pBuf2->usri2_country_code);
// wprintf(L"\tCode page: %d\n", pBuf2->usri2_code_page);
}
#include <comdef.h>
#define MAX_NAME 256
BOOL GetLogonFromToken (HANDLE hToken, _bstr_t& strUser, _bstr_t& strdomain)
{
DWORD dwSize = MAX_NAME;
BOOL bSuccess = FALSE;
DWORD dwLength = 0;
strUser = "";
strdomain = "";
PTOKEN_USER ptu = NULL;
//Verify the parameter passed in is not NULL.
if (NULL == hToken)
goto Cleanup;
if (!GetTokenInformation(
hToken, // handle to the access token
TokenUser, // get information about the token's groups
(LPVOID) ptu, // pointer to PTOKEN_USER buffer
0, // size of buffer
&dwLength // receives required buffer size
))
{
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
goto Cleanup;
ptu = (PTOKEN_USER)HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY, dwLength);
if (ptu == NULL)
goto Cleanup;
}
if (!GetTokenInformation(
hToken, // handle to the access token
TokenUser, // get information about the token's groups
(LPVOID) ptu, // pointer to PTOKEN_USER buffer
dwLength, // size of buffer
&dwLength // receives required buffer size
))
{
goto Cleanup;
}
SID_NAME_USE SidType;
char lpName[MAX_NAME];
char lpDomain[MAX_NAME];
if( !LookupAccountSidA( NULL , ptu->User.Sid, lpName, &dwSize, lpDomain, &dwSize, &SidType ) )
{
DWORD dwResult = GetLastError();
if( dwResult == ERROR_NONE_MAPPED )
strcpy (lpName, "NONE_MAPPED" );
else
{
printf("LookupAccountSid Error %u\n", GetLastError());
}
}
else
{
// printf( "Current user is %s\\%s\n",
// lpDomain, lpName );
strUser = lpName;
strdomain = lpDomain;
bSuccess = TRUE;
}
Cleanup:
if (ptu != NULL)
HeapFree(GetProcessHeap(), 0, (LPVOID)ptu);
return bSuccess;
}
HRESULT GetUserFromProcess( _bstr_t& strUser, _bstr_t& strdomain)
{
//HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION,FALSE,procId);
HANDLE hProcess = GetCurrentProcess();
if(hProcess == NULL)
return E_FAIL;
HANDLE hToken = NULL;
if( !OpenProcessToken( hProcess, TOKEN_QUERY, &hToken ) )
{
CloseHandle( hProcess );
return E_FAIL;
}
BOOL bres = GetLogonFromToken (hToken, strUser, strdomain);
CloseHandle( hToken );
CloseHandle( hProcess );
return bres?S_OK:E_FAIL;
}
int _tmain(int argc, _TCHAR* argv[])
{
//cout << IsUserInGroup(L"administrators");
getUserInfo(L"adtest.net", L"Administrator");
getUserInfo(NULL, L"Administrator");
getUserInfo(NULL, L"test");
getUserInfo(NULL, L"test2");
getUserInfo(NULL, L"testnormal");
_bstr_t username;
_bstr_t domain;
GetUserFromProcess(username, domain);
cout << "Current account running this program is: " << endl << domain << "\\" << username << endl;
getchar();
return 0;
}
You can do this by opening your process token (OpenProcessToken, listing the SIDs using GetTokenInformation and comparing each SID to the Administrators SID.
Microsoft have sample code here: Searching for a SID in an Access Token in C++
However, this is rarely a useful thing to do. Even if the user is not a member of the Administrators group, they can still elevate by providing an administrative username and password, so you should not (for example) only offer elevation if the user is in the Administrators group.
bool IsMemberOfGroup(const char *pszGroupName){
bool bFound = false;
HANDLE hToken=INVALID_HANDLE_VALUE;
BOOL bSuccess = OpenProcessToken( GetCurrentProcess(),
TOKEN_QUERY,//|TOKEN_QUERY_SOURCE,
&hToken);
if ( bSuccess )
{
DWORD dwSizeToken=0;
DWORD dwSizeName=0;
DWORD dwSizeReferencedDomainName = 0;
// Get group information:
GetTokenInformation(hToken, TokenGroups, NULL, dwSizeToken, &dwSizeToken);
{
const int MAX_NAME = 256;
char *psName = new char[MAX_NAME];
char *psDomain = new char[MAX_NAME];
char *pBuf = new char[dwSizeToken+10];
TOKEN_GROUPS *pGroupInfo = (TOKEN_GROUPS *)pBuf;
bSuccess = GetTokenInformation(hToken, TokenGroups, pGroupInfo, dwSizeToken, &dwSizeToken);
if ( bSuccess )
{
// find the group name we are looking for
for ( UINT uiGroupNdx = 0; uiGroupNdx < pGroupInfo->GroupCount && !bFound; uiGroupNdx++ )
{
SID_NAME_USE SidType;
dwSizeName = MAX_NAME;
dwSizeReferencedDomainName = MAX_NAME;
bSuccess = LookupAccountSid(NULL, // local system,
pGroupInfo->Groups[uiGroupNdx].Sid,
psName,
&dwSizeName,
psDomain,
&dwSizeReferencedDomainName,
&SidType);
if ( bSuccess )
{
if ( SidTypeGroup == SidType )
{
if ( !lstrcmpi(pszGroupName, psName) )
{
bFound = true;
}
}
}
}
}
delete [] pBuf;
delete [] psName;
delete [] psDomain;
}
CloseHandle(hToken);
}
return bFound;
}
//writing to mailslot
#include <windows.h>
#include <stdio.h>
LPTSTR SlotName = TEXT("\\\\.\\mailslot\\sample_mailslot");
BOOL WriteSlot(HANDLE hSlot, LPTSTR lpszMessage)
{
BOOL fResult;
DWORD cbWritten;
fResult = WriteFile(hSlot,
lpszMessage,
(DWORD) (lstrlen(lpszMessage)+1)*sizeof(TCHAR),
&cbWritten,
(LPOVERLAPPED) NULL);
if (!fResult)
{
printf("WriteFile failed with %d.\n", GetLastError());
return FALSE;
}
printf("Slot written to successfully.\n");
return TRUE;
}
int main()
{
HANDLE hFile;
hFile = CreateFile(SlotName,
GENERIC_WRITE,
FILE_SHARE_READ,
(LPSECURITY_ATTRIBUTES) NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
(HANDLE) NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
printf("CreateFile failed with %d.\n", GetLastError());
return FALSE;
}
WriteSlot(hFile, TEXT("Message one for mailslot."));
WriteSlot(hFile, TEXT("Message two for mailslot."));
Sleep(5000);
WriteSlot(hFile, TEXT("Message three for mailslot."));
CloseHandle(hFile);
return TRUE;
}
//reading from mailslot
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <strsafe.h>
HANDLE hSlot;
LPTSTR SlotName = TEXT("\\\\.\\mailslot\\sample_mailslot");
BOOL ReadSlot()
{
DWORD cbMessage, cMessage, cbRead;
BOOL fResult;
LPTSTR lpszBuffer;
TCHAR achID[80];
DWORD cAllMessages;
HANDLE hEvent;
OVERLAPPED ov;
cbMessage = cMessage = cbRead = 0;
hEvent = CreateEvent(NULL, FALSE, FALSE, TEXT("ExampleSlot"));
if( NULL == hEvent )
return FALSE;
ov.Offset = 0;
ov.OffsetHigh = 0;
ov.hEvent = hEvent;
fResult = GetMailslotInfo( hSlot, // mailslot handle
(LPDWORD) NULL, // no maximum message size
&cbMessage, // size of next message
&cMessage, // number of messages
(LPDWORD) NULL); // no read time-out
if (!fResult)
{
printf("GetMailslotInfo failed with %d.\n", GetLastError());
return FALSE;
}
if (cbMessage == MAILSLOT_NO_MESSAGE)
{
printf("Waiting for a message...\n");
return TRUE;
}
cAllMessages = cMessage;
while (cMessage != 0) // retrieve all messages
{
// Create a message-number string.
StringCchPrintf((LPTSTR) achID,
80,
TEXT("\nMessage #%d of %d\n"),
cAllMessages - cMessage + 1,
cAllMessages);
// Allocate memory for the message.
lpszBuffer = (LPTSTR) GlobalAlloc(GPTR,
lstrlen((LPTSTR) achID)*sizeof(TCHAR) + cbMessage);
if( NULL == lpszBuffer )
return FALSE;
lpszBuffer[0] = '\0';
fResult = ReadFile(hSlot,
lpszBuffer,
cbMessage,
&cbRead,
&ov);
if (!fResult)
{
printf("ReadFile failed with %d.\n", GetLastError());
GlobalFree((HGLOBAL) lpszBuffer);
return FALSE;
}
// Concatenate the message and the message-number string.
StringCbCat(lpszBuffer,
lstrlen((LPTSTR) achID)*sizeof(TCHAR)+cbMessage,
(LPTSTR) achID);
// Display the message.
_tprintf(TEXT("Contents of the mailslot: %s\n"), lpszBuffer);
GlobalFree((HGLOBAL) lpszBuffer);
fResult = GetMailslotInfo(hSlot, // mailslot handle
(LPDWORD) NULL, // no maximum message size
&cbMessage, // size of next message
&cMessage, // number of messages
(LPDWORD) NULL); // no read time-out
if (!fResult)
{
printf("GetMailslotInfo failed (%d)\n", GetLastError());
return FALSE;
}
}
CloseHandle(hEvent);
return TRUE;
}
BOOL WINAPI MakeSlot(LPTSTR lpszSlotName)
{
hSlot = CreateMailslot(lpszSlotName,
0, // no maximum message size
MAILSLOT_WAIT_FOREVER, // no time-out for operations
(LPSECURITY_ATTRIBUTES) NULL); // default security
if (hSlot == INVALID_HANDLE_VALUE)
{
printf("CreateMailslot failed with %d\n", GetLastError());
return FALSE;
}
return TRUE;
}
void main()
{
MakeSlot(SlotName);
while(TRUE)
{
ReadSlot();
Sleep(3000);
}
}
Go through the Visual Studio C++ Guided Tour on MSDN or watch this introductory video explaining how to create a basic Win32 application in C++. They should be enough of a starting point. From there on just browse the MSDN library to advance your knowledge or search for issues you encounter.