diff --git a/ctypes_generation/definitions/functions/symbols.txt b/ctypes_generation/definitions/functions/symbols.txt index bf94cc1..d982ec2 100644 --- a/ctypes_generation/definitions/functions/symbols.txt +++ b/ctypes_generation/definitions/functions/symbols.txt @@ -29,6 +29,13 @@ BOOL WINAPI SymFromAddr( _Inout_ PSYMBOL_INFO Symbol ); +BOOL WINAPI SymFromAddrW( + [in] HANDLE hProcess, + [in] DWORD64 Address, + [out, optional] PDWORD64 Displacement, + [in, out] PSYMBOL_INFOW Symbol +); + BOOL WINAPI SymGetModuleInfo64( _In_ HANDLE hProcess, @@ -48,6 +55,12 @@ BOOL WINAPI SymInitialize( _In_ BOOL fInvadeProcess ); +BOOL WINAPI SymInitializeW( + [in] HANDLE hProcess, + [in, optional] PCWSTR UserSearchPath, + [in] BOOL fInvadeProcess +); + BOOL WINAPI SymFromName( _In_ HANDLE hProcess, _In_ LPCSTR Name, @@ -117,6 +130,12 @@ BOOL WINAPI SymEnumerateModules64( _In_ PVOID UserContext ); +BOOL WINAPI SymEnumerateModulesW64( + [in] HANDLE hProcess, + [in] PSYM_ENUMMODULES_CALLBACKW64 EnumModulesCallback, + [in, optional] PVOID UserContext +); + BOOL SymNext( HANDLE hProcess, PSYMBOL_INFO si diff --git a/ctypes_generation/definitions/simple_types.txt b/ctypes_generation/definitions/simple_types.txt index 2b160aa..e41e41b 100644 --- a/ctypes_generation/definitions/simple_types.txt +++ b/ctypes_generation/definitions/simple_types.txt @@ -240,6 +240,7 @@ PTRANSLATE_ADDRESS_ROUTINE64 = PVOID # StackWalk PSYMBOL_REGISTERED_CALLBACK64 = PVOID # Symbols PSYMBOL_REGISTERED_CALLBACK = PVOID # Symbols PSYM_ENUMPROCESSES_CALLBACK = PVOID # Symbols +PSYM_ENUMMODULES_CALLBACKW64 = PVOID # Symbols ENUMRESNAMEPROCA = PVOID # Resources ENUMRESNAMEPROCW = PVOID # Resources ENUMRESTYPEPROCA = PVOID # Resources diff --git a/tests/test_symbol.py b/tests/test_symbol.py index 13778ce..b993367 100644 --- a/tests/test_symbol.py +++ b/tests/test_symbol.py @@ -13,9 +13,32 @@ def symctx(): # symbols.engine.options = gdef.SYMOPT_UNDNAME def test_symbols_loadfile(symctx): - mod = symctx.load_file(path=r"c:\windows\system32\ntdll.dll", addr=0x42000) + mod = symctx.load_file(path=u"c:\\windows\\system32\\ntdll.dll", addr=0x42000) assert mod.addr == 0x42000 # Resolve by name - createfile = symctx[b"ntdll!NtCreateFile"] + createfile = symctx[u"ntdll!NtCreateFile"] # Resolve by addr - assert symctx[createfile.addr].name in (b"NtCreateFile", b"ZwCreateFile") \ No newline at end of file + assert symctx[createfile.addr].name in (u"NtCreateFile", u"ZwCreateFile") + + +def test_symbols_module_info(symctx): + mod = symctx.load_file(path=u"c:\\windows\\system32\\ntdll.dll", addr=0x42000) + assert mod.name == u"ntdll" # SymGetModuleInfo64 + assert symctx.modules[0].name == u"ntdll" # SymEnumerateModules64 + +def test_symbols_search(symctx): + mod = symctx.load_file(path=u"c:\\windows\\system32\\ntdll.dll", addr=0x42000) + res = symctx.search(u"ntdll!*CreateFile") + assert set(s.name for s in res) == {"NtCreateFile", "ZwCreateFile"} + + +def test_symbols(symctx): + mod = symctx.load_file(path=u"c:\\windows\\system32\\ntdll.dll", addr=0x42000) + createfile = symctx[u"ntdll!NtCreateFile"] + res = symctx.get_symbols(int(createfile)) + assert set(s.name for s in res) == {"NtCreateFile", "ZwCreateFile"} + print("LOL") + +# TO test: + +# SymbolInfoBase / SymbolType / get_type \ No newline at end of file diff --git a/windows/debug/symbols.py b/windows/debug/symbols.py index aa63107..c34b664 100644 --- a/windows/debug/symbols.py +++ b/windows/debug/symbols.py @@ -22,7 +22,7 @@ def set_dbghelp_path(path): """ loaded_modules = [m.name.lower() for m in windows.current_process.peb.modules] if os.path.isdir(path): - path = os.path.join(path, str(windows.current_process.bitness), "dbghelp.dll") + path = os.path.join(path, str(windows.current_process.bitness), u"dbghelp.dll") if "dbghelp.dll" in loaded_modules: raise ValueError("setup_dbghelp_path should be called before any dbghelp function") # Change the DLL used by DbgHelpProxy @@ -31,7 +31,7 @@ def set_dbghelp_path(path): # Load symbol config from ENV if present try: - env_dbghelp_path = os.environ["PFW_DBGHELP_PATH"] + env_dbghelp_path = windows.system.environ["PFW_DBGHELP_PATH"] # Setup the dbghelp path used by PFW set_dbghelp_path(env_dbghelp_path) except KeyError as e: @@ -65,7 +65,12 @@ class SymbolInfoBase(object): return None size = self.NameLen addr = ctypes.addressof(self) + type(self).Name.offset - return (self.CHAR_TYPE * size).from_address(addr)[:] + # self.NameLen should not include the final \x00 + # But some W api (like SymSearchW) returns SYMBOL_INFOW with the leading \x00 + # For NtCreateFile: + # A() API -> NameLen == 12 + # W() API -> NameLen == 13 + return (self.CHAR_TYPE * size).from_address(addr)[:].strip(u"\x00") @property def fullname(self): @@ -117,6 +122,9 @@ class SymbolInfoBase(object): class SymbolInfoA(gdef.SYMBOL_INFO, SymbolInfoBase): + CHAR_TYPE = gdef.CHAR + +class SymbolInfoW(gdef.SYMBOL_INFOW, SymbolInfoBase): """Represent a Symbol. This class in based on the class `SYMBOL_INFO `_ with the handling on displacement embeded into it.s @@ -128,7 +136,7 @@ class SymbolInfoA(gdef.SYMBOL_INFO, SymbolInfoBase): >>> sym1 = sh["kernelbase!CreateFileW"] >>> sym2 = sh[int(sym1) + 3] >>> sym2 - + >>> hex(sym2.start) '0x100f20b0L' >>> hex(sym2.addr) @@ -138,13 +146,10 @@ class SymbolInfoA(gdef.SYMBOL_INFO, SymbolInfoBase): >>> str(sym2) 'kernelbase!CreateFileW+0x3' """ - CHAR_TYPE = gdef.CHAR - -class SymbolInfoW(gdef.SYMBOL_INFOW, SymbolInfoBase): CHAR_TYPE = gdef.WCHAR -# We use the A Api in our code (for now) -SymbolInfo = SymbolInfoA +# Unicode everywhere ! +SymbolInfo = SymbolInfoW class SymbolType(object): def __init__(self, typeid, modbase, resolver): @@ -243,9 +248,9 @@ class SymbolType(object): return '<{0} name="{1}" tag={2}>'.format(type(self).__name__, self.name, self.tag) -class SymbolModule(gdef.IMAGEHLP_MODULE64): +class SymbolModule(gdef.IMAGEHLP_MODULEW64): """Represent a loaded symbol module - (see `MSDN IMAGEHLP_MODULE64 `_) + (see `MSDN _IMAGEHLP_MODULEW64 `_) .. note:: @@ -307,7 +312,7 @@ class SymbolModule(gdef.IMAGEHLP_MODULE64): return LoadedPdbName def __repr__(self): - pdb_basename = self.LoadedPdbName.split(b"\\")[-1] + pdb_basename = self.LoadedPdbName.split("\\")[-1] return '<{0} name="{1}" type={2} pdb="{3}" addr={4:#x}>'.format(type(self).__name__, self.name, self.type.value.name, pdb_basename, self.addr) @@ -322,7 +327,7 @@ class SymbolHandler(object): self.handle = handle #: The handle of the symbol handler if not engine.options_already_setup: engine.set_options(DEFAULT_DBG_OPTION) - winproxy.SymInitialize(handle, search_path, invade_process) + winproxy.SymInitializeW(handle, search_path, invade_process) def load_module(self, file_handle=None, path=None, name=None, addr=0, size=0, data=None, flags=0): @@ -350,10 +355,8 @@ class SymbolHandler(object): path = name except Exception as e: pass - # Expect a-string - path = windows.pycompat.raw_encode(path) try: - load_addr = winproxy.SymLoadModuleEx(self.handle, file_handle, path, name, addr, size, data, flags) + load_addr = winproxy.SymLoadModuleExW(self.handle, file_handle, path, name, addr, size, data, flags) except WindowsError as e: # if e.winerror == 0: # Already loaded ? @@ -375,7 +378,7 @@ class SymbolHandler(object): @staticmethod - @ctypes.WINFUNCTYPE(gdef.BOOL, gdef.PCSTR, gdef.DWORD64, ctypes.py_object) + @ctypes.WINFUNCTYPE(gdef.BOOL, gdef.PVOID, gdef.DWORD64, ctypes.py_object) def modules_aggregator(modname, modaddr, ctx): ctx.append(modaddr) return True @@ -387,14 +390,14 @@ class SymbolHandler(object): :return: [:class:`SymbolModule`] -- A list of modules """ res = [] - windows.winproxy.SymEnumerateModules64(self.handle, self.modules_aggregator, res) + windows.winproxy.SymEnumerateModulesW64(self.handle, self.modules_aggregator, res) return [self.get_module(addr) for addr in res] def get_module(self, base): modinfo = SymbolModule(self) modinfo.SizeOfStruct = ctypes.sizeof(modinfo) - winproxy.SymGetModuleInfo64(self.handle, base, modinfo) + winproxy.SymGetModuleInfoW64(self.handle, base, modinfo) return modinfo def symbol_and_displacement_from_address(self, addr): @@ -405,7 +408,7 @@ class SymbolHandler(object): sym = buff[0] sym.SizeOfStruct = ctypes.sizeof(SymbolInfo) sym.MaxNameLen = max_len_size - winproxy.SymFromAddr(self.handle, addr, displacement, buff) # SymFromAddrW ? + winproxy.SymFromAddrW(self.handle, addr, displacement, buff) sym.resolver = self sym.displacement = displacement.value return sym @@ -418,9 +421,7 @@ class SymbolHandler(object): sym = buff[0] sym.SizeOfStruct = ctypes.sizeof(SymbolInfo) sym.MaxNameLen = max_len_size - # Expect a-string - name = windows.pycompat.raw_encode(name) - windows.winproxy.SymFromName(self.handle, name, buff) + windows.winproxy.SymFromNameW(self.handle, name, buff) sym.resolver = self sym.displacement = 0 return sym @@ -468,7 +469,7 @@ class SymbolHandler(object): @ctypes.WINFUNCTYPE(gdef.BOOL, ctypes.POINTER(SymbolInfo), gdef.ULONG , ctypes.py_object) def simple_aggregator(info, size, ctx): sym = info[0] - fullsize = sym.SizeOfStruct + sym.NameLen + fullsize = sym.SizeOfStruct + (sym.NameLen * ctypes.sizeof(SymbolInfo.CHAR_TYPE)) cpy = windows.utils.BUFFER(SymbolInfo)(size=fullsize) ctypes.memmove(cpy, info, fullsize) ctx.append(cpy[0]) @@ -482,9 +483,9 @@ class SymbolHandler(object): >>> sh = windows.debug.symbols.VirtualSymbolHandler() >>> mod = sh.load_file(r"c:\windows\system32\kernelbase.dll") >>> sh.search("kernelbase!CreateFile*") - [, - , - , + [, + , + , ...] """ res = [] @@ -494,9 +495,7 @@ class SymbolHandler(object): callback = ctypes.WINFUNCTYPE(gdef.BOOL, ctypes.POINTER(SymbolInfo), gdef.ULONG , ctypes.py_object)(callback) addr = getattr(mod, "addr", mod) # Retrieve mod.addr, else us the value directly - # Expect A-string - mask = windows.pycompat.raw_encode(mask) - windows.winproxy.SymSearch(self.handle, gdef.DWORD64(addr), 0, tag, mask, 0, callback, res, options) + windows.winproxy.SymSearchW(self.handle, gdef.DWORD64(addr), 0, tag, mask, 0, callback, res, options) for sym in res: sym.resolver = self sym.displacement = 0 @@ -509,7 +508,7 @@ class SymbolHandler(object): else: callback = ctypes.WINFUNCTYPE(gdef.BOOL, ctypes.POINTER(SymbolInfo), gdef.ULONG , ctypes.py_object)(callback) try: - windows.winproxy.SymEnumSymbolsForAddr(self.handle, addr, callback, res) + windows.winproxy.SymEnumSymbolsForAddrW(self.handle, addr, callback, res) except WindowsError as e: if e.winerror == gdef.ERROR_MOD_NOT_FOUND: return [] @@ -610,9 +609,6 @@ class StackWalker(object): - - - class VirtualSymbolHandler(SymbolHandler): """A SymbolHandler where its handle is not a valid process handle Allow to create/resolve symbol in a 'virtual' process diff --git a/windows/generated_def/winfuncs.py b/windows/generated_def/winfuncs.py index 7fa3607..c3f2eb6 100644 --- a/windows/generated_def/winfuncs.py +++ b/windows/generated_def/winfuncs.py @@ -2440,6 +2440,11 @@ SymLoadModuleExWParams = ((1, 'hProcess'), (1, 'hFile'), (1, 'ImageName'), (1, ' SymFromAddrPrototype = WINFUNCTYPE(BOOL, HANDLE, DWORD64, PDWORD64, PSYMBOL_INFO) SymFromAddrParams = ((1, 'hProcess'), (1, 'Address'), (1, 'Displacement'), (1, 'Symbol')) +#def SymFromAddrW(hProcess, Address, Displacement, Symbol): +# return SymFromAddrW.ctypes_function(hProcess, Address, Displacement, Symbol) +SymFromAddrWPrototype = WINFUNCTYPE(BOOL, HANDLE, DWORD64, PDWORD64, PSYMBOL_INFOW) +SymFromAddrWParams = ((1, 'hProcess'), (1, 'Address'), (1, 'Displacement'), (1, 'Symbol')) + #def SymGetModuleInfo64(hProcess, dwAddr, ModuleInfo): # return SymGetModuleInfo64.ctypes_function(hProcess, dwAddr, ModuleInfo) SymGetModuleInfo64Prototype = WINFUNCTYPE(BOOL, HANDLE, DWORD64, PIMAGEHLP_MODULE64) @@ -2455,6 +2460,11 @@ SymGetModuleInfoW64Params = ((1, 'hProcess'), (1, 'qwAddr'), (1, 'ModuleInfo')) SymInitializePrototype = WINFUNCTYPE(BOOL, HANDLE, LPCSTR, BOOL) SymInitializeParams = ((1, 'hProcess'), (1, 'UserSearchPath'), (1, 'fInvadeProcess')) +#def SymInitializeW(hProcess, UserSearchPath, fInvadeProcess): +# return SymInitializeW.ctypes_function(hProcess, UserSearchPath, fInvadeProcess) +SymInitializeWPrototype = WINFUNCTYPE(BOOL, HANDLE, PCWSTR, BOOL) +SymInitializeWParams = ((1, 'hProcess'), (1, 'UserSearchPath'), (1, 'fInvadeProcess')) + #def SymFromName(hProcess, Name, Symbol): # return SymFromName.ctypes_function(hProcess, Name, Symbol) SymFromNamePrototype = WINFUNCTYPE(BOOL, HANDLE, LPCSTR, PSYMBOL_INFO) @@ -2505,6 +2515,11 @@ SymEnumTypesByNameParams = ((1, 'hProcess'), (1, 'BaseOfDll'), (1, 'mask'), (1, SymEnumerateModules64Prototype = WINFUNCTYPE(BOOL, HANDLE, PVOID, PVOID) SymEnumerateModules64Params = ((1, 'hProcess'), (1, 'EnumModulesCallback'), (1, 'UserContext')) +#def SymEnumerateModulesW64(hProcess, EnumModulesCallback, UserContext): +# return SymEnumerateModulesW64.ctypes_function(hProcess, EnumModulesCallback, UserContext) +SymEnumerateModulesW64Prototype = WINFUNCTYPE(BOOL, HANDLE, PSYM_ENUMMODULES_CALLBACKW64, PVOID) +SymEnumerateModulesW64Params = ((1, 'hProcess'), (1, 'EnumModulesCallback'), (1, 'UserContext')) + #def SymNext(hProcess, si): # return SymNext.ctypes_function(hProcess, si) SymNextPrototype = WINFUNCTYPE(BOOL, HANDLE, PSYMBOL_INFO) diff --git a/windows/generated_def/winstructs.py b/windows/generated_def/winstructs.py index 6fb587c..bf69061 100644 --- a/windows/generated_def/winstructs.py +++ b/windows/generated_def/winstructs.py @@ -287,6 +287,7 @@ PTRANSLATE_ADDRESS_ROUTINE64 = PVOID#StackWalk PSYMBOL_REGISTERED_CALLBACK64 = PVOID#Symbols PSYMBOL_REGISTERED_CALLBACK = PVOID#Symbols PSYM_ENUMPROCESSES_CALLBACK = PVOID#Symbols +PSYM_ENUMMODULES_CALLBACKW64 = PVOID#Symbols ENUMRESNAMEPROCA = PVOID#Resources ENUMRESNAMEPROCW = PVOID#Resources ENUMRESTYPEPROCA = PVOID#Resources diff --git a/windows/winproxy/apis/dbghelp.py b/windows/winproxy/apis/dbghelp.py index 808dceb..1ad6a71 100644 --- a/windows/winproxy/apis/dbghelp.py +++ b/windows/winproxy/apis/dbghelp.py @@ -23,6 +23,10 @@ def transform_pyobject_to_pvoid(obj): def SymInitialize(hProcess, UserSearchPath, fInvadeProcess): return SymInitialize.ctypes_function(hProcess, UserSearchPath, fInvadeProcess) +@DbgHelpProxy() +def SymInitializeW(hProcess, UserSearchPath, fInvadeProcess): + return SymInitializeW.ctypes_function(hProcess, UserSearchPath, fInvadeProcess) + @DbgHelpProxy() def SymCleanup(hProcess): return SymCleanup.ctypes_function(hProcess) @@ -43,14 +47,26 @@ def SymUnloadModule64(hProcess, BaseOfDll): def SymFromAddr(hProcess, Address, Displacement, Symbol): return SymFromAddr.ctypes_function(hProcess, Address, Displacement, Symbol) +@DbgHelpProxy() +def SymFromAddrW(hProcess, Address, Displacement, Symbol): + return SymFromAddrW.ctypes_function(hProcess, Address, Displacement, Symbol) + @DbgHelpProxy() def SymGetModuleInfo64(hProcess, dwAddr, ModuleInfo): return SymGetModuleInfo64.ctypes_function(hProcess, dwAddr, ModuleInfo) +@DbgHelpProxy() +def SymGetModuleInfoW64(hProcess, qwAddr, ModuleInfo): + return SymGetModuleInfoW64.ctypes_function(hProcess, qwAddr, ModuleInfo) + @DbgHelpProxy() def SymFromName(hProcess, Name, Symbol): return SymFromName.ctypes_function(hProcess, Name, Symbol) +@DbgHelpProxy() +def SymFromNameW(hProcess, Name, Symbol): + return SymFromNameW.ctypes_function(hProcess, Name, Symbol) + @DbgHelpProxy() def SymLoadModuleEx(hProcess, hFile, ImageName, ModuleName, BaseOfDll, DllSize, Data, Flags): return SymLoadModuleEx.ctypes_function(hProcess, hFile, ImageName, ModuleName, BaseOfDll, DllSize, Data, Flags) @@ -123,6 +139,11 @@ def SymEnumerateModules64(hProcess, EnumModulesCallback, UserContext=None): UserContext = transform_pyobject_to_pvoid(UserContext) return SymEnumerateModules64.ctypes_function(hProcess, EnumModulesCallback, UserContext) +@DbgHelpProxy() +def SymEnumerateModulesW64(hProcess, EnumModulesCallback, UserContext=None): + UserContext = transform_pyobject_to_pvoid(UserContext) + return SymEnumerateModulesW64.ctypes_function(hProcess, EnumModulesCallback, UserContext) + @DbgHelpProxy() def SymGetTypeFromName(hProcess, BaseOfDll, Name, Symbol): return SymGetTypeFromName.ctypes_function(hProcess, BaseOfDll, Name, Symbol)