# JavaScript后门深层分析

Author: 乌云历史资料库 (@wooyun_archive)
Published: 2016-01-12T02:41:00Z
Canonical: https://wepostx.com/topics/1297

> 乌云历史资料归档
>
> **原始作者：** 路人甲
> **原始编号：** superkieran-wooyundrops:996
> **原始发布时间：** 2016-01-12 10:41
> **声明：内容仅用于技术研究和个人使用，版权归 wooyun.org。**

---

# 0x00 背景

[email protected][JavaScript BackDoor](http://drops.wooyun.org/tips/11764)中提到了利用rundll32.exe执行一段JavaScript代码即可反弹一个Http Shell，这里将之前看到的对其原理进行分析的文章翻译和大家分享。
links: [http://thisissecurity.net/2014/08/20/poweliks-command-line-confusion/](http://thisissecurity.net/2014/08/20/poweliks-command-line-confusion/)
最近，hFireF0X在逆向工程论坛kernelmode.info上发表了对Win32/Poweeliks恶意软件详细调查的文章。这个恶意软件的特别之处就是它存在于window注册表中并且使用rundll32.exe来执行JavaScript代码。
我发现很有趣的是我显然不是唯一一个发现可以通过rundll32来执行一些JavaScript代码的人。

![原文图片](/media/2016/06/517ba83be051b63fe2de7d509fa9e13d)

当我们第一次发现命令行执行JavaScript，我们很好奇它是如何工作的。
在接下来的文章中，我们会分析JavaScript代码时如何执以及为什么会在调用这样简单的命令行代码时执行：

```text
#!bash rundll32.exe javascript:"\..\mshtml,RunHTMLApplication ";alert(‘foo’);
```

# 0x01 Rundll32介绍

关于rundll32.dll的使用在MSDN上有专门的[文档](https://support.microsoft.com/zh-cn/kb/164787/en)；它往往被用来调用一个DLL文件的输出函数，可以通过以下的命令来实现：

```text
#!bash RUNDLL32.EXE <dllname>,<entrypoint> <optional arguments>
```
entrypoint就是输出函数；它的函数原型应该是如下所示：

```text
#!cpp void CALLBACK EntryPoint(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow);
```
参数lpszCmdLine是由rundll32.exe命令语句中的<optional arguments>值确定的。
我们会尝试指出rundll32.exe是如何能够调用被mshtml.dll输出的函数RunHTMLApplication，以及“Javascript”前缀是如何被用来执行实际的JavaScript代码的。

# 0x02 Rundll32.exe分析

a.参数
rundll32.exe做的第一件事就是使用内置的ParseCommand命令来对命令进行解析。这个函数会查找一个逗号（‘，’，0x2c）来定位dll的名称和一个空格（‘ ’，0x20）来定位入口点名称

![原文图片](/media/2016/06/0364f73cdfb19faa9fdd231abeabed90)

当使用我们的样本命令时，ParseCommand会返回javascript:"\..\mshtml作为DLL名称，返回RunHTMLApplication作为入口点。

![原文图片](/media/2016/06/f885e2f4ac2beb70ce580fd2f8894be9)

# 0x03 Dll loader

rundll32.exe会尝试几种方法来从最初的“JavaScript："\..\mshtml”加载实际的DLL。
第一次测试使用了函数GetFileAttributes("javascript:"\..\mshtml")。这个函数最终会接近C:\Windows\system32\mshtml。如果这个文件没有被发现，那么这个函数就会返回-1。

![原文图片](/media/2016/06/6952561f6fe6670103ba08da1b328b69)

接下来SearchPath会被调用来确定DLL的名称。这个函数会读取注册表键值HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\SafeProcessSearchMode。微软对于这个键值的定义是：
当这个REG_DWORD类型的注册表键值被设为1，SearchPath会首先搜索系统路径中指定的文件夹，然后会搜索当前工作的文件夹。当这个注册表键值被设为0时，电脑首先会搜索当前工作的文件夹，然后再去搜索系统路径中指定的文件夹。系统对于这个注册表键的默认值是0。
在默认情况下，这个注册表键值是不存在的（在win xp、7、8下），所以SearchPath会优先尝试在rundll32.dll的当前目录中加载文件mshtml，其次才会尝试在系统路径中进行定位。

![原文图片](/media/2016/06/e276ce965d9924f62af017d271bd63b4)

如果所有的尝试都失败了，那么rundll32.exe就会进行下一步。GetFileAttribute将再次被调用来给模块查找manifest文件：javascript:"\..\mshtml.manifest。
若所有的之前的步骤都失败了，rundll32.exe最终会调用Loadlibrary("javascript:"\..\mshtml")。
LoadLibrary只是位于ntdll.dll中的一个对LdrLoadDLL的简单封装。在内部，LdrLoadDll会添加默认的扩展dll并且把结果字串（javascript:”\..\mshtml.dll）作为路径来解析。“..”代表再向上一层文件夹：它就解析成了mshtml.dll。
当mshtml.dll已经被确定了，LdrLoadDll就可以加载系统目录中的lib库了。

![原文图片](/media/2016/06/ade89ac724b1b2a1ceade35e85196157)

rundll32.exe接下来会使用之前提取的入口点名称RunHTMLApplication调用GetProcAddress。
这个时候我们可以发现，javascript:前缀看起来毫无用处：LoadLibrary("foobar:\"\..\mshtml")工作的很好。所以，为什么要加这么一个前缀呢？

# 0x04 协议处理

一旦入口地址已经被解析出来，rundll32.dll会调用函数mshtml.dll!RunHTMLApplication。
即使没有被记录，实际的RunHTMLApplication也能从c:\windows\system32\mshta.exe的调用中推断出来（这个应用专门来启动一个.hta文件）。

```text
#!cpp HRESULT RunHTMLApplication( HINSTANCE hinst, HINSTANCE hPrevInst, LPSTR szCmdLine, int nCmdShow );
```
这和期望的rundll32.exe的入口点地址很相似：

```text
#!cpp void CALLBACK EntryPoint( HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow );
```
RunHTMLApplication接受一个窗口的句柄而不是一个模块的句柄作为第一个参数。这个参数会在mshml登记一个窗口类或者为一个类创建窗口时被使用。传递一个同实际的实例并不相一致的值并不会给user32带来很大影响。
第二个参数完全没有被使用，所以这个不匹配并不重要。
最后一个参数，nCmdShow，被RunHTMLApplication函数用来展示代管这个HTML应用的主机窗口。rundll32经常使用值SW_SHOWDEFAULT来调用入口点函数来指示任何可能打开的窗口使用窗口默认配置。
在我们的例子中，可能更让人感兴趣的参数是 lpszCmdLine (";alert('foo'))。

![原文图片](/media/2016/06/441b8891d84b9f1b7ff042b2dfad2c23)

这显然会导致问题，因为这并不是一个有效的JavaScript语句（注意在语句末尾丢掉的双引号）。但是它仍然有效，因为RunHTMLApplication忽略给定的参数，并且更倾向于从windows API GetCommandLine中重新请求原始的命令（封装在GetCmdKLine函数的一个调用中）。

![原文图片](/media/2016/06/62a5b1e4e9ea5f39b9776a50b24b758e)

完整的命令包含了可执行文件和参数的名称：GetCmdLine通过整理可执行规范来提取参数。

![原文图片](/media/2016/06/7faca4464830751405549a48454a1aca)

在这之后，RunHTMLApplication会调用CreateURLMonitor:

![原文图片](/media/2016/06/456c2f6e79a82cf5f57d6a61a28e3b89)

这也是需要字符串“javascript”的地方。
CreateURLMonitor解析命令行来提取char":"(0x3A)之前的字符串：“javascript”。

![原文图片](/media/2016/06/d84e6f78a4c5d1034f8fa303d9dd8264)

CreateUrlMoniker会爬取注册表键值HKCR\SOFTWARE\Classes\PROTOCOLS\Handler\。这些键值和一个协议集以及它们的CLSID有关。
CreateUrlMoniker会发现一个合适的协议处理器来对Javascript的协议进行处理（HKCR\SOFTWARE\Classes\PROTOCOLS\Handler\javascript）：

![原文图片](/media/2016/06/f1e7c353a5831cb7e3e58bbb7c118d2e)

CLSID{3050F3B2-98B5-11CF-BB82-00AA00BDCE0B}符合微软“Microsoft HTML Javascript Pluggable Protocol”规范。

![原文图片](/media/2016/06/6f941189ed968c053fa5b9a7545ec918)

这也是为什么字符串“javascript”必须在参数的开始部分的原因。
相同的机制在人们在IE的导航栏输入javascript:alert('alert')时也会起作用。

![原文图片](/media/2016/06/ce2c8ed587d9474649caa6d1b7553d22)

位于“：”分隔符之后的字符串会被JavaScript URL moniker解释成JavaScript指令：

```text
#!js "\..\mshtml,RunHTMLApplication ";alert(‘foo’);
```
这是一个带有字符串"\..\mshtml,RunHTMLApplication "和函数（alert)的无效JavaScript语句（因为双引号会跳过所有之前的步骤！）。
最终RunHTMLApplication会调用CHTMLApp::Run,这条JavaScript语句也会被执行：

![原文图片](/media/2016/06/b4c5ef77247b1c8965b8b1c0ae9c498f)

# 0x05 安全影响

从安全的角度来看，通过rundll32来执行JavaScript就像执行一个HTML应用。
换句话说，我们可以使用IE的全部权利。当区域安全被关闭，允许跨域脚本访问，我们就可以拥有读写客户端机器文件和注册表的权力。
通过这个技巧，JavaScript可以在IE外部被执行，并且脚本没有任何安全概念的约束，比如保护模式\沙盒。

# 0x06 结论

按照我们的理解，这个技术语序绕过一些信任内置的rundll32的行为的安全产品。

# 0x07 本文相关

- [https://twitter.com/hFireF0X](https://twitter.com/hFireF0X)

- [http://www.kernelmode.info/forum/viewtopic.php?f=16&t=3377](http://www.kernelmode.info/forum/viewtopic.php?f=16&t=3377)

- [http://support.microsoft.com/kb/164787/en](http://support.microsoft.com/kb/164787/en)

- [http://msdn.microsoft.com/enus/library/windows/desktop/aa365527%28v=vs.85%29.aspx](http://msdn.microsoft.com/enus/library/windows/desktop/aa365527%28v=vs.85%29.aspx)

- [https://thisiscybersec.files.wordpress.com/2014/08/capture-d_c3a9cran-2014-08-20-c3a0-16-16-36.png](https://thisiscybersec.files.wordpress.com/2014/08/capture-d_c3a9cran-2014-08-20-c3a0-16-16-36.png)

- [https://thisiscybersec.files.wordpress.com/2014/08/capture-d_c3a9cran-2014-08-20-c3a0-16-16-36.png](https://thisiscybersec.files.wordpress.com/2014/08/capture-d_c3a9cran-2014-08-20-c3a0-16-16-36.png)

## Replies
