Skip to content

Commit

Permalink
initial working zer0m0n enabler dependency
Browse files Browse the repository at this point in the history
  • Loading branch information
jbremer committed Nov 13, 2017
1 parent 2dca2f4 commit d778b5f
Show file tree
Hide file tree
Showing 6 changed files with 186 additions and 0 deletions.
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
install_requires=[
"click==6.6",
"jinja2==2.9.6",
"pefile2==1.2.11",
"pyyaml==3.12",
"sqlalchemy==1.0.8",
],
Expand Down
Binary file added tests/files/ntoskrnl.0x4ce7951a.exe
Binary file not shown.
Binary file added tests/files/winload.0x4ce7929c.exe
Binary file not shown.
21 changes: 21 additions & 0 deletions tests/test_zer0m0n.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Copyright (C) 2017 Jurriaan Bremer.
# This file is part of VMCloak - http://www.vmcloak.org/.
# See the file 'docs/LICENSE.txt' for copying permission.

import hashlib

from vmcloak.dependencies.zer0m0n import Zer0m0n

def patch_file(method, filename):
blob = open("tests/files/%s" % filename, "rb").read()
return hashlib.md5(method(blob)).hexdigest()

def patch_winload(filename):
return patch_file(Zer0m0n().patch_winload, filename)

def patch_ntoskrnl(filename):
return patch_file(Zer0m0n().patch_ntoskrnl, filename)

def test_winload():
assert patch_winload("winload.0x4ce7929c.exe") == "8f53e6483ef8af4ffacf48bbeb5b8c56"
assert patch_ntoskrnl("ntoskrnl.0x4ce7951a.exe") == "d8b4c59189401cd87d72a0f361c441d5"
11 changes: 11 additions & 0 deletions vmcloak/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,13 @@ def execute(self, command, async=False):
else:
return self.post("/execute", command=command)

def execpy(self, filepath, async=False):
"""Execute a Python file."""
if async:
return self.post("/execpy", filepath=filepath, async="true")
else:
return self.post("/execpy", filepath=filepath)

def remove(self, path):
"""Remove a file or entire directory."""
self.post("/remove", path=path)
Expand Down Expand Up @@ -123,6 +130,10 @@ def upload(self, filepath, contents):
contents = io.StringIO(contents)
self.postfile("/store", {"file": contents}, filepath=filepath)

def retrieve(self, filepath):
"""Retrieve a file from the Agent."""
return self.post("/retrieve", filepath=filepath).content

def click(self, window_title, button_name):
"""Identify a window by its title and click one of its buttons."""
log.debug(
Expand Down
153 changes: 153 additions & 0 deletions vmcloak/dependencies/zer0m0n.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
# Copyright (C) 2017 Jurriaan Bremer.
# This file is part of VMCloak - http://www.vmcloak.org/.
# See the file 'docs/LICENSE.txt' for copying permission.

import logging
import pefile
import time

from vmcloak.abstract import Dependency

log = logging.getLogger(__name__)

class Zer0m0n(Dependency):
name = "zer0m0n"
recommended = True

# Disable ntoskrnl validation in winload.
winload = {
0x4ce7929c: 0x4bdc,
}

# Disable PatchGuard initialization.
ntoskrnl_pg = {
0x4ce7951a: 0x4d1568,
}

# Disable Driver Signature Enforcement (driver signing).
ntoskrnl_ci = {
0x4ce7951a: 0x36a8f0,
}

def patch_winload(self, blob):
pe1 = pefile.PE(data=blob, fast_load=True)
if pe1.FILE_HEADER.TimeDateStamp not in self.winload:
log.warning(
"Unsupported winload.exe: timestamp 0x%08x",
pe1.FILE_HEADER.TimeDateStamp
)
return

off = self.winload[pe1.FILE_HEADER.TimeDateStamp]
buf = blob[:off] + "\xb0\x01\xc3\x90" + blob[off+4:]

pe2 = pefile.PE(data=buf, fast_load=True)
pe2.OPTIONAL_HEADER.CheckSum = pe2.generate_checksum()

buf = pe2.write()

count = 0
for idx in xrange(len(blob)):
if blob[idx] != buf[idx]:
count += 1

if count > 8:
log.warning("Something went wrong rebuilding winload.exe!")
return
return buf

def patch_ntoskrnl(self, blob):
pe1 = pefile.PE(data=blob, fast_load=True)
if pe1.FILE_HEADER.TimeDateStamp not in self.ntoskrnl_pg:
log.warning(
"Unsupported ntoskrnl.exe: timestamp=0x%08x",
pe1.FILE_HEADER.TimeDateStamp
)
return

# Disable PatchGuard initialization.
off = self.ntoskrnl_pg[pe1.FILE_HEADER.TimeDateStamp]
buf = blob[:off] + "\x90\x90" + blob[off+2:]

# Always set g_CiEnabled to zero.
off = self.ntoskrnl_ci[pe1.FILE_HEADER.TimeDateStamp]
buf = buf[:off] + "\x00" + buf[off+1:]

pe2 = pefile.PE(data=buf, fast_load=True)
pe2.OPTIONAL_HEADER.CheckSum = pe2.generate_checksum()

buf = pe2.write()

count = 0
for idx in xrange(len(blob)):
if blob[idx] != buf[idx]:
count += 1

if count > 7:
log.warning("Something went wrong rebuilding ntoskrnl.exe!")
return
return buf

def new_bcd_entry(self):
# Due to a bug with pythonw.exe & Cuckoo Agent <= 0.8 we can't run the
# commands the way we want to (i.e., "stdin" should be set to
# subprocess.PIPE in subprocess calls too). Dirty workaround follows.
return """
import re
import subprocess
import sys
out = subprocess.check_output([
"C:\\\\Windows\\\\Sysnative\\\\bcdedit.exe",
"/copy", "{current}", "/d", "Secret",
], stdin=subprocess.PIPE, stderr=subprocess.PIPE)
guid = re.search("({[a-z0-9-]+})", out)
if not guid:
sys.exit("Error creating BCD entry: out=%r err=%r" % (out, err))
guid = guid.group(1)
subprocess.check_output([
"C:\\\\Windows\\\\Sysnative\\\\bcdedit.exe",
"/timeout", "10",
], stdin=subprocess.PIPE, stderr=subprocess.PIPE)
subprocess.check_output([
"C:\\\\Windows\\\\Sysnative\\\\bcdedit.exe",
"/set", guid, "nointegritychecks", "1",
], stdin=subprocess.PIPE, stderr=subprocess.PIPE)
subprocess.check_output([
"C:\\\\Windows\\\\Sysnative\\\\bcdedit.exe",
"/set", guid, "path", "\\\\Windows\\\\System32\\\\osloader.exe",
], stdin=subprocess.PIPE, stderr=subprocess.PIPE)
subprocess.check_output([
"C:\\\\Windows\\\\Sysnative\\\\bcdedit.exe",
"/set", guid, "kernel", "ntkrnlmp.exe",
], stdin=subprocess.PIPE, stderr=subprocess.PIPE)
subprocess.check_output([
"C:\\\\Windows\\\\Sysnative\\\\bcdedit.exe",
"/default", guid,
], stdin=subprocess.PIPE, stderr=subprocess.PIPE)
""".strip()

def run(self):
winload = self.a.retrieve("C:\\Windows\\Sysnative\\winload.exe")
winload = self.patch_winload(winload)
if not winload:
return
self.a.upload("C:\\Windows\\Sysnative\\osloader.exe", winload)

ntoskrnl = self.a.retrieve("C:\\Windows\\Sysnative\\ntoskrnl.exe")
ntoskrnl = self.patch_ntoskrnl(ntoskrnl)
if not ntoskrnl:
return
self.a.upload("C:\\Windows\\Sysnative\\ntkrnlmp.exe", ntoskrnl)

self.a.upload("C:\\pgdsepatch.py", self.new_bcd_entry())
self.a.execpy("C:\\pgdsepatch.py", True)
time.sleep(2)
self.a.remove("C:\\pgdsepatch.py")

0 comments on commit d778b5f

Please sign in to comment.