reactos/sdk/tools/gen_baseaddress.py
Hermès Bélusca-Maïto 0e14378d3e
[SMDLL][SMLIB] Deprecate the legacy ROS-specific SMDLL and improve SM client functions. (#4821)
This DLL was exporting legacy NT-incompatible or ROS-specific SM client
functions, that have been since 10 years now (2012) replaced by the new
NT-compatible SM:

- SmConnectApiPort(): was just SmConnectToSm().

- SmCompleteSession():
  The legacy SMSS used it for when a subsystem initialization was finished.
  Now (NT-compatible) this function is called by subsystems **only** when a
  subsystem session **terminates**: SmSessionComplete().

- SmExecuteProgram(): was just the client side of SmLoadDeferedSubSystem()
  (whose server side is not implemented yet). The legacy SM "old" SmExecPgm
  implementation actually was "SmLoadDeferedSubSystem"...

- SmLookupSubsystem(): is a utility-only function to read any registry value
  inside "Session Manager\SubSystems".

Move SMDLL's readme into SMLIB and update its contents.

Collect some residual useful functions into smutils.c (and moved in SMLIB,
though not compiled yet):
- SmExecuteProgram(), now implemented as a wrapper around SmExecPgm();
- SmLookupSubsystem(), described above;
- SmQueryInformation(), that retrieves a list of currently-running subsystems.

[SMLIB] Validate SbApiPortName's length in SmConnectToSm().
Fix CommandLine length validation in SmStartCsr().

Add documentation (+ SAL annotations) to the NT-compatible SMSS client functions.

smmsg.h: Add both Win32 and Win64 struct sizes C_ASSERTs for those whose size
change between these two processor architecture sizes.

[SMLIB] Introduce SmSendMsgToSm() as helper to send data into the SM LPC port.
+ Make the other API functions use it.

It should be observed that in Vista+, both functions SmConnectToSm() and this
new SmSendMsgToSm() are exported by NTDLL under the names RtlConnectToSm()
and RtlSendMsgToSm() (and use the same signature).
See: https://www.geoffchappell.com/studies/windows/win32/ntdll/history/names60.htm

[NTDLL] Correctly stub RtlConnectToSm() and RtlSendMsgToSm().
[NTDLL_VISTA] Link to SMLIB and simply export RtlConnectToSm() and RtlSendMsgToSm().
2022-11-08 17:40:53 +01:00

392 lines
10 KiB
Python

'''
PROJECT: ReactOS baseaddress updater
LICENSE: MIT (https://spdx.org/licenses/MIT)
PURPOSE: Update baseaddresses of all modules
COPYRIGHT: Copyright 2017,2018 Mark Jansen (mark.jansen@reactos.org)
'''
from __future__ import print_function, absolute_import, division
USAGE = """
This script will update the baseaddresses of all modules, based on the build output.
Specify the build output dir as commandline argument to the script:
`python gen_baseaddress.py C:\\Users\\Mark\\reactos\\output-MinGW-i386`
Multiple directories can be specified:
`python gen_baseaddress r:/build/msvc r:/build/gcc`
"""
import os
import struct
import sys
try:
import pefile
except ImportError:
print('# Please install pefile from pip or https://github.com/erocarrera/pefile')
sys.exit(-1)
ALL_EXTENSIONS = (
'.dll', '.acm', '.ax', '.cpl', '.drv', '.ocx'
)
PRIORITIES = (
'ntdll.dll',
'kernel32.dll',
'msvcrt.dll',
'advapi32.dll',
'gdi32.dll',
'user32.dll',
'dhcpcsvc.dll',
'dnsapi.dll',
'icmp.dll',
'iphlpapi.dll',
'ws2_32.dll',
'ws2help.dll',
'shlwapi.dll',
'rpcrt4.dll',
'comctl32.dll',
'ole32.dll',
'winspool.drv',
'winmm.dll',
'comdlg32.dll',
'shell32.dll',
'lz32.dll',
'version.dll',
'oleaut32.dll',
'setupapi.dll',
'mpr.dll',
'crypt32.dll',
'wininet.dll',
'urlmon.dll',
'psapi.dll',
'imm32.dll',
'msvfw32.dll',
'dbghelp.dll',
'devmgr.dll',
'msacm32.dll',
'netapi32.dll',
'powrprof.dll',
'secur32.dll',
'wintrust.dll',
'avicap32.dll',
'cabinet.dll',
'dsound.dll',
'glu32.dll',
'opengl32.dll',
'riched20.dll',
'userenv.dll',
'uxtheme.dll',
'cryptui.dll',
'csrsrv.dll',
'basesrv.dll',
'winsrv.dll',
'dplayx.dll',
'gdiplus.dll',
'msimg32.dll',
'mswsock.dll',
'oledlg.dll',
'rasapi32.dll',
'rsaenh.dll',
'samlib.dll',
'sensapi.dll',
'sfc_os.dll',
'snmpapi.dll',
'spoolss.dll',
'usp10.dll',
)
EXCLUDE = (
'bmfd.dll',
'bootvid.dll',
'framebuf.dll',
'framebuf_new.dll',
'ftfd.dll',
'fusion.dll',
'genincdata.dll',
'hal.dll',
'halaacpi.dll',
'halacpi.dll',
'halapic.dll',
'kbda1.dll',
'kbda2.dll',
'kbda3.dll',
'kbdal.dll',
'kbdarme.dll',
'kbdarmw.dll',
'kbdaze.dll',
'kbdazel.dll',
'kbdbe.dll',
'kbdbga.dll',
'kbdbgt.dll',
'kbdblr.dll',
'kbdbr.dll',
'kbdbu.dll',
'kbdbur.dll',
'kbdcan.dll',
'kbdcr.dll',
'kbdcz.dll',
'kbdcz1.dll',
'kbdda.dll',
'kbddv.dll',
'kbdest.dll',
'kbdfc.dll',
'kbdfi.dll',
'kbdfr.dll',
'kbdgeo.dll',
'kbdgerg.dll',
'kbdgneo.dll',
'kbdgr.dll',
'kbdgr1.dll',
'kbdhe.dll',
'kbdheb.dll',
'kbdhu.dll',
'kbdic.dll',
'kbdinasa.dll',
'kbdinben.dll',
'kbdindev.dll',
'kbdinguj.dll',
'kbdinmal.dll',
'kbdir.dll',
'kbdit.dll',
'kbdjpn.dll',
'kbdkaz.dll',
'kbdkor.dll',
'kbdla.dll',
'kbdlt1.dll',
'kbdlv.dll',
'kbdmac.dll',
'kbdne.dll',
'kbdno.dll',
'kbdpl.dll',
'kbdpl1.dll',
'kbdpo.dll',
'kbdro.dll',
'kbdru.dll',
'kbdru1.dll',
'kbdsg.dll',
'kbdsl.dll',
'kbdsl1.dll',
'kbdsp.dll',
'kbdsw.dll',
'kbdtat.dll',
'kbdth0.dll',
'kbdth1.dll',
'kbdth2.dll',
'kbdth3.dll',
'kbdtuf.dll',
'kbdtuq.dll',
'kbduk.dll',
'kbdur.dll',
'kbdurs.dll',
'kbdus.dll',
'kbdusa.dll',
'kbdusl.dll',
'kbdusr.dll',
'kbdusx.dll',
'kbduzb.dll',
'kbdvntc.dll',
'kbdycc.dll',
'kbdycl.dll',
'kdcom.dll',
'kdvbox.dll',
'vgaddi.dll',
'dllexport_test_dll1.dll',
'dllexport_test_dll2.dll',
'dllimport_test.dll',
'MyEventProvider.dll',
'w32kdll_2k3sp2.dll',
'w32kdll_ros.dll',
'w32kdll_xpsp2.dll',
)
IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b
IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b
IMAGE_TYPES = {
IMAGE_NT_OPTIONAL_HDR32_MAGIC: 0,
IMAGE_NT_OPTIONAL_HDR64_MAGIC: 0
}
def is_x64():
return IMAGE_TYPES[IMAGE_NT_OPTIONAL_HDR64_MAGIC] > IMAGE_TYPES[IMAGE_NT_OPTIONAL_HDR32_MAGIC]
def size_of_image(filename):
with open(filename, 'rb') as fin:
if fin.read(2) != b'MZ':
print(filename, 'No dos header found!')
return 0
fin.seek(0x3C)
e_lfanew = struct.unpack('i', fin.read(4))[0]
fin.seek(e_lfanew)
if fin.read(4) != b'PE\0\0':
print(filename, 'No PE header found!')
return 0
fin.seek(e_lfanew + 0x18)
pe_magic = struct.unpack('h', fin.read(2))[0]
if pe_magic in IMAGE_TYPES.keys():
IMAGE_TYPES[pe_magic] += 1
fin.seek(e_lfanew + 0x50)
pe_size_of_image = struct.unpack('i', fin.read(4))[0]
return pe_size_of_image
print(filename, 'Unknown executable format!')
return 0
class Module(object):
def __init__(self, name, address, size, filename):
self._name = name
self.address = address
self.size = size
self._reserved = address != 0
self.filename = filename
def gen_baseaddress(self, output_file):
name, ext = os.path.splitext(self._name)
postfix = ''
if ext in('.acm', '.drv') and self._name != 'winspool.drv':
name = self._name
if name == 'ntdll':
postfix = ' # should be above 0x%08x' % self.address
elif self._reserved:
postfix = ' # reserved'
output_file.write('set(baseaddress_%-30s 0x%08x)%s\n' % (name, self.address, postfix))
def end(self):
return self.address + self.size
def __repr__(self):
return '%s (0x%08x - 0x%08x)' % (self._name, self.address, self.end())
class MemoryLayout(object):
def __init__(self, startaddress):
self.addresses = []
self.found = {}
self.reserved = {}
self.initial = startaddress
self.start_at = 0
self.module_padding = 0x2000
def add_reserved(self, name, address):
self.reserved[name] = (address, 0)
def add(self, filename, name):
size = size_of_image(filename)
addr = 0
if name in self.found:
return # Assume duplicate files (rshell, ...) are 1:1 copies
if name in self.reserved:
addr = self.reserved[name][0]
self.reserved[name] = (addr, size)
self.found[name] = Module(name, addr, size, filename)
def _next_address(self, size):
if self.start_at:
addr = (self.start_at - size - self.module_padding - 0xffff) & 0xffff0000
self.start_at = addr
else:
addr = self.start_at = self.initial
return addr
def next_address(self, size):
while True:
current_start = self._next_address(size)
current_end = current_start + size + self.module_padding
# Is there overlap with reserved modules?
for key, reserved in self.reserved.items():
res_start = reserved[0]
res_end = res_start + reserved[1] + self.module_padding
if (res_start <= current_start <= res_end) or \
(res_start <= current_end <= res_end) or \
(current_start < res_start and current_end > res_end):
# We passed this reserved item, we can remove it now
self.start_at = min(res_start, current_start)
del self.reserved[key]
current_start = 0
break
# No overlap with a reserved module?
if current_start:
return current_start
def update(self, priorities):
# sort addresses, should only contain reserved modules at this point!
for key, reserved in self.reserved.items():
assert reserved[1] != 0, key
for curr in priorities:
if not curr in self.found:
print('# Did not find', curr, '!')
else:
obj = self.found[curr]
del self.found[curr]
if not obj.address:
obj.address = self.next_address(obj.size)
self.addresses.append(obj)
# We handled all known modules now, run over the rest we found
for key in sorted(self.found):
obj = self.found[key]
obj.address = self.next_address(obj.size)
self.addresses.append(obj)
def gen_baseaddress(self, output_file):
for obj in self.addresses:
obj.gen_baseaddress(output_file)
def get_target_file(ntdll_path):
if 'pefile' in globals():
ntdll_pe = pefile.PE(ntdll_path, fast_load=True)
names = [sect.Name.strip(b'\0') for sect in ntdll_pe.sections]
count = b'|'.join(names).count(b'/')
if b'.rossym' in names:
return 'baseaddress.cmake'
elif is_x64():
return 'baseaddress_msvc_x64.cmake'
elif count == 0:
return 'baseaddress_msvc.cmake'
elif count > 3:
return 'baseaddress_dwarf.cmake'
else:
assert False, "Unknown"
return None
def run_dir(target):
layout = MemoryLayout(0x7c920000)
layout.add_reserved('user32.dll', 0x77a20000)
IMAGE_TYPES[IMAGE_NT_OPTIONAL_HDR64_MAGIC] = 0
IMAGE_TYPES[IMAGE_NT_OPTIONAL_HDR32_MAGIC] = 0
for root, _, files in os.walk(target):
for dll in [filename for filename in files if filename.endswith(ALL_EXTENSIONS)]:
if not dll in EXCLUDE and not dll.startswith('api-ms-win-'):
layout.add(os.path.join(root, dll), dll)
ntdll_path = layout.found['ntdll.dll'].filename
target_file = get_target_file(ntdll_path)
if target_file:
target_dir = os.path.realpath(os.path.dirname(os.path.dirname(__file__)))
target_path = os.path.join(target_dir, 'cmake', target_file)
output_file = open(target_path, "w")
else:
output_file = sys.stdout
with output_file:
output_file.write('# Generated from {}\n'.format(target))
output_file.write('# Generated by sdk/tools/gen_baseaddress.py\n\n')
layout.update(PRIORITIES)
layout.gen_baseaddress(output_file)
def main():
dirs = sys.argv[1:]
if len(dirs) < 1:
trydir = os.getcwd()
print(USAGE)
print('No path specified, trying the working directory: ', trydir)
dirs = [trydir]
for onedir in dirs:
if onedir.lower() in ['-help', '/help', '/h', '-h', '/?', '-?']:
print(USAGE)
else:
run_dir(onedir)
if __name__ == '__main__':
main()