修补微信Windows隐藏的深色模式




用逆向做点正向


MacOS版本的微信在2021年已经支持深色模式:


修补微信Windows隐藏的深色模式

Windows版本的微信到2024年还没有深色模式,看到下面链接说到:眼睛畏光的低视力人一直在反馈。


期盼尽快更新Windows版本(PC版本)微信深色模式(暗色、黑暗、暗夜、黑夜模式(https://developers.weixin.qq.com/community/develop/article/doc/00082aeaf0ca4009b620ec37e6b813)


试着用逆向去实现Windows版本的微信也支持深色模式,发现微信其实隐藏了深色模式,可惜不完善,修补之后效果如下:


修补微信Windows隐藏的深色模式






隐藏的深色模式


先试着用IDA搜素深色模式的关键词dark,发现确实有深色模式:‘weuithemedarktheme.xml’


修补微信Windows隐藏的深色模式


交叉索引一下引用字符串的地方:


int sub_1F35D30()
sub_1F33C40(dword_32C5500, L"weui\theme\dark\theme.xml");
sub_1F33C40(dword_32C54F4, L"Theme\dark\theme_dark.xml");


再看下sub_1F35D30调用的地方,dword_32C5500便是深色模式的资源路径:


int sub_1F35D00()
if ( !dword_32C5500 ) sub_1F35D30();
return dword_32C5500;


再看下sub_1F35D00调用的地方,可以看出byte_32B5474控制是否用深色模式:


int __thiscall sub_1EF62E0(_DWORD *this)
if ( byte_32B5474 ) sub_1F35D00();
else sub_1F35CF0();


交叉索引byte_32B5474,有两个地方写入byte_32B5474:


01EBC2ED 8A47 61			mov al, [edi+61h]
01EBC2F2 A2 74542B03        mov byte_32B5474, al

01EBCCE3 C605 74542B03 00 mov byte_32B5474, 0


在X86dbg上修改一下汇编:


7A47C2ED | B0 01                | mov al,1                                 |
7A47C2EF | 90                   | nop                                      |

7A47CCE3 | C605 7454877B 01     | mov byte ptr ds:[7B875474],1 


修改之后还是浅色模式,但个人名片从白色是黑色,说明深色模式有效且不完善。


修补微信Windows隐藏的深色模式






深色模式的原理


为了了解为什么深色模式不完善,需要梳理一下深色模式的底层原理。


1、微信里面有两个主题模式:


浅色:themedefaulttheme.xml

深色:themedarktheme.xml


2、不同主题模式的颜色配置文件不同:


浅色:themedefaulttheme.xml
<!-- color -->
<IncludeTheme source="weui/Theme/default/colors.xml" />

深色:themedarktheme.xml
<!-- color -->
<IncludeTheme source="weui/Theme/dark/colors.xml" />


3、同id不同主题模式下,具体值不同:


浅色:themedefaulttheme.xml
<!-- color -->
<IncludeTheme source="weui/Theme/default/colors.xml" />
<!-- 文字颜色 -->
<Color id="Text_1" opacity="1" color="#161616" /> // 浅色模式的文字比较深

深色:themedarktheme.xml
<!-- color -->
<IncludeTheme source="weui/Theme/dark/colors.xml" />
<!-- 文字颜色 -->
<Color id="Text_1" opacity="1" color="#F7F7F7" /> // 深色模式的文字比较浅


4、界面的属性值改为从固定值变成变量值:


textcolor="#FF000000"
改成
textcolor="@color:Text_1"


可以看出微信的底层已经有一套更换模式的基建,而深色模式之所以不完善是因为深色资源文件不完整。


themedefaultcolors.xml    5150 字节
themedarkcolors.xml 4370 字节





修改界面的资源


如果要完善深色模式,就需要修改界面资源,先了解一下原生Duilib生成界面的流程。


1、界面生成从OnCreate开始:


LRESULT WindowImplBase::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
switch (GetResourceType())
case UILIB_ZIP:
    m_pm.SetResourceZip(GetZIPFileName().GetData(), true);

CControlUI* pRoot = builder.Create(xml, _T("xml"), this, &m_pm);


2、builder.Create加载界面资源:


CControlUI* CDialogBuilder::Create(STRINGorID xml, LPCTSTR type, IDialogBuilderCallback* pCallback, CPaintManagerUI* pManager, CControlUI* pParent)
if( !m_xml.Load(xml.m_lpstr) ) return NULL;
if( !m_xml.LoadFromFile(xml.m_lpstr) ) return NULL;
if( !m_xml.LoadFromMem((BYTE*)::LockResource(hGlobal), ::SizeofResource(dll_instence, hResource) )) return NULL;
return Create(pCallback, pManager, pParent);

bool CMarkup::LoadFromMem(BYTE* pByte, DWORD dwSize, int encoding)
DWORD nWide = ::MultiByteToWideChar( CP_UTF8, 0, (LPCSTR)pByte, dwSize, NULL, 0 );
::MultiByteToWideChar( CP_UTF8, 0, (LPCSTR)pByte, dwSize, m_pstrXML, nWide );


3、最后是解析界面资源的内容:


CControlUI* CDialogBuilder::Create(IDialogBuilderCallback* pCallback, CPaintManagerUI* pManager, CControlUI* pParent)
CMarkupNode root = m_xml.GetRoot();
for( CMarkupNode node = root.GetChild() ; node.IsValid(); node = node.GetSibling() )
"linkhoverfontcolor"


根据这个流程,就可以定位微信Duilib对应的函数:


1、搜索关键词”linkhoverfontcolor”


int __thiscall sub_1EDDBE0(_DWORD *this, int pCallback, int pManager, int pParent)
"linkhoverfontcolor"


2、再查看sub_1EDDBE0的引用


int __thiscall sub_1EDDB80(_DWORD *this, wchar_t *Source, int a3, int a4, int a5, int a6)
wcXMLData = sub_1F20210(wcXMLPath, 1);
if ( wcXMLData && sub_1EE0BE0(this, *(wcXMLData + 0x2000), *(wcXMLData + 0x2004), v8) )
return sub_1EDDBE0(this, a4, a5, a6);


3、sub_1F20210就是CMarkup::LoadFromMem


把界面资源的路径(wcXMLPath)变成界面资源的内容(wcXMLData ):


char __thiscall sub_1EE0BE0(WCHAR **this, LPCCH lpMultiByteStr, unsigned int cbMultiByte, int a4)
v6 = MultiByteToWideChar(65001u, 0, v5, v4, 0, 0);// CP_UTF8
MultiByteToWideChar(65001u, 0, v5, cbMultiByte, v7, v6);


用Frida的js脚本拦截修改(需要修改很多地方),就可以实现深色模式:


const targetFunctionAddress = WeChatWin.add(0x1F20210);
Interceptor.attach(targetFunctionAddress,
...
ModifyAttribute(this.wsXMLDataArray, '', 'bkcolor', '#FF000000');


修补微信Windows隐藏的深色模式






修改业务的代码

修改资源的属性,发现了一个问题:编辑框的文字属性修改无效。原本是是白色背景加黑色字体,现在是黑色背景加黑色字体,看不清。这就意味着:控件的属性,不是完全依赖界面资源,还需要修改业务代码。


1、修改字体颜色的接口是SetAttribute:


void CRichEditUI::SetAttribute(LPCTSTR pstrName, LPCTSTR pstrValue)
if( _tcscmp(pstrName, _T("textcolor")) == 0 )
if( *pstrValue == _T('#')) pstrValue = ::CharNext(pstrValue);
DWORD clrColor = _tcstoul(pstrValue, &pstr, 16);
SetTextColor(clrColor);

void CRichEditUI::SetTextColor(DWORD dwTextColor)
m_pTwh->SetColor(dwTextColor);

void CTxtWinHost::SetColor(DWORD dwColor)
cf.crTextColor = RGB(GetBValue(dwColor), GetGValue(dwColor), GetRValue(dwColor));
pserv->OnTxPropertyBitsChange(TXTBIT_CHARFORMATCHANGE, TXTBIT_CHARFORMATCHANGE);


注入DLL调用SetAttribute确实能改变字体颜色,但再编辑编辑框RichEdit的文本,颜色又变成黑色。


DWORD pControl = 0x15a72bb8;
const wchar_t* wcAttr = L"textcolor";
const wchar_t* wcValue = L"#FFFFFFFF"; // 白色
SetAttribute(pControl, wcAttr, wcValue);


2、修改字体颜色的另一接口是SetSelectionCharFormat:


#define WM_USER                 0x0400
#define EM_GETCHARFORMAT (WM_USER + 58)  // 0x43A
#define EM_SETCHARFORMAT (WM_USER + 68)  // 0x444
#define SCF_SELECTION 0x0001

DWORD CRichEditUI::GetSelectionCharFormat(CHARFORMAT2 &cf) const
cf.cbSize = sizeof(CHARFORMAT2);
    TxSendMessage(EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf, &lResult);


bool CRichEditUI::SetSelectionCharFormat(CHARFORMAT2 &cf)
    cf.cbSize = sizeof(CHARFORMAT2);
    TxSendMessage(EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf, &lResult);

HRESULT CRichEditUI::TxSendMessage(UINT msg, WPARAM wparam, LPARAM lparam, LRESULT *plresult) const
return m_pTwh->GetTextServices()->TxSendMessage(msg, wparam, lparam, plresult);


X86dbg对TxSendMessage下条件断点并打印参数:


修补微信Windows隐藏的深色模式

发现编辑文本的时候调用了GetSelectionCharFormat:


#define EM_GETCHARFORMAT (WM_USER + 58)  // 0x43A
CRichEditUI::TxSendMessage this=15AA51E0 msg=43A wparam=1


添加暂停条件:[esp+4]==0x43A,看下哪里调用GetSelectionCharFormat:


修补微信Windows隐藏的深色模式


发现确实调用了SetSelectionCharFormat:


#define EM_GETCHARFORMAT		(WM_USER + 58)  0x43A
#define EM_SETCHARFORMAT (WM_USER + 68)  0x444
#define SCF_SELECTION 0x0001
int __thiscall sub_1F02FA0(int *this, _DWORD *pColor, int dwBegin, int dwEnd)
// GetSelectionCharFormat
(*(*this + 724))(this, 0x43A, 1, pcf, v10);
// SetSelectionCharFormat
(*(*this + 724))(this, 0x444, 1, pcfNew, v10);


再看下调用sub_1F02FA0的地方,发现微信在代码上直接写死成黑色:


void __thiscall sub_9FF580(int *this)
NewColor(pColor, 0xFF000000); // 写死黑色
sub_1F02FA0(this, pColor, 0, TextLength);


再看下调用sub_9FF580的上级函数,发现确实是有更新的时候修改字体颜色。


void __thiscall sub_01F03D70(char *this, unsigned int iNotify, int a3)
// #define EN_UPDATE           0x0400
if ( iNotify == 0x400 )
//GetManager()->SendNotify(this, DUI_MSGTYPE_TEXTCHANGED); 
sub_1EC0390(*(this + 22), this, L"textchanged", 0, 0, this[3820]);          
(*(*this + 740))(this);                   // sub_9FF580


简单的绕过方法就是修改一个字节:0x400改变成0x401:


7A4C3DBE | 81FB 00040000        | cmp ebx,400                              |
改成
7A4C3DBE | 81FB 01040000        | cmp ebx,401


修补微信Windows隐藏的深色模式




修补微信Windows隐藏的深色模式


看雪ID:GhHei

https://bbs.kanxue.com/homepage-1000535.htm

*本文为看雪论坛优秀文章,由 GhHei 原创,转载请注明来自看雪社区

修补微信Windows隐藏的深色模式

# 往期推荐

1、UnrealEngine POLYGON 全逆向笔记

2、inlinehook心得分享

3、PWN入门-2-LibC取物-Ret2LibC

4、HITCON CTF 2024 re AntiVirus wp clamav bytecode signature逆向

5、House of orange的进一步利用(house of orange+)


修补微信Windows隐藏的深色模式



修补微信Windows隐藏的深色模式

球分享

修补微信Windows隐藏的深色模式

球点赞

修补微信Windows隐藏的深色模式

球在看



修补微信Windows隐藏的深色模式

点击阅读原文查看更多

原文始发于微信公众号(看雪学苑):修补微信Windows隐藏的深色模式

版权声明:admin 发表于 2024年7月31日 下午6:05。
转载请注明:修补微信Windows隐藏的深色模式 | CTF导航

相关文章