Compare commits

38 Commits

Author SHA1 Message Date
corelanc0d3r 231ce6c061 mona load - change ACL on page after copying 2025-11-01 00:40:14 +01:00
corelanc0d3r 0da4627f64 make mona load default to EIP if no -a is given 2025-11-01 00:33:01 +01:00
corelanc0d3r ae842ceca2 add load function (windbg only) 2025-10-23 00:21:20 +02:00
corelanc0d3r 36f90104b5 add detection for page heap uninitialized pattern in dumpobj 2025-09-28 13:53:22 +02:00
corelanc0d3r e793209dd2 bump version number after merging PR 2025-07-13 10:17:58 +02:00
Peter Van Eeckhoutte 29f8e1a7a8 Merge pull request #78 from BitTheByte/patch-1
Fix Symbols Loading
2025-07-13 09:40:23 +02:00
Ahmed Ezzat 260a2a00cb Update mona.py
Fix Symbols Loading
2025-07-12 22:04:22 +03:00
corelanc0d3r 11d72aec9c self.log doesn't exist 2025-04-04 07:44:42 +02:00
corelanc0d3r ecbaed675b a bit of error handling and logging 2025-04-03 20:41:19 +02:00
corelanc0d3r 75ed430570 update toBP 2024-03-26 13:20:05 +01:00
corelanc0d3r 449402c242 fix output findmsp 2023-10-22 14:49:06 +02:00
corelanc0d3r 8330f9d4af add dll chracteristics flag to output 2023-08-25 08:11:35 +02:00
corelanc0d3r 96b493e9d3 it's only 16 bits 2023-08-24 11:18:20 +02:00
corelanc0d3r 5f99c5f502 this version should now correctly report CFG on 32bit binaries 2023-08-24 09:39:31 +02:00
corelanc0d3r 5c16fa5a95 oops 2023-08-18 18:35:36 +02:00
corelanc0d3r 4dd491f61d add initial support for CFG 2023-08-18 18:31:08 +02:00
Peter Van Eeckhoutte f4df5f4bd0 Merge pull request #64 from noraj/patch-1
fix rawsec badge
2023-01-12 09:37:57 +01:00
Alexandre ZANNI 2644ed1dcf fix rawsec badge 2023-01-11 22:38:51 +01:00
corelanc0d3r c19c74c862 remove reference to IRC from banner 2022-10-31 02:26:35 +01:00
corelanc0d3r aa192e13c0 stackpivot.txt output reverse order 2022-10-29 00:26:25 +02:00
corelanc0d3r 1a04075ab6 version bump 2022-10-29 00:07:18 +02:00
Peter Van Eeckhoutte 3dda20d41e Merge pull request #63 from dms1lva/master
fix pickup pointer
2022-10-29 09:05:16 +11:00
Dario Martins Silva 695114355f Merge branch 'master' of github.com:dms1lva/mona 2022-10-28 15:03:24 -07:00
Dario Martins Silva 6f5e04d2a8 fix pickup pointer 2022-10-28 15:02:47 -07:00
corelanc0d3r 497762cdbf don't create ROP chains don't won't work anyway 2022-10-28 23:26:13 +02:00
corelanc0d3r c592b02a5b version bump 2022-10-28 22:56:51 +02:00
Peter Van Eeckhoutte 36cbc25f3f Merge pull request #62 from dms1lva/master
fix returning bad gadgets (pop esp) bug
2022-10-29 07:54:56 +11:00
Dario Martins Silva 06cb11f1f9 clean up 2022-10-28 17:42:13 -03:00
Dario Martins Silva 2abf24b0f9 merge 2022-10-28 17:31:17 -03:00
Dario Martins Silva d6bf3f306d fix returning bad gadgets (pop esp) bug 2022-10-28 17:24:12 -03:00
corelanc0d3r b60f60b619 sigh 2022-10-28 07:32:21 +02:00
corelanc0d3r c761880b3c reverting some changes 2022-10-28 07:25:47 +02:00
corelanc0d3r 00f7c1122a no pop esp please 2022-10-28 06:28:28 +02:00
corelanc0d3r 6cad24fc30 create modules.txt file when running !mona modules 2022-10-28 05:36:33 +02:00
corelanc0d3r dc46be2968 fix issue https://github.com/corelan/mona/issues/60 2022-10-26 22:38:57 +02:00
corelanc0d3r 89182c1ba9 version bump 2022-10-09 17:57:01 +02:00
corelanc0d3r a94259fa5e version bump 2022-10-09 17:51:14 +02:00
Peter Van Eeckhoutte e65626351e Merge pull request #59 from corelan/revert-56-patch-1
Revert "refactoring code with For Else"
2022-10-09 17:47:31 +02:00
2 changed files with 268 additions and 85 deletions
+1 -1
View File
@@ -31,4 +31,4 @@ notes
-----
mona.py has been inventoried at Rawsec's CyberSecurity Inventory
[![Rawsec's CyberSecurity Inventory](https://inventory.rawsec.ml/img/badges/Rawsec-inventoried-FF5050_plastic.svg)](https://inventory.rawsec.ml/)
[![Rawsec's CyberSecurity Inventory](https://inventory.raw.pm/img/badges/Rawsec-inventoried-FF5050_plastic.svg)](https://inventory.raw.pm/)
+267 -84
View File
@@ -1,9 +1,12 @@
#!/usr/bin/env python2.7
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import print_function
"""
U{Corelan<https://www.corelan.be>}
Copyright (c) 2011-2021, Peter Van Eeckhoutte - Corelan Consulting bv
Copyright (c) 2011-2025, Peter Van Eeckhoutte - Corelan Consulting bv
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -27,13 +30,13 @@ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
$Revision: 616 $
$Id: mona.py 615 2021-09-04 08:29:00Z corelanc0d3r $
$Revision: 643 $
$Id: mona.py 643 2025-11-01 00:39:00Z corelanc0d3r $
"""
__VERSION__ = '2.0'
__REV__ = filter(str.isdigit, '$Revision: 616 $')
__REV__ = filter(str.isdigit, '$Revision: 643 $')
__IMM__ = '1.8'
__DEBUGGERAPP__ = ''
arch = 32
@@ -43,6 +46,7 @@ win7mode = False
# import debugger
# except:
# pass
try:
import immlib as dbglib
from immlib import LogBpHook
@@ -93,6 +97,7 @@ import itertools
import traceback
import pickle
import json
import math
from operator import itemgetter
from collections import defaultdict, namedtuple
@@ -161,14 +166,14 @@ if __DEBUGGERAPP__ == "WinDBG":
dbg.log("")
osver = dbg.getOsVersion()
if osver in ["6", "7", "8", "vista", "win7", "2008server", "win8", "win8.1", "win10"]:
if osver in ["6", "7", "8", "vista", "win7", "2008server", "win8", "win8.1", "win10", "win11"]:
win7mode = True
heapgranularity = 8
if arch == 64:
heapgranularity = 16
offset_categories = ["xp", "vista", "win7", "win8", "win10"]
offset_categories = ["xp", "vista", "win7", "win8", "win10", "win11"]
# offset = [x86,x64]
offsets = {
@@ -178,7 +183,10 @@ offsets = {
"win8" : [0x0d0,0x170],
"win10" : {
14393 : [0x0d4,0x178]
}
},
"win11" : {
14393 : [0x0d4,0x178]
}
},
"FrontEndHeapType" : {
"xp" : [0x586,0xae2],
@@ -186,7 +194,10 @@ offsets = {
"win8" : [0x0d6,0x17a],
"win10" : {
14393 : [0x0da,0x182]
}
},
"win11" : {
14393 : [0x0da,0x182]
}
},
"VirtualAllocdBlocks" : {
"xp" : [0x050,0x090],
@@ -2666,12 +2677,12 @@ class MnModule:
Class to access module properties
"""
def __init__(self, modulename):
#dbg.log("MnModule(%s)" % modulename)
modisaslr = True
modissafeseh = True
modrebased = True
modisnx = True
modisos = True
modiscfg = True
self.IAT = {}
self.EAT = {}
path = ""
@@ -2682,6 +2693,7 @@ class MnModule:
mcodesize = 0
mcodetop = 0
mentry = 0
mdllcharacteristics = 0
mversion = ""
self.internalname = modulename
if modulename != "":
@@ -2692,6 +2704,7 @@ class MnModule:
modrebased = getModuleProperty(modulename,"rebase")
modisnx = getModuleProperty(modulename,"nx")
modisos = getModuleProperty(modulename,"os")
modiscfg = getModuleProperty(modulename,"cfg")
path = getModuleProperty(modulename,"path")
mzbase = getModuleProperty(modulename,"base")
mzsize = getModuleProperty(modulename,"size")
@@ -2701,6 +2714,7 @@ class MnModule:
mcodebase = getModuleProperty(modulename,"codebase")
mcodesize = getModuleProperty(modulename,"codesize")
mcodetop = getModuleProperty(modulename,"codetop")
mdllcharacteristics = getModuleProperty(modulename, "dllcharacteristics")
else:
#gather info manually - this code should only get called from populateModuleInfo()
self.moduleobj = dbg.getModule(modulename)
@@ -2709,6 +2723,7 @@ class MnModule:
modisnx = True
modrebased = False
modisos = False
modiscfg = False
#if self.moduleobj == None:
# dbg.log("*** Error - self.moduleobj is None, key %s" % modulename, highlight=1)
mod = self.moduleobj
@@ -2720,7 +2735,7 @@ class MnModule:
mcodebase = mod.getCodebase()
mcodesize = mod.getCodesize()
mcodetop = mcodebase + mcodesize
mdllcharacteristics = 0
mversion=mversion.replace(", ",".")
mversionfields=mversion.split('(')
mversion=mversionfields[0].replace(" ","")
@@ -2767,15 +2782,27 @@ class MnModule:
else:
modissafeseh=False
# IMAGE_DLL_CHARACTERISTICS FIELD
# Sits at offset 0x5e in Optional Header
dll_characteristics_flags=struct.unpack('<H',dbg.readMemory(pebase+0x5e,2))[0]
mdllcharacteristics = dll_characteristics_flags
#dbg.log("%s: Flags: 0x%x" % (path, dll_characteristics_flags))
#aslr
if (flags&0x0040)==0: # 'IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE
if (dll_characteristics_flags&0x0040)==0:
modisaslr=False
#nx
if (flags&0x0100)==0:
modisnx=False
#cfg
if (dll_characteristics_flags&0x4000)==0:
modiscfg=False
else:
modiscfg=True
#rebase
if mzrebase != mzbase:
modrebased=True
else:
# should never be hit
#print "No module specified !!!"
@@ -2805,6 +2832,8 @@ class MnModule:
self.isNX = modisnx
self.isOS = modisos
self.isCFG = modiscfg
self.moduleKey = modulename
@@ -2825,6 +2854,8 @@ class MnModule:
self.moduleCodetop = mcodetop
self.moduleCodebase = mcodebase
self.moduleDllCharacteristics = mdllcharacteristics
@@ -2842,7 +2873,7 @@ class MnModule:
"""
outstring = ""
if self.moduleKey != "":
outstring = "[" + self.moduleKey + "] ASLR: " + str(self.isAslr) + ", Rebase: " + str(self.isRebase) + ", SafeSEH: " + str(self.isSafeSEH) + ", OS: " + str(self.isOS) + ", v" + self.moduleVersion + " (" + self.modulePath + ")"
outstring = "[" + self.moduleKey + "] ASLR: " + str(self.isAslr) + ", Rebase: " + str(self.isRebase) + ", SafeSEH: " + str(self.isSafeSEH) + ", CFG: " + str(self.isCFG) + ", OS: " + str(self.isOS) + ", v" + self.moduleVersion + " (" + self.modulePath + "), 0x%x" % self.moduleDllCharacteristics
else:
outstring = "[None]"
return outstring
@@ -2858,6 +2889,9 @@ class MnModule:
def isOS(self):
return self.isOS
def isCFG(self):
return self.isCFG
def isNX(self):
return self.isNX
@@ -2891,6 +2925,9 @@ class MnModule:
def moduleVersion(self):
return self.moduleVersion
def moduleDllCharacteristics(self):
return self.moduleDllCharacteristics
def isExcluded(self):
return self.isExcluded
@@ -2901,6 +2938,7 @@ class MnModule:
sequences.append(["call","\xff\x15"])
funccalls = searchInRange(sequences, self.moduleBase, self.moduleTop,criteria)
return funccalls
def getIAT(self):
IAT = {}
@@ -2908,7 +2946,7 @@ class MnModule:
dbg.logLines(" Getting IAT for %s." % (self.moduleKey))
try:
if not self.moduleKey in IATCache: # if len(self.IAT) == 0:
dbg.log(" Enumerating IAT")
dbg.log(" Enumerating IAT, method 1 (Symbols)")
try:
themod = dbg.getModule(self.moduleKey)
syms = themod.getSymbols()
@@ -2924,7 +2962,7 @@ class MnModule:
dbg.logLines(traceback.format_exc())
pass
# merge
dbg.log(" Enumerating IAT, method 2 (read strings)")
# find optional header
PEHeader_ref = self.moduleBase + 0x3c
PEHeader_location = self.moduleBase + struct.unpack('<L',dbg.readMemory(PEHeader_ref,4))[0]
@@ -2966,7 +3004,8 @@ class MnModule:
iatcnt += 1
if len(IAT) == 0:
#search method nr 2, not accurate, but will find *something*
#another search method, not accurate, but will find *something*
dbg.log(" Enumerating IAT, method 3 (getFunctionCalls)")
funccalls = self.getFunctionCalls()
for functype in funccalls:
for fptr in funccalls[functype]:
@@ -4858,6 +4897,10 @@ class MnPointer:
offset = addy - startaddy
locinfo = ["self","ptr to self+0x%08x" % offset,""]
return locinfo
if addy == 0xc0c0c0c0:
locinfo = ["self", "Uninitialized", addy]
return locinfo
ismapped = False
@@ -5324,7 +5367,7 @@ def searchInModule(sequences, name,criteria=[]):
module = dbg.getModule(name)
if(not module):
self.log("module %s not found" % name)
dbg.log("Module %s not found" % name)
return []
# get the base and end address of the module
@@ -5721,6 +5764,8 @@ def getModulesToQuery(criteria):
if ("os" in criteria) and ((not criteria["os"]) and thismod.isOS):
included = False
if ("nx" in criteria) and ((not criteria["nx"]) and thismod.isNX):
included = False
if ("cfg" in criteria) and ((not criteria["cfg"]) and thismod.isCFG):
included = False
else:
included = False
@@ -5818,28 +5863,37 @@ def populateModuleInfo():
allmodules=dbg.getAllModules()
curmod = ""
for key in allmodules.keys():
modinfo={}
thismod = MnModule(key)
if not thismod is None:
modinfo["path"] = thismod.modulePath
modinfo["base"] = thismod.moduleBase
modinfo["size"] = thismod.moduleSize
modinfo["top"] = thismod.moduleTop
modinfo["safeseh"] = thismod.isSafeSEH
modinfo["aslr"] = thismod.isAslr
modinfo["nx"] = thismod.isNX
modinfo["rebase"] = thismod.isRebase
modinfo["version"] = thismod.moduleVersion
modinfo["os"] = thismod.isOS
modinfo["name"] = key
modinfo["entry"] = thismod.moduleEntry
modinfo["codebase"] = thismod.moduleCodebase
modinfo["codesize"] = thismod.moduleCodesize
modinfo["codetop"] = thismod.moduleCodetop
g_modules[thismod.moduleKey] = modinfo
else:
try:
modinfo={}
thismod = MnModule(key)
if not thismod is None:
modinfo["path"] = thismod.modulePath
modinfo["base"] = thismod.moduleBase
modinfo["size"] = thismod.moduleSize
modinfo["top"] = thismod.moduleTop
modinfo["safeseh"] = thismod.isSafeSEH
modinfo["aslr"] = thismod.isAslr
modinfo["nx"] = thismod.isNX
modinfo["rebase"] = thismod.isRebase
modinfo["version"] = thismod.moduleVersion
modinfo["os"] = thismod.isOS
modinfo["cfg"] = thismod.isCFG
modinfo["name"] = key
modinfo["entry"] = thismod.moduleEntry
modinfo["codebase"] = thismod.moduleCodebase
modinfo["codesize"] = thismod.moduleCodesize
modinfo["codetop"] = thismod.moduleCodetop
modinfo["dllcharacteristics"] = thismod.moduleDllCharacteristics
g_modules[thismod.moduleKey] = modinfo
else:
if not silent:
dbg.log(" - Oops, potential issue with module %s, skipping module" % key)
except Exception as e:
if not silent:
dbg.log(" - Oops, potential issue with module %s, skipping module" % key)
dbg.log(" - Unable to create MnModule for '%s', skipping module" % key)
dbg.log("%s" % str(e))
continue
if not silent:
dbg.log(" - Done. Let's rock 'n roll.")
dbg.setStatusBar("")
@@ -5874,14 +5928,14 @@ def showModuleTable(logfile="", modules=[]):
thistable = ""
if len(g_modules) == 0:
populateModuleInfo()
thistable += "-----------------------------------------------------------------------------------------------------------------------------------------\n"
thistable += "----------------------------------------------------------------------------------------------------------------------------------------------\n"
thistable += " Module info :\n"
thistable += "-----------------------------------------------------------------------------------------------------------------------------------------\n"
thistable += "----------------------------------------------------------------------------------------------------------------------------------------------\n"
if arch == 32:
thistable += " Base | Top | Size | Rebase | SafeSEH | ASLR | NXCompat | OS Dll | Version, Modulename & Path\n"
thistable += " Base | Top | Size | Rebase | SafeSEH | ASLR | CFG | NXCompat | OS Dll | Version, Modulename & Path, DLLCharacteristics\n"
elif arch == 64:
thistable += " Base | Top | Size | Rebase | SafeSEH | ASLR | NXCompat | OS Dll | Version, Modulename & Path\n"
thistable += "-----------------------------------------------------------------------------------------------------------------------------------------\n"
thistable += " Base | Top | Size | Rebase | SafeSEH | ASLR | CFG | NXCompat | OS Dll | Version, Modulename & Path, DLLCharacteristics\n"
thistable += "----------------------------------------------------------------------------------------------------------------------------------------------\n"
for thismodule,modproperties in g_modules.iteritems():
if (len(modules) > 0 and modproperties["name"] in modules or len(logfile)>0):
@@ -5891,12 +5945,14 @@ def showModuleTable(logfile="", modules=[]):
size = toSize(str("0x" + toHex(modproperties["size"])),10)
safeseh = toSize(str(modproperties["safeseh"]),7)
aslr = toSize(str(modproperties["aslr"]),5)
cfg = toSize(str(modproperties["cfg"]),5)
nx = toSize(str(modproperties["nx"]),7)
isos = toSize(str(modproperties["os"]),7)
version = str(modproperties["version"])
path = str(modproperties["path"])
name = str(modproperties["name"])
thistable += " " + base + " | " + top + " | " + size + " | " + rebase +"| " +safeseh + " | " + aslr + " | " + nx + " | " + isos + "| " + version + " [" + name + "] (" + path + ")\n"
dllflag = "0x%x" % modproperties["dllcharacteristics"]
thistable += " " + base + " | " + top + " | " + size + " | " + rebase +"| " +safeseh + " | " + aslr + " | "+ cfg + " | " + nx + " | " + isos + "| " + version + " [" + name + "] (" + path + ") " + dllflag + "\n"
thistable += "-----------------------------------------------------------------------------------------------------------------------------------------\n"
tableinfo = thistable.split('\n')
if logfile == "":
@@ -5991,7 +6047,6 @@ def processResults(all_opcodes,logfile,thislog,specialcases = {},ptronly = False
dbg.log(" Found a total of %d pointers" % ptrcnt, highlight=1)
dbg.setStatusBar("Done. Found %d pointers" % ptrcnt)
def mergeOpcodes(all_opcodes,found_opcodes):
"""
merges two dictionaries together
@@ -6006,7 +6061,10 @@ def mergeOpcodes(all_opcodes,found_opcodes):
if found_opcodes:
for hf in found_opcodes:
if hf in all_opcodes:
all_opcodes[hf].update(found_opcodes[hf])
if isinstance(all_opcodes[hf], dict):
all_opcodes[hf].update(found_opcodes[hf])
else:
all_opcodes[hf] += found_opcodes[hf]
else:
all_opcodes[hf] = found_opcodes[hf]
return all_opcodes
@@ -6170,17 +6228,19 @@ def findROPFUNC(modulecriteria={},criteria={},searchfuncs=[]):
# found pointers to functions
# now query IATs
#dbg.log("%s" % modulecriteria)
# dbg.log("%s" % modulecriteria)
isrebased = False
for key in modulestosearch:
curmod = dbg.getModule(key)
#dbg.log("Searching in IAT of %s" % key)
dbg.log("Searching in IAT of %s" % key)
#is this module going to get rebase ?
themodule = MnModule(key)
isrebased = themodule.isRebase
if not silent:
dbg.log(" - Querying %s" % (key))
dbg.log(" - Querying %s" % (key))
dbg.log(" Enumerating IAT")
allfuncs = themodule.getIAT()
dbg.log(" Done enumerating IAT for %s" % key)
dbg.updateLog()
for fn in allfuncs:
thisfuncname = allfuncs[fn].lower()
@@ -6580,16 +6640,19 @@ def findROPGADGETS(modulecriteria={},criteria={},endings=[],maxoffset=40,depth=5
thislog = logfile.reset()
objprogressfile.write("Writing " + str(len(stackpivots)+len(stackpivots_safeseh))+" stackpivots with minimum offset " + str(pivotdistance)+" to file " + thislog,progressfile)
dbg.log("[+] Writing stackpivots to file " + thislog)
logfile.write("Stack pivots, minimum distance " + str(pivotdistance),thislog)
logfile.write("-------------------------------------",thislog)
logfile.write("Stack pivots, minimum distance " + str(pivotdistance) + ", in descending order",thislog)
logfile.write("------------------------------------------------------------------------------",thislog)
logfile.write("", thislog)
logfile.write("", thislog)
logfile.write("Non-SafeSEH protected pivots :",thislog)
logfile.write("------------------------------",thislog)
logfile.write("", thislog)
arrtowrite = ""
pivotcount = 0
try:
with open(thislog,"a") as fh:
arrtowrite = ""
stackpivots_index = sorted(stackpivots) # returns sorted keys as an array
stackpivots_index = sorted(stackpivots, reverse=True) # returns sorted keys as an array, in descending order
for sdist in stackpivots_index:
for spivot, schain in stackpivots[sdist]:
ptrx = MnPointer(spivot)
@@ -6603,13 +6666,19 @@ def findROPGADGETS(modulecriteria={},criteria={},endings=[],maxoffset=40,depth=5
pass
logfile.write("", thislog)
logfile.write("", thislog)
logfile.write("", thislog)
logfile.write("**********************************************************************************************************", thislog)
logfile.write("", thislog)
logfile.write("", thislog)
logfile.write("", thislog)
logfile.write("SafeSEH protected pivots :",thislog)
logfile.write("--------------------------",thislog)
logfile.write("", thislog)
arrtowrite = ""
try:
with open(thislog, "a") as fh:
arrtowrite = ""
stackpivots_safeseh_index = sorted(stackpivots_safeseh)
stackpivots_safeseh_index = sorted(stackpivots_safeseh, reverse=True)
for sdist in stackpivots_safeseh_index:
for spivot, schain in stackpivots_safeseh[sdist]:
ptrx = MnPointer(spivot)
@@ -8677,7 +8746,7 @@ def createRopChains(suggestions,interestinggadgets,allgadgets,modulecriteria,cri
routinedefs["VirtualAlloc"] = virtualalloc
# only run these on older systems
osver=dbg.getOsVersion()
if not (osver == "6" or osver == "7" or osver == "8" or osver == "vista" or osver == "win7" or osver == "2008server" or osver == "win8" or osver == "win8.1" or osver == "win10"):
if not (osver == "6" or osver == "7" or osver == "8" or osver == "10" or osver == "11" or osver == "vista" or osver == "win7" or osver == "2008server" or osver == "win8" or osver == "win8.1" or osver == "win10"):
routinedefs["SetInformationProcess"] = setinformationprocess
routinedefs["SetProcessDEPPolicy"] = setprocessdeppolicy
@@ -9656,7 +9725,7 @@ def getRopFuncPtr(apiname,modulecriteria,criteria,mode, objprogressfile, progres
#first look for good one
objprogressfile.write(" * Ropfunc - Found %d pointers" % len(ropfuncs), progressfile)
for ropfunctypes in ropfuncs:
#dbg.log("Ropfunc - %s %s" % (ropfunctypes, rfuncsearch))
dbg.log("Ropfunc - %s %s" % (ropfunctypes, rfuncsearch))
if ropfunctypes.lower().find(rfuncsearch) > -1 and ropfunctypes.lower().find("rebased") == -1:
ropfuncptr = ropfuncs[ropfunctypes][0]
break
@@ -9686,20 +9755,20 @@ def getRopFuncPtr(apiname,modulecriteria,criteria,mode, objprogressfile, progres
break
#still haven't found ? clear out modulecriteria, include ASLR/rebase modules (but not OS modules)
if (ropfuncptr == 0) and not selectedmodules:
objprogressfile.write(" * Ropfunc - Still no results, now going to search in all application modules", progressfile)
oldsilent = silent
silent = True
limitedmodulecriteria = {}
# search in anything except known OS modules - bad idea anyway
limitedmodulecriteria["os"] = False
ropfuncs2,ropfuncoffsets2 = findROPFUNC(limitedmodulecriteria,criteria)
silent = oldsilent
for ropfunctypes in ropfuncs2:
if ropfunctypes.lower().find(rfuncsearch) > -1 and ropfunctypes.lower().find("rebased") == -1:
ropfuncptr = ropfuncs2[ropfunctypes][0]
ropfunctext += " (skipped module criteria, check if pointer is reliable !)"
break
#if (ropfuncptr == 0) and not selectedmodules:
# objprogressfile.write(" * Ropfunc - Still no results, now going to search in all application modules", progressfile)
# oldsilent = silent
# silent = True
# limitedmodulecriteria = {}
# # search in anything except known OS modules - bad idea anyway
# limitedmodulecriteria["os"] = False
# ropfuncs2,ropfuncoffsets2 = findROPFUNC(limitedmodulecriteria,criteria)
# silent = oldsilent
# for ropfunctypes in ropfuncs2:
# if ropfunctypes.lower().find(rfuncsearch) > -1 and ropfunctypes.lower().find("rebased") == -1:
# ropfuncptr = ropfuncs2[ropfunctypes][0]
# ropfunctext += " (skipped module criteria, check if pointer is reliable !)"
# break
if ropfuncptr == 0:
ropfunctext = "[-] Unable to find ptr to &" + apiname+"()"
@@ -10515,10 +10584,17 @@ def isGadgetEnding(instruction,endings,verbosity=False):
def getRopSuggestion(ropchains,allchains):
suggestions={}
arch_aware_regs = dbglib.Registers32BitsOrder[:] if arch == 32 else dbglib.Registers64BitsOrder[:]
if arch == 32:
arch_aware_regs = dbglib.Registers32BitsOrder[:]
arch_aware_regs.remove('ESP')
else:
arch_aware_regs = dbglib.Registers64BitsOrder[:]
arch_aware_regs.remove('RSP')
regs = dbglib.Registers32BitsOrder[:]
regs.remove('ESP')
if arch == 64:
regs.extend(dbglib.Registers64BitsOrder)
regs.remove('RSP')
# pushad
# ======================
@@ -10559,9 +10635,9 @@ def getRopSuggestion(ropchains,allchains):
for r in arch_aware_regs:
for r2 in arch_aware_regs:
pickup_allowed = ["NOP","RETN ","INC ","DEC ","OR ","XOR ","MOV ","LEA ","ADD ","SUB ","POP","ADC ","FPATAN", "TEST ", "CMP "]
pickup_target = ["MOV "+r+","+PTR_SIZE_DIRECTIVE+" SS:["+r2+"+", "MOV "+r+","+PTR_SIZE_DIRECTIVE+" DS:["+r2+"+"]
pickup_allowed.append("MOV "+r+","+PTR_SIZE_DIRECTIVE+" SS:["+r2+"+")
pickup_allowed.append("MOV "+r+","+PTR_SIZE_DIRECTIVE+" DS:["+r2+"+")
pickup_target = ["MOV "+r+","+PTR_SIZE_DIRECTIVE+" SS:["+r2+"]", "MOV "+r+","+PTR_SIZE_DIRECTIVE+" DS:["+r2+"]"]
pickup_allowed.append("MOV "+r+","+PTR_SIZE_DIRECTIVE+" SS:["+r2+"]")
pickup_allowed.append("MOV "+r+","+PTR_SIZE_DIRECTIVE+" DS:["+r2+"]")
pickup_notallowed = ["POP "+r, "MOV "+r+",E", "LEA "+r+",E", "MOV ESP", "XOR ESP", "LEA ESP", "MOV DWORD PTR", "DEC ESP"]
if arch == 64:
pickup_notallowed.extend(["MOV RSP", "XOR RSP", "LEA RSP", "DEC RSP", "MOV QWORD PTR"])
@@ -11052,6 +11128,7 @@ def goFindMSP(distance = 0,args = {}):
#2. registers overwritten ?
if not silent:
dbg.log("[+] Examining registers")
tofile += "\n[+] Examining registers\n"
registers = {}
registers_to = {}
for reg in regs:
@@ -11145,7 +11222,7 @@ def goFindMSP(distance = 0,args = {}):
seh = {}
if not silent:
dbg.log("[+] Examining SEH chain")
tofile += "[+] Examining SEH chain\r\n"
tofile += "\n[+] Examining SEH chain\n"
thissehchain=dbg.getSehChain()
for chainentry in thissehchain:
@@ -11209,7 +11286,7 @@ def goFindMSP(distance = 0,args = {}):
else:
extratxt = "(+- "+str(distance)+" bytes)"
dbg.log("[+] Examining stack %s - looking for cyclic pattern" % extratxt)
tofile += "[+] Examining stack %s - looking for cyclic pattern\n" % extratxt
tofile += "\n[+] Examining stack %s - looking for cyclic pattern\n" % extratxt
# get stack this address belongs to
stacks = getStacks()
@@ -11310,7 +11387,7 @@ def goFindMSP(distance = 0,args = {}):
else:
extratxt = "(+- "+str(distance)+" bytes)"
dbg.log("[+] Examining stack %s - looking for pointers to cyclic pattern" % extratxt)
tofile += "[+] Examining stack %s - looking for pointers to cyclic pattern\n" % extratxt
tofile += "\n[+] Examining stack %s - looking for pointers to cyclic pattern\n" % extratxt
# get stack this address belongs to
stacks = getStacks()
thisstackbase = 0
@@ -11732,7 +11809,7 @@ def main(args):
bannertext += " | _____ ___ ____ ____ ____ _ |\n"
bannertext += " | / __ `__ \/ __ \/ __ \/ __ `/ https://www.corelan.be |\n"
bannertext += " | / / / / / / /_/ / / / / /_/ / https://www.corelan-training.com|\n"
bannertext += " | /_/ /_/ /_/\____/_/ /_/\__,_/ #corelan (Freenode IRC) |\n"
bannertext += " | /_/ /_/ /_/\____/_/ /_/\__,_/ |\n"
bannertext += " | |\n"
bannertext += " |------------------------------------------------------------------|\n"
banners[2] = bannertext
@@ -12030,6 +12107,9 @@ def main(args):
modulecriteria,criteria = args2criteria(args,modulecriteria,criteria)
modulestosearch = getModulesToQuery(modulecriteria)
showModuleTable("",modulestosearch)
logfile = MnLog("modules.txt")
thislog = logfile.reset()
# ----- ROP ----- #
def procFindROPFUNC(args):
@@ -15841,6 +15921,102 @@ def main(args):
return
def procLoad(args):
# checks the args
# file ok?
inputfile = ""
argspresent = False
stopnow = False
if "f" in args:
argspresent = True
if argspresent:
# target is an address or a register?
targetloc = "0x0"
if "a" in args:
if type(args["a"]).__name__.lower() != "bool":
targetloc = args["a"]
else:
targetloc = "EIP"
regs = dbg.getRegs()
targetlocupper = targetloc.upper()
if targetlocupper in regs:
targetloc = "0x" + toHex(regs[targetlocupper])
if type(args["f"]).__name__.lower() != "bool":
inputfile = args["f"]
if inputfile == "":
dbg.log("Missing argument -f <source filename>",highlight=1)
stopnow = True
if stopnow:
return
inputfile = inputfile.replace("'","").replace('"',"")
content = ""
try:
file = open(inputfile,"rb")
content = file.read()
file.close()
except:
dbg.log("Unable to read file %s" % inputfile,highlight=1)
return
dbg.log("[+] Read %d bytes from %s" % (len(content),inputfile))
dbg.log("[+] Attempting to write contents of file to %s" % targetloc)
batch_size = 16
#dbg.writeMemory doesn't work reliably
# so let's do it the dirty way
addr = int(targetloc, 0)
if sys.version_info[0] < 3:
bytes_list = [ord(c) for c in content]
else:
bytes_list = list(content)
total_len = len(content)
log_every = True
num_batches = int(math.ceil(float(total_len) / batch_size))
for batch_idx in range(num_batches):
start = batch_idx * batch_size
end = min(start + batch_size, total_len)
slice_bytes = bytes_list[start:end]
cur_addr = addr + start
addr_hex = "0x%X" % cur_addr
# format bytes as two-digit hex without 0x, separated by spaces
byte_tokens = " ".join("%02X" % (b & 0xFF) for b in slice_bytes)
# build command: eb 0xADDR <b1> <b2> ...
cmd = "eb %s %s" % (addr_hex, byte_tokens)
try:
dbg.nativeCommand(cmd)
except Exception as e:
dbg.log("Failed to run: %s (error: %s)" % (cmd, e), highlight=1)
return False
# optional progress logging
if log_every and ((batch_idx + 1) % log_every == 0 or batch_idx == num_batches - 1):
written = end
dbg.log("[+] Progress: wrote %d / %d bytes" % (written, total_len))
dbg.log("[+] Finished writing %d bytes to 0x%X" % (total_len, addr))
# let's make that location RWX to be sure
dbg.rVirtualProtect(addr,1,0x40)
dbg.log("[+] Changed ACL to RWX")
dbg.log("[+] Done.")
return
def procFillChunk(args):
@@ -18313,30 +18489,30 @@ def main(args):
if "[" in ipart:
regsyntax += ipart.replace("[","").replace("]","")
regsyntax += ": 0x%08x, "
regsyntax += ": 0x%p, "
argsyntax += "%s," % ipart.replace("[","").replace("]","")
regsyntax += ipart
regsyntax += ": 0x%08x, "
regsyntax += ": 0x%p, "
argsyntax += "%s," % ipart.replace("[","poi(").replace("]",")")
iparttxt = ipart.replace("[","").replace("]","")
dmpsyntax += ".echo;.echo %s:;dds %s L 0x24/4;" % (iparttxt,iparttxt)
dmpsyntax += ".echo;.echo %s:;dps %s L 0x24/4;" % (iparttxt,iparttxt)
else:
regsyntax += ipart
regsyntax += ": 0x%08x, "
regsyntax += ": 0x%p, "
argsyntax += "%s," % ipart
argsyntax = argsyntax.strip(",")
regsyntax = regsyntax.strip(", ")
regsyntax += '\\",%s;' % argsyntax
if "CALL" in instruction.upper():
dmpsyntax += '.echo;.printf \\"Stack (esp: 0x%08x):\\",esp;.echo;dds esp L 0x4;'
dmpsyntax += '.echo;.printf \\"Stack (esp: 0x%p):\\",esp;.echo;dps esp L 0x4;'
if instruction.upper().startswith("RET"):
dmpsyntax += '.echo;.printf \\"EAX: 0x%08x, Ret To: 0x%08x, Arg1: 0x%08x, Arg2: 0x%08x, Arg3: 0x%08x, Arg4: 0x%08x\\",eax,poi(esp),poi(esp+4),poi(esp+8),poi(esp+c),poi(esp+10);'
dmpsyntax += '.echo;.printf \\"EAX: 0x%p, Ret To: 0x%p, Arg1: 0x%p, Arg2: 0x%p, Arg3: 0x%p, Arg4: 0x%p\\",eax,poi(esp),poi(esp+4),poi(esp+8),poi(esp+c),poi(esp+10);'
bpsyntax = locsyntax + ' ".echo ---------------;u eip L 1;' + regsyntax + dmpsyntax + ".echo;g" + '"'
filename = "logbps.txt"
@@ -19055,6 +19231,12 @@ Arguments:
-save : save current state to disk
-diff : compare current state with previously saved state"""
loadUsage = """Read the contents from a file and write to a memory location
Arguments:
-f : Full path to the file to read
-a : address (or register) to write to"""
commands["seh"] = MnCommand("seh", "Find pointers to assist with SEH overwrite exploits",sehUsage, procFindSEH)
commands["config"] = MnCommand("config","Manage configuration file (mona.ini)",configUsage,procConfig,"conf")
@@ -19110,6 +19292,7 @@ Arguments:
commands["allocmem"] = MnCommand("allocmem","Allocate some memory in the process",allocmemUsage,procAllocMem,"alloc")
commands["tobp"] = MnCommand("tobp","Generate WinDBG syntax to create a logging breakpoint at given location",tobpUsage,procToBp,"2bp")
commands["flow"] = MnCommand("flow","Simulate execution flows, including all branch combinations",flowUsage,procFlow,"flw")
commands["load"] = MnCommand("load","Copy bytes from file to a memory location",loadUsage,procLoad)
#commands["diffheap"] = MnCommand("diffheap", "Compare current heap layout with previously saved state", diffheapUsage, procDiffHeap, "dh")
commands["fwptr"] = MnCommand("fwptr", "Find Writeable Pointers that get called", fwptrUsage, procFwptr, "fwp")
commands["sehchain"] = MnCommand("sehchain","Show the current SEH chain",sehchainUsage,procSehChain,"exchain")