*本文原创作者:浪子_三少,属Freebuf原创奖励计划,未经许可禁止转载

在win7时我们只需修改注册表就能设置默认浏览器,但是win8、win10下不能直接修改的因为同样的注册表项,win8、win10多了一个校验hash值。本文就以当下最流行的操作系统win10为例分析下,我们在设置默认浏览器一般会 操作:设置—默认应用—web浏览器,或者在使用chrome设置默认浏览器时都会弹出如下的对话框:

而国内的一些浏览器会绕过这个对话框设置默认浏览器,这个设置对话框就是systemsetting.exe进程来进行的。

下面我们就分析下systemsetting.exe是如何设置默认浏览器的。

一:首先我们要了解windows的默认浏览器设置在注册表里:

HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice

HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\Shell\Associations\UrlAssociations\https\UserChoice

项目:Progid 是浏览器的指向的chrome, hash是设置的hash校验值,只有校验值对了才会弹出指定的浏览器,如果随意修改这个注册表就会失效的,所以最关键是这个hash值。接下来我们开始分析过程,使用windbg我们挂接到systemsetting.exe

我们在注册表函数下断点: bp RegSetValueExW后,操作设置默认浏览器,这时windbg会自动停在RegSetValueExW的函数入口点,说明systemsetting.exe 达到了设置注册表的地方了,然后我们查看堆栈,输入命令kb:

发现函数调用过程由systemsetting.exe进入了shell32.dll的空间,看到几个关键函数名:

000002b8`4dc10000 :KERNELBASE!RegSetValueExW

00030018`000307e1 : SHELL32!_RegSetKeyValue+0×60

00007ff9`28b3c398 : SHELL32!SHRegSetString+0×39

000002b8`536394ac : SHELL32!SetProgIdAndHash+0x1fb

00000000`00000002 : SHELL32!_SetUserChoiceAndHash+0×63

000002b8`536394ac : SHELL32!UserAssocSet+0xf6

00007ff9`28842e00 : SHELL32!CAssocHandler::MakeDefaultPriv+0x16d

看到这个函数SetProgIdAndHash 我们大概就能知道这个的函数的作用了就是计算并且设置那个注册表了。

使用IDA 打开 shell32.dll,我们可以具体分析了:

在继续往下分析:

分别经过调用了IsBrowserExtension、SHGetValueW,前面都是一些条件判断与一些信息的获取最后经过了并且进入UerAssocSet函数

在继续进入分析:

_SetUserChoiceAndHash(ushort const *,ushort const *,bool)

然后继续进入

SetProgIdAndHash(HKEY__ *,ushort const *,ushort const *,ushort const *,ushort const *,bool)

下面我们就具体分析下这个函数,最开始经过第一个函数:call    ?_GetAssociationPath@@YAJPEBG_N1PEAGI@Z

第一个参数r9,   lea ,r9, [rbp+1E0h+SubKey] 这是从外部传进来的,这个具体干嘛的呢?

第二个参数是r8b

第三个参数dl,都是字节传入的应该属于bool类型

具体这些将干什么我们可以分析函数获取:

该函数就是根据不同传入类型拼接不同的路径,到这里我们显然知道了这个传进来的第一个参数就是注册表里的”ProgId”,返回原函数继续分析然后返回。

打开那个注册表项目后,获取当前时间GetSystemTime,接着根据传进来的浏览器类型字符串计算一个HashAssociation字符hash值

最后写入注册表UserChoice===hash,UserChoice == progid项目里,整个过程结束。这以上是大体设置过程的分析,下面我们就开始利用这些设置过程,看看是否能够直接使用接口是设置默认浏览器。

那我们从最开始的接口是CAssocHandler::MakeDefaultPriv(unsigned char );返回开始重新具体的分析,在此函数调用前下断点:

参数1是class指针rcx,参数2是 字节类型当前值为1。

进入MakeDefaultPrive函数

IsBrowserExtension ()函数判断当前是否是设置浏览器

查看[rcx +38h]

继续查看这个红框的地址内存

是L”https”,unicode字符串。

接下来在调用UserAssocSet函数时,传入了三个参数

第一个参数就是[rdi + 38h] 即:L”https”

第二个参数是:1

第三个参数是:[rdi+50h]  ,查看此内存

即L”ChromeHtml”的unicode编码。

那我们就可以假设了,我们是否能直接调用这个函数去调用设置呢,即UserAssocSet(L”http”,1,”ChromeHtml”);理论上是可以,但实际上这个函数不导出只在微软符号表里有,不太好调用,也就是说有点麻烦,写出来的代码会不是很简单,有没有更简单的方法呢,我们继续分析,我们可以看看是否也有其他导出的接口或者类调用了该函数。

鼠标点在函数UserAssocSet,按键盘”X”:

除了当前的CAssocHandler类还有一个比较可疑的函数_SetAssociation,仔细分析他的代码与刚才的MakeDefaultPrive函数类似:

我们再继续看谁调用了SetAssociation函数:

这里是不是看到很眼熟的函数:

CApplicationAssociationRegistration::_SetAppAsDefault(),google chrome浏览器就是调用的这个com类函数设置默认浏览器的,还有一个函数

SetProgIdAsDefault@?QIApplicationAssociationRegistrationInternal@@CApplicationAssociationRegistration,一个是CApplicationAssociationRegistration类,一个QIApplicationAssociationRegistrationInternal类,两个函数只有一个地方区别

我们看下IApplicationAssociationRegistrationInternal的结构定义怎样的:

发现CApplicationAssociationRegistration继承于IApplicationAssociationRegistrationInternal这个类,也就是说IApplicationAssociationRegistrationInternal,也是一个com接口,从结构看他也是继承于IUnknow:

我们可以获取其接口Id定义:

这就是intenal的id:_GUID_1c5c9d10_1225_4c97_8c51_98e1b6f0d4e0

从上我们大致能够知道其定义了:

MIDL_INTERFACE("1c5c9d10-1225-4c97-8c51-98e1b6f0d4e0")

IApplicationAssociationRegistrationInternalWin10: public IUnknown{

public:

virtual HRESULT STDMETHODCALLTYPE ClearUserAssociations(void) = 0;

virtual HRESULT STDMETHODCALLTYPE SetProgIdAsDefault(

/* [string][in] */ __RPC__in_string LPCWSTR pszAppRegistryName,

/* [string][in] */ __RPC__in_string LPCWSTR pszSet,

/* [in] */ ASSOCIATIONTYPE atSetType) = 0;

virtual HRESULT STDMETHODCALLTYPE SetAppAsDefault(

/* [string][in] */ __RPC__in_string LPCWSTR pszAppRegistryName,

/* [string][in] */ __RPC__in_string LPCWSTR pszSet,

/* [in] */ ASSOCIATIONTYPE atSetType) = 0;

// Only use this method. We can not gurantee other method is valid.

virtual HRESULT STDMETHODCALLTYPE SetAppAsDefaultAll(

/* [string][in] */ __RPC__in_string LPCWSTR pszAppRegistryName) = 0;

virtual HRESULT STDMETHODCALLTYPE QueryAppIsDefault(

/* [string][in] */ __RPC__in_string LPCWSTR pszQuery,

/* [in] */ ASSOCIATIONTYPE atQueryType,

/* [in] */ ASSOCIATIONLEVEL alQueryLevel,

/* [string][in] */ __RPC__in_string LPCWSTR pszAppRegistryName,

/* [out] */ __RPC__out BOOL *pfDefault) = 0;

virtual HRESULT STDMETHODCALLTYPE QueryAppIsDefaultAll(

/* [in] */ ASSOCIATIONLEVEL alQueryLevel,

/* [string][in] */ __RPC__in_string LPCWSTR pszAppRegistryName,

/* [out] */ __RPC__out BOOL *pfDefault) = 0;

virtual HRESULT STDMETHODCALLTYPE QueryCurrentDefault(

/* [string][in] */ __RPC__in_string LPCWSTR pszQuery,

/* [in] */ ASSOCIATIONTYPE atQueryType,

/* [in] */ ASSOCIATIONLEVEL alQueryLevel,

/* [string][out] */ __RPC__deref_out_opt_string LPWSTR *ppszAssociation) = 0;

virtual HRESULT STDMETHODCALLTYPE  GetDefaultBrowserInfo(

ASSOCIATIONTYPE atQueryType,

LPWSTR * ppszAssociation) = 0;

virtual HRESULT STDMETHODCALLTYPE  RestoreDefaultBrowserContractRegistration(void) = 0;

virtual HRESULT STDMETHODCALLTYPE  IsBrowserAssociation(LPCWSTR, int *) = 0;

virtual HRESULT STDMETHODCALLTYPE  ExportUserAssociations(LPCWSTR) = 0;

virtual HRESULT STDMETHODCALLTYPE  ApplyUserAssociations(LPCWSTR) = 0;

virtual HRESULT STDMETHODCALLTYPE  UpdateProtocolCapabilityCache(LPCWSTR, int) = 0;

};

我们要设置默认浏览器只需调用SetAppAsDefault这个函数,第一个是参数是pszAppRegistryName,第二个参数”https” 或者 “https”,第三个参数SetType,这个在微软sdk中有定义AT_URLPROTOCOL = 1,关键是第一个参数如何填写,在之前我们区分函数不同时函数内部函数:

_GetManifestedAppAssociation(a3, a4, AL_EFFECTIVE, a2, (unsigned __int16 **)&pv);

这个函数的作用就是判断第一个参数,我们进去看下:

v7 = _GetAppPathKey(a4, a3, &hKey); 传进去第一个参数的值,然后返回hKey,我们大概能想到这个一定是打开了什么注册表,再次进去

打开的是HKEY_CURRENT_USER或者HKEY_LOCAL_MACHINE

嗯?是不是发现了什么?对,L”SOFTWARE\\RegisteredApplications”这个注册表路径,我们去看看注册表信息

L“Google Chrome”这就是他要打开的路径,也就是上述函数的第一个参数。

下面我们可以具体写代码了,并且验证下该想法:

HRESULT SetAppAsDefault(const std::wstring& app_name){

IApplicationAssociationRegistration* pAAR;

HRESULT hr = CoCreateInstance(

CLSID_ApplicationAssociationRegistration,

NULL,

CLSCTX_INPROC,

__uuidof (IApplicationAssociationRegistration),

(void**)&pAAR);

if (SUCCEEDED(hr)) {

IApplicationAssociationRegistrationInternal *Paari = NULL;

HRESULT hr = pAAR->QueryInterface(

__uuidof(IApplicationAssociationRegistrationInternal),

(void**)&pAARI);

if (SUCCEEDED(hr)) {

hr = pAARI->SetAppAsDefault(

L"Goole Chrome",

L"http",

AT_URLPROTOCOL);

hr = pAARI->SetAppAsDefault(

L"Goole Chrome",

L"https",

AT_URLPROTOCOL);

pAARI->Release();

}

}

return hr;

}

我们可以看下运行结果:

运行中也不会弹出systemsetting.exe,直接就设置了,当然如果你再继续更加深入地话就去分析hash算法,这个不是今天的讨论的范围,留着读者们去分析,win8的分析过程与此一样,至此本文结束。

如何绕过Win8、Win10的systemsetting与注册表校验设置默认浏览器的更多相关文章

  1. How to:Installshield判断操作系统是否为64位,并且为操作注册表进行设置

    原文:How to:Installshield判断操作系统是否为64位,并且为操作注册表进行设置 IS脚本操作注册表在64位平台下必须有特殊的设置 if (SYSINFO.bIsWow64) then ...

  2. 将npm的注册表源设置为国内的镜像

    1.国内用户,建议将npm的注册表源设置为国内的镜像,可以大幅提升安装速度 2.国内优秀npm镜像推荐及使用:http://riny.net/2014/cnpm/ 淘宝npm镜像 ·搜索地址:http ...

  3. win7注册表常用设置

    win7注册表常用设置 一.总结 一句话总结:regedit可以修改很多东西,电脑时间,背景,u盘读写,鼠标右键情况. 二.win7注册表常用设置 一. 秀出自我风格的屏幕保护画面 1.气泡屏幕保护 ...

  4. win10家庭版的defender注册表关闭和开启

    关闭方法: 打开“命令提示符(管理员)”,然后输入: reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows Defe ...

  5. 通过cmd修改注册表并设置cmd窗口的大小

    设置cmd的窗口 mode: modem设置系统设备,主要是lpt1, com1/2, con: 启动时设置窗口大小: cmd /k "mode con: cols=120 lines=40 ...

  6. SqlDevlepor注册表监听器设置

      1.打开plsqldev.   2. 键入环境变量 NLS_LANG SIMPLIFIED CHINESE_CHINA.ZHS16GBK   3.下载sqldevclient. http://pa ...

  7. qt 操作注册表,设置ie代理

    void SetIEProxy(QString proxy) { QSettings settings("HKEY_CURRENT_USER\\Software\\Microsoft\\Wi ...

  8. delphi 注册表操作(读取、添加、删除、修改)完全手册

    DELPHI VS PASCAL(87)  32位Delphi程序中可利用TRegistry对象来存取注册表文件中的信息. 一.创建和释放TRegistry对象 1.创建TRegistry对象.为了操 ...

  9. Delphi的注册表操作

    转帖:Delphi的注册表操作 2009-12-21 11:12:52 分类: Delphi的注册表操作 32位Delphi程序中可利用TRegistry对象来存取注册表文件中的信息.     一.创 ...

随机推荐

  1. linux配置MySql表名不区分大小写

    1.Linux下mysql安装完后是默认:区分表名的大小写,不区分列名的大小写:2.用root帐号登录后,在/etc/my.cnf中的[mysqld]后添加添加lower_case_table_nam ...

  2. 简单的Redis数据迁移

    dump迁移 1.安装redis-dump工具 sudo apt-get install ruby rubygems ruby-devel -y gem sources --add http://ge ...

  3. sram bist scripts

    主要三个script: mbist_run: call mbistarchitect tool run.do:run bist flow  bist setup => bist mode(bis ...

  4. [php] 高级教程

    include 和 require 语句用于在执行流中插入写在其他文件中的有用的代码. include 和 require 除了处理错误的方式不同之外,在其他方面都是相同的: require 生成一个 ...

  5. Web框架之Django_06 模型层了解(F查询、Q查询、事务、update和save、only和defer、choice属性、bulk_create)

    摘要: F查询 Q查询 事务 一.F查询 在上面所有的例子中,我们构造的过滤器都只是将字段值与某个我们自己设定的常量做比较.如果我们要对两个字段的值做比较,那该怎么做呢?Django 提供 F() 来 ...

  6. NSArray 排序

    先研究一种方法 NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:]; ; i < ; i++) { ; [arr ...

  7. Django之ORM操作(重要)

    Django ORM操作 一般操作 看专业的官网文档,做专业的程序员! 必知必会13条   <1> all(): 查询所有结果 <2> get(**kwargs): 返回与所给 ...

  8. docker.io/centos安装phpstudy

    1.准备工作 yum install vimyum install wget yum install make yum -y install bzip2 yum install m4 yum inst ...

  9. E. A Magic Lamp

    E. A Magic Lamp Time Limit: 1000ms Case Time Limit: 1000ms Memory Limit: 32768KB   64-bit integer IO ...

  10. POJ 2157 Maze

    Maze Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 3183   Accepted: 996 Description A ...