I want to use large pages in my app like this:
VirtualAlloc(NULL, n_bytes, MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE, PAGE_READWRITE);
I plan to enable large pages for the current user during installation, while having elevated admin rights. Does anyone have code for enabling large pages programmatically?
I'm posting what I've gathered.
The general idea:
Enable large pages for the current user account. (Requires admin rights).
Enable large pages for the current process token. (Requires admin rights).
Allocate the memory (granular to large page size, 2Mb, in fact).
If you have UAC properly disabled, you need to execute step 1 only once with admin rights. If you have UAC enabled, you always have to execute it all with admin rights.
#define UNICODE
#define _UNICODE
#include <windows.h>
#include <ntsecapi.h>
#include <ntstatus.h>
#include <Sddl.h>
void InitLsaString(PLSA_UNICODE_STRING LsaString, LPWSTR String)
{
DWORD StringLength;
if (String == NULL) {
LsaString->Buffer = NULL;
LsaString->Length = 0;
LsaString->MaximumLength = 0;
return;
}
StringLength = wcslen(String);
LsaString->Buffer = String;
LsaString->Length = (USHORT)StringLength * sizeof(WCHAR);
LsaString->MaximumLength = (USHORT)(StringLength + 1) * sizeof(WCHAR);
}
NTSTATUS OpenPolicy(LPWSTR ServerName, DWORD DesiredAccess, PLSA_HANDLE PolicyHandle)
{
LSA_OBJECT_ATTRIBUTES ObjectAttributes;
LSA_UNICODE_STRING ServerString;
PLSA_UNICODE_STRING Server = NULL;
//
// Always initialize the object attributes to all zeroes.
//
ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));
if (ServerName != NULL) {
//
// Make a LSA_UNICODE_STRING out of the LPWSTR passed in
//
InitLsaString(&ServerString, ServerName);
Server = &ServerString;
}
//
// Attempt to open the policy.
//
return LsaOpenPolicy(
Server,
&ObjectAttributes,
DesiredAccess,
PolicyHandle
);
}
NTSTATUS SetPrivilegeOnAccount(LSA_HANDLE PolicyHandle, PSID AccountSid, LPWSTR PrivilegeName, BOOL bEnable)
{
LSA_UNICODE_STRING PrivilegeString;
//
// Create a LSA_UNICODE_STRING for the privilege name.
//
InitLsaString(&PrivilegeString, PrivilegeName);
//
// grant or revoke the privilege, accordingly
//
if (bEnable) {
return LsaAddAccountRights(
PolicyHandle, // open policy handle
AccountSid, // target SID
&PrivilegeString, // privileges
1 // privilege count
);
}
else {
return LsaRemoveAccountRights(
PolicyHandle, // open policy handle
AccountSid, // target SID
FALSE, // do not disable all rights
&PrivilegeString, // privileges
1 // privilege count
);
}
}
void main()
{
HANDLE hToken = NULL;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
{
applog(LOG_INFO, "OpenProcessToken failed. GetLastError returned: %d\n", GetLastError());
return -1;
}
DWORD dwBufferSize = 0;
// Probe the buffer size reqired for PTOKEN_USER structure
if (!GetTokenInformation(hToken, TokenUser, NULL, 0, &dwBufferSize) &&
(GetLastError() != ERROR_INSUFFICIENT_BUFFER))
{
applog(LOG_INFO, "GetTokenInformation failed. GetLastError returned: %d\n", GetLastError());
// Cleanup
CloseHandle(hToken);
hToken = NULL;
return -1;
}
PTOKEN_USER pTokenUser = (PTOKEN_USER) malloc(dwBufferSize);
// Retrieve the token information in a TOKEN_USER structure
if (!GetTokenInformation(
hToken,
TokenUser,
pTokenUser,
dwBufferSize,
&dwBufferSize))
{
applog(LOG_INFO, "GetTokenInformation failed. GetLastError returned: %d\n", GetLastError());
// Cleanup
CloseHandle(hToken);
hToken = NULL;
return -1;
}
// Print SID string
LPWSTR strsid;
ConvertSidToStringSid(pTokenUser->User.Sid, &strsid);
applog(LOG_INFO, "User SID: %S\n", strsid);
// Cleanup
CloseHandle(hToken);
hToken = NULL;
NTSTATUS status;
LSA_HANDLE policyHandle;
if (status = OpenPolicy(NULL, POLICY_CREATE_ACCOUNT | POLICY_LOOKUP_NAMES, &policyHandle))
{
applog(LOG_INFO, "OpenPolicy %d", status);
}
// Add new privelege to the account
if (status = SetPrivilegeOnAccount(policyHandle, pTokenUser->User.Sid, SE_LOCK_MEMORY_NAME, TRUE))
{
applog(LOG_INFO, "OpenPSetPrivilegeOnAccountolicy %d", status);
}
// Enable this priveledge for the current process
hToken = NULL;
TOKEN_PRIVILEGES tp;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &hToken))
{
applog(LOG_INFO, "OpenProcessToken #2 failed. GetLastError returned: %d\n", GetLastError());
return -1;
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (!LookupPrivilegeValue(NULL, SE_LOCK_MEMORY_NAME, &tp.Privileges[0].Luid))
{
applog(LOG_INFO, "LookupPrivilegeValue failed. GetLastError returned: %d\n", GetLastError());
return -1;
}
BOOL result = AdjustTokenPrivileges(hToken, FALSE, &tp, 0, (PTOKEN_PRIVILEGES)NULL, 0);
DWORD error = GetLastError();
if (!result || (error != ERROR_SUCCESS))
{
applog(LOG_INFO, "AdjustTokenPrivileges failed. GetLastError returned: %d\n", error);
return -1;
}
// Cleanup
CloseHandle(hToken);
hToken = NULL;
SIZE_T pageSize = GetLargePageMinimum();
// Finally allocate the memory
char *largeBuffer = VirtualAlloc(NULL, pageSize * N_PAGES_TO_ALLOC, MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE);
if (largeBuffer)
{
applog(LOG_INFO, "VirtualAlloc failed, error 0x%x", GetLastError());
}
}
Related
I want to list all executed runs of custom task of the Task Scheduler in C/C++. Therefore I access the Event Log and try to extract the TaskScheduler log entries, like so (removed all error handling for simplicity):
HANDLE hEv = OpenEventLogA(NULL, "Microsoft-Windows-TaskScheduler/Operational");
DWORD nrRead = 0x10000, status = ERROR_SUCCESS, nrMin = 0, nrDone;
PBYTE buf = (PBYTE) malloc(nrRead);
while (status == ERROR_SUCCESS) {
if (!ReadEventLog(hEv, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_BACKWARDS_READ,
0, buf, nrRead, &nrDone, &nrMin)) status = GetLastError();
for (PBYTE pRec = buf, pEnd = buf + nrRead; pRec < pEnd;) {
(void) (pRec + sizeof(EVENTLOGRECORD)); // Store record
pRec += ((PEVENTLOGRECORD) pRec)->Length;
if (((PEVENTLOGRECORD) pRec)->Length == 0) break; // Avoid endless loop
}
}
Actually I am able to read events from the log (e.g. the WiFi log). But I cannot open the TaskScheduler log. It then does as described in the documentation and falls back to the Application log.
I tried different strings for the log's name:
Protocol name from the Event Log
Path to the protocol separated by slashes
English and localized names
None of it seems to work. So how can I open the TaskScheduler log? Is the log name localized and needs to be adjusted according to the current Operating System language? Is there another way to retrieve the TaskScheduler executions?
I have tried your code, seem like OpenEventLog can only open some log that frequently-used(not sure). However, there is another way to list TaskScheduler event:
use EvtSubscribe() to add the callback function, When a record is queried, print it out in XML format. Here is the code example:
#include <windows.h>
#include <sddl.h>
#include <stdio.h>
#include <winevt.h>
#pragma comment(lib, "wevtapi.lib")
const int SIZE_DATA = 4096;
TCHAR XMLDataCurrent[SIZE_DATA];
TCHAR XMLDataUser[SIZE_DATA];
#define ARRAY_SIZE 10
#define TIMEOUT 1000 // 1 second; Set and use in place of INFINITE in EvtNext call
DWORD PrintEvent(EVT_HANDLE hEvent); // Shown in the Rendering Events topic
DWORD WINAPI SubscriptionCallback(EVT_SUBSCRIBE_NOTIFY_ACTION action, PVOID pContext, EVT_HANDLE hEvent);
void main(void)
{
DWORD status = ERROR_SUCCESS;
EVT_HANDLE hResults = NULL;
//hResults = EvtQuery(NULL, pwsPath, pwsQuery, EvtQueryChannelPath );// EvtQueryReverseDirection);
hResults = EvtSubscribe(NULL, NULL, L"Microsoft-Windows-TaskScheduler/Operational", NULL, NULL, NULL, (EVT_SUBSCRIBE_CALLBACK)SubscriptionCallback, EvtSubscribeStartAtOldestRecord);
if (NULL == hResults)
{
status = GetLastError();
if (ERROR_EVT_CHANNEL_NOT_FOUND == status)
wprintf(L"The channel was not found.\n");
else if (ERROR_EVT_INVALID_QUERY == status)
// You can call the EvtGetExtendedStatus function to try to get
// additional information as to what is wrong with the query.
wprintf(L"The query is not valid.\n");
else
wprintf(L"EvtQuery failed with %lu.\n", status);
}
Sleep(1000);
cleanup:
if (hResults)
EvtClose(hResults);
}
// The callback that receives the events that match the query criteria.
DWORD WINAPI SubscriptionCallback(EVT_SUBSCRIBE_NOTIFY_ACTION action, PVOID pContext, EVT_HANDLE hEvent)
{
UNREFERENCED_PARAMETER(pContext);
DWORD status = ERROR_SUCCESS;
switch (action)
{
// You should only get the EvtSubscribeActionError action if your subscription flags
// includes EvtSubscribeStrict and the channel contains missing event records.
case EvtSubscribeActionError:
if (ERROR_EVT_QUERY_RESULT_STALE == (DWORD)hEvent)
{
wprintf(L"The subscription callback was notified that event records are missing.\n");
// Handle if this is an issue for your application.
}
else
{
wprintf(L"The subscription callback received the following Win32 error: %lu\n", (DWORD)hEvent);
}
break;
case EvtSubscribeActionDeliver:
if (ERROR_SUCCESS != (status = PrintEvent(hEvent)))
{
goto cleanup;
}
break;
default:
wprintf(L"SubscriptionCallback: Unknown action.\n");
}
cleanup:
if (ERROR_SUCCESS != status)
{
// End subscription - Use some kind of IPC mechanism to signal
// your application to close the subscription handle.
}
return status; // The service ignores the returned status.
}
DWORD PrintEvent(EVT_HANDLE hEvent)
{
DWORD status = ERROR_SUCCESS;
DWORD dwBufferSize = 0;
DWORD dwBufferUsed = 0;
DWORD dwPropertyCount = 0;
LPWSTR pRenderedContent = NULL;
if (!EvtRender(NULL, hEvent, EvtRenderEventXml, dwBufferSize, pRenderedContent, &dwBufferUsed, &dwPropertyCount))
{
if (ERROR_INSUFFICIENT_BUFFER == (status = GetLastError()))
{
dwBufferSize = dwBufferUsed;
pRenderedContent = (LPWSTR)malloc(dwBufferSize);
if (pRenderedContent)
{
EvtRender(NULL, hEvent, EvtRenderEventXml, dwBufferSize, pRenderedContent, &dwBufferUsed, &dwPropertyCount);
}
else
{
wprintf(L"malloc failed\n");
status = ERROR_OUTOFMEMORY;
goto cleanup;
}
}
if (ERROR_SUCCESS != (status = GetLastError()))
{
wprintf(L"EvtRender failed with %d\n", status);
goto cleanup;
}
}
ZeroMemory(XMLDataCurrent, SIZE_DATA);
lstrcpyW(XMLDataCurrent, pRenderedContent);
wprintf(L"EvtRender data %s\n", XMLDataCurrent);
cleanup:
if (pRenderedContent)
free(pRenderedContent);
return status;
}
Hope it could help you!
Thank you #zett42 for pointing me in the right direction and #Drake Wu for the detailed code example. But as I don't need any future event or asynchronous retrieval, I now implemented a simple synchronous function:
#define EVT_SIZE 10
int GetEvents(LPCWSTR query) {
DWORD xmlLen = 0;
LPCWSTR xml = NULL;
EVT_HANDLE hQuery = EvtQuery(NULL, NULL, query, EvtQueryChannelPath | EvtQueryTolerateQueryErrors));
while (true) {
EVT_HANDLE hEv[EVT_SIZE];
DWORD dwReturned = 0;
if (!EvtNext(hQuery, EVT_SIZE, hEv, INFINITE, 0, &dwReturned)) return 0;
// Loop over all events
for (DWORD i = 0; i < dwReturned; i++) {
DWORD nrRead = 0, nrProps = 0;
if (!EvtRender(NULL, hEv[i], EvtRenderEventXml, xmlLen, xml, &nrRead, &nrProps)) {
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
xmlLen = nrRead;
xml = (LPWSTR) realloc(xml, xmlLen);
if (xml) {
EvtRender(NULL, hEv[i], EvtRenderEventXml, xmlLen, xml, &nrRead, &nrProps);
} else {
return -1;
}
}
if (GetLastError() != ERROR_SUCCESS) return -1;
}
// Store event data
EvtClose(hEv[i]);
hEv[i] = NULL;
}
}
return 0;
}
Again I removed most error handling for simplifying the example. The Evt* functions indeed work for the retrieval of the TaskScheduler data (independently from the language).
I am trying to share some data between 2 processes. The first writes the data in mapped file and the second reads it.
Here's my code so far:
First process:
#include "stdafx.h"
#include <Windows.h>
#include <tlhelp32.h>
#include <tchar.h>
#include<stdio.h>
#define BUF_SIZE 256
int _tmain(int argc, _TCHAR* argv[]) {
TCHAR szName[] = TEXT("Global\\MyFileMappingObject");
LPTSTR szMsg = TEXT("MESS");
HANDLE tokenH;
TOKEN_PRIVILEGES tp;
LUID luid;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &tokenH)) {
printf("OpenProcessToken error: %u\n", GetLastError());
return FALSE;
}
if (!LookupPrivilegeValue(NULL, SE_CREATE_GLOBAL_NAME, &luid)) {
printf("LookupPrivilegeValue error: %u\n", GetLastError());
return FALSE;
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (!AdjustTokenPrivileges(tokenH, FALSE, &tp, sizeof(TOKEN_PRIVILEGES),(PTOKEN_PRIVILEGES)NULL, (PDWORD)NULL)) {
printf("AdjustTokenPrivileges error: %u\n", GetLastError());
return FALSE;
}
if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
{
printf("The token does not have the specified privilege. \n");
return FALSE;
}
CloseHandle(tokenH);
HANDLE hMapFile;
LPCTSTR pBuf;
hMapFile = CreateFileMapping(
INVALID_HANDLE_VALUE,
NULL,
PAGE_READWRITE,
0,
BUF_SIZE,
szName);
if (hMapFile == NULL)
{
_tprintf(TEXT("Could not create file mapping object (%d).\n"),
GetLastError());
return 1;
}
pBuf = (LPTSTR)MapViewOfFile(hMapFile,
FILE_MAP_ALL_ACCESS,
0,
0,
BUF_SIZE);
if (pBuf == NULL)
{
_tprintf(TEXT("Could not map view of file (%d).\n"),
GetLastError());
CloseHandle(hMapFile);
return 1;
}
CopyMemory((PVOID)pBuf, szMsg, (_tcslen(szMsg) * sizeof(TCHAR)));
UnmapViewOfFile(pBuf);
printf("Done\n");
CloseHandle(hMapFile);
return 0;
}
Second process:
#include "stdafx.h"
#include <Windows.h>
#include <tlhelp32.h>
#include <tchar.h>
#include <stdio.h>
#pragma comment(lib, "user32.lib")
#define BUF_SIZE 256
int _tmain(int argc, _TCHAR* argv[])
{
TCHAR szName[] = TEXT("Global\\MyFileMappingObject");
HANDLE tokenH;
TOKEN_PRIVILEGES tp;
LUID luid;
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &tokenH);
if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) {
printf("LookupPrivilegeValue error: %u\n", GetLastError());
return FALSE;
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (!AdjustTokenPrivileges(tokenH, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES)NULL, (PDWORD)NULL)) {
printf("AdjustTokenPrivileges error: %u\n", GetLastError());
return FALSE;
}
if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
{
printf("The token does not have the specified privilege. \n");
return FALSE;
}
CloseHandle(tokenH);
HANDLE hMapFile;
LPCTSTR pBuf;
hMapFile = OpenFileMapping(
FILE_MAP_ALL_ACCESS, // read/write access
FALSE, // do not inherit the name
szName); // name of mapping object
if (hMapFile == NULL)
{
_tprintf(TEXT("Could not open file mapping object (%d).\n"),
GetLastError());
return 1;
}
pBuf = (LPTSTR)MapViewOfFile(hMapFile, // handle to map object
FILE_MAP_ALL_ACCESS, // read/write permission
0,
0,
BUF_SIZE);
if (pBuf == NULL)
{
_tprintf(TEXT("Could not map view of file (%d).\n"),
GetLastError());
CloseHandle(hMapFile);
return 1;
}
MessageBox(NULL, pBuf, TEXT("Process2"), MB_OK);
UnmapViewOfFile(pBuf);
CloseHandle(hMapFile);
return 0;
}
The first process manages to write its data (I don't receive any error message and get the "Done" message), but the problem is with the the second process.
After "OpenFileMapping", I get from getLastError the code 2 which is for non-existent file. I run both processes as administrator.
Error 2 is ERROR_FILE_NOT_FOUND, which means the named mapping object does not exist at the time OpenFileMapping() is called.
In order to share a named kernel object between processes, both processes need to be running at the same time. Like other named kernel objects (events, mutexes, etc), a mapping object has a reference count associated with it, where each open handle increments the reference count. After all handles are closed, the object is destroyed.
So, when the first app unmaps its view and closes its handle to the mapping object, the object will be destroyed if the second app does not already have its own handle open to the same mapping object. Thus the object will not exist when the second app tries to open it.
Handling & processing data from named pipes.
I am trying to implement a service provider to connect with a hardware device.
request some pointers on my approach to implement a robust system.
Mentioned are the raised requirements
Receive data from other EXE process
To process received Q information and send response information in clients response channel.
Asynchronously send information on some failure to client response channel.
TO implement the mentioned system:
Selected 2 named pipe (ClntcommandRecv & ClntRespSend) .bcz of between process (IPC)
ClntcommandRecv pipe will be used as "Named Pipe Server Using Overlapped" I/O"
ClntRespSend pipe will be used for sending the processed information.
ClntRespSend will also need to send all the async messages from service provider to connected application.
From here my implementation is straight forward.
Using "Named Pipe Server Using Overlapped I/O" by documentation I will be able to address multiple client connection request and its data processing using single thread.
On init system will create a thread to hold connection instance of clients ClntRespSend pipe.
Since, it requires for device to tell its failures to connected clients asynchronously.
Is it advisable for system to have timeout operation on "WaitForMultipleObjects" or
can we have readfile timeout counts after n timeout can we check for health info.WHich is advised
But, stuck in finding the best way to sync my ClntRespSend & ClntcommandRecv (MAPPIN).
Need to get process id of the connected process.Since the system is developed under MINGW - WIN32 - server will not be able to get the process id directly by using (GetNamedPipeClientProcessId).
Need to form a message structure on getting a client connection.
This is the code which i am trying to extend:
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
//#include <strsafe.h>
//#include <glib.h>
#define CONNECTING_STATE 0
#define READING_STATE 1
#define WRITING_STATE 2
#define INSTANCES 4
#define PIPE_TIMEOUT 5000
#define BUFSIZE 4096
typedef struct
{
OVERLAPPED oOverlap;
HANDLE hPipeInst;
TCHAR chRequest[BUFSIZE];
DWORD cbRead;
TCHAR chReply[BUFSIZE];
DWORD cbToWrite;
DWORD dwState;
BOOL fPendingIO;
int processId;
} PIPEINST, *LPPIPEINST;
typedef struct
{
char appName[256];
int processId;
}PIPEHANDSHAKE;
VOID DisconnectAndReconnect(DWORD);
BOOL ConnectToNewClient(HANDLE, LPOVERLAPPED);
VOID GetAnswerToRequest(LPPIPEINST);
PIPEINST Pipe[INSTANCES];
HANDLE hEvents[INSTANCES];
HANDLE responsePipeHandle[INSTANCES];
DWORD WINAPI InstanceThread(LPVOID);
HANDLE hPipeHandles[10];
PULONG s;
LPTSTR lpszPipename = TEXT("\\\\.\\pipe\\mynamedpipe");
LPTSTR lpszResponsePipe = TEXT("\\\\.\\pipe\\mynamedpipe1");
//GHashTable* hash;
int responsePipeConnectionHandler(VOID)
{
BOOL fConnected = FALSE;
DWORD dwThreadId = 0;
HANDLE hPipe = INVALID_HANDLE_VALUE, hThread = NULL;
int cbBytesRead;
INT threadCount=0;
//hash = g_hash_table_new(g_str_hash, g_str_equal);
char bufferSize[512];
for (;;)
{
_tprintf( TEXT("\nPipe Server: Main thread awaiting client connection on %s\n"), lpszResponsePipe);
hPipe = CreateNamedPipe(
lpszResponsePipe, // pipe name
PIPE_ACCESS_DUPLEX, // read/write access
PIPE_TYPE_MESSAGE | // message type pipe
PIPE_READMODE_MESSAGE | // message-read mode
PIPE_WAIT, // blocking mode
PIPE_UNLIMITED_INSTANCES, // max. instances
BUFSIZE, // output buffer size
BUFSIZE, // input buffer size
0, // client time-out
NULL); // default security attribute
if (hPipe == INVALID_HANDLE_VALUE)
{
_tprintf(TEXT("CreateNamedPipe failed, GLE=%d.\n"), GetLastError());
return -1;
}
// Wait for the client to connect; if it succeeds,
// the function returns a nonzero value. If the function
// returns zero, GetLastError returns ERROR_PIPE_CONNECTED.
fConnected = ConnectNamedPipe(hPipe, NULL) ?
TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
if(fConnected){
PIPEHANDSHAKE processData;
fConnected = ReadFile(
hPipe, // handle to pipe
bufferSize, // buffer to receive data
sizeof(PIPEHANDSHAKE), // size of buffer
&cbBytesRead, // number of bytes read
NULL); // not overlapped I/O
memset(&processData,0,sizeof(PIPEHANDSHAKE));
memcpy(&processData,&bufferSize,sizeof(PIPEHANDSHAKE));
printf("APP Process id: %d , app name: %s",processData.processId,processData.appName);
}
/* if (fConnected)
{
printf("Client connected, creating a processing thread.\n");
// Create a thread for this client.
hThread = CreateThread(
NULL, // no security attribute
0, // default stack size
InstanceThread, // thread proc
(LPVOID) hPipe, // thread parameter
0, // not suspended
&dwThreadId); // returns thread ID
if (hThread == NULL)
{
_tprintf(TEXT("CreateThread failed, GLE=%d.\n"), GetLastError());
return -1;
}
else CloseHandle(hThread);
}
else
// The client could not connect, so close the pipe.
CloseHandle(hPipe);*/
}
return 0;
}
int _tmain(VOID)
{
DWORD i, dwWait, cbRet, dwErr,hThread;
BOOL fSuccess;
int dwThreadId;
// The initial loop creates several instances of a named pipe
// along with an event object for each instance. An
// overlapped ConnectNamedPipe operation is started for
// each instance.
// Create response pipe thread
hThread = CreateThread(
NULL, // no security attribute
0, // default stack size
responsePipeConnectionHandler, // thread proc
NULL, // thread parameter
0, // not suspended
&dwThreadId); // returns thread ID
if (hThread == NULL)
{
printf("Response server creation failed with %d.\n", GetLastError());
return 0;
}
for (i = 0; i < INSTANCES; i++)
{
// Create an event object for this instance.
hEvents[i] = CreateEvent(
NULL, // default security attribute
TRUE, // manual-reset event
TRUE, // initial state = signaled
NULL); // unnamed event object
if (hEvents[i] == NULL)
{
printf("CreateEvent failed with %d.\n", GetLastError());
return 0;
}
Pipe[i].oOverlap.hEvent = hEvents[i];
Pipe[i].hPipeInst = CreateNamedPipe(
lpszPipename, // pipe name
PIPE_ACCESS_DUPLEX | // read/write access
FILE_FLAG_OVERLAPPED, // overlapped mode
PIPE_TYPE_MESSAGE | // message-type pipe
PIPE_READMODE_MESSAGE | // message-read mode
PIPE_WAIT, // blocking mode
INSTANCES, // number of instances
BUFSIZE*sizeof(TCHAR), // output buffer size
BUFSIZE*sizeof(TCHAR), // input buffer size
PIPE_TIMEOUT, // client time-out
NULL); // default security attributes
if (Pipe[i].hPipeInst == INVALID_HANDLE_VALUE)
{
printf("CreateNamedPipe failed with %d.\n", GetLastError());
return 0;
}
// Call the subroutine to connect to the new client
Pipe[i].fPendingIO = ConnectToNewClient(
Pipe[i].hPipeInst,
&Pipe[i].oOverlap);
Pipe[i].dwState = Pipe[i].fPendingIO ?
CONNECTING_STATE : // still connecting
READING_STATE; // ready to read
}
while (1)
{
dwWait = WaitForMultipleObjects(
INSTANCES, // number of event objects
hEvents, // array of event objects
FALSE, // does not wait for all
INFINITE); // waits indefinitely
// dwWait shows which pipe completed the operation.
i = dwWait - WAIT_OBJECT_0; // determines which pipe
if (i < 0 || i > (INSTANCES - 1))
{
printf("Index out of range.\n");
return 0;
}
// Get the result if the operation was pending.
if (Pipe[i].fPendingIO)
{
fSuccess = GetOverlappedResult(
Pipe[i].hPipeInst, // handle to pipe
&Pipe[i].oOverlap, // OVERLAPPED structure
&cbRet, // bytes transferred
FALSE); // do not wait
switch (Pipe[i].dwState)
{
// Pending connect operation
case CONNECTING_STATE:
if (! fSuccess)
{
printf("Error %d.\n", GetLastError());
return 0;
}
Pipe[i].dwState = READING_STATE;
break;
// Pending read operation
case READING_STATE:
if (! fSuccess || cbRet == 0)
{
DisconnectAndReconnect(i);
continue;
}
Pipe[i].cbRead = cbRet;
Pipe[i].dwState = WRITING_STATE;
break;
// Pending write operation
case WRITING_STATE:
if (! fSuccess || cbRet != Pipe[i].cbToWrite)
{
DisconnectAndReconnect(i);
continue;
}
Pipe[i].dwState = READING_STATE;
break;
default:
{
printf("Invalid pipe state.\n");
return 0;
}
}
}
// The pipe state determines which operation to do next.
switch (Pipe[i].dwState)
{
case READING_STATE:
fSuccess = ReadFile(
Pipe[i].hPipeInst,
Pipe[i].chRequest,
BUFSIZE*sizeof(TCHAR),
&Pipe[i].cbRead,
&Pipe[i].oOverlap);
if (fSuccess && Pipe[i].cbRead != 0)
{
Pipe[i].fPendingIO = FALSE;
Pipe[i].dwState = WRITING_STATE;
continue;
}
dwErr = GetLastError();
if (! fSuccess && (dwErr == ERROR_IO_PENDING))
{
Pipe[i].fPendingIO = TRUE;
continue;
}
DisconnectAndReconnect(i);
break;
case WRITING_STATE:
GetAnswerToRequest(&Pipe[i]);
fSuccess = WriteFile(
Pipe[i].hPipeInst,
Pipe[i].chReply,
Pipe[i].cbToWrite,
&cbRet,
&Pipe[i].oOverlap);
if (fSuccess && cbRet == Pipe[i].cbToWrite)
{
Pipe[i].fPendingIO = FALSE;
Pipe[i].dwState = READING_STATE;
continue;
}
dwErr = GetLastError();
if (! fSuccess && (dwErr == ERROR_IO_PENDING))
{
Pipe[i].fPendingIO = TRUE;
continue;
}
DisconnectAndReconnect(i);
break;
default:
{
printf("Invalid pipe state.\n");
return 0;
}
}
}
return 0;
}
VOID DisconnectAndReconnect(DWORD i)
{
if (! DisconnectNamedPipe(Pipe[i].hPipeInst) )
{
printf("DisconnectNamedPipe failed with %d.\n", GetLastError());
}
Pipe[i].fPendingIO = ConnectToNewClient(
Pipe[i].hPipeInst,
&Pipe[i].oOverlap);
Pipe[i].dwState = Pipe[i].fPendingIO ?
CONNECTING_STATE : // still connecting
READING_STATE; // ready to read
}
BOOL ConnectToNewClient(HANDLE hPipe, LPOVERLAPPED lpo)
{
BOOL fConnected, fPendingIO = FALSE;
fConnected = ConnectNamedPipe(hPipe, lpo);
if (fConnected)
{
printf("ConnectNamedPipe failed with %d.\n", GetLastError());
return 0;
}
switch (GetLastError())
{
// The overlapped connection in progress.
case ERROR_IO_PENDING:
fPendingIO = TRUE;
break;
case ERROR_PIPE_CONNECTED:
if (SetEvent(lpo->hEvent))
break;
default:
{
printf("ConnectNamedPipe failed with %d.\n", GetLastError());
return 0;
}
}
return fPendingIO;
}
int rxProccesIdMsg(HANDLE pipe)
{
PIPEHANDSHAKE pipeInfo;
CHAR bufferSize[512] = {'\0'};
INT cbBytesRead;
BOOL fSuccess;
PIPEHANDSHAKE processData;
fSuccess = ReadFile(
pipe, // handle to pipe
bufferSize, // buffer to receive data
sizeof(PIPEHANDSHAKE), // size of buffer
&cbBytesRead, // number of bytes read
NULL); // not overlapped I/O
memset(&processData,0,sizeof(PIPEHANDSHAKE));
memcpy(&processData,&bufferSize,sizeof(PIPEHANDSHAKE));
if ( (!fSuccess))
{
printf("Client: READ Server Pipe Failed(%d)\n",GetLastError());
CloseHandle(pipe);
return -1;
}
else
{
printf("Client: READ Server Pipe Success(%d)\n",GetLastError());
printf("APP Process id: %d , app name: %s",processData.processId,processData.appName);
//Sleep(3*100);
}
return processData.processId;
}
VOID GetAnswerToRequest(LPPIPEINST pipe)
{
_tprintf( TEXT("[%d] %s\n"), pipe->hPipeInst, pipe->chRequest);
// StringCchCopy( pipe->chReply, BUFSIZE, TEXT("Default answer from server") );
strncpy(pipe->chReply, "Default answer from server",BUFSIZE);
pipe->cbToWrite = (lstrlen(pipe->chReply)+1)*sizeof(TCHAR);
}
I am trying to decrypt WEP profile's key using CryptUnprotectData. The way I fetched the profile key is by exporting the profile using netsh.
netsh wlan export profile name="MyWEP" folder="./"
For now, I manually copied the key material from the .xml file generated by the netsh command to my program. And the way, I am decrypting is -
DATA_BLOB DataOut, DataVerify;
DataOut.cbData = encryptData.length();
DataOut.pbData = (BYTE*)("I_Manually_Copy_The_WEP_Key_Here");
if (CryptUnprotectData( &DataOut,
NULL,
NULL,
NULL,
NULL,
0,
&DataVerify))
{
printf("The decrypted data is: %s\n", DataVerify.pbData);
}
else
{
printf("Failed. Error Code: %d", GetLastError());
}
But I am getting the error code 13 citing Invalid Data. What am I doing wrong ? On Win 7 and later, I can directly use WlanGetProfile with the parameter WLAN_PROFILE_GET_PLAINTEXT_KEY . But I have NO option on Vista than to use the CryptUnprotectData function. I have seen similar posts here, here but didn't get much useful information. Also, I am using the same system with same user log on credentials. Could any one please suggest me how to proceed ?
PS: I have posted the same question on Windows Desktop SDK forums, but haven't got response yet. Trying my luck on SO.
I like questions about Windows Security. So if I occasionally see such one I try to solve it.
In your case you did already the first step by the usage of netsh.exe wlan export profile ... to export the data from the WLAN profile in XML file. The file contains <keyMaterial> element. The data inside of the element are binary data encoded as the Hex: (something like 01000000D08C9DDF0115D1118C7A00C0...).
So what you need to do first of all is to decode the string to binary data. You can use CryptStringToBinary with CRYPT_STRING_HEX parameter to decode the string to binary.
The next step will be to fill DATA_BLOB with the binary data and call CryptUnprotectData to get the result, but... There are small problem. How you can read in the documentation of WlanGetProfile the following
By default, the keyMaterial element returned in the profile pointed to
by the pstrProfileXml is encrypted. If your process runs in the
context of the LocalSystem account on the same computer, then you can
unencrypt key material by calling the CryptUnprotectData function.
Windows Server 2008 and Windows Vista: The keyMaterial element
returned in the profile schema pointed to by the pstrProfileXml is
always encrypted. If your process runs in the context of the
LocalSystem account, then you can unencrypt key material by calling
the CryptUnprotectData function.
So to be able to unencrypt the key we have to call CryptUnprotectData in LocalSystem security context. If your program already run under LocalSystem context you can do this directly. If it's not so, but you have administrative rights or you have at least Debug privilege, you can "to borrow" the LocalSystem token from some other process running on the computer. For example one can get the process token of "winlogon.exe" process and impersonate it.
The following demo program enumerate processes using NtQuerySystemInformation method (see my old answer) which I personally prefer. One can use EnumProcesses or other well-known ways to do the same. Here is the code which worked at me
#include <Windows.h>
#include <tchar.h>
#include <stdio.h>
#pragma comment (lib, "Crypt32.lib")
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L)
typedef enum _SYSTEM_INFORMATION_CLASS {
SystemProcessInformation = 5
} SYSTEM_INFORMATION_CLASS;
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING;
typedef LONG KPRIORITY; // Thread priority
typedef struct _SYSTEM_PROCESS_INFORMATION_DETAILD {
ULONG NextEntryOffset;
ULONG NumberOfThreads;
LARGE_INTEGER SpareLi1;
LARGE_INTEGER SpareLi2;
LARGE_INTEGER SpareLi3;
LARGE_INTEGER CreateTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER KernelTime;
UNICODE_STRING ImageName;
KPRIORITY BasePriority;
HANDLE UniqueProcessId;
ULONG InheritedFromUniqueProcessId;
ULONG HandleCount;
BYTE Reserved4[4];
PVOID Reserved5[11];
SIZE_T PeakPagefileUsage;
SIZE_T PrivatePageCount;
LARGE_INTEGER Reserved6[6];
} SYSTEM_PROCESS_INFORMATION_DETAILD, *PSYSTEM_PROCESS_INFORMATION_DETAILD;
typedef NTSTATUS (WINAPI *PFN_NT_QUERY_SYSTEM_INFORMATION)(
IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
IN OUT PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT OPTIONAL PULONG ReturnLength
);
//
// The function changes a privilege named pszPrivilege for
// the current process. If bEnablePrivilege is FALSE, the privilege
// will be disabled, otherwise it will be enabled.
//
BOOL SetCurrentPrivilege (LPCTSTR pszPrivilege, // Privilege to enable/disable
BOOL bEnablePrivilege) // to enable or disable privilege
{
HANDLE hToken;
TOKEN_PRIVILEGES tp;
LUID luid;
TOKEN_PRIVILEGES tpPrevious;
DWORD cbPrevious = sizeof(TOKEN_PRIVILEGES);
BOOL bSuccess = FALSE;
if (!LookupPrivilegeValue(NULL, pszPrivilege, &luid)) return FALSE;
if (!OpenProcessToken (GetCurrentProcess(),
TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
&hToken
)) return FALSE;
//
// first pass. get current privilege setting
//
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = 0;
AdjustTokenPrivileges(
hToken,
FALSE,
&tp,
sizeof(TOKEN_PRIVILEGES),
&tpPrevious,
&cbPrevious);
if (GetLastError() == ERROR_SUCCESS) {
//
// second pass. set privilege based on previous setting
//
tpPrevious.PrivilegeCount = 1;
tpPrevious.Privileges[0].Luid = luid;
if(bEnablePrivilege)
tpPrevious.Privileges[0].Attributes |= (SE_PRIVILEGE_ENABLED);
else
tpPrevious.Privileges[0].Attributes ^= (SE_PRIVILEGE_ENABLED &
tpPrevious.Privileges[0].Attributes);
AdjustTokenPrivileges(
hToken,
FALSE,
&tpPrevious,
cbPrevious,
NULL,
NULL);
if (GetLastError() == ERROR_SUCCESS) bSuccess=TRUE;
CloseHandle(hToken);
}
else {
DWORD dwErrorCode = GetLastError();
CloseHandle(hToken);
SetLastError(dwErrorCode);
}
return bSuccess;
}
DWORD GetProcessIdByProcessName (LPCWSTR pszProcessName)
{
SIZE_T bufferSize = 1024*sizeof(SYSTEM_PROCESS_INFORMATION_DETAILD);
PSYSTEM_PROCESS_INFORMATION_DETAILD pspid = NULL;
HANDLE hHeap = GetProcessHeap();
PBYTE pBuffer = NULL;
ULONG ReturnLength;
PFN_NT_QUERY_SYSTEM_INFORMATION pfnNtQuerySystemInformation = (PFN_NT_QUERY_SYSTEM_INFORMATION)
GetProcAddress (GetModuleHandle(TEXT("ntdll.dll")), "NtQuerySystemInformation");
NTSTATUS status;
int uLen = lstrlenW(pszProcessName)*sizeof(WCHAR);
__try {
pBuffer = (PBYTE) HeapAlloc (hHeap, 0, bufferSize);
#pragma warning(disable: 4127)
while (TRUE) {
#pragma warning(default: 4127)
status = pfnNtQuerySystemInformation (SystemProcessInformation, (PVOID)pBuffer,
bufferSize, &ReturnLength);
if (status == STATUS_SUCCESS)
break;
else if (status != STATUS_INFO_LENGTH_MISMATCH) { // 0xC0000004L
_tprintf (TEXT("ERROR 0x%X\n"), status);
return 1; // error
}
bufferSize *= 2;
pBuffer = (PBYTE) HeapReAlloc (hHeap, 0, (PVOID)pBuffer, bufferSize);
}
for (pspid = (PSYSTEM_PROCESS_INFORMATION_DETAILD)pBuffer; ;
pspid = (PSYSTEM_PROCESS_INFORMATION_DETAILD)(pspid->NextEntryOffset + (PBYTE)pspid)) {
if (pspid->ImageName.Length == uLen && lstrcmpiW(pspid->ImageName.Buffer, pszProcessName) == 0)
return (DWORD)pspid->UniqueProcessId;
if (pspid->NextEntryOffset == 0) break;
}
}
__finally {
pBuffer = (PBYTE) HeapFree (hHeap, 0, pBuffer);
}
return 0;
}
int _tmain()
{
BOOL bIsSuccess, bImpersonated = FALSE;
HANDLE hProcess = NULL, hProcessToken = NULL;
DATA_BLOB DataOut, DataVerify;
// !!! in the next line you should copy the string from <keyMaterial>
WCHAR szKey[] = L"01000000D08C9DDF0115D1118C7....";
BYTE byKey[1024];
DWORD cbBinary, dwFlags, dwSkip;
DWORD dwProcessId = GetProcessIdByProcessName(L"winlogon.exe");
if (dwProcessId == 0) return 1;
bIsSuccess = SetCurrentPrivilege(SE_DEBUG_NAME, TRUE);
if (!bIsSuccess) return GetLastError();
__try {
hProcess = OpenProcess(MAXIMUM_ALLOWED, FALSE, dwProcessId);
if (!hProcess) __leave;
bIsSuccess = OpenProcessToken (hProcess, MAXIMUM_ALLOWED, &hProcessToken);
if (!bIsSuccess) __leave;
bIsSuccess = ImpersonateLoggedOnUser(hProcessToken);
if (!bIsSuccess) __leave;
bImpersonated = TRUE;
cbBinary = sizeof(byKey);
bIsSuccess = CryptStringToBinary (szKey, lstrlenW(szKey), CRYPT_STRING_HEX, // CRYPT_STRING_HEX_ANY
byKey, &cbBinary, &dwSkip, &dwFlags);
if (!bIsSuccess) __leave;
DataOut.cbData = cbBinary;
DataOut.pbData = (BYTE*)byKey;
if (CryptUnprotectData (&DataOut, NULL, NULL, NULL, NULL, 0, &DataVerify)) {
_tprintf(TEXT("The decrypted data is: %hs\n"), DataVerify.pbData);
}
}
__finally {
if (bImpersonated)
RevertToSelf();
if (hProcess)
CloseHandle(hProcess);
if (hProcessToken)
CloseHandle(hProcessToken);
}
return 0;
}
I want to take file ownership using win32 api, and I want my code to work on both xp and win7
anyway, here is what i came up with
Function that changes the ownership of the file
int ChangeFileOwner()
{
HANDLE token;
char *filename = "c:\\file1.txt"; //(not owned by the current user)
DWORD len;
PSECURITY_DESCRIPTOR security = NULL;
int retValue = 1;
PSID sid;
// Get the privileges you need
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &token)) {
if(!SetPrivilege("SeTakeOwnershipPrivilege", 1))retValue=0;
if(!SetPrivilege("SeSecurityPrivilege", 1))retValue=0;
if(!SetPrivilege("SeBackupPrivilege", 1))retValue=0;
if(!SetPrivilege("SeRestorePrivilege", 1))retValue=0;
} else retValue = 0;
// Create the security descriptor
if (retValue) {
GetFileSecurity(filename, OWNER_SECURITY_INFORMATION, security, 0, &len);
security = (PSECURITY_DESCRIPTOR)malloc(len);
if (!InitializeSecurityDescriptor(security,SECURITY_DESCRIPTOR_REVISION))
retValue = 0;
}
// Get the sid for the username
if (retValue) {
GetLogonSID(token, &sid) ;
}
// Set the sid to be the new owner
if (retValue && !SetSecurityDescriptorOwner(security, sid, 0))
retValue = 0;
// Save the security descriptor
if (retValue)
retValue = SetFileSecurity(filename, OWNER_SECURITY_INFORMATION, security);
if (security) free(security);
return retValue;
}
Function to get the current user SID
BOOL GetLogonSID (HANDLE hToken, PSID *ppsid)
{
BOOL bSuccess = FALSE;
DWORD dwIndex;
DWORD dwLength = 0;
PTOKEN_GROUPS ptg = NULL;
// Get required buffer size and allocate the TOKEN_GROUPS buffer.
GetTokenInformation(hToken,TokenGroups,(LPVOID) ptg,0,&dwLength) ;
ptg = (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY, dwLength);
// Get the token group information from the access token.
GetTokenInformation(hToken,TokenGroups,(LPVOID) ptg,dwLength,&dwLength) ;
// Loop through the groups to find the logon SID.
for (dwIndex = 0; dwIndex < ptg->GroupCount; dwIndex++)
if ((ptg->Groups[dwIndex].Attributes & SE_GROUP_LOGON_ID)
== SE_GROUP_LOGON_ID)
{
// Found the logon SID; make a copy of it.
dwLength = GetLengthSid(ptg->Groups[dwIndex].Sid);
*ppsid = (PSID) HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY, dwLength);
CopySid(dwLength, *ppsid, ptg->Groups[dwIndex].Sid);
break;
}
return TRUE;
}
Code To Set Privilege
int SetPrivilege(char *privilege, int enable)
{
TOKEN_PRIVILEGES tp;
LUID luid;
HANDLE token;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token)) return 0;
if (!LookupPrivilegeValue(NULL, privilege, &luid)) return 0;
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
if (enable) tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
else tp.Privileges[0].Attributes = 0;
// Enable the privilege or disable all privileges.
return AdjustTokenPrivileges(token, 0, &tp, NULL, NULL, NULL);
}