sRDI
sRDI copied to clipboard
.rsrc section does not behave as expected
DLLs cannot use FindResource when converted into shellcode. Same code works when not loaded using sRDI. Issue seems to be the same as https://github.com/TheWover/donut/issues/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.
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);
...
}
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);
}
Hi Nick,
I had the exact same issue. Once loaded, I couldn't use FindResource()
anymore.
But your workaround (https://github.com/monoxgas/sRDI/issues/24#issuecomment-972201094) worked like charms :)
Thanks!.