2016年8月

fuzz程序的第一步:打开edge的几种方法

Edge属于Universal App,这类程序不能简单的通过CreateProcess系列函数打开,有人问我打开Edge的几种方式,这里总结一下。如果要给它做Fuzz的话,可以考虑下面三种打开方式去启动Edge。

本文授权drops.wiki及本站共发

0x01 第一种方式——ShellExecute

第一种方式,利用系统自动调用默认浏览器的功能,即:
设置默认浏览器为Edge。
使用ShellExecute(0, L"OPEN", L"HTTP://YOUR-START-PAGE/", NULL, NULL, SW_SHOW);走系统的默认浏览器逻辑启动Edge。

(通过explorer 参数或者.url快捷方式等来启动Edge也属于同样的方式)

这里的流程如下:

ShellExecuteW(ShellExecuteW就是ShellExecuteExW的wrapper)
↓
ShellExecuteExW(ShellExecuteExW则是ShellExecuteNormal的wrapper)
↓
ShellExecuteNormal(可以当作是正式的启动了。在ShellExecuteNormal中,代码创建一个CShellExecute的类的实例,然后调用其ExecuteNormal方法)
↓
CShellExecute::ExecuteNormal(根据启动参数[要启动的文件后缀为.CMD时,或者调用者含有同步原语时不满足]决定是否要使用新线程来调用,传入OPEN打开URL时,满足该判断)
↓
CShellExecute::_RunThreadMaybeWait(执行线程代码简单,创建事件并在新线程中执行具体的启动代码)
↓
pfnThreadProc(调用启动进程的入口CShellExecute::_DoExecute)
↓
CShellExecute::_DoExecute
↓
CShellExecute::_InvokeCtxMenu(它会把获取到的IContextMenu[000214E4-0000-0000-C000-000000000046]接口传给InvokeInProcExec)
↓
CShellExecute::_InvokeInProcExec(根据操作获取CmdId,传给DefFolderMenu::InvokeCommand)
↓
DefFolderMenu::InvokeCommand(这是一个巨大的函数,检测到连接打开的这种情况时,使用HDXA_LetHandlerProcessCommandEx来处理)
↓
HDXA_LetHandlerProcessCommandEx
↓
SHELL32!CRegistryVerbsContextMenu::InvokeCommand(打开URL的这个动作需要读取注册表中指定的动词[open],这里开始都是根据注册表关联的动词来启动关联程序)
↓
SHELL32!CRegistryVerbsContextMenu::_Execute
↓
windows_storage!CRegDataDrivenCommand::InvokeFromContextMenu
↓
windows_storage!CRegDataDrivenCommand::_Invoke
↓
windows_storage!CRegDataDrivenCommand::_TryInvokeAssociation
↓
windows_storage!CBindAndInvokeStaticVerb::Execute
↓
windows_storage!CBindAndInvokeStaticVerb::_TryExecuteCommandHandler
↓
windows_storage!CBindAndInvokeStaticVerb::_DoCommand
↓
twinui!CAssociationLaunchExecuteCommand::Execute

0x02 第二种方式——microsoft-edge protocol

Win8开始Windows提供的Custom Protocol Activation技术让edge有了这个新启动方式,Windows允许桌面程序和runtime app注册成某个URL scheme name的默认打开程序。通过Manifest注册关联程序的方式可以参考:https://msdn.microsoft.com/en-us/library/windows/apps/hh452686.aspx

UWP Edge可以在:
打开%SYSTEMROOT%\SystemApps\Microsoft.MicrosoftEdge_8wekyb3d8bbwe,这是Edge的App目录,8wxxx就是它的APPID。
打开AppxManifest.xml, 可以看到与之关联的协议之一:

        <uap:Extension Category="windows.protocol">
            <uap:Protocol Name="microsoft-edge">
                <uap:Logo>Assets\MicrosoftEdgeFile.png</uap:Logo>
            </uap:Protocol>
        </uap:Extension>

HKEY_CURRENT_USER\SOFTWARE\Classes\Extensions\ContractId\Windows.Protocol\PackageId\Microsoft.MicrosoftEdge_25.10586.0.0_neutral__8wekyb3d8bbwe\ActivatableClassId\ 下即为支持的协议,MicrosoftEdge.AppXeb42j1vh6rk395pm0vmcx57dxqjhej5d.mca是microsoft-edge的项目。

使用microsof-edge protocol。这意味着在C++中只需要CreateProcess系列指定参数为explorer microsoft-edge:http://www.baidu.com/,或者ShellExecute中open microsoft-edge:http://xxx/即可启动。这种方式启动的Edge,不需要用户设置默认浏览器。

所以,许多更愿意把Edge当备胎的用户应该会比较喜欢使用这种方式。

0x03 第三种方式(正经的)——IApplicationActivationManager 接口

直接上代码吧。

// testCallApplicationActivationManager.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <shobjidl.h>
#include <windows.h>
#include <atlcomcli.h>

int main()
{
    CComPtr<IApplicationActivationManager> piaam;
    CComPtr<IUnknown> punk;

    CoInitializeEx(NULL, COINIT_MULTITHREADED);
    LPCWSTR appId = L"Microsoft.MicrosoftEdge_8wekyb3d8bbwe!MicrosoftEdge";
    IApplicationActivationManager* paam = NULL;
    HRESULT hr = E_FAIL;
    LPCWSTR url = L"www.wooyun.org";
    do
    {
        hr = CoCreateInstance(CLSID_ApplicationActivationManager, NULL, 
            CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&paam));
        if (FAILED(hr))
            break;
        DWORD pid = 0;
        hr = paam->ActivateApplication(appId, url, AO_NONE, &pid);
        if (FAILED(hr))
            break;
    } while (0);

    return 0;
}

参考资料
【1】UWP是什么:https://msdn.microsoft.com/en-us/windows/uwp/get-started/whats-a-uwp
【2】https://www.microsoft.com/msj/0199/com/com0199.aspx