Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

.rsrc section does not behave as expected #24

Open
CodeXTF2 opened this issue Nov 2, 2021 · 3 comments
Open

.rsrc section does not behave as expected #24

CodeXTF2 opened this issue Nov 2, 2021 · 3 comments

Comments

@CodeXTF2
Copy link

CodeXTF2 commented Nov 2, 2021

DLLs cannot use FindResource when converted into shellcode. Same code works when not loaded using sRDI. Issue seems to be the same as TheWover/donut#70 where the PE stomping breaks the .rsrc section.
EDIT: Based on PE structure, not sure if there is a workaround other than disabling the SRDI_CLEARHEADER flag. Any ideas?
EDIT 2: Even with SRDI_CLEARHEADER it doesnt seem to work.

@monoxgas
Copy link
Owner

I haven't had any issues with accessing resource sections as long as SRDI_CLEARHEADER is not passed. Otherwise the PE header validation fails and the native APIs refuse to touch it. I would expect something like this to work:

BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{
   HRSRC rsc = FindResource(hModule, MAKEINTRESOURCE(IDI_ICON1), RT_GROUP_ICON);
   ...
}

@monoxgas
Copy link
Owner

If it helps, here is some extracted code which can parse the PE resource section manually:

static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry(void* root, PIMAGE_RESOURCE_DIRECTORY resources, LPCTSTR key)
{
	PIMAGE_RESOURCE_DIRECTORY_ENTRY entries = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resources + 1);
	PIMAGE_RESOURCE_DIRECTORY_ENTRY result = NULL;
	DWORD start;
	DWORD end;
	DWORD middle;

	if (IS_INTRESOURCE(key)) {
		WORD check = (WORD)(uintptr_t)key;
		start = resources->NumberOfNamedEntries;
		end = start + resources->NumberOfIdEntries;

		while (end > start) {
			WORD entryName;
			middle = (start + end) >> 1;
			entryName = (WORD)entries[middle].Name;
			if (check < entryName) {
				end = (end != middle ? middle : middle - 1);
			}
			else if (check > entryName) {
				start = (start != middle ? middle : middle + 1);
			}
			else {
				result = &entries[middle];
				break;
			}
		}
	}
	else {
		LPCWSTR searchKey;
		size_t searchKeyLen = wcslen(key);
		searchKey = key;

		start = 0;
		end = resources->NumberOfNamedEntries;
		while (end > start) {
			int cmp;
			PIMAGE_RESOURCE_DIR_STRING_U resourceString;
			middle = (start + end) >> 1;
			resourceString = PIMAGE_RESOURCE_DIR_STRING_U((UINT_PTR)root + (entries[middle].Name & 0x7FFFFFFF));
			cmp = _wcsnicmp(searchKey, resourceString->NameString, resourceString->Length);
			if (cmp == 0) {
				// Handle partial match
				if (searchKeyLen > resourceString->Length) {
					cmp = 1;
				}
				else if (searchKeyLen < resourceString->Length) {
					cmp = -1;
				}
			}
			if (cmp < 0) {
				end = (middle != end ? middle : middle - 1);
			}
			else if (cmp > 0) {
				start = (middle != start ? middle : middle + 1);
			}
			else {
				result = &entries[middle];
				break;
			}
		}
	}

	return result;
}

#define RVA(type, base, rva) (type)((ULONG_PTR) base + rva)

std::string * GetResourceR(HMODULE hModule, LPCTSTR name, LPCTSTR type, WORD language)
{
	PIMAGE_RESOURCE_DIRECTORY rootResources;
	PIMAGE_RESOURCE_DIRECTORY nameResources;
	PIMAGE_RESOURCE_DIRECTORY typeResources;
	PIMAGE_RESOURCE_DIRECTORY_ENTRY foundType;
	PIMAGE_RESOURCE_DIRECTORY_ENTRY foundName;
	PIMAGE_RESOURCE_DIRECTORY_ENTRY foundLanguage;

	if (language == 0) {
		language = LANGIDFROMLCID(GetThreadLocale());
	}

	if (hModule == NULL)
		return NULL;

	PIMAGE_NT_HEADERS ntHeaders = RVA(PIMAGE_NT_HEADERS, hModule, ((PIMAGE_DOS_HEADER)hModule)->e_lfanew);
	PIMAGE_DATA_DIRECTORY dataDir = &ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE];
	if (!dataDir->Size)
		return NULL;

	rootResources = RVA(PIMAGE_RESOURCE_DIRECTORY, hModule, dataDir->VirtualAddress);
	foundType = _MemorySearchResourceEntry(rootResources, rootResources, type);
	if (foundType == NULL) {
		SetLastError(ERROR_RESOURCE_TYPE_NOT_FOUND);
		return NULL;
	}

	typeResources = RVA(PIMAGE_RESOURCE_DIRECTORY, hModule, dataDir->VirtualAddress + (foundType->OffsetToData & 0x7fffffff));
	foundName = _MemorySearchResourceEntry(rootResources, typeResources, name);
	if (foundName == NULL) {
		SetLastError(ERROR_RESOURCE_NAME_NOT_FOUND);
		return NULL;
	}

	nameResources = RVA(PIMAGE_RESOURCE_DIRECTORY, hModule, dataDir->VirtualAddress + (foundName->OffsetToData & 0x7fffffff));
	foundLanguage = _MemorySearchResourceEntry(rootResources, nameResources, (LPCTSTR)(uintptr_t)language);
	if (foundLanguage == NULL) {
		// requested language not found, use first available
		if (nameResources->NumberOfIdEntries == 0) {
			SetLastError(ERROR_RESOURCE_LANG_NOT_FOUND);
			return NULL;
		}

		foundLanguage = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(nameResources + 1);
	}

	PIMAGE_RESOURCE_DATA_ENTRY entry = RVA(PIMAGE_RESOURCE_DATA_ENTRY, hModule, dataDir->VirtualAddress + (foundLanguage->OffsetToData & 0x7fffffff));
	if (entry == NULL || !entry->OffsetToData) {
		return NULL;
	}

	return new std::string(RVA(LPSTR, hModule, entry->OffsetToData), entry->Size);
}

@funoverip
Copy link
Contributor

Hi Nick,

I had the exact same issue. Once loaded, I couldn't use FindResource() anymore.

But your workaround (#24 (comment)) worked like charms :)

Thanks!.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants