Package rekall :: Package plugins :: Package common :: Module profile_index_test
[frames] | no frames]

Source Code for Module rekall.plugins.common.profile_index_test

  1  """Tests for profile_index.""" 
  2   
  3  import logging 
  4  import unittest 
  5   
  6  from rekall import session 
  7  from rekall import testlib 
  8  from rekall.plugins.common import profile_index 
  9   
 10   
11 -class SymbolOffsetIndexTest(testlib.RekallBaseUnitTestCase):
12 - def setUp(self):
13 14 self.test_index_data = { 15 "$METADATA": 16 { 17 "ProfileClass": "SymbolOffsetIndex", 18 "Type": "SymbolOffsetIndex", 19 "Version": 1, 20 "BaseSymbol": "c", 21 }, 22 "$INDEX": 23 { 24 "$PROFILES": 25 { 26 "P1": { "LastModified": 12345 }, 27 "P1-1": { "LastModified": 12346 }, 28 "P3": { "LastModified": 12347 }, 29 }, 30 "$TRAITS": 31 { 32 "P1": 33 [ 34 [["a", -2]], 35 ], 36 "P1-1": 37 [ 38 [["a", -3]], 39 ], 40 "P3": 41 [ 42 [["d", 1]], 43 [["e", 4]] 44 ], 45 }, 46 "$HASHES": 47 { 48 } 49 } 50 } 51 52 self.profiles = [ 53 ("P1", { 54 "$CONSTANTS": 55 { 56 "a": 1, 57 "b": 2, 58 "c": 3 59 } 60 }), 61 ("P1-DUPLICATE", { # This is a duplicate profile 62 "$CONSTANTS": 63 { 64 "a": 1, 65 "b": 2, 66 "c": 3, 67 } 68 }), 69 ("P1-1", { # P1-1 simulates a slightly newer P1 profile 70 "$CONSTANTS": 71 { 72 "a": 1, 73 "b": 2, 74 "c": 4 75 } 76 }), 77 ("P3", { # P3 simulated a completely different profile 78 "$CONSTANTS": 79 { 80 "b": 3, 81 "c": 5, 82 "d": 6, 83 "e": 9 84 } 85 }), 86 ] 87 88 self.dummy_index = profile_index.SymbolOffsetIndex.LoadProfileFromData( 89 self.test_index_data, session=session.Session())
90
91 - def testHashingIsStable(self):
92 """Test that hashing the same profile twice leads to the same hash.""" 93 hash1 = profile_index.SymbolOffsetIndex.CalculateRawProfileHash( 94 self.profiles[0][1]) 95 hash2 = profile_index.SymbolOffsetIndex.CalculateRawProfileHash( 96 self.profiles[0][1]) 97 self.assertEqual(hash1, hash2)
98
100 # This emulates having parsed kallsyms 101 # We fake-find a "P1" profile on a live machine 102 symbols = self.profiles[0][1].get("$CONSTANTS") 103 104 profiles = self.dummy_index.LookupProfile(symbols) 105 self.assertEqual(len(profiles), 1) # Only 1 profile matches 106 self.assertEqual(profiles[0][0], "P1") # It's "P1" 107 self.assertEqual(profiles[0][1], 1) # And only 1 trait matched
108
110 # We're gonna SHIFT P1 by 0x20000, just like the Linux kernel does 111 profile = self.profiles[0][1] 112 symbols = dict([(i[0], i[1]+0x200000) 113 for i in profile["$CONSTANTS"].iteritems()]) 114 115 116 profiles = self.dummy_index.LookupProfile(symbols) 117 self.assertEqual(len(profiles), 1) # Only 1 profile matches 118 self.assertEqual(profiles[0][0], "P1") # It's "P1" 119 self.assertEqual(profiles[0][1], 1) # And only 1 trait matched
120
122 # We'll have at least 3 cases where profile matching will find new 123 # profiles: 124 # 1) No match. If no profile matches, this is clearly a new profile. 125 # 2) Partial match. A profile that only matches some traits is a new 126 # profile that clashes with a known profile in the repository. 127 # 3) Several matches. A profile that matches more than one profile in 128 # the index is a new profile that clashes with several profiles and 129 # affects the quality of the index. 130 # 131 # Additionally, there's a chance a new profile may remain undiscovered 132 # when it matches all traits of a currently known profile, yet is 133 # actually slightly different. 134 135 # Unknown profile. 136 symbols1 = { "x": 99, "c": 14} 137 profiles = self.dummy_index.LookupProfile(symbols1) 138 self.assertEqual(len(profiles), 0) 139 140 # Partial match 141 symbols2 = { "c": 5, "d": 6, "e": 20} 142 profiles = self.dummy_index.LookupProfile(symbols2) 143 self.assertEqual(len(profiles), 1) 144 145 # Only 1 out of 2 traits matches from P3 146 profile = profiles[0][0] 147 num_matched_traits = profiles[0][1] 148 total_traits = len(self.dummy_index.traits[profile]) 149 self.assertEqual(num_matched_traits, 1) 150 self.assertEqual(total_traits, 2) 151 152 # Several profile matches. 153 # a is at -2 from c (matching P1's trait) 154 # d is at +3 from c (matching one of P3's traits) 155 symbols3 = { "a": 3, "c": 5, "d": 6 } 156 profiles = self.dummy_index.LookupProfile(symbols3) 157 # More than 1 profile matches will mean this profile is new and that we 158 # need to recompute the index. 159 self.assertEqual(len(profiles), 2) 160 self.assertListEqual(sorted([p[0] for p in profiles]), 161 ["P1", "P3"])
162 163 164 if __name__ == '__main__': 165 logging.basicConfig(level=logging.DEBUG) 166 unittest.main() 167