/// <summary> /// Find VAD that describes target address /// </summary> /// <param name="pProcess">Target process object</param> /// <param name="address">Address to find</param> /// <param name="pResult">Found VAD. NULL if not found</param> /// <returns>Status code</returns> NTSTATUS BBFindVAD( IN PEPROCESS pProcess, IN ULONG_PTR address, OUT PMMVAD_SHORT* pResult ) { NTSTATUS status = STATUS_SUCCESS; ULONG_PTR vpnStart = address >> PAGE_SHIFT; ASSERT( pProcess != NULL && pResult != NULL ); if (pProcess == NULL || pResult == NULL) return STATUS_INVALID_PARAMETER; if (dynData.VadRoot == 0) { DPRINT( "BlackBone: %s: Invalid VadRoot offset\n", __FUNCTION__ ); status = STATUS_INVALID_ADDRESS; } PMM_AVL_TABLE pTable = (PMM_AVL_TABLE)((PUCHAR)pProcess + dynData.VadRoot); PMM_AVL_NODE pNode = GET_VAD_ROOT( pTable ); // Search VAD if (MiFindNodeOrParent( pTable, vpnStart, &pNode ) == TableFoundNode) { *pResult = (PMMVAD_SHORT)pNode; } else { DPRINT( "BlackBone: %s: VAD entry for address 0x%p not found\n", __FUNCTION__, address ); status = STATUS_NOT_FOUND; } return status; }
VOID MiInsertNode ( IN PMMADDRESS_NODE NodeToInsert, IN PMM_AVL_TABLE Table ) /*++ Routine Description: This function inserts a new element in a table. Arguments: NodeToInsert - The initialized address node to insert. Table - Pointer to the table in which to insert the new node. Return Value: None. Environment: Kernel mode. The PFN lock is held for some of the tables. --*/ { // // Holds a pointer to the node in the table or what would be the // parent of the node. // PMMADDRESS_NODE NodeOrParent; TABLE_SEARCH_RESULT SearchResult; SearchResult = MiFindNodeOrParent (Table, (ULONG_PTR)((PMMVAD_SHORT)NodeToInsert)->StartingVpn, &NodeOrParent); // // The node wasn't in the (possibly empty) tree. // // We just check that the table isn't getting too big. // NodeToInsert->LeftChild = NULL; NodeToInsert->RightChild = NULL; Table->NumberGenericTableElements += 1; // // Insert the new node in the tree. // if (SearchResult == TableEmptyTree) { Table->BalancedRoot.RightChild = NodeToInsert; NodeToInsert->u1.Parent = &Table->BalancedRoot; Table->DepthOfTree = 1; } else { PMMADDRESS_NODE R = NodeToInsert; PMMADDRESS_NODE S = NodeOrParent; if (SearchResult == TableInsertAsLeft) { NodeOrParent->LeftChild = NodeToInsert; } else { NodeOrParent->RightChild = NodeToInsert; } NodeToInsert->u1.Parent = NodeOrParent; // // The above completes the standard binary tree insertion, which // happens to correspond to steps A1-A5 of Knuth's "balanced tree // search and insertion" algorithm. Now comes the time to adjust // balance factors and possibly do a single or double rotation as // in steps A6-A10. // // Set the Balance factor in the root to a convenient value // to simplify loop control. // COUNT_BALANCE_MAX ((SCHAR)-1); Table->BalancedRoot.u1.Balance = (ULONG_PTR) -1; // // Now loop to adjust balance factors and see if any balance operations // must be performed, using NodeOrParent to ascend the tree. // for(;;) { SCHAR a; // // Calculate the next adjustment. // a = 1; if (MiIsLeftChild (R)) { a = -1; } // // If this node was balanced, show that it is no longer and // keep looping. This is essentially A6 of Knuth's algorithm, // where he updates all of the intermediate nodes on the // insertion path which previously had balance factors of 0. // We are looping up the tree via Parent pointers rather than // down the tree as in Knuth. // if (S->u1.Balance == 0) { COUNT_BALANCE_MAX ((SCHAR)a); S->u1.Balance = a; R = S; S = SANITIZE_PARENT_NODE (S->u1.Parent); } else if ((SCHAR) S->u1.Balance != a) { // // If this node has the opposite balance, then the tree got // more balanced (or we hit the root) and we are done. // // Step A7.ii // S->u1.Balance = 0; // // If S is actually the root, then this means the depth // of the tree just increased by 1! (This is essentially // A7.i, but we just initialized the root balance to force // it through here.) // if (Table->BalancedRoot.u1.Balance == 0) { Table->DepthOfTree += 1; } break; } else { // // The tree became unbalanced (path length differs // by 2 below us) and we need to do one of the balancing // operations, and then we are done. The RebalanceNode routine // does steps A7.iii, A8 and A9. // MiRebalanceNode (S); break; } } } // // Sanity check tree size and depth. // return; }