我想看看Microsoft在Windows 10的“设置”->“更新”窗口中单击“立即重新启动”按钮时正在做什么:



可以通过InitiateSystemShutdownExInitiateShutdown WinAPI使用相同的功能,尤其是在安装更新方面。

所以我想研究一下它们用于该Restart按钮的代码。通常,我会使用Spy ++查找父窗口的WndProc,然后将进程加载到IDA Pro中并在其上放置一个断点。然后捕获BM_CLICK消息的条件。

在这种情况下,整个设置都是其自己的窗口。该按钮未在Spy ++中出现:



任何想法如何从那里继续进行?

评论

我很乐意看到有人提供解决方案。也许考虑在此时开始赏金,以吸引沉重打击者的更多兴趣?

@dsasmblr:来了。擦掉要点。希望有人能回答。

#1 楼

在将其添加为“另一个答案”之前,我已经进行了仔细的思考,而不是编辑今天早上在我上面发布的现有答案。

我觉得这个答案值得自己补充,因为它不仅简单

我花了两个多小时来避免只剪切和粘贴来自其他站点的内容。关于这一点,我只将内容包含在此内容中,这样即使将来的原始网站(从中获取该内容的网站)将来都将关闭,此答案仍将保持相关性。

我试图按照OP的要求,着重于使我们能够挂钩和修改UWP Apps中的代码的要素。

入侵和修改Windows通用应用程序:

DLL注入和函数挂钩在UWP-App中使用大多数(即使不是全部)注入和挂钩技术也能很好地工作。

UWP应用程序和“标准” Win32应用程序之间在函数挂钩和Dll注入方面有两个主要区别:

第一:
UWP app呈现其内容的对象,而不是由Apps
第二个:
要注入的DLL必须具有“读取, “执行”以及为“所有应用程序包”组设置的“读取”权限。
您可以通过DLL文件的属性标签进行设置,但名称可能会随
您的系统语言。

您也可以使用请使用
StackOverflow中的以下小代码段(所以不要介意“转到”)以编程方式设置权限。

代码段

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,然后DLLs代码就会神奇地起作用。
由于UWP-Apps在后台使用Win32 API,因此可以期待KernelBase.dll,
Kernel32.dll,ntdll.dll和user32.dll要加载到其中。您还将在所有UWP应用程序(包括新的UWP计算器应用程序)中找到d2d1.dll和
对于函数挂钩,正如您现在所期望的,它的工作方式与Win32程序相同。

控制(隐藏)“ C:\ Program Files \ WindowsApps \”目录:
如果不控制(隐藏)的“ C:\ Program Files \ WindowsApps \”目录,或者在任何可能的位置,都无法访问UWP-Apps的文件。
但是,您可以控制此文件及其任何子目录及其文件,而不会出现任何问题。

您还可以始终以NT-Authority的身份打开一个外壳并以这种方式访问​​它们。
如果您只想修改一个简单的配置文件或其他内容,就可以了。
/>但是,某些应用程序(不是全部)会检查其文件是否被篡改。但这很容易被规避。

您所要做的就是在“ KernelBase.dll”中挂接“ CreateFileW”方法,监视文件
访问,然后重新路由这些访问请求以从某些目录加载修改的版本
目录,您就可以访问它。

代码片段:

#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程序。
对我们来说,幸运的是,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;
}


重要说明:调用

// Initialize COM objects, only need to do this once per thread
DWORD hresult = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
if (!SUCCEEDED(hresult)) return hresult;


在启动应用程序或进行任何后续操作之前,请先调用它: br />(1)UWP App Modding的基本和中间技术
(2)Hacking and Modding Windows通用应用程序

我衷心希望我的这两个答案对搜索任何内容的人有帮助将来会在UWP App挂钩/修改主题上进行SE。

评论


好答案!我将确保阅读代码示例和参考-荣誉。

–barnaby-b
18年1月15日在15:31

是的,谢谢。这个答案更接近回答我的原始问题。 (您的其他答案是关于全局挂钩的。不幸的是,在这种情况下,您将无法做很多事情。我也可以通过捕获鼠标来单击UWP应用程序的窗口,即Windows.UI.Core.CoreWindow。单击事件在其带有IDA的WndProc中。遗憾的是,从这一点开始是不容易的。或者如何到达可帮助进一步从按钮单击路由呼叫的类。

–c00000fd
18年1月15日在21:42

我会将其标记为答案,以便您可以获得工作的赏金。我只想指出,还有很多工作要做。您可以通过电子邮件与我联系吗?解决后,我会在这里发布更新。

–c00000fd
18年1月16日在1:45

谢谢c00000fd!最近几天一直在加班(甚至在这个周末也都在加班),因此没有时间处理您提到的Windows Update中实际的“重新启动”按钮。希望在接下来的几天中,我将能够为该确切的“重新启动”按钮问题创建解决方案,并在此处进行更新。还将根据要求通过电子邮件发送给您。 @ barnaby-b-谢谢你的夸奖!

– TechLord
18年1月16日在4:35



出色的工作,TechLord,以及对这整件事c00000fd的出色反馈和态度!我希望看到您继续使用该重新启动按钮解决方案TechLord。另外,一旦您将事情固定下来,c00000fd也将很高兴为您提供更新。谢谢你们俩!

–dsasmblr
18年1月16日在18:13

#2 楼

如所承诺的,我将对OP提出的问题发表更具体的答案。

决定将其作为一个单独的答案写出来,因为我认为此内容会脱颖而出,不适合我上面发布的两个答案中的任何一个。 />解决他的第一个问题:


但是,在这种情况下,整个设置都是其自己的窗口。
按钮没有出现在Spy ++中


好吧,当使用Spy ++以外的其他工具时,该按钮确实出现了。
我将在帮助下粘贴2个工具的屏幕截图可以发现RESTART按钮的属性。

使用作为Microsoft SDK一部分的INSPECT TOOL:



并同时使用UI Spy工具(请注意,也可以使用许多其他工具)...



现在我们将看到我们破解了什么代码当我们单击RESTART按钮时为ON:

首先,运行系统设置管理器(在任务管理器中将看到SystemSettings.exe)。
通过以下方式“附加”到SystemSettings.exe进程一个调试器(为此目的,我使用了[优秀] x64dbg调试器)。
确保在调试器设置中勾选“ DLL加载中断”,如下所示:



现在,我们*单击“立即重新启动”按钮*(位于Windows设置窗口中) w)。随着“ SettingsHandlers_nt.dll”被加载到进程中,我们将破坏调试器。

这是处理设置窗口事件(单击等)的主要dll。





这是控制流图的一部分,实际上它决定
重新启动:




结果不尽相同,可以通过
InitiateSystemShutdownEx或InitiateShutdown WinAPIs获得,特别是关于安装更新的



OP是正确的。
MusUpdateHandlers.dll处理Microsoft Update之后,[自动]的实际决策部分将重新启动,如下所示:



以及这里:



我添加了最后两个屏幕截图,因为OP想要知道什么是API我希望UPDATE之后系统重新启动时调用...

我希望这现在可以得出@ c00000fd想知道的答案...

评论


您好TechLord,您能帮我解决一下问题吗:reverseengineering.stackexchange.com/questions/23454/…非常感谢:)

–沙燕
3月18日14:05

#3 楼


“我想了解有关如何挂接并进入功能的详细信息,该功能在UWP应用中处理按钮单击事件。”


我建议使用EventHook库来挂接全局Windows用户事件。该库可以作为Nuget包使用。

Github和我的fork上有项目库(名为Windows用户操作钩)可以在这里访问。这与我上面提到的库(EventHook库)相同。如果您想掌握源代码,可以访问Github仓库。 :(这些是可以全局挂接的事件)


鼠标事件
剪贴板事件
应用程序事件
/>打印事件



用法-通过nuget安装


安装包EventHook


样本代码:

KeyboardWatcher.Start();  
KeyboardWatcher.OnKeyInput += (s, e) =>  
{  
    Console.WriteLine(string.Format("Key {0} event of key {1}", e.KeyData.EventType, e.KeyData.Keyname));  
};  

MouseWatcher.Start();  
MouseWatcher.OnMouseInput += (s, e) =>  
{  
    Console.WriteLine(string.Format("Mouse event {0} at point {1},{2}", e.Message.ToString(), e.Point.x, e.Point.y));    
};  

ClipboardWatcher.Start();  
ClipboardWatcher.OnClipboardModified += (s, e) =>  
{  
    Console.WriteLine(string.Format("Clipboard updated with data '{0}' of format {1}", e.Data, e.DataFormat.ToString()));  
};  

ApplicationWatcher.Start();  
ApplicationWatcher.OnApplicationWindowChange += (s, e) =>  
{  
    Console.WriteLine(string.Format("Application window of '{0}' with the title '{1}' was {2}", e.ApplicationData.AppName, e.ApplicationData.AppTitle, e.Event));    
};  

PrintWatcher.Start();  
PrintWatcher.OnPrintEvent += (s, e) =>  
{  
    Console.WriteLine(string.Format("Printer '{0}' currently printing {1} pages.", e.EventData.PrinterName, e.EventData.Pages));    
};  

Console.Read();  
KeyboardWatcher.Stop();  
MouseWatcher.Stop();  
ClipboardWatcher.Stop();  

ApplicationWatcher.Stop();  
PrintWatcher.Stop();  





我确定一旦您了解了我们如何能够全局地挂接各种Windows用户事件。
在您的案例中,使用该库,我们将能够编写一个小型C#程序,例如,该程序将挂接mouse-press事件单击“立即重新启动”按钮,从而使我们能够控制后续事件。

由于这个问题是关于挂钩UWP应用程序的,所以我想举一个例子,其中该库用于专门挂钩UWP应用程序,以便在需要时可以将该仓库中的代码用作示例。
请注意,我并不是直接从该回购中摘录任何内容,因为我只想表明该库也可以与UWP Apps很好地配合使用。您可以在这里访问我的Github Repo UWPHook的叉子。

#4 楼

我在每个名为SystemSettting *。*的文件中的System32文件夹中搜索Shutdown一词。我使用Total Commander是因为它可以搜索多种编码,例如ASCII和Unicode:


然后内置的查看器显示了对InitiateSystemShutdownExW的引用:


从MSDN:


InitiateSystemShutdownEx函数启动指定计算机的关闭和可选的重新启动,并有选择地记录关闭的原因。

BOOL WINAPI InitiateSystemShutdownEx(
  _In_opt_ LPTSTR lpMachineName,
  _In_opt_ LPTSTR lpMessage,
  _In_     DWORD  dwTimeout,
  _In_     BOOL   bForceAppsClosed,
  _In_     BOOL   bRebootAfterShutdown,
  _In_     DWORD  dwReason
);


要进行验证,下一步是使用Ida Pro或API Monitor之类的工具在此API上设置断点。

评论


我不确定SystemSettingsThresholdAdminFlowUI.dll当时是否甚至映射到C:\ Windows \ ImmersiveControlPanel \ SystemSettings.exe进程。

–c00000fd
18年1月10日在3:59



您可以使用例如Process Explorer,但您可能是对的,它以另一种方式调用了此api。

–雷姆科
18年1月10日在9:49

要调试必须使用PLMDebug的UWP应用,可以使用windbg或x64dbg。

– mrexodia
18年1月10日在15:29

@mrexodia:是的,显然,您需要使用PLMDebug来关闭UWP应用程序上的进程生命周期管理。换句话说,这样它就不会在后台被代理暂停。但是,就其本身而言,您无需对其进行调试。它不是调试器。

–c00000fd
18年1月11日在6:42