inet_ntoa UNICODE or similar (convert IN_ADDR to UNICODE) - windows

I have an application server built as UNICODE running on Windows only. The application accepts lots of clients using multithreading.
Part of the application is responsible for logging connections, to log IPv4 addresses I convert them to UNICODE from ANSI. I achieve this using inet_ntoa + MultiByteToWideChar.
My frustration is that there is no UNICODE version of inet_ntoa and I am forced to convert each IPv4 to UNICODE. Although MultiByteToWideChar is relatively fast, it is still a performance loss and prone to failure, especially when you have 100,000 connections coming in.
Researching a bit I have found functions like RtlIpv4AddressToStringExW, however I do not have experience with these and applying it to real life applications can be fatal failure without proper testing.
Investigating the above function I have seen that there is no call to MultiByteToWideChar, but instead to RtlIpv4AddressToStringW and swprintf_s, which tells me I really don't need to convert anything (?).
Please advise what is the best way to obtain the readable UNICODE version of IN_ADDR.
Any advice is much appreciated.
Update:
I investigated inet_ntoa and there is quite a lot of code there, retrieving stuff from TLS among other stuff. Overkill from my opinion.
Also investigated WSAAddressToString as proposed by #Alex Guteniev. Again a ton of code, for what purpose...
Also investigated RtlIpv4AddressToStringExW, and my findings worry me again how Windows API's are designed and offered.
Windows Implementation:
LONG __stdcall RtlIpv4AddressToStringExW(const struct in_addr *Address, USHORT Port, PWSTR AddressString, PULONG AddressStringLength)
{
PULONG v4; // rdi
PWSTR v5; // rbp
USHORT v6; // si
wchar_t *v7; // rax
signed __int64 v8; // rbx
ULONG v9; // ebx
LONG result; // eax
WCHAR S; // [rsp+20h] [rbp-68h]
char v12[4]; // [rsp+4Ch] [rbp-3Ch]
v4 = AddressStringLength;
v5 = AddressString;
v6 = Port;
if ( Address && AddressStringLength && (AddressString || !*AddressStringLength) )
{
v7 = RtlIpv4AddressToStringW(Address, &S);
v8 = (signed __int64)v7;
if ( v6 )
v8 = (signed __int64)&v7[swprintf_s(v7, (v12 - (char *)v7) >> 1, L":%u", (unsigned __int16)__ROR2__(v6, 8))];
v9 = (unsigned __int64)((v8 - (signed __int64)&S) >> 1) + 1;
if ( *v4 >= v9 )
{
memmove(v5, &S, 2i64 * v9);
result = 0;
*v4 = v9;
return result;
}
*v4 = v9;
}
return -1073741811;
}
PWSTR __stdcall RtlIpv4AddressToStringW(const struct in_addr *Addr, PWSTR S)
{
__int64 v3; // [rsp+20h] [rbp-28h]
__int64 v4; // [rsp+28h] [rbp-20h]
__int64 v5; // [rsp+30h] [rbp-18h]
LODWORD(v5) = Addr->S_un.S_un_b.s_b4;
LODWORD(v4) = Addr->S_un.S_un_b.s_b3;
LODWORD(v3) = Addr->S_un.S_un_b.s_b2;
return &S[swprintf_s(S, 0x10ui64, L"%u.%u.%u.%u", Addr->S_un.S_un_b.s_b1, v3, v4, v5)];
}
RectOS Implementation:
NTSTATUS
NTAPI
RtlIpv4AddressToStringExW(
_In_ const struct in_addr *Address,
_In_ USHORT Port,
_Out_writes_to_(*AddressStringLength, *AddressStringLength) PWCHAR AddressString,
_Inout_ PULONG AddressStringLength)
{
WCHAR Buffer[IPV4_ADDR_STRING_MAX_LEN + IPV4_PORT_STRING_MAX_LEN];
NTSTATUS Status;
ULONG Length;
PWSTR End;
if (!Address || !AddressString || !AddressStringLength)
return STATUS_INVALID_PARAMETER;
Status = RtlStringCchPrintfExW(Buffer,
RTL_NUMBER_OF(Buffer),
&End,
NULL,
0,
Port ? L"%u.%u.%u.%u:%u"
: L"%u.%u.%u.%u",
Address->S_un.S_un_b.s_b1,
Address->S_un.S_un_b.s_b2,
Address->S_un.S_un_b.s_b3,
Address->S_un.S_un_b.s_b4,
WN2H(Port));
ASSERT(Status == STATUS_SUCCESS);
if (!NT_SUCCESS(Status))
return STATUS_INVALID_PARAMETER;
Length = End - AddressString;
if (*AddressStringLength > Length)
{
Status = RtlStringCchCopyW(AddressString,
*AddressStringLength,
Buffer);
ASSERT(Status == STATUS_SUCCESS);
*AddressStringLength = Length + 1;
return STATUS_SUCCESS;
}
*AddressStringLength = Length + 1;
return STATUS_INVALID_PARAMETER;
}
My opinion here is that the ReactOS implementation is FAR better than the one in Windows. I believe RtlStringCchPrintfExW is much safer than swprintf_s.
In the end, is it safe for me (and anyone else) to create their own implementation of formatting?

Use WSAAddressToStringW if you want a generic function to convert addresses.
These Windows API are not necessarily optimized for throughput, instead they probably handle different addresses type.
If you are limited to specific address types, like IPv4 only, you can probably create your own implementation, if performance that much matters.
Consider SIMD (SSE, AVX) if you need top performance. If you just need a simple implementation, consider just using swprintf (or calling _itow few times if you mind format specification parsing overhead)

Related

UNICODE_STRING to std String Conversion

I am using pFileObject->FileName to get the name of file opened in a kernel mode filter driver.This file name returned by this is in the form of UNICODE_STRING. I want to convert it into std String. What is the method ??? Please do provide example if possible...
Below is the code
NTSTATUS FsFilterDispatchCreate(
__in PDEVICE_OBJECT DeviceObject,
__in PIRP Irp
)
{
PFILE_OBJECT pFileObject = IoGetCurrentIrpStackLocation(Irp)->FileObject;
DbgPrint("%wZ\n", &pFileObject->FileName);
return FsFilterDispatchPassThrough(DeviceObject, Irp);
}
I agree with Hans' comment. Making std:: classes work in Windows kernel mode is extremely difficult if not impossible. The default WinDDK environment is C rather than C++. Your best bet is to convert UNICODE_STRING to ANSI null-terminated string. (You can print it with DbgPrint("%s"...) etc). See example below.
UNICODE_STRING tmp;
// ...
ANSI_STRING dest;
ULONG unicodeBufferSize = tmp.Length;
// Length of unicode string in bytes must be enough to keep ANSI string
dest.Buffer = (PCHAR)ExAllocatePool(NonPagedPool, unicodeBufferSize+1);
// check for allocation failure...
dest.Length = 0;
dest.MaximumLength = unicodeBufferSize+1;
RtlUnicodeStringToAnsiString(&dest, &tmp, FALSE);
// check for failure...
dest.Buffer[dest.Length] = 0; // now we get it in dest.Buffer

How to intercept out-of-proc desktop STA COM to STA COM communication or reference counting decrementing?

My example:
PowerPoint start Excel when insert embedded workbook.
I continue to work with PowerPoint. Excel stays as hidden process.
When I close PowerPoint it says to Excel to close itself (Excel closed later then PowerPoint).
When I kill PowerPoint, Excel becomes zombie.
My add-in is loaded into Excel process.
What message(I read that COM STA objects communicate through windows messaging) I should intercept to be notified about such event? What hook should I use? Is there any mean to be notified about count of reference to COM object changes?
UPDATE
My question seems was ambiguous. I am not trying to handle case when I kill PowerPoint. It just for evidence that PowerPoint send some message to Excel when closed normally. I am trying to intercept this message for a good reason.
UPDATE2
I cannot use API - because API fails. I am trying to solve Creating class in new thread in new app domain and providing it with Office COM object in embedded mode leads to zombie process
In case if you kill 'PowerPoint' there will be no reference count changes in Excel. That is why it is not being unloaded.
I believe you may simply post WM_QUIT message to the main window of the Excel process. You may find it using "Spy++.exe" which is a tool bundled with Visual Studio. Also, it is possible, that you may acquire a class factory for some object in Excel and invoke the 'LockServer' method with fLock = FALSE. This will decrease the reference count of Excel server.
But take this as a hack, since an add-in should not influence the behavior of the host application.
None. COM on a local server does use windows messages but it uses private messages which are an implementation detail. All it really does is post messages to a hidden window meaning "you have new COM events in your apartment". The hidden window passes this to the COM library which uses (I believe) shared memory to communicate with other processes, and does the rest of the work such as finding out what the event is (call, call return etc).
In other words, there is no specific message to say "excel go away", and even if there was you couldn't rely on it becaues it is an implementation detail which can change.
When you close the PowerPoint document containing the embedded spreadsheet, PowerPoint will call IUnknown::Release() on all the objects it holds. Excel keeps an internal track of outstanding objects, and will close itself when they all go away.
If you have an add-in in the excel process, and want to know when excel closes, use the addin api to find out.
Depending on the type of Add-In there are different APIs for this. The COM add-ins have events you can register for. But that is a different question: "how can my Excel add-in get notification that an invisible Excel instance is closing".
Added Solution to actual problem/question not asked
#asd.and.Rizzo, this is occurring because you hare holding on to the objects created by Excel. This means that Excel thinks it cannot exit because someone is using the objects. Excel is correct because that somone is your add-in.
This sort of lifetime issue is typical when creating any Office or Excel add-in and is not unique to .Net add-ins.
You are wanting to solve the problem by cheating Excel's reference count. But it is in your hands: The reference count is only up because you are holding objects! If you release them the count will go down to zero with no cheating.
Solution
The best solution is to avoid sinking events and avoid holding on to any object. Depending on what your add-in is doing this may not be possible.
If you cannot, you must sink the document close events. In each, check how many documents are open. When the count reaches zero you should remove your event handlers, call Marshall.ReleaseComObject on every object you have ever held, and unload your add-in. Excel will then exit.
But please note: You must call Marshall.ReleaseComObject on every object you ever hold. If you don't, Excel will never exit. This should occur if you unload the AppDomain.
I found next (from interpreting COM interfaces as pure C structs + function and Direct X hacks). Works but does not fix problem for some reason. My be should do the same for Workbooks, Worksheets...
Declare:
typedef HRESULT STDMETHODCALLTYPE QueryInterfacePtr( REFIID, void **);
typedef ULONG STDMETHODCALLTYPE AddRefPtr( );
typedef ULONG STDMETHODCALLTYPE ReleasePtr( );
typedef ULONG STDMETHODCALLTYPE GetTypeInfoCountPtr( UINT *) ;
typedef ULONG STDMETHODCALLTYPE GetTypeInfoPtr ( UINT, LCID, ITypeInfo **) ;
typedef ULONG STDMETHODCALLTYPE GetIDsOfNamesPtr ( REFIID, LPOLESTR *,
UINT, LCID, DISPID *) ;
typedef ULONG STDMETHODCALLTYPE InvokePtr ( DISPID, REFIID,
LCID, WORD, DISPPARAMS *,
VARIANT *, EXCEPINFO *, UINT *) ;
typedef struct {
// IUnknown functions
QueryInterfacePtr * QueryInterface;
AddRefPtr * AddRef;
ReleasePtr * Release;
// IDispatch functions
GetTypeInfoCountPtr* GetTypeInfoCount;
GetTypeInfoPtr* GetTypeInfo;
GetIDsOfNamesPtr* GetIDsOfNames;
InvokePtr* Invoke;
} IDispatchInterceptor;
typedef ULONG __stdcall releasePTR(IDispatch *self);
typedef ULONG __stdcall addrefPTR(IDispatch *self);
Next I have done for Excel:
static IDispatch * application = NULL;
static releasePTR* realRelease = NULL;
static addrefPTR* realAddRef = NULL;
static ULONG wasAdd = 0;
static ULONG oldCount = 0;
HRESULT STDMETHODCALLTYPE QueryInterfaceNativeOutOfProcSrv(REFIID riid, void **ppv){
return application->QueryInterface(riid,ppv);
}
ULONG STDMETHODCALLTYPE AddRefNativeOutOfProcSrv(){
return application->AddRef();
}
ULONG STDMETHODCALLTYPE ReleaseNativeOutOfProcSrv(){
return application->Release();
}
ULONG STDMETHODCALLTYPE GetTypeInfoCountSrv( UINT * count) {
return application->GetTypeInfoCount(count);
}
ULONG STDMETHODCALLTYPE GetTypeInfoSrv ( UINT n, LCID id, ITypeInfo ** inf) {
return application->GetTypeInfo(n,id,inf);
}
ULONG STDMETHODCALLTYPE GetIDsOfNamesSrv ( REFIID a, LPOLESTR * b, UINT c, LCID d, DISPID * e) {
return application->GetIDsOfNames(a,b,c,d,e);
}
ULONG STDMETHODCALLTYPE InvokeSrv ( DISPID a, REFIID b, LCID c, WORD d, DISPPARAMS * e, VARIANT * i, EXCEPINFO * j, UINT *k) {
return application->Invoke(a,b,c,d,e,i,j,k);
}
static IDispatchInterceptor interceptor =
{QueryInterfaceNativeOutOfProcSrv,AddRefNativeOutOfProcSrv,ReleaseNativeOutOfProcSrv,
GetTypeInfoCountSrv,GetTypeInfoSrv,GetIDsOfNamesSrv,InvokeSrv
};
ULONG __stdcall release(IDispatch *self)
{
ULONG c = realRelease(self);
Log->logWrite("release %d",c);
if ( c == 1)
{
if (instance != NULL)
{
instance->OnBeginShutdown(NULL);
Log->logWrite("OnBeginShutdown %d",c);
instance->OnEmbeddedDisconnection();
Log->logWrite("OnEmbeddedDisconnection %d",c);
instance = NULL;
}
}
//if (c == 2) {
// c = realRelease(self);
// c = realRelease(self);
//}
return c;
}
ULONG __stdcall addref(IDispatch *self)
{
ULONG c = oldCount;
if (wasAdd == 0)
{
c = realAddRef(self);
oldCount = c;
wasAdd++;
}
else if (wasAdd == 1)
{
Log->logWrite("ADDREF FAKE %d",c);
wasAdd++;
}
else if (wasAdd == 2)
{
Log->logWrite("ADDREF FAKE %d",c);
wasAdd++;
}
else
{
c = realAddRef(self);
}
Log->logWrite("ADDREF %d",c);
return c;
}
void InterceptRelease( IDispatch obj){
void iunknown_vtable= (void*)((unsigned int)obj);
void* idispatch_vtable = (void*)(((unsigned int)iunknown_vtable)+8);
unsigned int* v1 = (unsigned int*)idispatch_vtable;
realRelease = (releasePTR*)*v1;
DWORD old;
VirtualProtect(v1,4,PAGE_EXECUTE_READWRITE,&old);
*v1 = (unsigned int) release;
//while(obj->Release() > 0){};
}
void InterceptAddRef( IDispatch obj){
void iunknown_vtable= (void*)((unsigned int)obj);
void* idispatch_vtable = (void*)(((unsigned int)iunknown_vtable)+4);
unsigned int* v1 = (unsigned int*)idispatch_vtable;
realAddRef = (addrefPTR*)*v1;
DWORD old;
VirtualProtect(v1,4,PAGE_EXECUTE_READWRITE,&old);
*v1 = (unsigned int) addref;
}
Apply:
IDispatch * app = Application;
InterceptRelease(app);
InterceptAddRef(app);

SetFilePointerEx fails to read physical disk beyond size of LONG

It's taken a few years, but I am finally taking the plunge into VC++. I need to be able to read x number of sectors of a physical device (namely a hard drive). I am using the CreateFile() and SetFilePointerEx() and ReadFile() APIs.
I have done a LOT of reading online in all the major forums about this topic. I have exhausted my research and now I feel it's time to ask the experts to weigh in on this dilemma. As this is my very first post ever on this topic, please go easy on my :)
I should also point out that this is a .DLL that I consume with a simple C# app. The plumbing all works fine. It's the SetFilePointer(Ex)() APIs that are causing me grief.
I can get the code to work up until about the size of a LONG (4,xxx,xxx) - I can't remember the exact value. It suffices to say that I can read everything up to and including sector # 4,000,000 but not 5,000,000 or above. The problem lies in the "size" of the parameters for the SetFilePointer() and SetFilePointerEx() APIs. I've tried both and so far, SetFilePointerEx() seems to be what I should use to work on 64-bit systems.
The 2nd and 3rd parameters of the SetFilePointer are defined as follows:
BOOL WINAPI SetFilePointerEx(
__in HANDLE hFile,
__in LARGE_INTEGER liDistanceToMove,
__out_opt PLARGE_INTEGER lpNewFilePointer,
__in DWORD dwMoveMethod
);
Please note that I have tried passing the LowPart and the HighPart as the 2nd and 3 parameters without any success as I get a CANNOT CONVERT LARGE_INTEGER TO PLARGE_INTEGER (for parameter 3).
HERE IS MY CODE. I USE A CODE-BREAK TO VIEW buff[0], etc. I would like to read past the 4,xxx,xxx limitation. Obviously I am doing something wrong. Each read past this limit resets my file pointer to sector 0.
#include "stdafx.h"
#include <windows.h>
#include <conio.h>
extern "C"
__declspec(dllexport) int ReadSectors(long startSector, long numSectors)
{
HANDLE hFile;
const int SECTOR_SIZE = 512;
const int BUFFER_SIZE = 512;
LARGE_INTEGER liDistanceToMove;
PLARGE_INTEGER newFilePtr = NULL; // not used in this context.
// just reading from START to END
liDistanceToMove.QuadPart = startSector * SECTOR_SIZE;
DWORD dwBytesRead, dwPos;
LPCWSTR fname = L"\\\\.\\PHYSICALDRIVE0";
char buff[BUFFER_SIZE];
// Open the PHYSICALDEVICE as a file.
hFile = CreateFile(fname,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
// Here's the API definition
/*BOOL WINAPI SetFilePointerEx(
__in HANDLE hFile,
__in LARGE_INTEGER liDistanceToMove,
__out_opt PLARGE_INTEGER lpNewFilePointer,
__in DWORD dwMoveMethod
);*/
dwPos = SetFilePointerEx(hFile, liDistanceToMove, NULL, FILE_BEGIN);
if(ReadFile(hFile, buff, BUFFER_SIZE, &dwBytesRead, NULL))
{
if(dwBytesRead > 5)
{
BYTE x1 = buff[0];
BYTE x2 = buff[1];
BYTE x3 = buff[2];
BYTE x4 = buff[3];
BYTE x5 = buff[4];
}
}
// Close both files.
CloseHandle(hFile);
return 0;
}
startSector * SECTOR_SIZE;
startSector is a long (32bits), SECTOR_SIZE is a int (also 32bits), multiply these two guys and the intermediate result is going to be a long, which will overflow and you then stuff it into the __int64 of the LARGE_INTEGER, which is too late. You want to operate on __int64s, something like
liDistanceToMove.QuadPart = startSector;
liDistanceToMove.QuadPart *= SECTOR_SIZE;
for example.

how to use CryptoAPI in the linux kernel 2.6

I have been looking for some time but have not found anywhere near sufficient documentation / examples on how to use the CryptoAPI that comes with linux in the creation of syscalls / in kernel land.
If anyone knows of a good source please let me know, I would like to know how to do SHA1 / MD5 and Blowfish / AES within the kernel space only.
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/crypto.h>
#include <linux/err.h>
#include <linux/scatterlist.h>
#define SHA1_LENGTH 20
static int __init sha1_init(void)
{
struct scatterlist sg;
struct crypto_hash *tfm;
struct hash_desc desc;
unsigned char output[SHA1_LENGTH];
unsigned char buf[10];
int i;
printk(KERN_INFO "sha1: %s\n", __FUNCTION__);
memset(buf, 'A', 10);
memset(output, 0x00, SHA1_LENGTH);
tfm = crypto_alloc_hash("sha1", 0, CRYPTO_ALG_ASYNC);
desc.tfm = tfm;
desc.flags = 0;
sg_init_one(&sg, buf, 10);
crypto_hash_init(&desc);
crypto_hash_update(&desc, &sg, 10);
crypto_hash_final(&desc, output);
for (i = 0; i < 20; i++) {
printk(KERN_ERR "%d-%d\n", output[i], i);
}
crypto_free_hash(tfm);
return 0;
}
static void __exit sha1_exit(void)
{
printk(KERN_INFO "sha1: %s\n", __FUNCTION__);
}
module_init(sha1_init);
module_exit(sha1_exit);
MODULE_LICENSE("Dual MIT/GPL");
MODULE_AUTHOR("Me");
There are a couple of places in the kernel which use the crypto module: the eCryptfs file system (linux/fs/ecryptfs/) and the 802.11 wireless stack (linux/drivers/staging/rtl8187se/ieee80211/). Both of these use AES, but you may be able to extrapolate what you find there to MD5.
Another good example is from the 2.6.18 kernel source in security/seclvl.c
Note: You can change CRYPTO_TFM_REQ_MAY_SLEEP if needed
static int
plaintext_to_sha1(unsigned char *hash, const char *plaintext, unsigned int len)
{
struct crypto_tfm *tfm;
struct scatterlist sg;
if (len > PAGE_SIZE) {
seclvl_printk(0, KERN_ERR, "Plaintext password too large (%d "
"characters). Largest possible is %lu "
"bytes.\n", len, PAGE_SIZE);
return -EINVAL;
}
tfm = crypto_alloc_tfm("sha1", CRYPTO_TFM_REQ_MAY_SLEEP);
if (tfm == NULL) {
seclvl_printk(0, KERN_ERR,
"Failed to load transform for SHA1\n");
return -EINVAL;
}
sg_init_one(&sg, (u8 *)plaintext, len);
crypto_digest_init(tfm);
crypto_digest_update(tfm, &sg, 1);
crypto_digest_final(tfm, hash);
crypto_free_tfm(tfm);
return 0;
}
Cryptodev-linux
https://github.com/cryptodev-linux/cryptodev-linux
It is a kernel module that exposes the kernel crypto API to userspace through /dev/crypto .
SHA calculation example: https://github.com/cryptodev-linux/cryptodev-linux/blob/da730106c2558c8e0c8e1b1b1812d32ef9574ab7/examples/sha.c
As others have mentioned, the kernel does not seem to expose the crypto API to userspace itself, which is a shame since the kernel can already use native hardware accelerated crypto functions internally.
Crypto operations cryptodev supports: https://github.com/nmav/cryptodev-linux/blob/383922cabeea7dca354415e8c590f8e932f4d7a8/crypto/cryptodev.h
Crypto operations Linux x86 supports: https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/arch/x86/crypto?id=refs/tags/v4.0
The best place to start is Documentation/crytpo in the kernel sources. dm-crypt is one of the many components that probably uses the kernel crypto API and you can refer to it to get an idea about usage.
how to do SHA1 / MD5 and Blowfish / AES within the kernel space only.
Example of hashing data using a two-element scatterlist:
struct crypto_hash *tfm = crypto_alloc_hash("sha1", 0, CRYPTO_ALG_ASYNC);
if (tfm == NULL)
fail;
char *output_buf = kmalloc(crypto_hash_digestsize(tfm), GFP_KERNEL);
if (output_buf == NULL)
fail;
struct scatterlist sg[2];
struct hash_desc desc = {.tfm = tfm};
ret = crypto_hash_init(&desc);
if (ret != 0)
fail;
sg_init_table(sg, ARRAY_SIZE(sg));
sg_set_buf(&sg[0], "Hello", 5);
sg_set_buf(&sg[1], " World", 6);
ret = crypto_hash_digest(&desc, sg, 11, output_buf);
if (ret != 0)
fail;
One critical note:
Never compare the return value of crypto_alloc_hash function to NULL for detecting the failure.
Steps:
Always use IS_ERR function for this purpose. Comparing to NULL does not capture the error, hence you get segmentation faults later on.
If IS_ERR returns fail, you possibly have a missing crypto algorithm compiled into your kernel image (or as a module). Make sure you have selected the appropriate crypto algo. form make menuconfig.

SysInternal's WinObj device listing mechanism

SysInternals's WinObj can list all device objects.
I wonder how it can list the devices.
Is there any open source we can read?(or a code snippet)
What is the most significant function I should know?
WinObj uses the NT system calls NtOpenDirectoryObject and NtQueryDirectoryObject. There is no driver or kernel code needed. You won't see the imports because these NT functions are loaded via LoadLibrary/GetProcAddress.
You don't have to enumerate the entire object namespace. If you're interested in the device objects call NtOpenDirectoryObject with "\Device", then call NtQueryDirectoryObject on the returned handle.
According to SysInternals' web page:
The native NT API provides routines
that allow user-mode programs to
browse the namespace and query the
status of objects located there, but
the interfaces are undocumented.
I've tried looking at WinObj's import table (dumpbin /imports winobj.exe) but there are no obvious suspects :-(
As per the answer from user1575778 you can use NtOpenDirectoryObject and NtQueryDirectoryObject (which from user mode are identical to ZwOpenDirectoryObject and ZwQueryDirectoryObject respectively) to list the objects inside the object manager namespace.
Have a look at objmgr.hpp of NT Objects aka ntobjx, in particular at the class NtObjMgr::Directory (or DirectoryT). It provides the same functionality nicely wrapped into a C++ class. The whole utility is open source under a liberal license (dual-licensed due to WTL-use: MIT and MS-PL), so bits and pieces can be reused however you please, provided you comply with the license terms.
But here's a simple C++ code example catering just your use case:
#include <Windows.h>
#include <tchar.h>
#include <cstdio>
#include <winternl.h>
NTSTATUS (NTAPI* NtOpenDirectoryObject)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES);
NTSTATUS (NTAPI* NtQueryDirectoryObject)(HANDLE, PVOID, ULONG, BOOLEAN, BOOLEAN, PULONG, PULONG);
VOID (NTAPI* RtlInitUnicodeString_)(PUNICODE_STRING, PCWSTR);
NTSTATUS (NTAPI* NtClose_)(HANDLE);
#define DIRECTORY_QUERY (0x0001)
#define DIRECTORY_TRAVERSE (0x0002)
typedef struct _OBJECT_DIRECTORY_INFORMATION {
UNICODE_STRING Name;
UNICODE_STRING TypeName;
} OBJECT_DIRECTORY_INFORMATION, *POBJECT_DIRECTORY_INFORMATION;
#ifndef STATUS_SUCCESS
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L) // ntsubauth
#endif // STATUS_SUCCESS
#ifndef STATUS_MORE_ENTRIES
#define STATUS_MORE_ENTRIES ((NTSTATUS)0x00000105L)
#endif // STATUS_MORE_ENTRIES
#ifndef STATUS_NO_MORE_ENTRIES
#define STATUS_NO_MORE_ENTRIES ((NTSTATUS)0x8000001AL)
#endif // STATUS_NO_MORE_ENTRIES
int PrintDevices()
{
NTSTATUS ntStatus;
OBJECT_ATTRIBUTES oa;
UNICODE_STRING objname;
HANDLE hDeviceDir = NULL;
RtlInitUnicodeString_(&objname, L"\\Device");
InitializeObjectAttributes(&oa, &objname, 0, NULL, NULL);
ntStatus = NtOpenDirectoryObject(&hDeviceDir, DIRECTORY_QUERY | DIRECTORY_TRAVERSE, &oa);
if(NT_SUCCESS(ntStatus))
{
size_t const bufSize = 0x10000;
BYTE buf[bufSize] = {0};
ULONG start = 0, idx = 0, bytes;
BOOLEAN restart = TRUE;
for(;;)
{
ntStatus = NtQueryDirectoryObject(hDeviceDir, PBYTE(buf), bufSize, FALSE, restart, &idx, &bytes);
if(NT_SUCCESS(ntStatus))
{
POBJECT_DIRECTORY_INFORMATION const pdilist = reinterpret_cast<POBJECT_DIRECTORY_INFORMATION>(PBYTE(buf));
for(ULONG i = 0; i < idx - start; i++)
{
if(0 == wcsncmp(pdilist[i].TypeName.Buffer, L"Device", pdilist[i].TypeName.Length / sizeof(WCHAR)))
{
_tprintf(_T("%s\n"), pdilist[i].Name.Buffer);
}
}
}
if(STATUS_MORE_ENTRIES == ntStatus)
{
start = idx;
restart = FALSE;
continue;
}
if((STATUS_SUCCESS == ntStatus) || (STATUS_NO_MORE_ENTRIES == ntStatus))
{
break;
}
}
(void)NtClose_(hDeviceDir);
return 0;
}
_tprintf(_T("Failed NtOpenDirectoryObject with 0x%08X"), ntStatus);
return 1;
}
int _tmain(int /*argc*/, _TCHAR** /*argv*/)
{
HMODULE hNtDll = ::GetModuleHandle(_T("ntdll.dll"));
*(FARPROC*)&NtOpenDirectoryObject = ::GetProcAddress(hNtDll, "NtOpenDirectoryObject");
*(FARPROC*)&NtQueryDirectoryObject = ::GetProcAddress(hNtDll, "NtQueryDirectoryObject");
*(FARPROC*)&RtlInitUnicodeString_ = ::GetProcAddress(hNtDll, "RtlInitUnicodeString");
*(FARPROC*)&NtClose_ = ::GetProcAddress(hNtDll, "NtClose");
if (!NtOpenDirectoryObject || !NtQueryDirectoryObject || !RtlInitUnicodeString_ || !NtClose_)
{
_tprintf(_T("Failed to retrieve ntdll.dll function pointers\n"));
return 1;
}
return PrintDevices();
}
Some remarks: This will not delve into subdirectories, it will not list any types other than Device and it will not resolve symbolic links, if any. For any of those features, please look at the aforementioned utility's source code and adjust as needed. winternl.h should be available in any recent Windows SDK.
The functions RtlInitUnicodeString_ and NtClose_ have a trailing underscore to avoid clashes with these native API functions, which are declared in winternl.h, but use __declspec(dllimport).
Disclosure: I am the author of ntobjx.
You can use NtOpenDirectoryObject and NtQueryDirectoryObject to enumarate the objects list in a given directory.
To get the details of the object namespace, you must use the Windows NT Undocumented API. That is also used by the WinObj as it is described here that how WinOBj getting the all results..and for those who are saying that we need a driver to do this please, read these lines on given page.
"One obvious way is to use a driver – in kernel mode everything is accessible – so the client app can get the required information by communicating with its own driver. WinObj does not use a driver, however (this is one reason it’s able to execute without admin privileges, although with admin privileges it shows all objects as opposed to partial results)."
You can start with SetupDiCreateDeviceInfoList and use other related functions to enumerate all the devices. This stuff is painful to use.

Resources