[Shrinker] Another landmine

Robert Baruch autophile at starband.net
Mon Dec 24 16:01:35 CST 2001


On 24 Dec 2001 12:33:50 -0800
Alexandre Julliard <julliard at winehq.com> wrote:

> > Instead, it finds an unimplemented procedure in Wine. So now I will
look
> > at LdrAccessResource (and friends) to see what's involved in
implementing
> > it, whatever it is.
> 
> Sounds much more problematic. LdrAccessResource itself is not too
> hard, but I doubt you'll get gcc to generate exactly the above code;
> and writing LdrAccessResource in assembly is not really an option.

Well, Shrinker is getting kind of ridiculous with its required checks for
the genuine Microsoft NTDLL.DLL. Also I can't find LdrAccessResource
documented anywhere. Smacks of anticompetitiveness and monopolistic
intentions to me :) Is there a book on undocumented NT/2000?

I looked at the assembly of LdrAccessResource. All it is is push four args
onto the stack, call an internal function, and return.

That internal function is more complicated, but it looks like it is
getting a pointer to the RESOURCE entry of an image -- there are calls to
RtlImageNtHeader and RtlImageDirectoryEntryToData.

So anyway, if we implemented this internal function (in C), then in theory
it wouldn't be much of a big deal to code LdrAccessResource in assembly.
Although it will raise a few eyebrows, we can always put in a comment
similar to the one that will go in the assembler-coded EXC_CallHandler,
that this code is required by Shrinker.

For those who are interested, here's the pseudo-code I've come up with for
LdrAccessResource. The only missing piece is "call77F89D5F", and the
exception clause -- I haven't traced those yet.

BOOL LdrAccessResource(arg1, arg2, hModule, arg4, arg5, arg6)
{
	return _LdrAccessResource(hModule, arg4, arg5, arg6)
}

BOOL _LdrAccessResource(hModule, arg2, arg3, arg4)
{
	try
	{
		DWORD size;
		PIMAGE_RESOURCE_DIRECTORY *entry;
		PIMAGE_NT_HEADERS *ntheader;
		MEMORY_BASIC_INFORMATION meminfo;
		DWORD regionSize;
		void *ptr = 0;
		void *addr = 0;

		entry = RtlImageDirectoryEntryToData(
			hModule, 1, IMAGE_DIRECTORY_ENTRY_RESOURCE, &size);

		if (!entry)
			throw STATUS_RESOURCE_DATA_NOT_FOUND;

		if (arg2 < entry)
			hModule = LdrLoadAlternateResourceModule(
				hModule, 0);
		else
		{
			ntheader = RtlImageNtHeader(hModule&0xFFFFFFFE);
			if (ntheader)
			{
				if (!hModule & 0x01)
					regionSize = ntheader->OptionalHeader.SizeOfImage;
				else
				{
					ptr = ZwQueryVirtualMemory(
						-1, hModule&0xFFFFFFFE, 0,
						&meminfo, sizeof(meminfo), 0);
					regionSize = ptr<0 ? 0 : meminfo.RegionSize;
				}
				if (arg2 < regionSize ||
				    	arg2 >= regionSize + hModule&0xFFFFFFFE)
					hModule = LdrLoadAlternateResourceModule(
						hModule, 0);
			}
		}

		if (!hModule)
			throw STATUS_RESOURCE_DATA_NOT_FOUND;

		entry = RtlImageDirectoryEntryToData(
			hModule, 1, IMAGE_DIRECTORY_ENTRY_RESOURCE, &size);

		if (!entry)
			throw STATUS_RESOURCE_DATA_NOT_FOUND;

		if (hModule & 0x01)
		{
			hModule &= 0xFFFFFFFE;
			ntheader = RtlImageNtHeader(hModule);
			if (ntheader->OptionalHeader.Magic == 0x10B)
				addr =
ntheader->OptionalHeader.DataDirectory[2].VirtualAddress;
			else if (ntheader->OptionalHeader.Magic == 0x20B)
				addr =
ntheader->OptionalHeader.DataDirectory[4].VirtualAddress;
			else
				addr = 0;

			if (!addr)
				throw STATUS_RESOURCE_DATA_NOT_FOUND;

			ptr = hModule + (addr - entry);

			if (!(section = RtlImageRvaToSection(ntheader, hModule, addr)))
				throw STATUS_RESOURCE_DATA_NOT_FOUND;

			if (*arg2 > *(section+2))
			{
				section2 = RtlImageRvaToSection(ntheader, hModule, *arg2);
				rtn = call77F89D5F(ntheader, hModule, *(section2+3));
				ptr += *(section2+3) - *(section+3) - rtn;
			}

		}

		if (arg3)
			*arg3 = hModule + (*arg2 - ptr);
		if (arg4)
			*arg4 = *(arg2+1);
		return 0;
	}
	catch
	{
		// exception clause here
	}
}



--Rob




More information about the wine-devel mailing list