I want to query ETag header from response headers (Of course ETag is HTTP standar, but it is not defined as a flag in WinHttpQueryHeaders function). this is Microsoft's example:
HRESULT ReadHeader(
__in HINTERNET requestHandle,
__in_z WCHAR* headerName,
__in ULONG queryFlags)
{
HRESULT hr = NOERROR;
WCHAR headerBuffer[256];
ULONG headerLength = sizeof(headerBuffer);
if (!WinHttpQueryHeaders(
requestHandle,
queryFlags,
NULL,
headerBuffer,
&headerLength,
WINHTTP_NO_HEADER_INDEX))
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Exit;
}
wprintf(L"%s: %s\n", headerName, headerBuffer);
Exit:
return hr;
}
It can use to query value with flags. But how I can do with ETag? I tried:
WinHttpQueryHeaders(
requestHandle,
NULL,
L"ETag",
headerBuffer,
&headerLength,
WINHTTP_NO_HEADER_INDEX)
with no success.
Pass WinHttpQueryHeaders a dwInfoLevel set to WINHTTP_QUERY_CUSTOM which:
Causes WinHttpQueryHeaders to search for the header name specified in
the pwszName parameter and store the header information in lpBuffer.
Related
I tried FindProcessidByName with Kernel Mode Driver, sometimes ImageName.Buffer goes to NULL , because of this , when ImageName.Buffer goes to NULL I can not find process ids. Do you have any idea why ImageName.Buffer goes to NULL sometimes, sir ?
typedef struct _SYSTEM_PROCESS_INFO_L
{
ULONG NextEntryOffset;
ULONG NumberOfThreads;
LARGE_INTEGER Reserved[3];
LARGE_INTEGER CreateTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER KernelTime;
UNICODE_STRING ImageName;
ULONG BasePriority;
HANDLE ProcessId;
HANDLE InheritedFromProcessId;
}_SYSTEM_PROCESS_INFO_L, *P_SYSTEM_PROCESS_INFO_L;
HANDLE LSFindProcess(LPSTR name)
{
NTSTATUS durum;
ULONG retsize;
HANDLE hProcid = -1;
P_SYSTEM_PROCESS_INFO_L pi;
durum = ZwQuerySystemInformation(SystemProcessInformation, NULL, NULL, &retsize); // request how much memory size we need.
if (!NT_SUCCESS(durum) && durum !=STATUS_INFO_LENGTH_MISMATCH)
{
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "LS : ZwQuerySystemInformation Failed 1 durum : %p \n",durum);
return -1;
}
PVOID memPtr;
memPtr = ExAllocatePool(PagedPool, retsize);
if (!memPtr)
{
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "LS : ExAllocatePool Failed \n");
return -1;
}
memset(memPtr, 0, retsize);// zero mem
durum = ZwQuerySystemInformation(SystemProcessInformation, memPtr, retsize, NULL);
pi = (P_SYSTEM_PROCESS_INFO_L)memPtr; // parselliyorz
if (!NT_SUCCESS(durum))
{
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "LS : ZwQuerySystemInformation Failed 2 durum : %p \n", durum);
return -1;
}
while (pi->NextEntryOffset)
{
if (pi->ImageName.Buffer) //some process null if I dont use this I am getting BSOD.
{
if (!_stricmp(pi->ImageName.Buffer, name))
{
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "LS : name %ws , pid : %d \n", pi->ImageName.Buffer, pi->ProcessId);
hProcid = pi->ProcessId; // pid
break; // foundedd
}
}
pi = (P_SYSTEM_PROCESS_INFO_L)((unsigned char*)pi + pi->NextEntryOffset);
}
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "LS : LSFindProcess bitti \n");
return hProcid;
}
ZwQuerySystemInformation is Not working Properly
this is of course false. api working properly. if you got wrong results, this is only due errors in code. in concrete code spinet exist several errors.
in kernel mode exist difference between Zw and Nt api - need understand which version need call, if both (like in this concrete case) is exported. if you know that previous mode is kernel mode - need use Nt version. if you don't know previous mode in this point(at compile time) or previous mode user mode - need use Zw version. however this is general note and will be not error always call Zw
the first serious error - this is how ZwQuerySystemInformation called - first time for query requested buffer size retsize (in code) and second time already with this buffer size. but between this calls new threads and processes can be spawn in system. as result returned buffer size can be already not large enough. correct solution - call this api in loop, while it return STATUS_INFO_LENGTH_MISMATCH
the second - memory always must be free. especially in kernel mode. say that code incomplete - no excuse. code can be incomplete and intermediate, but free memory after allocation always must be immediately inserted
else one critical error - while (pi->NextEntryOffset) loop - with this loop we always lost (not process) the last entry (last created process). need change this.
if (pi->ImageName.Buffer) //some process null if I dont use this I am
getting BSOD.
the ImageName is UNICODE_STRING and need work with it respectively. in case ImageName.Buffer the ImageName.Length is also 0. the UNICODE_STRING ImageName; is correct. incorrect only how you use it.
!_stricmp(pi->ImageName.Buffer, name); // ??
the pi->ImageName.Buffer is PWSTR so it can not be used with _stricmp as a matter of principle. think you use c compiler - c++ simply give you error here. but even use _wcsicmp is incorrect here - again pi->ImageName is UNICODE_STRING and need use RtlEqualUnicodeString(&pi->ImageName, name, TRUE) where name must be of course PCUNICODE_STRING but not PCSTR or PSTR or even PCWSTR. if you have PCWSTR name as input - you need wrap it to UNICODE_STRING before call this api. example of code:
NTSTATUS LSFindProcess(PCUNICODE_STRING ImageName, PHANDLE UniqueProcessId)
{
ULONG cb = 0x20000;
PVOID buf;
NTSTATUS status;
do
{
status = STATUS_INSUFFICIENT_RESOURCES;
if (buf = ExAllocatePool(PagedPool, cb))
{
if (0 <= (status = NtQuerySystemInformation(SystemProcessInformation, buf, cb, &cb)))
{
union {
PVOID pv;
PBYTE pb;
PSYSTEM_PROCESS_INFORMATION pspi;
};
pv = buf;
ULONG NextEntryOffset;
goto __0;
do
{
pb += NextEntryOffset;
__0:
if (RtlEqualUnicodeString(&pspi->ImageName, ImageName, TRUE))
{
*UniqueProcessId = pspi->UniqueProcessId;
break;
}
} while (NextEntryOffset = pspi->NextEntryOffset);
}
ExFreePool(buf);
}
} while (status == STATUS_INFO_LENGTH_MISMATCH);
return status;
}
NTSTATUS LSFindProcess(PCWSTR ImageName, PHANDLE UniqueProcessId)
{
UNICODE_STRING us;
RtlInitUnicodeString(&us, ImageName);
return LSFindProcess(&us, UniqueProcessId);
}
thanks for everyone especially #RbMm thanks for informations.
Finished code I hope this post help someone..
/// <summary>
/// Struct SystemProcessInformation
/// </summary>
typedef struct _SYSTEM_PROCESS_INFO_L
{
ULONG NextEntryOffset;
ULONG NumberOfThreads;
LARGE_INTEGER Reserved[3];
LARGE_INTEGER CreateTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER KernelTime;
UNICODE_STRING ImageName;
ULONG BasePriority;
HANDLE ProcessId;
HANDLE InheritedFromProcessId;
}_SYSTEM_PROCESS_INFO_L, *P_SYSTEM_PROCESS_INFO_L;
/// <summary>
/// Find Process ID By Name , thanks #RbMm
/// </summary>
/// <param name="imagename">Process name </param>
/// <param name="pid">Output Process id</param>
/// <returns>NTSTATUS.</returns>
NTSTATUS LSFindProcessIdByName(IN PCWSTR imagename, OUT PHANDLE pid)
{
NTSTATUS durum = STATUS_UNSUCCESSFUL;
ULONG qmemsize = 0x1024;
PVOID qmemptr = 0;
P_SYSTEM_PROCESS_INFO_L spi;
UNICODE_STRING uimagename;
RtlInitUnicodeString(&uimagename, imagename); // #RbMm
*pid = -1;
do
{
qmemptr = ExAllocatePool(PagedPool, qmemsize); // alloc memory for spi
if (qmemptr == NULL) // check memory is allocated or not.
{
return STATUS_UNSUCCESSFUL;
}
durum = ZwQuerySystemInformation(SystemProcessInformation,qmemptr, qmemsize, NULL);
if (durum == STATUS_INFO_LENGTH_MISMATCH)
{
qmemsize = qmemsize * 2; // increase qmemsize for next memory alloc
ExFreePool(qmemptr); // free memory
}
} while (durum == STATUS_INFO_LENGTH_MISMATCH); // resize memory
spi = (P_SYSTEM_PROCESS_INFO_L)qmemptr;
while(1)
{
if (RtlEqualUnicodeString(&uimagename, &spi->ImageName, TRUE)) // #RbMm
{
*pid = spi->ProcessId;
break;
}
if (spi->NextEntryOffset == 0)
break;
spi = (P_SYSTEM_PROCESS_INFO_L)((unsigned char*)spi + spi->NextEntryOffset); // next info
}
if (!NT_SUCCESS(durum))
{
ExFreePool(qmemptr); // free memory
return STATUS_UNSUCCESSFUL;
}
ExFreePool(qmemptr); // free memory
return STATUS_SUCCESS;
}
You should not be calling ZwQuerySystemInformation, it's not easily portable across Windows OS's and may not even be available on some of them. The MSDN documentation for this function recommends alternate functions for your particular usage.
I am writing a program that lists open file handles. I am actually getting too many results. My list includes stuff like virus scanners. I am getting a bunch with object type 43 that don't seem like what I want. Is there a list of these values anywhere?
You can call NtQueryObject with specifying ObjectTypesInformation information class. That gives you information about all object types currently registered in the system. Use the SYSTEM_HANDLE_ENTRY.ObjectType as an index into the returned array in order to get information about the corresponding object type. Alternatively, you can use NtQueryObject with ObjectTypeInformation to obtain type information about a given object (specified by its handle).
This code should retrieve information about all type objects.
typedef enum _OBJECT_INFORMATION_CLASS {
ObjectBasicInformation,
ObjectNameInformation,
ObjectTypeInformation,
ObjectTypesInformation,
ObjectHandleFlagInformation,
ObjectSessionInformation,
} OBJECT_INFORMATION_CLASS;
typedef struct _OBJECT_TYPE_INFORMATION {
UNICODE_STRING TypeName;
ULONG TotalNumberOfObjects;
ULONG TotalNumberOfHandles;
ULONG TotalPagedPoolUsage;
ULONG TotalNonPagedPoolUsage;
ULONG TotalNamePoolUsage;
ULONG TotalHandleTableUsage;
ULONG HighWaterNumberOfObjects;
ULONG HighWaterNumberOfHandles;
ULONG HighWaterPagedPoolUsage;
ULONG HighWaterNonPagedPoolUsage;
ULONG HighWaterNamePoolUsage;
ULONG HighWaterHandleTableUsage;
ULONG InvalidAttributes;
GENERIC_MAPPING GenericMapping;
ULONG ValidAccessMask;
BOOLEAN SecurityRequired;
BOOLEAN MaintainHandleCount;
ULONG PoolType;
ULONG DefaultPagedPoolCharge;
ULONG DefaultNonPagedPoolCharge;
} OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION;
typedef struct _OBJECT_TYPES_INFORMATION {
LONG NumberOfTypes;
// OBJECT_TYPE_INFORMATION TypeInformation [1];
} OBJECT_TYPES_INFORMATION, *POBJECT_TYPES_INFORMATION;
NTSTATUS QueryObjectTypesInfo(POBJECT_TYPES_INFORMATION *TypesInfo)
{
ULONG StartBufferLength = 28;
ULONG BufferLength = 0;
NTSTATUS status = 0xC0000001;
status = STATUS_SUCCESS;
*TypesInfo = (POBJECT_TYPES_INFORMATION)malloc(StartBufferLength);
if (*TypesInfo != NULL) {
status = NtQueryObject(NULL, ObjectTypesInformation, TypesInfo, StartBufferLength, &BufferLength);
if (status == STATUS_INFO_LENGTH_MISMATCH) {
*TypesInfo = NULL;
while (status == STATUS_INFO_LENGTH_MISMATCH) {
if (*TypesInfo != NULL)
free(*TypesInfo);
*TypesInfo = (POBJECT_TYPES_INFORMATION)malloc(BufferLength);
if (*TypesInfo != NULL)
status = NtQueryObject(NULL, ObjectTypesInformation, *TypesInfo, BufferLength, &BufferLength);
else status = STATUS_INSUFFICIENT_RESOURCES;
}
if (!NT_SUCCESS(status)) {
if (*TypesInfo != NULL) {
free(*TypesInfo);
*TypesInfo = NULL;
}
}
}
} else status = STATUS_INSUFFICIENT_RESOURCES;
return status;
}
As stated in the comment(s) above, this stuff is quite undocumented. However, the above code (with slight modifications.. e.g. you need to get address of the NtQueryObject routine and define some NTSTATUS contants) works for me on 64-bit Windows 8.1.
For a complete code (that is quite old and commented in Czech), download this project from my (Czech) website:
https://jadro-windows.cz/download/ntqueryobject.zip
Use qo.exe --list-types command to obtain the type information
i am trying to hook CopyItems function ,its working fine but when i am trying to call Real CopyItems Function in the Callback function it is getting crash , my code is as below, please help me.
PVOID GetInterfaceMethod(PVOID intf, DWORD methodIndex)
{
return *(PVOID*)(*(DWORD*)intf + methodIndex * 4);
}
typedef HRESULT (WINAPI *CopyItemsNext)(IUnknown *punkItems,IShellItem *psiDestinationFolder);
CopyItemsNext Real_CopyItems = NULL;
CopyItemsNext Actual_CopyItems;
HRESULT WINAPI CopyItemsCallback(IUnknown *punkItems,IShellItem *psiDestinationFolder)
{
MessageBoxW(NULL,L"CopyItems Function Called", L"HookedCopyItemS", MB_OK);
return Real_CopyItems(punkItems, psiDestinationFolder);
}
HRESULT WINAPI CoCreateInstanceCallback(REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID *ppv)
{
const char *IFileOperation_GUID = "{3AD05575-8857-4850-9277-11B85BDB8E09}";
char GUIDString[64];
HRESULT HR = Real_CoCreateInstance(rclsid, pUnkOuter, dwClsContext, riid, ppv);
sprintf_s(GUIDString,64, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}\0",
rclsid.Data1, rclsid.Data2, rclsid.Data3,
rclsid.Data4[0], rclsid.Data4[1],
rclsid.Data4[2], rclsid.Data4[3],
rclsid.Data4[4], rclsid.Data4[5],
rclsid.Data4[6], rclsid.Data4[7]);
if(strcmp(GUIDString, IFileOperation_GUID) == 0)
{
MessageBoxA(NULL, "IFileOperation_GUID Found", GUIDString, MB_OK);
if(Real_CopyItems == NULL)
{
Actual_CopyItems = (CopyItemsNext)GetInterfaceMethod(*ppv, 17);
MessageBoxA(NULL,"AFTER GetInterfaceMethod", "TEST", MB_OK);
if (MH_CreateHook(Actual_CopyItems, &CopyItemsCallback, reinterpret_cast<void**>(&Real_CopyItems)) != MH_OK)
{
MessageBoxW(NULL, L"Failed CreateHook Real_CopyItem", L"Info!", MB_ICONWARNING|MB_OK);
}
if (MH_EnableHook(Actual_CopyItems) != MH_OK)
{
MessageBoxW(NULL, L"Failed EnableHook Real_CopyItem", L"Info!", MB_ICONWARNING|MB_OK);
}
}
}
return HR;
}
//DllMain Function
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
if (MH_Initialize() != MH_OK)
{
MessageBoxW(NULL, L"Failed Initialize", L"Info!", MB_ICONWARNING|MB_OK);
}
if (MH_CreateHook(&CoCreateInstance, &CoCreateInstanceCallback, reinterpret_cast<void**>(&Real_CoCreateInstance)) != MH_OK)
{
MessageBoxW(NULL,L"Failed MH_CreateHook CoCreateInstance",L"Info!",MB_ICONWARNING|MB_OK);
}
if (MH_EnableHook(&CoCreateInstance) != MH_OK)
{
MessageBoxW(NULL,L"Failed MH_EnableHook StartDocA",L"Info!",MB_ICONWARNING|MB_OK);
}
break;
case DLL_PROCESS_DETACH:
if (MH_Uninitialize() != MH_OK)
{
}
if (MH_DisableHook(Actual_CopyItems) != MH_OK)
{
}
if (MH_DisableHook(&CoCreateInstance) != MH_OK)
{
}
break;
}
return TRUE;
}
In the above code inside the CopyItemsCallback function i am displaying Message box just to confirm weather the function is getting hook r not ,so i got that message box after that i am calling Real CopyItems Function but there it is getting crash so please check what is the problem with my code .
IFileOperation::CopyItems is a COM method, not a regular Win32 function, so you need to treat it differently than CoCreateInstance, which is a plain Win32 API.
When you call a COM method using C++ syntax, what you don't see is the "this" pointer (same as the interface pointer) being passed behind the scenes as a hidden parameter. But if you want to call a COM method using C-style code, you have to deal with this manually.
So your definition of the CopyItems function should instead look something like this:
typedef HRESULT (STDMETHODCALLTYPE *CopyItemsNext)(IFileOperation * pThis, IUnknown *punkItems, IShellItem *psiDestinationFolder);
...and when you call through to the 'real' one, you'll have to pass that pThis as the first parameter.
Note that this trick is specific to COM, you can't in general treat C++ methods this way. It just happens that COM was designed to be usable from plain C, so COM requires that the 'this' pointer is passed just as a normal parameter would be. (COM methods are marked with STDMETHODCALLTYPE which is what tells the compiler to treat them differently than methods without that.) However, for non-COM C++ classes, a compiler might do something else, such as passing the this pointer in a register.
--
By the way, note that the DWORD in your GetInterfaceMethod will only work on 32-bit windows; use DWORD_PTR if you want a type that is always the size of a pointer and which will then work with either 32-bit or 64-bit code.
MSDN states that WinInet does not support chunked upload ("Client code must perform the chunking."). To me that meant I could manually chunk the transfer. My intention was to add "Transfer-Encoding: chunked" via HttpAddRequestHeaders, remove Content-Length via HttpAddRequestHeaders HTTP_ADDREQ_FLAG_REPLACE and then In my InternetWriteFile loop, write the data in chunked encoded blocks. The problem is, I cannot seem to convince WinInet to not send the Content-Length. Even after removal, it ends up sending "Content-Length: 0" to the server (in addition to "Transfer-Encoding: chunked") which is confusing the server.
I have also tried setting the HSR_CHUNKED flag in HttpSendRequestEx.
Does anyone have an example of getting WinInet to skip sending the Content-Length?
I know WinHTTP claims to support chunked upload, but we have other dependencies on WinInet which is why I am looking to solve the problem there if possible.
Here is a code sample of what I have tried:
#include <windows.h>
#include <wininet.h>
#include <tchar.h>
#include <stdio.h>
bool http_putfile(HINTERNET hConnection, TCHAR* resource);
#define HOST _T("www.website.com")
#define RESOURCE _T("/path/for/resource")
int _tmain(int argc, TCHAR* argv[])
{
LPCTSTR lpszHostName = HOST;
INTERNET_PORT nServerPort = INTERNET_DEFAULT_HTTP_PORT;
DWORD dwService = INTERNET_SERVICE_HTTP;
DWORD dwFlags = NULL;
DWORD dwContext = 0;
HINTERNET hSession = InternetOpen(
argv[0],
INTERNET_OPEN_TYPE_DIRECT,
NULL,
NULL,
NULL);
if(hSession != NULL)
{
HINTERNET hConnection = InternetConnect(
hSession,
lpszHostName,
nServerPort,
NULL,
NULL,
dwService,
dwFlags,
dwContext);
if(hConnection != NULL)
{
http_putfile(hConnection, RESOURCE);
InternetCloseHandle(hConnection);
}
else
{
printf("InternetConnect failed: %d\n", GetLastError());
}
InternetCloseHandle(hSession);
}
else
{
printf("InternetOpen failed: %d\n", GetLastError());
}
return 0;
}
bool http_putfile(HINTERNET hConnection, TCHAR* resource)
{
bool result = false;
HINTERNET hRequest = HttpOpenRequest(
hConnection,
_T("PUT"),
resource,
NULL,
NULL,
NULL,
INTERNET_FLAG_RELOAD | INTERNET_FLAG_EXISTING_CONNECT | INTERNET_FLAG_NO_CACHE_WRITE,
0);
if(hRequest != NULL)
{
HttpAddRequestHeaders(
hRequest,
_T("Transfer-Encoding: chunked\r\n"),
-1L,
HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE);
// have tried:
// Content-Length
// Content-Length:
// Content-Length\r\n
// Content-Length:\r\n
// all with/without HTTP_ADDREQ_FLAG_ADD. Have even tried adding in a Content-Length
// and then removing it. All results show "Content-Length: 0" in the header on the wire.
if(HttpAddRequestHeaders(
hRequest,
_T("Content-Length"),
-1L,
HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE) == FALSE)
{
DWORD err = GetLastError();
}
// have tried both 0 here for flags as documented on msdn
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa384318%28v=vs.85%29.aspx
// as well as other combinations of INITIATE/CHUNKED
if(HttpSendRequestEx(hRequest, NULL, NULL, HSR_INITIATE | HSR_CHUNKED /* 0 */, NULL))
{
DWORD wrote = 0;
char* chunks = "5\r\nCHUNK0\r\n";
if(InternetWriteFile(
hRequest,
chunks,
strlen(chunks),
&wrote) == FALSE)
{
printf("InternetWriteFile failed: %d\n", GetLastError());
}
HttpEndRequest(hRequest, NULL, 0, NULL);
}
else
{
printf("HttpSendRequestEx failed: %d\n", GetLastError);
}
InternetCloseHandle(hRequest);
}
else
{
printf("HttpOpenRequest failed: %d\n", GetLastError());
}
return result;
}
Well, it looks like you are right. In fact, I don't see anything to indicate that WinINet supports chunked uploading; only WinHTTP does. Looking at the Wine source code (which tends to be quite accurate), the "Content-Length" header is ALWAYS appended to the request for any method other than "GET".
According to the HTTP specs, if a non-identity "Transfer-Encoding" header is present then the message is considered to be chunked. If a "Content-Length" header is also present then it MUST be ignored. If the spurious "Content-Length: 0" header is causing you problems then it could be argued that it is an issue with the server. I would give WinHTTP a try and see if it fixes the problem.
Great question, I was frustrated by this myself for a good number of hours.
Your instincts about HTTP_ADDREQ_FLAG_REPLACE turned out to be right... However, you have to call it pretty late. Specifically you need to register a status callback, and when your callback gets called with INTERNET_STATUS_CONNECTED_TO_SERVER, that is when you remove the header:
// Inside InternetStatusCallback
//
if (dwInternetStatus == INTERNET_STATUS_CONNECTED_TO_SERVER)
{
HttpAddRequestHeaders(Handle, L"Content-Length", -1, HTTP_ADDREQ_FLAG_REPLACE);
}
On Windows XP there is a known way to create a Remote Assistance Ticket.
http://msdn.microsoft.com/en-us/library/ms811079.aspx
But on Vista this does not appear to work. How does one do this on Vista or Windows 7?
There turns out to be two ways. The Microsoft API is called IRASrv and is documented here:
http://msdn.microsoft.com/en-us/library/cc240176(PROT.10).aspx
Another way is to simply call msra.exe. with password and novice params (e.g. msra.exe /saveasfile testfile thepassword). However that does prompt the user with the password dialog.
Here is example code for calling the IRASrv interface and generating a Remote Assistance Connection String.
COSERVERINFO si; ::ZeroMemory( &si, sizeof( si ) );
MULTI_QI qi; ::ZeroMemory( &qi, sizeof( qi ) );
HRESULT hr = S_OK;
BSTR bstrUserName = SysAllocString(L"jon");
BSTR bstrDomainName = SysAllocString(L"");
BSTR bstrPasswordStr = SysAllocString(L"testpass");
// Get the security information entered by the user
_bstr_t bstrUser(bstrUserName);
_bstr_t bstrDomain(bstrDomainName);
_bstr_t bstrPassword(bstrPasswordStr);
// Set AuthIdentity
SEC_WINNT_AUTH_IDENTITY_W AuthIdentity = {
(unsigned short*)bstrUserName,
bstrUser.length(),
(unsigned short*)bstrDomainName,
bstrDomain.length(),
(unsigned short*)bstrPasswordStr,
bstrPassword.length(),
SEC_WINNT_AUTH_IDENTITY_UNICODE
};
COAUTHINFO AuthInfo = {
RPC_C_AUTHN_WINNT,
RPC_C_AUTHZ_DEFAULT,
NULL,
RPC_C_AUTHN_LEVEL_PKT_PRIVACY, // The authentication level used
RPC_C_IMP_LEVEL_IMPERSONATE,
(COAUTHIDENTITY*)&AuthIdentity,
EOAC_NONE
};
si.pAuthInfo = &AuthInfo;
si.pwszName = bstrMachineName;
qi.pIID = &(__uuidof(RAServerLib::IRASrv));
hr = ::CoCreateInstanceEx(
__uuidof(RAServerLib::RASrv), NULL, CLSCTX_REMOTE_SERVER,
&si, 1, &qi );
if (FAILED(hr))
{
return hr;
}
CComPtr<RAServerLib::IRASrv> prasrv;
hr = qi.pItf->QueryInterface(__uuidof(RAServerLib::IRASrv), (void**)&prasrv);
if (FAILED(hr))
{
return hr;
}
LPWSTR pstr=NULL;
hr = prasrv->raw_GetNoviceUserInfo(&pstr);
if (FAILED(hr))
{
return hr;
}
pstr contains the Remote Assistance Connection String (type 2)