Skip to content

Commit e70c97c

Browse files
committed
Added symbol sample + SymbolDebugger
1 parent 5b210b5 commit e70c97c

8 files changed

Lines changed: 308 additions & 26 deletions

File tree

samples/debug/symbol_debugger.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import argparse
2+
import os
3+
4+
import windows
5+
import windows.debug
6+
import windows.test
7+
8+
9+
parser = argparse.ArgumentParser(prog=__file__, formatter_class=argparse.ArgumentDefaultsHelpFormatter)
10+
parser.add_argument('--dbghelp', help='The path of DBG help to use (default use env:PFW_DBGHELP_PATH)')
11+
args = parser.parse_args()
12+
print(args)
13+
14+
if args.dbghelp:
15+
symbols.set_dbghelp_path(args.dbghelp)
16+
else:
17+
if "PFW_DBGHELP_PATH" not in os.environ:
18+
print("Not dbghelp path given and no environ var 'PFW_DBGHELP_PATH' sample may fail")
19+
20+
21+
class MyInfoBP(windows.debug.Breakpoint):
22+
COUNT = 0
23+
def trigger(self, dbg, exc):
24+
cursym = dbg.current_resolver[exc.ExceptionRecord.ExceptionAddress]
25+
print("Breakpoint triggered at: {0}".format(cursym))
26+
print(repr(cursym))
27+
MyInfoBP.COUNT += 1
28+
if MyInfoBP.COUNT == 4:
29+
print("Quitting")
30+
dbg.current_process.exit()
31+
print("")
32+
33+
dbg = windows.debug.SymbolDebugger.debug(r"c:\windows\system32\notepad.exe")
34+
dbg.add_bp(MyInfoBP("kernelbase!CreateFileInternal+2"))
35+
dbg.add_bp(MyInfoBP("ntdll!LdrpInitializeProcess"))
36+
dbg.loop()
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import os
2+
import argparse
3+
4+
import windows
5+
import windows.test
6+
import windows.generated_def as gdef
7+
from windows.debug import symbols
8+
9+
10+
parser = argparse.ArgumentParser(prog=__file__, formatter_class=argparse.ArgumentDefaultsHelpFormatter)
11+
parser.add_argument('--dbghelp', help='The path of DBG help to use (default use env:PFW_DBGHELP_PATH)')
12+
args = parser.parse_args()
13+
print(args)
14+
15+
if args.dbghelp:
16+
symbols.set_dbghelp_path(args.dbghelp)
17+
else:
18+
if "PFW_DBGHELP_PATH" not in os.environ:
19+
print("Not dbghelp path given and no environ var 'PFW_DBGHELP_PATH' sample may fail")
20+
21+
22+
if windows.current_process.bitness == 32:
23+
target = windows.test.pop_proc_32()
24+
else:
25+
target = windows.test.pop_proc_64()
26+
27+
print("Target is {0}".format(target))
28+
sh = symbols.ProcessSymbolHandler(target)
29+
import time;time.sleep(0.1) # Just wait for the process initialisation
30+
sh.refresh() # Refresh symbol list (Only meaningful for ProcessSymbolHandler)
31+
32+
print("Some loaded modules are:".format())
33+
for sm in sh.modules[:3]:
34+
print(" * {0}".format(sm))
35+
36+
createserv = sh["advapi32!CreateServiceEx"]
37+
38+
print("")
39+
TEST_FUNCTION = "advapi32!CreateServiceEx"
40+
print("Resolving function <{0}>".format(TEST_FUNCTION))
41+
createserv = sh[TEST_FUNCTION]
42+
print("Symbol found !")
43+
print(" * __repr__: {0!r}".format(createserv))
44+
print(" * __str__: {0}".format(createserv))
45+
print(" * addr: {0:#x}".format(createserv.addr))
46+
print(" * name: {0}".format(createserv.name))
47+
print(" * fullname: {0}".format(createserv.fullname))
48+
print(" * module: {0}".format(createserv.module))
49+
50+
target.exit()

samples/debug/symbols/symsearch.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import argparse
2+
import os
3+
4+
import windows
5+
import windows.debug.symbols as symbols
6+
7+
8+
parser = argparse.ArgumentParser(prog=__file__, formatter_class=argparse.ArgumentDefaultsHelpFormatter)
9+
parser.add_argument('pattern')
10+
parser.add_argument('file', help="The PE file to load")
11+
parser.add_argument('--addr', type=lambda x: int(x, 0), default=0, help="The load address of the PE")
12+
parser.add_argument('--tag', type=lambda x: int(x, 0), default=0)
13+
parser.add_argument('--dbghelp', help='The path of DBG help to use (default use env:PFW_DBGHELP_PATH)')
14+
15+
args = parser.parse_args()
16+
if args.dbghelp:
17+
symbols.set_dbghelp_path(args.dbghelp)
18+
else:
19+
if "PFW_DBGHELP_PATH" not in os.environ:
20+
print("Not dbghelp path given and no environ var 'PFW_DBGHELP_PATH' sample may fail")
21+
22+
23+
sh = symbols.VirtualSymbolHandler()
24+
mod = sh.load_file(path=args.file, addr=args.addr)
25+
res = sh.search(args.pattern, mod=mod, tag=args.tag)
26+
print("{0} symbols found:".format(len(res)))
27+
for sym in res:
28+
print(" * {0!r}".format(sym))
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import os
2+
import windows
3+
import windows.generated_def as gdef
4+
from windows.debug import symbols
5+
import argparse
6+
7+
8+
parser = argparse.ArgumentParser(prog=__file__, formatter_class=argparse.ArgumentDefaultsHelpFormatter)
9+
parser.add_argument('--dbghelp', help='The path of DBG help to use (default use env:PFW_DBGHELP_PATH)')
10+
args = parser.parse_args()
11+
print(args)
12+
13+
if args.dbghelp:
14+
symbols.set_dbghelp_path(args.dbghelp)
15+
else:
16+
if "PFW_DBGHELP_PATH" not in os.environ:
17+
print("Not dbghelp path given and no environ var 'PFW_DBGHELP_PATH' sample may fail")
18+
19+
20+
symbols.engine.options = 0 # Disable defered load
21+
sh = symbols.VirtualSymbolHandler()
22+
23+
ntmod = sh.load_file(r"c:\windows\system32\ntdll.dll", addr=0x420000)
24+
25+
print("Ntdll module is: {0}".format(ntmod))
26+
print(" * name = {0}".format(ntmod.name))
27+
print(" * addr = {0:#x}".format(ntmod.addr))
28+
print(" * path = {0:}".format(ntmod.path))
29+
print(" * type = {0:}".format(ntmod.type))
30+
print(" * pdb = {0:}".format(ntmod.pdb))
31+
32+
print("")
33+
TEST_FUNCTION = "LdrLoadDll"
34+
print("Resolving function <{0}>".format(TEST_FUNCTION))
35+
loaddll = sh["ntdll!" + TEST_FUNCTION]
36+
print("Symbol found !")
37+
print(" * __repr__: {0!r}".format(loaddll))
38+
print(" * __str__: {0}".format(loaddll))
39+
print(" * addr: {0:#x}".format(loaddll.addr))
40+
print(" * name: {0}".format(loaddll.name))
41+
print(" * fullname: {0}".format(loaddll.fullname))
42+
print(" * module: {0}".format(loaddll.module))
43+
44+
print("")
45+
print("Loading kernelbase")
46+
kbasemod = sh.load_file(r"c:\windows\system32\kernelbase.dll", addr=0x1230000)
47+
print("Loaded modules are: {0}".format(sh.modules))
48+
LOOKUP_ADDR = 0x1231242
49+
print("Looking up address: {0:#x}".format(LOOKUP_ADDR))
50+
lookupsym = sh[LOOKUP_ADDR]
51+
print("Symbol resolved !")
52+
print(" * __repr__: {0!r}".format(lookupsym))
53+
print(" * __str__: {0}".format(lookupsym))
54+
print(" * start: {0:#x}".format(lookupsym.start))
55+
print(" * addr: {0:#x}".format(lookupsym.addr))
56+
print(" * displacement: {0:#x}".format(lookupsym.displacement))
57+
print(" * name: {0}".format(lookupsym.name))
58+
print(" * fullname: {0}".format(lookupsym.fullname))
59+
print(" * module: {0}".format(lookupsym.module))

windows/debug/debugger.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -771,6 +771,7 @@ def _handle_create_process(self, debug_event):
771771
self.breakpoints[self.current_process.pid] = {}
772772
self._memory_save[self.current_process.pid] = {}
773773
self._module_by_process[self.current_process.pid] = {}
774+
self._internal_on_create_process(create_process) # Allow hook for symbol-debugger
774775
self._update_debugger_state(debug_event)
775776
self._add_exe_to_module_list(create_process)
776777
self._setup_pending_breakpoints_new_process(self.current_process)
@@ -836,6 +837,9 @@ def _handle_exit_thread(self, debug_event):
836837
del self._breakpoint_to_reput[self.current_thread.tid]
837838
return retvalue
838839

840+
def _internal_on_create_process(self, create_process):
841+
return None
842+
839843
def _internal_on_load_dll(self, load_dll):
840844
return None
841845

windows/debug/symboldbg.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import windows
2+
import windows.generated_def as gdef
3+
from windows.pycompat import int_types
4+
5+
from . import Debugger
6+
from . import symbols
7+
8+
class SymbolDebugger(Debugger):
9+
"""A debugger using the symbol API (hence PDB) for name resolution.
10+
To use PDB, a correct version of dbghelp should be configured as well as ``_NT_SYMBOL_PATH``.
11+
(See :ref:`debug_symbols_module`)
12+
13+
This debugger add a ``current_resolver`` variable (A :class:`~windows.debug.symbols.ProcessSymbolHandler`) for the ``current_process``.
14+
"""
15+
def __init__(self, *args, **kwargs):
16+
super(SymbolDebugger, self).__init__(*args, **kwargs)
17+
self._resolvers = {}
18+
19+
def _internal_on_load_dll(self, load_dll):
20+
path = self._get_loaded_dll(load_dll)
21+
# Path is used instead of name for naming the module (and can be set to whatever if using file handle)
22+
x = self.current_resolver.load_module(load_dll.hFile, path=path, addr=load_dll.lpBaseOfDll)
23+
24+
def _internal_on_create_process(self, create_process):
25+
# Create and setup a symbol resolver for the new process
26+
resolver = symbols.ProcessSymbolHandler(self.current_process)
27+
self._resolvers[self.current_process.pid] = resolver
28+
self.current_resolver = resolver
29+
30+
def _update_debugger_state(self, debug_event):
31+
super(SymbolDebugger, self)._update_debugger_state(debug_event)
32+
self.current_resolver = self._resolvers[debug_event.dwProcessId]
33+
34+
def _resolve(self, addr, target):
35+
if isinstance(addr, int_types):
36+
return addr
37+
if "+" in addr:
38+
symbol, deplacement = addr.split("+", 1)
39+
deplacement = int(deplacement, 0)
40+
else:
41+
symbol = addr
42+
deplacement = 0
43+
try:
44+
return self.current_resolver[symbol].addr + deplacement
45+
except WindowsError as e:
46+
if not e.winerror in (gdef.ERROR_NOT_FOUND, gdef.ERROR_MOD_NOT_FOUND):
47+
raise
48+
return None

0 commit comments

Comments
 (0)