今天为大家带来一个基于Dll劫持的MSVC编译过程劫持思路,我本来是想要研究下MSVC编译器想通过注入的方式劫持编译流,然后通过得出逆向出微软编译器的IR格式,最后通过自己的Pass实现原生的Windows下驱动混淆方案(又或者 编译期代码植入)。
我目前用的方案是自己写的LLVM替换编译工具链的方式来对驱动进行混淆的,但是该方案每次我改动LLVM的时候就需要重新编译LLVM,非常的麻烦。所以我就想着能不能通过注入的方式去做,结果在研究的过程中发现可以通过劫持的方式去做(微软偷懒没有对PASS 相关的DLL进行鉴权导致我们可以利用这个机制进行植入)换句话说这个也是一个代码植入的APT思路,虽然我们已经可以用譬如:
1.替换C库文件
2.替换静态库文件
等等方式使其编译带毒感染,但是总归都不如通过直接劫持编译器来的快。
影响版本
更早的没有测过了,至少新版本是可以的
◆VS2019
◆VS2017
◆VS2022
先看效果

利用方式
通过替换Dll即可实现。路径如下:
1.Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\bin\Hostx86\x86
2.Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\bin\Hostx86\x64
3.Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\bin\Hostx64\x86
4.Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\bin\Hostx64\x64
这些路径下的c1.dllc2.dll都可以劫持,微软完全没有对该部分dll的加载进行任何签名校验,问题是这些dll目录一般是在Path中的所以在微软的漏洞定义里面不属于漏洞(Hijack本来也不算),因为是管理员权限,但是我还是觉得微软应该做一下鉴权毕竟也不是经常更新的东西,这个组件c1.dll同时还承担了一些编译前端的工作,在加载C/C++项目的时候也会加载(估计是做代码提示分析这一类的),编译的时候也会加载(Pass嘛)。
分析 cl.exe
如下所示,有两个地方都可以加载Dll并且没有做任何的校验
.text:00426C20 ; int __fastcall execute(int, int, const WCHAR *lpLibFileName, wchar_t *Name, _DWORD *)
.text:00426C20 ?execute@@YAHW4driver_phases@@PAUpassinfo_t@@PBG2PAPAG@Z proc near in this methods this line
.text:00426E16 call ds:__imp__LoadLibraryExW@12 ; LoadLibraryExW(x,x,x)
they call the loadlibraryExW without check and after that
.text:00426E1C mov ebx, eax
.text:00426E1E test ebx, ebx
.text:00426E20 jz short loc_426E5A
.text:00426E22 push offset aInvokecompiler_0 ; "_InvokeCompilerPassW@16"
.text:00426E27 push ebx ; hModule
.text:00426E28 mov esi, ds:__imp__GetProcAddress@8 ; GetProcAddress(x,x)
.text:00426E2E call esi ; GetProcAddress(x,x) ; GetProcAddress(x,x)
.text:00426E30 mov [ebp+var_28], eax
.text:00426E33 push offset aAbortcompilerp_0 ; "_AbortCompilerPass@4"
.text:00426E38 push ebx ; hModule
.text:00426E39 call esi ; GetProcAddress(x,x) ; GetProcAddress(x,x).text:00426E1C mov ebx, eax (pollute _AbortCompilerPass)
.text:00426E1E test ebx, ebx
.text:00426E20 jz short loc_426E5A
.text:00426E22 push offset aInvokecompiler_0 ; "_InvokeCompilerPassW@16"
.text:00426E27 push ebx ; hModule
.text:00426E28 mov esi, ds:__imp__GetProcAddress@8 ; GetProcAddress(x,x)
.text:00426E2E call esi ; GetProcAddress(x,x) ; GetProcAddress(x,x)
pollute _InvokeCompilerPassW
.text:00426E30 mov [ebp+var_28], eax
.text:00426E33 push offset aAbortcompilerp_0 ; "_AbortCompilerPass@4"
.text:00426E38 push ebx ; hModule
.text:00426E39 call esi ; GetProcAddress(x,x) ; GetProcAddress(x,x)
分析c1.dll的利用方式
首先,我们根据cl.exe的名称可以看到他载入后调用了_InvokeCompilerPassW@16我们可以在IDA里面搜索这个签名。

找到该函数后进入Trap_callMain进入编译流程

继续进入CallMain

继续进入Trap_main_complie这里稍微还原以下如果大家是F5看的话应该最后是
return Trap_main_complie()

他里面还包了一层main_compile继续

这个非常大的函数就是编译的逻辑了,这里我给出一些大概的东西大家具体可以自己分析。
FileMap句柄(可以通过这个去写文件)
这里可以看到句柄位置

可以通过如下类方法去研究

然后IR的一些格式和操作需要结合cl.exe的方法才能分析出来,这部分内容我就不写了目前暂不公开,通过如上的句柄已经可以进行劫持了,修改c1.dll通过特征或者PDB获取到句柄后在编译的时候识别标准的__crt_main函数的特征码或者__init_term等等的点都可以注入一些意想不到的东西。我给出c1的主要CFG。
InvokeCompilerPassW -> Trap_CallMain -> CallMain -> Trap_main_compile ->main_compile(核心编译函数)
该方法挺通用的很多版本都可以用,具体更多用法等大家自己去开发,关于IR的一些研究我就不发了。
看雪ID:TeddyBe4r
https://bbs.kanxue.com/user-home-983513.htm
# 往期推荐
Hyper-V平台IUM进程调试工具及通用TPM漏洞CVE-2025-2884分析与复现
球分享
球点赞
球在看
点击阅读原文查看更多

