VMProtect/runtime/resource_manager.cc

1022 lines
31 KiB
C++
Raw Normal View History

2023-05-14 16:21:09 +03:00
#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