Skip to content
This repository has been archived by the owner on Oct 18, 2020. It is now read-only.

Commit

Permalink
Fixed unicode/bytes bug in heap analysis code. (#327)
Browse files Browse the repository at this point in the history
Also added final solution to the miranda workshop into the tree so it
wont be lost.
  • Loading branch information
scudette authored Nov 28, 2017
1 parent d7ac568 commit 0378be3
Show file tree
Hide file tree
Showing 6 changed files with 194 additions and 4 deletions.
1 change: 1 addition & 0 deletions rekall-core/rekall/plugins/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from rekall.plugins import addrspaces
from rekall.plugins import common
from rekall.plugins import contrib
from rekall.plugins import core
from rekall.plugins import darwin
from rekall.plugins import filesystems
Expand Down
1 change: 1 addition & 0 deletions rekall-core/rekall/plugins/contrib/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from rekall.plugins.contrib import miranda
179 changes: 179 additions & 0 deletions rekall-core/rekall/plugins/contrib/miranda.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
"""This is a plugin written as part of the DFRWS 2015 workshop:
Forensic Reverse Engineering with Rekall Workshop:
http://www.rekall-forensic.com/a/rekall-innovations.com/rekall-innovations/ForensicReverseEngineeringwithRekall-Solutions.pdf
"""

from rekall import scan

from rekall_lib import utils
from rekall.plugins.overlays import basic
from rekall.plugins.windows import common


TYPES = {
"MESSAGE_RECORD": [0x50, {
"Message": [0, ["Pointer", dict(
target="UnicodeString"
)]],
"Sender": [8, ["Pointer", dict(
target="UnicodeString"
)]],

"Timestamp": [48, ["UnixTimeStamp"]],

"Prev": [64, ["Pointer", dict(
target="MESSAGE_RECORD"
)]],
"Next": [72, ["Pointer", dict(
target="MESSAGE_RECORD"
)]],
}],

"CHANNEL_RECORD": [0x50, {
"Protocol": [0x20, ["Pointer", dict(
target="String"
)]],
"Label": [0x28, ["Pointer", dict(
target="UnicodeString"
)]],
"Channel": [0x30, ["Pointer", dict(
target="UnicodeString"
)]],
"Welcome": [0x40, ["Pointer", dict(
target="UnicodeString"
)]],
"LastMessage": [0xc8, ["Pointer", dict(
target="MESSAGE_RECORD"
)]],

"FirstMessage": [0xd0, ["Pointer", dict(
target="MESSAGE_RECORD"
)]],

"FirstUser": [0xd8, ["Pointer", dict(
target="USER_RECORD"
)]],

"CurrentUser": [0xe0, ["Pointer", dict(
target="USER_RECORD"
)]],

"NextChannel": [0x108, ["Pointer", dict(
target="CHANNEL_RECORD"
)]],
}],

"CHAT_RECORD": [96, {
"ChatName": [0x30, ["Pointer", dict(
target="UnicodeString"
)]],
"Channel": [0x40, ["Pointer", dict(
target="CHANNEL_RECORD"
)]],
}],

"USER_RECORD": [0x28, {
"Nick": [0x00, ["Pointer", dict(
target="UnicodeString"
)]],
"NickID": [0x08, ["Pointer", dict(
target="UnicodeString"
)]],
"NextUser": [0x20, ["Pointer", dict(
target="USER_RECORD"
)]],
}],

"CHATS": [48, {
"Count": [0, ["unsigned int"]],
"Chats": [0x8, ["Pointer", dict(
target="Array",
target_args=dict(
target="Pointer",
count=lambda x: x.Count,
target_args=dict(
target="CHAT_RECORD"
)
)
)]],
}]
}


class MirandaProfile(basic.ProfileLLP64, basic.BasicClasses):
"""A basic profile for Miranda IM."""

@classmethod
def Initialize(cls, profile):
super(MirandaProfile, cls).Initialize(profile)
profile.add_overlay(TYPES)


class HeapScannerMixin(object):
def scan(self):
task = self.session.GetParameter("process_context")
for vad in task.RealVadRoot.traverse():
if vad.u.VadFlags.ProtectionEnum == "READWRITE":
# Only scan the VAD region.
for match in super(HeapScannerMixin, self).scan(
vad.Start, vad.Length):
yield match

class HeapScanner(HeapScannerMixin, scan.MultiStringScanner):
pass


class HeapPointerScanner(HeapScannerMixin, scan.PointerScanner):
pass


class Miranda(common.WindowsCommandPlugin):
name = "miranda"

def FindChannels(self):
scanner = HeapScanner(
session=self.session,
needles=[b"\xba\xba\xba\xabIRC_1\x00"])

irc_hits = []
for hit, _ in scanner.scan():
irc_hits.append(hit)

scanner = HeapPointerScanner(
session=self.session,
profile=self.session.profile, pointers=[x+4 for x in irc_hits])

for referrer in scanner.scan():
if self.session.default_address_space.read(
referrer - 0x24, 4) == b"\xba\xba\xba\xab":
yield self.miranda_profile.CHANNEL_RECORD(referrer - 0x20)

def render(self, renderer):
self.miranda_profile = MirandaProfile(session=self.session)
with self.session.plugins.cc(proc_regex="miranda") as cc:
cc.SwitchContext()

for channel in self.FindChannels():
# For each channel we start a new section.
renderer.section("Channel {0} {1:#x}".format(
channel.Channel, channel))

users = []
for x in channel.FirstUser.walk_list("NextUser", True):
users.append(utils.SmartUnicode(x.Nick.deref()))

renderer.table_header([("Users", "users", "120")])
renderer.table_row(",".join(users))

renderer.table_header([
("Timestamp", "timestamp", "30"),
("User", "user", "20"),
("Message", "message", "80"),
])

for message_record in channel.FirstMessage.walk_list("Next"):
renderer.table_row(
message_record.Timestamp,
message_record.Sender.deref(),
message_record.Message.deref())
3 changes: 3 additions & 0 deletions rekall-core/rekall/plugins/overlays/windows/heap.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ def __init__(self, **kwargs):
encoding = self.obj_context.get("Encoding")
if encoding:
heap_as = self.obj_context["HeapAS"]

self.obj_vm = addrspace.BufferAddressSpace(
session=self.obj_session,
base_offset=self.obj_offset,
Expand Down Expand Up @@ -257,3 +258,5 @@ def InitializeHeapProfile(profile):
_HEAP_ENTRY=_HEAP_ENTRY,
_HEAP_FREE_ENTRY=_HEAP_ENTRY,
)

return profile
5 changes: 3 additions & 2 deletions rekall-core/rekall/plugins/windows/heap_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

from rekall.plugins import core
from rekall.plugins.windows import common
from rekall.plugins.overlays.windows import heap as heap_module
from rekall_lib import utils


Expand Down Expand Up @@ -132,7 +133,7 @@ def GenerateHeaps(self):
if not ntdll_mod:
return

ntdll_prof = ntdll_mod.profile
ntdll_prof = heap_module.InitializeHeapProfile(ntdll_mod.profile)

# Set the ntdll profile on the _PEB member.
peb = task.m("Peb").cast(
Expand Down Expand Up @@ -426,7 +427,7 @@ def get_referrers(self, address, maxlen=None):
def render(self, renderer):
show_allocation = None

for hit in self.get_referrers(self.address):
for hit in self.get_referrers(self.plugin_args.address):
show_allocation = self.session.plugins.show_allocation(hit)
show_allocation.render(renderer)

Expand Down
9 changes: 7 additions & 2 deletions rekall-lib/rekall_lib/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -967,8 +967,13 @@ def issubclass(obj, cls): # pylint: disable=redefined-builtin

def XOR(string1, string2):
"""Returns string1 xor string2."""
return "".join(chr(my_ord(x) ^ my_ord(y))
for x, y in zip(string1, string2))
xored = [my_ord(x) ^ my_ord(y)
for x, y in zip(string1, string2)]

if six.PY3:
return bytes(xored)

return b"".join(chr(x) for x in xored)


def xrange(start, end, step=1):
Expand Down

0 comments on commit 0378be3

Please sign in to comment.