[PATCH] ntdll: round section parameters on 0x200
Andrey Turkin
pancha at mail.nnov.ru
Mon Nov 13 01:57:12 CST 2006
Some comments inside. Sorry for over-quoting :)
Dmitry Timoshkov wrote, on 11/13/06 10:19 MSK:
> "Andrey Turkin" <pancha at Mail.nnov.ru> wrote:
>
>>> What is the file alignment of the problematic PE file? Is it 512
>>> (0x200) by any chance?
>>>
>> Yep. However, I've made some quick tests (that is, I've used PE tools
>> to rebuild some apps with larger file alignment and then tried to
>> change physical offset) and it seems that align cutoff is hard-coded
>> as 0x200.
>
> Well, of course larger alignments are always "aligned" to 0x200.
>
> I took your patch as a base and attached patch make upack 0.39 (latest
> available at its home page http://dwing.51.net/download/WinUpack39.rar)
> executable run under Wine.
>
> diff -up a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c
> --- a/dlls/ntdll/virtual.c 2006-11-08 13:55:07.000000000 +0800
> +++ b/dlls/ntdll/virtual.c 2006-11-13 14:57:07.000000000 +0800
> @@ -133,8 +133,10 @@ static UINT_PTR page_mask;
> #define ROUND_ADDR(addr,mask) \
> ((void *)((UINT_PTR)(addr) & ~(UINT_PTR)(mask)))
>
> -#define ROUND_SIZE(addr,size) \
> - (((UINT)(size) + ((UINT_PTR)(addr) & page_mask) + page_mask) &
> ~page_mask)
> +#define ROUND_UP(addr,size,mask) \
> + (((UINT)(size) + ((UINT_PTR)(addr) & (mask)) + (mask)) & ~(mask))
> +
> +#define ROUND_SIZE(addr,size) ROUND_UP(addr,size,page_mask)
>
> #define VIRTUAL_DEBUG_DUMP_VIEW(view) \
> do { if (TRACE_ON(virtual)) VIRTUAL_DumpView(view); } while (0)
> @@ -957,7 +959,7 @@ static NTSTATUS map_image( HANDLE hmappi
> if (!st.st_size) goto error;
> header_size = min( header_size, st.st_size );
> if (map_file_into_view( view, fd, 0, header_size, 0, VPROT_COMMITTED
> | VPROT_READ,
> - removable ) != STATUS_SUCCESS) goto error;
> + TRUE ) != STATUS_SUCCESS) goto error;
> dos = (IMAGE_DOS_HEADER *)ptr;
> nt = (IMAGE_NT_HEADERS *)(ptr + dos->e_lfanew);
> header_end = ptr + ROUND_SIZE( 0, header_size );
> @@ -1031,7 +1033,7 @@ static NTSTATUS map_image( HANDLE hmappi
>
> for (i = pos = 0; i < nt->FileHeader.NumberOfSections; i++, sec++)
> {
> - SIZE_T map_size, file_size, end;
> + SIZE_T map_size, file_size, start, end;
>
> if (!sec->Misc.VirtualSize)
> {
> @@ -1045,6 +1047,7 @@ static NTSTATUS map_image( HANDLE hmappi
> }
>
> /* a few sanity checks */
> + start = (SIZE_T) ROUND_ADDR( sec->PointerToRawData,
> nt->OptionalHeader.FileAlignment - 1 );
I believe this is incorrect with regard to native Windows loader. As I
already said, I've tried to change PointerToRawData field on some files
with big FileAlignment and they load correctly if I or'ed them with some
value in range 0..0x1FF. Files refuses to load if I or'ed
PointerToRawData with 0x200 or 0x3FF!
> end = sec->VirtualAddress + ROUND_SIZE( sec->VirtualAddress,
> map_size );
> if (sec->VirtualAddress > total_size || end > total_size || end
> < sec->VirtualAddress)
> {
> @@ -1095,9 +1098,9 @@ static NTSTATUS map_image( HANDLE hmappi
> /* Note: if the section is not aligned properly
> map_file_into_view will magically
> * fall back to read(), so we don't need to check anything
> here.
> */
> - end = sec->PointerToRawData + file_size;
> - if (sec->PointerToRawData >= st.st_size || end > st.st_size ||
> end < sec->PointerToRawData ||
> - map_file_into_view( view, fd, sec->VirtualAddress,
> file_size, sec->PointerToRawData,
> + end = start + file_size;
> + if (start >= st.st_size || end > st.st_size || end < start ||
> + map_file_into_view( view, fd, sec->VirtualAddress,
> file_size, start,
> VPROT_COMMITTED | VPROT_READ |
> VPROT_WRITECOPY,
> removable ) != STATUS_SUCCESS)
> {
> @@ -1107,12 +1110,13 @@ static NTSTATUS map_image( HANDLE hmappi
>
> if (file_size & page_mask)
> {
> + start = ROUND_UP( 0, file_size,
> nt->OptionalHeader.FileAlignment - 1 );
I've not checked this, but there's probability that align is 0x200 here too.
> end = ROUND_SIZE( 0, file_size );
> if (end > map_size) end = map_size;
> TRACE_(module)("clearing %p - %p\n",
> - ptr + sec->VirtualAddress + file_size,
> + ptr + sec->VirtualAddress + start,
> ptr + sec->VirtualAddress + end );
> - memset( ptr + sec->VirtualAddress + file_size, 0, end -
> file_size );
> + memset( ptr + sec->VirtualAddress + start, 0, end - start );
> }
> }
>
> diff -up a/server/mapping.c b/server/mapping.c
> --- a/server/mapping.c 2006-11-03 21:34:24.000000000 +0800
> +++ b/server/mapping.c 2006-11-13 14:34:50.000000000 +0800
> @@ -243,7 +243,7 @@ static int get_image_params( struct mapp
>
> mapping->size = ROUND_SIZE( nt.OptionalHeader.SizeOfImage );
> mapping->base = (void *)nt.OptionalHeader.ImageBase;
> - mapping->header_size = pos + size;
> + mapping->header_size = max( pos + size,
> nt.OptionalHeader.SizeOfHeaders );
You're reading my mind (or my hard drive), don't you? :) Ok, but if you
going to change server code here, then you should probably align
PointerToRawData in server code as well (writable shared sections will
be mapped incorrectly otherwise).
> mapping->protect = VPROT_IMAGE;
>
> /* sanity check */
More information about the wine-devel
mailing list