output from OutputDebugString [duplicate] - c++

I'm trying to catch all OutputDebugString messages (including those from services) using the following code. It worked fine until I migrated to Windows 7.
The problem is that since Windows Vista services are running in the low level Session #0, some people say that it's impossible to catch them and some that it is. What do you think?
Is it possible to modify the following code by increasing some rights to be able to receive OutputDebugString messages from the Session #0? In other words; is it possible to share DBWIN_BUFFER in the session #0 with Session #1?
I would say it should be possible because e.g. DebugView can do that, and I can't see any service helper which would send those messages (e.g. through the named pipes) from the Session #0 to Session #1, where the GUI's running.
The problem will be IMO in the security settings. Can anyone suggest me how to modify them?
type
TODSThread = class(TThread)
protected
procedure Execute; override;
end;
...
procedure TODSThread.Execute;
var SharedMem: Pointer;
SharedFile: THandle;
WaitingResult: DWORD;
SharedMessage: string;
DataReadyEvent: THandle;
BufferReadyEvent: THandle;
SecurityAttributes: SECURITY_ATTRIBUTES;
SecurityDescriptor: SECURITY_DESCRIPTOR;
begin
SecurityAttributes.nLength := SizeOf(SECURITY_ATTRIBUTES);
SecurityAttributes.bInheritHandle := True;
SecurityAttributes.lpSecurityDescriptor := #SecurityDescriptor;
if not InitializeSecurityDescriptor(#SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION) then
Exit;
if not SetSecurityDescriptorDacl(#SecurityDescriptor, True, nil, False) then
Exit;
BufferReadyEvent := CreateEvent(#SecurityAttributes, False, True, 'DBWIN_BUFFER_READY');
if BufferReadyEvent = 0 then
Exit;
DataReadyEvent := CreateEvent(#SecurityAttributes, False, False, 'DBWIN_DATA_READY');
if DataReadyEvent = 0 then
Exit;
SharedFile := CreateFileMapping(THandle(-1), #SecurityAttributes, PAGE_READWRITE, 0, 4096, 'DBWIN_BUFFER');
if SharedFile = 0 then
Exit;
SharedMem := MapViewOfFile(SharedFile, FILE_MAP_READ, 0, 0, 512);
if not Assigned(SharedMem) then
Exit;
while (not Terminated) and (not Application.Terminated) do
begin
SetEvent(BufferReadyEvent);
WaitingResult := WaitForSingleObject(DataReadyEvent, INFINITE);
case WaitingResult of
WAIT_TIMEOUT: Continue;
WAIT_OBJECT_0:
begin
SharedMessage := String(PAnsiChar(SharedMem) + SizeOf(DWORD));
// here I have what I need and process it in the main thread
end;
WAIT_FAILED: Continue;
end;
end;
UnmapViewOfFile(SharedMem);
CloseHandle(SharedFile);
end;
I've added the C# tag even if the code is in Delphi because the security attributes are common for the whole Windows API and C# has many followers :)

Someone talked about the same issue in the SysInternals forums. Their solution was to add "Global\" to the named objects.
So use the following
CreateEvent(#SecurityAttributes, False, True, 'Global\DBWIN_BUFFER_READY');
CreateEvent(#SecurityAttributes, False, False, 'Global\DBWIN_DATA_READY');
CreateFileMapping(THandle(-1), #SecurityAttributes, PAGE_READWRITE, 0, 4096, 'Global\DBWIN_BUFFER');

Related

How can an independent DLL find out what Token file accesses will be made with?

If the parent process has used LogonUser so that the access token being used for file access is different than than the token the process was started with, how can the DLL find out the NT User name that the file accesses will be processed under?
If I had a specific file location then I could use GetFileSecurity, however I don't know any guaranteed accessible paths in the context of the DLL.
If I used the following:
PSID ownedSID(NULL);
SECURITY_INFORMATION siRequested = OWNER_SECURITY_INFORMATION;
wSecInfoOK = GetSecurityInfo(GetCurrentProcess(), SE_KERNEL_OBJECT, siRequested, &ownedSID, NULL, NULL, NULL, NULL);
then the PSID returned references the Windows user of the logged on process rather than that under which any writes will be treated as!
New Question in light comment / answer from #arx
I am now using TokenUser with GetTokenInformation on the handle from OpenThreadToken, but again I am getting the launching user but not the impersonated user
HANDLE hThreadToken = NULL;
if (OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &hThreadToken))
{
// success
CHeapPtr<TOKEN_USER, CGlobalAllocator> pToken;
DWORD length = 0U, dwError(0UL);
if (!GetTokenInformation(hThreadToken, TokenUser, NULL, 0, &length) && ERROR_INSUFFICIENT_BUFFER == GetLastError())
{
pToken.AllocateBytes(length);
SetLastError(ERROR_SUCCESS);//Reset last error - we have now allocated the required memory so the buffer is now big enough i.e GetLastError() != ERROR_INSUFFICIENT_BUFFER
if (pToken && GetTokenInformation(hThreadToken, TokenUser, pToken, length, &length))
{
if (IsValidSid(pToken->User.Sid))
sFailedUser = WinSecurityInfo::GetAccountSID(pToken->User.Sid, dwError);
}
dwError = GetLastError();
if (dwError)
{
boost::system::error_code sidError = MakeSysError(dwError);
TRACE("Error text for GetLastError() = '%s'\n", sidError.message().c_str());
}
}
}
P.S WinSecurityInfo::GetAccountSID is just a wrapper around LookupAccountSid
P.P.S Tried both FALSE and TRUE in OpenThreadToken, no change
You are looking at the wrong information in the thread token retrieved with OpenThreadToken. To get the identity of the user being impersonated you need to look at the TokenUser, not the TokenOwner.
Use GetTokenInformation to retrieve the user.
However, rather than going to great lengths to work in the face of impersonation, it is more usual to specify as part of your API contract that you don't. And then ignore the problem.

Access violation on WinInetHttpInfo.QueryInfo

I got a simpel question. Does anybody know how I can retrieve the cookies from a webservice in Delphi?
I've already tried the following code and I can read all data from the soap header but the cookies are missing and I know they are there because when I call a function from the webservice by SoapUI I can see them.
I made a simpel form an put a button on it. On click of the button event calls a function with the following instructions in it:
Any idea?
var
hInet: HINTERNET;
hConnect: HINTERNET;
infoBuffer: array [0..INTERNET_MAX_PATH_LENGTH] of char;
dummy: DWORD;
bufLen: DWORD;
okay: LongBool;
reply: String;
begin
hInet := InternetOpen(PChar(application.title), INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY, nil, nil, 0);
hConnect := InternetOpenUrl(hInet, PChar(url), nil, 0, INTERNET_FLAG_NO_UI, 0);
if not Assigned(hConnect) then
result := false
else
begin
dummy := 0;
bufLen := Length(infoBuffer);
okey := HttpQueryInfo(hConnect, HTTP_QUERY_RAW_HEADERS_CRLF, #infoBuffer[0], bufLen, dummy);
...
I also have a HTTPRIO component on my form which I use to communicate with the webservice. What I couldn't figure out is how I can use this component to get it work with the code above.
Thank you all in advance for your answer,
Farshid
When calling HttpQueryInfo(), the buffer size needs to be expressed in bytes, but you are expressing it in characters instead. If you are using Delphi 2009 or later (you did not say which you are using), then SizeOf(Char) is 2, not 1.
Try this:
bufLen := Length(infoBuffer) * SizeOf(Char);
okey := HttpQueryInfo(hConnect, HTTP_QUERY_RAW_HEADERS_CRLF, #infoBuffer[0], bufLen, dummy);
...
Or:
bufLen := SizeOf(infoBuffer);
okey := HttpQueryInfo(hConnect, HTTP_QUERY_RAW_HEADERS_CRLF, #infoBuffer[0], bufLen, dummy);
...
That being said, you can alternatively ask HttpQueryInfo() for the necessary byte size instead:
var
infoBuffer: array of Byte;
...
bufLen := 0;
okey := HttpQueryInfo(hConnect, HTTP_QUERY_RAW_HEADERS_CRLF, nil, bufLen, dummy);
if (not okey) and (GetLastError = ERROR_INSUFFICIENT_BUFFER) then
begin
SetLength(infoBuffer, bufLen);
okey := HttpQueryInfo(hConnect, HTTP_QUERY_RAW_HEADERS_CRLF, Pointer(infoBuffer), bufLen, dummy);
end;
if okey then
begin
// use PChar(infoBuffer) up to (Length(infoBuffer) div SizeOf(Char)) characters...
...
end;

Directory relative ZwCreateFile

I have to implement cross view file integrity checker for my University project. For that how do I list the files of a Directory in Kernel Mode??
Your starting point would be ZwCreateFile - which has options such as "FILE_LIST_DIRECTORY".
You will then use ZwQueryDirectoryFile to get the information about the file(s) within that directory.
Make SURE that you are not forgetting to ZwClose after you open something - it's not so critical in a user-mode application that closes again after it's been used. But the kernel doesn't know when a driver stops using a file (or, for that matter, if some other driver has been given that filehandle, and will be using it at some point), so even if your driver is unloaded, files that it opened will remain open until the system restarts - I quite like to "not restart" my systems, and with a good set of drivers, running a machine for more than a year should be possible. If your driver so much as leaks one handle a day, that's 365 handles leaked.
So, the code would look something like this:
HANDLE h;
NTSTATUS status;
OBJECT_ATTRIBUTES oa = { sizeof(OBJECT_ATTRIBUTES), NULL, L"mydir",
OPEN_CASE_INSENSITIVE, NULL, NULL };
IO_STATUS_BLOCK iosb = {};
status = ZwCreateFile(&h, FILE_LIST_DIRECTORY, &oa, &iosb, NULL,
FILE_ATTRIBUTE_NORMAL, FILE_OPEN, FILE_DIRECTORY_FILE,
NULL, 0);
if (status != STATUS_SUCCESS)
{
... do something...
return errorcode;
}
else
{
FILE_DIRECTORY_INFORMATION info;
for(;;)
{
status = ZwQueryDirectoryFile(h, NULL, NULL, &iosb, &info, sizeof(info),
FileDirectoryInformation, TRUE, L"*.*",
FALSE);
if (status != STATUS_SUCCESS)
{
... check error code and perhaps print if unexpected error ...
break;
}
... do soemthing with `info` ...
}
}
ZwClose(h);
This is just a "rough sketch". I don't have a setup to compile this right now, and I may have missed something important. But it should give you some idea. There are LOTS of optional parameters and optional choices here, and some I've "guessed" what you'd want, but I think I've made reasonable choices. There may be details missing that make this not work, but as a rough starting point, it should give you an idea at least.

how to know if a MFC application is open when it is going to be uninstalled

I have a MFC application in which I want to implement a part, which displays a message popup when user is going to uninstall it while keeping the application open. But I am not getting any clue regarding this. Can anyone please suggest a way to do this?
Create a semaphore with a unique name. Then in your uninstallation program you check if the semaphore exists, if yes that means that the application is running.
In your program:
CreateSemaphore(NULL, 0, 1, "Some unique string of your choice") ;
In your uninstall program:
BOOL isrunning = FALSE ;
HANDLE hsem = CreateSemaphore(NULL, 0, 1, "Some unique string of your choice") ;
if (hsem != NULL)
{
if (GetLastError() == ERROR_ALREADY_EXISTS)
isrunning = TRUE ;
CloseHandle(hsem) ;
}

CreateFileMapping and OpenFileMapping not cooperating in different processes

I'm trying to use CreateFileMapping and OpenFileMapping to share memory between processes. This isn't working as I want it to - OpenFileMapping returns null and GetLastError is 5 - access denied. Any ideas what I am doing wrong? Name is something like MemoryTest.
Edit:
using CreateFileMapping both times I can read the data written in the other process. The reason this is a problem is that I get Error 183 - memory area already exists. However, it still returns a handle to the existing memory.
var map_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(int), name.c_str());
....
var handle = MapViewOfFile(map_handle, FILE_MAP_ALL_ACCESS , 0, 0, 0)
*handle = 10;
UnMapViewOfFile(map_handle);
getchar();
Other process:
var map_handle = OpenFileMapping(PAGE_READWRITE, false, name.c_str())
....
var handle = MapViewOfFile(map_handle, FILE_MAP_ALL_ACCESS , 0, 0, 0) //returns null
var out = *handle;
getchar();
This works for the second process though:
var map_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(int), name.c_str());
....
var handle = MapViewOfFile(map_handle, FILE_MAP_ALL_ACCESS , 0, 0, 0) //returns null
var out = *handle;
getchar();
Simple things to be aware of from the very start:
Error code 5: ERROR_ACCESS_DENIED "Access is denied."
Error code 183: ERROR_ALREADY_EXISTS "Cannot create a file when that file already exists."
ERROR_ALREADY_EXISTS is a documented behavior and is an indication of scenario that you do receive handle, but it is a handle to already existing object, not created.
The problem with not working OpenFileMapping is around its first argument: the API function expects values/flags from another enumeration, it takes FILE_MAP_* values and not PAGE_*. Incorrect argument results in failure to open you the mapping you want.
In case someone else needed, in my case the error has nothing to do with the access to the file, it's with the size provided to the CreateFileMapping, after spending hours with a similar error I'd to use a working sample posted somewhere else and line by line compare what was the difference.
If you don't know the size of the file when executing the CreateFileMapping you need to use 0, this will tell the API to use the file size of the mapped file. Most of the answers in SO around this are wrong and people is not bothering testing what is the problem about, I wasted hours reading other posts with similar suggestions.
To solve the problem the code should look like this:
var map_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 0, name.c_str());
Hope this saves hours to other fellow developers.