DLL-Injection 和 Function-Hooking,在 UWP-Apps 中使用大多数(如果不是全部)注入和挂钩技术都可以完美地工作。
UWP 应用程序和“标准”Win32 应用程序之间关于函数挂钩和 Dll 注入的几个主要区别:
第一:
UWP 应用程序在其中呈现其内容的窗口不属于应用程序可执行文件。取而代之的是“ ApplicationFrameHost ”,因此您不应以窗口为目标,而应以进程本身为目标。
注意:因此,当注入 UWP 应用程序时,您无法创建新窗口,例如消息框。
第二:
您要注入的 DLL 必须具有“读取、执行”以及为“所有应用程序包”组设置的“读取”权限。您可以通过 DLL 文件的属性选项卡进行设置,但名称可能因您的系统语言而异。
您也可以使用StackOverflow 中的以下小代码片段 (所以不要介意“goto”)以编程方式设置权限。
代码片段:
DWORD SetPermissions(std::wstring wstrFilePath) {
PACL pOldDACL = NULL, pNewDACL = NULL;
PSECURITY_DESCRIPTOR pSD = NULL;
EXPLICIT_ACCESS eaAccess;
SECURITY_INFORMATION siInfo = DACL_SECURITY_INFORMATION;
DWORD dwResult = ERROR_SUCCESS;
PSID pSID;
// Get a pointer to the existing DACL
dwResult = GetNamedSecurityInfo(wstrFilePath.c_str(), SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, & pOldDACL, NULL, & pSD);
if (dwResult != ERROR_SUCCESS)
goto Cleanup;
// Get the SID for ALL APPLICATION PACKAGES using its SID string
ConvertStringSidToSid(L"S-1-15-2-1", & pSID);
if (pSID == NULL)
goto Cleanup;
ZeroMemory( & eaAccess, sizeof(EXPLICIT_ACCESS));
eaAccess.grfAccessPermissions = GENERIC_READ | GENERIC_EXECUTE;
eaAccess.grfAccessMode = SET_ACCESS;
eaAccess.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
eaAccess.Trustee.TrusteeForm = TRUSTEE_IS_SID;
eaAccess.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
eaAccess.Trustee.ptstrName = (LPWSTR) pSID;
// Create a new ACL that merges the new ACE into the existing DACL
dwResult = SetEntriesInAcl(1, & eaAccess, pOldDACL, & pNewDACL);
if (ERROR_SUCCESS != dwResult)
goto Cleanup;
// Attach the new ACL as the object's DACL
dwResult = SetNamedSecurityInfo((LPWSTR) wstrFilePath.c_str(), SE_FILE_OBJECT, siInfo, NULL, NULL, pNewDACL, NULL);
if (ERROR_SUCCESS != dwResult)
goto Cleanup;
Cleanup:
if (pSD != NULL)
LocalFree((HLOCAL) pSD);
if (pNewDACL != NULL)
LocalFree((HLOCAL) pNewDACL);
return dwResult;
}
之后,使用您喜欢的注入器/方法注入您的 DLL,您的 DLL 代码将神奇地运行。
由于 UWP 应用程序在底层使用 Win32 API,因此您可以期望在其中加载 KernelBase.dll、Kernel32.dll、ntdll.dll 和 user32.dll。您还会发现 d2d1.dll 和 d3d11.dll 或 d3d12.dll(在少数应用中使用)加载在所有 UWP 应用中,包括新的 UWP 计算器应用。
对于函数挂钩,正如您现在所期望的,它的工作方式与 Win32 程序的工作方式相同。
以控制(隐藏)“C:\ Program Files文件\ WindowsApps \”目录下:
如果不采取控制(隐藏)“C:\ Program Files文件\ WindowsApps \”目录下,或任何你可能拥有它,你不能访问UWP-Apps 文件。
但是您可以控制它,以及任何子目录及其文件,而不会出现任何问题。
您也可以始终以 NT-Authority 身份打开一个 shell并以这种方式访问它们。
如果你只是想修改一个简单的配置文件或其他东西,你应该没问题。但是,某些应用程序(并非所有应用程序)会检查其文件是否被篡改。但这很容易规避。
你所要做的就是钩住“KernelBase.dll”中的“CreateFileW”-Method,监控文件访问,然后重新路由这些访问请求,从某个你可以访问的目录加载你的修改版本。
这是一个使用前面提到的 MinHook 库完成刚才描述的示例。
代码片段:
#include <Windows.h>
#include <atlbase.h>
#include <Shlobj.h>
#include <string>
#include "MinHook.h"
// Path to modified game files store in AppData
std::wstring MOD_FILES_PATH;
// Path to the apps protected resources in WindowsApps
// Don't use the full path name, just keep the Publisher.AppName part
std::wstring APP_LOCATION(L"C:\\ProgramFiles\\WindowsApps\\Publisher.AppName");
// Sets a hook on the function at origAddress function and provides a trampoline to the original function
BOOL setHook(LPVOID * origAddress, LPVOID * hookFunction, LPVOID * trampFunction);
// Attaches a hook on a function given the name of the owning module and the name of the function
BOOL attach(LPWSTR wstrModule, LPCSTR strFunction, LPVOID * hook, LPVOID * original);
// Basic hook setup for CreateFileW
typedef HANDLE(WINAPI * PfnCreateFileW)(LPCWSTR lpFilename, DWORD dwAccess,
DWORD dwSharing, LPSECURITY_ATTRIBUTES saAttributes, DWORD dwCreation,
DWORD dwAttributes, HANDLE hTemplate);
PfnCreateFileW pfnCreateFileW = NULL; // Will hold the trampoline to the original CreateFileW function
// CreateFileW hook function
HANDLE WINAPI HfnCreateFileW(LPCWSTR lpFilename, DWORD dwAccess, DWORD dwSharing, LPSECURITY_ATTRIBUTES saAttributes, DWORD dwCreation, DWORD dwAttributes, HANDLE hTemplate) {
std::wstring filePath(lpFilename);
// Check if the app is accessing protected resources
if (filePath.find(APP_LOCATION) != filePath.npos) {
std::wstring newPath(MOD_FILES_PATH);
// Windows provides the app the location of the WindowsApps directory, so the first half the file path will use back slashes
// After that, some apps will use back slashes while others use forward slashes so be aware of what the app uses
newPath += filePath.substr(filePath.find(L"\\", APP_LOCATION.size()) + 1,
filePath.size());
// Check if the file being accessed exists at the new path and reroute access to that file
// Don't reroute directories as bad things can happen such as directories being ghost locked
if (PathFileExists(newPath.c_str()) && !PathIsDirectory(newPath.c_str()))
return pfnCreateFileW(newPath.c_str(), dwAccess, dwSharing, saAttributes,
dwCreation, dwAttributes, hTemplate);
}
// Let the app load other files normally
return pfnCreateFileW(lpFilename, dwAccess, dwSharing, saAttributes,
dwCreation, dwAttributes, hTemplate);
}
BOOL Initialize() {
// Initialize MinHook
if (MH_Initialize() != MH_OK)
return FALSE;
// Get the path to the apps AppData folder
// When inside a UWP app, CSIDL_LOCAL_APPDATA returns the location of the apps AC folder in AppData
TCHAR szPath[MAX_PATH];
if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, szPath))) {
// Get the path to the mod files folder
std::wstring appData(szPath);
appData = appData.substr(0, appData.rfind(L"AC")); // Get the base directory
appData += L"LocalState\\ModFiles\\"; // Get the location of any new files you want the app to use
MOD_FILES_PATH = appData;
} else
return FALSE;
// Attach a hook on CreateProcessW and return the status of the hook
BOOL hook = TRUE;
hook &= attach(L"KernelBase.dll", "CreateFileW", (LPVOID * ) & HfnCreateFileW,
(LPVOID * ) & pfnCreateFileW);
return hook;
}
BOOL Uninitialize() {
// Uninitialize MinHook
if (MH_Uninitialize() != MH_OK)
return FALSE; // This status will end up being ignored
return TRUE;
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
return Initialize(); // If initialization failed, the DLL will detach
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
Uninitialize(); // Return value doesn't matter when detaching
break;
}
return TRUE;
}
BOOL setHook(LPVOID * origAddress, LPVOID * hookFunction, LPVOID * trampFunction) {
if (MH_CreateHook(origAddress, hookFunction,
reinterpret_cast < LPVOID * > (trampFunction)) != MH_OK)
return FALSE;
if (MH_EnableHook(origAddress) != MH_OK)
return FALSE;
return TRUE;
}
BOOL attach(LPWSTR wstrModule, LPCSTR strFunction, LPVOID * hook, LPVOID * original) {
HMODULE hModule = GetModuleHandle(wstrModule);
if (hModule == NULL)
return FALSE;
FARPROC hFunction = GetProcAddress(hModule, strFunction);
if (hFunction == NULL)
return FALSE;
return setHook((LPVOID * ) hFunction, hook, original);
}
还有一些事情:
您不能像使用 CreateProcess 的常规 Win32 程序一样启动 UWP 应用程序。幸运的是,M$ 为我们提供了IApplicationActivationManager接口,允许开发人员从常规 Win32 程序启动 UWP 应用程序。
如果我们想在应用程序启动之前对其执行某些操作,我们可以使用以下代码在此之前暂停它。
代码片段:
// Gets the current application's UserModelId and PackageId from the registry
// Substitute your own methods in place of these
std::wstring appName = GetApplicationUserModelId();
std::wstring appFullName = GetApplicationPackageId();
HRESULT hResult = S_OK;
// Create a new instance of IPackageDebugSettings
ATL::CComQIPtr debugSettings;
hResult = debugSettings.CoCreateInstance(CLSID_PackageDebugSettings, NULL, CLSCTX_ALL);
if(hResult != S_OK) return hResult;
// Enable debugging
hResult = debugSettings->EnableDebugging(appFullName.c_str(), NULL, NULL);
if(hResult != S_OK) return hResult;
// Launch the application using the function discussed above
DWORD dwProcessId = 0;
hResult = LaunchApplication(appName, &dwProcessId);
if(hResult != S_OK) return hResult;
/* Do more stuff after the app has been resumed */
// Stop debugging the application so it can run as normal
hResult = debugSettings->DisableDebugging(appFullName.c_str());
if(hResult != S_OK) return hResult;
使用上面的代码,您的程序将挂起,直到应用程序恢复,因为它正在等待应用程序在其启动状态回复 IApplicationActivationManager。要恢复应用程序,您只需在启用调试时指定可执行文件的路径:
代码片段:
// Enable Debugging with a custom debugger executable
hResult = debugSettings->EnableDebugging(appFullName.c_str(), pathToExecutable.c_str(), NULL);
if(hResult != S_OK) return hResult;
Windows 将使用命令行参数 -p 后跟进程 ID 将应用程序进程的进程 ID 传递给充当调试器的可执行文件。从调试器可执行文件中,您可以在应用程序暂停时做任何您想做的事情,例如注入 mod,最后使用 NtResumeProcess 恢复应用程序。
#define IMPORT extern __declspec(dllimport)
IMPORT int __argc;
IMPORT char** __argv;
//IMPORT wchar_t** __wargv;
// Turning this into a normal Windows program so it's invisible when run
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
DWORD dwProcessId = 0;
// Process the arguments passed to the debugger
for (int i = 1; i < __argc; i += 2)
{
std::string arg(__argv[i]);
if (arg == "-p")
dwProcessId = atoi(__argv[i + 1]);
}
if(dwProcessId == 0)
return E_FAIL;
// Can do additional error checking to make sure the app is active and not tombstoned
ModLoader::InjectMods(dwProcessId);
ProcessUtils::ResumeProcess(dwProcessId); // Uses NtResumeProcess
return S_OK;
重要提示:call
// Initialize COM objects, only need to do this once per thread
DWORD hresult = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
if (!SUCCEEDED(hresult)) return hresult;
在您启动应用程序或执行任何操作之前,请先调用它:
CoUninitialize();
参考资料:
(1)UWP App Modding的基础和中级技术
(2)Hacking和Modding Windows Universal Apps
我真诚地希望我的这两个答案对将来在 UWP App 挂钩/修改主题上搜索 SE 的人有所帮助。
转载:逆向工程 - 如何对 Windows 10 UWP 应用进行逆向工程? - 吾爱随笔录 - 问答 (52sbl.cn)
Comments NOTHING