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