mirror of
https://github.com/hakril/PythonForWindows
synced 2026-06-08 14:31:45 +00:00
147 lines
5.1 KiB
Python
147 lines
5.1 KiB
Python
import windows
|
|
import windows.generated_def as gdef
|
|
|
|
from windows import utils
|
|
|
|
|
|
def get_api_set_map_for_current_process(base):
|
|
base = windows.current_process.peb.ApiSetMap
|
|
version = windows.current_process.read_dword(base)
|
|
if version not in API_SET_MAP_BY_VERSION:
|
|
raise NotImplementedError("ApiSetMap version <{0}> not implemented, please contact me, I need a sample to implem it ;)")
|
|
return API_SET_MAP_BY_VERSION[version](base)
|
|
|
|
|
|
class ApiSetMap(object):
|
|
def __init__(self, base):
|
|
self.base = base
|
|
self.target = windows.current_process
|
|
|
|
# helpers
|
|
def read_apiset_wstring(self, offset, length):
|
|
return self.target.read_memory(self.base + offset, length).decode("utf-16")
|
|
|
|
# Low-level version-dependent parsing function
|
|
def entries_array(self):
|
|
raise NotImplementedError("Should be implemented by subclasses")
|
|
|
|
def get_entry_name(self, entry):
|
|
raise NotImplementedError("Should be implemented by subclasses")
|
|
|
|
def get_entry_name_basicimpl(self, entry):
|
|
return self.read_apiset_wstring(entry.NameOffset, entry.NameLength)
|
|
|
|
def values_for_entry(self, entry):
|
|
raise NotImplementedError("Should be implemented by subclasses")
|
|
|
|
@utils.fixedpropety
|
|
def apisetmap_dict(self):
|
|
res = {}
|
|
for entry in self.entries_array():
|
|
values = self.values_for_entry(entry)
|
|
if not values:
|
|
final_value = None
|
|
else:
|
|
final_value = values[-1]
|
|
res[self.get_entry_name(entry)] = final_value
|
|
return res
|
|
|
|
@utils.fixedpropety
|
|
def resolution_dict(self):
|
|
res = {}
|
|
for name, resolved_name in self.apisetmap_dict.items():
|
|
# ApiSetResolveToHost does not care about last version + extension
|
|
# It remove everything after the last '-'
|
|
|
|
# Possible to have no '-' ?
|
|
try:
|
|
cutname = name[:name.rindex("-") + 1]
|
|
except ValueError as e:
|
|
cutname = name
|
|
res[cutname] = resolved_name
|
|
return res
|
|
|
|
def resolve(self, dllname):
|
|
try:
|
|
cutname = dllname[:dllname.rindex("-") + 1]
|
|
except ValueError as e:
|
|
return None
|
|
return self.resolution_dict[cutname]
|
|
|
|
|
|
|
|
class ApiSetMapVersion2(ApiSetMap):
|
|
def namespace(self):
|
|
return gdef.API_SET_NAMESPACE_ARRAY_V2.from_address(self.base)
|
|
|
|
def entries_array(self):
|
|
namespace = self.namespace()
|
|
array_addr = ctypes.addressof(namespace.Array)
|
|
array_size = namespace.Count
|
|
return (gdef.API_SET_NAMESPACE_ENTRY_V2 * array_size).from_address(array_addr)
|
|
|
|
get_entry_name = ApiSetMap.get_entry_name_basicimpl
|
|
|
|
def values_for_entry(self, entry):
|
|
values_array_v2 = (gdef.API_SET_VALUE_ARRAY_V2).from_address(self.base + entry.DataOffset)
|
|
array_size = values_array_v2.Count
|
|
array_addr = ctypes.addressof(values_array_v2.Array)
|
|
values_array = (gdef.API_SET_VALUE_ENTRY_V2 * array_size).from_address(array_addr)
|
|
res = []
|
|
for value in values_array:
|
|
if value.ValueLength:
|
|
v = self.read_apiset_wstring(value.ValueOffset, value.ValueLength)
|
|
res.append(v)
|
|
return res
|
|
|
|
|
|
class ApiSetMapVersion4(ApiSetMap):
|
|
def namespace(self):
|
|
return gdef.API_SET_NAMESPACE_ARRAY_V4.from_address(self.base)
|
|
|
|
def entries_array(self):
|
|
namespace = self.namespace()
|
|
array_addr = ctypes.addressof(namespace.Array)
|
|
array_size = namespace.Count
|
|
return (gdef.API_SET_NAMESPACE_ENTRY_V4 * array_size).from_address(array_addr)
|
|
|
|
get_entry_name = ApiSetMap.get_entry_name_basicimpl
|
|
|
|
def values_for_entry(self, entry):
|
|
values_array_v2 = (gdef.API_SET_VALUE_ARRAY_V4).from_address(self.base + entry.DataOffset)
|
|
array_size = values_array_v2.Count
|
|
array_addr = ctypes.addressof(values_array_v2.Array)
|
|
values_array = (gdef.API_SET_VALUE_ENTRY * array_size).from_address(array_addr)
|
|
res = []
|
|
for value in values_array:
|
|
if value.ValueLength:
|
|
v = self.read_apiset_wstring(value.ValueOffset, value.ValueLength)
|
|
res.append(v)
|
|
return res
|
|
|
|
class ApiSetMapVersion6(ApiSetMap):
|
|
def namespace(self):
|
|
return gdef.API_SET_NAMESPACE_V6.from_address(self.base)
|
|
|
|
get_entry_name = ApiSetMap.get_entry_name_basicimpl
|
|
|
|
def entries_array(self):
|
|
namespace = self.namespace()
|
|
array_offset = namespace.EntryOffset
|
|
array_size = namespace.Count
|
|
return (gdef.API_SET_NAMESPACE_ENTRY_V6 * array_size).from_address(self.base + array_offset)
|
|
|
|
def values_for_entry(self, entry):
|
|
values_array = (gdef.API_SET_VALUE_ENTRY * entry.ValueCount).from_address(self.base + entry.ValueOffset)
|
|
res = []
|
|
for value in values_array:
|
|
if value.ValueLength:
|
|
v = self.read_apiset_wstring(value.ValueOffset, value.ValueLength)
|
|
res.append(v)
|
|
return res
|
|
|
|
API_SET_MAP_BY_VERSION = {
|
|
2: ApiSetMapVersion2,
|
|
4: ApiSetMapVersion4,
|
|
6: ApiSetMapVersion6,
|
|
} |