How RpcServerInqCallAttributes knows what ClientPID to retrieve - c++

I am reading about the function RpcServerInqCallAttributes (source).
I saw a program (vmcompute.exe) that calls this function like that (based on reversing):
RPC_CALL_ATTRIBUTES CallAttributes;
memset(&CallAttributes, 0, sizeof(CallAttributes));
CallAttributes.Version = 3;
CallAttributes.Flags = RPC_QUERY_CLIENT_PID;
Status = RpcServerInqCallAttributes(0, &ClientContextAttributes);
It retrieves the PID of dockerd but how it knows what PID to retrieve?
It just used the RPC_QUERY_CLIENT_PID to query the PID, but based on what? It didn't specify the name of the process.
I read this answer but it didn't explain how it knows what process PID to retrieve.

Both RpcServerInqCallAttributes and its lower-level counterpart I_RpcBindingInqLocalClientPID have RPC_BINDING_HANDLE Binding as their first parameter:
RPC_STATUS RpcServerInqCallAttributes(
[in] RPC_BINDING_HANDLE ClientBinding,
[in, out] void *RpcCallAttributes
);
RPC_STATUS I_RpcBindingInqLocalClientPID(
[in, optional] RPC_BINDING_HANDLE Binding,
[out] unsigned long *Pid
);
Local RPC requests are usually sent over ALPC, where each message delivered contains both the data payload and LPC/ALPC protocol header, described by PORT_MESSAGE structure. This header has ClientId field, which has both senders PID and TID.
Upon receiving an ALPC request the RPC runtime inside the server process saves these values in the RPC_BINDING_HANDLE object, where they can be retrieved from.
Passing a NULL handle to RpcServerInqCallAttributes/I_RpcBindingInqLocalClientPID means use the current thread's active binding, in which case these APIs take the RPC_BINDING_HANDLE pointer from the current thread's TEB, IIRC via ReservedForNtRpc field.

Related

Resume completion port notification after they were stopped

In the MSDN doc for the lpOverlapped parameter of GetQueuedCompletionStatus it is said that the application can prevent completion port notification by setting the low-order bit of the hEvent member of the OVERLAPPED structure. But is it possible to resume the notifications after they were stopped?
I need to use this for monitoring network folders for changes:
When GetQueuedCompletionStatus returns FALSE and GetLastError() returns ERROR_NETNAME_DELETED, I do this (works):
di->Overlapped.hEvent = CreateEvent( NULL, FALSE, FALSE, di->lpszDirName );
reinterpret_cast<uintptr_t &>(di->Overlapped.hEvent) |= 0x1;
And when the network problem was resolved, I tried to do the reverse operation - but it DID NOT work:
reinterpret_cast<uintptr_t &>(di->Overlapped.hEvent) &= ~(0x1);
(It will be good if the solution be compatible with Windows 7)
first of all completion port notification can not be "suspended" or "resumed"
Even if you have passed the function a file handle associated with a
completion port and a valid OVERLAPPED structure, an application can
prevent completion port notification. This is done by specifying a
valid event handle for the hEvent member of the OVERLAPPED structure,
and setting its low-order bit. A valid event handle whose low-order
bit is set keeps I/O completion from being queued to the completion
port.
this mean the next - when we call some win32 I/O api (api which take pointer to OVERLAPPED as in/out parameter, such as ReadFile, ReadDirectoryChangesW, LockFileEx etc) and file handle (passed to this api) associated with a completion port - despite this we can prevent completion port notification for this call by event handle with low-order bit. this is for only concrete api call and not affect any another api calls. and all this unrelated to GetQueuedCompletionStatus
(strictly said we can simply pass 1 in place hEvent too. but in this case question - how we get notify about I/O complete, if api return pending status ? yes possible wait and on file handle only, call GetOverlappedResult. but this will be correct only in no any another I/O call on this file in concurent)
in any case need understand how this is internally work. all native I/O api have the next signature:
NTSTATUS NTAPI SomeIoApi(
_In_ HANDLE FileHandle,
_In_opt_ HANDLE Event,
_In_opt_ PIO_APC_ROUTINE ApcRoutine,
_In_opt_ PVOID ApcContext,
_Out_ PIO_STATUS_BLOCK IoStatusBlock,
...
);
all have this common 5 parameters at begin. for queue I/O completion as result of this call several conditions must be met. of course FileHandle must be associated with some completion port (to this port and can be packet sent). but else one mandatory condition - ApcContext must be not zero (ApcContext != 0). if this 2 condition met and device return not error status (if FILE_SKIP_COMPLETION_PORT_ON_SUCCESS set on file - must be pending status only) - when I/O complete - ApcContext pointer will be pushed to port. and then it can be removed by
NTSTATUS
NTAPI
NtRemoveIoCompletion(
_In_ HANDLE IoCompletionHandle,
_Out_ PVOID *KeyContext,
_Out_ PVOID *ApcContext,
_Out_ PIO_STATUS_BLOCK IoStatusBlock,
_In_opt_ PLARGE_INTEGER Timeout
);
or by it win32 shell GetQueuedCompletionStatus.
so solution for not sent packet to port (even is file handle associated with completion port) - set ApcContext = 0. win32 layer do this in next way (pseudo - code):
BOOL WINAPI SomeWin32Api(
HANDLE FileHandle,
LPOVERLAPPED lpOverlapped,
LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
)
{
HANDLE hEvent = lpOverlapped->hEvent;
PVOID ApcContext = lpOverlapped;
if ((ULONG_PTR)hEvent & 1)
{
reinterpret_cast<uintptr_t&>(hEvent) &= ~1;
ApcContext = 0;
}
NTSTATUS status = SomeIoApi(
FileHandle,
hEvent,
lpCompletionRoutine, // not exactly, but by sense
ApcContext,
(PIO_STATUS_BLOCK)lpOverlapped,...);
}
it check low-order bit of hEvent in OVERLAPPED - if it set - pass 0 inplace ApcContext otherwise pass lpOverlapped (pointer to OVERLAPPED) as context ( ApcContext = lpOverlapped;)
note that nt layer let pass any void* pointer as ApcContext. but win32 layer always pass here pointer to OVERLAPPED structure or 0. because this and GetQueuedCompletionStatus return this pointer back as _Out_ LPOVERLAPPED *lpOverlapped (compare with NtRemoveIoCompletion - return as _Out_ PVOID *ApcContext)
anyway this trick affect only concrete single win32 I/O call, and if you late reset low-order bit in hEvent from overlapped ( reinterpret_cast<uintptr_t &>(di->Overlapped.hEvent) &= ~(0x1);) this already can not have any effect - the 0 in place ApcContext already passed.
also from general view this is rarely when we associate file handle with a completion port, but want not use it in some call. usually this is another api call. for example we can create asynchronous file handle, associate it with a completion port. and use port notifications in call WriteFile, but before begin write we can set/remove compression on file via FSCTL_SET_COMPRESSION. because file is asynchronous, the FSCTL_SET_COMPRESSION also can complete asynchronous, but we can want prevent completion port notification for this ioctl, instead wait inplace (on event) for it complete. for such situation and can be used this trick.
and in most case applications (if this not server with huge count of i/o requests) can instead manual call GetQueuedCompletionStatus, bind callback to file via BindIoCompletionCallback or CreateThreadpoolIo. as result system for you create iocp, thread pool which will be listen on this iocp (via GetQueuedCompletionStatus or NtRemoveIoCompletion) and then call your callback. this is very simplify your src code and logic
findings:
i almost sure (despite not view your code) that you not need at all
use trick with event low-order bit
if you use this trick in some I/O request (say ReadDirectoryChangesW)
this affect only this particular request
you can not change the behaviour by reset low-order bit in event
handle after request is sent, or by any another way
you in general not need use GetQueuedCompletionStatus and self thread
pool at all. instead simply call BindIoCompletionCallback for file

SASL bind over GSSAPI using kerberos credentials with ldap_sasl_bind_s function

I am trying to implement SASL bind over GSSAPI using kerberos credentials with ldap_sasl_bind_s function. I follow to the steps described in ldap_sasl_bind_s(GSSAPI) - What should be provided in the credentials BERVAL structure chain
I get expected return values for all calls described in the mentioned chain, until the last(third) call to ldap_sasl_bind_s, which fails with LDAP_INVALID_CREDENTIALS error. Also I see the following error occurs in the windows event viewer
Error value:
80090308: LdapErr: DSID-0C0904D1, comment: AcceptSecurityContext error, data 5, v1771
Please note I have two applications, let us call them client and server, client is being run under some Active domain account,server application receives credentials from the client and tries to bind to ldap using tokens provided by the client.
here are the steps I do. Client calls
int res = AcquireCredentialsHandle(NULL, "Kerberos" , SECPKG_CRED_BOTH,NULL, NULL, NULL, NULL, &credhandle1, &expry1);
After filling credhandle1 I pass it to the first call of InitializeSecurityContext again in the client side
res = InitializeSecurityContext(&credhandle1,NULL,(SEC_CHAR*)(&spn1[0]),ISC_REQ_INTEGRITY|ISC_REQ_MUTUAL_AUTH|ISC_REQ_SEQUENCE_DETECT|ISC_REQ_CONFIDENTIALITY|ISC_REQ_DELEGATE,0,SECURITY_NATIVE_DREP ,NULL,0,&NewContext2,&sec_buffer_desc1,&contextattr2,&expry2);
I use one of the spn-s available in my active directory setup. This call returns SEC_I_CONTINUE_NEEDED, and fills sec_buffer_desc1 which is then passed to my server application to call ldap_sasl_bind_s with constructed token.
First call of ldap_sasl_bind_s returns LDAP_SUCCESS, and fills struct berval *servresp, here is the call
rc1 = ldap_sasl_bind_s(ld1, "", "GSSAPI", &cred1, NULL, NULL, &servresp);
The token in servresp is passed to the client application which does the second call of InitializeSecurityContext as follows
res = InitializeSecurityContext(&credhandle1, &NewContext2, (SEC_CHAR*)(&spn1[0]),ISC_REQ_INTEGRITY|ISC_REQ_MUTUAL_AUTH|ISC_REQ_SEQUENCE_DETECT|ISC_REQ_CONFIDENTIALITY|ISC_REQ_DELEGATE,0, 0, &InBuffDesc3, 0, &NewContext3, &sec_buffer_desc3, &contextattr3, &expry3);
InBuffDesc3 contains credentials returned from the server.
This call returns SEC_E_OK, and produced empty output token in sec_buffer_desc3,
This token is passed to the server which calls ldap_sasl_bind_s second time
rc1 = ldap_sasl_bind_s(ld1, "", "GSSAPI", &cred2, NULL, NULL, &servresp2);
This call again returns LDAP_SUCCESS and fills servresp2 with 32 byte long token which is then passed to the client. Last error message in the server is LDAP_SASL_BIND_IN_PROGRESS.
I pass to DecryptMessage NewContext2 (that was received in InitSecContext call) as a first argument. BuffDesc passed as second argument to DecryptMessage contains pointer to two SecBuffer objects, SecBuffer[0] has type SECBUFFER_STREAM and contains server response (token generated by the second call of ldap_sasl_bind_s) and SecBuffer[1] has type SECBUFFER_DATA.After DecryptMessage call SecBuffer[1] is being filled by some token(also it's size is being changed, so I think that it contains decrypted message). Third argument of DecryptMessage is 0 and the last one is being filled by SECQOP_WRAP_NO_ENCRYPT value after Decrypting the message. Here is the call
ULONG ulQop;
res = DecryptMessage( &NewContext2, &BuffDesc, 0, &ulQop);
In SECBUFFER_DATA buffer passed to DecryptMessage I receive 4 bytes long token (which seems to be the last 4 bytes of input SECBUFFER_STREAM buffer). The first byte of "decrypted message(SecBuff[1].pvBuffer)" is 7, then I do the following
unsigned char * ptr = (unsigned char *)SecBuff[1].pvBuffer;
int maxsize = (ptr[1]<<16) | (ptr[2]<<8)| (ptr[3]);
ptr = (unsigned char *) malloc(4);
ptr[0]= 4;
ptr[1]= maxsize>>16;
ptr[2]= maxsize>>8;
ptr[3]= maxsize;
I am constructing the input SecBufferDesc object for EncryptMessage using
three buffers, first one has type SECBUFFER_TOKEN which is filled after EncryptMEssage call(so I think it contains encrypted message after this call), the second one has SECBUFFER_DATA type and contains ptr I have constructed above, and the third buffer of type SECBUFFER_PADDING.
I call EncryptMessage as follows
err = EncryptMessage(&NewContext2,fQOP,&inSecBufDescSecond, 0);
which returns SEC_E_OK, and produces 28 bytes long token in the buffer with type SECBUFFER_TOKEN, this output token is then passed to my server application which calls ldap_sasl_bind_s with this token as client credentials and fails with invalid credentials error.
I looked at RFC mentioned in the post also tried to find any working example with SASL and kerberos credentials, however was not able to deal with this error.
Any help will be appreciated, could you please help me to get to the bottom of this issue, or provide some working code example so that I can take a look.
Thank you !
-Grigor
I ran into the exact same problem, and I think I found the solution:
The message you send in the third ldap_sasl_bind_s call should be the concatenation of all three buffers given to EncryptMessage (in the order TOKEN, DATA, PADDING)
When I do that, it works!

WinHTTP Async Callback

I'm not very good in C++, you if you see something in the code fragment which could be better, please educate me!
I'm implementing winhttp in an asynchronous fashion. But im having trouble retrieving the response. I cant figure it out. Because you should be able to parsethe whole response at once. Since multiple concurent request can occur, buffering the response (headers+body) in a global variable is not the way to go.
How can I retrieve the response of the http get request? Or else, is it an good practice to execute winhttp synchronous on a new thread (so the main loop doesn;t get blocked and then calls a function when done?):
void __stdcall cb(HINTERNET h, DWORD_PTR d, DWORD dwInternetStatus, LPVOID lpvStatusInformation, DWORD dwStatusInformationLength){
char* s=new char[1];
DWORD dwSize = 0;
if (dwInternetStatus==WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE){
MessageBoxA(0,s,"",0);
WinHttpQueryDataAvailable( h, &dwSize);
.....
}
}
And the call in the main:
...winhttpopen...
WinHttpSetStatusCallback(request, (WINHTTP_STATUS_CALLBACK)whCallback,WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS,0);
...winhttpsend....
Check this sample code on MSDN - Asynchronous Completion in WinHTTP.
The call to WinHttpQueryDataAvailable in QueryData generates a status
callback with a WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE completion in
the dwInternetStatus parameter. By checking the value pointed to by
the lpvStatusInformation parameter, the callback can determine how
much data is left to be read, and if there is no remaining data, can
proceed to display all the data that has been read.
This shows you that your callback is called with buffer pointer and length of data in it.

threading in someone else's address space

I'm building a monitor app and am having some threading issues.
I have, using a cbt hook, injected a dll in to another processes memory. I am reading the memory of the other application at certain addresses. The trouble is I was using a loop to watch the process and basically the app being watched wasn't free to carry on. So I thought put my watch process in a thread. I am using the code below to create the thread:
void readAddresses(DWORD addr)
{
LPDWORD dwThreadID;
HANDLE hThread = CreateThread(NULL,0,ThreadProc,&addr,0,dwThreadID);
}
I did try with CreateRemoteThread(...) as well and got the same error. With the thread running when it calls the ReadProcessMemory() api it fails and i am not really sure what I am doing wrong.
//going to pass in an address, dword
DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
DWORD pid;
GetWindowThreadProcessId(targetWindow,&pid);
HANDLE hProcess = ::OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION |
PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ,
FALSE, pid);
...
ReadProcessMemory(hProcess,(void *)_start, data, 255, &lpRead);
...
}
The trouble is when I call readprocessmemory I now get an access violation. What I am curious about is that is the thread operating in the same process address space as the process into which it been injected. As I said without the thread code it works fine but i need the monitor code to run in the background and i am wondering how to achieve this? Should I use create remote thread?
As Remus sais use beginthread() or beginthreadex()...
Thanks
One thing is sure: addresses to read and write are definitely not a DWORD type. From the code above, it seems that you pass an DWORD addr as the address to read from, then you start a thread to which you pass on the address of your local addr parameter. Most likely the thread proc is then attempting to read the address where the addr parameter once was in the current process on the original thread stack (a meaningless address now in any process) and the result is random (sometimes you will hit jackpot and read some innocent victim location on the remote process).
pass in the address to read as a proper address (LPVOID). DWORD cannot be right.
pass to the background thread the address you want to read, not some local stack frame garbage it cannot use
.
void readAddresses(LPVOID addr)
{
LPDWORD dwThreadID;
HANDLE hThread = CreateThread(NULL,0,myThreadProc,addr,0,dwThreadID);
}
DWORD WINAPI myThreadProc(LPVOID addr)
{
...
ReadProcessMemory (..., addr);
}

RegisterDeviceNotification Returns NULL but notifications still recieved

I'm using RegisterDeviceNotification to watch for changes to a USB device, using the WM_DEVICECHANGE event. However, when I call RegisterDeviceNotification() it returns NULL for the notification handle, which should indicate that it failed. But GetLastError() returns ERROR_SUCCESS and the notifications actually go through.
This causes real trouble when I, later on, need to UnRegister for notifications and then re-register. Since the handle it returned was NULL, I can't actually re-register. If I try, RegisterDeviceNotification() just hangs.
My code is as follows:
DEV_BROADCAST_HANDLE devBrHdr;
::ZeroMemory( &devBrHdr,sizeof( DEV_BROADCAST_HANDLE ) );
devBrHdr.dbch_size = sizeof( DEV_BROADCAST_HANDLE );
devBrHdr.dbch_devicetype = DBT_DEVTYP_HANDLE;
devBrHdr.dbch_handle = m_hDriver;
m_hDevNotify = ::RegisterDeviceNotification( hWnd,&devBrHdr,DEVICE_NOTIFY_WINDOW_HANDLE );
m_hDriver is the Handle to the driver, which I opened earlier, upon connecting to the device (a USB barcode scanner).
Any ideas what I'm doing wrong here?
Make sure you are not making another Win32 API call between RegisterDeviceNotification and GetLastError.
Check the value of devBrHdr.dbch_hdevnotify. It should contain the same handle returned by RegisterDeviceNotification.
Was the m_hDriver value obtained from a call to CreateFile?