aboutsummaryrefslogtreecommitdiff
path: root/runtime/resource_manager.cc
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/resource_manager.cc')
-rw-r--r--runtime/resource_manager.cc1022
1 files changed, 1022 insertions, 0 deletions
diff --git a/runtime/resource_manager.cc b/runtime/resource_manager.cc
new file mode 100644
index 0000000..ca9ed3d
--- /dev/null
+++ b/runtime/resource_manager.cc
@@ -0,0 +1,1022 @@
+#include "common.h"
+#include "objects.h"
+
+#ifdef WIN_DRIVER
+typedef BOOL (WINAPI *ENUMRESNAMEPROCA)(HMODULE hModule, LPCSTR lpType, LPSTR lpName, LONG_PTR lParam);
+typedef BOOL (WINAPI *ENUMRESNAMEPROCW)(HMODULE hModule, LPCWSTR lpType, LPWSTR lpName, LONG_PTR lParam);
+typedef BOOL (WINAPI *ENUMRESLANGPROCA)(HMODULE hModule, LPCSTR lpType, LPCSTR lpName, WORD wLanguage, LONG_PTR lParam);
+typedef BOOL (WINAPI *ENUMRESLANGPROCW)(HMODULE hModule, LPCWSTR lpType, LPCWSTR lpName, WORD wLanguage, LONG_PTR lParam);
+typedef BOOL (WINAPI *ENUMRESTYPEPROCA)(HMODULE hModule, LPSTR lpType, LONG_PTR lParam);
+typedef BOOL (WINAPI *ENUMRESTYPEPROCW)(HMODULE hModule, LPWSTR lpType, LONG_PTR lParam);
+#else
+#include "core.h"
+#include "crypto.h"
+#include "resource_manager.h"
+#include "hook_manager.h"
+#include "utils.h"
+#endif
+
+/**
+ * exported functions
+ */
+
+HGLOBAL WINAPI ExportedLoadResource(HMODULE module, HRSRC res_info)
+{
+#ifdef WIN_DRIVER
+ return NULL;
+#else
+ ResourceManager *resource_manager = Core::Instance()->resource_manager();
+ return resource_manager ? resource_manager->LoadResource(module, res_info) : NULL;
+#endif
+}
+
+HRSRC WINAPI ExportedFindResourceA(HMODULE module, LPCSTR name, LPCSTR type)
+{
+#ifdef WIN_DRIVER
+ return NULL;
+#else
+ ResourceManager *resource_manager = Core::Instance()->resource_manager();
+ return resource_manager ? resource_manager->FindResourceA(module, name, type) : NULL;
+#endif
+}
+
+HRSRC WINAPI ExportedFindResourceExA(HMODULE module, LPCSTR type, LPCSTR name, WORD language)
+{
+#ifdef WIN_DRIVER
+ return NULL;
+#else
+ ResourceManager *resource_manager = Core::Instance()->resource_manager();
+ return resource_manager ? resource_manager->FindResourceExA(module, type, name, language) : NULL;
+#endif
+}
+
+HRSRC WINAPI ExportedFindResourceW(HMODULE module, LPCWSTR name, LPCWSTR type)
+{
+#ifdef WIN_DRIVER
+ return NULL;
+#else
+ ResourceManager *resource_manager = Core::Instance()->resource_manager();
+ return resource_manager ? resource_manager->FindResourceExW(module, type, name, 0) : NULL;
+#endif
+}
+
+HRSRC WINAPI ExportedFindResourceExW(HMODULE module, LPCWSTR type, LPCWSTR name, WORD language)
+{
+#ifdef WIN_DRIVER
+ return NULL;
+#else
+ ResourceManager *resource_manager = Core::Instance()->resource_manager();
+ return resource_manager ? resource_manager->FindResourceExW(module, type, name, language) : NULL;
+#endif
+}
+
+int WINAPI ExportedLoadStringA(HMODULE module, UINT id, LPSTR buffer, int buffer_max)
+{
+#ifdef WIN_DRIVER
+ return 0;
+#else
+ ResourceManager *resource_manager = Core::Instance()->resource_manager();
+ return resource_manager ? resource_manager->LoadStringA(module, id, buffer, buffer_max) : 0;
+#endif
+}
+
+int WINAPI ExportedLoadStringW(HMODULE module, UINT id, LPWSTR buffer, int buffer_max)
+{
+#ifdef WIN_DRIVER
+ return 0;
+#else
+ ResourceManager *resource_manager = Core::Instance()->resource_manager();
+ return resource_manager ? resource_manager->LoadStringW(module, id, buffer, buffer_max) : 0;
+#endif
+}
+
+BOOL WINAPI ExportedEnumResourceNamesA(HMODULE module, LPCSTR type, ENUMRESNAMEPROCA enum_func, LONG_PTR param)
+{
+#ifdef WIN_DRIVER
+ return FALSE;
+#else
+ ResourceManager *resource_manager = Core::Instance()->resource_manager();
+ return resource_manager ? resource_manager->EnumResourceNamesA(module, type, enum_func, param) : FALSE;
+#endif
+}
+
+BOOL WINAPI ExportedEnumResourceNamesW(HMODULE module, LPCWSTR type, ENUMRESNAMEPROCW enum_func, LONG_PTR param)
+{
+#ifdef WIN_DRIVER
+ return FALSE;
+#else
+ ResourceManager *resource_manager = Core::Instance()->resource_manager();
+ return resource_manager ? resource_manager->EnumResourceNamesW(module, type, enum_func, param) : FALSE;
+#endif
+}
+
+BOOL WINAPI ExportedEnumResourceLanguagesA(HMODULE module, LPCSTR type, LPCSTR name, ENUMRESLANGPROCA enum_func, LONG_PTR param)
+{
+#ifdef WIN_DRIVER
+ return FALSE;
+#else
+ ResourceManager *resource_manager = Core::Instance()->resource_manager();
+ return resource_manager ? resource_manager->EnumResourceLanguagesA(module, type, name, enum_func, param) : FALSE;
+#endif
+}
+
+BOOL WINAPI ExportedEnumResourceLanguagesW(HMODULE module, LPCWSTR type, LPCWSTR name, ENUMRESLANGPROCW enum_func, LONG_PTR param)
+{
+#ifdef WIN_DRIVER
+ return FALSE;
+#else
+ ResourceManager *resource_manager = Core::Instance()->resource_manager();
+ return resource_manager ? resource_manager->EnumResourceLanguagesW(module, type, name, enum_func, param) : FALSE;
+#endif
+}
+
+BOOL WINAPI ExportedEnumResourceTypesA(HMODULE module, ENUMRESTYPEPROCA enum_func, LONG_PTR param)
+{
+#ifdef WIN_DRIVER
+ return FALSE;
+#else
+ ResourceManager *resource_manager = Core::Instance()->resource_manager();
+ return resource_manager ? resource_manager->EnumResourceTypesA(module, enum_func, param) : FALSE;
+#endif
+}
+
+BOOL WINAPI ExportedEnumResourceTypesW(HMODULE module, ENUMRESTYPEPROCW enum_func, LONG_PTR param)
+{
+#ifdef WIN_DRIVER
+ return FALSE;
+#else
+ ResourceManager *resource_manager = Core::Instance()->resource_manager();
+ return resource_manager ? resource_manager->EnumResourceTypesW(module, enum_func, param) : FALSE;
+#endif
+}
+
+#ifdef WIN_DRIVER
+#else
+/**
+ * hooked functions
+ */
+
+int WINAPI HookedLoadStringA(HMODULE module, UINT id, LPSTR buffer, int buffer_max)
+{
+ ResourceManager *resource_manager = Core::Instance()->resource_manager();
+ return resource_manager->LoadStringA(module, id, buffer, buffer_max);
+}
+
+int WINAPI HookedLoadStringW(HMODULE module, UINT id, LPWSTR buffer, int buffer_max)
+{
+ ResourceManager *resource_manager = Core::Instance()->resource_manager();
+ return resource_manager->LoadStringW(module, id, buffer, buffer_max);
+}
+
+NTSTATUS WINAPI HookedLdrFindResource_U(HMODULE module, const LDR_RESOURCE_INFO *res_info, ULONG level, const IMAGE_RESOURCE_DATA_ENTRY **entry)
+{
+ ResourceManager *resource_manager = Core::Instance()->resource_manager();
+ return resource_manager->LdrFindResource_U(module, res_info, level, entry);
+}
+
+NTSTATUS WINAPI HookedLdrAccessResource(HMODULE module, const IMAGE_RESOURCE_DATA_ENTRY *entry, void **res, ULONG *size)
+{
+ ResourceManager *resource_manager = Core::Instance()->resource_manager();
+ return resource_manager->LdrAccessResource(module, entry, res, size);
+}
+
+/**
+ * ResourceManager
+ */
+
+ResourceManager::ResourceManager(const uint8_t *data, HMODULE instance, const uint8_t *key)
+ : instance_(instance)
+ , data_(data)
+ , load_resource_(NULL)
+ , load_string_a_(NULL)
+ , load_string_w_(NULL)
+ , load_string_a_kernel_(NULL)
+ , load_string_w_kernel_(NULL)
+ , ldr_find_resource_u_(NULL)
+ , ldr_access_resource_(NULL)
+ , get_thread_ui_language_(NULL)
+{
+ CriticalSection::Init(critical_section_);
+ key_ = *(reinterpret_cast<const uint32_t *>(key));
+ HMODULE dll = GetModuleHandleA(VMProtectDecryptStringA("kernel32.dll"));
+ if (dll)
+ get_thread_ui_language_ = InternalGetProcAddress(dll, VMProtectDecryptStringA("GetThreadUILanguage"));
+}
+
+ResourceManager::~ResourceManager()
+{
+ CriticalSection::Free(critical_section_);
+}
+
+void ResourceManager::HookAPIs(HookManager &hook_manager)
+{
+ hook_manager.Begin();
+ HMODULE dll = GetModuleHandleA(VMProtectDecryptStringA("ntdll.dll"));
+ ldr_find_resource_u_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("LdrFindResource_U"), &HookedLdrFindResource_U);
+ ldr_access_resource_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("LdrAccessResource"), &HookedLdrAccessResource);
+ dll = GetModuleHandleA(VMProtectDecryptStringA("user32.dll"));
+ load_string_a_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("LoadStringA"), &HookedLoadStringA);
+ load_string_w_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("LoadStringW"), &HookedLoadStringW);
+ dll = GetModuleHandleA(VMProtectDecryptStringA("kernelbase.dll"));
+ if (dll) {
+ load_string_a_kernel_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("LoadStringA"), &HookedLoadStringA);
+ load_string_w_kernel_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("LoadStringW"), &HookedLoadStringW);
+ }
+ hook_manager.End();
+}
+
+void ResourceManager::UnhookAPIs(HookManager &hook_manager)
+{
+ hook_manager.Begin();
+ hook_manager.UnhookAPI(ldr_find_resource_u_);
+ hook_manager.UnhookAPI(ldr_access_resource_);
+ hook_manager.UnhookAPI(load_string_a_);
+ hook_manager.UnhookAPI(load_string_w_);
+ if (load_string_a_kernel_) {
+ hook_manager.UnhookAPI(load_string_a_kernel_);
+ hook_manager.UnhookAPI(load_string_w_kernel_);
+ }
+ hook_manager.End();
+}
+
+int __forceinline ResourceManager::TrueLoadStringA(HMODULE module, UINT id, LPSTR buffer, int buffer_max)
+{
+ typedef int (WINAPI tLoadStringA)(HMODULE module, UINT id, LPSTR buffer, int buffer_max);
+ return reinterpret_cast<tLoadStringA *>(load_string_a_)(module, id, buffer, buffer_max);
+}
+
+int __forceinline ResourceManager::TrueLoadStringW(HMODULE module, UINT id, LPWSTR buffer, int buffer_max)
+{
+ typedef int (WINAPI tLoadStringW)(HMODULE module, UINT id, LPWSTR buffer, int buffer_max);
+ return reinterpret_cast<tLoadStringW *>(load_string_w_)(module, id, buffer, buffer_max);
+}
+
+NTSTATUS __forceinline ResourceManager::TrueLdrFindResource_U(HMODULE module, const LDR_RESOURCE_INFO *res_info, ULONG level, const IMAGE_RESOURCE_DATA_ENTRY **entry)
+{
+ typedef int (WINAPI tLdrFindResource_U)(HMODULE module, const LDR_RESOURCE_INFO *res_info, ULONG level, const IMAGE_RESOURCE_DATA_ENTRY **entry);
+ return reinterpret_cast<tLdrFindResource_U *>(ldr_find_resource_u_)(module, res_info, level, entry);
+}
+
+NTSTATUS __forceinline ResourceManager::TrueLdrAccessResource(HMODULE module, const IMAGE_RESOURCE_DATA_ENTRY *entry, void **res, ULONG *size)
+{
+ typedef int (WINAPI tLdrAccessResource)(HMODULE module, const IMAGE_RESOURCE_DATA_ENTRY *pEntry, void **pRes, ULONG *pSize);
+ return reinterpret_cast<tLdrAccessResource *>(ldr_access_resource_)(module, entry, res, size);
+}
+
+HGLOBAL ResourceManager::InternalLoadResource(HMODULE module, HRSRC res_info)
+{
+ if (!module)
+ module = GetModuleHandle(NULL);
+
+ if (module == instance_) {
+ CriticalSection cs(critical_section_);
+
+ size_t i = resources_.IndexByHandle(res_info);
+ if (i != -1)
+ return resources_[i]->Decrypt(instance_, key_);
+ }
+ return NULL;
+}
+
+HGLOBAL ResourceManager::LoadResource(HMODULE module, HRSRC res_info)
+{
+ HGLOBAL res = InternalLoadResource(module, res_info);
+ if (res)
+ return res;
+ return ::LoadResource(module, res_info);
+}
+
+HRSRC ResourceManager::InternalFindResourceExW(HMODULE module, LPCWSTR type, LPCWSTR name, WORD language)
+{
+ if (!module)
+ module = GetModuleHandle(NULL);
+
+ if (module == instance_) {
+ const RESOURCE_DATA_ENTRY *entry_enc = reinterpret_cast<const RESOURCE_DATA_ENTRY *>(FindResourceEntry(type, name, language));
+ if (entry_enc) {
+ CriticalSection cs(critical_section_);
+
+ size_t i = resources_.IndexByEntry(entry_enc);
+ if (i != -1)
+ return resources_[i]->handle();
+
+ return resources_.Add(entry_enc, key_)->handle();
+ }
+ }
+ return NULL;
+}
+
+BOOL CreateResourceName(LPCWSTR src, LPWSTR &dst)
+{
+ if (IS_INTRESOURCE(src)) {
+ dst = MAKEINTRESOURCEW(LOWORD(src));
+ return TRUE;
+ }
+
+ if (src[0] == L'#') {
+ ULONG value = wcstoul(src + 1, NULL, 10);
+ if (HIWORD(value))
+ return FALSE;
+ dst = MAKEINTRESOURCEW(value);
+ return TRUE;
+ }
+
+ size_t len = wcslen(src);
+ dst = new wchar_t[len + 1];
+ wcscpy_s(dst, len + 1, src);
+ CharUpperBuffW(dst, static_cast<DWORD>(len));
+ return TRUE;
+}
+
+BOOL CreateResourceName(LPCSTR src, LPWSTR &dst)
+{
+ if (IS_INTRESOURCE(src)) {
+ dst = MAKEINTRESOURCEW(LOWORD(src));
+ return TRUE;
+ }
+
+ if (src[0] == '#') {
+ ULONG value = strtoul(src + 1, NULL, 10);
+ if (HIWORD(value))
+ return FALSE;
+ dst = MAKEINTRESOURCEW(value);
+ return TRUE;
+ }
+
+ int size = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
+ if (size == 0)
+ return FALSE;
+ dst = new wchar_t[size];
+ int size2 = MultiByteToWideChar(CP_ACP, 0, src, -1, dst, size);
+ CharUpperBuffW(dst, static_cast<DWORD>(size2));
+ return TRUE;
+}
+
+void FreeResourceName(LPCWSTR src)
+{
+ if (!IS_INTRESOURCE(src))
+ delete [] src;
+}
+
+HRSRC ResourceManager::FindResourceExW(HMODULE module, LPCWSTR type, LPCWSTR name, WORD language)
+{
+ if (!module)
+ module = GetModuleHandle(NULL);
+
+ if (module == instance_) {
+ LPWSTR new_type = NULL;
+ LPWSTR new_name = NULL;
+ HRSRC res;
+
+ if (CreateResourceName(type, new_type) && CreateResourceName(name, new_name)) {
+ res = InternalFindResourceExW(module, new_type, new_name, language);
+ } else {
+ res = NULL;
+ }
+
+ FreeResourceName(new_type);
+ FreeResourceName(new_name);
+
+ if (res)
+ return res;
+ }
+ return ::FindResourceExW(module, type, name, language);
+}
+
+HRSRC ResourceManager::FindResourceW(HMODULE module, LPCWSTR name, LPCWSTR type)
+{
+ return FindResourceExW(module, type, name, 0);
+}
+
+HRSRC ResourceManager::FindResourceExA(HMODULE module, LPCSTR type, LPCSTR name, WORD language)
+{
+ if (!module)
+ module = GetModuleHandle(NULL);
+
+ if (module == instance_) {
+ LPWSTR new_type = NULL;
+ LPWSTR new_name = NULL;
+ HRSRC res;
+
+ if (CreateResourceName(type, new_type) && CreateResourceName(name, new_name)) {
+ res = FindResourceExW(module, new_type, new_name, language);
+ } else {
+ res = NULL;
+ }
+
+ FreeResourceName(new_name);
+ FreeResourceName(new_type);
+
+ if (res)
+ return res;
+ }
+ return ::FindResourceExA(module, type, name, language);
+}
+
+HRSRC ResourceManager::FindResourceA(HMODULE module, LPCSTR name, LPCSTR type)
+{
+ return FindResourceExA(module, type, name, 0);
+}
+
+RESOURCE_DIRECTORY ResourceManager::DecryptDirectory(const RESOURCE_DIRECTORY *directory_enc) const
+{
+ RESOURCE_DIRECTORY res;
+ res.NumberOfNamedEntries = directory_enc->NumberOfNamedEntries ^ key_;
+ res.NumberOfIdEntries = directory_enc->NumberOfIdEntries ^ key_;
+ return res;
+}
+
+RESOURCE_DIRECTORY_ENTRY ResourceManager::DecryptDirectoryEntry(const RESOURCE_DIRECTORY_ENTRY *entry_enc) const
+{
+ RESOURCE_DIRECTORY_ENTRY res;
+ res.Name = entry_enc->Name ^ key_;
+ res.OffsetToData = entry_enc->OffsetToData ^ key_;
+ return res;
+}
+
+const RESOURCE_DIRECTORY *ResourceManager::FindEntryById(const RESOURCE_DIRECTORY *directory_enc, WORD id, DWORD dir_type)
+{
+ const RESOURCE_DIRECTORY_ENTRY *entry_enc = reinterpret_cast<const RESOURCE_DIRECTORY_ENTRY *>(directory_enc + 1);
+
+ RESOURCE_DIRECTORY directory = DecryptDirectory(directory_enc);
+ int min = directory.NumberOfNamedEntries;
+ int max = min + directory.NumberOfIdEntries - 1;
+
+ while (min <= max) {
+ int i = (min + max) / 2;
+ RESOURCE_DIRECTORY_ENTRY entry = DecryptDirectoryEntry(&entry_enc[i]);
+ if (entry.Id == id) {
+ if (entry.DataIsDirectory == dir_type)
+ return reinterpret_cast<const RESOURCE_DIRECTORY *>(data_ + entry.OffsetToDirectory);
+ break;
+ }
+ if (entry.Id > id) {
+ max = i - 1;
+ } else {
+ min = i + 1;
+ }
+ }
+ return NULL;
+}
+
+int ResourceManager::CompareStringEnc(LPCWSTR name, LPCWSTR str_enc) const
+{
+ for (size_t i = 0; ;i++) {
+ wchar_t c = static_cast<wchar_t>(str_enc[i] ^ (_rotl32(key_, static_cast<int>(i)) + i));
+ int res = name[i] - c;
+ if (res)
+ return (res < 0) ? -1 : 1;
+ if (!name[i])
+ break;
+ }
+ return 0;
+}
+
+LPWSTR ResourceManager::DecryptStringW(LPCWSTR str_enc) const
+{
+ size_t len = 0;
+ while (true) {
+ wchar_t c = static_cast<wchar_t>(str_enc[len] ^ (_rotl32(key_, static_cast<int>(len)) + len));
+ len++;
+ if (!c)
+ break;
+ }
+
+ LPWSTR res = new wchar_t[len];
+ for (size_t i = 0; i < len; i++) {
+ res[i] = static_cast<wchar_t>(str_enc[i] ^ (_rotl32(key_, static_cast<int>(i)) + i));
+ }
+ return res;
+}
+
+LPSTR ResourceManager::DecryptStringA(LPCWSTR str_enc) const
+{
+ LPWSTR str = DecryptStringW(str_enc);
+ int len = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
+ LPSTR res = new char[len];
+ WideCharToMultiByte(CP_ACP, 0, str, -1, res, len, NULL, NULL);
+ delete [] str;
+ return res;
+}
+
+const RESOURCE_DIRECTORY *ResourceManager::FindEntryByName(const RESOURCE_DIRECTORY *directory_enc, LPCWSTR name, DWORD dir_type)
+{
+ const RESOURCE_DIRECTORY_ENTRY *entry_enc = reinterpret_cast<const RESOURCE_DIRECTORY_ENTRY *>(directory_enc + 1);
+ RESOURCE_DIRECTORY directory = DecryptDirectory(directory_enc);
+
+ int min = 0;
+ int max = directory.NumberOfNamedEntries - 1;
+
+ while (min <= max) {
+ int i = (min + max) / 2;
+ RESOURCE_DIRECTORY_ENTRY entry = DecryptDirectoryEntry(&entry_enc[i]);
+ int res = CompareStringEnc(name, reinterpret_cast<LPCWSTR>(data_ + entry.NameOffset));
+ if (!res) {
+ if (entry.DataIsDirectory == dir_type)
+ return reinterpret_cast<const RESOURCE_DIRECTORY *>(data_ + entry.OffsetToDirectory);
+ break;
+ }
+ if (res < 0) {
+ max = i - 1;
+ } else {
+ min = i + 1;
+ }
+ }
+ return NULL;
+}
+
+const RESOURCE_DIRECTORY *ResourceManager::FindEntry(const RESOURCE_DIRECTORY *directory_enc, LPCWSTR name, DWORD dir_type)
+{
+ if (IS_INTRESOURCE(name))
+ return FindEntryById(directory_enc, LOWORD(name), dir_type);
+ return FindEntryByName(directory_enc, name, dir_type);
+}
+
+const RESOURCE_DIRECTORY *ResourceManager::FindFirstEntry(const RESOURCE_DIRECTORY *directory_enc, DWORD dir_type)
+{
+ const RESOURCE_DIRECTORY_ENTRY *entry_enc = reinterpret_cast<const RESOURCE_DIRECTORY_ENTRY *>(directory_enc + 1);
+ RESOURCE_DIRECTORY directory = DecryptDirectory(directory_enc);
+
+ for (size_t i = 0; i < directory.NumberOfNamedEntries + directory.NumberOfIdEntries; i++) {
+ RESOURCE_DIRECTORY_ENTRY entry = DecryptDirectoryEntry(&entry_enc[i]);
+ if (entry.DataIsDirectory == dir_type)
+ return reinterpret_cast<const RESOURCE_DIRECTORY *>(data_ + entry.OffsetToDirectory);
+ }
+ return NULL;
+}
+
+const RESOURCE_DIRECTORY *ResourceManager::FindResourceEntry(LPCWSTR type, LPCWSTR name, WORD language)
+{
+ if (!data_)
+ return NULL;
+
+ size_t i, j;
+
+ const RESOURCE_DIRECTORY *directory = reinterpret_cast<const RESOURCE_DIRECTORY *>(data_);
+
+ for (i = 0; i < 2; i++){
+ LPCWSTR value = (!i) ? type : name;
+ directory = FindEntry(directory, value, TRUE);
+ if (!directory)
+ return NULL;
+ }
+
+ LANGID lang_list[10];
+ size_t lang_count = 0;
+
+ /* specified language */
+ lang_list[lang_count++] = language;
+
+ /* specified language with neutral sublanguage */
+ lang_list[lang_count++] = MAKELANGID(PRIMARYLANGID(language), SUBLANG_NEUTRAL);
+
+ /* neutral language with neutral sublanguage */
+ lang_list[lang_count++] = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
+
+ /* if no explicitly specified language, try some defaults */
+ if (PRIMARYLANGID(language) == LANG_NEUTRAL) {
+ /* user defaults, unless SYS_DEFAULT sublanguage specified */
+ if (SUBLANGID(language) != SUBLANG_SYS_DEFAULT) {
+ if (get_thread_ui_language_) {
+ typedef LANGID(WINAPI tGetThreadUILanguage)();
+ lang_list[lang_count++] = reinterpret_cast<tGetThreadUILanguage *>(get_thread_ui_language_)();
+ }
+
+ /* current thread locale language */
+ lang_list[lang_count++] = LANGIDFROMLCID(GetThreadLocale());
+
+ /* user locale language */
+ lang_list[lang_count++] = LANGIDFROMLCID(GetUserDefaultLCID());
+
+ /* user locale language with neutral sublanguage */
+ lang_list[lang_count++] = MAKELANGID(PRIMARYLANGID(GetUserDefaultLCID()), SUBLANG_NEUTRAL);
+ }
+
+ /* now system defaults */
+
+ /* system locale language */
+ lang_list[lang_count++] = LANGIDFROMLCID(GetSystemDefaultLCID());
+
+ /* system locale language with neutral sublanguage */
+ lang_list[lang_count++] = MAKELANGID(PRIMARYLANGID(GetSystemDefaultLCID()), SUBLANG_NEUTRAL);
+
+ /* English */
+ lang_list[lang_count++] = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
+ }
+
+ for (i = 0; i < lang_count; i++) {
+ LANGID lang = lang_list[i];
+ bool is_processed = false;
+ for (j = 0; j < i; j++) {
+ if (lang_list[j] == lang) {
+ is_processed = true;
+ break;
+ }
+ }
+ if (is_processed)
+ continue;
+
+ if (const RESOURCE_DIRECTORY *entry = FindEntryById(directory, lang, FALSE))
+ return entry;
+ }
+
+ return FindFirstEntry(directory, FALSE);
+}
+
+LPWSTR ResourceManager::InternalFindStringResource(HMODULE module, UINT id)
+{
+ HRSRC res_info = InternalFindResourceExW(module, LPWSTR(RT_STRING), MAKEINTRESOURCEW((LOWORD(id) >> 4) + 1),
+ 0);
+ if (!res_info)
+ return NULL;
+
+ LPWSTR res = reinterpret_cast<LPWSTR>(InternalLoadResource(module, res_info));
+ if (!res)
+ return NULL;
+
+ IMAGE_RESOURCE_DATA_ENTRY *entry = reinterpret_cast<IMAGE_RESOURCE_DATA_ENTRY *>(res_info);
+ UINT res_size = entry->Size / sizeof(wchar_t);
+ UINT size = 0;
+ UINT str_len = 0;
+
+ for (int i = id & 0x000f; i >= 0; i--) {
+ str_len = res[size] + 1;
+ size += str_len;
+ if (size > res_size)
+ return NULL;
+ }
+
+ return (res + size - str_len);
+}
+
+int ResourceManager::InternalLoadStringW(LPCWSTR res, LPWSTR buffer, int buffer_max)
+{
+ if (!buffer || (buffer_max < 0))
+ return 0;
+
+ if (buffer_max == 0) {
+ *(reinterpret_cast<LPCWSTR *>(buffer)) = res + 1;
+ return *res;
+ }
+
+ int i = std::min<int>(buffer_max - 1, *res);
+ if (i > 0) {
+ memcpy(buffer, res + 1, i * sizeof (WCHAR));
+ buffer[i] = 0;
+ return i;
+ }
+ if (buffer_max > 0)
+ buffer[0] = 0;
+ return 0;
+}
+
+int ResourceManager::InternalLoadStringA(LPCWSTR res, LPSTR buffer, int buffer_max)
+{
+ if (!buffer || (buffer_max <= 0))
+ return 0;
+
+ int i = WideCharToMultiByte(CP_ACP, 0, res + 1, *res, NULL, 0, NULL, NULL);
+ if (i > 0) {
+ if (i > buffer_max - 1) {
+ LPSTR str = new char[i];
+ i = std::min(buffer_max - 1, WideCharToMultiByte(CP_ACP, 0, res + 1, *res, str, i, NULL, NULL));
+ memcpy(buffer, str, i * sizeof (CHAR));
+ delete [] str;
+ } else {
+ i = WideCharToMultiByte(CP_ACP, 0, res + 1, *res, buffer, buffer_max - 1, NULL, NULL);
+ }
+ buffer[i] = 0;
+ return i;
+ }
+ if (buffer_max > 0)
+ buffer[0] = 0;
+ return 0;
+}
+
+int ResourceManager::LoadStringA(HMODULE module, UINT uID, LPSTR buffer, int buffer_max)
+{
+ LPWSTR res = InternalFindStringResource(module, uID);
+ if (res)
+ return InternalLoadStringA(res, buffer, buffer_max);
+ return TrueLoadStringA(module, uID, buffer, buffer_max);
+}
+
+int ResourceManager::LoadStringW(HMODULE module, UINT id, LPWSTR buffer, int buffer_max)
+{
+ LPWSTR res = InternalFindStringResource(module, id);
+ if (res)
+ return InternalLoadStringW(res, buffer, buffer_max);
+ return TrueLoadStringW(module, id, buffer, buffer_max);
+}
+
+NTSTATUS ResourceManager::LdrFindResource_U(HMODULE module, const LDR_RESOURCE_INFO *res_info, ULONG level, const IMAGE_RESOURCE_DATA_ENTRY **entry)
+{
+ if (level == 3) {
+ HRSRC res = InternalFindResourceExW(module, res_info->Type, res_info->Name, res_info->Language);
+ if (res) {
+ *entry = reinterpret_cast<IMAGE_RESOURCE_DATA_ENTRY *>(res);
+ return 0;
+ }
+ }
+ return TrueLdrFindResource_U(module, res_info, level, entry);
+}
+
+NTSTATUS ResourceManager::LdrAccessResource(HMODULE module, const IMAGE_RESOURCE_DATA_ENTRY *entry, void **res, ULONG *size)
+{
+ HGLOBAL h = InternalLoadResource(module, (HRSRC)entry);
+ if (h) {
+ if (res)
+ *res = h;
+ if (size)
+ *size = entry->Size;
+ return 0;
+ }
+ return TrueLdrAccessResource(module, entry, res, size);
+}
+
+BOOL ResourceManager::EnumResourceNamesA(HMODULE module, LPCSTR type, ENUMRESNAMEPROCA enum_func, LONG_PTR param)
+{
+ if (!module)
+ module = GetModuleHandle(NULL);
+
+ if (module == instance_) {
+ LPWSTR new_type = NULL;
+ const RESOURCE_DIRECTORY *directory_enc;
+
+ if (CreateResourceName(type, new_type)) {
+ directory_enc = FindEntry(reinterpret_cast<const RESOURCE_DIRECTORY *>(data_), new_type, TRUE);
+ } else {
+ directory_enc = NULL;
+ }
+ FreeResourceName(new_type);
+
+ if (directory_enc) {
+ const RESOURCE_DIRECTORY_ENTRY *entry_enc = reinterpret_cast<const RESOURCE_DIRECTORY_ENTRY *>(directory_enc + 1);
+ RESOURCE_DIRECTORY directory = DecryptDirectory(directory_enc);
+ for (size_t i = 0; i < directory.NumberOfNamedEntries + directory.NumberOfIdEntries; i++) {
+ RESOURCE_DIRECTORY_ENTRY entry = DecryptDirectoryEntry(&entry_enc[i]);
+ BOOL res;
+ if (entry.NameIsString) {
+ LPSTR name = DecryptStringA(reinterpret_cast<LPCWSTR>(data_ + entry.NameOffset));
+ res = enum_func(module, type, name, param);
+ delete [] name;
+ } else {
+ res = enum_func(module, type, MAKEINTRESOURCEA(entry.Id), param);
+ }
+
+ if (!res)
+ break;
+ }
+ return TRUE;
+ }
+ }
+ return ::EnumResourceNamesA(module, type, enum_func, param);
+}
+
+BOOL ResourceManager::EnumResourceNamesW(HMODULE module, LPCWSTR type, ENUMRESNAMEPROCW enum_func, LONG_PTR param)
+{
+ if (!module)
+ module = GetModuleHandle(NULL);
+
+ if (module == instance_) {
+ LPWSTR new_type = NULL;
+ const RESOURCE_DIRECTORY *directory_enc;
+
+ if (CreateResourceName(type, new_type)) {
+ directory_enc = FindEntry(reinterpret_cast<const RESOURCE_DIRECTORY *>(data_), new_type, TRUE);
+ } else {
+ directory_enc = NULL;
+ }
+ FreeResourceName(new_type);
+
+ if (directory_enc) {
+ const RESOURCE_DIRECTORY_ENTRY *entry_enc = reinterpret_cast<const RESOURCE_DIRECTORY_ENTRY *>(directory_enc + 1);
+ RESOURCE_DIRECTORY directory = DecryptDirectory(directory_enc);
+ for (size_t i = 0; i < directory.NumberOfNamedEntries + directory.NumberOfIdEntries; i++) {
+ RESOURCE_DIRECTORY_ENTRY entry = DecryptDirectoryEntry(&entry_enc[i]);
+ BOOL res;
+ if (entry.NameIsString) {
+ LPWSTR name = DecryptStringW(reinterpret_cast<LPCWSTR>(data_ + entry.NameOffset));
+ res = enum_func(module, type, name, param);
+ delete [] name;
+ } else {
+ res = enum_func(module, type, MAKEINTRESOURCEW(entry.Id), param);
+ }
+
+ if (!res)
+ break;
+ }
+ return TRUE;
+ }
+ }
+ return ::EnumResourceNamesW(module, type, enum_func, param);
+}
+
+BOOL ResourceManager::EnumResourceLanguagesA(HMODULE module, LPCSTR type, LPCSTR name, ENUMRESLANGPROCA enum_func, LONG_PTR param)
+{
+ if (!module)
+ module = GetModuleHandle(NULL);
+
+ if (module == instance_) {
+ const RESOURCE_DIRECTORY *directory_enc = reinterpret_cast<const RESOURCE_DIRECTORY *>(data_);
+
+ for (size_t i = 0; i < 2; i++) {
+ LPWSTR value = NULL;
+ if (CreateResourceName((!i) ? type : name, value)) {
+ directory_enc = FindEntry(directory_enc, value, TRUE);
+ } else {
+ directory_enc = NULL;
+ }
+
+ FreeResourceName(value);
+
+ if (!directory_enc)
+ break;
+ }
+
+ if (directory_enc) {
+ const RESOURCE_DIRECTORY_ENTRY *entry_enc = reinterpret_cast<const RESOURCE_DIRECTORY_ENTRY *>(directory_enc + 1);
+ RESOURCE_DIRECTORY directory = DecryptDirectory(directory_enc);
+ for (size_t i = 0; i < directory.NumberOfNamedEntries + directory.NumberOfIdEntries; i++) {
+ RESOURCE_DIRECTORY_ENTRY entry = DecryptDirectoryEntry(&entry_enc[i]);
+ if (!enum_func(module, type, name, entry.Id, param))
+ break;
+ }
+ return TRUE;
+ }
+ }
+ return ::EnumResourceLanguagesA(module, type, name, enum_func, param);
+}
+
+BOOL ResourceManager::EnumResourceLanguagesW(HMODULE module, LPCWSTR type, LPCWSTR name, ENUMRESLANGPROCW enum_func, LONG_PTR param)
+{
+ if (!module)
+ module = GetModuleHandle(NULL);
+
+ if (module == instance_) {
+ const RESOURCE_DIRECTORY *directory_enc = reinterpret_cast<const RESOURCE_DIRECTORY *>(data_);
+
+ for (size_t i = 0; i < 2; i++) {
+ LPWSTR value = NULL;
+ if (CreateResourceName((!i) ? type : name, value)) {
+ directory_enc = FindEntry(directory_enc, value, TRUE);
+ } else {
+ directory_enc = NULL;
+ }
+
+ FreeResourceName(value);
+
+ if (!directory_enc)
+ break;
+ }
+
+ if (directory_enc) {
+ const RESOURCE_DIRECTORY_ENTRY *entry_enc = reinterpret_cast<const RESOURCE_DIRECTORY_ENTRY *>(directory_enc + 1);
+ RESOURCE_DIRECTORY directory = DecryptDirectory(directory_enc);
+ for (size_t i = 0; i < directory.NumberOfNamedEntries + directory.NumberOfIdEntries; i++) {
+ RESOURCE_DIRECTORY_ENTRY entry = DecryptDirectoryEntry(&entry_enc[i]);
+ if (!enum_func(module, type, name, entry.Id, param))
+ break;
+ }
+ return TRUE;
+ }
+ }
+ return ::EnumResourceLanguagesW(module, type, name, enum_func, param);
+}
+
+BOOL ResourceManager::EnumResourceTypesA(HMODULE module, ENUMRESTYPEPROCA enum_func, LONG_PTR param)
+{
+ if (!module)
+ module = GetModuleHandle(NULL);
+
+ if (module == instance_) {
+ const RESOURCE_DIRECTORY *directory_enc = reinterpret_cast<const RESOURCE_DIRECTORY *>(data_);
+ const RESOURCE_DIRECTORY_ENTRY *entry_enc = reinterpret_cast<const RESOURCE_DIRECTORY_ENTRY *>(directory_enc + 1);
+ RESOURCE_DIRECTORY directory = DecryptDirectory(directory_enc);
+ for (size_t i = 0; i < directory.NumberOfNamedEntries + directory.NumberOfIdEntries; i++) {
+ RESOURCE_DIRECTORY_ENTRY entry = DecryptDirectoryEntry(&entry_enc[i]);
+ BOOL res;
+ if (entry.NameIsString) {
+ LPSTR type = DecryptStringA(reinterpret_cast<LPCWSTR>(data_ + entry.NameOffset));
+ res = enum_func(module, type, param);
+ delete [] type;
+ } else {
+ res = enum_func(module, MAKEINTRESOURCEA(entry.Id), param);
+ }
+
+ if (!res)
+ break;
+ }
+ }
+ return ::EnumResourceTypesA(module, enum_func, param);
+}
+
+BOOL ResourceManager::EnumResourceTypesW(HMODULE module, ENUMRESTYPEPROCW enum_func, LONG_PTR param)
+{
+ if (!module)
+ module = GetModuleHandle(NULL);
+
+ if (module == instance_) {
+ const RESOURCE_DIRECTORY *directory_enc = reinterpret_cast<const RESOURCE_DIRECTORY *>(data_);
+ const RESOURCE_DIRECTORY_ENTRY *entry_enc = reinterpret_cast<const RESOURCE_DIRECTORY_ENTRY *>(directory_enc + 1);
+ RESOURCE_DIRECTORY directory = DecryptDirectory(directory_enc);
+ for (size_t i = 0; i < directory.NumberOfNamedEntries + directory.NumberOfIdEntries; i++) {
+ RESOURCE_DIRECTORY_ENTRY entry = DecryptDirectoryEntry(&entry_enc[i]);
+ BOOL res;
+ if (entry.NameIsString) {
+ LPWSTR type = DecryptStringW(reinterpret_cast<LPCWSTR>(data_ + entry.NameOffset));
+ res = enum_func(module, type, param);
+ delete [] type;
+ } else {
+ res = enum_func(module, MAKEINTRESOURCEW(entry.Id), param);
+ }
+
+ if (!res)
+ break;
+ }
+ }
+ return ::EnumResourceTypesW(module, enum_func, param);
+}
+
+/**
+ * VirtualResource
+ */
+
+VirtualResource::VirtualResource(const RESOURCE_DATA_ENTRY *entry_enc, uint32_t key)
+ : entry_(entry_enc), address_(NULL)
+{
+ RESOURCE_DATA_ENTRY entry;
+ entry.OffsetToData = entry_enc->OffsetToData ^ key;
+ entry.Size = entry_enc->Size ^ key;
+ entry.CodePage = entry_enc->CodePage ^ key;
+ entry.Reserved = entry_enc->Reserved ^ key;
+
+ handle_.OffsetToData = entry.OffsetToData;
+ handle_.CodePage = entry.CodePage;
+ handle_.Size = entry.Size;
+ handle_.Reserved = entry.Reserved;
+}
+
+VirtualResource::~VirtualResource()
+{
+ delete [] address_;
+}
+
+HGLOBAL VirtualResource::Decrypt(HMODULE instance, uint32_t key)
+{
+ if (!address_) {
+ address_ = new uint8_t[handle_.Size];
+ uint8_t *source = reinterpret_cast<uint8_t *>(instance) + handle_.OffsetToData;
+ for (size_t i = 0; i < handle_.Size; i++) {
+ address_[i] = static_cast<uint8_t>(source[i] ^ (_rotl32(key, static_cast<int>(i)) + i));
+ }
+ }
+ return static_cast<HGLOBAL>(address_);
+}
+
+/**
+ * VirtualResourceList
+ */
+
+VirtualResourceList::~VirtualResourceList()
+{
+ for (size_t i = 0; i < size(); i++) {
+ VirtualResource *resource = v_[i];
+ delete resource;
+ }
+ v_.clear();
+}
+
+VirtualResource *VirtualResourceList::Add(const RESOURCE_DATA_ENTRY *entry, uint32_t key)
+{
+ VirtualResource *resource = new VirtualResource(entry, key);
+ v_.push_back(resource);
+ return resource;
+}
+
+void VirtualResourceList::Delete(size_t index)
+{
+ VirtualResource *resource = v_[index];
+ delete resource;
+ v_.erase(index);
+}
+
+size_t VirtualResourceList::IndexByEntry(const RESOURCE_DATA_ENTRY *entry) const
+{
+ for (size_t i = 0; i < size(); i++) {
+ if (v_[i]->entry() == entry)
+ return i;
+ }
+ return -1;
+}
+
+size_t VirtualResourceList::IndexByHandle(HRSRC handle) const
+{
+ for (size_t i = 0; i < size(); i++) {
+ if (v_[i]->handle() == handle)
+ return i;
+ }
+ return -1;
+}
+
+#endif \ No newline at end of file