2 PROJECT: ReactOS baseaddress updater
3 LICENSE: MIT (https://spdx.org/licenses/MIT)
4 PURPOSE: Update baseaddresses of all modules
5 COPYRIGHT: Copyright 2017,2018 Mark Jansen (mark.jansen@reactos.org)
7 from __future__
import print_function
, absolute_import
, division
15 print('# Please install pefile from pip or https://github.com/erocarrera/pefile')
16 print('# Using fallback')
20 '.dll', '.acm', '.ax', '.cpl', '.drv', '.ocx'
184 'dllexport_test_dll1.dll',
185 'dllexport_test_dll2.dll',
186 'dllimport_test.dll',
187 'MyEventProvider.dll',
188 'w32kdll_2k3sp2.dll',
193 IMAGE_NT_OPTIONAL_HDR32_MAGIC
= 0x10b
194 IMAGE_NT_OPTIONAL_HDR64_MAGIC
= 0x20b
197 IMAGE_NT_OPTIONAL_HDR32_MAGIC
: 0,
198 IMAGE_NT_OPTIONAL_HDR64_MAGIC
: 0
202 return IMAGE_TYPES
[IMAGE_NT_OPTIONAL_HDR64_MAGIC
] > IMAGE_TYPES
[IMAGE_NT_OPTIONAL_HDR32_MAGIC
]
204 def size_of_image_fallback(filename
):
205 with
open(filename
, 'rb') as fin
:
206 if fin
.read(2) != 'MZ':
207 print(filename
, 'No dos header found!')
210 e_lfanew
= struct
.unpack('i', fin
.read(4))[0]
212 if fin
.read(4) != 'PE\0\0':
213 print(filename
, 'No PE header found!')
215 fin
.seek(e_lfanew
+ 0x18)
216 pe_magic
= struct
.unpack('h', fin
.read(2))[0]
217 if pe_magic
in IMAGE_TYPES
.keys():
218 IMAGE_TYPES
[pe_magic
] += 1
219 fin
.seek(e_lfanew
+ 0x50)
220 pe_size_of_image
= struct
.unpack('i', fin
.read(4))[0]
221 return pe_size_of_image
222 print(filename
, 'Unknown executable format!')
226 def size_of_image_verify(filename
):
227 pefile_size
= pefile
.PE(filename
, fast_load
=True).OPTIONAL_HEADER
.SizeOfImage
228 custom_size
= size_of_image_fallback(filename
)
229 assert custom_size
== pefile_size
, filename
232 SIZE_OF_IMAGE_FN
= size_of_image_fallback
234 class Module(object):
235 def __init__(self
, name
, address
, size
, filename
):
237 self
.address
= address
239 self
._reserved
= address
!= 0
240 self
.filename
= filename
242 def gen_baseaddress(self
):
243 name
, ext
= os
.path
.splitext(self
._name
)
245 if ext
in('.acm', '.drv') and self
._name
!= 'winspool.drv':
248 postfix
= ' # should be above 0x%08x' % self
.address
250 postfix
= ' # reserved'
251 print('set(baseaddress_%-30s 0x%08x)%s' % (name
, self
.address
, postfix
))
254 return self
.address
+ self
.size
257 return '%s (0x%08x - 0x%08x)' % (self
._name
, self
.address
, self
.end())
259 class MemoryLayout(object):
260 def __init__(self
, startaddress
):
264 self
.initial
= startaddress
266 self
.module_padding
= 0x2000
268 def add_reserved(self
, name
, address
):
269 self
.reserved
[name
] = (address
, 0)
271 def add(self
, filename
, name
):
272 size
= SIZE_OF_IMAGE_FN(filename
)
274 if name
in self
.found
:
275 return # Assume duplicate files (rshell, ...) are 1:1 copies
276 if name
in self
.reserved
:
277 addr
= self
.reserved
[name
][0]
278 self
.reserved
[name
] = (addr
, size
)
279 self
.found
[name
] = Module(name
, addr
, size
, filename
)
281 def _next_address(self
, size
):
283 addr
= (self
.start_at
- size
- self
.module_padding
- 0xffff) & 0xffff0000
286 addr
= self
.start_at
= self
.initial
289 def next_address(self
, size
):
291 current_start
= self
._next
_address
(size
)
292 current_end
= current_start
+ size
+ self
.module_padding
293 # Is there overlap with reserved modules?
294 for key
, reserved
in self
.reserved
.items():
295 res_start
= reserved
[0]
296 res_end
= res_start
+ reserved
[1] + self
.module_padding
297 if (res_start
<= current_start
<= res_end
) or \
298 (res_start
<= current_end
<= res_end
) or \
299 (current_start
< res_start
and current_end
> res_end
):
300 # We passed this reserved item, we can remove it now
301 self
.start_at
= min(res_start
, current_start
)
302 del self
.reserved
[key
]
305 # No overlap with a reserved module?
309 def update(self
, priorities
):
310 # sort addresses, should only contain reserved modules at this point!
311 for key
, reserved
in self
.reserved
.items():
312 assert reserved
[1] != 0, key
313 for curr
in priorities
:
314 if not curr
in self
.found
:
315 print('# Did not find', curr
, '!')
317 obj
= self
.found
[curr
]
320 obj
.address
= self
.next_address(obj
.size
)
321 self
.addresses
.append(obj
)
322 # We handled all known modules now, run over the rest we found
323 for key
in sorted(self
.found
):
324 obj
= self
.found
[key
]
325 obj
.address
= self
.next_address(obj
.size
)
326 self
.addresses
.append(obj
)
328 def gen_baseaddress(self
):
329 for obj
in self
.addresses
:
330 obj
.gen_baseaddress()
332 def guess_version(ntdll_path
):
333 if 'pefile' in globals():
334 ntdll_pe
= pefile
.PE(ntdll_path
, fast_load
=True)
335 names
= [sect
.Name
.strip('\0') for sect
in ntdll_pe
.sections
]
336 count
= '|'.join(names
).count('/')
337 if '.rossym' in names
:
338 print('# This should probably go in baseaddress.cmake')
340 print('# This should probably go in baseaddress_msvc_x64.cmake')
342 print('# This should probably go in baseaddress_msvc.cmake')
344 print('# This should probably go in baseaddress_dwarf.cmake')
346 print('# No clue where to put this')
349 print('# Generated from', target
)
350 print('# Generated by sdk/tools/gen_baseaddress.py')
351 layout
= MemoryLayout(0x7c920000)
352 layout
.add_reserved('user32.dll', 0x77a20000)
353 for root
, _
, files
in os
.walk(target
):
354 for dll
in [filename
for filename
in files
if filename
.endswith(ALL_EXTENSIONS
)]:
355 if not dll
in EXCLUDE
and not dll
.startswith('api-ms-win-'):
356 layout
.add(os
.path
.join(root
, dll
), dll
)
357 ntdll_path
= layout
.found
['ntdll.dll'].filename
358 guess_version(ntdll_path
)
359 layout
.update(PRIORITIES
)
360 layout
.gen_baseaddress()
366 print('# No path specified, trying', trydir
)
374 # pyprof2calltree -k -i test.cprof
375 cProfile
.run('main()', filename
='test.cprof')
377 if __name__
== '__main__':
379 #SIZE_OF_IMAGE_FN = size_of_image_verify