On Mon, Oct 10, 2011 at 11:36:33AM +0200, Bernhard Loos wrote: > --- > dlls/ntdll/virtual.c | 38 ++++++++++++++++++++++++++++++++++---- > 1 files changed, 34 insertions(+), 4 deletions(-)
I think this needs tests, the algorithms are very fragile. Ciao, Marcus > diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c > index 5e69eb9..7841d9c 100644 > --- a/dlls/ntdll/virtual.c > +++ b/dlls/ntdll/virtual.c > @@ -1114,6 +1114,7 @@ static NTSTATUS map_image( HANDLE hmapping, int fd, > char *base, SIZE_T total_siz > IMAGE_DOS_HEADER *dos; > IMAGE_NT_HEADERS *nt; > IMAGE_SECTION_HEADER *sec; > + IMAGE_SECTION_HEADER *section_table = NULL; > IMAGE_DATA_DIRECTORY *imports; > NTSTATUS status = STATUS_CONFLICTING_ADDRESSES; > int i; > @@ -1123,6 +1124,7 @@ static NTSTATUS map_image( HANDLE hmapping, int fd, > char *base, SIZE_T total_siz > struct file_view *view = NULL; > char *ptr, *header_end; > INT_PTR delta = 0; > + DWORD SizeOfHeaders; > > /* zero-map the whole range */ > > @@ -1158,8 +1160,11 @@ static NTSTATUS map_image( HANDLE hmapping, int fd, > char *base, SIZE_T total_siz > header_end = ptr + ROUND_SIZE( 0, header_size ); > memset( ptr + header_size, 0, header_end - (ptr + header_size) ); > if ((char *)(nt + 1) > header_end) goto error; > - sec = > (IMAGE_SECTION_HEADER*)((char*)&nt->OptionalHeader+nt->FileHeader.SizeOfOptionalHeader); > - if ((char *)(sec + nt->FileHeader.NumberOfSections) > header_end) goto > error; > + section_table = > (IMAGE_SECTION_HEADER*)((char*)&nt->OptionalHeader+nt->FileHeader.SizeOfOptionalHeader); > + /* make sure we mapped enough memory */ > + if ((char *)(section_table + nt->FileHeader.NumberOfSections) > > header_end) goto error; > + /* windows is only interested in the size as given by > OptionalHeader.SizeOfHeaders */ > + SizeOfHeaders = ROUND_SIZE( 0, nt->OptionalHeader.SizeOfHeaders ); > > imports = nt->OptionalHeader.DataDirectory + > IMAGE_DIRECTORY_ENTRY_IMPORT; > if (!imports->Size || !imports->VirtualAddress) imports = NULL; > @@ -1180,7 +1185,7 @@ static NTSTATUS map_image( HANDLE hmapping, int fd, > char *base, SIZE_T total_siz > if (nt->OptionalHeader.FileAlignment != > nt->OptionalHeader.SectionAlignment) goto error; > for (i = 0; i < nt->FileHeader.NumberOfSections; i++) > { > - if (sec[i].VirtualAddress != sec[i].PointerToRawData) > + if (section_table[i].VirtualAddress != > section_table[i].PointerToRawData) > goto error; /* Windows refuses to load in that case too */ > } > > @@ -1192,6 +1197,24 @@ static NTSTATUS map_image( HANDLE hmapping, int fd, > char *base, SIZE_T total_siz > goto done; > } > > + if ((char *)(section_table + nt->FileHeader.NumberOfSections) > ptr + > SizeOfHeaders) > + { > + /* part of the section table is outside of SizeOfHeaders > + * at this point, it's likely that a section will get mapped over > + * the section table (Borderlands does this) > + * Not sure how it works on Windows, but we make a copy of the > + * table at this point */ > + sec = RtlAllocateHeap( virtual_heap, 0, sizeof(*sec) * > nt->FileHeader.NumberOfSections); > + if (!sec) > + { > + status = STATUS_NO_MEMORY; > + goto error; > + } > + memcpy( sec, section_table, sizeof(*sec) * > nt->FileHeader.NumberOfSections); > + section_table = sec; > + } > + else > + sec = section_table; > > /* map all the sections */ > > @@ -1200,6 +1223,9 @@ static NTSTATUS map_image( HANDLE hmapping, int fd, > char *base, SIZE_T total_siz > static const SIZE_T sector_align = 0x1ff; > SIZE_T map_size, file_start, file_size, end; > > + if (sec->VirtualAddress < SizeOfHeaders) > + goto error; > + > if (!sec->Misc.VirtualSize) > map_size = ROUND_SIZE( 0, sec->SizeOfRawData ); > else > @@ -1329,7 +1355,7 @@ static NTSTATUS map_image( HANDLE hmapping, int fd, > char *base, SIZE_T total_siz > > VIRTUAL_SetProt( view, ptr, ROUND_SIZE( 0, header_size ), > VPROT_COMMITTED | VPROT_READ ); > > - sec = (IMAGE_SECTION_HEADER*)((char > *)&nt->OptionalHeader+nt->FileHeader.SizeOfOptionalHeader); > + sec = section_table; > for (i = 0; i < nt->FileHeader.NumberOfSections; i++, sec++) > { > SIZE_T size; > @@ -1361,6 +1387,8 @@ static NTSTATUS map_image( HANDLE hmapping, int fd, > char *base, SIZE_T total_siz > } > > done: > + if (section_table && (char *)section_table != (char > *)&nt->OptionalHeader+nt->FileHeader.SizeOfOptionalHeader) > + RtlFreeHeap( virtual_heap, 0, section_table ); > view->mapping = dup_mapping; > server_leave_uninterrupted_section( &csVirtual, &sigset ); > > @@ -1373,6 +1401,8 @@ static NTSTATUS map_image( HANDLE hmapping, int fd, > char *base, SIZE_T total_siz > > error: > if (view) delete_view( view ); > + if (section_table && (char *)section_table != (char > *)&nt->OptionalHeader+nt->FileHeader.SizeOfOptionalHeader) > + RtlFreeHeap( virtual_heap, 0, section_table ); > server_leave_uninterrupted_section( &csVirtual, &sigset ); > if (dup_mapping) NtClose( dup_mapping ); > return status; >