std::pair<HRESULT, std::string> UnicodeStringStructToString(const ExtRemoteTyped &unicode_string) { std::string output_string = ""; try { ExtRemoteTyped loc_unicode_string = unicode_string; ExtRemoteTyped buffer = *loc_unicode_string.Field("Buffer"); uint16_t len = loc_unicode_string.Field("Length").GetUshort(); uint16_t maxlen = loc_unicode_string.Field("MaximumLength").GetUshort(); if ( len == 0 && maxlen == 1 ) { return std::make_pair(S_OK, output_string); } if ( maxlen >= sizeof(wchar_t) && (maxlen % sizeof(wchar_t) == 0) ) { uint16_t max_len_wide = maxlen / sizeof(wchar_t) + 1; std::unique_ptr<wchar_t[]> test_name(new wchar_t[max_len_wide]); std::memset(test_name.get(), 0, max_len_wide * sizeof(wchar_t)); uint32_t read = buffer.ReadBuffer(test_name.get(), maxlen, true); if ( read == maxlen ) output_string = wstring_to_string(test_name.get()); return std::make_pair(S_OK, output_string); } } catch ( const ExtRemoteException &Ex ) { std::stringstream locerr; locerr << wa::showminus << __FUNCTION__ << ": " << Ex.GetMessage() << wa::endlerr; return std::make_pair(Ex.GetStatus(), output_string); } return std::make_pair(E_INVALIDARG, output_string); }
vector<HANDLE_OBJECT> ObOpenObjectDirectory( _In_ ULONG64 InputObject ) /*++ Routine Description: Description. Arguments: InputObject - Return Value: vector<HANDLE_OBJECT>. --*/ { vector<HANDLE_OBJECT> Handles; HANDLE_OBJECT Handle = { 0 }; ExtRemoteTyped Directory; ULONG64 ObjectDir = InputObject; if (!ObjectDir) { ReadPointer(GetExpression("nt!ObpRootDirectoryObject"), &ObjectDir); } Directory = ExtRemoteTyped("(nt!_OBJECT_DIRECTORY *)@$extin", ObjectDir); ObReadObject(ObjectDir, &Handle); for (UINT i = 0; i < 37; i += 1) { ULONG64 Entry = Directory.Field("HashBuckets").ArrayElement(i).GetPointerTo().GetPtr(); if (!Entry) continue; // // ExtRemoteTypedList requires a POINTER to the first entry. Not the offset of the first entry. // ExtRemoteTypedList EntryList(Entry, "nt!_OBJECT_DIRECTORY_ENTRY", "ChainLink"); for (EntryList.StartHead(); EntryList.HasNode(); EntryList.Next()) { HANDLE_OBJECT Handle = {0}; ULONG64 Object = EntryList.GetTypedNode().Field("Object").GetPtr(); ObReadObject(Object, &Handle); Handles.push_back(Handle); } } return Handles; }
void WDbgArk::WalkDirectoryObject(const uint64_t directory_address, void* context, RemoteTypedCallback callback) { if ( !directory_address ) { err << wa::showminus << __FUNCTION__ << ": invalid directory address" << endlerr; return; } if ( !callback ) { err << wa::showminus << __FUNCTION__ << ": invalid callback address" << endlerr; return; } try { ExtRemoteTyped directory_object("nt!_OBJECT_DIRECTORY", directory_address, false, NULL, NULL); ExtRemoteTyped buckets = directory_object.Field("HashBuckets"); int64_t num_buckets = buckets.GetTypeSize() / m_PtrSize; for ( int64_t i = 0; i < num_buckets; i++ ) { for ( ExtRemoteTyped directory_entry = *buckets[i]; directory_entry.m_Offset; directory_entry = *directory_entry.Field("ChainLink") ) { ExtRemoteTyped object = *directory_entry.Field("Object"); if ( !SUCCEEDED(callback(this, object, context)) ) { err << wa::showminus << __FUNCTION__ << ": error while invoking callback" << endlerr; return; } } } } catch ( const ExtRemoteException &Ex ) { err << wa::showminus << __FUNCTION__ << ": " << Ex.GetMessage() << endlerr; } }
BOOLEAN ObReadObject( _In_ ULONG64 Object, _Out_ PHANDLE_OBJECT HandleObj ) /*++ Routine Description: Description. Arguments: Object - HandleObj - Return Value: BOOLEAN. --*/ { BOOLEAN Result = FALSE; LPWSTR ObjName = NULL; ULONG BodyOffset = 0; GetFieldOffset("nt!_OBJECT_HEADER", "Body", &BodyOffset); WCHAR TypeStr[64] = { 0 }; if ((!Object) || (!IsValid(Object))) return FALSE; if (!ObTypeInit) { ObjTypeTable = ExtRemoteTyped("(nt!_OBJECT_TYPE **)@$extin", GetExpression("nt!ObTypeIndexTable")); ObTypeInit = TRUE; } ULONG64 ObjHeaderAddr = Object - BodyOffset; if (!IsValid(ObjHeaderAddr)) return FALSE; ExtRemoteTyped ObjHeader("(nt!_OBJECT_HEADER *)@$extin", ObjHeaderAddr); HandleObj->ObjectPtr = Object; // ObjHeader.Field("Body").GetPointerTo().GetPtr(); if (ObjHeader.HasField("TypeIndex")) { HandleObj->ObjectTypeIndex = ObjHeader.Field("TypeIndex").GetChar(); if ((HandleObj->ObjectTypeIndex <= 1) || (HandleObj->ObjectTypeIndex >= 45)) return FALSE; ExtRemoteTypedEx::GetUnicodeString(ObjTypeTable.ArrayElement(HandleObj->ObjectTypeIndex).Field("Name"), TypeStr, sizeof(TypeStr)); wcscpy_s(HandleObj->Type, TypeStr); } else { if (!IsValid(ObjHeader.Field("Type").GetPtr())) goto CleanUp; ExtRemoteTypedEx::GetUnicodeString(ObjHeader.Field("Type").Field("Name"), TypeStr, sizeof(TypeStr)); wcscpy_s(HandleObj->Type, TypeStr); } if (_wcsicmp(TypeStr, L"File") == 0) { ExtRemoteTyped FileObject("(nt!_FILE_OBJECT *)@$extin", HandleObj->ObjectPtr); ObjName = ExtRemoteTypedEx::GetUnicodeString2(FileObject.Field("FileName")); } else if (_wcsicmp(TypeStr, L"Driver") == 0) { ExtRemoteTyped DrvObject("(nt!_DRIVER_OBJECT *)@$extin", HandleObj->ObjectPtr); ObjName = ExtRemoteTypedEx::GetUnicodeString2(DrvObject.Field("DriverName")); } else if (_wcsicmp(TypeStr, L"Process") == 0) { ExtRemoteTyped ProcessObj("(nt!_EPROCESS *)@$extin", HandleObj->ObjectPtr); ObjName = ExtRemoteTypedEx::GetUnicodeString2(ProcessObj.Field("ImageFileName")); } else if (_wcsicmp(TypeStr, L"ALPC Port") == 0) { // dt nt!_ALPC_PORT } else if (_wcsicmp(TypeStr, L"EtwRegistration") == 0) { // dt nt!_ETW_? } else if (_wcsicmp(TypeStr, L"Thread") == 0) { // dt nt!_ETHREAD } else if (_wcsicmp(TypeStr, L"Event") == 0) { // dt nt!_KTHREAD } else if (_wcsicmp(TypeStr, L"Key") == 0) { ExtRemoteTyped KeyObject("(nt!_CM_KEY_BODY *)@$extin", HandleObj->ObjectPtr); HandleObj->ObjectKcb = KeyObject.Field("KeyControlBlock").GetPtr(); ObjName = RegGetKeyName(KeyObject.Field("KeyControlBlock")); // dt nt!_CM_KEY_BODY -> nt!_CM_KEY_CONTROL_BLOCK } else { ULONG Offset = 0; UCHAR InfoMask = 0; if (ObjHeader.HasField("InfoMask")) { InfoMask = ObjHeader.Field("InfoMask").GetUchar(); if (InfoMask & OBP_NAME_INFO_BIT) { if (InfoMask & OBP_CREATOR_INFO_BIT) Offset += GetTypeSize("nt!_OBJECT_HEADER_CREATOR_INFO"); Offset += GetTypeSize("nt!_OBJECT_HEADER_NAME_INFO"); } } else { Offset = ObjHeader.Field("NameInfoOffset").GetUchar(); } if (Offset) { ExtRemoteTyped ObjNameInfo("(nt!_OBJECT_HEADER_NAME_INFO *)@$extin", ObjHeaderAddr - Offset); ObjName = ExtRemoteTypedEx::GetUnicodeString2(ObjNameInfo.Field("Name")); } } if (ObjName) { wcscpy_s(HandleObj->Name, ObjName); free(ObjName); ObjName = NULL; } Result = TRUE; CleanUp: return Result; }
BOOLEAN PEFile::InitImage( ) /*++ Routine Description: Description. Arguments: - Return Value: BOOLEAN. --*/ { PIMAGE_DOS_HEADER Header = NULL; PVOID Image = NULL; ULONG BytesRead = 0; ULONG64 BaseImageAddress = m_ImageBase; PIMAGE_NT_HEADERS32 NtHeader32 = NULL; PIMAGE_NT_HEADERS64 NtHeader64 = NULL; PIMAGE_DATA_DIRECTORY DataDirectory = NULL; ExtRemoteTyped BaseImage; BOOLEAN Result = FALSE; ULONG64 ProcessDataOffset = 0ULL; if (m_Image.Initialized) { // g_Ext->Dml("b_Initialized already set to TRUE\n"); Result = TRUE; goto CleanUp; } if (!m_ImageSize) { Header = (PIMAGE_DOS_HEADER)malloc(PAGE_SIZE); if (Header == NULL) goto CleanUp; RtlZeroMemory(Header, PAGE_SIZE); if (g_Ext->m_Data->ReadVirtual(BaseImageAddress, Header, PAGE_SIZE, &BytesRead) != S_OK) { #if VERBOSE_MODE g_Ext->Dml("Error: Can't read 0x%I64x bytes at %I64x.\n", PAGE_SIZE, BaseImageAddress); #endif goto CleanUp; } BaseImage = ExtRemoteTyped("(nt!_IMAGE_DOS_HEADER *)@$extin", BaseImageAddress); if (BaseImage.Field("e_magic").GetUshort() != IMAGE_DOS_SIGNATURE) goto CleanUp; NtHeader32 = (PIMAGE_NT_HEADERS32)((PUCHAR)Header + BaseImage.Field("e_lfanew").GetUlong()); if (NtHeader32->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) { m_ImageSize = NtHeader32->OptionalHeader.SizeOfImage; } else if (NtHeader32->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) { NtHeader64 = (PIMAGE_NT_HEADERS64)NtHeader32; NtHeader32 = NULL; m_ImageSize = NtHeader64->OptionalHeader.SizeOfImage;; } else { #if VERBOSE_MODE g_Ext->Dml("Error: Invalid signature.\n"); #endif goto CleanUp; } } Image = malloc(m_ImageSize); if (Image == NULL) goto CleanUp; RtlZeroMemory(Image, (ULONG)m_ImageSize); if (ExtRemoteTypedEx::ReadVirtual(BaseImageAddress, Image, (ULONG)m_ImageSize, &BytesRead) != S_OK) { #if VERBOSE_MODE g_Ext->Dml("Error: Can't read 0x%I64x bytes at %I64x.\n", m_ImageSize, BaseImageAddress); #endif goto CleanUp; } m_Image.Image = (PIMAGE_DOS_HEADER)Image; REF_POINTER(m_Image.Image); m_Image.NtHeader32 = (PIMAGE_NT_HEADERS32)((PUCHAR)Image + m_Image.Image->e_lfanew); NtHeader32 = m_Image.NtHeader32; if (NtHeader32->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) { m_Image.NtHeader32 = NULL; m_Image.NtHeader64 = (PIMAGE_NT_HEADERS64)((PUCHAR)Image + m_Image.Image->e_lfanew); m_Image.DataDirectory = (PIMAGE_DATA_DIRECTORY)m_Image.NtHeader64->OptionalHeader.DataDirectory; m_Image.Sections = (PIMAGE_SECTION_HEADER)(m_Image.NtHeader64 + 1); m_Image.NumberOfSections = m_Image.NtHeader64->FileHeader.NumberOfSections; } else if (NtHeader32->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) { m_Image.NtHeader64 = NULL; m_Image.DataDirectory = (PIMAGE_DATA_DIRECTORY)m_Image.NtHeader32->OptionalHeader.DataDirectory; m_Image.Sections = (PIMAGE_SECTION_HEADER)(m_Image.NtHeader32 + 1); m_Image.NumberOfSections = m_Image.NtHeader32->FileHeader.NumberOfSections; } else { goto CleanUp; } #if VERBOSE_MODE g_Ext->Dml("m_Image = %p\n" "m_NtHeader32 = %p\n" "m_DataDirectory = %p\n" "m_Sections = %p\n", m_Image.Image, m_Image.NtHeader32, m_Image.DataDirectory, m_Image.Sections); g_Ext->Dml("m_NumberOfSections = %x\n", m_Image.NumberOfSections); #endif Result = TRUE; CleanUp: if (Header) free(Header); m_Image.Initialized = Result; return Result; }
ExtRemoteTyped GetKeyNode( _In_ PWSTR FullKeyPath ) { ULONG64 CmpMasterHive; ULONG64 CmpRegistryRootObject; ExtRemoteTyped KeyNode; try { ReadPointer(CmpMasterHiveAddress, &CmpMasterHive); ReadPointer(CmpRegistryRootObjectAddress, &CmpRegistryRootObject); ExtRemoteTyped KeyHive("(nt!_HHIVE *)@$extin", CmpMasterHive); ExtRemoteTyped KeyBody("(nt!_CM_KEY_BODY *)@$extin", CmpRegistryRootObject); ExtRemoteTyped KeyControlBlock("(nt!_CM_KEY_CONTROL_BLOCK *)@$extin", KeyBody.Field("KeyControlBlock").GetPtr()); ULONG KeyCell = KeyControlBlock.Field("KeyCell").GetUlong(); KeyNode = ExtRemoteTyped("(nt!_CM_KEY_NODE *)@$extin", RegGetCellPaged(KeyHive, KeyCell)); vector<KEY_NAME> KeysNames = GetKeysNames(FullKeyPath); for (size_t i = 1; i < KeysNames.size(); i++) { BOOL IsFound = FALSE; vector<KEY_NODE> SubKeys = GetSubKeys(KeyHive, KeyNode); for (size_t j = 0; j < SubKeys.size(); j++) { if (0 == _wcsicmp(KeysNames[i].Name, SubKeys[j].Name)) { KeyNode = SubKeys[j].KeyNode; if (KeyNode.Field("Signature").GetUshort() == CM_LINK_NODE_SIGNATURE) { KeyHive = ExtRemoteTyped("(nt!_HHIVE *)@$extin", KeyNode.Field("ChildHiveReference.KeyHive").GetPtr()); KeyCell = KeyNode.Field("ChildHiveReference.KeyCell").GetUlong(); KeyNode = ExtRemoteTyped("(nt!_CM_KEY_NODE *)@$extin", RegGetCellPaged(KeyHive, KeyCell)); } IsFound = TRUE; break; } } if (!IsFound) { KeyNode = ExtRemoteTyped("(nt!_CM_KEY_NODE *)@$extin", NULL); break; } } } catch (...) { } return KeyNode; }
BOOLEAN ObReadObject( _In_ ULONG64 Object, _Out_ PHANDLE_OBJECT HandleObj ) /*++ Routine Description: Description. Arguments: Object - HandleObj - Return Value: BOOLEAN. --*/ { BOOLEAN Result = FALSE; PWSTR ObjectName = NULL; WCHAR TypeStr[64] = {0}; ULONG BodyOffset = 0; GetFieldOffset("nt!_OBJECT_HEADER", "Body", &BodyOffset); try { ZeroMemory(HandleObj, sizeof(HANDLE_OBJECT)); if ((!Object) || (!IsValid(Object))) return FALSE; if (!ObTypeInit) { ObjTypeTable = ExtRemoteTyped("(nt!_OBJECT_TYPE **)@$extin", ObTypeIndexTableAddress); ObTypeInit = TRUE; } ULONG64 ObjHeaderAddr = Object - BodyOffset; if (!IsValid(ObjHeaderAddr)) return FALSE; ExtRemoteTyped ObjHeader("(nt!_OBJECT_HEADER *)@$extin", ObjHeaderAddr); HandleObj->ObjectPtr = Object; // ObjHeader.Field("Body").GetPointerTo().GetPtr(); if (ObjHeader.HasField("TypeIndex")) { BYTE HeaderCookie; HandleObj->ObjectTypeIndex = ObjHeader.Field("TypeIndex").GetUchar(); if (g_Ext->m_Data->ReadVirtual(ObHeaderCookieAddress, &HeaderCookie, sizeof(HeaderCookie), NULL) == S_OK) { HandleObj->ObjectTypeIndex = (((ObjHeaderAddr >> 8) & 0xff) ^ HandleObj->ObjectTypeIndex) ^ HeaderCookie; } ExtRemoteTypedEx::GetUnicodeString(ObjTypeTable.ArrayElement(HandleObj->ObjectTypeIndex).Field("Name"), TypeStr, sizeof(TypeStr)); StringCchCopyW(HandleObj->Type, _countof(HandleObj->Type), TypeStr); }