How to import a PKCS#8 with CryptoApi - c++

I Have a PKCS#8 Key and I desperately try to import in CryptoAPI without any success. I have :
-----BEGIN PRIVATE KEY-----
<privatekey>
-----END PRIVATE KEY-----
That contain this :
Private Key algo RSA
Private Format PKCS#8
ASN1 Dump
RSA Private CRT Key [.....]
modulus: .....
public exponent: .....
I try to import the key like this :
if not CryptStringToBinaryA(
PansiChar(aBase64PrivateKey), // pszString: LPCSTR;
length(aBase64PrivateKey), // cchString: DWORD;
CRYPT_STRING_BASE64HEADER, // dwFlags: DWORD;
nil, // pbBinary: pByte;
#cbPrivKey, // pcbBinary: PDWORD;
nil, // pdwSkip: PDWORD;
nil) then raiseLastOsError; // pdwFlags: PDWORD
setlength(pPrivKey, cbPrivKey);
if not CryptStringToBinaryA(
PansiChar(aBase64PrivateKey), // pszString: LPCSTR;
length(aBase64PrivateKey), // cchString: DWORD;
CRYPT_STRING_BASE64HEADER, // dwFlags: DWORD;
#pPrivKey[0], // pbBinary: pByte;
#cbPrivKey, // pcbBinary: PDWORD;
nil, // pdwSkip: PDWORD;
nil) then raiseLastOsError; // pdwFlags: PDWORD
//init pKeyBlob
if not CryptDecodeObjectEx(
X509_ASN_ENCODING or PKCS_7_ASN_ENCODING, // dwCertEncodingType: DWORD;
PKCS_PRIVATE_KEY_INFO, // lpszStructType: LPCSTR;
#pPrivKey[0], // const pbEncoded: PBYTE;
cbPrivKey, // cbEncoded: DWORD;
0, // dwFlags: DWORD;
nil, // pDecodePara: PCRYPT_DECODE_PARA;
nil, // pvStructInfo: Pointer;
#cbKeyBlob) then raiseLastOsError; // pcbStructInfo: PDWORD
setlength(pKeyBlob, cbKeyBlob);
if not CryptDecodeObjectEx(
X509_ASN_ENCODING or PKCS_7_ASN_ENCODING, // dwCertEncodingType: DWORD;
PKCS_PRIVATE_KEY_INFO, // lpszStructType: LPCSTR;
#pPrivKey[0], // const pbEncoded: PBYTE;
cbPrivKey, // cbEncoded: DWORD;
0, // dwFlags: DWORD;
nil, // pDecodePara: PCRYPT_DECODE_PARA;
#pKeyBlob[0], // pvStructInfo: Pointer;
#cbKeyBlob) then raiseLastOsError; // pcbStructInfo: PDWORD
//acquire a handle to a particular key container
if (not CryptAcquireContextA(#hProv, // phProv: PHCRYPTPROV;
nil, // pszContainer: PAnsiChar;
nil, // pszProvider: PAnsiChar;
PROV_RSA_AES, // dwProvType: DWORD;
CRYPT_VERIFYCONTEXT)) then raiselastOsError; // dwFlags: DWORD
try
// Now import the key.
if not CryptImportKey(hProv, // hProv: HCRYPTPROV;
#pKeyBlob[0], // const pbData: PBYTE;
cbKeyBlob, // dwDataLen: DWORD;
0, // hPubKey: HCRYPTKEY;
0, // dwFlags: DWORD;
#hRSAKey) then raiseLastOsError; // phKey: PHCRYPTKEY
but CryptImportKey fail with "Bad Version of provider", I guess because it's was waiting for a PKCS#1 Key. How can I import a PKCS#8 key?

for convert PKCS #8 format to legacy or CNG crypto api need several steps.
first need convert string to binary via CryptStringToBinaryA with CRYPT_STRING_BASE64HEADER
than call CryptDecodeObjectEx with PKCS_PRIVATE_KEY_INFO (if private key encrypted need use PKCS_ENCRYPTED_PRIVATE_KEY_INFO )
than need again call CryptDecodeObjectEx with PKCS_RSA_PRIVATE_KEY for legacy crypto api and CNG_RSA_PUBLIC_KEY_BLOB for CNG.
now we can call BCryptImportKeyPair or CryptImportKey
for import public key need use X509_PUBLIC_KEY_INFO, for public key from cert - X509_CERT_TO_BE_SIGNED (+ CNG_RSA_PUBLIC_KEY_BLOB for CNG, for legacy can use CryptImportPublicKeyInfo)
say code for legacy
inline ULONG BOOL_TO_ERROR(BOOL f)
{
return f ? NOERROR : GetLastError();
}
ULONG CryptImportPublicKey(_Out_ HCRYPTKEY *phKey,
_In_ HCRYPTPROV hProv,
_In_ PCUCHAR pbKeyOrCert,
_In_ ULONG cbKeyOrCert,
_In_ bool bCert)
{
ULONG cb;
union {
PVOID pvStructInfo;
PCERT_INFO pCertInfo;
PCERT_PUBLIC_KEY_INFO PublicKeyInfo;
};
ULONG dwError = BOOL_TO_ERROR(CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
bCert ? X509_CERT_TO_BE_SIGNED : X509_PUBLIC_KEY_INFO,
pbKeyOrCert, cbKeyOrCert, CRYPT_DECODE_ALLOC_FLAG|CRYPT_DECODE_NOCOPY_FLAG, 0, &pvStructInfo, &cb));
if (dwError == NOERROR)
{
PVOID pv = pvStructInfo;
if (bCert)
{
PublicKeyInfo = &pCertInfo->SubjectPublicKeyInfo;
}
dwError = BOOL_TO_ERROR(CryptImportPublicKeyInfo(hProv,
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, PublicKeyInfo, phKey));
LocalFree(pv);
}
return dwError;
}
ULONG CryptImportPrivateKey(_Out_ HCRYPTKEY* phKey,
_In_ HCRYPTPROV hProv,
_In_ PCUCHAR pbKey,
_In_ ULONG cbKey)
{
ULONG cb;
PCRYPT_PRIVATE_KEY_INFO PrivateKeyInfo;
ULONG dwError = BOOL_TO_ERROR(CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, PKCS_PRIVATE_KEY_INFO,
pbKey, cbKey, CRYPT_DECODE_ALLOC_FLAG|CRYPT_DECODE_NOCOPY_FLAG, 0, (void**)&PrivateKeyInfo, &cb));
if (dwError == NOERROR)
{
PUBLICKEYSTRUC* ppks;
dwError = BOOL_TO_ERROR(CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
PKCS_RSA_PRIVATE_KEY, PrivateKeyInfo->PrivateKey.pbData, PrivateKeyInfo->PrivateKey.cbData,
CRYPT_DECODE_ALLOC_FLAG, 0, (void**)&ppks, &cb));
LocalFree(PrivateKeyInfo);
if (dwError == NOERROR)
{
dwError = BOOL_TO_ERROR(CryptImportKey(hProv, (PUCHAR)ppks, cb, 0, CRYPT_EXPORTABLE, phKey));
LocalFree(ppks);
}
}
return dwError;
}
enum BLOB_TYPE { bt_priv, bt_pub, bt_cert };
ULONG CryptImportKey(_Out_ HCRYPTKEY *phKey,
_In_ HCRYPTPROV hProv,
_In_ BLOB_TYPE bt,
_In_ PCSTR szKey,
_In_ ULONG cchKey)
{
PUCHAR pbKey = 0;
ULONG cbKey = 0;
ULONG dwError;
while (CryptStringToBinaryA(szKey, cchKey, CRYPT_STRING_BASE64HEADER, pbKey, &cbKey, 0, 0))
{
if (pbKey)
{
switch (bt)
{
case bt_priv:
dwError = CryptImportPrivateKey(phKey, hProv, pbKey, cbKey);
break;
case bt_pub:
dwError = CryptImportPublicKey(phKey, hProv, pbKey, cbKey, false);
break;
case bt_cert:
dwError = CryptImportPublicKey(phKey, hProv, pbKey, cbKey, true);
break;
default: dwError = ERROR_INVALID_PARAMETER;
}
_freea(pbKey);
return dwError;
}
if (!(pbKey = (PUCHAR)_malloca(cbKey)))
{
break;
}
}
dwError = GetLastError();
if (pbKey) _freea(pbKey);
return dwError;
}
void DoLegacyTest(_In_ PCSTR szToBeSigned,
_In_ PCSTR szPrivateKey,
_In_ ULONG cchPrivateKey,
_In_ PCSTR szPublicKeyOrCert,
_In_ ULONG cchPublicKeyOrCert,
_In_ bool bCert)
{
HCRYPTPROV hProv;
if (CryptAcquireContextW(&hProv, 0, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, CRYPT_VERIFYCONTEXT))
{
HCRYPTKEY hKey;
HCRYPTHASH hHash;
if (CryptCreateHash(hProv, CALG_SHA_256, 0, 0, &hHash))
{
if (CryptHashData(hHash, (PUCHAR)szToBeSigned, (ULONG)strlen(szToBeSigned), 0))
{
PUCHAR pbSignature = 0;
ULONG cbSignature = 0;
BOOL fOk = false;
if (NOERROR == CryptImportKey(&hKey, hProv, bt_priv, szPrivateKey, cchPrivateKey))
{
ULONG dwKeySpec, cb;
if (CryptGetKeyParam(hKey, KP_ALGID, (PUCHAR)&dwKeySpec, &(cb = sizeof(dwKeySpec)), 0))
{
switch (dwKeySpec)
{
case CALG_RSA_KEYX:
dwKeySpec = AT_KEYEXCHANGE;
break;
case CALG_RSA_SIGN:
dwKeySpec = AT_SIGNATURE;
break;
default: dwKeySpec = 0;
}
if (CryptGetKeyParam(hKey, KP_BLOCKLEN, (PUCHAR)&cbSignature, &(cb = sizeof(cbSignature)), 0))
{
pbSignature = (PUCHAR)alloca(cbSignature >>= 3);
fOk = CryptSignHashW(hHash, dwKeySpec, 0, 0, pbSignature, &cbSignature);
}
}
CryptDestroyKey(hKey);
}
if (fOk)
{
if (NOERROR == CryptImportKey(&hKey, hProv, bCert ? bt_cert : bt_pub, szPublicKeyOrCert, cchPublicKeyOrCert))
{
if (!CryptVerifySignatureW(hHash, pbSignature, cbSignature, hKey, 0, 0))
{
__debugbreak();
}
CryptDestroyKey(hKey);
}
}
}
CryptDestroyHash(hHash);
}
CryptReleaseContext(hProv, 0);
}
}
code for CNG
inline ULONG BOOL_TO_ERROR(BOOL f)
{
return f ? NOERROR : GetLastError();
}
NTSTATUS openssl_verify(_In_ BCRYPT_KEY_HANDLE hKey,
_In_ PCUCHAR pbToBeSigned,
_In_ ULONG cbToBeSigned,
_In_ PCUCHAR pbSignature,
_In_ ULONG cbSignature,
_In_ PCWSTR pszAlgId)
{
BCRYPT_ALG_HANDLE hAlgorithm;
NTSTATUS status = BCryptOpenAlgorithmProvider(&hAlgorithm, pszAlgId, 0, 0);
if (0 <= status)
{
BCRYPT_HASH_HANDLE hHash = 0;
ULONG HashBlockLength, cb;
0 <= (status = BCryptGetProperty(hAlgorithm, BCRYPT_HASH_LENGTH, (PUCHAR)&HashBlockLength, sizeof(ULONG), &cb, 0)) &&
0 <= (status = BCryptCreateHash(hAlgorithm, &hHash, 0, 0, 0, 0, 0));
BCryptCloseAlgorithmProvider(hAlgorithm, 0);
if (0 <= status)
{
PUCHAR pbHash = (PUCHAR)alloca(HashBlockLength);
0 <= (status = BCryptHashData(hHash, const_cast<PUCHAR>(pbToBeSigned), cbToBeSigned, 0)) &&
0 <= (status = BCryptFinishHash(hHash, pbHash, HashBlockLength, 0));
BCryptDestroyHash(hHash);
if (0 <= status)
{
BCRYPT_PKCS1_PADDING_INFO pi = { pszAlgId };
status = BCryptVerifySignature(hKey, &pi, pbHash, HashBlockLength,
const_cast<PUCHAR>(pbSignature), cbSignature, BCRYPT_PAD_PKCS1);
}
}
}
return status;
}
inline NTSTATUS openssl_verify(_In_ BCRYPT_KEY_HANDLE hKey,
_In_ PCSTR szToBeSigned,
_In_ PCUCHAR pbSignature,
_In_ ULONG cbSignature,
_In_ PCWSTR pszAlgId)
{
return openssl_verify(hKey, (PCUCHAR)szToBeSigned, (ULONG)strlen(szToBeSigned), pbSignature, cbSignature, pszAlgId);
}
NTSTATUS openssl_sign(_In_ BCRYPT_KEY_HANDLE hKey,
_In_ PCUCHAR pbToBeSigned,
_In_ ULONG cbToBeSigned,
_Out_ PUCHAR pbSignature,
_Inout_ PULONG pcbSignature,
_In_ PCWSTR pszAlgId)
{
BCRYPT_ALG_HANDLE hAlgorithm;
NTSTATUS status = BCryptOpenAlgorithmProvider(&hAlgorithm, pszAlgId, 0, 0);
if (0 <= status)
{
BCRYPT_HASH_HANDLE hHash = 0;
ULONG HashBlockLength, cb;
0 <= (status = BCryptGetProperty(hAlgorithm, BCRYPT_HASH_LENGTH, (PUCHAR)&HashBlockLength, sizeof(ULONG), &cb, 0)) &&
0 <= (status = BCryptCreateHash(hAlgorithm, &hHash, 0, 0, 0, 0, 0));
BCryptCloseAlgorithmProvider(hAlgorithm, 0);
if (0 <= status)
{
PUCHAR pbHash = (PUCHAR)alloca(HashBlockLength);
0 <= (status = BCryptHashData(hHash, const_cast<PUCHAR>(pbToBeSigned), cbToBeSigned, 0)) &&
0 <= (status = BCryptFinishHash(hHash, pbHash, HashBlockLength, 0));
BCryptDestroyHash(hHash);
if (0 <= status)
{
BCRYPT_PKCS1_PADDING_INFO pi = { pszAlgId };
status = BCryptSignHash(hKey, &pi, pbHash, HashBlockLength,
pbSignature, *pcbSignature, pcbSignature, BCRYPT_PAD_PKCS1);
}
}
}
return status;
}
inline NTSTATUS openssl_sign(_In_ BCRYPT_KEY_HANDLE hKey,
_In_ PCSTR szToBeSigned,
_Out_ PUCHAR pbSignature,
_Inout_ PULONG pcbSignature,
_In_ PCWSTR pszAlgId)
{
return openssl_sign(hKey, (PCUCHAR)szToBeSigned, (ULONG)strlen(szToBeSigned), pbSignature, pcbSignature, pszAlgId);
}
NTSTATUS BCryptImportKey(_Out_ BCRYPT_KEY_HANDLE *phKey,
_In_ PCWSTR pszBlobType,
_In_ BCRYPT_RSAKEY_BLOB* prkb,
_In_ ULONG cb)
{
BCRYPT_ALG_HANDLE hAlgorithm;
NTSTATUS status = BCryptOpenAlgorithmProvider(&hAlgorithm, BCRYPT_RSA_ALGORITHM, 0, 0);
if (0 <= status)
{
status = BCryptImportKeyPair(hAlgorithm, 0, pszBlobType, phKey, (PUCHAR)prkb, cb, 0);
BCryptCloseAlgorithmProvider(hAlgorithm, 0);
}
return status;
}
HRESULT BCryptImportPrivateKey(_Out_ BCRYPT_KEY_HANDLE *phKey, _In_ PCUCHAR pbKey, _In_ ULONG cbKey)
{
ULONG cb;
PCRYPT_PRIVATE_KEY_INFO PrivateKeyInfo;
ULONG dwError = BOOL_TO_ERROR(CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, PKCS_PRIVATE_KEY_INFO,
pbKey, cbKey, CRYPT_DECODE_ALLOC_FLAG|CRYPT_DECODE_NOCOPY_FLAG, 0, (void**)&PrivateKeyInfo, &cb));
if (dwError == NOERROR)
{
BCRYPT_RSAKEY_BLOB* prkb;
dwError = BOOL_TO_ERROR(CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
CNG_RSA_PRIVATE_KEY_BLOB, PrivateKeyInfo->PrivateKey.pbData, PrivateKeyInfo->PrivateKey.cbData,
CRYPT_DECODE_ALLOC_FLAG, 0, (void**)&prkb, &cb));
LocalFree(PrivateKeyInfo);
if (dwError == NOERROR)
{
NTSTATUS status = BCryptImportKey(phKey, BCRYPT_RSAPRIVATE_BLOB, prkb, cb);
LocalFree(prkb);
return HRESULT_FROM_NT(status);
}
}
return HRESULT_FROM_WIN32(dwError);
}
HRESULT BCryptImportPublicKey(_Out_ BCRYPT_KEY_HANDLE *phKey, _In_ PCUCHAR pbKeyOrCert, _In_ ULONG cbKeyOrCert, _In_ bool bCert)
{
ULONG cb;
union {
PVOID pvStructInfo;
PCERT_INFO pCertInfo;
PCERT_PUBLIC_KEY_INFO PublicKeyInfo;
};
ULONG dwError = BOOL_TO_ERROR(CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
bCert ? X509_CERT_TO_BE_SIGNED : X509_PUBLIC_KEY_INFO,
pbKeyOrCert, cbKeyOrCert, CRYPT_DECODE_ALLOC_FLAG|CRYPT_DECODE_NOCOPY_FLAG, 0, &pvStructInfo, &cb));
if (dwError == NOERROR)
{
BCRYPT_RSAKEY_BLOB* prkb;
PVOID pv = pvStructInfo;
if (bCert)
{
PublicKeyInfo = &pCertInfo->SubjectPublicKeyInfo;
}
dwError = BOOL_TO_ERROR(CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
CNG_RSA_PUBLIC_KEY_BLOB,
PublicKeyInfo->PublicKey.pbData,
PublicKeyInfo->PublicKey.cbData,
CRYPT_DECODE_ALLOC_FLAG, 0, (void**)&prkb, &cb));
LocalFree(pv);
if (dwError == NOERROR)
{
NTSTATUS status = BCryptImportKey(phKey, BCRYPT_RSAPUBLIC_BLOB, prkb, cb);
LocalFree(prkb);
return HRESULT_FROM_NT(status);
}
}
return HRESULT_FROM_WIN32(dwError);
}
enum BLOB_TYPE { bt_priv, bt_pub, bt_cert };
HRESULT BCryptImportKey(_Out_ BCRYPT_KEY_HANDLE *phKey, _In_ BLOB_TYPE bt, _In_ PCSTR szKey, _In_ ULONG cchKey)
{
PUCHAR pbKey = 0;
ULONG cbKey = 0;
HRESULT hr;
while (CryptStringToBinaryA(szKey, cchKey, CRYPT_STRING_BASE64HEADER, pbKey, &cbKey, 0, 0))
{
if (pbKey)
{
switch (bt)
{
case bt_priv:
hr = BCryptImportPrivateKey(phKey, pbKey, cbKey);
break;
case bt_pub:
hr = BCryptImportPublicKey(phKey, pbKey, cbKey, false);
break;
case bt_cert:
hr = BCryptImportPublicKey(phKey, pbKey, cbKey, true);
break;
default: hr = E_INVALIDARG;
}
_freea(pbKey);
return hr;
}
if (!(pbKey = (PUCHAR)_malloca(cbKey)))
{
break;
}
}
hr = HRESULT_FROM_WIN32(GetLastError());
if (pbKey) _freea(pbKey);
return hr;
}
void DoCNGTest(_In_ PCSTR szToBeSigned,
_In_ PCSTR szPrivateKey,
_In_ ULONG cchPrivateKey,
_In_ PCSTR szPublicKeyOrCert,
_In_ ULONG cchPublicKeyOrCert,
_In_ bool bCert)
{
HRESULT hr;
BCRYPT_KEY_HANDLE hKey;
PUCHAR pbSignature = 0;
ULONG cbSignature = 0, cb;
if (0 <= (hr = BCryptImportKey(&hKey, bt_priv, szPrivateKey, cchPrivateKey)))
{
if (0 <= (hr = BCryptGetProperty(hKey, BCRYPT_SIGNATURE_LENGTH, (PUCHAR)&cbSignature, sizeof(ULONG), &cb, 0)))
{
pbSignature = (PUCHAR)alloca(cbSignature);
hr = HRESULT_FROM_NT(openssl_sign(hKey, szToBeSigned, pbSignature, &cbSignature, BCRYPT_SHA256_ALGORITHM));
}
BCryptDestroyKey(hKey);
}
if (0 <= hr)
{
if (0 <= (hr = BCryptImportKey(&hKey, bCert ? bt_cert : bt_pub, szPublicKeyOrCert, cchPublicKeyOrCert)))
{
hr = HRESULT_FROM_NT(openssl_verify(hKey, szToBeSigned, pbSignature, cbSignature, BCRYPT_SHA256_ALGORITHM));
if (0 > hr)
{
__debugbreak();
}
BCryptDestroyKey(hKey);
}
}
}

Related

How to start a new process as user "NT AUTHORITY\Network Service"?

I am trying to launch a new process as NT AUTHORITY\Network Service from a process that is running as NT AUTHORITY\System.
I have looked at other questions, such as the following, which does not provide a working example: CreateProcess running as user: "NT AUTHORITY/Network Service" without knowing the credentials?
And, I have come across some posts which talk about copying a token from a process that is already running as NT AUTHORITY\Network Service: Windows API and Impersonation Part 1 - How to get SYSTEM using Primary Tokens.
I wonder, is there a way to launch a process without having to depend on another process to copy a token from? Is there a way to hand-craft a token that can help launch a process as NT AUTHORITY\Network Service using CreateProcessAsUserW(), for example?
I came across a function LogonUser which can be used to create token for required user. The doc shows an example for creating token for NT AUTHORITY\LocalService like this:
LogonUser(L"LocalService", L"NT AUTHORITY", NULL, LOGON32_LOGON_SERVICE, LOGON32_PROVIDER_DEFAULT, &hToken)
I used the above in combination with CreateProcessAsUser function which starts child process as NT AUTHORITY\NetworkService where the parent is running as NT AUTHORITY\System
#include <Windows.h>
HANDLE token;
LogonUser(
L"NetworkService",
L"NT AUTHORITY",
nullptr,
LOGON32_LOGON_SERVICE,
LOGON32_PROVIDER_DEFAULT,
&token);
// Setup required variables to start the process
LPPROCESS_INFORMATION lpProcessInformation;
STARTUPINFOEX si;
PWCHAR path;
PCWSTR environmentBlockPtr = nullptr;
DWORD creationFlags;
WCHAR* commandStr;
CreateProcessAsUser(
token,
nullptr,
const_cast<WCHAR*>(commandStr),
nullptr,
nullptr,
FALSE,
creationFlags,
const_cast<WCHAR*>(environmentBlockPtr),
path,
&si.StartupInfo,
lpProcessInformation);
I suggest you do it via a scheduled task and then delete the task after it runs (or maybe there is a one-shot setting you could use). While System has the create token privilege the NtCreateToken function is not part of the documented API and using it would be an enormous pain. If not a scheduled task then as a service (again even if you are only going to run it once).
Is there a way to hand-craft a token that can help launch a process
as NT AUTHORITY\Network Service
yes. by call NtCreateToken. but for this need have SE_CREATE_TOKEN_PRIVILEGE. but services.exe and services, even running as 'NT AUTHORITY\System' have not it. so you can not just call NtCreateToken. first you need find token with this privilege and only after this.
for get token with required privileges set we can use next code:
extern const SECURITY_QUALITY_OF_SERVICE sqos = {
sizeof (sqos), SecurityImpersonation, SECURITY_DYNAMIC_TRACKING, FALSE
};
extern const OBJECT_ATTRIBUTES oa_sqos = { sizeof(oa_sqos), 0, 0, 0, 0, const_cast<SECURITY_QUALITY_OF_SERVICE*>(&sqos) };
NTSTATUS GetToken(_In_ PVOID buf, _In_ const TOKEN_PRIVILEGES* RequiredSet, _Out_ PHANDLE phToken)
{
NTSTATUS status;
union {
PVOID pv;
PBYTE pb;
PSYSTEM_PROCESS_INFORMATION pspi;
};
pv = buf;
ULONG NextEntryOffset = 0;
do
{
pb += NextEntryOffset;
HANDLE hProcess, hToken, hNewToken;
CLIENT_ID ClientId = { pspi->UniqueProcessId };
if (ClientId.UniqueProcess)
{
if (0 <= NtOpenProcess(&hProcess, PROCESS_QUERY_LIMITED_INFORMATION,
const_cast<POBJECT_ATTRIBUTES>(&oa_sqos), &ClientId))
{
status = NtOpenProcessToken(hProcess, TOKEN_DUPLICATE, &hToken);
NtClose(hProcess);
if (0 <= status)
{
status = NtDuplicateToken(hToken, TOKEN_ADJUST_PRIVILEGES|TOKEN_IMPERSONATE|TOKEN_QUERY,
const_cast<POBJECT_ATTRIBUTES>(&oa_sqos), FALSE, TokenImpersonation, &hNewToken);
NtClose(hToken);
if (0 <= status)
{
status = NtAdjustPrivilegesToken(hNewToken, FALSE, const_cast<PTOKEN_PRIVILEGES>(RequiredSet), 0, 0, 0);
if (STATUS_SUCCESS == status)
{
*phToken = hNewToken;
return STATUS_SUCCESS;
}
NtClose(hNewToken);
}
}
}
}
} while (NextEntryOffset = pspi->NextEntryOffset);
return STATUS_UNSUCCESSFUL;
}
NTSTATUS GetToken(_In_ const TOKEN_PRIVILEGES* RequiredSet, _Out_ PHANDLE phToken)
/*++
Routine Description:
try found process token with RequiredSet; duplicate and adjust privilege
Arguments:
RequiredSet - set of privileges which must be in token
phToken - Impersonation Token with all privileges from RequiredSet, all it is enabled (even if some is disabled in original token)
--*/
{
NTSTATUS status;
ULONG cb = 0x40000;
do
{
status = STATUS_INSUFFICIENT_RESOURCES;
if (PBYTE buf = new BYTE[cb += PAGE_SIZE])
{
if (0 <= (status = NtQuerySystemInformation(SystemProcessInformation, buf, cb, &cb)))
{
status = GetToken(buf, RequiredSet, phToken);
if (status == STATUS_INFO_LENGTH_MISMATCH)
{
status = STATUS_UNSUCCESSFUL;
}
}
delete [] buf;
}
} while(status == STATUS_INFO_LENGTH_MISMATCH);
return status;
}
with this we can do next:
#define BEGIN_PRIVILEGES(name, n) static const union { TOKEN_PRIVILEGES name;\
struct { ULONG PrivilegeCount; LUID_AND_ATTRIBUTES Privileges[n];} label(_) = { n, {
#define LAA(se) {{se}, SE_PRIVILEGE_ENABLED }
#define LAA_D(se) {{se} }
#define END_PRIVILEGES }};};
BEGIN_PRIVILEGES(tp_dbg, 2)
LAA(SE_DEBUG_PRIVILEGE), // need for open processes
LAA(SE_IMPERSONATE_PRIVILEGE), // need for impersonate token
END_PRIVILEGES
BEGIN_PRIVILEGES(tp_cai, 3)
LAA(SE_CREATE_TOKEN_PRIVILEGE),
LAA(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE),
LAA(SE_INCREASE_QUOTA_PRIVILEGE),
END_PRIVILEGES
EXTERN_C NTSYSCALLAPI NTSTATUS NTAPI NtCreateToken(
_Out_ PHANDLE TokenHandle,
_In_ ACCESS_MASK DesiredAccess,
_In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,
_In_ TOKEN_TYPE TokenType,
_In_ PLUID AuthenticationId,
_In_ PLARGE_INTEGER ExpirationTime,
_In_ PTOKEN_USER User,
_In_ PTOKEN_GROUPS Groups,
_In_ PTOKEN_PRIVILEGES Privileges,
_In_opt_ PTOKEN_OWNER Owner,
_In_ PTOKEN_PRIMARY_GROUP PrimaryGroup,
_In_opt_ PTOKEN_DEFAULT_DACL DefaultDacl,
_In_ PTOKEN_SOURCE TokenSource
);
NTSTATUS CreateServiceToken(HANDLE hToken, PHANDLE phToken)
{
NTSTATUS status;
PVOID stack = alloca(guz);
PVOID buf = 0;
ULONG cb = 0, rcb;
struct {
PTOKEN_GROUPS ptg;
PTOKEN_STATISTICS pts;
PTOKEN_DEFAULT_DACL ptdd;
PTOKEN_PRIVILEGES ptp;
} s;
void** ppv = (void**)&s.ptp;
static const ULONG rcbV[] = {
sizeof(TOKEN_GROUPS)+0x80,
sizeof(TOKEN_STATISTICS),
sizeof(TOKEN_DEFAULT_DACL)+0x80,
sizeof(TOKEN_PRIVILEGES)+0x80,
};
static TOKEN_INFORMATION_CLASS TokenInformationClassV[] = {
TokenGroups,
TokenStatistics,
TokenDefaultDacl,
TokenPrivileges,
};
ULONG n = _countof(TokenInformationClassV);
do
{
TOKEN_INFORMATION_CLASS TokenInformationClas = TokenInformationClassV[--n];
rcb = rcbV[n], cb = 0;
do
{
if (cb < rcb)
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
}
status = NtQueryInformationToken(hToken, TokenInformationClas, buf, cb, &rcb);
} while (status == STATUS_BUFFER_TOO_SMALL);
if (0 > status)
{
return status;
}
*(ppv--) = buf, stack = buf;
} while (n);
static const SID NetworkService = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_NETWORK_SERVICE_RID } };
static const TOKEN_OWNER to = { const_cast<SID*>(&NetworkService) };
static const TOKEN_USER tu = { { const_cast<SID*>(&NetworkService) } };
static const TOKEN_SOURCE ts = { {"Advapi"}, SYSTEM_LUID};
return NtCreateToken(phToken, TOKEN_ALL_ACCESS, 0, TokenPrimary,
&s.pts->AuthenticationId, &s.pts->ExpirationTime,
const_cast<PTOKEN_USER>(&tu), s.ptg, s.ptp, const_cast<PTOKEN_OWNER>(&to),
(PTOKEN_PRIMARY_GROUP)&to, s.ptdd, const_cast<PTOKEN_SOURCE>(&ts));
}
NTSTATUS RunAsNetworkService()
{
HANDLE hMyToken, hToken;
NTSTATUS status = NtOpenProcessToken(NtCurrentProcess(), TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &hMyToken);
if (0 <= status)
{
if (0 <= (status = NtAdjustPrivilegesToken(hMyToken, FALSE, const_cast<PTOKEN_PRIVILEGES>(&tp_dbg), 0, 0, 0)))
{
if (0 <= (status = GetToken(&tp_cai, &hToken)))
{
status = RtlSetCurrentThreadToken(hToken);
NtClose(hToken);
if (0 <= status)
{
if (0 <= (status = CreateServiceToken(hMyToken, &hToken)))
{
ULONG SessionId;
ProcessIdToSessionId(GetCurrentProcessId(), &SessionId);
if (0 <= (status = NtSetInformationToken(hToken, TokenSessionId, &SessionId, sizeof(SessionId))))
{
STARTUPINFO si = { sizeof(si) };
si.lpDesktop = const_cast<PWSTR>(L"WinSta0\\Default");
PROCESS_INFORMATION pi;
WCHAR cmdline[] = L"cmd /k whoami.exe /user";
if (CreateProcessAsUserW(hToken, 0, cmdline, 0, 0, 0, 0, 0, 0, &si, &pi))
{
NtClose(pi.hThread);
NtClose(pi.hProcess);
}
else
{
status = RtlGetLastNtStatus();
}
}
NtClose(hToken);
}
RtlSetCurrentThreadToken();
}
}
}
NtClose(hMyToken);
}
return status;
}
(code not use /RTCs )

Shell Execute From Explorer

Trying to follow this sample:
https://devblogs.microsoft.com/oldnewthing/20040520-00/?p=39243
void ShellExecuteFromExplorer(PCWSTR pszFile, PCWSTR pszParameters = nullptr, PCWSTR pszDirectory = nullptr, PCWSTR pszOperation = nullptr, int nShowCmd = SW_SHOWNORMAL)
{
CComPtr<IShellFolderViewDual> spFolderView;
GetDesktopAutomationObject(IID_PPV_ARGS(&spFolderView));
CComPtr<IDispatch> spdispShell;
spFolderView->get_Application(&spdispShell);
CComQIPtr<IShellDispatch2>(spdispShell)
->ShellExecute(CComBSTR(pszFile),
CComVariant(pszParameters ? pszParameters : L""),
CComVariant(pszDirectory ? pszDirectory : L""),
CComVariant(pszOperation ? pszOperation : L""),
CComVariant(nShowCmd));
}
In this case, how do i retrieve the pid from the process being launch from the ShellExecute?
not need use this way for create unelevated process. for instance we can use shell process (explorer) as parent for new process with help PROC_THREAD_ATTRIBUTE_PARENT_PROCESS. example of code
ULONG ExecFromShell(_In_opt_ PCWSTR lpApplicationName,
_Inout_opt_ PWSTR lpCommandLine)
{
if (HWND hwnd = GetShellWindow())
{
ULONG dwProcessId, dwThreadId;
if (dwThreadId = GetWindowThreadProcessId(hwnd, &dwProcessId))
{
if (HANDLE hProcess = OpenProcess(PROCESS_CREATE_PROCESS|READ_CONTROL,
FALSE, dwProcessId))
{
PROCESS_INFORMATION pi;
STARTUPINFOEXW si { sizeof(si)};
SIZE_T s = 0;
ULONG dwError;
__0:
switch (dwError = InitializeProcThreadAttributeList(
si.lpAttributeList, 1, 0, &s) ? NOERROR : GetLastError())
{
case ERROR_INSUFFICIENT_BUFFER:
if (!si.lpAttributeList)
{
si.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)alloca(s);
goto __0;
}
break;
case NOERROR:
if (UpdateProcThreadAttribute(si.lpAttributeList, 0,
PROC_THREAD_ATTRIBUTE_PARENT_PROCESS,
&hProcess, sizeof(hProcess), 0, 0))
{
ULONG cb = 0;
SECURITY_ATTRIBUTES sa = { sizeof(sa) };
__1:
switch (GetKernelObjectSecurity(hProcess,
DACL_SECURITY_INFORMATION|LABEL_SECURITY_INFORMATION,
sa.lpSecurityDescriptor, cb, &cb) ? NOERROR : GetLastError())
{
case ERROR_INSUFFICIENT_BUFFER:
if (!sa.lpSecurityDescriptor)
{
sa.lpSecurityDescriptor = alloca(cb);
goto __1;
}
break;
case NOERROR:
if (CreateProcessW(lpApplicationName, lpCommandLine, &sa, &sa,
FALSE, EXTENDED_STARTUPINFO_PRESENT, 0, 0, &si.StartupInfo, &pi))
{
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
}
else
{
dwError = GetLastError();
}
break;
}
}
else
{
dwError = GetLastError();
}
DeleteProcThreadAttributeList(si.lpAttributeList);
break;
}
CloseHandle(hProcess);
return dwError;
}
return GetLastError();
}
}
return ERROR_NOT_FOUND;
}
In this case, how do i retrieve the pid from the process being launch from the ShellExecute?
You can't. just like ::ShellExecute(), IShellDispatch2::ShellExecute() simply does not provide any information about the new process.

ZwQueryInformationFile() on Windows 64 bits

I have the following code that works fine on Windows 32, already when tested on Windows 64 the text (the path of file) comes missing somes bytes, example:
\Program Files\Folder Software\Subfolder\123456.dll > Windows 32 OK
rogram Files\Folder Software\Subfolder\123456.dll > Windows 64 comes missing some first bytes
this is a bug of ZwQueryInformationFile on Win64 or there is something wrong with the following code that i'm not seeing?
Thanks in advance.
#include <ntifs.h>
#include <ntddk.h>
#include <windef.h>
NTSYSAPI NTSTATUS NTAPI ZwQueryInformationFile(IN HANDLE FileHandle, OUT PIO_STATUS_BLOCK IoStatusBlock, OUT PVOID FileInformation, IN ULONG Length, IN FILE_INFORMATION_CLASS FileInformationClass);
HANDLE GetFileHandle(IN PCWSTR FileName, IN ACCESS_MASK DesiredAccess, IN ULONG ShareAccess)
{
NTSTATUS ntStatus;
UNICODE_STRING uniFileName;
OBJECT_ATTRIBUTES objectAttributes;
HANDLE ntFileHandle;
IO_STATUS_BLOCK ioStatus;
if (KeGetCurrentIrql() > PASSIVE_LEVEL)
{
DbgPrint("KeGetCurrentIrql() > PASSIVE_LEVEL \n");
return 0;
}
RtlInitUnicodeString(&uniFileName, FileName);
InitializeObjectAttributes(&objectAttributes, &uniFileName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
ntStatus = IoCreateFile(&ntFileHandle, DesiredAccess, &objectAttributes, &ioStatus, 0, FILE_ATTRIBUTE_NORMAL, ShareAccess, FILE_OPEN, 0, NULL, 0, 0, NULL, IO_NO_PARAMETER_CHECKING);
if (!NT_SUCCESS(ntStatus))
{
DbgPrint("IoCreateFile() error - 0x%X \n", ntStatus);
return 0;
}
return ntFileHandle;
}
void test()
{
POBJECT_NAME_INFORMATION pfni;
IO_STATUS_BLOCK IoStatus = { 0 };
NTSTATUS status;
HANDLE hFileHandle;
SIZE_T allocSize;
hFileHandle = GetFileHandle(L"\\??\\C:\\Program Files\\Folder Software\\Subfolder\\123456.dll", FILE_READ_ATTRIBUTES, FILE_SHARE_DELETE);
if (hFileHandle != NULL)
{
allocSize = sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR);
pfni = (POBJECT_NAME_INFORMATION)(ExAllocatePool(NonPagedPool, allocSize));
if (pfni != NULL)
{
RtlZeroMemory(pfni, allocSize);
status = ZwQueryInformationFile(hFileHandle, &IoStatus, pfni, allocSize, FileNameInformation);
if (!NT_SUCCESS(status))
DbgPrint("ZwQueryInformationFile() error - 0x%X \n", status);
else
DbgPrint("Filename: %ws \n", &pfni->Name.Buffer);
ExFreePool(pfni);
}
}
}

How do start a process as a normal user?

There is a launcher - a program in C++, which you need to run as administrator. The launcher launches another process as well on behalf of the administrator and because of this, third-party programs (AutoHotkey) running with the rights of a normal user can not access it. The second process does not require administrator rights, so I would like to implement the launch with the rights of a normal user. How to do it?
At the moment I'm running the process using boost::process::system.
Raymond Chen has a blog article on this very topic:
How can I launch an unelevated process from my elevated process and vice versa?
Going from an unelevated process to an elevated process is easy. You can run a process with elevation by passing the runas verb to Shell­Execute or ShellExecute­Ex.
Going the other way is trickier. For one thing, it's really hard to munge your token to remove the elevation nature properly. And for another thing, even if you could do it, it's not the right thing to do, because the unelevated user may be different from the elevated user.
...
The solution here is to go back to Explorer and ask Explorer to launch the program for you. Since Explorer is running as the original unelevated user, the program ... will run as [the user]. 
His article provides the following code to launch an unelevated process, and a detailed explanation of what the code is actually doing (the FindDesktopFolderView function mentioned below is defined in his Manipulating the positions of desktop icons blog article):
#define STRICT
#include <windows.h>
#include <shldisp.h>
#include <shlobj.h>
#include <exdisp.h>
#include <atlbase.h>
#include <stdlib.h>
// FindDesktopFolderView incorporated by reference
void GetDesktopAutomationObject(REFIID riid, void **ppv)
{
CComPtr<IShellView> spsv;
FindDesktopFolderView(IID_PPV_ARGS(&spsv));
CComPtr<IDispatch> spdispView;
spsv->GetItemObject(SVGIO_BACKGROUND, IID_PPV_ARGS(&spdispView));
spdispView->QueryInterface(riid, ppv);
}
void ShellExecuteFromExplorer(
PCWSTR pszFile,
PCWSTR pszParameters = nullptr,
PCWSTR pszDirectory = nullptr,
PCWSTR pszOperation = nullptr,
int nShowCmd = SW_SHOWNORMAL)
{
CComPtr<IShellFolderViewDual> spFolderView;
GetDesktopAutomationObject(IID_PPV_ARGS(&spFolderView));
CComPtr<IDispatch> spdispShell;
spFolderView->get_Application(&spdispShell);
CComQIPtr<IShellDispatch2>(spdispShell)
->ShellExecute(CComBSTR(pszFile),
CComVariant(pszParameters ? pszParameters : L""),
CComVariant(pszDirectory ? pszDirectory : L""),
CComVariant(pszOperation ? pszOperation : L""),
CComVariant(nShowCmd));
}
int __cdecl wmain(int argc, wchar_t **argv)
{
if (argc < 2) return 0;
CCoInitialize init;
ShellExecuteFromExplorer(
argv[1],
argc >= 3 ? argv[2] : L"",
argc >= 4 ? argv[3] : L"",
argc >= 5 ? argv[4] : L"",
argc >= 6 ? _wtoi(argv[5]) : SW_SHOWNORMAL);
return 0;
}
if we run as admin (more concrete have S-1-5-32-544 'Administrators' group enabled in token) we can open local system process token (it grant all needed to as access for 'Administrators').
so we can do next:
get self terminal session id
enable debug privileges in token, for be able open any process with
PROCESS_QUERY_LIMITED_INFORMATION
enumerate running processes in system
open process with PROCESS_QUERY_LIMITED_INFORMATION
open process token with TOKEN_QUERY|TOKEN_DUPLICATE
query token privileges - are it have
SE_ASSIGNPRIMARYTOKEN_PRIVILEGE and SE_INCREASE_QUOTA_PRIVILEGE -
it need for call CreateProcessAsUser and SE_TCB_PRIVILEGE it
require for WTSQueryUserToken
if token have all this privileges (LocalSystem token have) -
duplicate this token to TokenImpersonation type.
if need enable some of this 3 privileges in token
impersonate with this token
and now we can
call WTSQueryUserToken with self session id - for get not elevated
user token
and finally CreateProcessAsUser with this token
reset impersonation
code:
static volatile UCHAR guz;
ULONG RunNonElevated(_In_ ULONG SessionId,
_In_ HANDLE hToken,
_In_opt_ LPCWSTR lpApplicationName,
_Inout_opt_ LPWSTR lpCommandLine,
_In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
_In_ BOOL bInheritHandles,
_In_ DWORD dwCreationFlags,
_In_opt_ LPVOID lpEnvironment,
_In_opt_ LPCWSTR lpCurrentDirectory,
_In_ LPSTARTUPINFOW lpStartupInfo,
_Out_ LPPROCESS_INFORMATION lpProcessInformation)
{
ULONG err;
PVOID stack = alloca(guz);
ULONG cb = 0, rcb = FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges[SE_MAX_WELL_KNOWN_PRIVILEGE]);
union {
PVOID buf;
::PTOKEN_PRIVILEGES ptp;
};
do
{
if (cb < rcb)
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
}
if (GetTokenInformation(hToken, ::TokenPrivileges, buf, cb, &rcb))
{
if (ULONG PrivilegeCount = ptp->PrivilegeCount)
{
int n = 3;
BOOL fAdjust = FALSE;
::PLUID_AND_ATTRIBUTES Privileges = ptp->Privileges;
do
{
switch (Privileges->Luid.LowPart)
{
case SE_ASSIGNPRIMARYTOKEN_PRIVILEGE:
case SE_INCREASE_QUOTA_PRIVILEGE:
case SE_TCB_PRIVILEGE:
if (!(Privileges->Attributes & SE_PRIVILEGE_ENABLED))
{
Privileges->Attributes |= SE_PRIVILEGE_ENABLED;
fAdjust = TRUE;
}
if (!--n)
{
err = NOERROR;
if (DuplicateTokenEx(hToken,
TOKEN_ADJUST_PRIVILEGES|TOKEN_IMPERSONATE,
0, ::SecurityImpersonation, ::TokenImpersonation,
&hToken))
{
if (fAdjust)
{
AdjustTokenPrivileges(hToken, FALSE, ptp, rcb, NULL, NULL);
err = GetLastError();
}
if (err == NOERROR)
{
if (SetThreadToken(0, hToken))
{
HANDLE hUserToken;
if (WTSQueryUserToken(SessionId, &hUserToken))
{
if (!CreateProcessAsUserW(hUserToken,
lpApplicationName,
lpCommandLine,
lpProcessAttributes,
lpThreadAttributes,
bInheritHandles,
dwCreationFlags,
lpEnvironment,
lpCurrentDirectory,
lpStartupInfo,
lpProcessInformation))
{
err = GetLastError();
}
CloseHandle(hUserToken);
}
else
{
err = GetLastError();
}
SetThreadToken(0, 0);
}
else
{
err = GetLastError();
}
}
CloseHandle(hToken);
}
else
{
err = GetLastError();
}
return err;
}
}
} while (Privileges++, --PrivilegeCount);
}
return ERROR_NOT_FOUND;
}
} while ((err = GetLastError()) == ERROR_INSUFFICIENT_BUFFER);
return err;
}
ULONG RunNonElevated(_In_opt_ LPCWSTR lpApplicationName,
_Inout_opt_ LPWSTR lpCommandLine,
_In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
_In_ BOOL bInheritHandles,
_In_ DWORD dwCreationFlags,
_In_opt_ LPVOID lpEnvironment,
_In_opt_ LPCWSTR lpCurrentDirectory,
_In_ LPSTARTUPINFOW lpStartupInfo,
_Out_ LPPROCESS_INFORMATION lpProcessInformation
)
{
ULONG SessionId;
if (!ProcessIdToSessionId(GetCurrentProcessId(), &SessionId))
{
return GetLastError();
}
BOOLEAN b;
RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE, TRUE, FALSE, b);
ULONG err = NOERROR;
// much more effective of course use NtQuerySystemInformation(SystemProcessesAndThreadsInformation) here
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0), hToken;
if (hSnapshot != INVALID_HANDLE_VALUE)
{
PROCESSENTRY32W pe = { sizeof(pe) };
if (Process32FirstW(hSnapshot, &pe))
{
err = ERROR_NOT_FOUND;
do
{
if (pe.th32ProcessID && pe.th32ParentProcessID)
{
if (HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pe.th32ProcessID))
{
if (OpenProcessToken(hProcess, TOKEN_QUERY|TOKEN_DUPLICATE, &hToken))
{
err = RunNonElevated(
SessionId,
hToken,
lpApplicationName,
lpCommandLine,
lpProcessAttributes,
lpThreadAttributes,
bInheritHandles,
dwCreationFlags,
lpEnvironment,
lpCurrentDirectory,
lpStartupInfo,
lpProcessInformation);
CloseHandle(hToken);
}
else
{
err = GetLastError();
}
CloseHandle(hProcess);
}
else
{
err = GetLastError();
}
}
} while (err && Process32NextW(hSnapshot, &pe));
}
else
{
err = GetLastError();
}
CloseHandle(hSnapshot);
}
return err;
}
and test:
void test()
{
STARTUPINFO si = { sizeof(si)};
PROCESS_INFORMATION pi;
WCHAR ApplicationName[MAX_PATH];
if (GetEnvironmentVariableW(L"ComSpec", ApplicationName, RTL_NUMBER_OF(ApplicationName)))
{
if (!RunNonElevated(ApplicationName, L"cmd /k whoami.exe /priv /groups",0,0,0,0,0,0,&si, &pi))
{
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
}
}
with this we can not only run not elevated process, but ,if need, start it with duplicated handles

CreateProcessAsUser fail,use GetLastError() to get the error code is 1314

I use win7 os and the develop environment is vs2005.
The situation is I want to create the process as current account's priviledge.(such as: in the normal account ,right click the program choice "run as admin" )
I refer to other people's way:
1.get the token of the process explorer.exe;
2.improve the priviledge;
3.use the CreateProcessAsUser to create a process.
But the CreateProcessAsUser failed,and use GetLastError() to get the error code is 1314.
Because of that, I think I'am crazy now.
Can you tell me what's wrong in my program. Thank you!!!
#include <iostream>
using namespace std;
#include "windows.h"
#include "tlhelp32.h"
BOOL GetProcessTokenByName(HANDLE &hToken, LPTSTR szProcessName)
{
// var init
STARTUPINFO st;
PROCESS_INFORMATION pi;
PROCESSENTRY32 ps;
HANDLE hSnapshot;
ZeroMemory(&st, sizeof(STARTUPINFO));
ZeroMemory(&pi, sizeof(PROCESS_INFORMATIO
N));
st.cb = sizeof(STARTUPINFO);
ZeroMemory(&ps,sizeof(PROCESSENTRY32));
ps.dwSize = sizeof(PROCESSENTRY32);
// find the explorer.exe
hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0);
if(hSnapshot == INVALID_HANDLE_VALUE)
{
return FALSE;
}
if(!Process32First(hSnapshot,&ps))
{
return FALSE;
}
do
{
wprintf(_T("%s , %u\n"), ps.szExeFile, ps.th32ProcessID);
// compare the process name
if(lstrcmpi(ps.szExeFile,szProcessName)==0)
{ // find
//*lpPID = ps.th32ProcessID;
//CloseHandle(hSnapshot);
//return TRUE;
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, ps.th32ProcessID);
BOOL bRet = FALSE;
HANDLE tmpToken;
if( OpenProcessToken(hProcess, /*TOKEN_QUERY*/TOKEN_ALL_ACCESS, &tmpToken) )
{
bRet = DuplicateTokenEx(
tmpToken, //_In_ HANDLE hExistingToken,
MAXIMUM_ALLOWED, //_In_ DWORD dwDesiredAccess,
NULL, //_In_opt_ LPSECURITY_ATTRIBUTES lpTokenAttributes,
SecurityIdentification, //_In_ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
TokenPrimary, //_In_ TOKEN_TYPE TokenType,
&hToken //_Out_ PHANDLE phNewToken
);
//DWORD dwSessionId = WTSGetActiveConsoleSessionId();
//SetTokenInformation(hToken,TokenSessionId,(void*)dwSessionId,sizeof(DWORD));
//SetPrivilege(hToken, SE_ASSIGNPRIMARYTOKEN_NAME, TRUE);
}
else
{
printf("OpenProcessToken error: %u\n", GetLastError());
}
CloseHandle (hSnapshot);
return (bRet);
}
}while(Process32Next(hSnapshot,&ps));
// didn't find
CloseHandle(hSnapshot);
return FALSE;
}
BOOL RunasUser( )
{
HANDLE hToken;
if( GetProcessTokenByName( hToken, _T("explorer.exe") ) )
{
if( hToken != INVALID_HANDLE_VALUE )
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb= sizeof(STARTUPINFO);
si.lpDesktop = TEXT("winsta0\\default");
{
TOKEN_PRIVILEGES tp;
tp.PrivilegeCount =1;
if(!LookupPrivilegeValue(NULL,SE_ASSIGNPRIMARYTOKEN_NAME/*SE_DEBUG_NAME*/,&tp.Privileges[0].Luid))
{
printf("LookupPrivilegeValue value Error: %u\n",GetLastError());
}
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if(!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES)NULL, NULL) )
{
printf("Adjust Privilege value Error: %u\n",GetLastError());
}
}
printf("Adjust Privilege\n");
{
TOKEN_PRIVILEGES tp;
tp.PrivilegeCount =1;
if(!LookupPrivilegeValue(NULL,SE_INCREASE_QUOTA_NAME/*SE_DEBUG_NAME*/,&tp.Privileges[0].Luid))
{
printf("LookupPrivilegeValue value Error: %u\n",GetLastError());
}
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if(!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES)NULL, NULL) )
{
printf("Adjust Privilege value Error: %u\n",GetLastError());
}
}
BOOL bResult = CreateProcessAsUser(
hToken, //_In_opt_ HANDLE hToken,
_T("D:\\GetMac.exe"), //_In_opt_ LPCTSTR lpApplicationName,
NULL, //_Inout_opt_ LPTSTR lpCommandLine,
NULL, //_In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
NULL, //_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
FALSE, //_In_ BOOL bInheritHandles,
NORMAL_PRIORITY_CLASS, //_In_ DWORD dwCreationFlags,
NULL, //_In_opt_ LPVOID lpEnvironment,
NULL, //_In_opt_ LPCTSTR lpCurrentDirectory,
&si, //_In_ LPSTARTUPINFO lpStartupInfo,
&pi //_Out_ LPPROCESS_INFORMATION lpProcessInformation
);
CloseHandle(hToken);
if( bResult )
{
//succeed
return TRUE;
}
else
{ //fail
DWORD dwErr = GetLastError();
printf( "error: %u\n", dwErr );
}
}
}
else
{
printf("GetProcessTokenByName fail\n");
}
return FALSE;
}
int _tmain(int argc, _TCHAR* argv[])
{
BOOL bRet = RunasUser();
printf("result: %d\n", bRet);
system("pause");
return 0;
}