How to get module image name from an arbitrary address in Windows kernel space? - c

I'm trying to see how I can get a loaded module image name from an arbitrary address from the kernel code.
In user mode I would do this:
void* pAddr;
VOID* pBase;
WCHAR buff[MAX_PATH] = {0};
//Get address of some function in some module (just to test it)
pAddr = GetProcAddress(GetModuleHandle(L"kernel32.dll"), "GetCurrentProcess");
//Get module base address
RtlPcToFileHeader(pAddr, &pBase);
//Get module image file name
GetModuleFileNameEx(GetCurrentProcess(), (HMODULE)pBase, buff, SIZEOF(buff));
Is there a way to do the same in kernel mode if I have pAddr that can point to some address in kernel or user space?
EDIT: While waiting for the answer I came up with my own code (using undocumented way of traversing PEB):
#ifdef CALLING_FROM_KERNEL_MODE
//Kernel mode
TEB* pTEB = (TEB*)PsGetCurrentThreadTeb();
#else
//User mode
#if defined(_M_X64)
//64-bit
TEB* pTEB = reinterpret_cast<TEB*>(__readgsqword(reinterpret_cast<DWORD_PTR>(&static_cast<NT_TIB*>(nullptr)->Self)));
#else
//32-bit
TEB* pTEB = reinterpret_cast<TEB*>(__readfsdword(reinterpret_cast<DWORD_PTR>(&static_cast<NT_TIB*>(nullptr)->Self)));
#endif
#endif
PEB* p_PEB = pTEB->ProcessEnvironmentBlock;
PEB_LDR_DATA* pPLD = p_PEB->Ldr;
const WCHAR* pModName = NULL;
LIST_ENTRY* pLE = &pPLD->InMemoryOrderModuleList;
LIST_ENTRY* pLE_Head = pLE;
while(pLE_Head != pLE->Flink)
{
PLDR_DATA_TABLE_ENTRY pLDTE = CONTAINING_RECORD(pLE, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
size_t szcbSizeOfImg = (size_t)pLDTE->Reserved3[1];
if((size_t)pAddr - (size_t)pLDTE->DllBase < szcbSizeOfImg)
{
pModName = pLDTE->FullDllName.Buffer;
break;
}
pLE = pLE->Flink;
}
The problem is that although it works from a user-mode, from a kernel mode PsGetCurrentThreadTeb() seems to return NULL. Does this mean kernel threads do not have a TEB?

this can be done by creating list of all loaded modules via ZwQuerySystemInformation with SystemModuleInformation
void fgt(PVOID *Callers, ULONG Count)
{
NTSTATUS status;
ULONG cb = 0x10000;
do
{
status = STATUS_INSUFFICIENT_RESOURCES;
if (PRTL_PROCESS_MODULES prpm = (PRTL_PROCESS_MODULES)ExAllocatePool(PagedPool, cb))
{
if (0 <= (status = NtQuerySystemInformation(SystemModuleInformation, prpm, cb, &cb)))
{
do
{
PVOID Caller = *Callers++;
if (ULONG NumberOfModules = prpm->NumberOfModules)
{
PRTL_PROCESS_MODULE_INFORMATION Modules = prpm->Modules;
do
{
if ((SIZE_T)Caller - (SIZE_T)Modules->ImageBase < Modules->ImageSize)
{
DbgPrint("%p> %s\n", Caller, Modules->FullPathName);
break;
}
} while (Modules++, --NumberOfModules);
}
} while (--Count);
}
ExFreePool(prpm);
}
} while (status == STATUS_INFO_LENGTH_MISMATCH);
}

Related

HAL_FLASHEx_DATAEEPROM_Program hard fault

I use my function to write a string to the eeprom bank of the stm32l073.
Directly after the function HAL_FLASHEx_DATAEEPROM_Program will be called, the sytem goes into HardFault:
Debug Stack
The address i want to write is in the correct space 0x080803b4: MemoryMap
Do you see any problem in that process? I tried also to erase this WORD before write, but same problem with that write function.
HAL_StatusTypeDef eepromDrv_WriteWORD(uint32_t address, const uint32_t* pData, uint16_t dataLength)
{
bool bSuccess = true;
uint32_t ui32Addr = 0;
HAL_StatusTypeDef status = HAL_ERROR;
HAL_FLASHEx_DATAEEPROM_DisableFixedTimeProgram(); // Only Erase befor Write, when EEPROM_READ != DATA
HAL_FLASHEx_DATAEEPROM_Unlock();
for (ui32Addr=0;ui32Addr < dataLength; ui32Addr+=4,pData++)
{
if ((HAL_FLASHEx_DATAEEPROM_Program( FLASH_TYPEPROGRAMDATA_WORD, address + ui32Addr, *pData)) != HAL_OK)
{
bSuccess = false;
}
}
HAL_FLASHEx_DATAEEPROM_Lock();
if(true == bSuccess)
{
status = HAL_OK;
}
return status;
}

WINAPI determine if specific SCSI device is present

I'm currently trying to detect if a machine has a specific NVME SSD installed. On my machine, the file name is: SCSI#Disk&Ven_NVMe&Prod_XPG_SPECTRIX_S40#5&1363da6c&0&000000#{53f56307-b6bf-11d0-94f2-00a0c91efb8b}
What would be a reliable way to detect this universally on any machine? I don't know if any of these fields are unique to each machine, and I'm not very familiar with Windows' API.
when disk type hardware is detected, kernel create device for it (really 2 device usually PDO and FDO attached to it) and register well known interface GUID_DEVINTERFACE_DISK (by call IoRegisterDeviceInterface ). as result Symbolic Link will be created under \GLOBAL?? directory. we can got all registered disk interfaces via CM_Get_Device_Interface_ListW.
SCSI#Disk&Ven_NVMe&Prod_XPG_SPECTRIX_S40# obvious unique and will be the same anywhere for this device.
so code can be next
CONFIGRET Is_XPG_SPECTRIX_S40_Present(PBOOL pb)
{
CONFIGRET cr;
ULONG cb = 0, rcb;
union {
PVOID buf;
PZZWSTR Buffer;
};
static volatile UCHAR guz = 0;
PVOID stack = alloca(guz);
do
{
cr = CM_Get_Device_Interface_List_SizeW(&rcb, const_cast<GUID*>(&GUID_DEVINTERFACE_DISK), 0, CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
if (cr != CR_SUCCESS)
{
break;
}
if (cb < (rcb *= sizeof(WCHAR)))
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);// /RTCs must be off
}
cr = CM_Get_Device_Interface_ListW(const_cast<GUID*>(&GUID_DEVINTERFACE_DISK),
0, Buffer, cb, CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
} while (cr == CR_BUFFER_SMALL);
if (cr == CR_SUCCESS)
{
while (*Buffer)
{
if (wcsstr(Buffer, L"\\SCSI#Disk&Ven_NVMe&Prod_XPG_SPECTRIX_S40#"))
{
*pb = TRUE;
break;
}
Buffer += wcslen(Buffer) + 1;
}
}
return cr;
}

How to disable WOW64 file system redirection for GetModuleFileNameEx?

I'm running the following from a 32-bit process on a 64-bit Windows 10:
#ifndef _DEBUG
WCHAR buffPath[MAX_PATH] = {0};
FARPROC pfn = (FARPROC)::GetModuleHandleEx;
HMODULE hMod = NULL;
::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
(LPCTSTR)pfn, &hMod);
PVOID pOldVal = NULL;
if(::Wow64DisableWow64FsRedirection(&pOldVal))
{
::GetModuleFileNameEx(::GetCurrentProcess(), hMod, buffPath, _countof(buffPath));
::Wow64RevertWow64FsRedirection(pOldVal);
wprintf(L"Path=%s\n", buffPath);
}
#else
#error run_in_release_mode
#endif
and I'm expecting to receive the path as c:\windows\syswow64\KERNEL32.DLL, but it gives me:
Path=C:\Windows\System32\KERNEL32.DLL
Any idea why?
when we load dll via LoadLibrary[Ex] or LdrLoadDll - first some pre-process transmitted dll name (say convert api-* to actual dll name or redirect dll name based on manifest - well known example comctl32.dll) and then use this (possible modified) dll name to load file as dll. but wow fs redirection - not preprocessed at this stage. if dll was successfully loaded - system allocate LDR_DATA_TABLE_ENTRY structure and save transmitted (after pre-process) dll name here as is.
the GetModuleFileNameEx simply walk throughout LDR_DATA_TABLE_ENTRY double linked list and search entry where DllBase == hModule - if found - copy FullDllName to lpFilename (if buffer big enough). so it simply return dll path used during load dll. the Wow64DisableWow64FsRedirection have no any effect to this call.
if we want get real (canonical) full path to dll - need use GetMappedFileNameW or ZwQueryVirtualMemory with MemoryMappedFilenameInformation
so code can be (if we hope that MAX_PATH is enough)
WCHAR path[MAX_PATH];
GetMappedFileNameW(NtCurrentProcess(), hmod, path, RTL_NUMBER_OF(path));
or if use ntapi and correct handle any path length:
NTSTATUS GetDllName(PVOID AddressInDll, PUNICODE_STRING NtImageName)
{
NTSTATUS status;
union {
PVOID buf;
PUNICODE_STRING ImageName;
};
static volatile UCHAR guz;
PVOID stack = alloca(guz);
SIZE_T cb = 0, rcb = 0x200;
do
{
if (cb < rcb)
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
}
if (0 <= (status = ZwQueryVirtualMemory(NtCurrentProcess(), AddressInDll,
MemoryMappedFilenameInformation, buf, cb, &rcb)))
{
return RtlDuplicateUnicodeString(
RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
ImageName, NtImageName);
}
} while (status == STATUS_BUFFER_OVERFLOW);
return status;
}
UNICODE_STRING NtImageName;
if (0 <= GetDllName(hmod, &NtImageName))
{
RtlFreeUnicodeString(&NtImageName);
}
about question "way to convert it to the win32 form" - there is a counter question - for what ?
at first we can use it as is with NtOpenFile (well documented api), at second - the simplest way convert to win32 form, accepted by CreateFileW - add \\?\globalroot prefix to nt path. but not all win32 api (primary shell api) accept this form. if we want exactly dos-device form path (aka X:) need use IOCTL_MOUNTMGR_QUERY_POINTS - got the array of MOUNTMGR_MOUNT_POINT inside MOUNTMGR_MOUNT_POINTS structure and search for DeviceName which is prefix for our nt path and SymbolicLinkName have driver letter form. code can be ~
#include <mountmgr.h>
ULONG NtToDosPath(HANDLE hMM, PUNICODE_STRING ImageName, PWSTR* ppsz)
{
static MOUNTMGR_MOUNT_POINT MountPoint;
static volatile UCHAR guz;
PVOID stack = alloca(guz);
PMOUNTMGR_MOUNT_POINTS pmmp = 0;
DWORD cb = 0, rcb = 0x200, BytesReturned;
ULONG err = NOERROR;
do
{
if (cb < rcb) cb = RtlPointerToOffset(pmmp = (PMOUNTMGR_MOUNT_POINTS)alloca(rcb - cb), stack);
if (DeviceIoControl(hMM, IOCTL_MOUNTMGR_QUERY_POINTS,
&MountPoint, sizeof(MOUNTMGR_MOUNT_POINT),
pmmp, cb, &BytesReturned, 0))
{
if (ULONG NumberOfMountPoints = pmmp->NumberOfMountPoints)
{
PMOUNTMGR_MOUNT_POINT MountPoints = pmmp->MountPoints;
do
{
UNICODE_STRING SymbolicLinkName = {
MountPoints->SymbolicLinkNameLength,
SymbolicLinkName.Length,
(PWSTR)RtlOffsetToPointer(pmmp, MountPoints->SymbolicLinkNameOffset)
};
UNICODE_STRING DeviceName = {
MountPoints->DeviceNameLength,
DeviceName.Length,
(PWSTR)RtlOffsetToPointer(pmmp, MountPoints->DeviceNameOffset)
};
PWSTR FsPath;
if (RtlPrefixUnicodeString(&DeviceName, ImageName, TRUE) &&
DeviceName.Length < ImageName->Length &&
*(FsPath = (PWSTR)RtlOffsetToPointer(ImageName->Buffer, DeviceName.Length)) == '\\' &&
MOUNTMGR_IS_DRIVE_LETTER(&SymbolicLinkName))
{
cb = ImageName->Length - DeviceName.Length;
if (PWSTR psz = new WCHAR[3 + cb/sizeof(WCHAR)])
{
*ppsz = psz;
psz[0] = SymbolicLinkName.Buffer[12];
psz[1] = ':';
memcpy(psz + 2, FsPath, cb + sizeof(WCHAR));
return NOERROR;
}
return ERROR_NO_SYSTEM_RESOURCES;
}
} while (MountPoints++, --NumberOfMountPoints);
}
return ERROR_NOT_FOUND;
}
rcb = pmmp->Size;
} while ((err = GetLastError()) == ERROR_MORE_DATA);
return err;
}
ULONG NtToDosPath(PWSTR lpFilename, PWSTR* ppsz)
{
HANDLE hMM = CreateFile(MOUNTMGR_DOS_DEVICE_NAME, FILE_GENERIC_READ,
FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);
if (hMM == INVALID_HANDLE_VALUE)
{
return GetLastError();
}
UNICODE_STRING us;
RtlInitUnicodeString(&us, lpFilename);
ULONG err = NtToDosPath(hMM, &us, ppsz);
CloseHandle(hMM);
return err;
}
PWSTR psz;
if (NtToDosPath(path, &psz) == NOERROR)
{
DbgPrint("%S\n", psz);
delete [] psz;
}
also we can change in code to MOUNTMGR_IS_VOLUME_NAME(&SymbolicLinkName) for get volume (persistent) name form instead driver letter form

Hostapd - print wpa passphrase

It's possible to print wpa passphrase in hostapd (by editing the code)?
This is the conf of hostapd (we use TKIP) :
wpa=1
#wpa_psk=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
wpa_passphrase=passphrase
wpa_key_mgmt=WPA-PSK
wpa_pairwise=TKIP
In the file hostpad/src/ap/wpa_auth.c, we have lots of information about the connection :
SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
{
struct wpa_ptk PTK;
int ok = 0, psk_found = 0;
const u8 *pmk = NULL;
unsigned int pmk_len;
SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk);
sm->EAPOLKeyReceived = FALSE;
sm->update_snonce = FALSE;
/* WPA with IEEE 802.1X: use the derived PMK from EAP
* WPA-PSK: iterate through possible PSKs and select the one matching
* the packet */
for (;;) {
if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr,
sm->p2p_dev_addr, pmk);
if (pmk == NULL)
break;
psk_found = 1;
pmk_len = PMK_LEN;
} else {
pmk = sm->PMK;
pmk_len = sm->pmk_len;
}
wpa_derive_ptk(sm, sm->SNonce, pmk, pmk_len, &PTK);
if (wpa_verify_key_mic(sm->wpa_key_mgmt, &PTK,
sm->last_rx_eapol_key,
sm->last_rx_eapol_key_len) == 0) {
ok = 1;
break;
}
if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt))
break;
}
if (!ok) {
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
"invalid MIC in msg 2/4 of 4-Way Handshake");
if (psk_found)
wpa_auth_psk_failure_report(sm->wpa_auth, sm->addr);
return;
}
#ifdef CONFIG_IEEE80211R
// ....
#endif /* CONFIG_IEEE80211R */
sm->pending_1_of_4_timeout = 0;
eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm);
if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
/* PSK may have changed from the previous choice, so update
* state machine data based on whatever PSK was selected here.
*/
os_memcpy(sm->PMK, pmk, PMK_LEN);
sm->pmk_len = PMK_LEN;
}
sm->MICVerified = TRUE;
os_memcpy(&sm->PTK, &PTK, sizeof(PTK));
sm->PTK_valid = TRUE;
}
My knowledge in networks are limited, and I do not understand very well WPA protocol. There is an article interesting on the question here, but the situation is a little bit different because we are in the case of an attack "man in the middle".

Should I IUnknown::Release interfaces created with DllGetClassObject

I'm trying to debug some code that uses COM, which I am a beginner at.
The two calls to IUnknown::Release at the end have got me worried.
The interfaces were created with DllGetClassObject and IClassFactory::CreateInstance.
I have seen other similar code that does not call IUnknown::Release on these - which is correct?
int OpenMixer_Win_DirectSound(px_mixer *Px, int index)
{
DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_DATA desc;
HMODULE hDsound = INVALID_HANDLE_VALUE;
GCO DllGetClassObject;
IClassFactory *pcf = NULL;
IKsPropertySet *pps = NULL;
HRESULT hr;
ULONG bytes;
LPGUID guidIn;
LPGUID guidOut;
UINT deviceIn = -1;
UINT deviceOut = -1;
int ret = FALSE;
guidIn = PaWinDS_GetStreamInputGUID(Px->pa_stream);
guidOut = PaWinDS_GetStreamOutputGUID(Px->pa_stream);
do {
hDsound = LoadLibraryA("dsound.dll");
if (hDsound == NULL) {
break;
}
DllGetClassObject = (GCO) GetProcAddress(hDsound, "DllGetClassObject");
if (DllGetClassObject == NULL) {
break;
}
hr = DllGetClassObject(&CLSID_DirectSoundPrivate,
&IID_IClassFactory,
(void **)(&pcf));
if (hr || pcf == NULL) {
break;
}
hr = IClassFactory_CreateInstance(pcf,
NULL,
&IID_IKsPropertySet,
(void **)(&pps));
if (hr || pps == NULL) {
break;
}
/* Do stuff with the interfaces */
} while( FALSE );
if (pps) {
IUnknown_Release(pps);
}
if (pcf) {
IUnknown_Release(pcf);
}
// Free the library. Note that portaudio also opens dsound.dll
// so this probably doesn't do anything until Pa_Terminate is called.
if (hDsound != INVALID_HANDLE_VALUE) {
FreeLibrary(hDsound);
}
}
Absolutely. Both functions create a new interface pointer, they will have a reference count of 1, the AddRef() function was already called. When you're done with it then you have to call Release(). You'll leak memory if you don't. Every interface in COM works this way.
Yes. As seen in DllGetClassObject sample, the return ppvObj will have a refcount.
Yes, DllGetClassObject() will create an object and pass ownership of that object to your code. Your code will now own the object and be responsible for releasing it by calling IUnknown::Release().

Resources